From 9f1e3979fb26efb1f15e4401efe6de69eaffa310 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Fri, 16 Sep 2022 14:12:13 +0200 Subject: [PATCH] Update es2panda Squashed patches/ark-opensource-es2panda-test/*.patch, rebased and fixed clang-tidy issues. Major changes: - Rework the checker component based on TypeScript Compiler - Fix destructuring pattern validation in the parser - Implement direct/indirect eval - Optimize ecma.call* instructions - Implement BigInt - Update classes to ES.next - Implement AssemblyScript parser - Remove unnecessary opcodes realted to js class - Optimize LdObj* instructions - Optimize register allocation for es2panda - Ensure deterministic output of multithreaded es2panda - Optimize lexical variable load/store - Optimize RegExp creation - Update Named backreferences parse - Fix class field property name check in parser - Compile Nullish coalescing operator - Optimize literal buffer creation - Implement Optional chaining operator Change-Id: Ia0817cbc400c7d5c07ba2d5f0dbd4e6e9c1d7d4e Signed-off-by: Robert Fancsik --- BUILD.gn | 2 +- .../code_generator/compiler_base_types.cpp | 8 + compiler/optimizer/ir/dyn_datatype.h | 9 + .../ir_builder/ecmascript_inst_builder.cpp | 70 +- .../ir_builder/ecmascript_inst_builder.h | 1 + .../ir_builder/ecmascript_inst_templates.yaml | 24 + ecmascript_plugin_options.yaml | 1 + ecmastdlib/ecmastdlib.pa | 25 +- irtoc_scripts/interpreter_handlers.irt | 24 +- irtoc_scripts/interpreter_main_loop.irt | 117 +- isa/isa.yaml | 433 ++++- runtime/CMakeLists.txt | 12 + runtime/asm_defines/asm_defines.def | 1 + runtime/base/number_helper.cpp | 88 + runtime/base/number_helper.h | 1 + runtime/base/typed_array_helper-inl.h | 28 +- runtime/base/typed_array_helper.cpp | 25 +- ...dle_call_ecma_call0dyn_pref_none_aarch64.S | 57 + ...e_call_ecma_call0thisdyn_pref_v8_aarch64.S | 42 + ...andle_call_ecma_call1dyn_pref_v8_aarch64.S | 26 + ...all_ecma_call1thisdyn_pref_v8_v8_aarch64.S | 26 + ...le_call_ecma_call2dyn_pref_v8_v8_aarch64.S | 31 + ..._ecma_call2thisdyn_pref_v8_v8_v8_aarch64.S | 31 + ...call_ecma_call3dyn_pref_v8_v8_v8_aarch64.S | 36 + ...ma_call3thisdyn_pref_v8_v8_v8_v8_aarch64.S | 36 + ...handle_call_ecma_calldyn_helper_aarch64.S} | 79 +- ...ecma_callirangedyn_pref_imm16_v8_aarch64.S | 2 +- ..._callithisrangedyn_pref_imm16_v8_aarch64.S | 2 +- ...dle_call_ecma_callthisdyn_helper_aarch64.S | 41 + ...andle_call_ecma_call0dyn_pref_none_amd64.S | 55 + ...dle_call_ecma_call0thisdyn_pref_v8_amd64.S | 39 + .../handle_call_ecma_call1dyn_pref_v8_amd64.S | 27 + ..._call_ecma_call1thisdyn_pref_v8_v8_amd64.S | 27 + ...ndle_call_ecma_call2dyn_pref_v8_v8_amd64.S | 32 + ...ll_ecma_call2thisdyn_pref_v8_v8_v8_amd64.S | 32 + ...e_call_ecma_call3dyn_pref_v8_v8_v8_amd64.S | 37 + ...ecma_call3thisdyn_pref_v8_v8_v8_v8_amd64.S | 37 + ...> handle_call_ecma_calldyn_helper_amd64.S} | 63 +- ...l_ecma_callirangedyn_pref_imm16_v8_amd64.S | 2 +- ...ma_callithisrangedyn_pref_imm16_v8_amd64.S | 2 +- ...andle_call_ecma_callthisdyn_helper_amd64.S | 38 + .../handle_call_ecma_call0dyn_pref_none_arm.S | 16 + ...andle_call_ecma_call0thisdyn_pref_v8_arm.S | 16 + .../handle_call_ecma_call1dyn_pref_v8_arm.S | 16 + ...le_call_ecma_call1thisdyn_pref_v8_v8_arm.S | 16 + ...handle_call_ecma_call2dyn_pref_v8_v8_arm.S | 16 + ...call_ecma_call2thisdyn_pref_v8_v8_v8_arm.S | 16 + ...dle_call_ecma_call3dyn_pref_v8_v8_v8_arm.S | 16 + ...l_ecma_call3thisdyn_pref_v8_v8_v8_v8_arm.S | 16 + .../arm/handle_call_ecma_calldyn_helper_arm.S | 16 + .../handle_call_ecma_callthisdyn_helper_arm.S | 16 + runtime/builtins.cpp | 84 +- runtime/builtins.h | 6 + runtime/builtins/builtins_array.cpp | 8 +- runtime/builtins/builtins_arraybuffer.cpp | 121 +- runtime/builtins/builtins_arraybuffer.h | 42 +- runtime/builtins/builtins_async_function.cpp | 6 +- runtime/builtins/builtins_async_generator.cpp | 6 +- runtime/builtins/builtins_bigint.cpp | 175 ++ runtime/builtins/builtins_bigint.h | 41 + runtime/builtins/builtins_dataview.cpp | 34 +- runtime/builtins/builtins_dataview.h | 8 + runtime/builtins/builtins_function.cpp | 108 +- runtime/builtins/builtins_generator.cpp | 6 +- runtime/builtins/builtins_global.cpp | 6 +- runtime/builtins/builtins_global.h | 2 +- runtime/builtins/builtins_typedarray.cpp | 58 +- runtime/builtins/builtins_typedarray.h | 2 + runtime/class_info_extractor.cpp | 4 +- .../class_linker/panda_file_translator.cpp | 29 +- runtime/class_linker/panda_file_translator.h | 2 +- runtime/dump.cpp | 48 + runtime/ecma_runtime.yaml | 271 ++- runtime/ecma_vm.cpp | 21 +- runtime/ecma_vm.h | 4 + runtime/global_env.h | 6 +- runtime/global_env_constants.cpp | 7 + runtime/global_env_constants.h | 4 + runtime/ic/ic_runtime.cpp | 25 - runtime/ic/profile_type_info.cpp | 6 - runtime/ic/profile_type_info.h | 10 +- runtime/interpreter/ecma-interpreter-inl.h | 406 ++++- runtime/interpreter/fast_runtime_stub-inl.h | 8 +- runtime/interpreter/fast_runtime_stub.h | 2 +- runtime/interpreter/interpreter.h | 9 +- runtime/interpreter/js_decode_call_instr.h | 146 +- runtime/interpreter/slow_runtime_helper.cpp | 40 + runtime/interpreter/slow_runtime_helper.h | 5 + runtime/interpreter/slow_runtime_stub.cpp | 746 +++++++-- runtime/interpreter/slow_runtime_stub.h | 24 +- .../debugger_instruction_dispatch.inl | 5 +- .../debugger_instruction_handler.inl | 15 - .../templates/instruction_dispatch.inl | 3 - runtime/intrinsics-inl.h | 377 ++++- runtime/js_bigint.cpp | 1455 +++++++++++++++++ runtime/js_bigint.h | 145 ++ runtime/js_dataview.cpp | 4 + runtime/js_dataview.h | 14 +- runtime/js_eval.cpp | 220 +++ runtime/js_eval.h | 42 + runtime/js_function.h | 15 + runtime/js_hclass.h | 26 +- runtime/js_number_format.cpp | 14 +- runtime/js_object.h | 1 + runtime/js_primitive_ref.h | 1 + runtime/js_tagged_value-inl.h | 120 +- runtime/js_tagged_value.cpp | 80 +- runtime/js_tagged_value.h | 9 +- runtime/js_typed_array.cpp | 18 +- runtime/js_typed_array.h | 4 +- runtime/literal_data_extractor.cpp | 14 + runtime/mem/object_xray-inl.h | 4 + runtime/object_factory.cpp | 17 +- runtime/object_factory.h | 4 +- runtime/runtime_call_id.h | 444 ++--- runtime/runtime_sources.gn | 3 + subproject_sources.gn | 10 + tests/runtime/CMakeLists.txt | 3 +- .../runtime/builtins/builtins_bigint_test.cpp | 618 +++++++ tests/runtime/common/js_serializer_test.cpp | 12 +- tests/runtime/common/test_helper.h | 3 + tests/runtime/tooling/js/GetVariable.js | 6 +- 122 files changed, 7003 insertions(+), 1068 deletions(-) create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_call0dyn_pref_none_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_call0thisdyn_pref_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_call1dyn_pref_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_call1thisdyn_pref_v8_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_call2dyn_pref_v8_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_call3dyn_pref_v8_v8_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_aarch64.S rename runtime/bridge/arch/aarch64/{handle_call_ecma_N_v8_aarch64.S => handle_call_ecma_calldyn_helper_aarch64.S} (52%) create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_callthisdyn_helper_aarch64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_call0dyn_pref_none_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_call0thisdyn_pref_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_call1dyn_pref_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_call1thisdyn_pref_v8_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_call2dyn_pref_v8_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_call3dyn_pref_v8_v8_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_amd64.S rename runtime/bridge/arch/amd64/{handle_call_ecma_N_v8_amd64.S => handle_call_ecma_calldyn_helper_amd64.S} (54%) create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_callthisdyn_helper_amd64.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_call0dyn_pref_none_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_call0thisdyn_pref_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_call1dyn_pref_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_call1thisdyn_pref_v8_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_call2dyn_pref_v8_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_call3dyn_pref_v8_v8_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_calldyn_helper_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_callthisdyn_helper_arm.S create mode 100644 runtime/builtins/builtins_bigint.cpp create mode 100644 runtime/builtins/builtins_bigint.h create mode 100644 runtime/js_bigint.cpp create mode 100644 runtime/js_bigint.h create mode 100644 runtime/js_eval.cpp create mode 100644 runtime/js_eval.h create mode 100644 tests/runtime/builtins/builtins_bigint_test.cpp diff --git a/BUILD.gn b/BUILD.gn index d5150242c..3eaa77d35 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -15,7 +15,7 @@ import("//ark/runtime_core/ark_config.gni") import("//build/ohos.gni") group("ark_packages") { - deps = [] + deps = ["$ark_root/plugins/ecmascript/es2panda/aot:es2panda"] } group("ark_host_linux_tools_packages") { diff --git a/compiler/optimizer/code_generator/compiler_base_types.cpp b/compiler/optimizer/code_generator/compiler_base_types.cpp index a286ea54a..fc35cdaf5 100644 --- a/compiler/optimizer/code_generator/compiler_base_types.cpp +++ b/compiler/optimizer/code_generator/compiler_base_types.cpp @@ -192,6 +192,9 @@ bool ecmascript::CompareAnyTypeGen(const CompareAnyTypeInst *cati, EncodeVisitor case AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: CompareAnyTypeGenObjectType(codegen, enc, dst, src, cross_values::GetJstypeSymbol(codegen->GetArch())); return true; + case AnyBaseType::ECMASCRIPT_BIGINT_TYPE: + CompareAnyTypeGenObjectType(codegen, enc, dst, src, cross_values::GetJstypeBigint(codegen->GetArch())); + return true; case AnyBaseType::ECMASCRIPT_ARRAY_TYPE: CompareAnyTypeGenObjectType(codegen, enc, dst, src, cross_values::GetJstypeJsArray(codegen->GetArch())); return true; @@ -281,6 +284,7 @@ bool ecmascript::CastAnyTypeValueGen(const CastAnyTypeValueInst *cati, EncodeVis case AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE: case AnyBaseType::ECMASCRIPT_STRING_TYPE: case AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: + case AnyBaseType::ECMASCRIPT_BIGINT_TYPE: case AnyBaseType::ECMASCRIPT_ARRAY_TYPE: case AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: case AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: @@ -328,6 +332,7 @@ bool ecmascript::CastValueToAnyTypeGen(const CastValueToAnyTypeInst *cvai, Encod return true; case AnyBaseType::ECMASCRIPT_STRING_TYPE: case AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: + case AnyBaseType::ECMASCRIPT_BIGINT_TYPE: case AnyBaseType::ECMASCRIPT_OBJECT_TYPE: case AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE: case AnyBaseType::ECMASCRIPT_ARRAY_TYPE: @@ -383,6 +388,9 @@ bool ecmascript::AnyTypeCheckGen(const AnyTypeCheckInst *check_inst, EncodeVisit case AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: CompareAnyTypeGenObjectType(codegen, enc, tmp_reg, src, cross_values::GetJstypeSymbol(codegen->GetArch())); return true; + case AnyBaseType::ECMASCRIPT_BIGINT_TYPE: + CheckAnyTypeGenObjectType(codegen, enc, src, cross_values::GetJstypeBigint(codegen->GetArch()), id); + return true; case AnyBaseType::ECMASCRIPT_ARRAY_TYPE: CheckAnyTypeGenObjectType(codegen, enc, src, cross_values::GetJstypeJsArray(codegen->GetArch()), id); return true; diff --git a/compiler/optimizer/ir/dyn_datatype.h b/compiler/optimizer/ir/dyn_datatype.h index 0c40665cb..498e730a8 100644 --- a/compiler/optimizer/ir/dyn_datatype.h +++ b/compiler/optimizer/ir/dyn_datatype.h @@ -51,6 +51,11 @@ static inline panda::compiler::AnyBaseType GetAnyStringType() return panda::compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE; } +static inline panda::compiler::AnyBaseType GetAnyBigintType() +{ + return panda::compiler::AnyBaseType::ECMASCRIPT_BIGINT_TYPE; +} + static inline std::optional IsAnyTypeCanBeSubtypeOf(panda::compiler::AnyBaseType super_type, panda::compiler::AnyBaseType type) { @@ -64,6 +69,7 @@ static inline std::optional IsAnyTypeCanBeSubtypeOf(panda::compiler::AnyBa case panda::compiler::AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_BIGINT_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_ARRAY_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: @@ -77,6 +83,7 @@ static inline std::optional IsAnyTypeCanBeSubtypeOf(panda::compiler::AnyBa switch (type) { case panda::compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_BIGINT_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_ARRAY_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: @@ -88,6 +95,7 @@ static inline std::optional IsAnyTypeCanBeSubtypeOf(panda::compiler::AnyBa break; case panda::compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_BIGINT_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_ARRAY_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: @@ -106,6 +114,7 @@ static inline std::optional IsAnyTypeCanBeSubtypeOf(panda::compiler::AnyBa return std::nullopt; case panda::compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_BIGINT_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: return true; diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp index a598059e1..45fa29ebe 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp +++ b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include #include "compiler_logger.h" #include "optimizer/ir_builder/inst_builder.h" #include "optimizer/ir_builder/ir_builder.h" @@ -20,9 +21,18 @@ #include "bytecode_instruction.h" #include "bytecode_instruction-inl.h" #include "include/coretypes/tagged_value.h" +#include "optimizer/ir_builder/pbc_iterator.h" namespace panda::compiler { +void InstBuilder::FinalizeEcmaFnCall(SaveStateInst *save_state, CallInst *call_inst) +{ + call_inst->AppendInput(save_state); + call_inst->AddInputType(DataType::NO_TYPE); + AddInstruction(call_inst); + UpdateDefinitionAcc(call_inst); +} + // NOLINTNEXTLINE(misc-definitions-in-headers) void InstBuilder::BuildEcmaFnCall(const BytecodeInstruction *bc_inst, bool is_range, bool call_this, uint64_t num_args) { @@ -30,7 +40,18 @@ void InstBuilder::BuildEcmaFnCall(const BytecodeInstruction *bc_inst, bool is_ra auto save_state = CreateSaveState(Opcode::SaveState, bc_pc); AddInstruction(save_state); - auto callee = GetDefinition(bc_inst->GetVReg(0)); + Inst *callee {}; + + switch (bc_inst->GetOpcode()) { + case BytecodeInstruction::Opcode::ECMA_CALL0DYN_PREF_NONE: { + callee = GetDefinitionAcc(); + break; + } + default: { + callee = GetDefinition(bc_inst->GetVReg(0)); + break; + } + } { // Check callee is JSFunction auto callee_func = BuildAnyTypeCheckInst(bc_pc, callee, save_state, AnyBaseType::ECMASCRIPT_FUNCTION_TYPE); @@ -64,29 +85,46 @@ void InstBuilder::BuildEcmaFnCall(const BytecodeInstruction *bc_inst, bool is_ra call_inst->AddInputType(DataType::ANY); call_inst->AppendInput(FindOrCreateConstant(coretypes::TaggedValue::VALUE_UNDEFINED)); call_inst->AddInputType(DataType::ANY); + if (!call_this) { // Assume strict mode call_inst->AppendInput(FindOrCreateConstant(coretypes::TaggedValue::VALUE_UNDEFINED)); call_inst->AddInputType(DataType::ANY); + } else { + num_args++; } - if (is_range) { - auto range_start = bc_inst->GetVReg(0) + 1; - auto range_size = bc_inst->GetImm64(); - - for (int64_t i = 0; i < range_size; ++i) { - call_inst->AppendInput(GetDefinition(range_start + i)); - call_inst->AddInputType(DataType::ANY); + switch (bc_inst->GetOpcode()) { + case BytecodeInstruction::Opcode::ECMA_CALL0DYN_PREF_NONE: { + FinalizeEcmaFnCall(save_state, call_inst); + return; } - } else { - for (uint64_t i = 0; i < num_args; ++i) { - call_inst->AppendInput(GetDefinition(bc_inst->GetVReg(1 + i))); - call_inst->AddInputType(DataType::ANY); + case BytecodeInstruction::Opcode::ECMA_CALLIRANGEDYN_PREF_IMM16_V8: + case BytecodeInstruction::Opcode::ECMA_CALLITHISRANGEDYN_PREF_IMM16_V8: { + auto range_start = bc_inst->GetVReg(0) + 1; + auto range_size = bc_inst->GetImm64(); + + for (int64_t i = 0; i < range_size; ++i) { + call_inst->AppendInput(GetDefinition(range_start + i)); + call_inst->AddInputType(DataType::ANY); + } + + FinalizeEcmaFnCall(save_state, call_inst); + return; + } + default: { + break; } } - call_inst->AppendInput(save_state); - call_inst->AddInputType(DataType::NO_TYPE); - AddInstruction(call_inst); - UpdateDefinitionAcc(call_inst); + + for (uint64_t i = 1; i < num_args; ++i) { + call_inst->AppendInput(GetDefinition(bc_inst->GetVReg(i))); + call_inst->AddInputType(DataType::ANY); + } + + call_inst->AppendInput(GetDefinitionAcc()); + call_inst->AddInputType(DataType::ANY); + + FinalizeEcmaFnCall(save_state, call_inst); } void InstBuilder::BuildEcmaNewobjdynrange(const BytecodeInstruction *bc_inst) diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_builder.h b/compiler/optimizer/ir_builder/ecmascript_inst_builder.h index 27f4c2c27..3c9569016 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_builder.h +++ b/compiler/optimizer/ir_builder/ecmascript_inst_builder.h @@ -26,6 +26,7 @@ template void BuildLdGlobalVar(const BytecodeInstruction *bc_inst, size_t type_id); void BuildEcmaFnCall(const BytecodeInstruction *bc_inst, bool is_range, bool call_this, uint64_t num_args = 0); +void FinalizeEcmaFnCall(SaveStateInst *save_state, CallInst *call_inst); void BuildEcmaNewobjdynrange(const BytecodeInstruction *bc_inst); diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml b/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml index 1188ad306..40a588ef0 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml +++ b/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml @@ -56,6 +56,30 @@ } else { BuildEcmaFnCall(instruction, false, false, 3); } + % when "CALL0THISDYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, false, true, 0); + } + % when "CALL1THISDYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, false, true, 1); + } + % when "CALL2THISDYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, false, true, 2); + } + % when "CALL3THISDYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, false, true, 3); + } % when "CALLIRANGEDYN" if (graph_->IsBytecodeOptimizer()) { BuildEcma(instruction); diff --git a/ecmascript_plugin_options.yaml b/ecmascript_plugin_options.yaml index af576bf15..da7f8e684 100644 --- a/ecmascript_plugin_options.yaml +++ b/ecmascript_plugin_options.yaml @@ -60,6 +60,7 @@ SPECIAL_INDEXED_TYPE: panda::compiler::DataType::Type::REFERENCE BOOLEAN_TYPE: panda::compiler::DataType::Type::BOOL FUNCTION_TYPE: panda::compiler::DataType::Type::REFERENCE + BIGINT_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/ecmastdlib/ecmastdlib.pa b/ecmastdlib/ecmastdlib.pa index e2111886d..4ca7e12c6 100644 --- a/ecmastdlib/ecmastdlib.pa +++ b/ecmastdlib/ecmastdlib.pa @@ -22,7 +22,7 @@ .function any Ecmascript.Intrinsics.ldboolean(any a0) .function any Ecmascript.Intrinsics.ldnumber(any a0) .function any Ecmascript.Intrinsics.ldstring(any a0) -.function any Ecmascript.Intrinsics.ldbigint(any a0) +.function any Ecmascript.Intrinsics.ldbigint(u32 a0) .function any Ecmascript.Intrinsics.ldnull() .function any Ecmascript.Intrinsics.ldsymbol() .function any Ecmascript.Intrinsics.ldobject(any a0, any a1) @@ -80,7 +80,9 @@ .function any Ecmascript.Intrinsics.newlexenvDyn(u16 a0) .function any Ecmascript.Intrinsics.copylexenvDyn() .function void Ecmascript.Intrinsics.StLexVarDyn(u16 a0, u16 a1, any a2) +.function any Ecmascript.Intrinsics.StLexDyn(u32 a0, u16 a1, u16 a2, any a3) .function any Ecmascript.Intrinsics.LdLexVarDyn(u16 a0, u16 a1) +.function any Ecmascript.Intrinsics.LdLexDyn(u32 a0, u16 a1, u16 a2) .function any Ecmascript.Intrinsics.ldlexenvDyn() .function void Ecmascript.Intrinsics.popLexenvDyn() .function any Ecmascript.Intrinsics.getUnmappedArgs() @@ -113,7 +115,7 @@ .function any Ecmascript.Intrinsics.asyncGeneratorReject(any a0, any a1) .function void Ecmascript.Intrinsics.throwUndefined(any a0) .function void Ecmascript.Intrinsics.throwConstAssignment(u32 a0) -.function any Ecmascript.Intrinsics.throwUndefinedIfHole(u32 a0, any a1) +.function void Ecmascript.Intrinsics.throwTdz(u32 a0) .function any Ecmascript.Intrinsics.copyrestargs(u16 a0) .function any Ecmascript.Intrinsics.copyrestargsInterp(u16 a0) .function any Ecmascript.Intrinsics.ldHole() @@ -123,7 +125,6 @@ .function any Ecmascript.Intrinsics.TryStGlobalByName(u32 a0, any a1, u16 a2) .function any Ecmascript.Intrinsics.LdGlobalVar(u32 a0, u16 a1) .function any Ecmascript.Intrinsics.StGlobalVar(u32 a0, any a1, u16 a2) -.function any Ecmascript.Intrinsics.StGlobalLet(u32 a0, any a1) .function any Ecmascript.Intrinsics.LdObjByName(u32 a0, any a1, u16 a2) .function any Ecmascript.Intrinsics.StObjByName(u32 a0, any a1, any a2, u16 a3) .function any Ecmascript.Intrinsics.LdObjByIndex(u32 a0, any a1) @@ -137,6 +138,10 @@ .function any Ecmascript.Intrinsics.Call3Dyn(any a0, any a1, any a2, any a3) .function any Ecmascript.Intrinsics.CalliRangeDyn(u16 a0, any a1) .function any Ecmascript.Intrinsics.CalliRangeDynInterp(u16 a0, any a1) +.function any Ecmascript.Intrinsics.Call0ThisDyn(any a0, any a1) +.function any Ecmascript.Intrinsics.Call1ThisDyn(any a0, any a1, any a2) +.function any Ecmascript.Intrinsics.Call2ThisDyn(any a0, any a1, any a2, any a3) +.function any Ecmascript.Intrinsics.Call3ThisDyn(any a0, any a1, any a2, any a3, any a4) .function any Ecmascript.Intrinsics.CalliThisRangeDyn(u16 a0, any a1) .function any Ecmascript.Intrinsics.createemptyobject() .function any Ecmascript.Intrinsics.createobjectwithbuffer(u16 a0) @@ -145,6 +150,7 @@ .function any Ecmascript.Intrinsics.definegettersetterbyvalue(any a0, any a1, any a2, any a3, any a4) .function any Ecmascript.Intrinsics.createemptyarray() .function any Ecmascript.Intrinsics.createarraywithbuffer(u16 a0) +.function any Ecmascript.Intrinsics.createregexpwithliteral(u32 a0, u8 a1) .function any Ecmascript.Intrinsics.StOwnByName(u32 a0, any a1, any a2) .function any Ecmascript.Intrinsics.StOwnByIndex(u32 a0, any a1, any a2) .function any Ecmascript.Intrinsics.StOwnByValue(any a0, any a1, any a2) @@ -160,7 +166,16 @@ .function void Ecmascript.Intrinsics.StModuleVar(u32 a0, any a1) .function void Ecmascript.Intrinsics.CopyModule(any a0) .function any Ecmascript.Intrinsics.LdModvarByName(u32 a0, any a1) +.function any Ecmascript.Intrinsics.LoadClassComputedInstanceFields(any a0) +.function void Ecmascript.Intrinsics.SetClassComputedFields(any a0, any a1) .function any Ecmascript.Intrinsics.DefineClassWithBuffer(u32 a0, u16 a1, any a2, any a3) +.function any Ecmascript.Intrinsics.ClassFieldAdd(any a0, any a1, any a2) +.function void Ecmascript.Intrinsics.DefineClassPrivateFields(u16 a0, any a1, any a2) +.function any Ecmascript.Intrinsics.ClassPrivateMethodOrAccessorAdd(any a0, any a1) +.function any Ecmascript.Intrinsics.ClassPrivateFieldAdd(u32 a0, any a1, any a2, any a3) +.function any Ecmascript.Intrinsics.ClassPrivateFieldGet(u32 a0, any a1, any a2) +.function any Ecmascript.Intrinsics.ClassPrivateFieldSet(u32 a0, any a1, any a2, any a3) +.function any Ecmascript.Intrinsics.ClassPrivateFieldIn(u32 a0, any a1, any a2) .function any Ecmascript.Intrinsics.SuperCall(u16 a0, any a1, any a2, any a3) .function any Ecmascript.Intrinsics.SuperCallSpread(any a0, any a1, any a2) .function any Ecmascript.Intrinsics.defineMethod(u32 a0, any a1, any a2) @@ -172,6 +187,10 @@ .function any Ecmascript.Intrinsics.ThrowIfSuperNotCorrectCall(u16 a0, any a1) .function any Ecmascript.Intrinsics.LdHomeObject() .function void Ecmascript.Intrinsics.ThrowDeleteSuperProperty() +.function any Ecmascript.Intrinsics.LdEvalBindings(u16 a0) +.function any Ecmascript.Intrinsics.DirectEval(u32 a0, any a1, any a2) +.function any Ecmascript.Intrinsics.LdEvalVar(u32 a0, any a1) +.function any Ecmascript.Intrinsics.StEvalVar(u32 a0, any a1, any a2) .function void Ecmascript.Intrinsics.debugger() .function void Ecmascript.Intrinsics.NativeMethodWrapper(any a0) diff --git a/irtoc_scripts/interpreter_handlers.irt b/irtoc_scripts/interpreter_handlers.irt index 059752d5d..346231c7d 100644 --- a/irtoc_scripts/interpreter_handlers.irt +++ b/irtoc_scripts/interpreter_handlers.irt @@ -117,6 +117,10 @@ macro(:cmpanystring) do |arg| CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_STRING_TYPE").b end +macro(:cmpanybigint) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_BIGINT_TYPE").b +end + macro(:cmpany_notNumber) do |arg| # notNumber(a) is not a synonym of isnan(a) cmpanyobj(arg) end @@ -151,9 +155,15 @@ macro(:any_extractBoolean) do |arg| string_length := ShrI(string_mix_length).Imm(2).u32 arg_stringtoboolean := Compare(string_length, 0).CC(:CC_NE).b } Else { - arg_objtoboolean := AddI(0).Imm(1).b + If(cmpanybigint(arg), 1).CC(:CC_EQ).b { + v7 := ecma_intrinsic_invoke("TobooleanSlow", arg).any + arg_biginttoboolean := AndI(anytou8(v7)).Imm(1).b + } Else { + arg_objtoboolean := AddI(0).Imm(1).b + } + arg_objectlike := Phi(arg_biginttoboolean, arg_objtoboolean).b } - ret := Phi(arg_stringtoboolean, arg_objtoboolean).b + ret := Phi(arg_stringtoboolean, arg_objectlike).b } arg_rawtoboolean_ := Phi(arg_rawtoboolean, ret).b } @@ -1002,16 +1012,6 @@ end # Return(handle_ecma_ldlexenvdyn()) # end -macro(:handle_ecma_throwundefinedifhole) do |id, obj| - IfImm(cmpanyhole(obj)).Imm(0).CC(:CC_NE).b { - ecma_intrinsic_invoke("ThrowUndefinedIfHoleSlow", id, obj) - } -end - -function(:EcmaThrowundefinedifhole, params: {'id'=>'i32', 'obj'=>'any'}, mode: [:Interpreter, :DynamicMethod, :DynamicStub], enable_builder: true) do - Return(handle_ecma_throwundefinedifhole(id, obj)) -end - function(:EcmaLdnull, params: {}, mode: [:Interpreter, :DynamicMethod, :DynamicStub], enable_builder: true) do Return(Constants::TAGGED_NULL) end diff --git a/irtoc_scripts/interpreter_main_loop.irt b/irtoc_scripts/interpreter_main_loop.irt index de6368ec5..8a8749a2e 100644 --- a/irtoc_scripts/interpreter_main_loop.irt +++ b/irtoc_scripts/interpreter_main_loop.irt @@ -92,6 +92,8 @@ handle_ecma_ldconst(Constants::VALUE_UNDEFINED) when "ECMA_LDINFINITY_PREF_NONE" ecma_intrinsic_setacc("Ldinfinity") + when "ECMA_LDBIGINT_PREF_ID32" + ecma_intrinsic_setacc("Ldbigint", as_id(op[0])) when "ECMA_LDNULL_PREF_NONE" handle_ecma_ldconst(Constants::VALUE_NULL) when "ECMA_LDHOLE_PREF_NONE" @@ -158,8 +160,6 @@ ecma_intrinsic_setacc("AsyncFunctionAwait", vreg_value(op[0]).any, acc.any) when "ECMA_ASYNCFUNCTIONREJECT_PREF_V8" ecma_intrinsic_setacc("AsyncFunctionReject", vreg_value(op[0]).any, acc.any) - when "ECMA_DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_V8_V8" - ecma_intrinsic_setacc("DefineClassWithBuffer", as_id(op[0]), as_imm(op[1]), vreg_value(op[2]).any, vreg_value(op[3]).any) when "ECMA_DEFINEMETHOD_PREF_ID16_V8" ecma_intrinsic_setacc("DefineMethod", as_id(op[0]), vreg_value(op[1]).any, acc.any) when "ECMA_DEFINEGETTERSETTERBYVALUE_PREF_V8_V8_V8_V8" @@ -179,15 +179,55 @@ when "ECMA_COPYRESTARGS_PREF_IMM16" ecma_intrinsic_setacc("CopyrestargsInterp", as_imm(op[0])) + #class + when "ECMA_DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_V8_V8" + ecma_intrinsic_setacc("DefineClassWithBuffer", as_id(op[0]), as_imm(op[1]), vreg_value(op[2]).any, vreg_value(op[3]).any) + when "ECMA_LOADCLASSCOMPUTEDINSTANCEFIELDS_PREF_V8" + ecma_intrinsic_setacc("LoadClassComputedInstanceFields", vreg_value(op[0])) + when "ECMA_SETCLASSCOMPUTEDFIELDS_PREF_V8_V8" + ecma_intrinsic_invoke("SetClassComputedFields", vreg_value(op[0]), vreg_value(op[1])) + when "ECMA_CLASSFIELDADD_PREF_V8_V8" + ecma_intrinsic_setacc("ClassFieldAdd", vreg_value(op[0]), vreg_value(op[1]), acc.any) + when "ECMA_DEFINECLASSPRIVATEFIELDS_PREF_ID16_V8" + ecma_intrinsic_invoke("DefineClassPrivateFields", as_id(op[0]), vreg_value(op[1]), acc.any) + when "ECMA_CLASSPRIVATEMETHODORACCESSORADD_PREF_V8_V8" + ecma_intrinsic_setacc("ClassPrivateMethodOrAccessorAdd", vreg_value(op[0]), vreg_value(op[1])) + when "ECMA_CLASSPRIVATEFIELDADD_PREF_ID32_V8_V8" + ecma_intrinsic_setacc("ClassPrivateFieldAdd", as_id(op[0]), vreg_value(op[1]), vreg_value(op[2]), acc.any) + when "ECMA_CLASSPRIVATEFIELDGET_PREF_ID32_V8_V8" + ecma_intrinsic_setacc("ClassPrivateFieldGet", as_id(op[0]), vreg_value(op[1]), vreg_value(op[2])) + when "ECMA_CLASSPRIVATEFIELDSET_PREF_ID32_V8_V8" + ecma_intrinsic_setacc("ClassPrivateFieldSet", as_id(op[0]), vreg_value(op[1]), vreg_value(op[2]), acc.any) + when "ECMA_CLASSPRIVATEFIELDIN_PREF_ID32_V8" + ecma_intrinsic_setacc("ClassPrivateFieldIn", as_id(op[0]), vreg_value(op[1]), acc.any) + + #eval + when "ECMA_LDEVALBINDINGS_PREF_ID16" + ecma_intrinsic_setacc("LdEvalBindings", as_id(op[0])) + when "ECMA_DIRECTEVAL_PREF_IMM32_V8_V8" + ecma_intrinsic_setacc("DirectEval", as_imm(op[0]), vreg_value(op[1]), vreg_value(op[2])) + when "ECMA_LDEVALVAR_PREF_ID32" + ecma_intrinsic_setacc("LdEvalVar", as_id(op[0]), acc.any) + when "ECMA_STEVALVAR_PREF_ID32_V8" + ecma_intrinsic_setacc("StEvalVar", as_id(op[0]), vreg_value(op[1]), acc.any) + # ecma frames - when "ECMA_CALL0DYN_PREF_V8" - ecma_intrinsic_check_setacc("Call0Dyn", i.format.size, vreg_value(op[0]).u64) - when "ECMA_CALL1DYN_PREF_V8_V8" - ecma_intrinsic_check_setacc("Call1Dyn", i.format.size, vreg_value(op[0]).u64, vreg_value(op[1]).u64) - when "ECMA_CALL2DYN_PREF_V8_V8_V8" - ecma_intrinsic_check_setacc("Call2Dyn", i.format.size, vreg_value(op[0]).u64, vreg_value(op[1]).u64, vreg_value(op[2]).u64) - when "ECMA_CALL3DYN_PREF_V8_V8_V8_V8" - ecma_intrinsic_check_setacc("Call3Dyn", i.format.size, vreg_value(op[0]).u64, vreg_value(op[1]).u64, vreg_value(op[2]).u64, vreg_value(op[3]).u64) + when "ECMA_CALL0DYN_PREF_NONE" + ecma_intrinsic_check_setacc("Call0Dyn", i.format.size, acc.u64) + when "ECMA_CALL1DYN_PREF_V8" + ecma_intrinsic_check_setacc("Call1Dyn", i.format.size, vreg_value(op[0]).u64, acc.u64) + when "ECMA_CALL2DYN_PREF_V8_V8" + ecma_intrinsic_check_setacc("Call2Dyn", i.format.size, vreg_value(op[0]).u64, vreg_value(op[1]).u64, acc.u64) + when "ECMA_CALL3DYN_PREF_V8_V8_V8" + ecma_intrinsic_check_setacc("Call3Dyn", i.format.size, vreg_value(op[0]).u64, vreg_value(op[1]).u64, vreg_value(op[2]).u64, acc.u64) + when "ECMA_CALL0THISDYN_PREF_V8" + ecma_intrinsic_check_setacc("Call0ThisDyn", i.format.size, vreg_value(op[0]).u64, acc.u64) + when "ECMA_CALL1THISDYN_PREF_V8_V8" + ecma_intrinsic_check_setacc("Call1ThisDyn", i.format.size, vreg_value(op[0]).u64, vreg_value(op[1]).u64, acc.u64) + when "ECMA_CALL2THISDYN_PREF_V8_V8_V8" + ecma_intrinsic_check_setacc("Call2ThisDyn", i.format.size, vreg_value(op[0]).u64, vreg_value(op[1]).u64, vreg_value(op[2]).u64, acc.u64) + when "ECMA_CALL3THISDYN_PREF_V8_V8_V8_V8" + ecma_intrinsic_check_setacc("Call3ThisDyn", i.format.size, vreg_value(op[0]).u64, vreg_value(op[1]).u64, vreg_value(op[2]).u64, vreg_value(op[3]).u64, acc.u64) when "ECMA_CALLSPREADDYN_PREF_V8_V8_V8" ecma_intrinsic_setacc("CallspreadDyn", vreg_value(op[0]).any, vreg_value(op[1]).any, vreg_value(op[2]).any) when "ECMA_NEWOBJSPREADDYN_PREF_V8_V8" @@ -209,9 +249,15 @@ when "ECMA_STLEXVARDYN_PREF_IMM4_IMM4" ecma_intrinsic_invoke("StLexVarDyn", i8tou16(as_imm(op[0])), i8tou16(as_imm(op[1])), acc.u64) when "ECMA_STLEXVARDYN_PREF_IMM8_IMM8" - ecma_intrinsic_invoke("StLexVarDyn", i8tou16(as_imm(op[0])), i8tou16(as_imm(op[1])), acc.u64) + ecma_intrinsic_setacc("StLexVarDyn", i8tou16(as_imm(op[0])), i8tou16(as_imm(op[1])), acc.u64) when "ECMA_STLEXVARDYN_PREF_IMM16_IMM16" - ecma_intrinsic_invoke("StLexVarDyn", as_imm(op[0]), as_imm(op[1]), acc.u64) + ecma_intrinsic_setacc("StLexVarDyn", as_imm(op[0]), as_imm(op[1]), acc.u64) + when "ECMA_STLEXDYN_PREF_ID32_IMM4_IMM4" + ecma_intrinsic_setacc("StLexDyn", as_id(op[0]), i8tou16(as_imm(op[1])), i8tou16(as_imm(op[2])), acc.u64) + when "ECMA_STLEXDYN_PREF_ID32_IMM8_IMM8" + ecma_intrinsic_setacc("StLexDyn", as_id(op[0]), i8tou16(as_imm(op[1])), i8tou16(as_imm(op[2])), acc.u64) + when "ECMA_STLEXDYN_PREF_ID32_IMM16_IMM16" + ecma_intrinsic_setacc("StLexDyn", as_id(op[0]), as_imm(op[1]), as_imm(op[2]), acc.u64) when "ECMA_LDLEXVARDYN_PREF_IMM4_IMM4" ecma_intrinsic_setacc("LdLexVarDyn", i8tou16(as_imm(op[0])), i8tou16(as_imm(op[1]))) when "ECMA_LDLEXVARDYN_PREF_IMM8_IMM8" @@ -220,6 +266,14 @@ ecma_intrinsic_setacc("LdLexVarDyn", as_imm(op[0]), as_imm(op[1])) when "ECMA_LDHOMEOBJECT_PREF_NONE" ecma_intrinsic_setacc("LdHomeObject") + when "ECMA_LDLEXDYN_PREF_ID32_IMM4_IMM4" + ecma_intrinsic_setacc("LdLexDyn", as_id(op[0]), i8tou16(as_imm(op[1])), i8tou16(as_imm(op[2]))) + when "ECMA_LDLEXDYN_PREF_ID32_IMM8_IMM8" + ecma_intrinsic_setacc("LdLexDyn", as_id(op[0]), i8tou16(as_imm(op[1])), i8tou16(as_imm(op[2]))) + when "ECMA_LDLEXDYN_PREF_ID32_IMM16_IMM16" + ecma_intrinsic_setacc("LdLexDyn", as_id(op[0]), as_imm(op[1]), as_imm(op[2])) + when "ECMA_CREATEEMPTYOBJECT_PREF_NONE" + ecma_intrinsic_setacc("CreateEmptyObject") when "ECMA_RETURNUNDEFINED_PREF_NONE" handle_ecma_ldconst(Constants::VALUE_UNDEFINED) StoreI(%frame, acc).Imm(Constants::GET_ACC_OFFSET).send(acc.type) @@ -228,6 +282,8 @@ Intrinsic(:INTERPRETER_RETURN).ptr when "ECMA_CREATEARRAYWITHBUFFER_PREF_ID16" ecma_intrinsic_setacc("CreateArrayWithBuffer", as_id(op[0])) + when "ECMA_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8" + ecma_intrinsic_setacc("CreateRegExpWithLiteral", as_id(op[0]), as_imm(op[1])) when "ECMA_CREATEEMPTYARRAY_PREF_NONE" ecma_intrinsic_setacc("CreateEmptyArray") when "ECMA_STARRAYSPREAD_PREF_V8_V8" @@ -262,30 +318,30 @@ when "ECMA_STOWNBYINDEX_PREF_IMM32_V8" handle_ecma_stownbyindex(i32tou32(as_imm(op[0])), vreg_value(op[1]).any, acc.any) - when "ECMA_LDOBJBYINDEX_PREF_IMM8_V8" - acc := handle_ecma_ldobjbyindex(i8tou32(as_imm(op[0])), vreg_value(op[1]).any) - when "ECMA_LDOBJBYINDEX_PREF_IMM16_V8" - acc := handle_ecma_ldobjbyindex(i16tou32(as_imm(op[0])), vreg_value(op[1]).any) - when "ECMA_LDOBJBYINDEX_PREF_IMM32_V8" - acc := handle_ecma_ldobjbyindex(i32tou32(as_imm(op[0])), vreg_value(op[1]).any) + when "ECMA_LDOBJBYINDEX_PREF_IMM8" + acc := handle_ecma_ldobjbyindex(i8tou32(as_imm(op[0])), acc.any) + when "ECMA_LDOBJBYINDEX_PREF_IMM16" + acc := handle_ecma_ldobjbyindex(i16tou32(as_imm(op[0])), acc.any) + when "ECMA_LDOBJBYINDEX_PREF_IMM32" + acc := handle_ecma_ldobjbyindex(i32tou32(as_imm(op[0])), acc.any) # ecma load/stores by value when "ECMA_STOBJBYVALUE_PREF_V8_V8" handle_ecma_stobjbyvalue(vreg_value(op[0]).any, vreg_value(op[1]).any, acc.any, ins_offset) - when "ECMA_LDOBJBYVALUE_PREF_V8_V8" - acc := handle_ecma_ldobjbyvalue(vreg_value(op[0]).any, vreg_value(op[1]).any, ins_offset) - when "ECMA_LDSUPERBYVALUE_PREF_V8_V8" - ecma_intrinsic_setacc("LdSuperByValue", vreg_value(op[0]).any, vreg_value(op[1]).any) + when "ECMA_LDOBJBYVALUE_PREF_V8" + acc := handle_ecma_ldobjbyvalue(vreg_value(op[0]).any, acc.any, ins_offset) + when "ECMA_LDSUPERBYVALUE_PREF_V8" + ecma_intrinsic_setacc("LdSuperByValue", vreg_value(op[0]).any, acc.any) when "ECMA_STOWNBYVALUE_PREF_V8_V8" ecma_intrinsic_invoke("StOwnByValue", vreg_value(op[0]).any, vreg_value(op[1]).any, acc.any) # ecma load/stores by name when "ECMA_STOBJBYNAME_PREF_ID32_V8" handle_ecma_stobjbyname(vreg_value(op[1]).any, as_id(op[0]), acc.any, ins_offset) - when "ECMA_LDOBJBYNAME_PREF_ID32_V8" - acc := handle_ecma_ldobjbyname(vreg_value(op[1]).any, as_id(op[0]), ins_offset) - when "ECMA_LDSUPERBYNAME_PREF_ID32_V8" - ecma_intrinsic_setacc("LdSuperByName", as_id(op[0]), vreg_value(op[1]).any) + when "ECMA_LDOBJBYNAME_PREF_ID32" + acc := handle_ecma_ldobjbyname(acc.any, as_id(op[0]), ins_offset) + when "ECMA_LDSUPERBYNAME_PREF_ID32" + ecma_intrinsic_setacc("LdSuperByName", as_id(op[0]), acc.any) when "ECMA_STSUPERBYNAME_PREF_ID32_V8" ecma_intrinsic_invoke("StSuperByName", as_id(op[0]), vreg_value(op[1]).any, acc.any) when "ECMA_STOWNBYNAME_PREF_ID32_V8" @@ -302,8 +358,6 @@ acc := handle_ecma_ldglobalvar(as_id(op[0]), ins_offset) when "ECMA_STGLOBALVAR_PREF_ID32" handle_ecma_stglobalvar(as_id(op[0]), acc.any, ins_offset) - when "ECMA_STGLOBALLET_PREF_ID32" - ecma_intrinsic_invoke("StGlobalLet", as_id(op[0]), acc.any) # ecma generators when "ECMA_CREATEGENERATOROBJ_PREF_V8" @@ -358,8 +412,11 @@ pc := find_catch_block() frame := frame_eh acc := acc_eh - when "ECMA_THROWUNDEFINEDIFHOLE_PREF_ID32" - ecma_intrinsic_setacc("ThrowUndefinedIfHole", as_id(op[0]), acc.any) + when "ECMA_THROWTDZ_PREF_ID32" + ecma_intrinsic_invoke("ThrowTdz", as_id(op[0])) + pc := find_catch_block() + frame := frame_eh + acc := acc_eh when "ECMA_THROWIFNOTOBJECT_PREF_NONE" ecma_intrinsic_invoke("ThrowIfNotObject", acc.any) when "ECMA_THROWIFSUPERNOTCORRECTCALL_PREF_IMM16" diff --git a/isa/isa.yaml b/isa/isa.yaml index 00f3e91d6..5e3719358 100644 --- a/isa/isa.yaml +++ b/isa/isa.yaml @@ -26,6 +26,8 @@ properties: description: Handler is implemented in IRtoC and can be inlined by JIT/AOT. - tag: use_ic description: Instruction uses inline cache + - tag: skip_literal_id_patch + description: Do not patch literal array id namespaces: - namespace: ecmascript @@ -64,153 +66,188 @@ groups: format: [pref_op_none] properties: [inlinable] intrinsic_name: INTRINSIC_LDNAN + - sig: ecma.ldinfinity acc: out:top prefix: ecma format: [pref_op_none] properties: [inlinable] intrinsic_name: INTRINSIC_LDINFINITY + - sig: ecma.ldglobalthis acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_LDGLOBALTHIS + - sig: ecma.ldundefined acc: out:top prefix: ecma format: [pref_op_none] properties: [inlinable] intrinsic_name: INTRINSIC_LDUNDEFINED + - sig: ecma.ldnull acc: out:top prefix: ecma format: [pref_op_none] properties: [inlinable] intrinsic_name: INTRINSIC_LDNULL + - sig: ecma.ldsymbol acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_LDSYMBOL + - sig: ecma.ldglobal acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_LDGLOBAL + - sig: ecma.ldtrue acc: out:top prefix: ecma properties: [inlinable] format: [pref_op_none] intrinsic_name: INTRINSIC_LDTRUE + - sig: ecma.ldfalse acc: out:top prefix: ecma properties: [inlinable] format: [pref_op_none] intrinsic_name: INTRINSIC_LDFALSE + + - sig: ecma.ldbigint string_id + acc: out:top + prefix: ecma + format: [pref_op_id_32] + intrinsic_name: INTRINSIC_LDBIGINT + properties: [string_id] + - sig: ecma.throwdyn acc: in:top prefix: ecma format: [pref_op_none] exceptions: [x_throw] intrinsic_name: INTRINSIC_THROW_DYN + - sig: ecma.rethrowdyn acc: in:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_RETHROW_DYN + - sig: ecma.typeofdyn acc: inout:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_TYPEOF_DYN + - sig: ecma.ldlexenvdyn acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_LDLEXENV_DYN + - sig: ecma.poplexenvdyn acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_POP_LEXENV_DYN + - sig: ecma.getunmappedargs acc: out:top prefix: ecma format: [pref_op_none] properties: [not_compilable] intrinsic_name: INTRINSIC_GET_UNMAPPED_ARGS + - sig: ecma.getpropiterator acc: inout:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_GET_PROP_ITERATOR + - sig: ecma.asyncfunctionenter acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_ASYNC_FUNCTION_ENTER + - sig: ecma.ldhole acc: out:top prefix: ecma format: [pref_op_none] properties: [inlinable] intrinsic_name: INTRINSIC_LDHOLE + - sig: ecma.returnundefined acc: out:top prefix: ecma format: [pref_op_none] properties: [return] intrinsic_name: INTRINSIC_RETURN_UNDEFINED + - sig: ecma.createemptyobject acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_CREATE_EMPTY_OBJECT + - sig: ecma.createemptyarray acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_CREATE_EMPTY_ARRAY + - sig: ecma.getiterator acc: inout:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_GET_ITERATOR + - sig: ecma.getasynciterator acc: inout:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_GET_ASYNC_ITERATOR + - sig: ecma.throwthrownotexists acc: none prefix: ecma format: [pref_op_none] exceptions: [x_throw] intrinsic_name: INTRINSIC_THROW_THROW_NOT_EXISTS + - sig: ecma.throwpatternnoncoercible acc: none prefix: ecma format: [pref_op_none] exceptions: [x_throw] intrinsic_name: INTRINSIC_THROW_PATTERN_NON_COERCIBLE + - sig: ecma.ldhomeobject acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_LD_HOME_OBJECT + - sig: ecma.throwdeletesuperproperty acc: none prefix: ecma format: [pref_op_none] exceptions: [x_throw] intrinsic_name: INTRINSIC_THROW_DELETE_SUPER_PROPERTY + - sig: ecma.debugger acc: none prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_DEBUGGER + - sig: ecma.add2dyn v:in:top acc: inout:top prefix: ecma @@ -218,6 +255,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_ADD2_DYN profile: BinaryArith + - sig: ecma.sub2dyn v:in:top acc: inout:top prefix: ecma @@ -225,6 +263,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_SUB2_DYN profile: BinaryArith + - sig: ecma.mul2dyn v:in:top acc: inout:top prefix: ecma @@ -232,6 +271,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_MUL2_DYN profile: BinaryArith + - sig: ecma.div2dyn v:in:top acc: inout:top prefix: ecma @@ -239,12 +279,14 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_DIV2_DYN profile: BinaryArith + - sig: ecma.mod2dyn v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_MOD2_DYN + - sig: ecma.eqdyn v:in:top acc: inout:top prefix: ecma @@ -252,6 +294,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_EQ_DYN profile: BinaryArith + - sig: ecma.noteqdyn v:in:top acc: inout:top prefix: ecma @@ -259,6 +302,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_NOT_EQ_DYN profile: BinaryArith + - sig: ecma.lessdyn v:in:top acc: inout:top prefix: ecma @@ -266,6 +310,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_LESS_DYN profile: BinaryArith + - sig: ecma.lesseqdyn v:in:top acc: inout:top prefix: ecma @@ -273,6 +318,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_LESS_EQ_DYN profile: BinaryArith + - sig: ecma.greaterdyn v:in:top acc: inout:top prefix: ecma @@ -280,6 +326,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_GREATER_DYN profile: BinaryArith + - sig: ecma.greatereqdyn v:in:top acc: inout:top prefix: ecma @@ -287,6 +334,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_GREATER_EQ_DYN profile: BinaryArith + - sig: ecma.shl2dyn v:in:top acc: inout:top prefix: ecma @@ -294,6 +342,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_SHL2_DYN profile: BinaryArith + - sig: ecma.shr2dyn v:in:top acc: inout:top prefix: ecma @@ -301,11 +350,13 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_SHR2_DYN profile: BinaryArith + - sig: ecma.ashr2dyn v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_ASHR2_DYN + - sig: ecma.and2dyn v:in:top acc: inout:top prefix: ecma @@ -313,6 +364,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_AND2_DYN profile: BinaryArith + - sig: ecma.or2dyn v:in:top acc: inout:top prefix: ecma @@ -320,6 +372,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_OR2_DYN profile: BinaryArith + - sig: ecma.xor2dyn v:in:top acc: inout:top prefix: ecma @@ -327,6 +380,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_XOR2_DYN profile: BinaryArith + - sig: ecma.tonumber v:in:top acc: out:top prefix: ecma @@ -334,6 +388,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_TONUMBER profile: UnaryArith + - sig: ecma.negdyn v:in:top acc: out:top prefix: ecma @@ -341,6 +396,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_NEG_DYN profile: UnaryArith + - sig: ecma.notdyn v:in:top acc: out:top prefix: ecma @@ -348,6 +404,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_NOT_DYN profile: UnaryArith + - sig: ecma.incdyn v:in:top acc: out:top prefix: ecma @@ -355,6 +412,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_INC_DYN profile: UnaryArith + - sig: ecma.decdyn v:in:top acc: out:top prefix: ecma @@ -362,58 +420,69 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_DEC_DYN profile: UnaryArith + - sig: ecma.expdyn v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_EXP_DYN + - sig: ecma.isindyn v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_ISIN_DYN + - sig: ecma.instanceofdyn v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_INSTANCEOF_DYN + - sig: ecma.strictnoteqdyn v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_STRICT_NOT_EQ_DYN + - sig: ecma.stricteqdyn v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_STRICT_EQ_DYN + - sig: ecma.resumegenerator v:in:top acc: out:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_RESUME_GENERATOR + - sig: ecma.getresumemode v:in:top acc: out:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_GET_RESUME_MODE + - sig: ecma.creategeneratorobj v:in:top acc: out:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_CREATE_GENERATOR_OBJ + - sig: ecma.setgeneratorstate v:in:top, imm acc: none prefix: ecma format: [pref_op_v_8_imm_8] intrinsic_name: INTRINSIC_SET_GENERATOR_STATE + - sig: ecma.createasyncgeneratorobj v:in:top acc: out:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_CREATE_ASYNC_GENERATOR_OBJ + - sig: ecma.throwconstassignment string_id acc: none prefix: ecma @@ -421,450 +490,661 @@ groups: exceptions: [x_throw] properties: [string_id] intrinsic_name: INTRINSIC_THROW_CONST_ASSIGNMENT + - sig: ecma.getmethod string_id, v:in:top acc: out:top prefix: ecma format: [pref_op_id_32_v_8] properties: [string_id] intrinsic_name: INTRINSIC_GET_METHOD + - sig: ecma.gettemplateobject v:in:top acc: out:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_GET_TEMPLATE_OBJECT + - sig: ecma.getnextpropname v:in:top acc: out:top prefix: ecma format: [pref_op_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_GET_NEXT_PROP_NAME - - sig: ecma.call0dyn v:in:top - acc: out:top - prefix: ecma - format: [pref_op_v_8] - properties: [call] - intrinsic_name: INTRINSIC_CALL0_DYN + - sig: ecma.throwifnotobject acc: in:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_THROW_IF_NOT_OBJECT + - sig: ecma.closeiterator v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_CLOSE_ITERATOR + - sig: ecma.copymodule v:in:top acc: out:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_COPY_MODULE + - sig: ecma.supercallspread v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_SUPER_CALL_SPREAD + - sig: ecma.delobjprop v1:in:top, v2:in:top acc: out:top prefix: ecma format: [pref_op_v1_8_v2_8] intrinsic_name: INTRINSIC_DELOBJPROP + - sig: ecma.newobjspreaddyn v1:in:top, v2:in:top acc: inout:top prefix: ecma format: [pref_op_v1_8_v2_8] intrinsic_name: INTRINSIC_NEWOBJSPREAD_DYN + - sig: ecma.createiterresultobj imm acc: inout:top prefix: ecma format: [pref_op_imm_8] intrinsic_name: INTRINSIC_CREATE_ITER_RESULT_OBJ + - sig: ecma.suspendgenerator v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] properties: [return, not_compilable, suspend] intrinsic_name: INTRINSIC_SUSPEND_GENERATOR + - sig: ecma.suspendasyncgenerator v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] properties: [return, not_compilable, suspend] intrinsic_name: INTRINSIC_SUSPEND_ASYNC_GENERATOR + - sig: ecma.asyncfunctionawait v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_ASYNC_FUNCTION_AWAIT - - sig: ecma.throwundefinedifhole string_id - acc: in:top + + - sig: ecma.throwtdz string_id + acc: none prefix: ecma format: [pref_op_id_32] - properties: [string_id, inlinable] - intrinsic_name: INTRINSIC_THROW_UNDEFINED_IF_HOLE - - sig: ecma.call1dyn v1:in:top, v2:in:top - acc: out:top - prefix: ecma - format: [pref_op_v1_8_v2_8] - properties: [call] - intrinsic_name: INTRINSIC_CALL1_DYN + properties: [string_id] + exceptions: [x_throw] + intrinsic_name: INTRINSIC_THROW_TDZ + - sig: ecma.copydataproperties v1:in:top, v2:in:top acc: out:top prefix: ecma format: [pref_op_v1_8_v2_8] intrinsic_name: INTRINSIC_COPY_DATA_PROPERTIES + - sig: ecma.starrayspread v1:in:top, v2:in:top acc: inout:top prefix: ecma format: [pref_op_v1_8_v2_8] intrinsic_name: INTRINSIC_ST_ARRAY_SPREAD + - sig: ecma.setobjectwithproto v1:in:top, v2:in:top acc: none prefix: ecma format: [pref_op_v1_8_v2_8] intrinsic_name: INTRINSIC_SET_OBJECT_WITH_PROTO - - sig: ecma.ldobjbyvalue v1:in:top, v2:in:top - acc: out:top + + - sig: ecma.ldobjbyvalue v:in:top + acc: inout:top prefix: ecma - format: [pref_op_v1_8_v2_8] + format: [pref_op_v_8] properties: [use_ic, inlinable] intrinsic_name: INTRINSIC_LD_OBJ_BY_VALUE + - sig: ecma.stobjbyvalue v1:in:top, v2:in:top acc: in:top prefix: ecma format: [pref_op_v1_8_v2_8] properties: [use_ic, inlinable] intrinsic_name: INTRINSIC_ST_OBJ_BY_VALUE + - sig: ecma.stownbyvalue v1:in:top, v2:in:top acc: in:top prefix: ecma format: [pref_op_v1_8_v2_8] intrinsic_name: INTRINSIC_ST_OWN_BY_VALUE - - sig: ecma.ldsuperbyvalue v1:in:top, v2:in:top - acc: out:top + + - sig: ecma.ldsuperbyvalue v:in:top + acc: inout:top prefix: ecma - format: [pref_op_v1_8_v2_8] + format: [pref_op_v_8] intrinsic_name: INTRINSIC_LD_SUPER_BY_VALUE + - sig: ecma.stsuperbyvalue v1:in:top, v2:in:top acc: in:top prefix: ecma format: [pref_op_v1_8_v2_8] intrinsic_name: INTRINSIC_ST_SUPER_BY_VALUE - - sig: ecma.ldobjbyindex imm, v:in:top - acc: out:top + + - sig: ecma.ldobjbyindex imm + acc: inout:top prefix: ecma - format: [pref_op_imm_8_v_8] + format: [pref_op_imm_8] properties: [inlinable] intrinsic_name: INTRINSIC_LD_OBJ_BY_INDEX - - sig: ecma.ldobjbyindex imm, v:in:top - acc: out:top + + - sig: ecma.ldobjbyindex imm + acc: inout:top prefix: ecma - format: [pref_op_imm_16_v_8] + format: [pref_op_imm_16] properties: [inlinable] intrinsic_name: INTRINSIC_LD_OBJ_BY_INDEX - - sig: ecma.ldobjbyindex imm, v:in:top - acc: out:top + + - sig: ecma.ldobjbyindex imm + acc: inout:top prefix: ecma - format: [pref_op_imm_32_v_8] + format: [pref_op_imm_32] properties: [inlinable] intrinsic_name: INTRINSIC_LD_OBJ_BY_INDEX + - sig: ecma.stobjbyindex imm, v:in:top acc: in:top prefix: ecma format: [pref_op_imm_8_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_ST_OBJ_BY_INDEX + - sig: ecma.stobjbyindex imm, v:in:top acc: in:top prefix: ecma format: [pref_op_imm_16_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_ST_OBJ_BY_INDEX + - sig: ecma.stobjbyindex imm, v:in:top acc: in:top prefix: ecma format: [pref_op_imm_32_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_ST_OBJ_BY_INDEX + - sig: ecma.stownbyindex imm, v:in:top acc: in:top prefix: ecma format: [pref_op_imm_8_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_ST_OWN_BY_INDEX + - sig: ecma.stownbyindex imm, v:in:top acc: in:top prefix: ecma format: [pref_op_imm_16_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_ST_OWN_BY_INDEX + - sig: ecma.stownbyindex imm, v:in:top acc: in:top prefix: ecma format: [pref_op_imm_32_v_8] properties: [inlinable] intrinsic_name: INTRINSIC_ST_OWN_BY_INDEX + - sig: ecma.callspreaddyn v1:in:top, v2:in:top, v3:in:top acc: out:top prefix: ecma format: [pref_op_v1_8_v2_8_v3_8] intrinsic_name: INTRINSIC_CALLSPREAD_DYN + - sig: ecma.asyncfunctionresolve v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_ASYNC_FUNCTION_RESOLVE + - sig: ecma.asyncfunctionreject v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_ASYNC_FUNCTION_REJECT + - sig: ecma.asyncgeneratorresolve v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_ASYNC_GENERATOR_RESOLVE + - sig: ecma.asyncgeneratorreject v:in:top acc: inout:top prefix: ecma format: [pref_op_v_8] intrinsic_name: INTRINSIC_ASYNC_GENERATOR_REJECT - - sig: ecma.call2dyn v1:in:top, v2:in:top, v3:in:top - acc: out:top + + - sig: ecma.call0dyn + acc: inout:top prefix: ecma - format: [pref_op_v1_8_v2_8_v3_8] + format: [pref_op_none] properties: [call] - intrinsic_name: INTRINSIC_CALL2_DYN - - sig: ecma.call3dyn v1:in:top, v2:in:top, v3:in:top, v4:in:top - acc: out:top + intrinsic_name: INTRINSIC_CALL0_DYN + + - sig: ecma.call1dyn v:in:top + acc: inout:top prefix: ecma - format: [pref_op_v1_8_v2_8_v3_8_v4_8] + format: [pref_op_v_8] properties: [call] - intrinsic_name: INTRINSIC_CALL3_DYN - - sig: ecma.definegettersetterbyvalue v1:in:top, v2:in:top, v3:in:top, v4:in:top + intrinsic_name: INTRINSIC_CALL1_DYN + + - sig: ecma.call2dyn v1:in:top, v2:in:top acc: inout:top prefix: ecma - format: [pref_op_v1_8_v2_8_v3_8_v4_8] - intrinsic_name: INTRINSIC_DEFINE_GETTER_SETTER_BY_VALUE - - sig: ecma.newobjdynrange imm, v:in:top - acc: out:top + format: [pref_op_v1_8_v2_8] + properties: [call] + intrinsic_name: INTRINSIC_CALL2_DYN + + - sig: ecma.call3dyn v1:in:top, v2:in:top, v3:in:top + acc: inout:top prefix: ecma - format: [pref_op_imm_16_v_8] - properties: [not_compilable] - intrinsic_name: INTRINSIC_NEWOBJ_DYNRANGE + format: [pref_op_v1_8_v2_8_v3_8] + properties: [call] + intrinsic_name: INTRINSIC_CALL3_DYN + - sig: ecma.callirangedyn imm, v:in:top acc: out:top prefix: ecma format: [pref_op_imm_16_v_8] properties: [call] intrinsic_name: INTRINSIC_CALLI_RANGE_DYN + + - sig: ecma.call0thisdyn v:in:top + acc: inout:top + prefix: ecma + format: [pref_op_v_8] + properties: [call] + intrinsic_name: INTRINSIC_CALL0_THIS_DYN + + - sig: ecma.call1thisdyn v1:in:top, v2:in:top + acc: inout:top + prefix: ecma + format: [pref_op_v1_8_v2_8] + properties: [call] + intrinsic_name: INTRINSIC_CALL1_THIS_DYN + + - sig: ecma.call2thisdyn v1:in:top, v2:in:top, v3:in:top + acc: inout:top + prefix: ecma + format: [pref_op_v1_8_v2_8_v3_8] + properties: [call] + intrinsic_name: INTRINSIC_CALL2_THIS_DYN + + - sig: ecma.call3thisdyn v1:in:top, v2:in:top, v3:in:top, v4:in:top + acc: inout:top + prefix: ecma + format: [pref_op_v1_8_v2_8_v3_8_v4_8] + properties: [call] + intrinsic_name: INTRINSIC_CALL3_THIS_DYN + - sig: ecma.callithisrangedyn imm, v:in:top acc: out:top prefix: ecma format: [pref_op_imm_16_v_8] properties: [call] intrinsic_name: INTRINSIC_CALLI_THIS_RANGE_DYN + + - sig: ecma.definegettersetterbyvalue v1:in:top, v2:in:top, v3:in:top, v4:in:top + acc: inout:top + prefix: ecma + format: [pref_op_v1_8_v2_8_v3_8_v4_8] + intrinsic_name: INTRINSIC_DEFINE_GETTER_SETTER_BY_VALUE + + - sig: ecma.newobjdynrange imm, v:in:top + acc: out:top + prefix: ecma + format: [pref_op_imm_16_v_8] + properties: [not_compilable] + intrinsic_name: INTRINSIC_NEWOBJ_DYNRANGE + - sig: ecma.supercall imm, v:in:top acc: inout:top prefix: ecma format: [pref_op_imm_16_v_8] properties: [not_compilable] intrinsic_name: INTRINSIC_SUPER_CALL + - sig: ecma.createobjectwithexcludedkeys imm, v1:in:top, v2:in:top acc: out:top prefix: ecma format: [pref_op_imm_16_v1_8_v2_8] properties: [not_compilable] intrinsic_name: INTRINSIC_CREATE_OBJECT_WITH_EXCLUDED_KEYS + - sig: ecma.definefuncdyn method_id, v:in:top acc: out:top prefix: ecma format: [pref_op_id_16_v_8] properties: [method_id] intrinsic_name: INTRINSIC_DEFINEFUNC_DYN + - sig: ecma.definencfuncdyn method_id, v:in:top acc: inout:top prefix: ecma format: [pref_op_id_16_v_8] properties: [method_id] intrinsic_name: INTRINSIC_DEFINE_NC_FUNC_DYN + - sig: ecma.definegeneratorfunc method_id, v:in:top acc: out:top prefix: ecma format: [pref_op_id_16_v_8] properties: [method_id] intrinsic_name: INTRINSIC_DEFINE_GENERATOR_FUNC + - sig: ecma.defineasyncfunc method_id, v:in:top acc: out:top prefix: ecma format: [pref_op_id_16_v_8] properties: [method_id] intrinsic_name: INTRINSIC_DEFINE_ASYNC_FUNC + - sig: ecma.defineasyncgeneratorfunc method_id, v:in:top acc: out:top prefix: ecma format: [pref_op_id_16_v_8] properties: [method_id] intrinsic_name: INTRINSIC_DEFINE_ASYNC_GENERATOR_FUNC + - sig: ecma.definemethod method_id, v:in:top acc: inout:top prefix: ecma format: [pref_op_id_16_v_8] properties: [method_id] intrinsic_name: INTRINSIC_DEFINE_METHOD + - sig: ecma.newlexenvdyn imm acc: out:top prefix: ecma format: [pref_op_imm_16] intrinsic_name: INTRINSIC_NEWLEXENV_DYN + - sig: ecma.copylexenvdyn acc: out:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_COPYLEXENV_DYN + - sig: ecma.copyrestargs imm acc: out:top prefix: ecma format: [pref_op_imm_16] properties: [not_compilable] intrinsic_name: INTRINSIC_COPYRESTARGS + + - sig: ecma.createregexpwithliteral string_id, imm + acc: out:top + prefix: ecma + format: [pref_op_id_32_imm_8] + properties: [string_id] + intrinsic_name: INTRINSIC_CREATE_REG_EXP_WITH_LITERAL + - sig: ecma.createarraywithbuffer literalarray_id acc: out:top prefix: ecma format: [pref_op_id_16] properties: [literalarray_id] intrinsic_name: INTRINSIC_CREATE_ARRAY_WITH_BUFFER + - sig: ecma.createobjecthavingmethod literalarray_id acc: inout:top prefix: ecma format: [pref_op_id_16] properties: [literalarray_id] intrinsic_name: INTRINSIC_CREATE_OBJECT_HAVING_METHOD + - sig: ecma.throwifsupernotcorrectcall imm acc: in:top prefix: ecma format: [pref_op_imm_16] intrinsic_name: INTRINSIC_THROW_IF_SUPER_NOT_CORRECT_CALL + - sig: ecma.createobjectwithbuffer literalarray_id acc: out:top prefix: ecma format: [pref_op_id_16] properties: [literalarray_id] intrinsic_name: INTRINSIC_CREATE_OBJECT_WITH_BUFFER + - sig: ecma.ldlexvardyn imm1, imm2 acc: out:top prefix: ecma format: [pref_op_imm1_4_imm2_4] intrinsic_name: INTRINSIC_LD_LEX_VAR_DYN + - sig: ecma.ldlexvardyn imm1, imm2 acc: out:top prefix: ecma format: [pref_op_imm1_8_imm2_8] intrinsic_name: INTRINSIC_LD_LEX_VAR_DYN + - sig: ecma.ldlexvardyn imm1, imm2 acc: out:top prefix: ecma format: [pref_op_imm1_16_imm2_16] intrinsic_name: INTRINSIC_LD_LEX_VAR_DYN + + - sig: ecma.ldlexdyn string_id, imm1, imm2 + acc: out:top + prefix: ecma + format: [pref_op_id_32_imm1_4_imm2_4] + intrinsic_name: INTRINSIC_LD_LEX_DYN + properties: [string_id] + + - sig: ecma.ldlexdyn string_id, imm1, imm2 + acc: out:top + prefix: ecma + format: [pref_op_id_32_imm1_8_imm2_8] + properties: [string_id] + intrinsic_name: INTRINSIC_LD_LEX_DYN + + - sig: ecma.ldlexdyn string_id, imm1, imm2 + acc: out:top + prefix: ecma + format: [pref_op_id_32_imm1_16_imm2_16] + properties: [string_id] + intrinsic_name: INTRINSIC_LD_LEX_DYN + - sig: ecma.stlexvardyn imm1, imm2 acc: in:top prefix: ecma format: [pref_op_imm1_4_imm2_4] intrinsic_name: INTRINSIC_ST_LEX_VAR_DYN + + - sig: ecma.loadclasscomputedinstancefields v:in:top + acc: out:top + prefix: ecma + format: [pref_op_v_8] + intrinsic_name: INTRINSIC_LOAD_CLASS_COMPUTED_INSTANCE_FIELDS + + - sig: ecma.setclasscomputedfields v1:in:top, v2:in:top + acc: none + prefix: ecma + format: [pref_op_v1_8_v2_8] + intrinsic_name: INTRINSIC_SET_CLASS_COMPUTED_FIELDS + - sig: ecma.stlexvardyn imm1, imm2 acc: in:top prefix: ecma format: [pref_op_imm1_8_imm2_8] intrinsic_name: INTRINSIC_ST_LEX_VAR_DYN + - sig: ecma.stlexvardyn imm1, imm2 acc: in:top prefix: ecma format: [pref_op_imm1_16_imm2_16] intrinsic_name: INTRINSIC_ST_LEX_VAR_DYN + + - sig: ecma.stlexdyn string_id, imm1, imm2 + acc: inout:top + prefix: ecma + format: [pref_op_id_32_imm1_4_imm2_4] + properties: [string_id] + intrinsic_name: INTRINSIC_ST_LEX_DYN + + - sig: ecma.stlexdyn string_id, imm1, imm2 + acc: inout:top + prefix: ecma + format: [pref_op_id_32_imm1_8_imm2_8] + properties: [string_id] + intrinsic_name: INTRINSIC_ST_LEX_DYN + + - sig: ecma.stlexdyn string_id, imm1, imm2 + acc: inout:top + prefix: ecma + format: [pref_op_id_32_imm1_16_imm2_16] + properties: [string_id] + intrinsic_name: INTRINSIC_ST_LEX_DYN + - sig: ecma.defineclasswithbuffer method_id, imm, v1:in:top, v2:in:top acc: out:top prefix: ecma format: [pref_op_id_16_imm_16_v1_8_v2_8] intrinsic_name: INTRINSIC_DEFINE_CLASS_WITH_BUFFER - properties: [method_id] + properties: [method_id, literalarray_id] + + - sig: ecma.classfieldadd v1:in:top, v2:in:top + acc: in:top + prefix: ecma + format: [pref_op_v1_8_v2_8] + intrinsic_name: INTRINSIC_CLASS_FIELD_ADD + + - sig: ecma.defineclassprivatefields literalarray_id, v:in:top + acc: in:top + prefix: ecma + format: [pref_op_id_16_v_8] + intrinsic_name: INTRINSIC_DEFINE_CLASS_PRIVATE_FIELDS + properties: [literalarray_id] + + - sig: ecma.classprivatemethodoraccessoradd v1:in:top, v2:in:top + acc: none + prefix: ecma + format: [pref_op_v1_8_v2_8] + intrinsic_name: INTRINSIC_CLASS_PRIVATE_METHOD_OR_ACCESSOR_ADD + + - sig: ecma.classprivatefieldadd string_id, v1:in:top, v2:in:top + acc: in:top + prefix: ecma + format: [pref_op_id_32_v1_8_v2_8] + intrinsic_name: INTRINSIC_CLASS_PRIVATE_FIELD_ADD + properties: [string_id] + + - sig: ecma.classprivatefieldget string_id, v1:in:top, v2:in:top + acc: out:top + prefix: ecma + format: [pref_op_id_32_v1_8_v2_8] + intrinsic_name: INTRINSIC_CLASS_PRIVATE_FIELD_GET + properties: [string_id] + + - sig: ecma.classprivatefieldset string_id, v1:in:top, v2:in:top + acc: in:top + prefix: ecma + format: [pref_op_id_32_v1_8_v2_8] + intrinsic_name: INTRINSIC_CLASS_PRIVATE_FIELD_SET + properties: [string_id] + + - sig: ecma.classprivatefieldin string_id, v:in:top + acc: inout:top + prefix: ecma + format: [pref_op_id_32_v_8] + intrinsic_name: INTRINSIC_CLASS_PRIVATE_FIELD_IN + properties: [string_id] + + - sig: ecma.importmodule string_id acc: out:top prefix: ecma format: [pref_op_id_32] properties: [string_id] intrinsic_name: INTRINSIC_IMPORT_MODULE + - sig: ecma.stmodulevar string_id acc: in:top prefix: ecma format: [pref_op_id_32] properties: [string_id] intrinsic_name: INTRINSIC_ST_MODULE_VAR + - sig: ecma.tryldglobalbyname string_id acc: out:top prefix: ecma format: [pref_op_id_32] properties: [string_id, use_ic, inlinable] intrinsic_name: INTRINSIC_TRY_LD_GLOBAL_BY_NAME + - sig: ecma.trystglobalbyname string_id acc: in:top prefix: ecma format: [pref_op_id_32] properties: [string_id, use_ic] intrinsic_name: INTRINSIC_TRY_ST_GLOBAL_BY_NAME + - sig: ecma.ldglobalvar string_id acc: out:top prefix: ecma format: [pref_op_id_32] properties: [string_id, use_ic, inlinable] intrinsic_name: INTRINSIC_LD_GLOBAL_VAR + - sig: ecma.stglobalvar string_id acc: in:top prefix: ecma format: [pref_op_id_32] properties: [string_id, use_ic, inlinable] intrinsic_name: INTRINSIC_ST_GLOBAL_VAR - - sig: ecma.stgloballet string_id - acc: in:top + + - sig: ecma.ldobjbyname string_id + acc: inout:top prefix: ecma format: [pref_op_id_32] - properties: [string_id] - intrinsic_name: INTRINSIC_ST_GLOBAL_LET - - sig: ecma.ldobjbyname string_id, v:in:top - acc: out:top - prefix: ecma - format: [pref_op_id_32_v_8] properties: [string_id, use_ic, inlinable] intrinsic_name: INTRINSIC_LD_OBJ_BY_NAME + - sig: ecma.stobjbyname string_id, v:in:top acc: in:top prefix: ecma format: [pref_op_id_32_v_8] properties: [string_id, use_ic, inlinable] intrinsic_name: INTRINSIC_ST_OBJ_BY_NAME + - sig: ecma.stownbyname string_id, v:in:top acc: in:top prefix: ecma format: [pref_op_id_32_v_8] properties: [string_id] intrinsic_name: INTRINSIC_ST_OWN_BY_NAME - - sig: ecma.ldsuperbyname string_id, v:in:top - acc: out:top + + - sig: ecma.ldsuperbyname string_id + acc: inout:top prefix: ecma - format: [pref_op_id_32_v_8] + format: [pref_op_id_32] properties: [string_id] intrinsic_name: INTRINSIC_LD_SUPER_BY_NAME + - sig: ecma.stsuperbyname string_id, v:in:top acc: in:top prefix: ecma format: [pref_op_id_32_v_8] properties: [string_id] intrinsic_name: INTRINSIC_ST_SUPER_BY_NAME + - sig: ecma.ldmodvarbyname string_id, v:in:top acc: out:top prefix: ecma format: [pref_op_id_32_v_8] properties: [string_id] intrinsic_name: INTRINSIC_LD_MODVAR_BY_NAME + - sig: ecma.toboolean acc: inout:top prefix: ecma @@ -872,6 +1152,7 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_TOBOOLEAN profile: UnaryArith + - sig: ecma.negate acc: inout:top prefix: ecma @@ -879,44 +1160,78 @@ groups: properties: [inlinable] intrinsic_name: INTRINSIC_NEGATE profile: UnaryArith + - sig: ecma.istrue acc: inout:top prefix: ecma format: [pref_op_none] properties: [inlinable] intrinsic_name: INTRINSIC_IS_TRUE + - sig: ecma.isfalse acc: inout:top prefix: ecma format: [pref_op_none] properties: [inlinable] intrinsic_name: INTRINSIC_IS_FALSE + - sig: ecma.isundefined acc: inout:top prefix: ecma format: [pref_op_none] properties: [inlinable] intrinsic_name: INTRINSIC_IS_UNDEFINED + - sig: ecma.iscoercible acc: inout:top prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_IS_COERCIBLE + - sig: ecma.jfalse imm:i32 acc: in:top prefix: ecma format: [pref_op_imm_8, pref_op_imm_16, pref_op_imm_32] properties: [jump, conditional] intrinsic_name: INTRINSIC_JFALSE_DYN + - sig: ecma.jtrue imm:i32 acc: in:top prefix: ecma format: [pref_op_imm_8, pref_op_imm_16, pref_op_imm_32] properties: [jump, conditional] intrinsic_name: INTRINSIC_JTRUE_DYN + - sig: ecma.return.dyn acc: in:any prefix: ecma format: [pref_op_none] intrinsic_name: INTRINSIC_RETURN_DYN properties: [return] + + - sig: ecma.ldevalbindings literalarray_id + acc: out:top + prefix: ecma + format: [pref_op_id_16] + intrinsic_name: INTRINSIC_LD_EVAL_BINDINGS + properties: [literalarray_id, skip_literal_id_patch] + + - sig: ecma.directeval imm, v1:in:top, v2:in:top + acc: out:top + prefix: ecma + format: [pref_op_imm_32_v1_8_v2_8] + intrinsic_name: INTRINSIC_DIRECT_EVAL + + - sig: ecma.ldevalvar string_id + acc: inout:top + prefix: ecma + format: [pref_op_id_32] + properties: [string_id] + intrinsic_name: INTRINSIC_LD_EVAL_VAR + + - sig: ecma.stevalvar string_id, v:in:top + acc: inout:top + prefix: ecma + format: [pref_op_id_32_v_8] + properties: [string_id] + intrinsic_name: INTRINSIC_ST_EVAL_VAR diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 56b25a893..8d1401e02 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -66,6 +66,7 @@ set(ECMASCRIPT_SOURCES ${ECMA_SRC_DIR}/builtins/builtins_async_from_sync_iterator.cpp ${ECMA_SRC_DIR}/builtins/builtins_async_generator.cpp ${ECMA_SRC_DIR}/builtins/builtins_async_iterator.cpp + ${ECMA_SRC_DIR}/builtins/builtins_bigint.cpp ${ECMA_SRC_DIR}/builtins/builtins_boolean.cpp ${ECMA_SRC_DIR}/builtins/builtins_dataview.cpp ${ECMA_SRC_DIR}/builtins/builtins_date.cpp @@ -129,8 +130,10 @@ set(ECMASCRIPT_SOURCES ${ECMA_SRC_DIR}/js_async_from_sync_iterator_object.cpp ${ECMA_SRC_DIR}/js_async_function.cpp ${ECMA_SRC_DIR}/js_async_generator_object.cpp + ${ECMA_SRC_DIR}/js_bigint.cpp ${ECMA_SRC_DIR}/js_dataview.cpp ${ECMA_SRC_DIR}/js_date.cpp + ${ECMA_SRC_DIR}/js_eval.cpp ${ECMA_SRC_DIR}/js_for_in_iterator.cpp ${ECMA_SRC_DIR}/js_function.cpp ${ECMA_SRC_DIR}/js_generator_object.cpp @@ -226,6 +229,15 @@ target_include_directories(arkruntime_static PUBLIC ${ECMA_GEN_DIR} ) +# Suppress warning for line `target_link_libraries(arkruntime_static es2panda-lib arkassembler)`: +# Attempt to add link library "es2panda-lib" to target "arkruntime_static" which is not built in this directory. + +if(POLICY CMP0079) + cmake_policy(SET CMP0079 NEW) +endif() + +target_link_libraries(arkruntime_static es2panda-lib arkassembler) + set(RUNTIME_TEMPLATES intrinsics_gen.cpp.erb ) diff --git a/runtime/asm_defines/asm_defines.def b/runtime/asm_defines/asm_defines.def index f51225178..4c79c9bb3 100644 --- a/runtime/asm_defines/asm_defines.def +++ b/runtime/asm_defines/asm_defines.def @@ -11,6 +11,7 @@ DEFINE_VALUE(JSTYPE_JS_OBJECT_BEGIN, static_cast(panda::ecmascript::JST DEFINE_VALUE(JSTYPE_JS_OBJECT_END, static_cast(panda::ecmascript::JSType::JS_OBJECT_END)) DEFINE_VALUE(JSTYPE_STRING, static_cast(panda::ecmascript::JSType::STRING)) DEFINE_VALUE(JSTYPE_SYMBOL, static_cast(panda::ecmascript::JSType::SYMBOL)) +DEFINE_VALUE(JSTYPE_BIGINT, static_cast(panda::ecmascript::JSType::BIGINT)) 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)) diff --git a/runtime/base/number_helper.cpp b/runtime/base/number_helper.cpp index 47a7003a8..20b55df38 100644 --- a/runtime/base/number_helper.cpp +++ b/runtime/base/number_helper.cpp @@ -326,6 +326,94 @@ PandaString NumberHelper::IntToString(int number) return ToPandaString(number); } +JSTaggedValue NumberHelper::StringToBigInt(JSThread *thread, JSHandle strVal) +{ + Span str; + auto strObj = static_cast(strVal->GetTaggedObject()); + size_t strLen = strObj->GetLength(); + if (strLen == 0) { + return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue(); + } + if (UNLIKELY(strObj->IsUtf16())) { + PandaVector buf; + size_t len = base::utf_helper::Utf16ToUtf8Size(strObj->GetDataUtf16(), strLen) - 1; + buf.reserve(len); + len = base::utf_helper::ConvertRegionUtf16ToUtf8(strObj->GetDataUtf16(), buf.data(), strLen, len, 0); + str = Span(buf.data(), len); + } else { + str = Span(strObj->GetDataUtf8(), strLen); + } + auto p = const_cast(str.begin()); + auto end = str.end(); + // 1. skip space and line terminal + if (!NumberHelper::GotoNonspace(&p, end)) { + return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue(); + } + // 2. get bigint sign + Sign sign = Sign::NONE; + if (*p == '+') { + RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE)); + sign = Sign::POS; + } else if (*p == '-') { + RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE)); + sign = Sign::NEG; + } + // 3. bigint not allow Infinity, decimal points, or exponents. + if (isalpha(*p) != 0) { + return JSTaggedValue(NAN_VALUE); + } + // 4. get bigint radix + uint8_t radix = DECIMAL; + if (*p == '0') { + if (++p == end) { + return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue(); + } + if (*p == 'x' || *p == 'X') { + RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE)); + if (sign != Sign::NONE) { + return JSTaggedValue(NAN_VALUE); + } + radix = HEXADECIMAL; + } else if (*p == 'o' || *p == 'O') { + RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE)); + if (sign != Sign::NONE) { + return JSTaggedValue(NAN_VALUE); + } + radix = OCTAL; + } else if (*p == 'b' || *p == 'B') { + RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE)); + if (sign != Sign::NONE) { + return JSTaggedValue(NAN_VALUE); + } + radix = BINARY; + } + } + + auto pStart = p; + // 5. skip leading '0' + while (*p == '0') { + if (++p == end) { + return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue(); + } + } + // 6. parse to bigint + std::string buffer; + if (sign == Sign::NEG) { + buffer += "-"; + } + do { + uint8_t c = ToDigit(*p); + if (c >= radix) { + if (pStart != p && !NumberHelper::GotoNonspace(&p, end)) { + break; + } + return JSTaggedValue(NAN_VALUE); + } + buffer += *p; + } while (++p != end); + return BigIntHelper::SetBigInt(thread, buffer, radix).GetTaggedValue(); +} + JSTaggedValue NumberHelper::Pow(double base, double exponent) { // The result of base ** exponent when base is 1 or -1 and exponent is +Infinity diff --git a/runtime/base/number_helper.h b/runtime/base/number_helper.h index 3b26925d1..a68ab871a 100644 --- a/runtime/base/number_helper.h +++ b/runtime/base/number_helper.h @@ -91,6 +91,7 @@ public: static JSTaggedValue DoubleToPrecision(JSThread *thread, double number, int digit); static JSTaggedValue StringToDoubleWithRadix(const uint8_t *start, const uint8_t *end, int radix); static PandaString IntToString(int number); + static JSTaggedValue StringToBigInt(JSThread *thread, JSHandle strVal); private: static char Carry(char current, int radix); diff --git a/runtime/base/typed_array_helper-inl.h b/runtime/base/typed_array_helper-inl.h index 4c9defbbd..b74e7f9a7 100644 --- a/runtime/base/typed_array_helper-inl.h +++ b/runtime/base/typed_array_helper-inl.h @@ -54,8 +54,12 @@ DataViewType TypedArrayHelper::GetType(const JSHandle &obj) return DataViewType::UINT32; case JSType::JS_FLOAT32_ARRAY: return DataViewType::FLOAT32; - default: + case JSType::JS_FLOAT64_ARRAY: return DataViewType::FLOAT64; + case JSType::JS_BIGINT64_ARRAY: + return DataViewType::BIGINT64; + default: + return DataViewType::BIGUINT64; } } @@ -106,7 +110,13 @@ DataViewType TypedArrayHelper::GetTypeFromName(JSThread *thread, const JSHandle< if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat32ArrayString())) { return DataViewType::FLOAT32; } - return DataViewType::FLOAT64; + if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat64ArrayString())) { + return DataViewType::FLOAT64; + } + if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledBigInt64ArrayString())) { + return DataViewType::BIGINT64; + } + return DataViewType::BIGUINT64; } JSHandle TypedArrayHelper::GetConstructor(JSThread *thread, const JSHandle &obj) @@ -130,8 +140,12 @@ JSHandle TypedArrayHelper::GetConstructor(JSThread *thread, const return env->GetUint32ArrayFunction(); case JSType::JS_FLOAT32_ARRAY: return env->GetFloat32ArrayFunction(); - default: + case JSType::JS_FLOAT64_ARRAY: return env->GetFloat64ArrayFunction(); + case JSType::JS_BIGINT64_ARRAY: + return env->GetBigInt64ArrayFunction(); + default: + return env->GetBigUint64ArrayFunction(); } } @@ -163,7 +177,13 @@ JSHandle TypedArrayHelper::GetConstructorFromName(JSThread *thread, if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat32ArrayString())) { return JSHandle(env->GetFloat32ArrayFunction()); } - return JSHandle(env->GetFloat64ArrayFunction()); + if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat64ArrayString())) { + return JSHandle(env->GetFloat64ArrayFunction()); + } + if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledBigInt64ArrayString())) { + return JSHandle(env->GetBigInt64ArrayFunction()); + } + return JSHandle(env->GetBigUint64ArrayFunction()); } int32_t TypedArrayHelper::GetSizeFromName(JSThread *thread, const JSHandle &typeName) diff --git a/runtime/base/typed_array_helper.cpp b/runtime/base/typed_array_helper.cpp index 13cf8934e..e99a7737b 100644 --- a/runtime/base/typed_array_helper.cpp +++ b/runtime/base/typed_array_helper.cpp @@ -233,11 +233,10 @@ JSTaggedValue TypedArrayHelper::CreateFromTypedArray(EcmaRuntimeCallInfo *argv, for (int32_t count = elementLength; count > 0; count--) { // i. Let value be GetValueFromBuffer(srcData, srcByteIndex, srcType, true, Unordered). JSTaggedValue taggedData = - BuiltinsArrayBuffer::GetValueFromBuffer(srcData.GetTaggedValue(), srcByteIndex, srcType, true); + BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcData.GetTaggedValue(), srcByteIndex, srcType, true); value.Update(taggedData); - JSTaggedNumber numVal = JSTaggedValue::ToNumber(thread, value); // ii. Perform SetValueInBuffer(data, targetByteIndex, elementType, value, true, Unordered). - BuiltinsArrayBuffer::SetValueInBuffer(data, targetByteIndex, elementType, numVal, true); + BuiltinsArrayBuffer::SetValueInBuffer(thread, data, targetByteIndex, elementType, value, true); // iii. Set srcByteIndex to srcByteIndex + srcElementSize. // iv. Set targetByteIndex to targetByteIndex + elementSize. // v. Set count to count - 1. @@ -343,6 +342,17 @@ JSHandle TypedArrayHelper::AllocateTypedArray(ObjectFactory *factory, RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle(thread, JSTaggedValue::Exception())); // 3. Assert: obj.[[ViewedArrayBuffer]] is undefined. // 4. Set obj.[[TypedArrayName]] to constructorName. + + // 5. If constructorName is "BigInt64Array" or "BigUint64Array", set obj.[[ContentType]] to BigInt. + // 6. Otherwise, set obj.[[ContentType]] to Number. + JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj); + if (JSTaggedValue::SameValue(constructorName, thread->GlobalConstants()->GetHandledBigInt64ArrayString()) || + JSTaggedValue::SameValue(constructorName, thread->GlobalConstants()->GetHandledBigUint64ArrayString())) { + jsTypedArray->SetContentType(ContentType::BigInt); + } else { + jsTypedArray->SetContentType(ContentType::Number); + } + // 7. If length is not present, then // a. Set obj.[[ByteLength]] to 0. // b. Set obj.[[ByteOffset]] to 0. @@ -403,6 +413,13 @@ JSHandle TypedArrayHelper::AllocateTypedArrayBuffer(JSThread *thread, JSHandle constructor = env->GetArrayBufferFunction(); JSTaggedValue data = BuiltinsArrayBuffer::AllocateArrayBuffer(thread, constructor, byteLength); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exception); + JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj); + if (JSTaggedValue::SameValue(constructorName, thread->GlobalConstants()->GetHandledBigInt64ArrayString()) || + JSTaggedValue::SameValue(constructorName, thread->GlobalConstants()->GetHandledBigUint64ArrayString())) { + jsTypedArray->SetContentType(ContentType::BigInt); + } else { + jsTypedArray->SetContentType(ContentType::Number); + } // 8. Set O.[[ViewedArrayBuffer]] to data. // 9. Set O.[[ByteLength]] to byteLength. // 10. Set O.[[ByteOffset]] to 0. @@ -490,7 +507,7 @@ int32_t TypedArrayHelper::SortCompare(JSThread *thread, const JSHandleGlobalConstants(); // 1. Assert: Both Type(x) and Type(y) is Number. - ASSERT(firstValue->IsNumber() && secondValue->IsNumber()); + ASSERT((firstValue->IsNumber() && secondValue->IsNumber()) || (firstValue->IsBigInt() && secondValue->IsBigInt())); // 2. If the argument comparefn is not undefined, then // a. Let v be Call(comparefn, undefined, «x, y»). // b. ReturnIfAbrupt(v). diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_call0dyn_pref_none_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_call0dyn_pref_none_aarch64.S new file mode 100644 index 000000000..3ce199c70 --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_call0dyn_pref_none_aarch64.S @@ -0,0 +1,57 @@ +/** + * 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. + */ + +// uint64_t EcmaResolveSecondArgument(uint64_t function_tagged_value); +.extern EcmaResolveSecondArgument + +// handle ecma.call0dyn +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc (functional object), x13, x14 - temp + + ldr w14, [x15, JSFUNCTION_FUNCTION_INFO_FLAG_OFFSET] + tbz w14, JSFUNCTION_FUNCTION_INFO_FLAG_IS_STRICT_START_BIT, 1f + // (x14) <- resolved this + mov x14, #TAGGED_VALUE_UNDEFINED + b 2f + +1: + mov x0, x15 + stp x12, x15, [sp, #-16]! + bl EcmaResolveSecondArgument + ldp x12, x15, [sp], #16 + // (x14) <- resolved this + mov x14, x0 + +2: + // ABI arg reg 0 (x0) <- panda::Method* + mov x0, x12 + + // ABI arg reg 1 (x1) <- number of arguments + mov x1, #3 // mandatory params + + // Reserve stack args + sub sp, sp, (4 * FRAME_VREGISTER_SIZE) + + // ABI arg stack <- functional object + str x15, [sp, 0 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- new.target + mov x2, #TAGGED_VALUE_UNDEFINED + str x2, [sp, 1 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- resolved this + str x14, [sp, 2 * FRAME_VREGISTER_SIZE] + + b .Linvoke diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_call0thisdyn_pref_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_call0thisdyn_pref_v8_aarch64.S new file mode 100644 index 000000000..06ab06d72 --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_call0thisdyn_pref_v8_aarch64.S @@ -0,0 +1,42 @@ +/** + * 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. + */ + +// handle ecma.call0thisdyn +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp + + // ABI arg reg 0 (x0) <- panda::Method* + mov x0, x12 + + // ABI arg reg 1 (x1) <- number of arguments + mov x1, #3 // mandatory params + + // Reserve stack args + sub sp, sp, (4 * FRAME_VREGISTER_SIZE) + + // ABI arg stack <- functional object + ldrb w13, [x10], #1 + ldr x14, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) + str x14, [sp, 0 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- new.target + mov x2, #TAGGED_VALUE_UNDEFINED + str x2, [sp, 1 * FRAME_VREGISTER_SIZE] + + + // ABI arg stack <- resolved this + str x15, [sp, 2 * FRAME_VREGISTER_SIZE] + + b .Linvoke diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_call1dyn_pref_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_call1dyn_pref_v8_aarch64.S new file mode 100644 index 000000000..f72d8eac3 --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_call1dyn_pref_v8_aarch64.S @@ -0,0 +1,26 @@ +/** + * 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. + */ + +// handle ecma.call1dyn +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp + + // ABI arg reg 1 (x1) <- number of arguments + mov x1, #4 // mandatory params + arg0 +#include "handle_call_ecma_calldyn_helper_aarch64.S" + + // ABI arg stack <- arg 1 + str x15, [sp, 3 * FRAME_VREGISTER_SIZE] + b .Linvoke diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_call1thisdyn_pref_v8_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_call1thisdyn_pref_v8_v8_aarch64.S new file mode 100644 index 000000000..c53137ad7 --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_call1thisdyn_pref_v8_v8_aarch64.S @@ -0,0 +1,26 @@ +/** + * 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. + */ + +// handle ecma.call1thisdyn +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp + + // ABI arg reg 1 (x1) <- number of arguments + mov x1, #4 // mandatory params + arg0 +#include "handle_call_ecma_callthisdyn_helper_aarch64.S" + + // ABI arg stack <- arg 1 + str x15, [sp, 3 * FRAME_VREGISTER_SIZE] + b .Linvoke diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_call2dyn_pref_v8_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_call2dyn_pref_v8_v8_aarch64.S new file mode 100644 index 000000000..1705e00af --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_call2dyn_pref_v8_v8_aarch64.S @@ -0,0 +1,31 @@ +/** + * 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. + */ + +// handle ecma.call2dyn +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp + + // ABI arg reg 1 (x1) <- number of arguments + mov x1, #5 // mandatory params + arg0 + arg1 +#include "handle_call_ecma_calldyn_helper_aarch64.S" + + // ABI arg stack <- arg 1 + ldrb w13, [x10], #1 + ldr x14, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) + str x14, [sp, 3 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- arg 2 + str x15, [sp, 4 * FRAME_VREGISTER_SIZE] + b .Linvoke diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_aarch64.S new file mode 100644 index 000000000..490751f67 --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_aarch64.S @@ -0,0 +1,31 @@ +/** + * 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. + */ + +// handle ecma.call2thisdyn +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp + + // ABI arg reg 1 (x1) <- number of arguments + mov x1, #5 // mandatory params + arg0 + arg1 +#include "handle_call_ecma_callthisdyn_helper_aarch64.S" + + // ABI arg stack <- arg 1 + ldrb w13, [x10], #1 + ldr x14, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) + str x14, [sp, 3 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- arg 2 + str x15, [sp, 4 * FRAME_VREGISTER_SIZE] + b .Linvoke diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_call3dyn_pref_v8_v8_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_call3dyn_pref_v8_v8_v8_aarch64.S new file mode 100644 index 000000000..b44697d87 --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_call3dyn_pref_v8_v8_v8_aarch64.S @@ -0,0 +1,36 @@ +/** + * 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. + */ + +// handle ecma.call3dyn +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp + + // ABI arg reg 1 (x1) <- number of arguments + mov x1, #6 // mandatory params + arg0 + arg1 + arg2 +#include "handle_call_ecma_calldyn_helper_aarch64.S" + + // ABI arg stack <- arg 1 + ldrb w13, [x10], #1 + ldr x14, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) + str x14, [sp, 3 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- arg 2 + ldrb w13, [x10], #1 + ldr x14, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) + str x14, [sp, 4 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- arg 3 + str x15, [sp, 5 * FRAME_VREGISTER_SIZE] + b .Linvoke diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_aarch64.S new file mode 100644 index 000000000..cf7ba7662 --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_aarch64.S @@ -0,0 +1,36 @@ +/** + * 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. + */ + +// handle ecma.call3thisdyn +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp + + // ABI arg reg 1 (x1) <- number of arguments + mov x1, #6 // mandatory params + arg0 + arg1 + arg2 +#include "handle_call_ecma_callthisdyn_helper_aarch64.S" + + // ABI arg stack <- arg 1 + ldrb w13, [x10], #1 + ldr x14, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) + str x14, [sp, 3 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- arg 2 + ldrb w13, [x10], #1 + ldr x14, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) + str x14, [sp, 4 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- arg 3 + str x15, [sp, 5 * FRAME_VREGISTER_SIZE] + b .Linvoke diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_N_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_calldyn_helper_aarch64.S similarity index 52% rename from runtime/bridge/arch/aarch64/handle_call_ecma_N_v8_aarch64.S rename to runtime/bridge/arch/aarch64/handle_call_ecma_calldyn_helper_aarch64.S index f5cb6ba01..0fecfcb22 100644 --- a/runtime/bridge/arch/aarch64/handle_call_ecma_N_v8_aarch64.S +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_calldyn_helper_aarch64.S @@ -16,57 +16,21 @@ // uint64_t EcmaResolveSecondArgument(uint64_t function_tagged_value); .extern EcmaResolveSecondArgument -// handle ecma.call0dyn, ecma.call1dyn, ecma.call2dyn, ecma.call3dyn +// Prepare mandatory params for ecma.call1dyn, ecma.call2dyn, ecma.call3dyn // regs set as follow -// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - number of passed arguments, x13, x14 - temp +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp - // w15 <- num_args // + new.target + calculated argument - add w15, w15, 2 + // (x13) <- functional object + ldrb w13, [x10], #1 + ldr x13, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) - // x13 <- func (v0) - ldrb w13, [x10, 0] - ldr x13, [x9, x13, lsl 3] - - // x14 <- resolved this ldr w14, [x13, JSFUNCTION_FUNCTION_INFO_FLAG_OFFSET] - tbz w14, JSFUNCTION_FUNCTION_INFO_FLAG_IS_STRICT_START_BIT, 3f - mov w14, TAGGED_VALUE_UNDEFINED -1: - - // ABI arg reg 0 <- panda::Method* - // ABI arg reg 1 <- num_args - mov x0, x12 - mov w1, w15 - - // Reserve stack args - // x12 <- stack pointer - sub x12, sp, x15, lsl 3 - and x12, x12, -16 - mov sp, x12 - - // stack arg0 <- func (v0) - // stack arg1 <- new_target (undefined) - // stack arg3 <- resolved this - str x13, [x12, 0 * 8] - mov x13, TAGGED_VALUE_UNDEFINED - str x13, [x12, 1 * 8] - str x14, [x12, 2 * 8] - - subs w15, w15, 3 - beq .Linvoke - - add x12, x12, ((3 - 1) * 8) -2: - ldrb w13, [x10, x15] - ldr x13, [x9, x13, lsl 3] - str x13, [x12, x15, lsl 3] - subs x15, x15, 1 - bhi 2b - - b .Linvoke + tbz w14, JSFUNCTION_FUNCTION_INFO_FLAG_IS_STRICT_START_BIT, 1f + // (x14) <- resolved this + mov x14, TAGGED_VALUE_UNDEFINED + b 2f -3: - // !IsStrict slowpath +1: stp x9, x10, [sp, #-16]! stp x12, x13, [sp, #-16]! stp x14, x15, [sp, #-16]! @@ -75,5 +39,26 @@ ldp x14, x15, [sp], #16 ldp x12, x13, [sp], #16 ldp x9, x10, [sp], #16 + // ABI arg reg 4 (x4) <- resolved this mov x14, x0 - b 1b + +2: + // ABI arg reg 0 (x0) <- panda::Method* + mov x0, x12 + + // Reserve stack args + sub x2, sp, x1, lsl 3 + and x2, x2, -16 + mov sp, x2 + + // arg stack <- functional object + str x13, [sp, 0 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- new.target + mov x2, #TAGGED_VALUE_UNDEFINED + str x2, [sp, 1 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- resolved this + str x14, [sp, 2 * FRAME_VREGISTER_SIZE] + + diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_callirangedyn_pref_imm16_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_callirangedyn_pref_imm16_v8_aarch64.S index 254a38601..d52dacef0 100644 --- a/runtime/bridge/arch/aarch64/handle_call_ecma_callirangedyn_pref_imm16_v8_aarch64.S +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_callirangedyn_pref_imm16_v8_aarch64.S @@ -18,7 +18,7 @@ // handle ecma.callirangedyn // regs set as follow -// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x13-x15 - temp +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp // w15 <- num_args ldrh w15, [x10, 0] diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_aarch64.S index 3448a51cd..ac2849dce 100644 --- a/runtime/bridge/arch/aarch64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_aarch64.S +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_aarch64.S @@ -15,7 +15,7 @@ // handle ecma.callithisrangedyn // regs set as follow -// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x13-x15 - temp +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp // w15 <- num_args ldrh w15, [x10, 0] diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_callthisdyn_helper_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_callthisdyn_helper_aarch64.S new file mode 100644 index 000000000..e7b5cbba6 --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_callthisdyn_helper_aarch64.S @@ -0,0 +1,41 @@ +/** + * 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. + */ + +// Prepare mandatory params for ecma.call1thisdyn, ecma.call2thisdyn, ecma.call3thisdyn +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp + + // ABI arg reg 0 (x0) <- panda::Method* + mov x0, x12 + + // Reserve stack args + sub x2, sp, x1, lsl 3 + and x2, x2, -16 + mov sp, x2 + + // arg stack <- functional object + ldrb w13, [x10], #1 + ldr x14, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) + str x14, [sp, 0 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- new.target + mov x2, #TAGGED_VALUE_UNDEFINED + str x2, [sp, 1 * FRAME_VREGISTER_SIZE] + + // ABI arg stack <- this + ldrb w13, [x10], #1 + ldr x14, [x9, x13, lsl #3] // log2(FRAME_VREGISTER_SIZE) + str x14, [sp, 2 * FRAME_VREGISTER_SIZE] + diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_call0dyn_pref_none_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_call0dyn_pref_none_amd64.S new file mode 100644 index 000000000..635c76525 --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_call0dyn_pref_none_amd64.S @@ -0,0 +1,55 @@ +/** + * 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. + */ + +// uint64_t EcmaResolveSecondArgument(uint64_t function_tagged_value); +.extern EcmaResolveSecondArgument + +// handle ecma.call0dyn +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc (functional object), %r13, %r14 - temp + + movl JSFUNCTION_FUNCTION_INFO_FLAG_OFFSET(%r15), %r14d + andl $(1 << JSFUNCTION_FUNCTION_INFO_FLAG_IS_STRICT_START_BIT), %r14d + jz 1f + // (r14) <- resolved this + movq $TAGGED_VALUE_UNDEFINED, %r14 + jmp 2f + +1: + // !IsStrict slowpath + movq %r15, %rdi + // (r14) <- resolved this + callq EcmaResolveSecondArgument@plt + movq %rax, %r14 + +2: + // ABI arg reg 0 (rdi) <- panda::Method* + movq %r12, %rdi + + // ABI arg reg 1 (rsi) <- number of arguments + movq $3, %rsi // mandatory params + + subq $(4 * FRAME_VREGISTER_SIZE), %rsp // functional object + new.target + this + + // ABI arg stack <- functional object + movq %r15, (0 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- new.target + movq $TAGGED_VALUE_UNDEFINED, (1 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- resolved this + movq %r14, (2 * FRAME_VREGISTER_SIZE)(%rsp) + + jmp .Linvoke diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_call0thisdyn_pref_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_call0thisdyn_pref_v8_amd64.S new file mode 100644 index 000000000..2c315884b --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_call0thisdyn_pref_v8_amd64.S @@ -0,0 +1,39 @@ +/** + * 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. + */ + +// handle ecma.callthis0dyn +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp + + // ABI arg reg 0 (rdi) <- panda::Method* + movq %r12, %rdi + + // ABI arg reg 1 (rsi) <- number of arguments + movq $3, %rsi // mandatory params + + subq $(4 * FRAME_VREGISTER_SIZE), %rsp // functional object + new.target + this + + // ABI arg stack <- functional object + movzbl (%rax), %r13d + movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r14 + movq %r14, (%rsp) + + // ABI arg stack <- new.target + movq $TAGGED_VALUE_UNDEFINED, FRAME_VREGISTER_SIZE(%rsp) + + // ABI arg stack <- this + movq %r15, (2 * FRAME_VREGISTER_SIZE)(%rsp) + + jmp .Linvoke diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_call1dyn_pref_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_call1dyn_pref_v8_amd64.S new file mode 100644 index 000000000..7597660f0 --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_call1dyn_pref_v8_amd64.S @@ -0,0 +1,27 @@ +/** + * 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. + */ + +// handle ecma.call1dyn +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp + + // ABI arg reg 1 (rsi) <- number of arguments + movq $4, %rsi // mandatory params + arg0 +#include "handle_call_ecma_calldyn_helper_amd64.S" + + // ABI arg stack <- arg1 + movq %r15, (3 * FRAME_VREGISTER_SIZE)(%rsp) + + jmp .Linvoke diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_call1thisdyn_pref_v8_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_call1thisdyn_pref_v8_v8_amd64.S new file mode 100644 index 000000000..453fb115a --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_call1thisdyn_pref_v8_v8_amd64.S @@ -0,0 +1,27 @@ +/** + * 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. + */ + +// handle ecma.callthis1dyn +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp + + // ABI arg reg 1 (rsi) <- number of arguments + movq $4, %rsi // mandatory params + arg0 +#include "handle_call_ecma_callthisdyn_helper_amd64.S" + + // ABI arg stack <- arg1 + movq %r15, (3 * FRAME_VREGISTER_SIZE)(%rsp) + + jmp .Linvoke diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_call2dyn_pref_v8_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_call2dyn_pref_v8_v8_amd64.S new file mode 100644 index 000000000..6ef6b7ce1 --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_call2dyn_pref_v8_v8_amd64.S @@ -0,0 +1,32 @@ +/** + * 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. + */ + +// handle ecma.call2dyn +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp + + // ABI arg reg 1 (rsi) <- number of arguments + movq $5, %rsi // mandatory params + arg0 + arg1 +#include "handle_call_ecma_calldyn_helper_amd64.S" + + // ABI arg stack <- arg1 + movzbl 1(%rax), %r13d + movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r14 + movq %r14, (3 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- arg2 + movq %r15, (4 * FRAME_VREGISTER_SIZE)(%rsp) + + jmp .Linvoke diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_amd64.S new file mode 100644 index 000000000..81e1ae8e2 --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_amd64.S @@ -0,0 +1,32 @@ +/** + * 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. + */ + +// handle ecma.callthis2dyn +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp + + // ABI arg reg 1 (rsi) <- number of arguments + movq $5, %rsi // mandatory params + arg0 + arg1 +#include "handle_call_ecma_callthisdyn_helper_amd64.S" + + // ABI arg stack <- arg1 + movzbl 2(%rax), %r13d + movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r14 + movq %r14, (3 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- arg2 + movq %r15, (4 * FRAME_VREGISTER_SIZE)(%rsp) + + jmp .Linvoke diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_call3dyn_pref_v8_v8_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_call3dyn_pref_v8_v8_v8_amd64.S new file mode 100644 index 000000000..170240d7b --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_call3dyn_pref_v8_v8_v8_amd64.S @@ -0,0 +1,37 @@ +/** + * 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. + */ + +// handle ecma.call3dyn +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp + + // ABI arg reg 1 (rsi) <- number of arguments + movq $6, %rsi // mandatory params + arg0 + arg1 + arg2 +#include "handle_call_ecma_calldyn_helper_amd64.S" + + // ABI arg stack <- arg1 + movzbl 1(%rax), %r13d + movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r14 + movq %r14, (3 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- arg2 + movzbl 2(%rax), %r13d + movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r14 + movq %r14, (4 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- arg3 + movq %r15, (5 * FRAME_VREGISTER_SIZE)(%rsp) + + jmp .Linvoke diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_amd64.S new file mode 100644 index 000000000..7a3ee55cd --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_amd64.S @@ -0,0 +1,37 @@ +/** + * 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. + */ + +// handle ecma.call3thisdyn +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp + + // ABI arg reg 1 (rsi) <- number of arguments + movq $6, %rsi // mandatory params + arg0 + arg1 + arg2 +#include "handle_call_ecma_callthisdyn_helper_amd64.S" + + // ABI arg stack <- arg1 + movzbl 2(%rax), %r13d + movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r14 + movq %r14, (3 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- arg2 + movzbl 3(%rax), %r13d + movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r14 + movq %r14, (4 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- arg3 + movq %r15, (5 * FRAME_VREGISTER_SIZE)(%rsp) + + jmp .Linvoke diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_N_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_calldyn_helper_amd64.S similarity index 54% rename from runtime/bridge/arch/amd64/handle_call_ecma_N_v8_amd64.S rename to runtime/bridge/arch/amd64/handle_call_ecma_calldyn_helper_amd64.S index 9654999f5..5d044c468 100644 --- a/runtime/bridge/arch/amd64/handle_call_ecma_N_v8_amd64.S +++ b/runtime/bridge/arch/amd64/handle_call_ecma_calldyn_helper_amd64.S @@ -16,60 +16,45 @@ // uint64_t EcmaResolveSecondArgument(uint64_t function_tagged_value); .extern EcmaResolveSecondArgument -// handle ecma.call0dyn, ecma.call1dyn, ecma.call2dyn, ecma.call3dyn +// Prepare mandatory params for ecma.call1dyn, ecma.call2dyn, ecma.call3dyn // regs set as follow -// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - number of passed arguments, %r13, %r14 - temp +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp - // r15d <- num_args // + new.target + calculated argument - addl $2, %r15d - - // r13 <- func (v0) - movzbl 0(%rax), %r13d + // (%r13) <- functional object + movzbl (%rax), %r13d movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r13 - // r14 <- resolved this movl JSFUNCTION_FUNCTION_INFO_FLAG_OFFSET(%r13), %r14d andl $(1 << JSFUNCTION_FUNCTION_INFO_FLAG_IS_STRICT_START_BIT), %r14d - jz 3f + jz 1f + // (r14) <- resolved this movq $TAGGED_VALUE_UNDEFINED, %r14 + jmp 2f + 1: + // !IsStrict slowpath + movq %r13, %rdi + movq %rax, %r9 + // (r14) <- resolved this + callq EcmaResolveSecondArgument@plt + movq %rax, %r14 + movq %r9, %rax +2: // ABI arg reg 0 (rdi) <- panda::Method* - // ABI arg reg 1 (rsi) <- num_args movq %r12, %rdi - movq %r15, %rsi // Reserve stack args - // %r12 <- stack pointer - leal (, %r15d, 8), %r12d - subq %r12, %rsp + leal (, %rsi, 8), %r9d + subq %r9, %rsp andq $-16, %rsp - movq %rsp, %r12 - // stack arg0 <- func (v0) - // stack arg1 <- new_target (undefined) - // stack arg3 <- resolved this - movq %r13, (0 * 8)(%r12) - movq $TAGGED_VALUE_UNDEFINED, (1 * 8)(%r12) - movq %r14, (2 * 8)(%r12) + // ABI arg stack <- functional object + movq %r13, (0 * FRAME_VREGISTER_SIZE)(%rsp) - subl $3, %r15d - jz .Linvoke + // ABI arg stack <- new.target + movq $TAGGED_VALUE_UNDEFINED, (1 * FRAME_VREGISTER_SIZE)(%rsp) - addq $((3 - 1) * 8), %r12 -2: - movzbl (%rax, %r15), %r13d - movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r13 - movq %r13, (%r12, %r15, 8) - subl $1, %r15d - ja 2b + // ABI arg stack <- resolved this + movq %r14, (2 * FRAME_VREGISTER_SIZE)(%rsp) - jmp .Linvoke - -3: - // !IsStrict slowpath - movq %rax, %r14 - movq %r13, %rdi - callq EcmaResolveSecondArgument@plt - jmp 1b - xchgq %rax, %r14 diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_callirangedyn_pref_imm16_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_callirangedyn_pref_imm16_v8_amd64.S index 2909e5793..1d4e7a16e 100644 --- a/runtime/bridge/arch/amd64/handle_call_ecma_callirangedyn_pref_imm16_v8_amd64.S +++ b/runtime/bridge/arch/amd64/handle_call_ecma_callirangedyn_pref_imm16_v8_amd64.S @@ -18,7 +18,7 @@ // handle ecma.callirangedyn // regs set as follow -// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r13, %r14, %r15 - temp +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp // r15d <- num_args movzwl 0(%rax), %r15d diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_amd64.S index 5d3c56950..cd42ddedf 100644 --- a/runtime/bridge/arch/amd64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_amd64.S +++ b/runtime/bridge/arch/amd64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_amd64.S @@ -15,7 +15,7 @@ // handle ecma.callithisrangedyn // regs set as follow -// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r13, %r14, %r15 - temp +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp // r15d <- num_args movzwl (%rax), %r15d diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_callthisdyn_helper_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_callthisdyn_helper_amd64.S new file mode 100644 index 000000000..32f341402 --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_callthisdyn_helper_amd64.S @@ -0,0 +1,38 @@ +/** + * 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. + */ + +// Prepare mandatory params for ecma.call1thisdyn, ecma.call2thisdyn, ecma.call3thisdyn +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp + // ABI arg reg 0 (rdi) <- panda::Method* + movq %r12, %rdi + + // Reserve stack args + leal (, %rsi, 8), %r8d + subq %r8, %rsp + andq $-16, %rsp + + // ABI arg stack <- functional object + movzbl (%rax), %r13d + movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r14 + movq %r14, (0 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- new.target + movq $TAGGED_VALUE_UNDEFINED, (1 * FRAME_VREGISTER_SIZE)(%rsp) + + // ABI arg stack <- resolved this + movzbl 1(%rax), %r13d + movq (%rbx, %r13, FRAME_VREGISTER_SIZE), %r14 + movq %r14, (2 * FRAME_VREGISTER_SIZE)(%rsp) diff --git a/runtime/bridge/arch/arm/handle_call_ecma_call0dyn_pref_none_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_call0dyn_pref_none_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_call0dyn_pref_none_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/bridge/arch/arm/handle_call_ecma_call0thisdyn_pref_v8_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_call0thisdyn_pref_v8_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_call0thisdyn_pref_v8_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/bridge/arch/arm/handle_call_ecma_call1dyn_pref_v8_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_call1dyn_pref_v8_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_call1dyn_pref_v8_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/bridge/arch/arm/handle_call_ecma_call1thisdyn_pref_v8_v8_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_call1thisdyn_pref_v8_v8_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_call1thisdyn_pref_v8_v8_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/bridge/arch/arm/handle_call_ecma_call2dyn_pref_v8_v8_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_call2dyn_pref_v8_v8_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_call2dyn_pref_v8_v8_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/bridge/arch/arm/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_call2thisdyn_pref_v8_v8_v8_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/bridge/arch/arm/handle_call_ecma_call3dyn_pref_v8_v8_v8_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_call3dyn_pref_v8_v8_v8_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_call3dyn_pref_v8_v8_v8_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/bridge/arch/arm/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_call3thisdyn_pref_v8_v8_v8_v8_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/bridge/arch/arm/handle_call_ecma_calldyn_helper_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_calldyn_helper_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_calldyn_helper_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/bridge/arch/arm/handle_call_ecma_callthisdyn_helper_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_callthisdyn_helper_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_callthisdyn_helper_arm.S @@ -0,0 +1,16 @@ +/** + * 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. + */ + +// The bridge is not supported currently diff --git a/runtime/builtins.cpp b/runtime/builtins.cpp index ee50d0a3b..52cefc0a0 100644 --- a/runtime/builtins.cpp +++ b/runtime/builtins.cpp @@ -26,6 +26,7 @@ #include "plugins/ecmascript/runtime/builtins/builtins_async_function.h" #include "plugins/ecmascript/runtime/builtins/builtins_async_generator.h" #include "plugins/ecmascript/runtime/builtins/builtins_async_iterator.h" +#include "plugins/ecmascript/runtime/builtins/builtins_bigint.h" #include "plugins/ecmascript/runtime/builtins/builtins_boolean.h" #include "plugins/ecmascript/runtime/builtins/builtins_collator.h" #include "plugins/ecmascript/runtime/builtins/builtins_dataview.h" @@ -103,6 +104,7 @@ using Number = builtins::BuiltinsNumber; using Object = builtins::BuiltinsObject; using Date = builtins::BuiltinsDate; using Symbol = builtins::BuiltinsSymbol; +using BuiltinsBigInt = builtins::BuiltinsBigInt; using Boolean = builtins::BuiltinsBoolean; using BuiltinsMap = builtins::BuiltinsMap; using BuiltinsSet = builtins::BuiltinsSet; @@ -278,6 +280,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread) } InitializeNumber(env, globalObject, primRefObjDynclass); + InitializeBigInt(env, objFuncDynclass); InitializeDate(env, objFuncDynclass); InitializeObject(env, objFuncPrototype, objectFunction); InitializeBoolean(env, primRefObjDynclass); @@ -378,7 +381,7 @@ void Builtins::InitializeGlobalObject(const JSHandle &env, const JSHa #endif // Global object function - SetFunction(env, globalObject, "eval", Global::NotSupportEval, FunctionLength::ONE); + SetFunction(env, globalObject, "eval", Global::Eval, FunctionLength::ONE); SetFunction(env, globalObject, "isFinite", Global::IsFinite, FunctionLength::ONE); SetFunction(env, globalObject, "isNaN", Global::IsNaN, FunctionLength::ONE); SetFunction(env, globalObject, "unescape", Global::Unescape, FunctionLength::ONE); @@ -781,6 +784,35 @@ void Builtins::InitializeNumber(const JSHandle &env, const JSHandleSetNumberFunction(thread_, numFunction); } +void Builtins::InitializeBigInt(const JSHandle &env, const JSHandle &objFuncDynclass) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + // BigInt.prototype + JSHandle bigIntFuncPrototype = factory_->NewJSObject(objFuncDynclass); + JSHandle bigIntFuncPrototypeValue(bigIntFuncPrototype); + + // BigInt.prototype_or_dynclass + JSHandle bigIntFuncInstanceDynclass = + factory_->NewEcmaDynClass(JSPrimitiveRef::SIZE, JSType::JS_PRIMITIVE_REF, bigIntFuncPrototypeValue); + // BigInt = new Function() + JSHandle bigIntFunction(NewBuiltinConstructor(env, bigIntFuncPrototype, BuiltinsBigInt::BigIntConstructor, + "BigInt", FunctionLength::ONE)); + JSHandle(bigIntFunction)->SetFunctionPrototype(thread_, bigIntFuncInstanceDynclass.GetTaggedValue()); + + // BigInt.prototype method + SetFunction(env, bigIntFuncPrototype, "toLocaleString", BuiltinsBigInt::ToLocaleString, FunctionLength::ZERO); + SetFunction(env, bigIntFuncPrototype, "toString", BuiltinsBigInt::ToString, FunctionLength::ZERO); + SetFunction(env, bigIntFuncPrototype, "valueOf", BuiltinsBigInt::ValueOf, FunctionLength::ZERO); + + // BigInt method + SetFunction(env, bigIntFunction, "asUintN", BuiltinsBigInt::AsUintN, FunctionLength::TWO); + SetFunction(env, bigIntFunction, "asIntN", BuiltinsBigInt::AsIntN, FunctionLength::TWO); + + // @@ToStringTag + SetStringTagSymbol(env, bigIntFuncPrototype, "BigInt"); + env->SetBigIntFunction(thread_, bigIntFunction); +} + void Builtins::InitializeDate(const JSHandle &env, const JSHandle &objFuncDynclass) const { [[maybe_unused]] EcmaHandleScope scope(thread_); @@ -1953,6 +1985,8 @@ void Builtins::InitializeTypedArray(const JSHandle &env, const JSHand InitializeUint32Array(env, typedArrFuncInstanceDynclass); InitializeFloat32Array(env, typedArrFuncInstanceDynclass); InitializeFloat64Array(env, typedArrFuncInstanceDynclass); + InitializeBigInt64Array(env, typedArrFuncInstanceDynclass); + InitializeBigUint64Array(env, typedArrFuncInstanceDynclass); } void Builtins::InitializeInt8Array(const JSHandle &env, const JSHandle &objFuncDynclass) const @@ -2173,6 +2207,54 @@ void Builtins::InitializeFloat64Array(const JSHandle &env, const JSHa env->SetFloat64ArrayFunction(thread_, float64ArrayFunction); } +void Builtins::InitializeBigInt64Array(const JSHandle &env, const JSHandle &objFuncDynclass) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + // BigInt64Array.prototype + JSHandle bigInt64ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass); + JSHandle bigInt64ArrFuncPrototypeValue(bigInt64ArrFuncPrototype); + + // BigInt64Array.prototype_or_dynclass + JSHandle bigInt64ArrFuncInstanceDynclass = factory_->NewEcmaDynClass( + panda::ecmascript::JSTypedArray::SIZE, JSType::JS_BIGINT64_ARRAY, bigInt64ArrFuncPrototypeValue); + + // BigInt64Array = new Function() + JSHandle bigInt64ArrayFunction = factory_->NewSpecificTypedArrayFunction( + env, reinterpret_cast(BuiltinsTypedArray::BigInt64ArrayConstructor)); + InitializeCtor(env, bigInt64ArrFuncPrototype, bigInt64ArrayFunction, "BigInt64Array", FunctionLength::THREE); + + bigInt64ArrayFunction->SetProtoOrDynClass(thread_, bigInt64ArrFuncInstanceDynclass.GetTaggedValue()); + + const int bytesPerElement = 8; + SetConstant(bigInt64ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); + SetConstant(JSHandle(bigInt64ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); + env->SetBigInt64ArrayFunction(thread_, bigInt64ArrayFunction); +} + +void Builtins::InitializeBigUint64Array(const JSHandle &env, const JSHandle &objFuncDynclass) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + // BigUint64Array.prototype + JSHandle bigUint64ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass); + JSHandle bigUint64ArrFuncPrototypeValue(bigUint64ArrFuncPrototype); + + // BigUint64Array.prototype_or_dynclass + JSHandle bigUint64ArrFuncInstanceDynclass = factory_->NewEcmaDynClass( + panda::ecmascript::JSTypedArray::SIZE, JSType::JS_BIGUINT64_ARRAY, bigUint64ArrFuncPrototypeValue); + + // BigUint64Array = new Function() + JSHandle bigUint64ArrayFunction = factory_->NewSpecificTypedArrayFunction( + env, reinterpret_cast(BuiltinsTypedArray::BigUint64ArrayConstructor)); + InitializeCtor(env, bigUint64ArrFuncPrototype, bigUint64ArrayFunction, "BigUint64Array", FunctionLength::THREE); + + bigUint64ArrayFunction->SetProtoOrDynClass(thread_, bigUint64ArrFuncInstanceDynclass.GetTaggedValue()); + + const int bytesPerElement = 8; + SetConstant(bigUint64ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); + SetConstant(JSHandle(bigUint64ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); + env->SetBigUint64ArrayFunction(thread_, bigUint64ArrayFunction); +} + void Builtins::InitializeArrayBuffer(const JSHandle &env, const JSHandle &objFuncDynclass) const { [[maybe_unused]] EcmaHandleScope scope(thread_); diff --git a/runtime/builtins.h b/runtime/builtins.h index c9cd2f15f..9deda55c9 100644 --- a/runtime/builtins.h +++ b/runtime/builtins.h @@ -67,6 +67,8 @@ private: void InitializeNumber(const JSHandle &env, const JSHandle &globalObject, const JSHandle &primRefObjDynclass); + void InitializeBigInt(const JSHandle &env, const JSHandle &objFuncDynclass) const; + void InitializeDate(const JSHandle &env, const JSHandle &objFuncDynclass) const; void InitializeBoolean(const JSHandle &env, const JSHandle &primRefObjDynclass) const; @@ -97,6 +99,10 @@ private: void InitializeFloat64Array(const JSHandle &env, const JSHandle &objFuncDynclass) const; + void InitializeBigInt64Array(const JSHandle &env, const JSHandle &objFuncDynclass) const; + + void InitializeBigUint64Array(const JSHandle &env, const JSHandle &objFuncDynclass) const; + void InitializeAllTypeError(const JSHandle &env, const JSHandle &objFuncDynclass) const; void InitializeAllTypeErrorWithRealm(const JSHandle &realm) const; diff --git a/runtime/builtins/builtins_array.cpp b/runtime/builtins/builtins_array.cpp index 807142316..e3bdb9ee5 100644 --- a/runtime/builtins/builtins_array.cpp +++ b/runtime/builtins/builtins_array.cpp @@ -896,9 +896,13 @@ JSTaggedValue BuiltinsArray::Fill(EcmaRuntimeCallInfo *argv) JSHandle value = GetCallArg(argv, 0); if (thisHandle->IsTypedArray()) { - JSTaggedNumber number = JSTaggedValue::ToNumber(thread, value); + ContentType contentType = JSHandle::Cast(thisHandle)->GetContentType(); + if (contentType == ContentType::BigInt) { + value = JSHandle(thread, JSTaggedValue::ToBigInt(thread, value)); + } else { + value = JSHandle(thread, JSTaggedValue::ToNumber(thread, value)); + } RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - value = JSHandle(thread, JSTaggedValue(number.GetNumber())); } // 3. Let len be ToLength(Get(O, "length")). diff --git a/runtime/builtins/builtins_arraybuffer.cpp b/runtime/builtins/builtins_arraybuffer.cpp index 428e32d09..c020cd977 100644 --- a/runtime/builtins/builtins_arraybuffer.cpp +++ b/runtime/builtins/builtins_arraybuffer.cpp @@ -320,8 +320,8 @@ JSTaggedValue BuiltinsArrayBuffer::CloneArrayBuffer(JSThread *thread, const JSHa // 24.1.1.5 // NOLINTNEXTLINE(readability-function-size) -JSTaggedValue BuiltinsArrayBuffer::GetValueFromBuffer(JSTaggedValue arrBuf, int32_t byteIndex, DataViewType type, - bool littleEndian) +JSTaggedValue BuiltinsArrayBuffer::GetValueFromBuffer(JSThread *thread, JSTaggedValue arrBuf, int32_t byteIndex, + DataViewType type, bool littleEndian) { JSArrayBuffer *jsArrayBuffer = JSArrayBuffer::Cast(arrBuf.GetTaggedObject()); JSTaggedValue data = jsArrayBuffer->GetArrayBufferData(); @@ -347,9 +347,13 @@ JSTaggedValue BuiltinsArrayBuffer::GetValueFromBuffer(JSTaggedValue arrBuf, int3 case DataViewType::INT32: return GetValueFromBufferForInteger(block, byteIndex, littleEndian); case DataViewType::FLOAT32: - return GetValueFromBufferForFloat(block, byteIndex, littleEndian); + return GetValueFromBufferForFloat(block, byteIndex, littleEndian); case DataViewType::FLOAT64: - return GetValueFromBufferForFloat(block, byteIndex, littleEndian); + return GetValueFromBufferForFloat(block, byteIndex, littleEndian); + case DataViewType::BIGINT64: + return GetValueFromBufferForBigInt(thread, block, byteIndex, littleEndian); + case DataViewType::BIGUINT64: + return GetValueFromBufferForBigInt(thread, block, byteIndex, littleEndian); default: break; } @@ -358,14 +362,33 @@ JSTaggedValue BuiltinsArrayBuffer::GetValueFromBuffer(JSTaggedValue arrBuf, int3 } // 24.1.1.6 -JSTaggedValue BuiltinsArrayBuffer::SetValueInBuffer(JSTaggedValue arrBuf, int32_t byteIndex, DataViewType type, - JSTaggedNumber value, bool littleEndian) +JSTaggedValue BuiltinsArrayBuffer::SetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, int32_t byteIndex, + DataViewType type, const JSHandle &value, + bool littleEndian) { JSArrayBuffer *jsArrayBuffer = JSArrayBuffer::Cast(arrBuf.GetTaggedObject()); JSTaggedValue data = jsArrayBuffer->GetArrayBufferData(); void *pointer = JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer(); auto *block = reinterpret_cast(pointer); - double val = value.GetNumber(); + + if (IsBigIntElementType(type)) { + switch (type) { + case DataViewType::BIGINT64: + SetValueInBufferForBigInt(thread, value, block, byteIndex, littleEndian); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + break; + case DataViewType::BIGUINT64: + SetValueInBufferForBigInt(thread, value, block, byteIndex, littleEndian); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + break; + default: + UNREACHABLE(); + } + return JSTaggedValue::Undefined(); + } + + double val = value->GetNumber(); + switch (type) { case DataViewType::UINT8: SetValueInBufferForByte(val, block, byteIndex); @@ -400,6 +423,12 @@ JSTaggedValue BuiltinsArrayBuffer::SetValueInBuffer(JSTaggedValue arrBuf, int32_ return JSTaggedValue::Undefined(); } +// es12 25.1.2.7 IsBigIntElementType ( type ) +bool BuiltinsArrayBuffer::IsBigIntElementType(DataViewType type) +{ + return type == DataViewType::BIGINT64 || type == DataViewType::BIGUINT64; +} + template void BuiltinsArrayBuffer::SetTypeData(uint8_t *block, T value, int32_t index) { @@ -433,7 +462,8 @@ T BuiltinsArrayBuffer::LittleEndianToBigEndian(T liValue) return biValue; } -uint64_t BuiltinsArrayBuffer::LittleEndianToBigEndianUint64(uint64_t liValue) +template +T BuiltinsArrayBuffer::LittleEndianToBigEndian64Bit(T liValue) { return ((liValue & 0x00000000000000FF) << BITS_FIFTY_SIX) // NOLINT | ((liValue & 0x000000000000FF00) << BITS_FORTY) // NOLINT @@ -473,36 +503,62 @@ JSTaggedValue BuiltinsArrayBuffer::GetValueFromBufferForInteger(uint8_t *block, return GetTaggedInt(res); } -template +template // NOLINTNEXTLINE(readability-non-const-parameter) JSTaggedValue BuiltinsArrayBuffer::GetValueFromBufferForFloat(uint8_t *block, int32_t byteIndex, bool littleEndian) { static_assert(std::is_same_v || std::is_same_v, "T must be float type"); static_assert(sizeof(T) == size, "Invalid number size"); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - T tmp = UnalignedLoad(reinterpret_cast(block + byteIndex)); + UnionType unionValue = {0}; // NOLINTNEXTLINE(readability-braces-around-statements) if constexpr (std::is_same_v) { - if (std::isnan(tmp)) { - return GetTaggedDouble(tmp); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access,cppcoreguidelines-pro-bounds-pointer-arithmetic) + unionValue.uValue = *reinterpret_cast(block + byteIndex); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + if (std::isnan(unionValue.value)) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + return GetTaggedDouble(unionValue.value); } if (!littleEndian) { - auto res = bit_cast(tmp); - res = LittleEndianToBigEndian(res); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + uint32_t res = LittleEndianToBigEndian(unionValue.uValue); return GetTaggedDouble(bit_cast(res)); } - } else if constexpr (std::is_same_v) { // NOLINTNEXTLINE(readability-braces-around-statements) - if (std::isnan(tmp) && !JSTaggedValue::IsImpureNaN(tmp)) { - return GetTaggedDouble(tmp); + // NOLINTNEXTLINE(readability-misleading-indentation) + } else if constexpr (std::is_same_v) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access,cppcoreguidelines-pro-bounds-pointer-arithmetic) + unionValue.uValue = *reinterpret_cast(block + byteIndex); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + if (std::isnan(unionValue.value) && !JSTaggedValue::IsImpureNaN(unionValue.value)) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + return GetTaggedDouble(unionValue.value); } if (!littleEndian) { - auto res = bit_cast(tmp); - res = LittleEndianToBigEndianUint64(res); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + uint64_t res = LittleEndianToBigEndian64Bit(unionValue.uValue); return GetTaggedDouble(bit_cast(res)); } } - return GetTaggedDouble(tmp); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + return GetTaggedDouble(unionValue.value); +} + +template +JSTaggedValue BuiltinsArrayBuffer::GetValueFromBufferForBigInt(JSThread *thread, const uint8_t *block, + uint32_t byteIndex, bool littleEndian) +{ + static_assert(std::is_same_v || std::is_same_v, "T must be uint64_t/int64_t"); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto pTmp = *reinterpret_cast(block + byteIndex); + if (!littleEndian) { + pTmp = LittleEndianToBigEndian64Bit(pTmp); + } + // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon) + if constexpr (std::is_same_v) { + return BigInt::Uint64ToBigInt(thread, pTmp).GetTaggedValue(); + } + return BigInt::Int64ToBigInt(thread, pTmp).GetTaggedValue(); } template @@ -582,9 +638,30 @@ void BuiltinsArrayBuffer::SetValueInBufferForFloat(double val, uint8_t *block, i // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if constexpr (std::is_same_v) { auto res = bit_cast(data); - data = bit_cast(LittleEndianToBigEndianUint64(res)); + data = bit_cast(LittleEndianToBigEndian64Bit(res)); } } SetTypeData(block, data, byteIndex); } + +template +void BuiltinsArrayBuffer::SetValueInBufferForBigInt(JSThread *thread, const JSHandle &val, + uint8_t *block, uint32_t byteIndex, bool littleEndian) +{ + static_assert(std::is_same_v || std::is_same_v, "T must be int64_t/uint64_t"); + T value = 0; + bool lossless = true; + // NOLINTNEXTLINE(readability-braces-around-statements) + if constexpr (std::is_same_v) { + BigInt::BigIntToUint64(thread, val, reinterpret_cast(&value), &lossless); + // NOLINTNEXTLINE(readability-misleading-indentation) + } else { + BigInt::BigIntToInt64(thread, val, reinterpret_cast(&value), &lossless); + } + RETURN_IF_ABRUPT_COMPLETION(thread); + if (!littleEndian) { + value = LittleEndianToBigEndian64Bit(value); + } + SetTypeData(block, value, byteIndex); +} } // namespace panda::ecmascript::builtins diff --git a/runtime/builtins/builtins_arraybuffer.h b/runtime/builtins/builtins_arraybuffer.h index 523ab0505..a414c707a 100644 --- a/runtime/builtins/builtins_arraybuffer.h +++ b/runtime/builtins/builtins_arraybuffer.h @@ -27,9 +27,26 @@ static constexpr uint32_t BITS_TWENTY_FOUR = 24; static constexpr uint32_t BITS_FORTY = 40; static constexpr uint32_t BITS_FIFTY_SIX = 56; using DataViewType = ecmascript::DataViewType; +union UnionType32 { + uint32_t uValue; + float value; +}; +union UnionType64 { + uint64_t uValue; + double value; +}; class BuiltinsArrayBuffer : public ecmascript::base::BuiltinsBase { public: - enum NumberSize : uint8_t { UINT16 = 2, INT16 = 2, UINT32 = 4, INT32 = 4, FLOAT32 = 4, FLOAT64 = 8 }; + enum NumberSize : uint8_t { + UINT16 = 2, + INT16 = 2, + UINT32 = 4, + INT32 = 4, + FLOAT32 = 4, + FLOAT64 = 8, + BIGINT64 = 8, + BIGUINT64 = 8 + }; // 24.1.2.1 ArrayBuffer(length) static JSTaggedValue ArrayBufferConstructor(EcmaRuntimeCallInfo *argv); @@ -44,23 +61,26 @@ public: // 24.1.1.2 IsDetachedBuffer(arrayBuffer) static bool IsDetachedBuffer(JSTaggedValue arrayBuffer); // 24.1.1.5 GetValueFromBuffer ( arrayBuffer, byteIndex, type, isLittleEndian ) - static JSTaggedValue GetValueFromBuffer(JSTaggedValue arrBuf, int32_t byteIndex, DataViewType type, - bool littleEndian); + static JSTaggedValue GetValueFromBuffer(JSThread *thread, JSTaggedValue arrBuf, int32_t byteIndex, + DataViewType type, bool littleEndian); // 24.1.1.6 SetValueInBuffer ( arrayBuffer, byteIndex, type, value, isLittleEndian ) - static JSTaggedValue SetValueInBuffer(JSTaggedValue arrBuf, int32_t byteIndex, DataViewType type, - JSTaggedNumber value, bool littleEndian); + static JSTaggedValue SetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, int32_t byteIndex, DataViewType type, + const JSHandle &value, bool littleEndian); // 24.1.1.4 CloneArrayBuffer( srcBuffer, srcByteOffset [, cloneConstructor] ) static JSTaggedValue CloneArrayBuffer(JSThread *thread, const JSHandle &srcBuffer, int32_t srcByteOffset, JSHandle constructor); // 24.1.1.1 AllocateArrayBuffer(constructor, byteLength) static JSTaggedValue AllocateArrayBuffer(JSThread *thread, const JSHandle &new_target, double byteLength); + // es12 25.1.2.7 IsBigIntElementType ( type ) + static bool IsBigIntElementType(DataViewType type); private: template static T LittleEndianToBigEndian(T liValue); - static uint64_t LittleEndianToBigEndianUint64(uint64_t liValue); + template + static T LittleEndianToBigEndian64Bit(T liValue); template static void SetTypeData(uint8_t *block, T value, int32_t index); @@ -68,9 +88,13 @@ private: template static JSTaggedValue GetValueFromBufferForInteger(uint8_t *block, int32_t byteIndex, bool littleEndian); - template + template static JSTaggedValue GetValueFromBufferForFloat(uint8_t *block, int32_t byteIndex, bool littleEndian); + template + static JSTaggedValue GetValueFromBufferForBigInt(JSThread *thread, const uint8_t *block, uint32_t byteIndex, + bool littleEndian); + template static void SetValueInBufferForByte(double val, uint8_t *block, int32_t byteIndex); @@ -81,6 +105,10 @@ private: template static void SetValueInBufferForFloat(double val, uint8_t *block, int32_t byteIndex, bool littleEndian); + + template + static void SetValueInBufferForBigInt(JSThread *thread, const JSHandle &val, uint8_t *block, + uint32_t byteIndex, bool littleEndian); }; } // namespace panda::ecmascript::builtins diff --git a/runtime/builtins/builtins_async_function.cpp b/runtime/builtins/builtins_async_function.cpp index a43508996..53ba1fa77 100644 --- a/runtime/builtins/builtins_async_function.cpp +++ b/runtime/builtins/builtins_async_function.cpp @@ -15,14 +15,12 @@ #include "plugins/ecmascript/runtime/builtins/builtins_async_function.h" #include "plugins/ecmascript/runtime/ecma_macros.h" +#include "plugins/ecmascript/runtime/js_eval.h" namespace panda::ecmascript::builtins { // ecma2017 25.5.1.1 AsyncFunction (p1, p2, ... , pn, body) JSTaggedValue BuiltinsAsyncFunction::AsyncFunctionConstructor(EcmaRuntimeCallInfo *argv) { - ASSERT(argv); - // not support - THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "Not support eval. Forbidden using new AsyncFunction().", - JSTaggedValue::Exception()); + return EvalUtils::CreateDynamicFunction(argv, EvalUtils::DynamicFunctionKind::ASYNC); } } // namespace panda::ecmascript::builtins diff --git a/runtime/builtins/builtins_async_generator.cpp b/runtime/builtins/builtins_async_generator.cpp index 9723b7491..dd3d44a8d 100644 --- a/runtime/builtins/builtins_async_generator.cpp +++ b/runtime/builtins/builtins_async_generator.cpp @@ -4,6 +4,7 @@ */ #include "plugins/ecmascript/runtime/builtins/builtins_async_generator.h" +#include "plugins/ecmascript/runtime/js_eval.h" #include "plugins/ecmascript/runtime/js_function.h" #include "plugins/ecmascript/runtime/js_async_generator_object.h" @@ -11,10 +12,7 @@ namespace panda::ecmascript::builtins { // 27.4.1.1 AsyncGeneratorFunction (p1, p2, ... , pn, body) JSTaggedValue BuiltinsAsyncGenerator::AsyncGeneratorFunctionConstructor(EcmaRuntimeCallInfo *argv) { - ASSERT(argv); - // not support - THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "Not support eval. Forbidden using new AsyncGeneratorFunction().", - JSTaggedValue::Exception()); + return EvalUtils::CreateDynamicFunction(argv, EvalUtils::DynamicFunctionKind::ASYNC_GENERATOR); } // 27.6.1.2 AsyncGenerator.prototype.next(value) diff --git a/runtime/builtins/builtins_bigint.cpp b/runtime/builtins/builtins_bigint.cpp new file mode 100644 index 000000000..f2403df5f --- /dev/null +++ b/runtime/builtins/builtins_bigint.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugins/ecmascript/runtime/builtins/builtins_bigint.h" + +#include "plugins/ecmascript/runtime/ecma_runtime_call_info.h" +#include "plugins/ecmascript/runtime/js_number_format.h" +#include "plugins/ecmascript/runtime/js_primitive_ref.h" +#include "plugins/ecmascript/runtime/js_bigint.h" + +namespace panda::ecmascript::builtins { +JSTaggedValue BuiltinsBigInt::BigIntConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, BigInt, Constructor); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle newTarget = GetNewTarget(argv); + // 1. If NewTarget is not undefined, throw a TypeError exception. + JSHandle value = GetCallArg(argv, 0); + if (!newTarget->IsUndefined()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "BigInt is not a constructor", JSTaggedValue::Exception()); + } + // 2. Let prim be ? ToPrimitive(value). + JSHandle Primitive(thread, JSTaggedValue::ToPrimitive(thread, value)); + // 3. If Type(prim) is Number, return ? NumberToBigInt(prim). + if (Primitive->IsNumber()) { + return BigInt::NumberToBigInt(thread, Primitive); + } + // 4. Otherwise, return ? ToBigInt(value). + return JSTaggedValue::ToBigInt(thread, value); +} + +JSTaggedValue BuiltinsBigInt::AsUintN(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, BigInt, AsUintN); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle bits = GetCallArg(argv, 0); + JSHandle bigint = GetCallArg(argv, 1); + // 1. Let bits be ? ToIndex(bits). + JSTaggedNumber index = JSTaggedValue::ToIndex(thread, bits); + // 2. Let bigint be ? ToBigInt(bigint). + JSTaggedValue jsBigint = JSTaggedValue::ToBigInt(thread, bigint); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle jsBigintVal(thread, jsBigint); + // 3. Return a BigInt representing bigint modulo 2bits. + return BigInt::AsUintN(thread, index, jsBigintVal); +} + +JSTaggedValue BuiltinsBigInt::AsIntN(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, BigInt, AsIntN); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle bits = GetCallArg(argv, 0); + JSHandle bigint = GetCallArg(argv, 1); + // 1. Let bits be ? ToIndex(bits). + JSTaggedNumber index = JSTaggedValue::ToIndex(thread, bits); + // 2. Let bigint be ? ToBigInt(bigint). + JSTaggedValue jsBigint = JSTaggedValue::ToBigInt(thread, bigint); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle jsBigintVal(thread, jsBigint); + // 3. Let mod be ℝ(bigint) modulo 2bits. + // 4. If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return ℤ(mod). + return BigInt::AsintN(thread, index, jsBigintVal); +} + +JSTaggedValue BuiltinsBigInt::ToLocaleString(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, BigInt, ToLocaleString); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let x be ? ThisBigIntValue(this value). + JSTaggedValue value = ThisBigIntValue(argv); + JSHandle thisVal(thread, value); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 2. Let numberFormat be ? Construct(%NumberFormat%, « locales, options »). + JSHandle ctor = thread->GetEcmaVM()->GetGlobalEnv()->GetNumberFormatFunction(); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(ctor), ctor); + JSHandle numberFormat = JSHandle::Cast(obj); + JSHandle locales = GetCallArg(argv, 0); + JSHandle options = GetCallArg(argv, 1); + JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, options); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // Return ? FormatNumeric(numberFormat, x). + JSHandle result = JSNumberFormat::FormatNumeric(thread, numberFormat, thisVal.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return result.GetTaggedValue(); +} + +JSTaggedValue BuiltinsBigInt::ToString(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, BigInt, ToString); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let x be ? thisBigIntValue(this value). + JSTaggedValue value = ThisBigIntValue(argv); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisBigint(thread, value); + // 2. If radix is not present, let radixNumber be 10 + double radix = base::DECIMAL; + JSHandle radixValue = GetCallArg(argv, 0); + // 3. Else, let radixNumber be ? ToIntegerOrInfinity(radix). + if (!radixValue->IsUndefined()) { + JSTaggedNumber radixNumber = JSTaggedValue::ToInteger(thread, radixValue); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + radix = radixNumber.GetNumber(); + } + // 4. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception. + if (radix < base::MIN_RADIX || radix > base::MAX_RADIX) { + THROW_RANGE_ERROR_AND_RETURN(thread, "toString() radix argument must be between 2 and 36", + JSTaggedValue::Exception()); + } + // 5. If radixNumber = 10, return ToString(x). + if (radix == base::DECIMAL) { + return BigInt::ToString(thread, thisBigint).GetTaggedValue(); + } + // 6. Return the String representation of this BigInt value using the radix specified by radixNumber + return BigInt::ToString(thread, thisBigint, static_cast(radix)).GetTaggedValue(); +} + +JSTaggedValue BuiltinsBigInt::ValueOf(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, BigInt, ValueOf); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let x be ? thisBigIntValue(this value). + return ThisBigIntValue(argv); +} + +JSTaggedValue BuiltinsBigInt::ThisBigIntValue(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, BigInt, ThisBigIntValue); + JSHandle value = GetThis(argv); + // 1. If Type(value) is BigInt, return value. + if (value->IsBigInt()) { + return value.GetTaggedValue(); + } + // 2. If Type(value) is Object and value has a [[BigIntData]] internal slot, then + if (value->IsJSPrimitiveRef()) { + JSTaggedValue primitive = JSPrimitiveRef::Cast(value->GetTaggedObject())->GetValue(); + // a. Assert: Type(value.[[BigIntData]]) is BigInt. + if (primitive.IsBigInt()) { + // b. Return value.[[BigIntData]]. + return primitive; + } + } + // 3. Throw a TypeError exception. + THROW_TYPE_ERROR_AND_RETURN(thread, "not BigInt type", JSTaggedValue::Exception()); +} +} // namespace panda::ecmascript::builtins diff --git a/runtime/builtins/builtins_bigint.h b/runtime/builtins/builtins_bigint.h new file mode 100644 index 000000000..c9a2f85f5 --- /dev/null +++ b/runtime/builtins/builtins_bigint.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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_BUILTINS_BUILTINS_BIGINT_H +#define ECMASCRIPT_BUILTINS_BUILTINS_BIGINT_H + +#include "plugins/ecmascript/runtime/base/builtins_base.h" + +namespace panda::ecmascript::builtins { +class BuiltinsBigInt : public ecmascript::base::BuiltinsBase { +public: + // 21.2.1.1 + static JSTaggedValue BigIntConstructor(EcmaRuntimeCallInfo *argv); + // 21.2.2.1 + static JSTaggedValue AsUintN(EcmaRuntimeCallInfo *argv); + // 21.2.2.2 + static JSTaggedValue AsIntN(EcmaRuntimeCallInfo *argv); + // 21.2.3.2 + static JSTaggedValue ToLocaleString(EcmaRuntimeCallInfo *argv); + // 21.2.3.3 + static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv); + // 21.2.3.4 + static JSTaggedValue ValueOf(EcmaRuntimeCallInfo *argv); + +private: + static JSTaggedValue ThisBigIntValue(EcmaRuntimeCallInfo *argv); +}; +} // namespace panda::ecmascript::builtins +#endif // ECMASCRIPT_BUILTINS_BUILTINS_BIGINT_H diff --git a/runtime/builtins/builtins_dataview.cpp b/runtime/builtins/builtins_dataview.cpp index b11865241..b099edfb8 100644 --- a/runtime/builtins/builtins_dataview.cpp +++ b/runtime/builtins/builtins_dataview.cpp @@ -243,6 +243,20 @@ JSTaggedValue BuiltinsDataView::GetUint32(EcmaRuntimeCallInfo *argv) return GetTypedValue(argv, DataViewType::UINT32); } +// 25.3.4.5 +JSTaggedValue BuiltinsDataView::GetBigInt64(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + return GetTypedValue(argv, DataViewType::BIGINT64); +} + +// 25.3.4.6 +JSTaggedValue BuiltinsDataView::GetBigUint64(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + return GetTypedValue(argv, DataViewType::BIGUINT64); +} + // 24.2.4.13 JSTaggedValue BuiltinsDataView::SetFloat32(EcmaRuntimeCallInfo *argv) { @@ -292,6 +306,20 @@ JSTaggedValue BuiltinsDataView::SetUint16(EcmaRuntimeCallInfo *argv) return SetTypedValue(argv, DataViewType::UINT16); } +// 25.3.4.15 +JSTaggedValue BuiltinsDataView::SetBigInt64(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + return SetTypedValue(argv, DataViewType::BIGINT64); +} + +// 25.3.4.16 +JSTaggedValue BuiltinsDataView::SetBigUint64(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + return SetTypedValue(argv, DataViewType::BIGUINT64); +} + // 24.2.4.20 JSTaggedValue BuiltinsDataView::SetUint32(EcmaRuntimeCallInfo *argv) { @@ -359,7 +387,7 @@ JSTaggedValue BuiltinsDataView::GetViewValue(JSThread *thread, const JSHandleGetViewedArrayBuffer(); - return BuiltinsArrayBuffer::GetValueFromBuffer(buffer, bufferIndex, type, isLittleEndian); + return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, bufferIndex, type, isLittleEndian); } } @@ -386,7 +414,7 @@ JSTaggedValue BuiltinsDataView::SetViewValue(JSThread *thread, const JSHandle numVal = JSTaggedValue::ToNumeric(thread, value); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 7. Let isLittleEndian be ToBoolean(isLittleEndian). bool isLittleEndian; @@ -425,7 +453,7 @@ JSTaggedValue BuiltinsDataView::SetViewValue(JSThread *thread, const JSHandleGetViewedArrayBuffer(); // 15. Return SetValueFromBuffer(buffer, bufferIndex, type, value, isLittleEndian). - return BuiltinsArrayBuffer::SetValueInBuffer(buffer, bufferIndex, type, numVal, isLittleEndian); + return BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer, bufferIndex, type, numVal, isLittleEndian); } } diff --git a/runtime/builtins/builtins_dataview.h b/runtime/builtins/builtins_dataview.h index 24170642b..adaba56c6 100644 --- a/runtime/builtins/builtins_dataview.h +++ b/runtime/builtins/builtins_dataview.h @@ -47,6 +47,10 @@ public: static JSTaggedValue GetUint16(EcmaRuntimeCallInfo *argv); // 24.2.4.12 DataView.prototype.getUint32 ( byteOffset [ , littleEndian ] ) static JSTaggedValue GetUint32(EcmaRuntimeCallInfo *argv); + // 25.3.4.5 DataView.prototype.getBigInt64 ( byteOffset [ , littleEndian ] ) + static JSTaggedValue GetBigInt64(EcmaRuntimeCallInfo *argv); + // 25.3.4.6 DataView.prototype.getBigUint64 ( byteOffset [ , littleEndian ] ) + static JSTaggedValue GetBigUint64(EcmaRuntimeCallInfo *argv); // 24.2.4.13 DataView.prototype.setFloat32 ( byteOffset, value [ , littleEndian ] ) static JSTaggedValue SetFloat32(EcmaRuntimeCallInfo *argv); // 24.2.4.14 DataView.prototype.setFloat64 ( byteOffset, value [ , littleEndian ] ) @@ -63,6 +67,10 @@ public: static JSTaggedValue SetUint16(EcmaRuntimeCallInfo *argv); // 24.2.4.20 DataView.prototype.setUint32 ( byteOffset, value [ , littleEndian ] ) static JSTaggedValue SetUint32(EcmaRuntimeCallInfo *argv); + // 25.3.4.15 DataView.prototype.setBigInt64 ( byteOffset, value [ , littleEndian ] ) + static JSTaggedValue SetBigInt64(EcmaRuntimeCallInfo *argv); + // 25.3.4.16 DataView.prototype.setBigUint64 ( byteOffset, value [ , littleEndian ] ) + static JSTaggedValue SetBigUint64(EcmaRuntimeCallInfo *argv); private: // 24.2.1.1 GetViewValue ( view, requestIndex, isLittleEndian, type ) diff --git a/runtime/builtins/builtins_function.cpp b/runtime/builtins/builtins_function.cpp index 2d59ba02a..a85e6ba66 100644 --- a/runtime/builtins/builtins_function.cpp +++ b/runtime/builtins/builtins_function.cpp @@ -18,119 +18,15 @@ #include "plugins/ecmascript/runtime/global_env.h" #include "plugins/ecmascript/runtime/internal_call_params.h" #include "plugins/ecmascript/runtime/js_arguments.h" +#include "plugins/ecmascript/runtime/js_eval.h" #include "plugins/ecmascript/runtime/js_stable_array.h" #include "plugins/ecmascript/runtime/tagged_array-inl.h" namespace panda::ecmascript::builtins { - -static JSTaggedValue EvalHackReturnThis([[maybe_unused]] EcmaRuntimeCallInfo *argv) -{ - 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) -{ - return JSTaggedValue(JSTaggedValue::VALUE_UNDEFINED); -} - -static JSMethod *LookupEvalHack(JSThread *thread, uint8_t const *str, uint32_t str_len) -{ - using key_type = Span; - auto constexpr makeKey = [](char const *s) { return key_type(reinterpret_cast(s), strlen(s)); }; - auto constexpr hash = [](key_type k) { return ComputeHashForData(k.data(), k.size()); }; - auto constexpr keyEq = [](key_type k1, key_type k2) { - if (k1.size() != k2.size()) { - return false; - } - return std::memcmp(k1.data(), k2.data(), k1.size()) == 0; - }; - - EcmaVM *vm = thread->GetEcmaVM(); - static const std::unordered_map evalMap( - {{makeKey("return this"), vm->GetMethodForNativeFunction(reinterpret_cast(EvalHackReturnThis))}, - {makeKey("return this;"), vm->GetMethodForNativeFunction(reinterpret_cast(EvalHackReturnThis))}, - {makeKey(""), vm->GetMethodForNativeFunction(reinterpret_cast(EvalHackNop))}}, - 0, hash, keyEq); - - auto e = evalMap.find(key_type(str, str_len)); - if (e == evalMap.end()) { - return nullptr; - } - return e->second; -} - -static JSHandle WrapEvalHack(JSThread *thread, JSMethod *target, JSTaggedValue funcLen) -{ - EcmaVM *vm = thread->GetEcmaVM(); - - ObjectFactory *factory = vm->GetFactory(); - JSHandle env = vm->GetGlobalEnv(); - auto globalConst = thread->GlobalConstants(); - JSHandle dynclass = JSHandle::Cast(env->GetNormalFunctionClass()); - JSHandle func = factory->NewJSFunctionByDynClass(target, dynclass, FunctionKind::NORMAL_FUNCTION); - func->SetStrict(thread, false); - func->SetLexicalEnv(thread, vm->GetGlobalEnv()); - // TODO(audovichenko): Remove this suppression when CSA gets recognize primitive TaggedValue (issue #I5QOJX) - // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) - JSFunction::SetFunctionLength(thread, func, funcLen); - JSHandle emptyString = globalConst->GetHandledEmptyString(); - JSHandle nameKey = globalConst->GetHandledNameString(); - PropertyDescriptor nameDesc(thread, emptyString, false, false, true); - JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle::Cast(func), nameKey, nameDesc); - return func; -} - -static inline JSTaggedValue TryEvalHack(EcmaRuntimeCallInfo *argv) -{ - uint32_t nargs = argv->GetArgsNumber(); - if (nargs > 1) { - return JSTaggedValue::Hole(); - } - - uint8_t const *data; - uint32_t dataLen; - if (nargs == 0) { - data = reinterpret_cast(""); - dataLen = 0; - } else { - JSHandle functionBody = BuiltinsFunction::GetCallArg(argv, nargs - 1); - if (!functionBody->IsString()) { - return JSTaggedValue::Hole(); - } - auto str = EcmaString::Cast(functionBody->GetHeapObject()); - if (!str->IsUtf8()) { - return JSTaggedValue::Hole(); - } - data = str->GetDataUtf8(); - dataLen = str->GetUtf8Length() - 1; - } - - auto method = LookupEvalHack(argv->GetThread(), data, dataLen); - if (method == nullptr) { - return JSTaggedValue::Hole(); - } - - return WrapEvalHack(argv->GetThread(), method, JSTaggedValue(0)).GetTaggedValue(); -} - // ecma 19.2.1 Function (p1, p2, ... , pn, body) JSTaggedValue BuiltinsFunction::FunctionConstructor(EcmaRuntimeCallInfo *argv) { - // not support - JSThread *thread = argv->GetThread(); - [[maybe_unused]] EcmaHandleScope handleScope(thread); - - auto func = TryEvalHack(argv); - if (func != JSTaggedValue::Hole()) { - return func; - } - - THROW_TYPE_ERROR_AND_RETURN(thread, "Not support eval. Forbidden using new Function()/Function().", - JSTaggedValue::Exception()); + return EvalUtils::CreateDynamicFunction(argv, EvalUtils::DynamicFunctionKind::NORMAL); } // ecma 19.2.3 The Function prototype object is itself a built-in function object. diff --git a/runtime/builtins/builtins_generator.cpp b/runtime/builtins/builtins_generator.cpp index 387bd7554..31e60c1c8 100644 --- a/runtime/builtins/builtins_generator.cpp +++ b/runtime/builtins/builtins_generator.cpp @@ -14,6 +14,7 @@ */ #include "builtins_generator.h" +#include "plugins/ecmascript/runtime/js_eval.h" #include "plugins/ecmascript/runtime/js_function.h" #include "plugins/ecmascript/runtime/js_generator_object.h" @@ -21,10 +22,7 @@ namespace panda::ecmascript::builtins { // 26.2.1.1 GeneratorFunction(p1, p2, … , pn, body) JSTaggedValue BuiltinsGenerator::GeneratorFunctionConstructor(EcmaRuntimeCallInfo *argv) { - BUILTINS_API_TRACE(argv->GetThread(), Generator, Constructor); - // not support - THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "Not support eval. Forbidden using new GeneratorFunction().", - JSTaggedValue::Exception()); + return EvalUtils::CreateDynamicFunction(argv, EvalUtils::DynamicFunctionKind::GENERATOR); } // 26.4.1.2 Generator.prototype.next(value) diff --git a/runtime/builtins/builtins_global.cpp b/runtime/builtins/builtins_global.cpp index 01487e3fa..8e7d235f5 100644 --- a/runtime/builtins/builtins_global.cpp +++ b/runtime/builtins/builtins_global.cpp @@ -25,6 +25,7 @@ #include "plugins/ecmascript/runtime/interpreter/fast_runtime_stub-inl.h" #include "plugins/ecmascript/runtime/interpreter/slow_runtime_helper.h" #include "plugins/ecmascript/runtime/js_invoker.h" +#include "plugins/ecmascript/runtime/js_eval.h" #include "plugins/ecmascript/runtime/tagged_array-inl.h" #include "include/thread_scopes.h" @@ -86,14 +87,15 @@ void BuiltinsGlobal::GCTaskTracker::RemoveId(uint64_t id) } // 18.2.1 -JSTaggedValue BuiltinsGlobal::NotSupportEval(EcmaRuntimeCallInfo *msg) +JSTaggedValue BuiltinsGlobal::Eval(EcmaRuntimeCallInfo *msg) { JSThread *thread = msg->GetThread(); [[maybe_unused]] EcmaHandleScope handleScope(thread); if (msg->GetArgsNumber() == 0) { return JSTaggedValue(JSTaggedValue::VALUE_UNDEFINED); } - THROW_TYPE_ERROR_AND_RETURN(thread, "not support eval()", JSTaggedValue::Exception()); + + return EvalUtils::Eval(thread, msg->GetCallArg(0)); } // 18.2.2 diff --git a/runtime/builtins/builtins_global.h b/runtime/builtins/builtins_global.h index 134ee76aa..534ea064a 100644 --- a/runtime/builtins/builtins_global.h +++ b/runtime/builtins/builtins_global.h @@ -32,7 +32,7 @@ using judgURIFunc = bool (*)(uint16_t); class BuiltinsGlobal : public ecmascript::base::BuiltinsBase { public: // 18.2.1 - static JSTaggedValue NotSupportEval(EcmaRuntimeCallInfo *msg); + static JSTaggedValue Eval(EcmaRuntimeCallInfo *msg); // 18.2.2 static JSTaggedValue IsFinite(EcmaRuntimeCallInfo *msg); // 18.2.3 diff --git a/runtime/builtins/builtins_typedarray.cpp b/runtime/builtins/builtins_typedarray.cpp index 20f39a675..8479cf25b 100644 --- a/runtime/builtins/builtins_typedarray.cpp +++ b/runtime/builtins/builtins_typedarray.cpp @@ -111,6 +111,20 @@ JSTaggedValue BuiltinsTypedArray::Float64ArrayConstructor(EcmaRuntimeCallInfo *a return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledFloat64ArrayString()); } +JSTaggedValue BuiltinsTypedArray::BigInt64ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledBigInt64ArrayString()); +} + +JSTaggedValue BuiltinsTypedArray::BigUint64ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledBigUint64ArrayString()); +} + // 22.2.2.1 %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] ) JSTaggedValue BuiltinsTypedArray::From(EcmaRuntimeCallInfo *argv) { @@ -914,6 +928,7 @@ JSTaggedValue BuiltinsTypedArray::Reverse(EcmaRuntimeCallInfo *argv) } // 22.2.3.22 %TypedArray%.prototype.set ( overloaded [ , offset ]) +// NOLINTNEXTLINE(readability-function-size) JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv) { ASSERT(argv); @@ -1002,19 +1017,28 @@ JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv) // f. Set k to k + 1. // g. Set targetByteIndex to targetByteIndex + targetElementSize. JSMutableHandle tKey(thread, JSTaggedValue::Undefined()); + JSMutableHandle kNumberHandle(thread, JSTaggedValue::Undefined()); while (targetByteIndex < limit) { tKey.Update(JSTaggedValue(k)); JSHandle kKey(JSTaggedValue::ToString(thread, tKey)); JSHandle kValue = JSTaggedValue::GetProperty(thread, JSHandle::Cast(src), kKey).GetValue(); - JSTaggedNumber kNumber = JSTaggedValue::ToNumber(thread, kValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (BuiltinsArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) { THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.", JSTaggedValue::Exception()); } - BuiltinsArrayBuffer::SetValueInBuffer(targetBuffer.GetTaggedValue(), targetByteIndex, targetType, kNumber, - true); + + ContentType contentType = JSHandle::Cast(target)->GetContentType(); + if (contentType == ContentType::BigInt) { + kNumberHandle.Update(JSTaggedValue::ToBigInt(thread, kValue)); + } else { + kNumberHandle.Update(JSTaggedValue::ToNumber(thread, kValue)); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex, targetType, + kNumberHandle, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); k++; targetByteIndex = targetByteIndex + targetElementSize; } @@ -1075,11 +1099,12 @@ JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv) JSMutableHandle value(thread, JSTaggedValue::Undefined()); if (srcType != targetType) { while (targetByteIndex < limit) { - JSTaggedValue taggedData = BuiltinsArrayBuffer::GetValueFromBuffer(srcBuffer, srcByteIndex, srcType, true); + JSTaggedValue taggedData = + BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcBuffer, srcByteIndex, srcType, true); value.Update(taggedData); - JSTaggedNumber kNumber = JSTaggedValue::ToNumber(thread, value); - BuiltinsArrayBuffer::SetValueInBuffer(targetBuffer.GetTaggedValue(), targetByteIndex, targetType, kNumber, - true); + BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex, targetType, + value, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); srcByteIndex = srcByteIndex + srcElementSize; targetByteIndex = targetByteIndex + targetElementSize; } @@ -1097,18 +1122,18 @@ JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv) // TODO(audovichenko): Remove this suppression when CSA gets recognize primitive TaggedValue // (issue #I5QOJX) // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) - BuiltinsArrayBuffer::GetValueFromBuffer(srcBuffer, srcByteIndex, DataViewType::UINT8, true); + BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcBuffer, srcByteIndex, DataViewType::UINT8, true); value.Update(taggedData); - JSTaggedNumber kNumber = JSTaggedValue::ToNumber(thread, value); - BuiltinsArrayBuffer::SetValueInBuffer(targetBuffer.GetTaggedValue(), targetByteIndex, DataViewType::UINT8, - kNumber, true); + BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex, + DataViewType::UINT8, value, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); srcByteIndex = srcByteIndex + 1; targetByteIndex = targetByteIndex + 1; } } // 30. Return undefined. return JSTaggedValue::Undefined(); -} // namespace panda::ecmascript::builtins +} // 22.2.3.23 %TypedArray%.prototype.slice ( start, end ) JSTaggedValue BuiltinsTypedArray::Slice(EcmaRuntimeCallInfo *argv) @@ -1227,12 +1252,11 @@ JSTaggedValue BuiltinsTypedArray::Slice(EcmaRuntimeCallInfo *argv) // iv. Increase targetByteIndex by 1. JSMutableHandle value(thread, JSTaggedValue::Undefined()); for (int32_t targetByteIndex = 0; targetByteIndex < count * elementSize; srcByteIndex++, targetByteIndex++) { - JSTaggedValue taggedData = BuiltinsArrayBuffer::GetValueFromBuffer(srcBuffer.GetTaggedValue(), srcByteIndex, - DataViewType::UINT8, true); + JSTaggedValue taggedData = BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcBuffer.GetTaggedValue(), + srcByteIndex, DataViewType::UINT8, true); value.Update(taggedData); - JSTaggedNumber kNumber = JSTaggedValue::ToNumber(thread, value); - BuiltinsArrayBuffer::SetValueInBuffer(targetBuffer.GetTaggedValue(), targetByteIndex, DataViewType::UINT8, - kNumber, true); + BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex, + DataViewType::UINT8, value, true); } } // 23. Return A. diff --git a/runtime/builtins/builtins_typedarray.h b/runtime/builtins/builtins_typedarray.h index e0542e294..8fb2ced64 100644 --- a/runtime/builtins/builtins_typedarray.h +++ b/runtime/builtins/builtins_typedarray.h @@ -32,6 +32,8 @@ public: static JSTaggedValue Uint32ArrayConstructor(EcmaRuntimeCallInfo *argv); static JSTaggedValue Float32ArrayConstructor(EcmaRuntimeCallInfo *argv); static JSTaggedValue Float64ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue BigInt64ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue BigUint64ArrayConstructor(EcmaRuntimeCallInfo *argv); // 22.2.1.2.1 static JSTaggedValue AllocateTypedArray(EcmaRuntimeCallInfo *argv); diff --git a/runtime/class_info_extractor.cpp b/runtime/class_info_extractor.cpp index b360fde9b..76ab56c7a 100644 --- a/runtime/class_info_extractor.cpp +++ b/runtime/class_info_extractor.cpp @@ -251,14 +251,14 @@ JSHandle ClassInfoExtractor::CreateConstructorHClass(JSThread *thread, layout->AddKey(thread, index, key.GetTaggedValue(), attributes); } - hclass = factory->NewEcmaDynClass(factory->hclass_class_, JSFunction::SIZE, JSType::JS_FUNCTION, + hclass = factory->NewEcmaDynClass(factory->hclass_class_, JSConstructorFunction::SIZE, JSType::JS_FUNCTION, HClass::IS_CALLABLE, length); // Not need set proto here hclass->SetLayout(thread, layout); hclass->SetNumberOfProps(length); } else { // dictionary mode - hclass = factory->NewEcmaDynClass(JSFunction::SIZE, JSType::JS_FUNCTION, 0); // without in-obj + hclass = factory->NewEcmaDynClass(JSConstructorFunction::SIZE, JSType::JS_FUNCTION, 0); // without in-obj hclass->SetIsDictionaryMode(true); hclass->SetNumberOfProps(0); } diff --git a/runtime/class_linker/panda_file_translator.cpp b/runtime/class_linker/panda_file_translator.cpp index 163b5ffed..08059cd08 100644 --- a/runtime/class_linker/panda_file_translator.cpp +++ b/runtime/class_linker/panda_file_translator.cpp @@ -293,7 +293,7 @@ Program *PandaFileTranslator::GenerateProgram(const panda_file::File &pf) JSHandle arr(JSArray::ArrayCreate(thread_, JSTaggedNumber(length))); arr->SetElements(thread_, literal); constpool->Set(thread_, value.GetConstpoolIndex(), arr.GetTaggedValue()); - } else if (value.GetConstpoolType() == ConstPoolType::CLASS_LITERAL) { + } else if (value.GetConstpoolType() == ConstPoolType::TAGGED_ARRAY) { size_t index = it.first; JSHandle literal = LiteralDataExtractor::GetDatasIgnoreType(thread_, &pf, static_cast(index), this); @@ -355,7 +355,15 @@ void PandaFileTranslator::FixInstructionId32(const BytecodeInstruction &inst, [[ } break; } - case R::template Get(): { + // Create RegexpWithLiteral + case R::template Get(): + /* The following 3 formats matches for Ld/StLexDyn where the string_id should be fixed and the remaining + * immediates are untouched */ + case R::template Get(): + case R::template Get(): + case R::template Get(): + case R::template Get(): + case R::template Get(): { uint8_t size = sizeof(uint32_t); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) if (memcpy_s(pc + payload_offset, size, &index, size) != EOK) { @@ -364,8 +372,8 @@ void PandaFileTranslator::FixInstructionId32(const BytecodeInstruction &inst, [[ } break; } - case R::template Get(): - case R::template Get(): { + case R::template Get(): + case R::template Get(): { ASSERT(static_cast(index) == index); uint16_t u16_index = index; uint8_t size = sizeof(uint16_t); @@ -468,12 +476,19 @@ void PandaFileTranslator::TranslateBytecode(uint32_t ins_sz, const uint8_t *ins_ bc_ins.GetId().AsFileId().GetOffset()); FixInstructionId32(bc_ins, index); break; + case R::template Get(): + case R::template Get(): { + index = GetOrInsertConstantPool(ConstPoolType::TAGGED_ARRAY, + bc_ins.GetId().AsFileId().GetOffset()); + FixInstructionId32(bc_ins, index); + break; + } case R::template Get(): method_id = pf.ResolveMethodIndex(method->GetFileId(), bc_ins.GetId().AsIndex()).GetOffset(); index = GetOrInsertConstantPool(ConstPoolType::CLASS_FUNCTION, method_id); FixInstructionId32(bc_ins, index); index = GetOrInsertConstantPool( - ConstPoolType::CLASS_LITERAL, + ConstPoolType::TAGGED_ARRAY, bc_ins.GetImm()>()); FixInstructionId32(bc_ins, index, 1); break; @@ -503,12 +518,12 @@ void PandaFileTranslator::UpdateICOffset(JSMethod *method, uint32_t ins_sz, cons case R::template Get(): slot_size = ICRuntimeStub::SlotSizeForGlobalICByName(); break; - case R::template Get(): + case R::template Get(): case R::template Get(): case R::template Get(): slot_size = ICRuntimeStub::SlotSizeForICByValue(); break; - case R::template Get(): + case R::template Get(): case R::template Get(): case R::template Get(): slot_size = ICRuntimeStub::SlotSizeForICByName(); diff --git a/runtime/class_linker/panda_file_translator.h b/runtime/class_linker/panda_file_translator.h index 536f2b235..ff2984338 100644 --- a/runtime/class_linker/panda_file_translator.h +++ b/runtime/class_linker/panda_file_translator.h @@ -51,7 +51,7 @@ private: METHOD, ARRAY_LITERAL, OBJECT_LITERAL, - CLASS_LITERAL, + TAGGED_ARRAY, }; class ConstPoolValue { diff --git a/runtime/dump.cpp b/runtime/dump.cpp index 5bbca0498..d28a3129e 100644 --- a/runtime/dump.cpp +++ b/runtime/dump.cpp @@ -137,6 +137,8 @@ PandaString JSHClass::DumpJSType(JSType type) return "Bound Function"; case JSType::JS_ARRAY: return "Array"; + case JSType::BIGINT: + return "BigInt"; case JSType::JS_TYPED_ARRAY: return "Typed Array"; case JSType::JS_INT8_ARRAY: @@ -451,6 +453,9 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::ostream &os) case JSType::JS_ARRAY: JSArray::Cast(obj)->Dump(thread, os); break; + case JSType::BIGINT: + BigInt::Cast(obj)->Dump(thread, os); + break; case JSType::JS_TYPED_ARRAY: case JSType::JS_INT8_ARRAY: case JSType::JS_UINT8_ARRAY: @@ -973,6 +978,18 @@ void JSHClass::Dump(JSThread *thread, std::ostream &os) const DumpHClass(thread, this, os, true); } +void JSConstructorFunction::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - ComputedFields: "; + GetComputedFields().DumpTaggedValue(thread, os); + os << "\n"; + os << " - PrivateFields: "; + GetPrivateFields().DumpTaggedValue(thread, os); + os << "\n"; + + JSObject::Dump(thread, os); +} + void JSBoundFunction::Dump(JSThread *thread, std::ostream &os) const { os << " - BoundTarget: "; @@ -1126,6 +1143,15 @@ void JSArray::Dump(JSThread *thread, std::ostream &os) const JSObject::Dump(thread, os); } +void BigInt::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - data: "; + GetData().D(); + os << "\n"; + os << " - value : " << ToStdString(thread, DECIMAL) << "\n"; + os << " - sign : " << GetSign() << "\n"; +} + void JSArrayList::Dump(JSThread *thread, std::ostream &os) const { os << " - length: " << std::dec << GetLength().GetArrayLength() << "\n"; @@ -1222,6 +1248,8 @@ void GlobalEnv::Dump(JSThread *thread, std::ostream &os) const GetFunctionFunction().GetTaggedValue().Dump(thread, os); os << " - NumberFunction: "; GetNumberFunction().GetTaggedValue().Dump(thread, os); + os << " - BigIntFunction: "; + GetBigIntFunction().GetTaggedValue().Dump(thread, os); os << " - DateFunction: "; GetDateFunction().GetTaggedValue().Dump(thread, os); os << " - BooleanFunction: "; @@ -2090,6 +2118,9 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::vectorDumpForSnapshot(thread, vec); return; + case JSType::BIGINT: + BigInt::Cast(obj)->DumpForSnapshot(thread, vec); + return; case JSType::JS_TYPED_ARRAY: case JSType::JS_INT8_ARRAY: case JSType::JS_UINT8_ARRAY: @@ -2471,6 +2502,15 @@ void ConstantPool::DumpForSnapshot([[maybe_unused]] JSThread *thread, DumpArrayClass(thread, this, vec); } +void JSConstructorFunction::DumpForSnapshot([[maybe_unused]] JSThread *thread, + std::vector> &vec) const +{ + JSObject::DumpForSnapshot(thread, vec); + + vec.emplace_back(std::make_pair(PandaString("ComputedFields"), GetComputedFields())); + vec.emplace_back(std::make_pair(PandaString("PrivateFields"), GetPrivateFields())); +} + void JSBoundFunction::DumpForSnapshot([[maybe_unused]] JSThread *thread, std::vector> &vec) const { @@ -2568,6 +2608,13 @@ void JSArray::DumpForSnapshot([[maybe_unused]] JSThread *thread, JSObject::DumpForSnapshot(thread, vec); } +void BigInt::DumpForSnapshot([[maybe_unused]] JSThread *thread, + std::vector> &vec) const +{ + vec.emplace_back(std::make_pair(PandaString("Data"), GetData())); + vec.emplace_back(std::make_pair(PandaString("Sign"), JSTaggedValue(GetSign()))); +} + void JSArrayList::DumpForSnapshot([[maybe_unused]] JSThread *thread, std::vector> &vec) const { @@ -2646,6 +2693,7 @@ void GlobalEnv::DumpForSnapshot([[maybe_unused]] JSThread *thread, vec.emplace_back(std::make_pair(PandaString("ObjectFunction"), GetObjectFunction().GetTaggedValue())); vec.emplace_back(std::make_pair(PandaString("FunctionFunction"), GetFunctionFunction().GetTaggedValue())); vec.emplace_back(std::make_pair(PandaString("NumberFunction"), GetNumberFunction().GetTaggedValue())); + vec.emplace_back(std::make_pair(PandaString("BigIntFunction"), GetBigIntFunction().GetTaggedValue())); vec.emplace_back(std::make_pair(PandaString("DateFunction"), GetDateFunction().GetTaggedValue())); vec.emplace_back(std::make_pair(PandaString("BooleanFunction"), GetBooleanFunction().GetTaggedValue())); vec.emplace_back(std::make_pair(PandaString("ErrorFunction"), GetErrorFunction().GetTaggedValue())); diff --git a/runtime/ecma_runtime.yaml b/runtime/ecma_runtime.yaml index 5ed3c0bad..2dc97348f 100644 --- a/runtime/ecma_runtime.yaml +++ b/runtime/ecma_runtime.yaml @@ -98,7 +98,7 @@ intrinsics: static: true signature: ret: any - args: [any] + args: [string_id] impl: panda::ecmascript::intrinsics::Ldbigint - name: Ldnull @@ -323,7 +323,7 @@ intrinsics: exception: true signature: ret: any - args: [any, any, u16] + args: [any, acc, u16] impl: panda::ecmascript::intrinsics::LdObjByValue fast_path: FastPathLdObjByValue set_flags: [heap_inv] @@ -684,7 +684,6 @@ intrinsics: impl: panda::ecmascript::intrinsics::StrictNotEqDyn set_flags: [heap_inv] clear_flags: [no_dce] - use_thread: false - name: StrictEqDyn space: ecmascript @@ -696,7 +695,6 @@ intrinsics: args: [any, acc] impl: panda::ecmascript::intrinsics::StrictEqDyn set_flags: [heap_inv] - use_thread: false - name: NewobjspreadDyn space: ecmascript @@ -784,6 +782,17 @@ intrinsics: args: [u16, u16, acc] impl: panda::ecmascript::intrinsics::StLexVarDyn +- name: StLexDyn + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: StLexDyn + static: true + exception: true + signature: + ret: any + args: [string_id, u16, u16, acc] + impl: panda::ecmascript::intrinsics::StLexDyn + - name: LdLexVarDyn space: ecmascript class_name: Ecmascript.Intrinsics @@ -798,6 +807,17 @@ intrinsics: clear_flags: [no_dce] codegen_func: LdLexVarDyn +- name: LdLexDyn + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: LdLexDyn + static: true + exception: true + signature: + ret: any + args: [string_id, u16, u16] + impl: panda::ecmascript::intrinsics::LdLexDyn + - name: LdlexenvDyn space: ecmascript class_name: Ecmascript.Intrinsics @@ -1172,16 +1192,16 @@ intrinsics: args: [string_id] impl: panda::ecmascript::intrinsics::ThrowConstAssignment -- name: ThrowUndefinedIfHole +- name: ThrowTdz space: ecmascript class_name: Ecmascript.Intrinsics - method_name: throwUndefinedIfHole + method_name: throwTdz static: true exception: true signature: - ret: any - args: [string_id, acc] - impl: panda::ecmascript::intrinsics::ThrowUndefinedIfHole + ret: void + args: [string_id] + impl: panda::ecmascript::intrinsics::ThrowTdz - name: Copyrestargs space: ecmascript @@ -1303,18 +1323,6 @@ intrinsics: fast_path: FastPathStGlobalVar set_flags: [heap_inv] -- name: StGlobalLet - space: ecmascript - class_name: Ecmascript.Intrinsics - method_name: StGlobalLet - static: true - exception: true - signature: - ret: any - args: [string_id, acc] - impl: panda::ecmascript::intrinsics::StGlobalLet - set_flags: [heap_inv] - - name: LdObjByName space: ecmascript class_name: Ecmascript.Intrinsics @@ -1323,7 +1331,7 @@ intrinsics: exception: true signature: ret: any - args: [string_id, any, u16] + args: [string_id, acc, u16] impl: panda::ecmascript::intrinsics::LdObjByName fast_path: FastPathLdObjByName set_flags: [heap_inv] @@ -1349,7 +1357,7 @@ intrinsics: exception: true signature: ret: any - args: [u32, any] + args: [u32, acc] impl: panda::ecmascript::intrinsics::LdObjByIndex set_flags: [heap_inv] @@ -1395,7 +1403,7 @@ intrinsics: exception: true signature: ret: any - args: [any] + args: [acc] impl: panda::ecmascript::intrinsics::Call0Dyn set_flags: [heap_inv] @@ -1407,7 +1415,7 @@ intrinsics: exception: true signature: ret: any - args: [any, any] + args: [any, acc] impl: panda::ecmascript::intrinsics::Call1Dyn set_flags: [heap_inv] @@ -1419,7 +1427,7 @@ intrinsics: exception: true signature: ret: any - args: [any, any, any] + args: [any, any, acc] impl: panda::ecmascript::intrinsics::Call2Dyn set_flags: [heap_inv] @@ -1431,10 +1439,58 @@ intrinsics: exception: true signature: ret: any - args: [any, any, any, any] + args: [any, any, any, acc] impl: panda::ecmascript::intrinsics::Call3Dyn set_flags: [heap_inv] +- name: Call0ThisDyn + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: Call0ThisDyn + static: true + exception: true + signature: + ret: any + args: [any, acc] + impl: panda::ecmascript::intrinsics::Call0ThisDyn + set_flags: [heap_inv] + +- name: Call1ThisDyn + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: Call1ThisDyn + static: true + exception: true + signature: + ret: any + args: [any, any, acc] + impl: panda::ecmascript::intrinsics::Call1ThisDyn + set_flags: [heap_inv] + +- name: Call2ThisDyn + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: Call2ThisDyn + static: true + exception: true + signature: + ret: any + args: [any, any, any, acc] + impl: panda::ecmascript::intrinsics::Call2ThisDyn + set_flags: [heap_inv] + +- name: Call3ThisDyn + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: Call3ThisDyn + static: true + exception: true + signature: + ret: any + args: [any, any, any, any, acc] + impl: panda::ecmascript::intrinsics::Call3ThisDyn + set_flags: [heap_inv] + - name: CalliRangeDyn space: ecmascript class_name: Ecmascript.Intrinsics @@ -1541,6 +1597,18 @@ intrinsics: args: [u16] impl: panda::ecmascript::intrinsics::CreateArrayWithBuffer +- name: CreateRegExpWithLiteral + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: createregexpwithliteral + static: true + exception: true + signature: + ret: any + args: [string_id, u8] + impl: panda::ecmascript::intrinsics::CreateRegExpWithLiteral + + - name: StOwnByName space: ecmascript class_name: Ecmascript.Intrinsics @@ -1717,6 +1785,28 @@ intrinsics: clear_flags: [no_dce] set_flags: [heap_inv] +- name: LoadClassComputedInstanceFields + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: LoadClassComputedInstanceFields + static: true + exception: true + signature: + ret: any + args: [any] + impl: panda::ecmascript::intrinsics::LoadClassComputedInstanceFields + +- name: SetClassComputedFields + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: SetClassComputedFields + static: true + exception: true + signature: + ret: void + args: [any, any] + impl: panda::ecmascript::intrinsics::SetClassComputedFields + - name: DefineClassWithBuffer space: ecmascript class_name: Ecmascript.Intrinsics @@ -1728,6 +1818,83 @@ intrinsics: args: [method_id, u16, any, any] impl: panda::ecmascript::intrinsics::DefineClassWithBuffer +- name: ClassFieldAdd + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: ClassFieldAdd + static: true + exception: true + signature: + ret: any + args: [any, any, acc] + impl: panda::ecmascript::intrinsics::ClassFieldAdd + +- name: DefineClassPrivateFields + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: DefineClassPrivateFields + static: true + exception: true + signature: + ret: void + args: [u16, any, acc] + impl: panda::ecmascript::intrinsics::DefineClassPrivateFields + +- name: ClassPrivateMethodOrAccessorAdd + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: ClassPrivateMethodOrAccessorAdd + static: true + exception: true + signature: + ret: any + args: [any, any] + impl: panda::ecmascript::intrinsics::ClassPrivateMethodOrAccessorAdd + +- name: ClassPrivateFieldAdd + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: ClassPrivateFieldAdd + static: true + exception: true + signature: + ret: any + args: [string_id, any, any, acc] + impl: panda::ecmascript::intrinsics::ClassPrivateFieldAdd + +- name: ClassPrivateFieldGet + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: ClassPrivateFieldGet + static: true + exception: true + signature: + ret: any + args: [string_id, any, any] + impl: panda::ecmascript::intrinsics::ClassPrivateFieldGet + +- name: ClassPrivateFieldSet + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: ClassPrivateFieldSet + static: true + exception: true + signature: + ret: any + args: [string_id, any, any, acc] + impl: panda::ecmascript::intrinsics::ClassPrivateFieldSet + +- name: ClassPrivateFieldIn + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: ClassPrivateFieldIn + static: true + exception: true + signature: + ret: any + args: [string_id, any, acc] + impl: panda::ecmascript::intrinsics::ClassPrivateFieldIn + - name: SuperCall space: ecmascript class_name: Ecmascript.Intrinsics @@ -1771,7 +1938,7 @@ intrinsics: exception: true signature: ret: any - args: [string_id, any] + args: [string_id, acc] impl: panda::ecmascript::intrinsics::LdSuperByName set_flags: [heap_inv] @@ -1783,7 +1950,7 @@ intrinsics: exception: true signature: ret: any - args: [string_id, any, any] + args: [string_id, any, acc] impl: panda::ecmascript::intrinsics::StSuperByName set_flags: [heap_inv] @@ -1807,7 +1974,7 @@ intrinsics: exception: true signature: ret: any - args: [any, any] + args: [any, acc] impl: panda::ecmascript::intrinsics::LdSuperByValue set_flags: [heap_inv] @@ -1866,6 +2033,50 @@ intrinsics: args: [] impl: panda::ecmascript::intrinsics::ThrowDeleteSuperProperty +- name: LdEvalBindings + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: LdEvalBindings + static: true + exception: true + signature: + ret: any + args: [u16] + impl: panda::ecmascript::intrinsics::LdEvalBindings + +- name: DirectEval + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: DirectEval + static: true + exception: true + signature: + ret: any + args: [u32, any, any] + impl: panda::ecmascript::intrinsics::DirectEval + +- name: LdEvalVar + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: LdEvalVar + static: true + exception: true + signature: + ret: any + args: [string_id, acc] + impl: panda::ecmascript::intrinsics::LdEvalVar + +- name: StEvalVar + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: StEvalVar + static: true + exception: true + signature: + ret: any + args: [string_id, any, acc] + impl: panda::ecmascript::intrinsics::StEvalVar + - name: Debugger space: ecmascript class_name: Ecmascript.Intrinsics diff --git a/runtime/ecma_vm.cpp b/runtime/ecma_vm.cpp index 2bae8e6ff..49898a7b8 100644 --- a/runtime/ecma_vm.cpp +++ b/runtime/ecma_vm.cpp @@ -14,6 +14,7 @@ */ #include "plugins/ecmascript/runtime/ecma_vm.h" +#include "include/mem/panda_string.h" #include "plugins/ecmascript/runtime/bridge.h" #include "js_tagged_value.h" @@ -248,7 +249,6 @@ bool EcmaVM::Initialize() globalEnvHandle->SetEmptyWeakArray(thread_, factory_->NewEmptyArray(true)); globalEnvHandle->SetEmptyLayoutInfo(thread_, factory_->CreateLayoutInfo(0)); globalEnvHandle->SetRegisterSymbols(thread_, SymbolTable::Create(thread_)); - globalEnvHandle->SetGlobalRecord(thread_, GlobalDictionary::Create(thread_)); JSTaggedValue empty_str = thread_->GlobalConstants()->GetEmptyString(); string_table_->InternEmptyString(EcmaString::Cast(empty_str.GetTaggedObject())); globalEnvHandle->SetEmptyTaggedQueue(thread_, factory_->NewTaggedQueue(0)); @@ -583,8 +583,8 @@ Expected EcmaVM::InvokeEntrypointImpl(Method *entrypoint, c return InvokeEcmaEntrypoint(*file, utf::Mutf8AsCString(entrypoint->GetName().data), args); } -Expected EcmaVM::InvokeEcmaEntrypoint(const panda_file::File &pf, const PandaString &method_name, - const std::vector &args) +Expected EcmaVM::GetInvocableFunction(const panda_file::File &pf, + const PandaString &method_name) { [[maybe_unused]] EcmaHandleScope scope(thread_); JSHandle program; @@ -603,7 +603,20 @@ Expected EcmaVM::InvokeEcmaEntrypoint(const panda_file::Fil return Unexpected(Runtime::Error::PANDA_FILE_LOAD_ERROR); } - JSHandle func = JSHandle(thread_, program->GetMainFunction()); + return program->GetMainFunction(); +} + +Expected EcmaVM::InvokeEcmaEntrypoint(const panda_file::File &pf, const PandaString &method_name, + const std::vector &args) +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + auto resolveFunc = GetInvocableFunction(pf, method_name); + + if (!resolveFunc.HasValue()) { + return Unexpected(resolveFunc.Error()); + } + + JSHandle func(thread_, resolveFunc.Value()); JSHandle global = GlobalEnv::Cast(global_env_.GetTaggedObject())->GetJSGlobalObject(); JSHandle new_target(thread_, JSTaggedValue::Undefined()); JSHandle jsargs = factory_->NewTaggedArray(args.size()); diff --git a/runtime/ecma_vm.h b/runtime/ecma_vm.h index 604f728a6..8406f864b 100644 --- a/runtime/ecma_vm.h +++ b/runtime/ecma_vm.h @@ -101,6 +101,9 @@ public: bool ExecuteFromBuffer(const void *buffer, size_t size, std::string_view entry_point, const std::vector &args); + Expected GetInvocableFunction(const panda_file::File &pf, + const PandaString &method_name); + PtJSExtractor *GetDebugInfoExtractor(const panda_file::File *file); bool IsInitialized() const @@ -546,6 +549,7 @@ private: friend class ObjectFactory; friend class panda::JSNApi; + friend class EvalUtils; }; } // namespace ecmascript } // namespace panda diff --git a/runtime/global_env.h b/runtime/global_env.h index 33978dc37..8e004373a 100644 --- a/runtime/global_env.h +++ b/runtime/global_env.h @@ -34,6 +34,7 @@ class JSThread; V(JSTaggedValue, FunctionFunction, FUNCTION_FUNCTION_INDEX) \ V(JSTaggedValue, FunctionPrototype, FUNCTION_PROTOTYPE_INDEX) \ V(JSTaggedValue, NumberFunction, NUMBER_FUNCTION_INDEX) \ + V(JSTaggedValue, BigIntFunction, BIGINT_FUNCTION_INDEX) \ V(JSTaggedValue, DateFunction, DATE_FUNCTION_INDEX) \ V(JSTaggedValue, BooleanFunction, BOOLEAN_FUNCTION_INDEX) \ V(JSTaggedValue, ErrorFunction, ERROR_FUNCTION_INDEX) \ @@ -50,6 +51,8 @@ class JSThread; V(JSTaggedValue, Uint32ArrayFunction, UINT32_ARRAY_FUNCTION_INDEX) \ V(JSTaggedValue, Float32ArrayFunction, FLOAT32_ARRAY_FUNCTION_INDEX) \ V(JSTaggedValue, Float64ArrayFunction, FLOAT64_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, BigInt64ArrayFunction, BIGINT64_ARRAY_FUNCTION_INDEX) \ + V(JSTaggedValue, BigUint64ArrayFunction, BIGUINT64_ARRAY_FUNCTION_INDEX) \ V(JSTaggedValue, ArrayBufferFunction, ARRAY_BUFFER_FUNCTION_INDEX) \ V(JSTaggedValue, ArrayProtoValuesFunction, ARRAY_PROTO_VALUES_FUNCTION_INDEX) \ V(JSTaggedValue, DataViewFunction, DATA_VIEW_FUNCTION_INDEX) \ @@ -150,8 +153,7 @@ class JSThread; V(JSTaggedValue, NormalFunctionClass, NORMAL_FUNCTION_CLASS) \ V(JSTaggedValue, JSIntlBoundFunctionClass, JS_INTL_BOUND_FUNCTION_CLASS) \ V(JSTaggedValue, NumberFormatLocales, NUMBER_FORMAT_LOCALES_INDEX) \ - V(JSTaggedValue, DateTimeFormatLocales, DATE_TIMEFORMAT_LOCALES_INDEX) \ - V(JSTaggedValue, GlobalRecord, GLOBAL_RECORD) + V(JSTaggedValue, DateTimeFormatLocales, DATE_TIMEFORMAT_LOCALES_INDEX) class GlobalEnv : public TaggedObject { public: diff --git a/runtime/global_env_constants.cpp b/runtime/global_env_constants.cpp index 8223769f0..7425cc9ef 100644 --- a/runtime/global_env_constants.cpp +++ b/runtime/global_env_constants.cpp @@ -70,6 +70,8 @@ void GlobalEnvConstants::InitRootsClass([[maybe_unused]] JSThread *thread, JSHCl JSHClass *weak_array_class = *factory->NewEcmaDynClass(dyn_class_class, 0, JSType::TAGGED_ARRAY, HClass::ARRAY); weak_array_class->SetWeakContainer(true); SetConstant(ConstantIndex::WEAK_ARRAY_CLASS_INDEX, JSTaggedValue(weak_array_class)); + SetConstant(ConstantIndex::BIGINT_CLASS_INDEX, + factory->NewEcmaDynClass(dyn_class_class, BigInt::SIZE, JSType::BIGINT).GetTaggedValue()); SetConstant(ConstantIndex::DICTIONARY_CLASS_INDEX, factory ->NewEcmaDynClass(dyn_class_class, 0, JSType::TAGGED_DICTIONARY, @@ -263,6 +265,7 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread) SetConstant(ConstantIndex::NULL_STRING_INDEX, factory->NewFromCanBeCompressString("null").GetTaggedValue()); SetConstant(ConstantIndex::BOOLEAN_STRING_INDEX, factory->NewFromCanBeCompressString("boolean").GetTaggedValue()); SetConstant(ConstantIndex::NUMBER_STRING_INDEX, factory->NewFromCanBeCompressString("number").GetTaggedValue()); + SetConstant(ConstantIndex::BIGINT_STRING_INDEX, factory->NewFromCanBeCompressString("bigint").GetTaggedValue()); SetConstant(ConstantIndex::FUNCTION_STRING_INDEX, factory->NewFromCanBeCompressString("function").GetTaggedValue()); SetConstant(ConstantIndex::STRING_STRING_INDEX, factory->NewFromCanBeCompressString("string").GetTaggedValue()); SetConstant(ConstantIndex::SYMBOL_STRING_INDEX, factory->NewFromCanBeCompressString("symbol").GetTaggedValue()); @@ -303,6 +306,10 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread) factory->NewFromCanBeCompressString("Float32Array").GetTaggedValue()); SetConstant(ConstantIndex::FLOAT64_ARRAY_STRING_INDEX, factory->NewFromCanBeCompressString("Float64Array").GetTaggedValue()); + SetConstant(ConstantIndex::BIGINT64_ARRAY_STRING_INDEX, + factory->NewFromCanBeCompressString("BigInt64Array").GetTaggedValue()); + SetConstant(ConstantIndex::BIGUINT64_ARRAY_STRING_INDEX, + factory->NewFromCanBeCompressString("BigUint64Array").GetTaggedValue()); SetConstant(ConstantIndex::ASYNC_FUNCTION_STRING_INDEX, factory->NewFromCanBeCompressString("AsyncFunction").GetTaggedValue()); SetConstant(ConstantIndex::PROMISE_RESOLVE_STRING_INDEX, diff --git a/runtime/global_env_constants.h b/runtime/global_env_constants.h index 1d0cc3270..beb994d1e 100644 --- a/runtime/global_env_constants.h +++ b/runtime/global_env_constants.h @@ -36,6 +36,7 @@ class JSThread; V(JSTaggedValue, StringClass, STRING_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ArrayClass, ARRAY_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, WeakArrayClass, WEAK_ARRAY_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, BigIntClass, BIGINT_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, DictionaryClass, DICTIONARY_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSNativePointerClass, JS_NATIVE_POINTER_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, EnvClass, ENV_CLASS_INDEX, ecma_roots_class) \ @@ -119,6 +120,7 @@ class JSThread; V(JSTaggedValue, NullString, NULL_STRING_INDEX, null) \ V(JSTaggedValue, BooleanString, BOOLEAN_STRING_INDEX, boolean) \ V(JSTaggedValue, NumberString, NUMBER_STRING_INDEX, number) \ + V(JSTaggedValue, BigIntString, BIGINT_STRING_INDEX, bigint) \ V(JSTaggedValue, FunctionString, FUNCTION_STRING_INDEX, function) \ V(JSTaggedValue, StringString, STRING_STRING_INDEX, string) \ V(JSTaggedValue, SymbolString, SYMBOL_STRING_INDEX, symbol) \ @@ -146,6 +148,8 @@ class JSThread; V(JSTaggedValue, Uint32ArrayString, UINT32_ARRAY_STRING_INDEX, Uint32Array) \ V(JSTaggedValue, Float32ArrayString, FLOAT32_ARRAY_STRING_INDEX, Float32Array) \ V(JSTaggedValue, Float64ArrayString, FLOAT64_ARRAY_STRING_INDEX, Float64Array) \ + V(JSTaggedValue, BigInt64ArrayString, BIGINT64_ARRAY_STRING_INDEX, BigInt64Array) \ + V(JSTaggedValue, BigUint64ArrayString, BIGUINT64_ARRAY_STRING_INDEX, BigUint64Array) \ V(JSTaggedValue, AsyncFunctionString, ASYNC_FUNCTION_STRING_INDEX, AsyncFunction) \ V(JSTaggedValue, PromiseResolveString, PROMISE_RESOLVE_STRING_INDEX, resolve) \ V(JSTaggedValue, IdString, ID_STRING_INDEX, id) \ diff --git a/runtime/ic/ic_runtime.cpp b/runtime/ic/ic_runtime.cpp index 5338d6a7c..550b116b6 100644 --- a/runtime/ic/ic_runtime.cpp +++ b/runtime/ic/ic_runtime.cpp @@ -132,17 +132,6 @@ JSTaggedValue LoadICRuntime::LoadMiss(JSHandle receiver, JSHandle return JSTaggedValue::GetProperty(thread_, receiver, key).GetValue().GetTaggedValue(); } - // global variable find from global record firstly - if (GetICKind() == ICKind::TRY_NAMED_GLOBAL_LOAD_IC) { - bool found = false; - JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue(), &found); - if (found) { - ASSERT(box.IsPropertyBox()); - ic_accessor_.AddGlobalRecordHandler(JSHandle(thread_, box)); - return PropertyBox::Cast(box.GetTaggedObject())->GetValue(); - } - } - ObjectOperator op(GetThread(), receiver, key); auto result = JSHandle(thread_, JSObject::GetProperty(GetThread(), &op)); if (!op.IsFound() && @@ -180,22 +169,8 @@ JSTaggedValue StoreICRuntime::StoreMiss(JSHandle receiver, JSHand return JSTaggedValue::Undefined(); } - // global variable find from global record firstly if (GetICKind() == ICKind::TRY_NAMED_GLOBAL_STORE_IC) { bool found = false; - JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue(), &found); - if (found) { - ASSERT(box.IsPropertyBox()); - SlowRuntimeStub::TryUpdateGlobalRecord(thread_, key.GetTaggedValue(), value.GetTaggedValue()); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); - // CSA reports usage of 'box' variable after GC in TryUpdateGlobalRecord. - // GC could be triggered when the function throws an exception. - // In this case the next line will not be executed because we check the exception in the previous line - // and return. - // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) - ic_accessor_.AddGlobalRecordHandler(JSHandle(thread_, box)); - return JSTaggedValue::Undefined(); - } FastRuntimeStub::GetGlobalOwnProperty(receiver.GetTaggedValue(), key.GetTaggedValue(), &found); if (!found) { return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not defined"); diff --git a/runtime/ic/profile_type_info.cpp b/runtime/ic/profile_type_info.cpp index a7e9cc569..e62d72fb6 100644 --- a/runtime/ic/profile_type_info.cpp +++ b/runtime/ic/profile_type_info.cpp @@ -101,12 +101,6 @@ void ProfileTypeAccessor::AddGlobalHandlerKey(JSHandle key, JSHan profile_type_info_->Set(thread_, slot_id_, JSTaggedValue::Hole()); } -void ProfileTypeAccessor::AddGlobalRecordHandler(JSHandle handler) const -{ - uint32_t index = slot_id_; - profile_type_info_->Set(thread_, index, handler.GetTaggedValue()); -} - void ProfileTypeAccessor::SetAsMega() const { profile_type_info_->Set(thread_, slot_id_, JSTaggedValue::Hole()); diff --git a/runtime/ic/profile_type_info.h b/runtime/ic/profile_type_info.h index d6dc8a205..1997f456b 100644 --- a/runtime/ic/profile_type_info.h +++ b/runtime/ic/profile_type_info.h @@ -122,8 +122,16 @@ public: void AddHandlerWithKey(JSHandle key, JSHandle dynclass, JSHandle handler) const; void AddGlobalHandlerKey(JSHandle key, JSHandle handler) const; - void AddGlobalRecordHandler(JSHandle handler) const; + JSTaggedValue GetWeakRef(JSTaggedValue value) const + { + return JSTaggedValue(value.CreateAndGetWeakRef()); + } + + JSTaggedValue GetRefFromWeak(const JSTaggedValue &value) const + { + return JSTaggedValue(value.GetWeakReferent()); + } void SetAsMega() const; ICKind GetKind() const diff --git a/runtime/interpreter/ecma-interpreter-inl.h b/runtime/interpreter/ecma-interpreter-inl.h index a3566204f..b9e4c7ed0 100644 --- a/runtime/interpreter/ecma-interpreter-inl.h +++ b/runtime/interpreter/ecma-interpreter-inl.h @@ -81,13 +81,14 @@ public: ALWAYS_INLINE static void CopyArgumentsDyn(InstructionHandler *instr_handler, Frame *new_frame, uint32_t num_vregs, uint32_t num_actual_args) { - uint16_t prev_v0 = instr_handler->GetInst().template GetVReg(); Frame *prev_frame = instr_handler->GetFrame(); BytecodeInstruction prev_inst = instr_handler->GetInst(); auto *thread = JSThread::Cast(instr_handler->GetThread()); - JSCopyArgumets(thread, prev_frame, prev_v0, prev_inst, new_frame, num_vregs, - num_actual_args); + uint64_t prev_raw_func_obj = JSGetCalleDyn(prev_frame, prev_inst); + + JSCopyArgumets(thread, prev_frame, prev_raw_func_obj, prev_inst, new_frame, + num_vregs, num_actual_args); } template @@ -203,10 +204,11 @@ public: ALWAYS_INLINE void DoEcmaCallDyn() { this->UpdateBytecodeOffset(); + this->SaveAccToFrame(); - uint16_t v0 = this->GetInst().template GetVReg(); - uint64_t function = GetRegAsTaggedValue(v0).GetRawData(); JSThread *js_thread = this->GetJSThread(); + uint64_t function = JSGetCalleDyn(js_thread->GetCurrentFrame(), this->GetInst()); + if (UNLIKELY(!JSTaggedValue(function).IsCallable())) { JSHandle error = GetFactory()->GetJSError(ErrorType::TYPE_ERROR, "is not callable"); js_thread->SetException(error.GetTaggedValue()); @@ -229,7 +231,7 @@ public: Frame *frame = JSFrame::CreateNativeFrame(js_thread, method, js_thread->GetCurrentFrame(), num_args, num_actual_args); - JSCopyArgumets(this->GetJSThread(), prev_frame, v0, prev_inst, frame, 0, + JSCopyArgumets(this->GetJSThread(), prev_frame, function, prev_inst, frame, 0, num_actual_args); // Call native method @@ -288,23 +290,20 @@ public: template ALWAYS_INLINE void HandleEcmaCall0dyn() { - auto v0 = this->GetInst().template GetVReg(); - LOG_INST() << "call0.dyn " - << "v" << v0; + LOG_INST() << "call0.dyn"; - this->template DoEcmaCallDyn(); + this->template DoEcmaCallDyn(); } template ALWAYS_INLINE void HandleEcmaCall1dyn() { auto v0 = this->GetInst().template GetVReg(); - auto v1 = this->GetInst().template GetVReg(); LOG_INST() << "call1.dyn " - << "v" << v0 << ", v" << v1; + << "v" << v0; - this->template DoEcmaCallDyn(); + this->template DoEcmaCallDyn(); } template @@ -312,11 +311,10 @@ public: { auto v0 = this->GetInst().template GetVReg(); auto v1 = this->GetInst().template GetVReg(); - auto v2 = this->GetInst().template GetVReg(); LOG_INST() << "call2.dyn " - << "v" << v0 << ", v" << v1 << ", v" << v2; + << "v" << v0 << ", v" << v1; - this->template DoEcmaCallDyn(); + this->template DoEcmaCallDyn(); } template @@ -325,11 +323,57 @@ public: auto v0 = this->GetInst().template GetVReg(); auto v1 = this->GetInst().template GetVReg(); auto v2 = this->GetInst().template GetVReg(); - auto v3 = this->GetInst().template GetVReg(); LOG_INST() << "call3.dyn " - << "v" << v0 << ", v" << v1 << ", v" << v2 << ", v" << v3; + << "v" << v0 << ", v" << v1 << ", v" << v2; + + this->template DoEcmaCallDyn(); + } + + template + ALWAYS_INLINE void HandleEcmaCall0thisdyn() + { + auto v0 = this->GetInst().template GetVReg(); + + LOG_INST() << "callthis0.dyn " + << "this v:" << v0; + + this->template DoEcmaCallDyn(); + } + + template + ALWAYS_INLINE void HandleEcmaCall1thisdyn() + { + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + LOG_INST() << "callthis1.dyn " + << "this v" << v0 << ", v" << v1; + + this->template DoEcmaCallDyn(); + } + + template + ALWAYS_INLINE void HandleEcmaCall2thisdyn() + { + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + auto v2 = this->GetInst().template GetVReg(); + LOG_INST() << "callthis2.dyn " + << "this v" << v0 << ", v" << v1 << ", v" << v2; - this->template DoEcmaCallDyn(); + this->template DoEcmaCallDyn(); + } + + template + ALWAYS_INLINE void HandleEcmaCall3thisdyn() + { + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + auto v2 = this->GetInst().template GetVReg(); + auto v3 = this->GetInst().template GetVReg(); + LOG_INST() << "callthis3.dyn " + << "this v" << v0 << ", v" << v1 << ", v" << v2 << ", v" << v3; + + this->template DoEcmaCallDyn(); } template @@ -474,6 +518,16 @@ public: this->template MoveToNextInst(); } + template + ALWAYS_INLINE void HandleEcmaLdbigint() + { + auto bigInt = this->GetInst().template GetId(); + LOG_INST() << "ld.bigint " << bigInt << "n"; + + INTRINSIC_CALL_SETACC(intrinsics::Ldbigint(this->GetJSThread(), bigInt.AsIndex())); + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleEcmaLdlexenvdyn() { @@ -528,13 +582,6 @@ public: UNREACHABLE(); } - template - ALWAYS_INLINE void HandleEcmaLdbigint() - { - // it38 Unimplement - UNREACHABLE(); - } - template ALWAYS_INLINE void HandleEcmaTonumber() { @@ -1289,7 +1336,7 @@ public: uint64_t left = GetRegAsTaggedValue(v0).GetRawData(); uint64_t right = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_SETACC(intrinsics::StrictNotEqDyn(left, right)); + INTRINSIC_CALL_SETACC(intrinsics::StrictNotEqDyn(this->GetJSThread(), left, right)); this->template MoveToNextInst(); } @@ -1302,7 +1349,7 @@ public: uint64_t left = GetRegAsTaggedValue(v0).GetRawData(); uint64_t right = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::StrictEqDyn(left, right)); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::StrictEqDyn(this->GetJSThread(), left, right)); this->template MoveToNextInst(); } @@ -1318,6 +1365,21 @@ public: this->template MoveToNextInst(); } + template + ALWAYS_INLINE void HandleEcmaLdlexdyn() + { + auto string_id = this->GetInst().template GetId(); + auto prop = GetConstantPool(this->GetJSThread())->GetObjectFromCache(string_id.AsIndex()); + auto level = this->GetInst().template GetImm(); + auto slot = this->GetInst().template GetImm(); + LOG_INST() << "ldlexdyn" + << " string_id:" << ConvertToPandaString(EcmaString::Cast(prop.GetHeapObject())) + << " level:" << level << " slot:" << slot; + + INTRINSIC_CALL_SETACC(intrinsics::LdLexDyn(string_id.AsIndex(), level, slot)); + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleEcmaStlexvardyn() { @@ -1333,6 +1395,23 @@ public: this->template MoveToNextInst(); } + template + ALWAYS_INLINE void HandleEcmaStlexdyn() + { + auto string_id = this->GetInst().template GetId(); + auto prop = GetConstantPool(this->GetJSThread())->GetObjectFromCache(string_id.AsIndex()); + auto level = this->GetInst().template GetImm(); + auto slot = this->GetInst().template GetImm(); + LOG_INST() << "stlexdyn" + << " string_id:" << ConvertToPandaString(EcmaString::Cast(prop.GetHeapObject())) + << " level:" << level << " slot:" << slot; + + uint64_t value = GetAccAsTaggedValue().GetRawData(); + INTRINSIC_CALL_CHECK(intrinsics::StLexDyn(string_id.AsIndex(), level, slot, value)); + + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleEcmaNewlexenvdyn() { @@ -1504,20 +1583,15 @@ public: } template - ALWAYS_INLINE void HandleEcmaThrowundefinedifhole() + ALWAYS_INLINE void HandleEcmaThrowtdz() { auto string_id = this->GetInst().template GetId(); auto prop = GetConstantPool(this->GetJSThread())->GetObjectFromCache(string_id.AsIndex()); LOG_INST() << "intrinsic::throwundefinedifhole " << "string_id:" << ConvertToPandaString(EcmaString::Cast(prop.GetHeapObject())); - if (!GetAccAsTaggedValue().IsHole()) { - this->template MoveToNextInst(); - return; - } - auto thread = JSThread::Cast(this->GetThread()); - SlowRuntimeStub::ThrowUndefinedIfHole(thread, prop); + SlowRuntimeStub::ThrowTdz(thread, prop); this->MoveToExceptionHandler(); } @@ -1579,6 +1653,19 @@ public: this->template MoveToNextInst(); } + template + ALWAYS_INLINE void HandleEcmaCreateregexpwithliteral() + { + auto string_id = this->GetInst().template GetId(); + auto flags = this->GetInst().template GetImm(); + LOG_INST() << "createregexpwithliteral" + << " string_id: " << string_id << " flags:" << flags; + + INTRINSIC_CALL_CHECK_SETACC( + intrinsics::CreateRegExpWithLiteral(this->GetJSThread(), string_id.AsIndex(), flags)); + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleEcmaImportmodule() { @@ -1837,11 +1924,10 @@ public: ALWAYS_INLINE void HandleEcmaLdobjbyindex() { uint32_t idx = this->GetInst().template GetImm(); - auto v0 = this->GetInst().template GetVReg(); LOG_INST() << "ldobjbyindex" - << " v" << v0 << " imm" << idx; + << " imm" << idx; - uint64_t obj = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t obj = GetAccAsTaggedValue().GetRawData(); INTRINSIC_CALL_CHECK_SETACC(intrinsics::LdObjByIndex(this->GetJSThread(), idx, obj)); this->template MoveToNextInst(); @@ -1868,12 +1954,11 @@ public: ALWAYS_INLINE void HandleEcmaLdobjbyvalue() { auto v0 = this->GetInst().template GetVReg(); - auto v1 = this->GetInst().template GetVReg(); LOG_INST() << "Ldobjbyvalue" - << " v" << v0 << " v" << v1; + << " v" << v0; uint64_t receiver = GetRegAsTaggedValue(v0).GetRawData(); - uint64_t prop_key = GetRegAsTaggedValue(v1).GetRawData(); + uint64_t prop_key = GetAccAsTaggedValue().GetRawData(); INTRINSIC_CALL_CHECK_SETACC( intrinsics::LdObjByValue(this->GetJSThread(), receiver, prop_key, this->GetBytecodeOffset())); @@ -1903,12 +1988,11 @@ public: ALWAYS_INLINE void HandleEcmaLdsuperbyvalue() { auto v0 = this->GetInst().template GetVReg(); - auto v1 = this->GetInst().template GetVReg(); LOG_INST() << "Ldsuperbyvalue" - << " v" << v0 << " v" << v1; + << " v" << v0; uint64_t receiver = GetRegAsTaggedValue(v0).GetRawData(); - uint64_t prop_key = GetRegAsTaggedValue(v1).GetRawData(); + uint64_t prop_key = GetAccAsTaggedValue().GetRawData(); INTRINSIC_CALL_CHECK_SETACC(intrinsics::LdSuperByValue(this->GetJSThread(), receiver, prop_key)); this->template MoveToNextInst(); @@ -1974,11 +2058,11 @@ public: template ALWAYS_INLINE void HandleEcmaLdobjbyname() { - auto v0 = this->GetInst().template GetVReg(); auto string_id = this->GetInst().template GetId(); - LOG_INST() << "ldobjbyname v" << v0 << " string_id:" << string_id; - uint64_t obj = GetRegAsTaggedValue(v0).GetRawData(); + LOG_INST() << "ldobjbyname" + << " string_id:" << string_id; + uint64_t obj = GetAccAsTaggedValue().GetRawData(); INTRINSIC_CALL_CHECK_SETACC( intrinsics::LdObjByName(this->GetJSThread(), string_id.AsIndex(), obj, this->GetBytecodeOffset())); @@ -2007,13 +2091,12 @@ public: template ALWAYS_INLINE void HandleEcmaLdsuperbyname() { - auto v0 = this->GetInst().template GetVReg(); auto string_id = this->GetInst().template GetId(); LOG_INST() << "ldsuperbyname" - << "v" << v0 << " string_id:" << string_id.AsIndex(); + << " string_id:" << string_id.AsIndex(); - uint64_t obj = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t obj = GetAccAsTaggedValue().GetRawData(); INTRINSIC_CALL_CHECK_SETACC(intrinsics::LdSuperByName(this->GetJSThread(), string_id.AsIndex(), obj)); this->template MoveToNextInst(); @@ -2054,22 +2137,6 @@ public: this->template MoveToNextInst(); } - template - ALWAYS_INLINE void HandleEcmaStgloballet() - { - auto string_id = this->GetInst().template GetId(); - - LOG_INST() << "stgloballet " - << "string_id:" << string_id.AsIndex(); - - uint64_t value = GetAccAsTaggedValue().GetRawData(); - - SaveAccToFrame(); - INTRINSIC_CALL_CHECK(intrinsics::StGlobalLet(this->GetJSThread(), string_id.AsIndex(), value)); - RestoreAccFromFrame(); - this->template MoveToNextInst(); - } - template ALWAYS_INLINE void HandleEcmaCreategeneratorobj() { @@ -2122,10 +2189,35 @@ public: uint64_t index = GetRegAsTaggedValue(v1).GetRawData(); uint64_t src = GetAccAsTaggedValue().GetRawData(); - SaveAccToFrame(); - INTRINSIC_CALL_CHECK(intrinsics::StArraySpread(this->GetJSThread(), dst, index, src)); - RestoreAccFromFrame(); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::StArraySpread(this->GetJSThread(), dst, index, src)); + this->template MoveToNextInst(); + } + template + ALWAYS_INLINE void HandleEcmaLoadclasscomputedinstancefields() + { + auto v0 = this->GetInst().template GetVReg(); + LOG_INST() << "loadclasscomputedinstancefields" + << " v" << v0; + + uint64_t ctor = GetRegAsTaggedValue(v0).GetRawData(); + + SetAccFromTaggedValue(JSTaggedValue(intrinsics::LoadClassComputedInstanceFields(this->GetJSThread(), ctor))); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaSetclasscomputedfields() + { + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + LOG_INST() << "setclasscomputedfields" + << " class_reg v:" << v0 << " computed_fields v:" << v1; + + uint64_t classReg = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t computedFields = GetRegAsTaggedValue(v1).GetRawData(); + + intrinsics::SetClassComputedFields(this->GetJSThread(), classReg, computedFields); this->template MoveToNextInst(); } @@ -2147,6 +2239,124 @@ public: this->template MoveToNextInst(); } + template + ALWAYS_INLINE void HandleEcmaClassfieldadd() + { + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + LOG_INST() << "classfieldadd" + << " obj: v" << v0 << " prop: v" << v1; + + uint64_t obj = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t prop = GetRegAsTaggedValue(v1).GetRawData(); + uint64_t value = GetAccAsTaggedValue().GetRawData(); + + INTRINSIC_CALL_CHECK_SETACC(intrinsics::ClassFieldAdd(this->GetJSThread(), obj, prop, value)); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaDefineclassprivatefields() + { + auto literalarray_id = this->GetInst().template GetId(); + LOG_INST() << "ldevalbindings" + << " literalArrayId:" << literalarray_id.AsIndex(); + + auto v0 = this->GetInst().template GetVReg(); + LOG_INST() << "defineclassprivatefields" + << " literalArrayId:" << literalarray_id.AsIndex() << " v0:" << v0; + + uint64_t env = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t ctor = GetAccAsTaggedValue().GetRawData(); + + intrinsics::DefineClassPrivateFields(this->GetJSThread(), literalarray_id.AsIndex(), env, ctor); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaClassprivatemethodoraccessoradd() + { + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + LOG_INST() << "classprivatemethodoraccessoradd" + << " ctor: v" << v0 << " obj: v" << v1; + + uint64_t ctor = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t obj = GetRegAsTaggedValue(v1).GetRawData(); + + INTRINSIC_CALL_CHECK_SETACC(intrinsics::ClassPrivateMethodOrAccessorAdd(this->GetJSThread(), ctor, obj)); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaClassprivatefieldadd() + { + auto string_id = this->GetInst().template GetId(); + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + LOG_INST() << "classprivatefieldadd" + << " string id:" << string_id << " ctor: v" << v0 << " obj: v" << v1; + + uint64_t ctor = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t obj = GetRegAsTaggedValue(v1).GetRawData(); + uint64_t value = GetAccAsTaggedValue().GetRawData(); + + INTRINSIC_CALL_CHECK_SETACC( + intrinsics::ClassPrivateFieldAdd(this->GetJSThread(), string_id.AsIndex(), ctor, obj, value)); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaClassprivatefieldget() + { + auto string_id = this->GetInst().template GetId(); + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + LOG_INST() << "classprivatefieldadd" + << " string id:" << string_id << " private contexts: v" << v0 << " obj: v" << v1; + + uint64_t ctor = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t obj = GetRegAsTaggedValue(v1).GetRawData(); + + INTRINSIC_CALL_CHECK_SETACC( + intrinsics::ClassPrivateFieldGet(this->GetJSThread(), string_id.AsIndex(), ctor, obj)); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaClassprivatefieldset() + { + auto string_id = this->GetInst().template GetId(); + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + LOG_INST() << "classprivatefieldset" + << " string id:" << string_id << " private contexts: v" << v0 << " obj: v" << v1; + + uint64_t ctor = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t obj = GetRegAsTaggedValue(v1).GetRawData(); + uint64_t value = GetAccAsTaggedValue().GetRawData(); + + INTRINSIC_CALL_CHECK_SETACC( + intrinsics::ClassPrivateFieldSet(this->GetJSThread(), string_id.AsIndex(), ctor, obj, value)); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaClassprivatefieldin() + { + auto string_id = this->GetInst().template GetId(); + auto v0 = this->GetInst().template GetVReg(); + LOG_INST() << "classprivatefieldin" + << " string id:" << string_id << " private contexts: v" << v0; + + uint64_t ctor = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t obj = GetAccAsTaggedValue().GetRawData(); + + INTRINSIC_CALL_CHECK_SETACC( + intrinsics::ClassPrivateFieldIn(this->GetJSThread(), string_id.AsIndex(), ctor, obj)); + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleEcmaSupercall() { @@ -2274,6 +2484,64 @@ public: this->template MoveToNextInst(); } + template + ALWAYS_INLINE void HandleEcmaLdevalbindings() + { + auto literalarray_id = this->GetInst().template GetId(); + LOG_INST() << "ldevalbindings" + << " literalArrayId:" << literalarray_id.AsIndex(); + + INTRINSIC_CALL_SETACC(intrinsics::LdEvalBindings(this->GetJSThread(), literalarray_id.AsIndex())); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaDirecteval() + { + auto imm = this->GetInst().template GetImm(); + auto v0 = this->GetInst().template GetVReg(); + auto v1 = this->GetInst().template GetVReg(); + + LOG_INST() << "directeval" + << " status:" << imm << " v0:" << v0 << " v1:" << v1; + + uint64_t arg0 = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t evalBindings = GetRegAsTaggedValue(v1).GetRawData(); + + INTRINSIC_CALL_CHECK_SETACC(intrinsics::DirectEval(this->GetJSThread(), imm, arg0, evalBindings)); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaLdevalvar() + { + auto id = this->GetInst().template GetId(); + + LOG_INST() << "ldevalvar" + << " name:" << id.AsIndex(); + + uint64_t lexicalContext = GetAccAsTaggedValue().GetRawData(); + + INTRINSIC_CALL_CHECK_SETACC(intrinsics::LdEvalVar(this->GetJSThread(), id.AsIndex(), lexicalContext)); + this->template MoveToNextInst(); + } + + template + ALWAYS_INLINE void HandleEcmaStevalvar() + { + auto id = this->GetInst().template GetId(); + auto v0 = this->GetInst().template GetVReg(); + + LOG_INST() << "stevalvar" + << " name:" << id.AsIndex() << " v0:" << v0; + + uint64_t value = GetRegAsTaggedValue(v0).GetRawData(); + uint64_t lexicalContext = GetAccAsTaggedValue().GetRawData(); + + INTRINSIC_CALL_CHECK_SETACC(intrinsics::StEvalVar(this->GetJSThread(), id.AsIndex(), value, lexicalContext)); + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleEcmaDebugger() { diff --git a/runtime/interpreter/fast_runtime_stub-inl.h b/runtime/interpreter/fast_runtime_stub-inl.h index 8edd4461b..52437167c 100644 --- a/runtime/interpreter/fast_runtime_stub-inl.h +++ b/runtime/interpreter/fast_runtime_stub-inl.h @@ -129,7 +129,7 @@ JSTaggedValue FastRuntimeStub::FastEqual(JSTaggedValue left, JSTaggedValue right return JSTaggedValue::Hole(); } -bool FastRuntimeStub::FastStrictEqual(JSTaggedValue left, JSTaggedValue right) +bool FastRuntimeStub::FastStrictEqual(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { if (left.IsNumber()) { if (right.IsNumber()) { @@ -149,6 +149,9 @@ bool FastRuntimeStub::FastStrictEqual(JSTaggedValue left, JSTaggedValue right) return EcmaString::StringsAreEqual(static_cast(left.GetTaggedObject()), static_cast(right.GetTaggedObject())); } + if (left.IsBigInt() && right.IsBigInt()) { + return BigInt::Equal(thread, left, right); + } return false; } @@ -622,6 +625,9 @@ JSTaggedValue FastRuntimeStub::FastTypeOf(JSThread *thread, JSTaggedValue obj) if (obj.IsSymbol()) { return global_const->GetSymbolString(); } + if (obj.IsBigInt()) { + return global_const->GetBigIntString(); + } if (obj.IsCallable()) { return global_const->GetFunctionString(); } diff --git a/runtime/interpreter/fast_runtime_stub.h b/runtime/interpreter/fast_runtime_stub.h index c68cc389c..af74653df 100644 --- a/runtime/interpreter/fast_runtime_stub.h +++ b/runtime/interpreter/fast_runtime_stub.h @@ -34,7 +34,7 @@ public: static inline JSTaggedValue FastMod(JSTaggedValue left, JSTaggedValue right); static inline JSTaggedValue FastEqual(JSTaggedValue left, JSTaggedValue right); static inline JSTaggedValue FastTypeOf(JSThread *thread, JSTaggedValue obj); - static inline bool FastStrictEqual(JSTaggedValue left, JSTaggedValue right); + static inline bool FastStrictEqual(JSThread *thread, JSTaggedValue left, JSTaggedValue right); static inline JSTaggedValue NewLexicalEnvDyn(JSThread *thread, ObjectFactory *factory, uint16_t num_vars); static inline JSTaggedValue GetGlobalOwnProperty(JSTaggedValue receiver, JSTaggedValue key, bool *found); /* -------------- Special API For Multi-Language VM Begin ----------------- */ diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h index 89d3f6d61..cfc0c012c 100644 --- a/runtime/interpreter/interpreter.h +++ b/runtime/interpreter/interpreter.h @@ -108,7 +108,7 @@ enum EcmaOpcode { LDBOOLEAN_IMM8_V8, LDNUMBER_IMM8_V8, LDSTRING_IMM8_V8, - LDBIGINT_IMM8_V8, + LDBIGINT_IMM8_ID32, ADD2DYN_IMM8_V8, SUB2DYN_IMM8_V8, MUL2DYN_IMM8_V8, @@ -164,7 +164,7 @@ enum EcmaOpcode { SUSPENDGENERATOR_IMM8_V8, SUSPENDASYNCGENERATOR_IMM8_V8, ASYNCFUNCTIONAWAIT_IMM8_V8, - THROWUNDEFINEDIFHOLE_IMM8_ID32, + THROWTDZ_IMM8_ID32, CALL1DYN_IMM8_V8_V8, COPYDATAPROPERTIES_IMM8_V8_V8, STARRAYSPREAD_IMM8_V8_V8, @@ -211,14 +211,19 @@ enum EcmaOpcode { LDSUPERBYNAME_IMM8_ID32_IMM16_V8, STSUPERBYNAME_IMM8_ID32_IMM16_V8, STLEXVARDYN_IMM8_IMM16_IMM16, + STLEXDYN_IMM8_ID32_IMM16_IMM16, LDLEXVARDYN_IMM8_IMM16_IMM16, + LDLEXDYN_IMM8_ID32_IMM16_IMM16, NEWLEXENVDYN_IMM8_IMM16, COPYLEXENVDYN_IMM8, COPYRESTARGS_IMM8_IMM16, CREATEOBJECTWITHBUFFER_IMM8_IMM16, CREATEARRAYWITHBUFFER_IMM8_IMM16, + CREATEREGEXPWITHLITERAL_IMM8_ID32_IMM8, CREATEOBJECTHAVINGMETHOD_IMM8_IMM16, THROWIFSUPERNOTCORRECTCALL_IMM8_IMM16, + LOADCLASSCOMPUTEDINSTANCEFIELDS_IMM8_V8, + SETCLASSCOMPUTEDFIELDS_IMM8_V8_V8, DEFINECLASSWITHBUFFER_IMM8_ID16_IMM16_V8_V8, RETURN_DYN, MOV_V4_V4, diff --git a/runtime/interpreter/js_decode_call_instr.h b/runtime/interpreter/js_decode_call_instr.h index 9fc599ae5..79670d648 100644 --- a/runtime/interpreter/js_decode_call_instr.h +++ b/runtime/interpreter/js_decode_call_instr.h @@ -16,25 +16,37 @@ ALWAYS_INLINE inline uint32_t JSGetNumberActualArgsDyn([[maybe_unused]] Bytecode { using R = BytecodeInstructionResolver; constexpr auto OP = R::template Get(); - if constexpr (OP == R::template Get()) { - static_assert(FORMAT == R::template Get()); + if constexpr (OP == R::template Get()) { + static_assert(FORMAT == R::template Get()); return NUM_MANDATORY_JSFUNC_ARGS + 0; - } else if constexpr (OP == R::template Get()) { - static_assert(FORMAT == R::template Get()); + } else if constexpr (OP == R::template Get()) { + static_assert(FORMAT == R::template Get()); return NUM_MANDATORY_JSFUNC_ARGS + 1; - } else if constexpr (OP == R::template Get()) { - static_assert(FORMAT == R::template Get()); + } else if constexpr (OP == R::template Get()) { + static_assert(FORMAT == R::template Get()); return NUM_MANDATORY_JSFUNC_ARGS + 2; - } else if constexpr (OP == R::template Get()) { - static_assert(FORMAT == R::template Get()); + } else if constexpr (OP == R::template Get()) { + static_assert(FORMAT == R::template Get()); return NUM_MANDATORY_JSFUNC_ARGS + 3; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - auto imm = inst.GetImm(); + auto imm = inst.GetImm(); return NUM_MANDATORY_JSFUNC_ARGS + imm; + } else if constexpr (OP == R::template Get()) { + static_assert(FORMAT == R::template Get()); + return NUM_MANDATORY_JSFUNC_ARGS; + } else if constexpr (OP == R::template Get()) { + static_assert(FORMAT == R::template Get()); + return NUM_MANDATORY_JSFUNC_ARGS + 1; + } else if constexpr (OP == R::template Get()) { + static_assert(FORMAT == R::template Get()); + return NUM_MANDATORY_JSFUNC_ARGS + 2; + } else if constexpr (OP == R::template Get()) { + static_assert(FORMAT == R::template Get()); + return NUM_MANDATORY_JSFUNC_ARGS + 3; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - auto imm = inst.GetImm(); + auto imm = inst.GetImm(); ASSERT(imm >= 1); // 'this' is always passed to the function return NUM_MANDATORY_JSFUNC_ARGS - 1 + imm; } else { @@ -47,9 +59,39 @@ ALWAYS_INLINE inline uint32_t JSGetNumberActualArgsDyn([[maybe_unused]] Bytecode } template -ALWAYS_INLINE inline static void JSCopyArgumets(JSThread *thread, Frame *prev_frame, uint16_t prev_v0, - [[maybe_unused]] BytecodeInstruction prev_inst, Frame *new_frame, - uint32_t num_vregs, uint32_t num_actual_args) +ALWAYS_INLINE inline int64_t JSGetCalleDyn([[maybe_unused]] Frame *frame, [[maybe_unused]] BytecodeInstruction inst) +{ + using R = BytecodeInstructionResolver; + constexpr auto op = R::template Get(); + + if constexpr (op == R::template Get()) { + return frame->GetAccAsVReg().GetValue(); + } else { + return frame->GetVReg(inst.GetVReg()).GetValue(); + } + + UNREACHABLE_CONSTEXPR(); + return 0; +} + +template +ALWAYS_INLINE inline uint16_t JSGetCalleRangeStartDyn([[maybe_unused]] BytecodeInstruction inst) +{ + using R = BytecodeInstructionResolver; + constexpr auto op = R::template Get(); + + if constexpr (op == R::template Get() || + op == R::template Get()) { + return inst.GetVReg(); + } + + return 0; +} + +template +ALWAYS_INLINE inline static void JSCopyArgumets(JSThread *thread, Frame *prev_frame, uint64_t raw_fn_object, + BytecodeInstruction prev_inst, Frame *new_frame, uint32_t num_vregs, + uint32_t num_actual_args) { // ecma.call0dyn // ecma.call1dyn @@ -65,6 +107,10 @@ ALWAYS_INLINE inline static void JSCopyArgumets(JSThread *thread, Frame *prev_fr // ... // dyn_arg[N] - vreg[N-2] [ args[N-3] ] + // ecma.call0thisdyn + // ecma.call1thisdyn + // ecma.call2thisdyn + // ecma.call3thisdyn // ecma.callithisrangedyn: // dyn_arg[0] - vreg[ 0] [functional object] // dyn_arg[1] - undefined [ new.target ] @@ -74,16 +120,20 @@ ALWAYS_INLINE inline static void JSCopyArgumets(JSThread *thread, Frame *prev_fr // ... // dyn_arg[N] - vreg[N-1] [ args[N-3] ] - using R = BytecodeInstructionResolver; - constexpr auto OP = R::template Get(); + // Where vreg[N-1] is accumulator - ASSERT(num_actual_args >= 3); - uint64_t raw_fn_object = prev_frame->GetVReg(prev_v0).GetValue(); + using R = BytecodeInstructionResolver; + constexpr auto op = R::template Get(); + ASSERT(num_actual_args >= NUM_MANDATORY_JSFUNC_ARGS); new_frame->GetVReg(num_vregs + 0).SetValue(raw_fn_object); new_frame->GetVReg(num_vregs + 1).SetValue(JSTaggedValue::VALUE_UNDEFINED); - if constexpr (OP != R::template Get()) { + if constexpr (op == R::template Get() || + op == R::template Get() || + op == R::template Get() || + op == R::template Get() || + op == R::template Get()) { JSTaggedValue fn_object(raw_fn_object); uint64_t dyn_arg2 = JSTaggedValue::VALUE_UNDEFINED; if (fn_object.IsJSFunction() && !JSFunction::Cast(fn_object.GetHeapObject())->IsStrict()) { @@ -92,32 +142,56 @@ ALWAYS_INLINE inline static void JSCopyArgumets(JSThread *thread, Frame *prev_fr new_frame->GetVReg(num_vregs + 2).SetValue(dyn_arg2); } - if constexpr (OP == R::template Get()) { - static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == 3); + if constexpr (op == R::template Get()) { + static_assert(FORMAT == R::template Get()); + ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS); // Do nothing - } else if constexpr (OP == R::template Get()) { + } else if constexpr (op == R::template Get()) { + static_assert(FORMAT == R::template Get()); + ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 1); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0).SetValue(prev_frame->GetAccAsVReg().GetValue()); + } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == 3 + 1); - new_frame->GetVReg(num_vregs + 3 + 0) = prev_frame->GetVReg(prev_inst.GetVReg(1)); - } else if constexpr (OP == R::template Get()) { + ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 2); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 1).SetValue(prev_frame->GetAccAsVReg().GetValue()); + } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == 3 + 2); - new_frame->GetVReg(num_vregs + 3 + 0) = prev_frame->GetVReg(prev_inst.GetVReg(1)); - new_frame->GetVReg(num_vregs + 3 + 1) = prev_frame->GetVReg(prev_inst.GetVReg(2)); - } else if constexpr (OP == R::template Get()) { - static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == 3 + 3); - new_frame->GetVReg(num_vregs + 3 + 0) = prev_frame->GetVReg(prev_inst.GetVReg(1)); - new_frame->GetVReg(num_vregs + 3 + 1) = prev_frame->GetVReg(prev_inst.GetVReg(2)); - new_frame->GetVReg(num_vregs + 3 + 2) = prev_frame->GetVReg(prev_inst.GetVReg(3)); - } else if constexpr (OP == R::template Get()) { + ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 3); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 1) = prev_frame->GetVReg(prev_inst.GetVReg(2)); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 2).SetValue(prev_frame->GetAccAsVReg().GetValue()); + } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); + uint16_t prev_v0 = JSGetCalleRangeStartDyn(prev_inst); for (uint16_t i = 1; i < (num_actual_args - 2); ++i) { new_frame->GetVReg(num_vregs + 2 + i) = prev_frame->GetVReg(prev_v0 + i); } - } else if constexpr (OP == R::template Get()) { + } else if constexpr (op == R::template Get()) { + static_assert(FORMAT == R::template Get()); + ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS); + new_frame->GetVReg(num_vregs + 2).SetValue(prev_frame->GetAccAsVReg().GetValue()); + } else if constexpr (op == R::template Get()) { + static_assert(FORMAT == R::template Get()); + ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 1); + new_frame->GetVReg(num_vregs + 2) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0).SetValue(prev_frame->GetAccAsVReg().GetValue()); + } else if constexpr (op == R::template Get()) { + static_assert(FORMAT == R::template Get()); + ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 2); + new_frame->GetVReg(num_vregs + 2) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0) = prev_frame->GetVReg(prev_inst.GetVReg(2)); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 1).SetValue(prev_frame->GetAccAsVReg().GetValue()); + } else if constexpr (op == R::template Get()) { + static_assert(FORMAT == R::template Get()); + ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 3); + new_frame->GetVReg(num_vregs + 2) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0) = prev_frame->GetVReg(prev_inst.GetVReg(2)); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 1) = prev_frame->GetVReg(prev_inst.GetVReg(3)); + new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 2).SetValue(prev_frame->GetAccAsVReg().GetValue()); + } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); + uint16_t prev_v0 = JSGetCalleRangeStartDyn(prev_inst); for (uint16_t i = 0; i < (num_actual_args - 2); ++i) { new_frame->GetVReg(num_vregs + 2 + i) = prev_frame->GetVReg(prev_v0 + 1 + i); } diff --git a/runtime/interpreter/slow_runtime_helper.cpp b/runtime/interpreter/slow_runtime_helper.cpp index 948b39865..ff7f44bb1 100644 --- a/runtime/interpreter/slow_runtime_helper.cpp +++ b/runtime/interpreter/slow_runtime_helper.cpp @@ -275,4 +275,44 @@ JSTaggedValue SlowRuntimeHelper::Construct(JSThread *thread, JSHandle &private_context, + const JSHandle &obj, const JSHandle &key, + PropertyDescriptor &prop_desc, PrivateFieldKind &kind) +{ + JSHandle desc(thread, private_context->GetPrivateFields()); + + for (ArraySizeT i = 0; i < desc->GetLength();) { + JSHandle kind_value(thread, desc->Get(thread, i++)); + kind = static_cast(kind_value->GetInt()); + JSHandle private_symbol(thread, desc->Get(thread, i++)); + + switch (kind) { + case PrivateFieldKind::FIELD: + case PrivateFieldKind::STATIC_FIELD: { + break; + } + default: { + i++; + } + } + + if (!JSTaggedValue::Equal(thread, JSHandle(thread, private_symbol->GetDescription()), key)) { + continue; + } + + bool exists = JSObject::GetOwnProperty(thread, obj, JSHandle::Cast(private_symbol), prop_desc); + + if (!exists) { + prop_desc.SetValue(JSHandle(thread, JSTaggedValue::Hole())); + } + + return private_symbol.GetTaggedValue(); + } + + prop_desc.SetValue(JSHandle(thread, JSTaggedValue::Hole())); + return JSTaggedValue::Undefined(); +} + } // namespace panda::ecmascript diff --git a/runtime/interpreter/slow_runtime_helper.h b/runtime/interpreter/slow_runtime_helper.h index 1d7678c1b..e2c18fbf2 100644 --- a/runtime/interpreter/slow_runtime_helper.h +++ b/runtime/interpreter/slow_runtime_helper.h @@ -34,6 +34,11 @@ public: static JSTaggedValue Construct(JSThread *thread, JSHandle ctor, JSHandle new_target, JSHandle pre_args, uint32_t args_count, JSTaggedType *stkargs); + using PrivateFieldKind = JSConstructorFunction::PrivateFieldKind; + + static JSTaggedValue FindPrivateKey(JSThread *thread, const JSHandle &private_context, + const JSHandle &obj, const JSHandle &key, + PropertyDescriptor &prop_desc, PrivateFieldKind &kind); }; } // namespace panda::ecmascript diff --git a/runtime/interpreter/slow_runtime_stub.cpp b/runtime/interpreter/slow_runtime_stub.cpp index f8a2f0e67..f64d28f1a 100644 --- a/runtime/interpreter/slow_runtime_stub.cpp +++ b/runtime/interpreter/slow_runtime_stub.cpp @@ -15,6 +15,8 @@ #include "plugins/ecmascript/runtime/interpreter/slow_runtime_stub.h" +#include "js_tagged_value.h" +#include "lexical_env.h" #include "plugins/ecmascript/runtime/base/number_helper.h" #include "plugins/ecmascript/runtime/base/utf_helper.h" #include "plugins/ecmascript/runtime/builtins/builtins_regexp.h" @@ -42,6 +44,7 @@ #include "plugins/ecmascript/runtime/js_proxy.h" #include "plugins/ecmascript/runtime/js_tagged_value-inl.h" #include "plugins/ecmascript/runtime/js_thread.h" +#include "plugins/ecmascript/runtime/linked_hash_table-inl.h" #include "plugins/ecmascript/runtime/tagged_dictionary.h" #include "plugins/ecmascript/runtime/runtime_call_id.h" #include "plugins/ecmascript/runtime/template_string.h" @@ -76,18 +79,23 @@ JSTaggedValue SlowRuntimeStub::NegDyn(JSThread *thread, JSTaggedValue value) [[maybe_unused]] EcmaHandleScope handle_scope(thread); JSHandle input(thread, value); - JSTaggedNumber number = JSTaggedValue::ToNumber(thread, input); + JSHandle input_val = JSTaggedValue::ToNumeric(thread, input); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - if (number.IsInt()) { - int32_t int_value = number.GetInt(); + if (input_val->IsBigInt()) { + JSHandle big_value(input_val); + return BigInt::UnaryMinus(thread, big_value).GetTaggedValue(); + } + + if (input_val->IsInt()) { + int32_t int_value = input_val->GetInt(); if (int_value == 0) { return JSTaggedValue(-0.0); } return JSTaggedValue(-int_value); } - if (number.IsDouble()) { - return JSTaggedValue(-number.GetDouble()); + if (input_val->IsDouble()) { + return JSTaggedValue(-input_val->GetDouble()); } UNREACHABLE(); @@ -128,16 +136,22 @@ JSTaggedValue SlowRuntimeStub::ToNumber(JSThread *thread, JSTaggedValue value) JSHandle number(thread, value); // may return exception - return JSTaggedValue::ToNumber(thread, number); + return JSTaggedValue::ToNumeric(thread, number).GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::NotDyn(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, NotDyn); [[maybe_unused]] EcmaHandleScope handle_scope(thread); - JSHandle value_handle(thread, value); - int32_t number = JSTaggedValue::ToInt32(thread, value_handle); + + JSHandle input_tag(thread, value); + JSHandle input_val = JSTaggedValue::ToNumeric(thread, input_tag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (input_val->IsBigInt()) { + JSHandle big_value(input_val); + return BigInt::BitwiseNOT(thread, big_value).GetTaggedValue(); + } + int32_t number = JSTaggedValue::ToInt32(thread, input_val); return JSTaggedValue(~number); // NOLINT(hicpp-signed-bitwise) } @@ -146,9 +160,14 @@ JSTaggedValue SlowRuntimeStub::IncDyn(JSThread *thread, JSTaggedValue value) INTERPRETER_TRACE(thread, IncDyn); [[maybe_unused]] EcmaHandleScope handle_scope(thread); - JSHandle value_handle(thread, value); - JSTaggedNumber number = JSTaggedValue::ToNumber(thread, value_handle); + JSHandle input_tag(thread, value); + JSHandle input_val = JSTaggedValue::ToNumeric(thread, input_tag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (input_val->IsBigInt()) { + JSHandle big_value(input_val); + return BigInt::BigIntAddOne(thread, big_value).GetTaggedValue(); + } + JSTaggedNumber number(input_val.GetTaggedValue()); return (++number); } @@ -157,9 +176,14 @@ JSTaggedValue SlowRuntimeStub::DecDyn(JSThread *thread, JSTaggedValue value) INTERPRETER_TRACE(thread, DecDyn); [[maybe_unused]] EcmaHandleScope handle_scope(thread); - JSHandle value_handle(thread, value); - JSTaggedNumber number = JSTaggedValue::ToNumber(thread, value_handle); + JSHandle input_tag(thread, value); + JSHandle input_val = JSTaggedValue::ToNumeric(thread, input_tag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (input_val->IsBigInt()) { + JSHandle big_value(input_val); + return BigInt::BigIntSubOne(thread, big_value).GetTaggedValue(); + } + JSTaggedNumber number(input_val.GetTaggedValue()); return (--number); } @@ -227,12 +251,23 @@ JSTaggedValue SlowRuntimeStub::Add2Dyn(JSThread *thread, EcmaVM *ecma_vm, JSTagg EcmaString *new_string = EcmaString::Concat(string_a0, string_a1, ecma_vm); return JSTaggedValue(new_string); } - JSTaggedNumber tagged_value_a0 = JSTaggedValue::ToNumber(thread, primitive_a0); + + JSHandle val_left = JSTaggedValue::ToNumeric(thread, primitive_a0); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSTaggedNumber tagged_value_a1 = JSTaggedValue::ToNumber(thread, primitive_a1); + JSHandle val_right = JSTaggedValue::ToNumeric(thread, primitive_a1); + + if (val_left->IsBigInt() || val_right->IsBigInt()) { + if (val_left->IsBigInt() && val_right->IsBigInt()) { + JSHandle big_left(val_left); + JSHandle big_right(val_right); + return BigInt::Add(thread, big_left, big_right).GetTaggedValue(); + } + return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - double a0_double = tagged_value_a0.GetNumber(); - double a1_double = tagged_value_a1.GetNumber(); + double a0_double = val_left->GetNumber(); + double a1_double = val_right->GetNumber(); return JSTaggedValue(a0_double + a1_double); } @@ -244,10 +279,22 @@ JSTaggedValue SlowRuntimeStub::Sub2Dyn(JSThread *thread, JSTaggedValue left, JST JSHandle left_handle(thread, left); JSHandle right_handle(thread, right); - JSTaggedNumber number0 = JSTaggedValue::ToNumber(thread, left_handle); + JSHandle val_left = JSTaggedValue::ToNumeric(thread, left_handle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSTaggedNumber number1 = JSTaggedValue::ToNumber(thread, right_handle); + JSHandle val_right = JSTaggedValue::ToNumeric(thread, right_handle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + if (val_left->IsBigInt() || val_right->IsBigInt()) { + if (val_left->IsBigInt() && val_right->IsBigInt()) { + JSHandle big_left(val_left); + JSHandle big_right(val_right); + return BigInt::Subtract(thread, big_left, big_right).GetTaggedValue(); + } + return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); + } + + JSTaggedNumber number0(val_left.GetTaggedValue()); + JSTaggedNumber number1(val_right.GetTaggedValue()); return number0 - number1; } @@ -259,17 +306,28 @@ JSTaggedValue SlowRuntimeStub::Mul2Dyn(JSThread *thread, JSTaggedValue left, JST JSHandle left_value(thread, left); JSHandle right_value(thread, right); - // 6. Let lnum be ToNumber(leftValue). - JSTaggedNumber primitive_a = JSTaggedValue::ToNumber(thread, left_value); + // 6. Let lnum be ToNumeric(leftValue). + JSHandle val_left = JSTaggedValue::ToNumeric(thread, left_value); // 7. ReturnIfAbrupt(lnum). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // 8. Let rnum be ToNumber(rightValue). - JSTaggedNumber primitive_b = JSTaggedValue::ToNumber(thread, right_value); + // 8. Let rnum be ToNumeric(rightValue). + JSHandle val_right = JSTaggedValue::ToNumeric(thread, right_value); // 9. ReturnIfAbrupt(rnum). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (val_left->IsBigInt() || val_right->IsBigInt()) { + if (val_left->IsBigInt() && val_right->IsBigInt()) { + JSHandle big_left(val_left); + JSHandle big_right(val_right); + return BigInt::Multiply(thread, big_left, big_right).GetTaggedValue(); + } + return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); + } + // 12.6.3.1 Applying the * Operator - return primitive_a * primitive_b; + JSTaggedNumber number0(val_left.GetTaggedValue()); + JSTaggedNumber number1(val_right.GetTaggedValue()); + return number0 * number1; } JSTaggedValue SlowRuntimeStub::Div2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) @@ -280,12 +338,23 @@ JSTaggedValue SlowRuntimeStub::Div2Dyn(JSThread *thread, JSTaggedValue left, JST JSHandle left_handle(thread, left); JSHandle right_handle(thread, right); - JSTaggedNumber left_number = JSTaggedValue::ToNumber(thread, left_handle); + JSHandle val_left = JSTaggedValue::ToNumeric(thread, left_handle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - double d_left = left_number.GetNumber(); - JSTaggedNumber right_number = JSTaggedValue::ToNumber(thread, right_handle); + JSHandle val_right = JSTaggedValue::ToNumeric(thread, right_handle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - double d_right = right_number.GetNumber(); + + if (val_left->IsBigInt() || val_right->IsBigInt()) { + if (val_left->IsBigInt() && val_right->IsBigInt()) { + JSHandle big_left(val_left); + JSHandle big_right(val_right); + return BigInt::Divide(thread, big_left, big_right).GetTaggedValue(); + } + return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); + } + + double d_left = val_left->GetNumber(); + double d_right = val_right->GetNumber(); + if (d_right == 0) { if (d_left == 0 || std::isnan(d_left)) { return JSTaggedValue(base::NAN_VALUE); @@ -305,12 +374,23 @@ JSTaggedValue SlowRuntimeStub::Mod2Dyn(JSThread *thread, JSTaggedValue left, JST JSHandle left_handle(thread, left); JSHandle right_handle(thread, right); - JSTaggedNumber left_number = JSTaggedValue::ToNumber(thread, left_handle); + JSHandle val_left = JSTaggedValue::ToNumeric(thread, left_handle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - double d_left = left_number.GetNumber(); - JSTaggedNumber right_number = JSTaggedValue::ToNumber(thread, right_handle); + JSHandle val_right = JSTaggedValue::ToNumeric(thread, right_handle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - double d_right = right_number.GetNumber(); + + if (val_left->IsBigInt() || val_right->IsBigInt()) { + if (val_left->IsBigInt() && val_right->IsBigInt()) { + JSHandle left_bigint(val_left); + JSHandle right_bigint(val_right); + return BigInt::Remainder(thread, left_bigint, right_bigint).GetTaggedValue(); + } + return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); + } + + double d_left = val_left->GetNumber(); + double d_right = val_right->GetNumber(); + // 12.6.3.3 Applying the % Operator if ((d_right == 0.0) || std::isnan(d_right) || std::isnan(d_left) || std::isinf(d_left)) { return JSTaggedValue(base::NAN_VALUE); @@ -454,59 +534,58 @@ JSTaggedValue SlowRuntimeStub::CreateObjectWithExcludedKeys(JSThread *thread, ui JSHandle obj_tval(thread, obj_val); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - uint32_t num_excluded_keys = 0; - JSHandle excluded_keys = factory->NewTaggedArray(num_keys + 1); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - auto excluded_key = JSTaggedValue(stkargs[0]); - if (!excluded_key.IsUndefined()) { - num_excluded_keys = num_keys + 1; - excluded_keys->Set(thread, 0, excluded_key); - for (ArraySizeT i = 1; i < num_excluded_keys; i++) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - excluded_key = JSTaggedValue(stkargs[i]); - excluded_keys->Set(thread, i, excluded_key); - } - } - - JSHandle rest_obj = factory->NewEmptyJSObject(); - JSHandle all_keys; + JSHandle from_value(thread, obj_val); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - if (obj_tval->IsJSProxy()) { - all_keys = JSProxy::OwnPropertyKeys(thread, JSHandle(obj_tval)); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - } else { - ASSERT(obj_tval->IsJSObject()); - JSHandle obj(obj_tval); - uint32_t num_all_keys = obj->GetNumberOfKeys(); - all_keys = factory->NewTaggedArray(num_all_keys); - JSObject::GetAllKeys(thread, obj, 0, all_keys); + // 3. If source is undefined or null, return target. + if (from_value->IsNull() || from_value->IsUndefined()) { + return obj_val; } + // 4. Let from be ! ToObject(source). + JSHandle from = JSTaggedValue::ToObject(thread, from_value); + ASSERT_NO_ABRUPT_COMPLETION(thread); - JSMutableHandle key(thread, JSTaggedValue::Undefined()); - - for (uint32_t i = 0; i < all_keys->GetLength(); i++) { - key.Update(all_keys->Get(i)); - bool is_excluded_key = false; - for (uint32_t j = 0; j < num_excluded_keys; j++) { - if (JSTaggedValue::Equal(thread, key, JSHandle(thread, excluded_keys->Get(j)))) { - is_excluded_key = true; + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + JSTaggedValue vreg(stkargs[0]); + ArraySizeT num_excluded_keys = vreg.IsUndefined() ? 0 : num_keys + 1; + // 5.Let keys be obj.[[OwnPropertyKeys]](). + JSHandle from_keys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle::Cast(from)); + // 6. For each element nextKey of keys, do + JSHandle new_obj = factory->NewEmptyJSObject(); + + bool excluded = true; + for (ArraySizeT i = 0; i < from_keys->GetLength(); i++) { + JSMutableHandle key(thread, from_keys->Get(i)); + // a. Let excluded be false. + excluded = false; + // b. For each element e of excludedItems, do + for (ArraySizeT e = 0; e < num_excluded_keys; e++) { + // i. If SameValue(e, nextKey) is true, then + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + JSTaggedValue ereg(stkargs[e]); + if (JSTaggedValue::SameValue(key, JSHandle(thread, ereg))) { + // 1. Set excluded to true. + excluded = true; break; } } - if (!is_excluded_key) { + // c. If excluded is false, then + if (!excluded) { + // i. Let desc be ? from.[[GetOwnProperty]](nextKey). PropertyDescriptor desc(thread); - bool success = JSTaggedValue::GetOwnProperty(thread, obj_tval, key, desc); + bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle(from), key, desc); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - if (success && desc.IsEnumerable()) { - JSHandle value = - JSObject::GetProperty(thread, JSHandle(obj_tval), key).GetValue(); + // ii. If desc is not undefined and desc.[[Enumerable]] is true, then + if (status && desc.IsEnumerable()) { + JSHandle prop_value = + JSTaggedValue::GetProperty(thread, JSHandle(from), key).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSObject::SetProperty(thread, rest_obj, key, value, true); + JSObject::CreateDataPropertyOrThrow(thread, new_obj, key, prop_value); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } } } - return rest_obj.GetTaggedValue(); + return new_obj.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::ExpDyn(JSThread *thread, JSTaggedValue base, JSTaggedValue exponent) @@ -514,16 +593,24 @@ JSTaggedValue SlowRuntimeStub::ExpDyn(JSThread *thread, JSTaggedValue base, JSTa INTERPRETER_TRACE(thread, ExpDyn); [[maybe_unused]] EcmaHandleScope handle_scope(thread); - JSHandle base_handle(thread, base); - JSHandle exp_handle(thread, exponent); - JSTaggedNumber base_number = JSTaggedValue::ToNumber(thread, base_handle); + JSHandle base_tag(thread, base); + JSHandle exponent_tag(thread, exponent); + JSHandle val_base = JSTaggedValue::ToNumeric(thread, base_tag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - double double_base = base_number.GetNumber(); - JSTaggedNumber exponent_number = JSTaggedValue::ToNumber(thread, exp_handle); + JSHandle val_exponent = JSTaggedValue::ToNumeric(thread, exponent_tag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - double double_exponent = exponent_number.GetNumber(); - return base::NumberHelper::Pow(double_base, double_exponent); + if (val_base->IsBigInt() || val_exponent->IsBigInt()) { + if (val_base->IsBigInt() && val_exponent->IsBigInt()) { + JSHandle big_base_value(val_base); + JSHandle big_exponent_value(val_exponent); + return BigInt::Exponentiate(thread, big_base_value, big_exponent_value).GetTaggedValue(); + } + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot mix BigInt and other types, use explicit conversions", + JSTaggedValue::Exception()); + } + + return base::NumberHelper::Pow(base_tag->GetNumber(), exponent.GetNumber()); } JSTaggedValue SlowRuntimeStub::IsInDyn(JSThread *thread, JSTaggedValue prop, JSTaggedValue obj) @@ -766,13 +853,13 @@ JSTaggedValue SlowRuntimeStub::NewObjSpreadDyn(JSThread *thread, JSTaggedValue f return tagged; } -void SlowRuntimeStub::ThrowUndefinedIfHole(JSThread *thread, JSTaggedValue obj) +void SlowRuntimeStub::ThrowTdz(JSThread *thread, JSTaggedValue bindingName) { - INTERPRETER_TRACE(thread, ThrowUndefinedIfHole); + INTERPRETER_TRACE(thread, ThrowTdz); [[maybe_unused]] EcmaHandleScope handle_scope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle name(thread, obj); + JSHandle name(thread, bindingName); JSHandle info = factory->NewFromCanBeCompressString(" is not initialized"); JSHandle msg = factory->ConcatFromString(name, info); @@ -1079,6 +1166,343 @@ JSTaggedValue SlowRuntimeStub::LdModvarByName([[maybe_unused]] JSThread *thread, return module_var.GetTaggedValue(); } +JSTaggedValue SlowRuntimeStub::ClassFieldAdd(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop_name, + JSTaggedValue value) +{ + INTERPRETER_TRACE(thread, ClassFieldAdd); + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + + const GlobalEnvConstants *global_consts = thread->GlobalConstants(); + JSHandle obj_handle(thread, obj); + JSHandle prop_handle(thread, prop_name); + JSHandle value_handle(thread, value); + ASSERT(prop_handle->IsStringOrSymbol()); + + if (obj_handle->IsClassConstructor() && + JSTaggedValue::SameValue(prop_handle, global_consts->GetHandledPrototypeString())) { + return ThrowTypeError(thread, "In a class, static property named 'prototype' throw a TypeError"); + } + + PropertyDescriptor desc(thread, value_handle, true, true, true); + bool ret = JSTaggedValue::DefineOwnProperty(thread, obj_handle, prop_handle, desc); + if (!ret) { + return ThrowTypeError(thread, "ClassFieldAdd failed"); + } + return JSTaggedValue::True(); +} + +using PrivateFieldKind = JSConstructorFunction::PrivateFieldKind; + +void SlowRuntimeStub::DefineClassPrivateFields(JSThread *thread, ConstantPool *constpool, JSTaggedValue env, + JSTaggedValue ctor, JSTaggedValue private_buf) +{ + INTERPRETER_TRACE(thread, DefineClassPrivateFields); + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + + auto factory = thread->GetEcmaVM()->GetFactory(); + JSHandle desc_template(thread, private_buf); + JSHandle constpool_handle(thread, constpool); + JSHandle lexical_env(thread, env); + JSHandle ctor_handle(thread, ctor); + JSHandle new_desc = factory->NewTaggedArray(desc_template->GetLength()); + JSHandle accessor_keys = LinkedHashMap::Create(thread); + + for (ArraySizeT i = 0; i < desc_template->GetLength();) { + JSHandle kind_value(thread, desc_template->Get(thread, i)); + auto kind = static_cast(kind_value->GetInt()); + new_desc->Set(thread, i++, kind_value); + + switch (kind) { + case PrivateFieldKind::FIELD: + case PrivateFieldKind::STATIC_FIELD: + case PrivateFieldKind::METHOD: + case PrivateFieldKind::STATIC_METHOD: { + JSHandle name(thread, desc_template->Get(thread, i)); + JSHandle private_key = factory->NewPrivateNameSymbol(name); + new_desc->Set(thread, i++, private_key.GetTaggedValue()); + break; + } + default: { + JSHandle name(thread, desc_template->Get(thread, i)); + int hash = LinkedHash::Hash(name.GetTaggedValue()); + JSTaggedValue private_key = accessor_keys->Get(name.GetTaggedValue(), hash); + + if (private_key.IsUndefined()) { + JSHandle shared_private_key = factory->NewPrivateNameSymbol(name); + LinkedHashMap::Set(thread, accessor_keys, name, JSHandle::Cast(shared_private_key)); + private_key = shared_private_key.GetTaggedValue(); + } + + new_desc->Set(thread, i++, private_key); + break; + } + } + + switch (kind) { + case PrivateFieldKind::FIELD: + case PrivateFieldKind::STATIC_FIELD: { + break; + } + default: { + JSHandle value_handle(thread, desc_template->Get(thread, i)); + JSHandle new_func = factory->CloneJSFuction(value_handle, value_handle->GetFunctionKind()); + new_func->SetLexicalEnv(thread, lexical_env.GetTaggedValue()); + new_func->SetConstantPool(thread, constpool_handle.GetTaggedValue()); + new_desc->Set(thread, i++, new_func.GetTaggedValue()); + break; + } + } + } + + JSConstructorFunction::Cast(ctor_handle->GetHeapObject())->SetPrivateFields(new_desc.GetTaggedValue()); +} + +JSTaggedValue SlowRuntimeStub::ClassPrivateMethodOrAccessorAdd(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj) +{ + INTERPRETER_TRACE(thread, ClassPrivateMethodOrAccessorAdd); + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + + auto factory = thread->GetEcmaVM()->GetFactory(); + JSHandle ctor_handle(thread, ctor); + JSHandle obj_handle(thread, obj); + + bool isStatic = JSTaggedValue::Equal(thread, JSHandle::Cast(ctor_handle), + JSHandle::Cast(obj_handle)); + + JSHandle desc = JSHandle(thread, ctor_handle->GetPrivateFields()); + JSHandle accessor_pairs = LinkedHashMap::Create(thread); + + for (ArraySizeT i = 0; i < desc->GetLength();) { + JSHandle kind_value(thread, desc->Get(thread, i++)); + auto kind = static_cast(kind_value->GetInt()); + + switch (kind) { + case PrivateFieldKind::FIELD: + case PrivateFieldKind::STATIC_FIELD: { + i++; + continue; + } + case PrivateFieldKind::METHOD: + case PrivateFieldKind::GET: + case PrivateFieldKind::SET: { + if (isStatic) { + i += 2; // 2: skip key + value + continue; + } + break; + } + case PrivateFieldKind::STATIC_METHOD: + case PrivateFieldKind::STATIC_GET: + case PrivateFieldKind::STATIC_SET: { + if (!isStatic) { + i += 2; // 2: skip key + value + continue; + } + break; + } + } + + JSHandle private_symbol(thread, desc->Get(thread, i++)); + JSHandle value(thread, desc->Get(thread, i++)); + + PropertyDescriptor prop_desc(thread); + bool exists = JSObject::GetOwnProperty(thread, obj_handle, private_symbol, prop_desc); + + switch (kind) { + case PrivateFieldKind::METHOD: + case PrivateFieldKind::STATIC_METHOD: { + if (exists) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot declare same private field twice", + JSTaggedValue::Exception()); + } + + prop_desc = PropertyDescriptor(thread, value, false, false, false); + JSObject::DefineOwnProperty(thread, obj_handle, private_symbol, prop_desc); + continue; + } + case PrivateFieldKind::GET: + case PrivateFieldKind::STATIC_GET: { + int hash = LinkedHash::Hash(private_symbol.GetTaggedValue()); + JSTaggedValue pair = accessor_pairs->Get(private_symbol.GetTaggedValue(), hash); + + if (pair.IsUndefined()) { + JSHandle arr = factory->NewTaggedArray(2); // 2: getter-setter pair + arr->Set(thread, 0, value); + arr->Set(thread, 1, JSTaggedValue::Undefined()); + LinkedHashMap::Set(thread, accessor_pairs, private_symbol, JSHandle::Cast(arr)); + continue; + } + TaggedArray::Cast(pair.GetHeapObject())->Set(thread, 0, value); + continue; + } + case PrivateFieldKind::SET: + case PrivateFieldKind::STATIC_SET: { + int hash = LinkedHash::Hash(private_symbol.GetTaggedValue()); + JSTaggedValue pair = accessor_pairs->Get(private_symbol.GetTaggedValue(), hash); + + if (pair.IsUndefined()) { + JSHandle arr = factory->NewTaggedArray(2); // 2: getter-setter pair + arr->Set(thread, 0, JSTaggedValue::Undefined()); + arr->Set(thread, 1, value); + LinkedHashMap::Set(thread, accessor_pairs, private_symbol, JSHandle::Cast(arr)); + continue; + } + TaggedArray::Cast(pair.GetHeapObject())->Set(thread, 1, value); + continue; + } + default: { + UNREACHABLE(); + break; + } + } + } + + PropertyDescriptor prop_desc(thread); + for (int i = 0; i < accessor_pairs->NumberOfElements(); i++) { + JSHandle private_symbol(thread, accessor_pairs->GetKey(i)); + + int hash = LinkedHash::Hash(private_symbol.GetTaggedValue()); + JSHandle accessor_pair(thread, accessor_pairs->Get(private_symbol.GetTaggedValue(), hash)); + JSHandle getter(thread, accessor_pair->Get(0)); + JSHandle setter(thread, accessor_pair->Get(1)); + + prop_desc.SetGetter(getter); + prop_desc.SetSetter(setter); + prop_desc.SetConfigurable(false); + prop_desc.SetEnumerable(false); + JSObject::DefineOwnProperty(thread, obj_handle, private_symbol, prop_desc); + } + + return JSTaggedValue::Undefined(); +} + +JSTaggedValue SlowRuntimeStub::ClassPrivateFieldAdd(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj, + JSTaggedValue propName, JSTaggedValue value) +{ + INTERPRETER_TRACE(thread, ClassPrivateFieldAdd); + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + + PropertyDescriptor prop_desc(thread); + [[maybe_unused]] PrivateFieldKind kind; + + JSHandle obj_handle(thread, obj); + JSHandle prop_name_handle(thread, propName); + JSHandle value_handle(thread, value); + + JSHandle private_symbol( + thread, SlowRuntimeHelper::FindPrivateKey(thread, JSHandle(thread, ctor), obj_handle, + prop_name_handle, prop_desc, kind)); + + if (!prop_desc.GetValue()->IsHole()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot declare same private field twice", JSTaggedValue::Exception()); + } + + prop_desc = PropertyDescriptor(thread, value_handle, true, false, false); + JSObject::DefineOwnProperty(thread, obj_handle, private_symbol, prop_desc); + + return JSTaggedValue::Undefined(); +} + +JSTaggedValue SlowRuntimeStub::ClassPrivateFieldGet(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj, + JSTaggedValue propName) +{ + INTERPRETER_TRACE(thread, ClassPrivateFieldGet); + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + + PropertyDescriptor prop_desc(thread); + [[maybe_unused]] PrivateFieldKind kind; + + JSHandle ctor_handle(thread, ctor); + JSHandle obj_handle(thread, obj); + JSHandle prop_name_handle(thread, propName); + JSHandle js_obj(JSTaggedValue::ToObject(thread, obj_handle)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSHandle private_symbol( + thread, SlowRuntimeHelper::FindPrivateKey(thread, ctor_handle, js_obj, prop_name_handle, prop_desc, kind)); + + if (prop_desc.GetValue()->IsHole()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot read private member to an object whose class did not declare it", + JSTaggedValue::Exception()); + } + + if (prop_desc.HasValue()) { + return prop_desc.GetValue().GetTaggedValue(); + } + + if (!prop_desc.HasGetter()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Private field was defined without a getter", JSTaggedValue::Exception()); + } + + return JSFunction::Call(thread, prop_desc.GetGetter(), obj_handle, 0, nullptr); +} + +JSTaggedValue SlowRuntimeStub::ClassPrivateFieldSet(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj, + JSTaggedValue propName, JSTaggedValue value) +{ + INTERPRETER_TRACE(thread, ClassPrivateFieldSet); + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + + PropertyDescriptor prop_desc(thread); + [[maybe_unused]] PrivateFieldKind kind; + + JSHandle ctor_handle(thread, ctor); + JSHandle obj_handle(thread, obj); + JSHandle prop_name_handle(thread, propName); + JSHandle value_handle(thread, value); + JSHandle js_obj(JSTaggedValue::ToObject(thread, obj_handle)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSHandle private_symbol( + thread, SlowRuntimeHelper::FindPrivateKey(thread, ctor_handle, js_obj, prop_name_handle, prop_desc, kind)); + + if (prop_desc.GetValue()->IsHole()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot read private member to an object whose class did not declare it", + JSTaggedValue::Exception()); + } + + if (prop_desc.HasValue()) { + if (kind == PrivateFieldKind::METHOD || kind == PrivateFieldKind::STATIC_METHOD) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Private method is not writable", JSTaggedValue::Exception()); + } + + prop_desc.SetValue(value_handle); + JSObject::DefineOwnProperty(thread, js_obj, private_symbol, prop_desc); + return JSTaggedValue::Undefined(); + } + + if (!prop_desc.HasSetter()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Private field was defined without a setter", JSTaggedValue::Exception()); + } + + InternalCallParams *params = thread->GetInternalCallParams(); + params->MakeArgv(value_handle); + return JSFunction::Call(thread, prop_desc.GetSetter(), obj_handle, 1, params->GetArgv()); +} + +JSTaggedValue SlowRuntimeStub::ClassPrivateFieldIn(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj, + JSTaggedValue propName) +{ + INTERPRETER_TRACE(thread, ClassPrivateFieldIn); + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + + PropertyDescriptor prop_desc(thread); + [[maybe_unused]] PrivateFieldKind kind; + + if (!obj.IsECMAObject()) { + return ThrowTypeError(thread, "Cannot use 'in' operator in Non-Object"); + } + + JSHandle obj_handle(thread, obj); + JSHandle prop_name_handle(thread, propName); + + JSHandle private_symbol( + thread, SlowRuntimeHelper::FindPrivateKey(thread, JSHandle(thread, ctor), obj_handle, + prop_name_handle, prop_desc, kind)); + + return JSTaggedValue(!prop_desc.GetValue()->IsHole()); +} + JSTaggedValue SlowRuntimeStub::CreateRegExpWithLiteral(JSThread *thread, JSTaggedValue pattern, uint8_t flags) { INTERPRETER_TRACE(thread, CreateRegExpWithLiteral); @@ -1478,78 +1902,6 @@ JSTaggedValue SlowRuntimeStub::StGlobalVar(JSThread *thread, JSTaggedValue prop, return JSTaggedValue::True(); } -JSTaggedValue SlowRuntimeStub::TryUpdateGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value) -{ - INTERPRETER_TRACE(thread, TryUpdateGlobalRecord); - [[maybe_unused]] EcmaHandleScope handle_scope(thread); - - EcmaVM *vm = thread->GetEcmaVM(); - JSHandle env = vm->GetGlobalEnv(); - GlobalDictionary *dict = GlobalDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); - int entry = dict->FindEntry(prop); - ASSERT(entry != -1); - - if (dict->GetAttributes(entry).IsConstProps()) { - return ThrowSyntaxError(thread, "const variable can not be modified"); - } - - PropertyBox *box = dict->GetBox(entry); - box->SetValue(thread, value); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - return JSTaggedValue::True(); -} - -// return box -JSTaggedValue SlowRuntimeStub::LdGlobalRecord(JSThread *thread, JSTaggedValue key, bool *found) -{ - INTERPRETER_TRACE(thread, LdGlobalRecord); - [[maybe_unused]] EcmaHandleScope handle_scope(thread); - - EcmaVM *vm = thread->GetEcmaVM(); - JSHandle env = vm->GetGlobalEnv(); - GlobalDictionary *dict = GlobalDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); - int entry = dict->FindEntry(key); - if (entry != -1) { - *found = true; - return JSTaggedValue(dict->GetBox(entry)); - } - return JSTaggedValue::Undefined(); -} - -JSTaggedValue SlowRuntimeStub::StGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value, bool is_const) -{ - INTERPRETER_TRACE(thread, StGlobalRecord); - [[maybe_unused]] EcmaHandleScope handle_scope(thread); - - EcmaVM *vm = thread->GetEcmaVM(); - JSHandle env = vm->GetGlobalEnv(); - GlobalDictionary *dict = GlobalDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); - - // cross files global record name binding judgment - int entry = dict->FindEntry(prop); - if (entry != -1) { - return ThrowSyntaxError(thread, "Duplicate identifier"); - } - - PropertyAttributes attributes; - if (is_const) { - attributes.SetIsConstProps(true); - } - JSHandle prop_handle(thread, prop); - JSHandle value_handle(thread, value); - JSHandle dict_handle(thread, dict); - - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle box = factory->NewPropertyBox(value_handle); - PropertyBoxType box_type = value_handle->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT; - attributes.SetBoxType(box_type); - - dict = *GlobalDictionary::PutIfAbsent(thread, dict_handle, prop_handle, JSHandle(box), attributes); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - env->SetGlobalRecord(thread, JSTaggedValue(dict)); - return JSTaggedValue::True(); -} - JSTaggedValue SlowRuntimeStub::ThrowReferenceError(JSThread *thread, JSTaggedValue prop, const char *desc) { INTERPRETER_TRACE(thread, ThrowReferenceError); @@ -2061,4 +2413,92 @@ JSTaggedValue SlowRuntimeStub::SetClassConstructorLength(JSThread *thread, JSTag } return JSTaggedValue::Undefined(); } + +JSTaggedValue SlowRuntimeStub::LdEvalVar(JSThread *thread, JSTaggedValue name, JSTaggedValue eval_bindings) +{ + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + JSHandle name_handle(thread, name); + JSHandle eval_bindings_handle(thread, eval_bindings); + + uint32_t index = 0; + JSMutableHandle lex_env( + thread, JSArray::FastGetPropertyByValue(thread, JSHandle::Cast(eval_bindings_handle), index++)); + + ArraySizeT size = eval_bindings_handle->GetArrayLength(); + + while (index < size) { + auto scope = JSHandle::Cast( + JSArray::FastGetPropertyByValue(thread, JSHandle::Cast(eval_bindings_handle), index++)); + + ArraySizeT slot = 0; + for (ArraySizeT j = 0; j < scope->GetLength(); slot++) { + JSTaggedValue binding = scope->Get(j++); + + if (binding.IsTrue()) { + binding = scope->Get(j++); + } + + if (EcmaString::StringsAreEqual(*name_handle, static_cast(binding.GetHeapObject()))) { + return lex_env->GetProperties(slot); + } + } + + lex_env.Update(lex_env->GetParentEnv()); + } + + auto global_obj = thread->GetGlobalObject(); + + bool found = false; + JSTaggedValue result = FastRuntimeStub::GetGlobalOwnProperty(global_obj, name_handle.GetTaggedValue(), &found); + if (found) { + return result; + } + return TryLdGlobalByName(thread, global_obj, name_handle.GetTaggedValue()); +} + +JSTaggedValue SlowRuntimeStub::StEvalVar(JSThread *thread, JSTaggedValue name, JSTaggedValue eval_bindings, + JSTaggedValue value) +{ + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + JSHandle name_handle(thread, name); + JSHandle eval_bindings_handle(thread, eval_bindings); + JSHandle value_handle(thread, value); + + uint32_t index = 0; + JSMutableHandle lex_env( + thread, JSArray::FastGetPropertyByValue(thread, JSHandle::Cast(eval_bindings_handle), index++)); + + ArraySizeT size = eval_bindings_handle->GetArrayLength(); + + while (index < size) { + auto scope = JSHandle::Cast( + JSArray::FastGetPropertyByValue(thread, JSHandle::Cast(eval_bindings_handle), index++)); + + ArraySizeT slot = 0; + for (ArraySizeT j = 0; j < scope->GetLength(); slot++) { + JSTaggedValue binding = scope->Get(j++); + bool is_const = false; + + if (binding.IsTrue()) { + is_const = true; + binding = scope->Get(j++); + } + + if (EcmaString::StringsAreEqual(*name_handle, static_cast(binding.GetHeapObject()))) { + if (is_const) { + return ThrowTypeError(thread, "Assignment to constant variable"); + } + lex_env->SetProperties(thread, slot, value_handle.GetTaggedValue()); + return value_handle.GetTaggedValue(); + } + } + + lex_env.Update(lex_env->GetParentEnv()); + } + + JSObject::GlobalSetProperty(thread, JSHandle::Cast(name_handle), value_handle, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return value_handle.GetTaggedValue(); +} + } // namespace panda::ecmascript diff --git a/runtime/interpreter/slow_runtime_stub.h b/runtime/interpreter/slow_runtime_stub.h index 50e2e6e71..a881b0521 100644 --- a/runtime/interpreter/slow_runtime_stub.h +++ b/runtime/interpreter/slow_runtime_stub.h @@ -76,7 +76,7 @@ public: static JSTaggedValue AsyncGeneratorReject(JSThread *thread, JSTaggedValue async_gen_obj, JSTaggedValue value); static JSTaggedValue NewObjSpreadDyn(JSThread *thread, JSTaggedValue func, JSTaggedValue new_target, JSTaggedValue array); - static void ThrowUndefinedIfHole(JSThread *thread, JSTaggedValue obj); + static void ThrowTdz(JSThread *thread, JSTaggedValue bindingName); static void ThrowIfNotObject(JSThread *thread); static void ThrowThrowNotExists(JSThread *thread); static void ThrowPatternNonCoercible(JSThread *thread); @@ -113,6 +113,21 @@ public: static void StModuleVar(JSThread *thread, JSTaggedValue export_name, JSTaggedValue export_obj); static void CopyModule(JSThread *thread, JSTaggedValue src_module); static JSTaggedValue LdModvarByName(JSThread *thread, JSTaggedValue module_obj, JSTaggedValue item_name); + + static JSTaggedValue ClassFieldAdd(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop_name, + JSTaggedValue value); + static void DefineClassPrivateFields(JSThread *thread, ConstantPool *constpool, JSTaggedValue env, + JSTaggedValue ctor, JSTaggedValue private_buf); + static JSTaggedValue ClassPrivateMethodOrAccessorAdd(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj); + static JSTaggedValue ClassPrivateFieldAdd(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj, + JSTaggedValue propName, JSTaggedValue value); + static JSTaggedValue ClassPrivateFieldGet(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj, + JSTaggedValue propName); + static JSTaggedValue ClassPrivateFieldSet(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj, + JSTaggedValue propName, JSTaggedValue value); + static JSTaggedValue ClassPrivateFieldIn(JSThread *thread, JSTaggedValue ctor, JSTaggedValue obj, + JSTaggedValue propName); + static JSTaggedValue CreateRegExpWithLiteral(JSThread *thread, JSTaggedValue pattern, uint8_t flags); static JSTaggedValue DefineGetterSetterByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, @@ -130,9 +145,6 @@ public: static JSTaggedValue TryLdGlobalByName(JSThread *thread, JSTaggedValue global, JSTaggedValue prop); static JSTaggedValue LdGlobalVar(JSThread *thread, JSTaggedValue global, JSTaggedValue prop); static JSTaggedValue StGlobalVar(JSThread *thread, JSTaggedValue prop, JSTaggedValue value); - static JSTaggedValue StGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value, bool is_const); - static JSTaggedValue LdGlobalRecord(JSThread *thread, JSTaggedValue key, bool *found); - static JSTaggedValue TryUpdateGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value); static JSTaggedValue StArraySpread(JSThread *thread, JSTaggedValue dst, JSTaggedValue index, JSTaggedValue src); static JSTaggedValue DefineGeneratorFunc(JSThread *thread, JSMethod *method); @@ -161,6 +173,10 @@ public: static JSTaggedValue CloneClassFromTemplate(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base, JSTaggedValue lexenv, ConstantPool *constpool); static JSTaggedValue SetClassConstructorLength(JSThread *thread, JSTaggedValue ctor, JSTaggedValue length); + + static JSTaggedValue LdEvalVar(JSThread *thread, JSTaggedValue name, JSTaggedValue eval_bindings); + static JSTaggedValue StEvalVar(JSThread *thread, JSTaggedValue name, JSTaggedValue eval_bindings, + JSTaggedValue value); /* -------------- Common API End, Don't change those interface!!! ----------------- */ private: diff --git a/runtime/interpreter/templates/debugger_instruction_dispatch.inl b/runtime/interpreter/templates/debugger_instruction_dispatch.inl index e45c0bae5..ff6baafb0 100644 --- a/runtime/interpreter/templates/debugger_instruction_dispatch.inl +++ b/runtime/interpreter/templates/debugger_instruction_dispatch.inl @@ -142,9 +142,6 @@ &&DEBUG_HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8, &&DEBUG_HANDLE_ISTRUE_PREF, &&DEBUG_HANDLE_ISFALSE_PREF, - &&DEBUG_HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32, - &&DEBUG_HANDLE_STLETTOGLOBALRECORD_PREF_ID32, - &&DEBUG_HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32, &&DEBUG_HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8, &&DEBUG_HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8, &&DEBUG_HANDLE_LDFUNCTION_PREF, @@ -269,4 +266,4 @@ &&DEBUG_HANDLE_OVERFLOW, &&DEBUG_HANDLE_OVERFLOW, &&DEBUG_HANDLE_OVERFLOW, - &&DEBUG_HANDLE_OVERFLOW, \ No newline at end of file + &&DEBUG_HANDLE_OVERFLOW, diff --git a/runtime/interpreter/templates/debugger_instruction_handler.inl b/runtime/interpreter/templates/debugger_instruction_handler.inl index 7c816660f..12089b719 100644 --- a/runtime/interpreter/templates/debugger_instruction_handler.inl +++ b/runtime/interpreter/templates/debugger_instruction_handler.inl @@ -658,21 +658,6 @@ NOTIFY_DEBUGGER_EVENT(); REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::ISFALSE_PREF); } - HANDLE_OPCODE(DEBUG_HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32) - { - NOTIFY_DEBUGGER_EVENT(); - REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STCONSTTOGLOBALRECORD_PREF_ID32); - } - HANDLE_OPCODE(DEBUG_HANDLE_STLETTOGLOBALRECORD_PREF_ID32) - { - NOTIFY_DEBUGGER_EVENT(); - REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STLETTOGLOBALRECORD_PREF_ID32); - } - HANDLE_OPCODE(DEBUG_HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32) - { - NOTIFY_DEBUGGER_EVENT(); - REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STCLASSTOGLOBALRECORD_PREF_ID32); - } HANDLE_OPCODE(DEBUG_HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8) { NOTIFY_DEBUGGER_EVENT(); diff --git a/runtime/interpreter/templates/instruction_dispatch.inl b/runtime/interpreter/templates/instruction_dispatch.inl index dc4ec7d1c..544ba93d2 100644 --- a/runtime/interpreter/templates/instruction_dispatch.inl +++ b/runtime/interpreter/templates/instruction_dispatch.inl @@ -142,9 +142,6 @@ &&HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8, &&HANDLE_ISTRUE_PREF, &&HANDLE_ISFALSE_PREF, - &&HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32, - &&HANDLE_STLETTOGLOBALRECORD_PREF_ID32, - &&HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32, &&HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8, &&HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8, &&HANDLE_LDFUNCTION_PREF, diff --git a/runtime/intrinsics-inl.h b/runtime/intrinsics-inl.h index 2c45c23f7..6847b21c5 100644 --- a/runtime/intrinsics-inl.h +++ b/runtime/intrinsics-inl.h @@ -31,6 +31,7 @@ #include "plugins/ecmascript/runtime/js_generator_object.h" #include "plugins/ecmascript/runtime/js_handle.h" #include "plugins/ecmascript/runtime/js_array.h" +#include "plugins/ecmascript/runtime/js_eval.h" namespace panda::ecmascript::intrinsics { #ifndef INLINE_ECMA_INTRINSICS @@ -60,6 +61,7 @@ static inline JSTaggedValue HandlerCall(JSThread *thread, JSTaggedValue fn_objec ECMAObject *js_object = ECMAObject::Cast(fn_object.GetHeapObject()); Method *method = js_object->GetCallTarget(); + // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if constexpr (!THIS_CALL) { ASSERT(args[2] == JSTaggedValue::Undefined()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) if (fn_object.IsJSFunction() && !JSFunction::Cast(js_object)->IsStrict()) { @@ -143,9 +145,12 @@ INLINE_ECMA_INTRINSICS uint64_t Ldstring([[maybe_unused]] JSThread *thread, [[ma } // NOLINTNEXTLINE(misc-definitions-in-headers) -INLINE_ECMA_INTRINSICS uint64_t Ldbigint([[maybe_unused]] JSThread *thread, [[maybe_unused]] uint64_t a0) +INLINE_ECMA_INTRINSICS uint64_t Ldbigint([[maybe_unused]] JSThread *thread, [[maybe_unused]] uint32_t stringId) { - UNREACHABLE(); + INTERPRETER_TRACE(thread, Ldbigint); + JSTaggedValue numberBigInt = GetConstantPool(thread)->GetObjectFromCache(stringId); + JSHandle bigIntHandle(thread, numberBigInt); + return JSTaggedValue::ToBigInt(thread, bigIntHandle).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) @@ -320,19 +325,19 @@ INLINE_ECMA_INTRINSICS uint64_t NotEqDyn(JSThread *thread, uint64_t lhs, uint64_ } // NOLINTNEXTLINE(misc-definitions-in-headers) -INLINE_ECMA_INTRINSICS uint64_t StrictEqDyn(uint64_t lhs, uint64_t rhs) +INLINE_ECMA_INTRINSICS uint64_t StrictEqDyn(JSThread *thread, uint64_t lhs, uint64_t rhs) { auto left = JSTaggedValue(lhs); auto right = JSTaggedValue(rhs); - return JSTaggedValue(FastRuntimeStub::FastStrictEqual(left, right)).GetRawData(); + return JSTaggedValue(FastRuntimeStub::FastStrictEqual(thread, left, right)).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) -INLINE_ECMA_INTRINSICS uint64_t StrictNotEqDyn(uint64_t lhs, uint64_t rhs) +INLINE_ECMA_INTRINSICS uint64_t StrictNotEqDyn(JSThread *thread, uint64_t lhs, uint64_t rhs) { auto left = JSTaggedValue(lhs); auto right = JSTaggedValue(rhs); - return JSTaggedValue(!FastRuntimeStub::FastStrictEqual(left, right)).GetRawData(); + return JSTaggedValue(!FastRuntimeStub::FastStrictEqual(thread, left, right)).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) @@ -430,10 +435,6 @@ INLINE_ECMA_INTRINSICS uint64_t TryLdGlobalByName(JSThread *thread, uint32_t str #endif bool found = false; - result = SlowRuntimeStub::LdGlobalRecord(thread, prop, &found); - if (found) { - return PropertyBox::Cast(result.GetTaggedObject())->GetValue().GetRawData(); - } result = FastRuntimeStub::GetGlobalOwnProperty(global_obj, prop, &found); if (found) { @@ -785,6 +786,53 @@ INLINE_ECMA_INTRINSICS uint64_t CalliRangeDyn([[maybe_unused]] JSThread *thread, UNREACHABLE(); } +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t Call0ThisDyn(JSThread *thread, uint64_t raw_fn_object, uint64_t raw_this) +{ + std::array args = { + JSTaggedValue(raw_fn_object), + JSTaggedValue::Undefined(), + JSTaggedValue(raw_this), + }; + return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t Call1ThisDyn(JSThread *thread, uint64_t raw_fn_object, uint64_t raw_this, + uint64_t raw_a0) +{ + std::array args = { + JSTaggedValue(raw_fn_object), + JSTaggedValue::Undefined(), + JSTaggedValue(raw_this), + JSTaggedValue(raw_a0), + }; + return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t Call2ThisDyn(JSThread *thread, uint64_t raw_fn_object, uint64_t raw_this, + uint64_t raw_a0, uint64_t raw_a1) +{ + std::array args = { + JSTaggedValue(raw_fn_object), JSTaggedValue::Undefined(), JSTaggedValue(raw_this), + JSTaggedValue(raw_a0), JSTaggedValue(raw_a1), + }; + return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t Call3ThisDyn(JSThread *thread, uint64_t raw_fn_object, uint64_t raw_this, + uint64_t raw_a0, uint64_t raw_a1, uint64_t raw_a2) +{ + std::array args = { + JSTaggedValue(raw_fn_object), JSTaggedValue::Undefined(), JSTaggedValue(raw_this), + JSTaggedValue(raw_a0), JSTaggedValue(raw_a1), JSTaggedValue(raw_a2), + }; + return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); +} + +// Just declared here, not used // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t CalliRangeDynInterp(JSThread *thread, uint16_t args_num, uint64_t args_ptr) { @@ -932,11 +980,6 @@ INLINE_ECMA_INTRINSICS uint64_t TryStGlobalByName(JSThread *thread, uint32_t str #endif bool found = false; - SlowRuntimeStub::LdGlobalRecord(thread, prop_key, &found); - // 1. find from global record - if (found) { - return SlowRuntimeStub::TryUpdateGlobalRecord(thread, prop_key, JSTaggedValue(value)).GetRawData(); - } // 2. find from global object FastRuntimeStub::GetGlobalOwnProperty(global_obj, prop_key, &found); if (!found) { @@ -992,13 +1035,6 @@ INLINE_ECMA_INTRINSICS uint64_t StGlobalVar(JSThread *thread, uint32_t string_id return SlowRuntimeStub::StGlobalVar(thread, prop, JSTaggedValue(value)).GetRawData(); } -// NOLINTNEXTLINE(misc-definitions-in-headers) -INLINE_ECMA_INTRINSICS uint64_t StGlobalLet(JSThread *thread, uint32_t string_id, uint64_t value) -{ - JSTaggedValue prop = GetConstantPool(thread)->GetObjectFromCache(string_id); - return SlowRuntimeStub::StGlobalRecord(thread, prop, JSTaggedValue(value), false).GetRawData(); -} - // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t LdObjByName(JSThread *thread, uint32_t string_id, uint64_t object, [[maybe_unused]] uint16_t slot_id) @@ -1087,8 +1123,10 @@ INLINE_ECMA_INTRINSICS uint64_t StObjByIndex(JSThread *thread, uint32_t idx, uin return SlowRuntimeStub::StObjByIndex(thread, obj, idx, val).GetRawData(); } -ARK_INLINE inline static bool GetLeftRightInt(JSThread *thread, uint64_t lhs, uint64_t rhs, bool is_u_left, - bool is_u_right, int32_t &left, int32_t &right) +template bigintOP(JSThread *, JSHandle, JSHandle), bool is_u_left = false, + bool is_u_right = false> +ARK_INLINE inline static JSTaggedValue GetLeftRightInt(JSThread *thread, uint64_t lhs, uint64_t rhs, int32_t &left, + int32_t &right) { auto jleft = JSTaggedValue(lhs); auto jright = JSTaggedValue(rhs); @@ -1096,48 +1134,78 @@ ARK_INLINE inline static bool GetLeftRightInt(JSThread *thread, uint64_t lhs, ui if (jleft.IsInt() && jright.IsInt()) { left = jleft.GetInt(); right = jright.GetInt(); - return true; + return JSTaggedValue::Hole(); } if (jleft.IsNumber() && jright.IsNumber()) { left = jleft.IsInt() ? jleft.GetInt() : base::NumberHelper::DoubleToInt(jleft.GetDouble(), base::INT32_BITS); right = jright.IsInt() ? jright.GetInt() : base::NumberHelper::DoubleToInt(jright.GetDouble(), base::INT32_BITS); - return true; + return JSTaggedValue::Hole(); } - [[maybe_unused]] EcmaHandleScope handle_scope(thread); - JSHandle right_handle(thread, jright); - jleft = is_u_left ? SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, jleft) - : SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, jleft); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle rightHandle(thread, jright); + JSHandle leftHandle(thread, jleft); + + JSHandle leftValue = JSTaggedValue::ToNumeric(thread, leftHandle); + + if (leftValue->IsException()) { + return JSTaggedValue::Exception(); + } + + JSHandle rightValue = JSTaggedValue::ToNumeric(thread, rightHandle); + + if (rightValue->IsException()) { + return JSTaggedValue::Exception(); + } + + if (leftValue->IsBigInt() || rightValue->IsBigInt()) { + if (leftValue->IsBigInt() && rightValue->IsBigInt()) { + return bigintOP(thread, JSHandle::Cast(leftValue), JSHandle::Cast(rightValue)) + .GetTaggedValue(); + } + + JSHandle error = GetFactory(thread)->GetJSError( + ErrorType::TYPE_ERROR, "Cannot mix BigInt and other types, use explicit conversions"); + thread->SetException(error.GetTaggedValue()); + return JSTaggedValue::Exception(); + } + + jleft = is_u_left ? SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, leftValue.GetTaggedValue()) + : SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, leftValue.GetTaggedValue()); if (jleft.IsException()) { - return false; + return JSTaggedValue::Exception(); } - jright = right_handle.GetTaggedValue(); // Maybe moved by GC - jright = is_u_right ? SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, jright) - : SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, jright); + jright = is_u_right ? SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, rightValue.GetTaggedValue()) + : SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, rightValue.GetTaggedValue()); if (jright.IsException()) { - return false; + return JSTaggedValue::Exception(); } left = jleft.GetInt(); right = jright.GetInt(); - return true; + return JSTaggedValue::Hole(); } // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t And2Dyn(JSThread *thread, uint64_t lhs, uint64_t rhs) { - int32_t left; - int32_t right; + int32_t left {}; + int32_t right {}; - if (!GetLeftRightInt(thread, lhs, rhs, false, false, left, right)) { + JSTaggedValue res = GetLeftRightInt(thread, lhs, rhs, left, right); + if (res.IsException()) { return TaggedValue::VALUE_EXCEPTION; } + if (!res.IsHole()) { + return res.GetRawData(); + } + // NOLINT(hicpp-signed-bitwise) auto ret = static_cast(left) & static_cast(right); return JSTaggedValue(static_cast(ret)).GetRawData(); @@ -1146,13 +1214,18 @@ INLINE_ECMA_INTRINSICS uint64_t And2Dyn(JSThread *thread, uint64_t lhs, uint64_t // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t Or2Dyn(JSThread *thread, uint64_t lhs, uint64_t rhs) { - int32_t left; - int32_t right; + int32_t left {}; + int32_t right {}; - if (!GetLeftRightInt(thread, lhs, rhs, false, false, left, right)) { + JSTaggedValue res = GetLeftRightInt(thread, lhs, rhs, left, right); + if (res.IsException()) { return TaggedValue::VALUE_EXCEPTION; } + if (!res.IsHole()) { + return res.GetRawData(); + } + auto ret = static_cast(left) | static_cast(right); return JSTaggedValue(static_cast(ret)).GetRawData(); } @@ -1160,13 +1233,18 @@ INLINE_ECMA_INTRINSICS uint64_t Or2Dyn(JSThread *thread, uint64_t lhs, uint64_t // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t Xor2Dyn(JSThread *thread, uint64_t lhs, uint64_t rhs) { - int32_t left; - int32_t right; + int32_t left {}; + int32_t right {}; - if (!GetLeftRightInt(thread, lhs, rhs, false, false, left, right)) { + JSTaggedValue res = GetLeftRightInt(thread, lhs, rhs, left, right); + if (res.IsException()) { return TaggedValue::VALUE_EXCEPTION; } + if (!res.IsHole()) { + return res.GetRawData(); + } + auto ret = static_cast(left) ^ static_cast(right); return JSTaggedValue(static_cast(ret)).GetRawData(); } @@ -1174,13 +1252,18 @@ INLINE_ECMA_INTRINSICS uint64_t Xor2Dyn(JSThread *thread, uint64_t lhs, uint64_t // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t Shl2Dyn(JSThread *thread, uint64_t lhs, uint64_t rhs) { - int32_t left; - int32_t right; + int32_t left {}; + int32_t right {}; - if (!GetLeftRightInt(thread, lhs, rhs, false, true, left, right)) { + JSTaggedValue res = GetLeftRightInt(thread, lhs, rhs, left, right); + if (res.IsException()) { return TaggedValue::VALUE_EXCEPTION; } + if (!res.IsHole()) { + return res.GetRawData(); + } + uint32_t shift = static_cast(right) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) using UnsignedType = std::make_unsigned_t; return JSTaggedValue(static_cast(static_cast(left) << shift)) @@ -1190,13 +1273,18 @@ INLINE_ECMA_INTRINSICS uint64_t Shl2Dyn(JSThread *thread, uint64_t lhs, uint64_t // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t Shr2Dyn(JSThread *thread, uint64_t lhs, uint64_t rhs) { - int32_t left; - int32_t right; + int32_t left {}; + int32_t right {}; - if (!GetLeftRightInt(thread, lhs, rhs, false, true, left, right)) { + JSTaggedValue res = GetLeftRightInt(thread, lhs, rhs, left, right); + if (res.IsException()) { return TaggedValue::VALUE_EXCEPTION; } + if (!res.IsHole()) { + return res.GetRawData(); + } + uint32_t shift = static_cast(right) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) return JSTaggedValue(static_cast(left >> shift)).GetRawData(); // NOLINT(hicpp-signed-bitwise) } @@ -1204,13 +1292,18 @@ INLINE_ECMA_INTRINSICS uint64_t Shr2Dyn(JSThread *thread, uint64_t lhs, uint64_t // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t Ashr2Dyn(JSThread *thread, uint64_t lhs, uint64_t rhs) { - int32_t left; - int32_t right; + int32_t left {}; + int32_t right {}; - if (!GetLeftRightInt(thread, lhs, rhs, true, true, left, right)) { + JSTaggedValue res = GetLeftRightInt(thread, lhs, rhs, left, right); + if (res.IsException()) { return TaggedValue::VALUE_EXCEPTION; } + if (!res.IsHole()) { + return res.GetRawData(); + } + uint32_t shift = static_cast(right) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) using UnsignedType = std::make_unsigned_t; return JSTaggedValue(static_cast(static_cast(left) >> shift)) @@ -1277,6 +1370,20 @@ INLINE_ECMA_INTRINSICS uint64_t LdLexVarDyn(JSThread *thread, uint16_t level, ui return env->GetProperties(slot).GetRawData(); } +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t LdLexDyn(JSThread *thread, uint32_t string_id, uint16_t level, uint16_t slot) +{ + JSTaggedValue binding(LdLexVarDyn(level, slot)); + + if (!binding.IsHole()) { + return binding.GetRawData(); + } + + auto bindingName = GetConstantPool(thread)->GetObjectFromCache(string_id); + SlowRuntimeStub::ThrowTdz(GetJSThread(), bindingName); + return JSTaggedValue(JSTaggedValue::VALUE_EXCEPTION).GetRawData(); +} + // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS void PopLexenvDyn(JSThread *thread) { @@ -1373,6 +1480,12 @@ INLINE_ECMA_INTRINSICS uint64_t CopylexenvDyn(JSThread *thread) return res.GetRawData(); } +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS void ThrowTdz(JSThread *thread, uint32_t string_id) +{ + SlowRuntimeStub::ThrowTdz(thread, GetConstantPool(thread)->GetObjectFromCache(string_id)); +} + // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS void StLexVarDyn(JSThread *thread, uint16_t level, uint16_t slot, uint64_t value) { @@ -1387,6 +1500,30 @@ INLINE_ECMA_INTRINSICS void StLexVarDyn(JSThread *thread, uint16_t level, uint16 LexicalEnv::Cast(env.GetHeapObject())->SetProperties(thread, slot, JSTaggedValue(value)); } +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t StLexDyn(JSThread *thread, uint32_t stringId, uint16_t level, uint16_t slot, + uint64_t value) +{ + JSTaggedValue currentLexenv(GetLexicalEnv(thread)); + JSTaggedValue env(currentLexenv); + + for (int i = 0; i < level; i++) { + JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetHeapObject())->GetParentEnv(); + ASSERT(!taggedParentEnv.IsUndefined()); + env = taggedParentEnv; + } + + LexicalEnv *lexEnv = LexicalEnv::Cast(env.GetHeapObject()); + + if (lexEnv->GetProperties(slot).IsHole()) { + ThrowTdz(thread, stringId); + return JSTaggedValue(JSTaggedValue::VALUE_EXCEPTION).GetRawData(); + } + + lexEnv->SetProperties(thread, slot, JSTaggedValue(value)); + return value; +} + // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t Toboolean(uint64_t obj) { @@ -1539,19 +1676,6 @@ INLINE_ECMA_INTRINSICS void ThrowConstAssignment(JSThread *thread, uint32_t stri return SlowRuntimeStub::ThrowConstAssignment(thread, GetConstantPool(thread)->GetObjectFromCache(string_id)); } -// NOLINTNEXTLINE(misc-definitions-in-headers) -INLINE_ECMA_INTRINSICS uint64_t ThrowUndefinedIfHole(JSThread *thread, uint32_t string_id, uint64_t hole) -{ - if (!JSTaggedValue(hole).IsHole()) { - return JSTaggedValue(hole).GetRawData(); - } - - auto obj = GetConstantPool(thread)->GetObjectFromCache(string_id); - ASSERT(obj.IsString()); - SlowRuntimeStub::ThrowUndefinedIfHole(thread, obj); - return JSTaggedValue(JSTaggedValue::VALUE_EXCEPTION).GetRawData(); -} - // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t GetMethod(JSThread *thread, uint32_t string_id, uint64_t object) { @@ -1625,6 +1749,14 @@ INLINE_ECMA_INTRINSICS uint64_t CreateArrayWithBuffer(JSThread *thread, uint16_t return SlowRuntimeStub::CreateArrayWithBuffer(thread, factory, result).GetRawData(); } +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t CreateRegExpWithLiteral(JSThread *thread, uint32_t string_id, uint8_t flags) +{ + return SlowRuntimeStub::CreateRegExpWithLiteral(thread, GetConstantPool(thread)->GetObjectFromCache(string_id), + flags) + .GetRawData(); +} + // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t StOwnByIndex(JSThread *thread, uint64_t object, uint64_t idx, uint64_t val) { @@ -1788,6 +1920,65 @@ INLINE_ECMA_INTRINSICS uint64_t LdModvarByName(JSThread *thread, uint32_t string return SlowRuntimeStub::LdModvarByName(thread, JSTaggedValue(module_obj), item_name).GetRawData(); } +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t ClassFieldAdd(JSThread *thread, uint64_t ctor, uint64_t prop, uint64_t value) +{ + return SlowRuntimeStub::ClassFieldAdd(thread, JSTaggedValue(ctor), JSTaggedValue(prop), JSTaggedValue(value)) + .GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS void DefineClassPrivateFields(JSThread *thread, uint16_t privateBufIdx, uint64_t env, + uint64_t ctor) +{ + auto *constpool = GetConstantPool(thread); + SlowRuntimeStub::DefineClassPrivateFields(thread, constpool, JSTaggedValue(env), JSTaggedValue(ctor), + constpool->GetObjectFromCache(privateBufIdx)); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t ClassPrivateMethodOrAccessorAdd(JSThread *thread, uint64_t ctor, uint64_t obj) +{ + return SlowRuntimeStub::ClassPrivateMethodOrAccessorAdd(thread, JSTaggedValue(ctor), JSTaggedValue(obj)) + .GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t ClassPrivateFieldAdd(JSThread *thread, uint32_t string_id, uint64_t ctor, uint64_t obj, + uint64_t value) +{ + return SlowRuntimeStub::ClassPrivateFieldAdd(thread, JSTaggedValue(ctor), JSTaggedValue(obj), + GetConstantPool(thread)->GetObjectFromCache(string_id), + JSTaggedValue(value)) + .GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t ClassPrivateFieldGet(JSThread *thread, uint32_t string_id, uint64_t ctor, uint64_t obj) +{ + return SlowRuntimeStub::ClassPrivateFieldGet(thread, JSTaggedValue(ctor), JSTaggedValue(obj), + GetConstantPool(thread)->GetObjectFromCache(string_id)) + .GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t ClassPrivateFieldSet(JSThread *thread, uint32_t string_id, uint64_t ctor, uint64_t obj, + uint64_t value) +{ + return SlowRuntimeStub::ClassPrivateFieldSet(thread, JSTaggedValue(ctor), JSTaggedValue(obj), + GetConstantPool(thread)->GetObjectFromCache(string_id), + JSTaggedValue(value)) + .GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t ClassPrivateFieldIn(JSThread *thread, uint32_t string_id, uint64_t ctor, uint64_t obj) +{ + return SlowRuntimeStub::ClassPrivateFieldIn(thread, JSTaggedValue(ctor), JSTaggedValue(obj), + GetConstantPool(thread)->GetObjectFromCache(string_id)) + .GetRawData(); +} + // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t DefineClassWithBuffer(JSThread *thread, uint32_t method_id, uint16_t imm, uint64_t lexenv, uint64_t proto) @@ -1818,6 +2009,30 @@ INLINE_ECMA_INTRINSICS uint64_t DefineClassWithBuffer(JSThread *thread, uint32_t return res.GetRawData(); } +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS void SetClassComputedFields(JSThread *thread, uint64_t class_reg, uint64_t computed_fields) +{ + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle cls(thread, JSTaggedValue(class_reg)); + JSHandle computedFieldsHandle(thread, JSTaggedValue(computed_fields)); + cls->SetComputedFields(thread, computedFieldsHandle); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t LoadClassComputedInstanceFields(JSThread *thread, uint64_t class_reg) +{ + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle cls(thread, JSTaggedValue(class_reg)); + JSTaggedValue computedInstanceFields = cls->GetComputedFields(); + ASSERT(computedInstanceFields.IsJSArray()); + cls->SetComputedFields(thread, JSTaggedValue::Hole()); + + return computedInstanceFields.GetRawData(); +} + +// Just declared here, not used // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t SuperCall(JSThread *thread, uint16_t range, uint64_t args, uint64_t new_target, uint64_t obj_value) @@ -1922,6 +2137,34 @@ INLINE_ECMA_INTRINSICS void ThrowDeleteSuperProperty(JSThread *thread) SlowRuntimeStub::ThrowDeleteSuperProperty(thread); } +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t LdEvalBindings(JSThread *thread, uint16_t index) +{ + return GetConstantPool(thread)->GetObjectFromCache(index).GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t DirectEval(JSThread *thread, uint32_t status, uint64_t arg0, uint64_t evalBindings) +{ + return EvalUtils::DirectEval(thread, status, JSTaggedValue(arg0), JSTaggedValue(evalBindings)).GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t LdEvalVar(JSThread *thread, uint32_t string_id, uint64_t lexicalContext) +{ + return SlowRuntimeStub::LdEvalVar(thread, GetConstantPool(thread)->GetObjectFromCache(string_id), + JSTaggedValue(lexicalContext)) + .GetRawData(); +} + +// NOLINTNEXTLINE(misc-definitions-in-headers) +INLINE_ECMA_INTRINSICS uint64_t StEvalVar(JSThread *thread, uint32_t string_id, uint64_t value, uint64_t lexicalContext) +{ + return SlowRuntimeStub::StEvalVar(thread, GetConstantPool(thread)->GetObjectFromCache(string_id), + JSTaggedValue(lexicalContext), JSTaggedValue(value)) + .GetRawData(); +} + // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS void Debugger() { diff --git a/runtime/js_bigint.cpp b/runtime/js_bigint.cpp new file mode 100644 index 000000000..9e035ef26 --- /dev/null +++ b/runtime/js_bigint.cpp @@ -0,0 +1,1455 @@ +/* + * 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. + */ + +#include "js_bigint.h" +#include +#include "plugins/ecmascript/runtime/js_array.h" +#include "plugins/ecmascript/runtime/object_factory.h" + +namespace panda::ecmascript { +class ObjectFactory; +constexpr char dp[] = "0123456789abcdefghijklmnopqrstuvwxyz"; // NOLINT(modernize-avoid-c-arrays) +static int CharToInt(char c) +{ + int res = 0; + if (c >= '0' && c <= '9') { + res = c - '0'; + } else if (c >= 'A' && c <= 'Z') { + res = c - 'A' + 10; // NOLINT(readability-magic-numbers) 10:res must Greater than 10. + } else if (c >= 'a' && c <= 'z') { + res = c - 'a' + 10; // NOLINT(readability-magic-numbers) 10:res must Greater than 10 + } + return res; +} + +static std::string Division(std::string &num, uint32_t conversionToRadix, uint32_t currentRadix, uint32_t &remain) +{ + ASSERT(conversionToRadix != 0); + uint32_t temp = 0; + remain = 0; + for (char &c : num) { + temp = (currentRadix * remain + static_cast(CharToInt(c))); + c = dp[temp / conversionToRadix]; + remain = temp % conversionToRadix; + } + int count = 0; + while (num[count] == '0') { + count++; + } + return num.substr(count); +} + +std::string BigIntHelper::Conversion(const std::string &num, uint32_t conversionToRadix, uint32_t currentRadix) +{ + ASSERT(conversionToRadix != 0); + std::string newNum = num; + std::string res; + uint32_t remain = 0; + while (!newNum.empty()) { + newNum = Division(newNum, conversionToRadix, currentRadix, remain); + res.insert(res.begin(), dp[remain]); + } + return res; +} + +JSHandle BigIntHelper::SetBigInt(JSThread *thread, const std::string &numStr, uint32_t currentRadix) +{ + int flag = 0; + if (numStr[0] == '-') { + flag = 1; + } + + std::string binaryStr; + if (currentRadix != BigInt::BINARY) { + binaryStr = Conversion(numStr.substr(flag), BigInt::BINARY, currentRadix); + } else { + binaryStr = numStr.substr(flag); + } + + JSHandle bigInt; + size_t binaryStrLen = binaryStr.size(); + size_t len = binaryStrLen / BigInt::DATEBITS; + size_t mod = binaryStrLen % BigInt::DATEBITS; + int index = 0; + if (mod == 0) { + index = static_cast(len - 1); + bigInt = BigInt::CreateBigInt(thread, len); + } else { + len++; + index = static_cast(len - 1); + bigInt = BigInt::CreateBigInt(thread, len); + uint32_t val = 0; + for (size_t i = 0; i < mod; ++i) { + val <<= 1U; + val |= static_cast(binaryStr[i] - '0'); + } + BigInt::SetDigit(thread, bigInt, index, val); + index--; + } + if (flag == 1) { + bigInt->SetSign(true); + } + size_t i = mod; + while (i < binaryStrLen) { + uint32_t val = 0; + for (size_t j = 0; j < BigInt::DATEBITS && i < binaryStrLen; ++j, ++i) { + val <<= 1U; + val |= static_cast(binaryStr[i] - '0'); + } + BigInt::SetDigit(thread, bigInt, index, val); + index--; + } + return BigIntHelper::RightTruncate(thread, bigInt); +} + +JSHandle BigIntHelper::RightTruncate(JSThread *thread, JSHandle x) +{ + int len = static_cast(x->GetLength()); + ASSERT(len != 0); + if (len == 1 && x->GetDigit(0) == 0) { + x->SetSign(false); + return x; + } + int index = len - 1; + if (x->GetDigit(index) != 0) { + return x; + } + while (index >= 0) { + if (x->GetDigit(index) != 0) { + break; + } + index--; + } + JSHandle array(thread, x->GetData()); + if (index == -1) { + array->Trim(thread, 1); + } else { + array->Trim(thread, index + 1); + } + if (x->IsZero()) { + x->SetSign(false); + } + return x; +} + +std::string BigIntHelper::GetBinary(const JSHandle &bigInt) +{ + int index = 0; + auto len = static_cast(bigInt->GetLength()); + int strLen = BigInt::DATEBITS * len; + std::string res(strLen, '0'); + int strIndex = strLen - 1; + while (index < len) { + int bityLen = BigInt::DATEBITS; + uint32_t val = bigInt->GetDigit(index); + while (bityLen-- != 0) { + res[strIndex--] = (val & 1U) + '0'; + val = val >> 1UL; + } + index++; + } + size_t count = 0; + size_t resLen = res.size(); + for (size_t i = 0; i < resLen; ++i) { + if (res[i] != '0') { + break; + } + count++; + } + if (count == resLen) { + return "0"; + } + return res.substr(count); +} + +uint32_t BigInt::GetDigit(uint32_t index) const +{ + TaggedArray *taggedArray = TaggedArray::Cast(GetData().GetTaggedObject()); + JSTaggedValue digit = taggedArray->Get(index); + return static_cast(digit.GetInt()); +} + +void BigInt::SetDigit(JSThread *thread, JSHandle bigInt, uint32_t index, uint32_t digit) +{ + JSHandle digitsHandle(thread, bigInt->GetData().GetTaggedObject()); + digitsHandle->Set(thread, index, JSTaggedValue(static_cast(digit))); +} + +uint32_t BigInt::GetLength() const +{ + TaggedArray *taggedArray = TaggedArray::Cast(GetData().GetTaggedObject()); + return taggedArray->GetLength(); +} + +JSHandle BigInt::CreateBigInt(JSThread *thread, uint32_t size) +{ + ASSERT(size < MAXSIZE); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle bigInt = factory->NewBigInt(); + JSHandle taggedArray = factory->NewTaggedArray(size); + bigInt->SetData(thread, taggedArray.GetTaggedValue()); + return bigInt; +} + +// 6.1.6.2.13 +bool BigInt::Equal(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y) +{ + [[maybe_unused]] EcmaHandleScope scope(thread); + JSHandle xHandle(thread, x); + JSHandle yHandle(thread, y); + return Equal(xHandle, yHandle); +} + +bool BigInt::Equal(const JSHandle &x, const JSHandle &y) +{ + if (x->GetSign() != y->GetSign() || x->GetLength() != y->GetLength()) { + return false; + } + for (uint32_t i = 0; i < x->GetLength(); ++i) { + if (x->GetDigit(i) != y->GetDigit(i)) { + return false; + } + } + return true; +} + +// 6.1.6.2.14 +bool BigInt::SameValue(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y) +{ + return Equal(thread, x, y); +} + +// 6.1.6.2.15 +bool BigInt::SameValueZero(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y) +{ + return Equal(thread, x, y); +} + +void BigInt::InitializationZero(JSThread *thread, JSHandle bigInt) +{ + uint32_t len = bigInt->GetLength(); + for (uint32_t i = 0; i < len; ++i) { + SetDigit(thread, bigInt, i, 0); + } +} + +JSHandle BigInt::BitwiseOp(JSThread *thread, Operate op, JSHandle x, JSHandle y) +{ + uint32_t maxLen = 0; + uint32_t minLen = 0; + uint32_t xlen = x->GetLength(); + uint32_t ylen = y->GetLength(); + if (xlen > ylen) { + maxLen = xlen; + minLen = ylen; + } else { + maxLen = ylen; + minLen = xlen; + } + JSHandle bigInt = BigInt::CreateBigInt(thread, maxLen); + InitializationZero(thread, bigInt); + for (size_t i = 0; i < minLen; ++i) { + if (op == Operate::OR) { + SetDigit(thread, bigInt, i, x->GetDigit(i) | y->GetDigit(i)); + } else if (op == Operate::AND) { + SetDigit(thread, bigInt, i, x->GetDigit(i) & y->GetDigit(i)); + } else { + ASSERT(op == Operate::XOR); + SetDigit(thread, bigInt, i, x->GetDigit(i) ^ y->GetDigit(i)); + } + } + if (op == Operate::OR || op == Operate::XOR) { + if (xlen > ylen) { + for (size_t i = ylen; i < xlen; ++i) { + SetDigit(thread, bigInt, i, x->GetDigit(i)); + } + } else if (ylen > xlen) { + for (size_t i = xlen; i < ylen; ++i) { + SetDigit(thread, bigInt, i, y->GetDigit(i)); + } + } + } + return BigIntHelper::RightTruncate(thread, bigInt); +} + +JSHandle OneIsNegativeAND(JSThread *thread, JSHandle x, JSHandle y) +{ + JSHandle yVal = BigInt::BitwiseSubOne(thread, y, y->GetLength()); + uint32_t xLength = x->GetLength(); + uint32_t yLength = yVal->GetLength(); + uint32_t minLen = xLength; + if (xLength > yLength) { + minLen = yLength; + } + JSHandle newBigInt = BigInt::CreateBigInt(thread, xLength); + uint32_t i = 0; + while (i < minLen) { + uint32_t res = x->GetDigit(i) & ~(yVal->GetDigit(i)); + BigInt::SetDigit(thread, newBigInt, i, res); + ++i; + } + while (i < xLength) { + BigInt::SetDigit(thread, newBigInt, i, x->GetDigit(i)); + ++i; + } + return BigIntHelper::RightTruncate(thread, newBigInt); +} + +// 6.1.6.2.20 BigInt::bitwiseAND ( x, y ) +JSHandle BigInt::BitwiseAND(JSThread *thread, JSHandle x, JSHandle y) +{ + if (x->GetSign() && y->GetSign()) { + // (-x) & (-y) == -(((x-1) | (y-1)) + 1) + JSHandle xVal = BitwiseSubOne(thread, x, x->GetLength()); + JSHandle yVal = BitwiseSubOne(thread, y, y->GetLength()); + JSHandle temp = BitwiseOp(thread, Operate::OR, xVal, yVal); + JSHandle res = BitwiseAddOne(thread, temp); + return res; + } + if (x->GetSign() != y->GetSign()) { + // x & (-y) == x & ~(y-1) + if (!x->GetSign()) { + return OneIsNegativeAND(thread, x, y); + } + return OneIsNegativeAND(thread, y, x); + } + return BitwiseOp(thread, Operate::AND, x, y); +} + +JSHandle OneIsNegativeXOR(JSThread *thread, JSHandle x, JSHandle y) +{ + JSHandle yVal = BigInt::BitwiseSubOne(thread, y, y->GetLength()); + JSHandle temp = BigInt::BitwiseOp(thread, Operate::XOR, x, yVal); + JSHandle res = BigInt::BitwiseAddOne(thread, temp); + return res; +} + +// 6.1.6.2.21 BigInt::bitwiseOR ( x, y ) +JSHandle BigInt::BitwiseXOR(JSThread *thread, JSHandle x, JSHandle y) +{ + if (x->GetSign() && y->GetSign()) { + // (-x) ^ (-y) == (x-1) ^ (y-1) + JSHandle xVal = BitwiseSubOne(thread, x, x->GetLength()); + JSHandle yVal = BitwiseSubOne(thread, y, y->GetLength()); + return BitwiseOp(thread, Operate::XOR, xVal, yVal); + } + if (x->GetSign() != y->GetSign()) { + // x ^ (-y) == -((x ^ (y-1)) + 1) + if (!x->GetSign()) { + return OneIsNegativeXOR(thread, x, y); + } + return OneIsNegativeXOR(thread, y, x); + } + return BitwiseOp(thread, Operate::XOR, x, y); +} + +JSHandle BigInt::BitwiseSubOne(JSThread *thread, JSHandle bigInt, uint32_t maxLen) +{ + ASSERT(!bigInt->IsZero()); + ASSERT(maxLen >= bigInt->GetLength()); + + JSHandle newBigInt = BigInt::CreateBigInt(thread, maxLen); + + uint32_t bigIntLen = bigInt->GetLength(); + uint32_t carry = 1; + for (uint32_t i = 0; i < bigIntLen; i++) { + uint32_t bigIntCarry = 0; + BigInt::SetDigit(thread, newBigInt, i, BigIntHelper::SubHelper(bigInt->GetDigit(i), carry, bigIntCarry)); + carry = bigIntCarry; + } + ASSERT(!carry); + for (uint32_t i = bigIntLen; i < maxLen; i++) { + BigInt::SetDigit(thread, newBigInt, i, carry); + } + return BigIntHelper::RightTruncate(thread, newBigInt); +} + +JSHandle BigInt::BitwiseAddOne(JSThread *thread, JSHandle bigInt) +{ + uint32_t bigIntLength = bigInt->GetLength(); + + bool needExpend = true; + for (uint32_t i = 0; i < bigIntLength; i++) { + if (std::numeric_limits::max() != bigInt->GetDigit(i)) { + needExpend = false; + break; + } + } + uint32_t newLength = bigIntLength; + if (needExpend) { + newLength += 1; + } + JSHandle newBigInt = BigInt::CreateBigInt(thread, newLength); + + uint32_t carry = 1; + for (uint32_t i = 0; i < bigIntLength; i++) { + uint32_t bigIntCarry = 0; + BigInt::SetDigit(thread, newBigInt, i, BigIntHelper::AddHelper(bigInt->GetDigit(i), carry, bigIntCarry)); + carry = bigIntCarry; + } + if (needExpend) { + BigInt::SetDigit(thread, newBigInt, bigIntLength, carry); + } else { + ASSERT(!carry); + } + newBigInt->SetSign(true); + return BigIntHelper::RightTruncate(thread, newBigInt); +} + +JSHandle OneIsNegativeOR(JSThread *thread, JSHandle x, JSHandle y) +{ + uint32_t xLength = x->GetLength(); + uint32_t maxLen = xLength; + if (maxLen < y->GetLength()) { + maxLen = y->GetLength(); + } + JSHandle yVal = BigInt::BitwiseSubOne(thread, y, maxLen); + uint32_t yLength = yVal->GetLength(); + uint32_t minLen = xLength; + if (minLen > yLength) { + minLen = yLength; + } + JSHandle newBigInt = BigInt::CreateBigInt(thread, yLength); + uint32_t i = 0; + while (i < minLen) { + uint32_t res = ~(x->GetDigit(i)) & yVal->GetDigit(i); + BigInt::SetDigit(thread, newBigInt, i, res); + ++i; + } + while (i < yLength) { + BigInt::SetDigit(thread, newBigInt, i, yVal->GetDigit(i)); + ++i; + } + JSHandle temp = BigIntHelper::RightTruncate(thread, newBigInt); + JSHandle res = BigInt::BitwiseAddOne(thread, temp); + res->SetSign(true); + return res; +} + +// 6.1.6.2.22 BigInt::bitwiseOR ( x, y ) +JSHandle BigInt::BitwiseOR(JSThread *thread, JSHandle x, JSHandle y) +{ + if (x->GetSign() && y->GetSign()) { + // (-x) | (-y) == -(((x-1) & (y-1)) + 1) + uint32_t maxLen = x->GetLength(); + uint32_t yLen = y->GetLength(); + maxLen < yLen ? maxLen = yLen : 0; + JSHandle xVal = BitwiseSubOne(thread, x, maxLen); + JSHandle yVal = BitwiseSubOne(thread, y, yLen); + JSHandle temp = BitwiseOp(thread, Operate::AND, xVal, yVal); + JSHandle res = BitwiseAddOne(thread, temp); + res->SetSign(true); + return res; + } + if (x->GetSign() != y->GetSign()) { + // x | (-y) == -(((y-1) & ~x) + 1) + if (!x->GetSign()) { + return OneIsNegativeOR(thread, x, y); + } + return OneIsNegativeOR(thread, y, x); + } + return BitwiseOp(thread, Operate::OR, x, y); +} + +// 6.1.6.2.23 BigInt::toString ( x ) +JSHandle BigInt::ToString(JSThread *thread, JSHandle bigInt, uint32_t conversionToRadix) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + std::string result = bigInt->ToStdString(thread, conversionToRadix); + return factory->NewFromStdString(result); +} + +std::string BigInt::ToStdString(JSThread *thread, uint32_t conversionToRadix) const +{ + JSHandle thisHandle(thread, JSTaggedValue(this)); + std::string result = BigIntHelper::Conversion(BigIntHelper::GetBinary(thisHandle), conversionToRadix, BINARY); + if (GetSign()) { + result = "-" + result; + } + return result; +} + +JSTaggedValue BigInt::NumberToBigInt(JSThread *thread, JSHandle number) +{ + if (!number->IsInteger()) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The number cannot be converted to a BigInt because it is not an integer", + JSTaggedValue::Exception()); + } + double num = number->GetNumber(); + if (num == 0.0) { + return Int32ToBigInt(thread, 0).GetTaggedValue(); + } + + // Bit operations must be of integer type + uint64_t bits = 0; + if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) { + LOG_ECMA(FATAL) << "memcpy_s failed"; + UNREACHABLE(); + } + // Take out bits 62-52 (11 bits in total) and subtract 1023 + // NOLINTNEXTLINE(readability-magic-numbers) + uint64_t integerDigits = ((bits >> base::DOUBLE_SIGNIFICAND_SIZE) & 0x7FFU) - base::DOUBLE_EXPONENT_BIAS; + uint32_t mayNeedLen = integerDigits / BigInt::DATEBITS + 1; + + JSHandle bigInt = CreateBigInt(thread, mayNeedLen); + bigInt->SetSign(num < 0); + uint64_t mantissa = (bits & base::DOUBLE_SIGNIFICAND_MASK) | base::DOUBLE_HIDDEN_BIT; + int mantissaSize = base::DOUBLE_SIGNIFICAND_SIZE; + + uint32_t leftover = 0; + bool isFirstInto = true; + for (int index = static_cast(mayNeedLen - 1); index >= 0; --index) { + uint32_t doubleNum = 0; + if (isFirstInto) { + isFirstInto = false; + leftover = mantissaSize - static_cast(integerDigits % BigInt::DATEBITS); + doubleNum = static_cast(mantissa >> leftover); + mantissa = mantissa << (64U - leftover); // NOLINT(readability-magic-numbers) 64 : double bits size + BigInt::SetDigit(thread, bigInt, index, doubleNum); + } else { + leftover -= BigInt::DATEBITS; + doubleNum = static_cast(mantissa >> BigInt::DATEBITS); + mantissa = mantissa << BigInt::DATEBITS; + BigInt::SetDigit(thread, bigInt, index, doubleNum); + } + } + return BigIntHelper::RightTruncate(thread, bigInt).GetTaggedValue(); +} + +JSHandle BigInt::Int32ToBigInt(JSThread *thread, const int &number) +{ + JSHandle bigInt = CreateBigInt(thread, 1); + uint32_t value = 0; + bool sign = number < 0; + if (sign) { + value = static_cast(-(number + 1)) + 1; + } else { + value = number; + } + BigInt::SetDigit(thread, bigInt, 0, value); + bigInt->SetSign(sign); + return bigInt; +} + +JSHandle BigInt::Int64ToBigInt(JSThread *thread, const int64_t &number) +{ + JSHandle bigInt = CreateBigInt(thread, 2); // 2 : one int64_t bits need two uint32_t bits + uint64_t value = 0; + bool sign = number < 0; + if (sign) { + value = static_cast(-(number + 1)) + 1; + } else { + value = number; + } + auto *addr = reinterpret_cast(&value); + BigInt::SetDigit(thread, bigInt, 0, *(addr)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + BigInt::SetDigit(thread, bigInt, 1, *(addr + 1)); + bigInt->SetSign(sign); + return BigIntHelper::RightTruncate(thread, bigInt); +} + +JSHandle BigInt::Uint64ToBigInt(JSThread *thread, const uint64_t &number) +{ + JSHandle bigInt = CreateBigInt(thread, 2); // 2 : one int64_t bits need two uint32_t bits + const auto *addr = reinterpret_cast(&number); + BigInt::SetDigit(thread, bigInt, 0, *(addr)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + BigInt::SetDigit(thread, bigInt, 1, *(addr + 1)); + return BigIntHelper::RightTruncate(thread, bigInt); +} + +void BigInt::BigIntToInt64(JSThread *thread, JSHandle bigInt, int64_t *cValue, bool *lossless) +{ + ASSERT(cValue != nullptr); + ASSERT(lossless != nullptr); + JSHandle bigInt64(thread, JSTaggedValue::ToBigInt64(thread, bigInt)); + RETURN_IF_ABRUPT_COMPLETION(thread); + if (Equal(thread, bigInt64.GetTaggedValue(), bigInt.GetTaggedValue())) { + *lossless = true; + } + auto *addr = reinterpret_cast(cValue); + auto len = static_cast(bigInt64->GetLength()); + for (int index = len - 1; index >= 0; --index) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + *(addr + index) = bigInt64->GetDigit(index); + } + if (bigInt64->GetSign()) { + *cValue = ~(static_cast(static_cast(*cValue - 1))); + } +} + +void BigInt::BigIntToUint64(JSThread *thread, JSHandle bigInt, uint64_t *cValue, bool *lossless) +{ + ASSERT(cValue != nullptr); + ASSERT(lossless != nullptr); + JSHandle bigUint64(thread, JSTaggedValue::ToBigUint64(thread, bigInt)); + RETURN_IF_ABRUPT_COMPLETION(thread); + if (Equal(thread, bigUint64.GetTaggedValue(), bigInt.GetTaggedValue())) { + *lossless = true; + } + auto *addr = reinterpret_cast(cValue); + auto len = static_cast(bigUint64->GetLength()); + for (int index = len - 1; index >= 0; --index) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + *(addr + index) = bigUint64->GetDigit(index); + } +} + +JSHandle BigInt::CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t *words) +{ + ASSERT(words != nullptr); + uint32_t needLen = size * 2; // 2 : uint64_t size to uint32_t size + JSHandle bigInt = CreateBigInt(thread, needLen); + const auto *digits = reinterpret_cast(words); + for (uint32_t index = 0; index < needLen; ++index) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + SetDigit(thread, bigInt, index, *(digits + index)); + } + bigInt->SetSign(sign); + return BigIntHelper::RightTruncate(thread, bigInt); +} + +JSHandle BigInt::Add(JSThread *thread, JSHandle x, JSHandle y) +{ + bool xSignFlag = x->GetSign(); + bool ySignFlag = y->GetSign(); + // x + y == x + y + // -x + -y == -(x + y) + if (xSignFlag == ySignFlag) { + return BigIntAdd(thread, x, y, xSignFlag); + } + // x + -y == x - y == -(y - x) + // -x + y == y - x == -(x - y) + uint32_t xLength = x->GetLength(); + uint32_t yLength = y->GetLength(); + uint32_t i = xLength - 1; + auto subSize = static_cast(xLength - yLength); + if (subSize > 0) { + return BigIntSub(thread, x, y, xSignFlag); + } + + if (subSize == 0) { + while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) { + i--; + } + if ((x->GetDigit(i) > y->GetDigit(i))) { + return BigIntSub(thread, x, y, xSignFlag); + } + + return BigIntSub(thread, y, x, ySignFlag); + } + + return BigIntSub(thread, y, x, ySignFlag); +} +JSHandle BigInt::Subtract(JSThread *thread, JSHandle x, JSHandle y) +{ + bool xSignFlag = x->GetSign(); + bool ySignFlag = y->GetSign(); + if (xSignFlag != ySignFlag) { + // x - (-y) == x + y + // (-x) - y == -(x + y) + return BigIntAdd(thread, x, y, xSignFlag); + } + // x - y == -(y - x) + // (-x) - (-y) == y - x == -(x - y) + uint32_t xLength = x->GetLength(); + uint32_t yLength = y->GetLength(); + uint32_t i = xLength - 1; + auto subSize = static_cast(xLength - yLength); + if (subSize > 0) { + return BigIntSub(thread, x, y, xSignFlag); + } + + if (subSize == 0) { + while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) { + i--; + } + + if ((x->GetDigit(i) > y->GetDigit(i))) { + return BigIntSub(thread, x, y, xSignFlag); + } + + return BigIntSub(thread, y, x, !ySignFlag); + } + + return BigIntSub(thread, y, x, !ySignFlag); +} + +JSHandle BigInt::BigIntAdd(JSThread *thread, JSHandle x, JSHandle y, bool resultSign) +{ + if (x->GetLength() < y->GetLength()) { + return BigIntAdd(thread, y, x, resultSign); + } + JSHandle bigInt = BigInt::CreateBigInt(thread, x->GetLength() + 1); + uint32_t bigIntCarry = 0; + uint32_t i = 0; + while (i < y->GetLength()) { + uint32_t newBigIntCarry = 0; + uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), y->GetDigit(i), newBigIntCarry); + addPlus = BigIntHelper::AddHelper(addPlus, bigIntCarry, newBigIntCarry); + SetDigit(thread, bigInt, i, addPlus); + bigIntCarry = newBigIntCarry; + i++; + } + while (i < x->GetLength()) { + uint32_t newBigIntCarry = 0; + uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), bigIntCarry, newBigIntCarry); + SetDigit(thread, bigInt, i, addPlus); + bigIntCarry = newBigIntCarry; + i++; + } + SetDigit(thread, bigInt, i, bigIntCarry); + bigInt->SetSign(resultSign); + return BigIntHelper::RightTruncate(thread, bigInt); +} + +inline uint32_t BigIntHelper::AddHelper(uint32_t x, uint32_t y, uint32_t &bigIntCarry) +{ + uint32_t addPlus = x + y; + if (addPlus < x) { + bigIntCarry += 1; + } + return addPlus; +} + +JSHandle BigInt::BigIntSub(JSThread *thread, JSHandle x, JSHandle y, bool resultSign) +{ + JSHandle bigInt = BigInt::CreateBigInt(thread, x->GetLength()); + uint32_t bigIntCarry = 0; + uint32_t i = 0; + while (i < y->GetLength()) { + uint32_t newBigIntCarry = 0; + uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), y->GetDigit(i), newBigIntCarry); + minuSub = BigIntHelper::SubHelper(minuSub, bigIntCarry, newBigIntCarry); + SetDigit(thread, bigInt, i, minuSub); + bigIntCarry = newBigIntCarry; + i++; + } + while (i < x->GetLength()) { + uint32_t newBigIntCarry = 0; + uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), bigIntCarry, newBigIntCarry); + SetDigit(thread, bigInt, i, minuSub); + bigIntCarry = newBigIntCarry; + i++; + } + bigInt->SetSign(resultSign); + return BigIntHelper::RightTruncate(thread, bigInt); +} + +JSHandle BigInt::BigIntAddOne(JSThread *thread, JSHandle x) +{ + JSHandle temp = Int32ToBigInt(thread, 1); + return Add(thread, x, temp); +} + +JSHandle BigInt::BigIntSubOne(JSThread *thread, JSHandle x) +{ + JSHandle temp = Int32ToBigInt(thread, 1); + return Subtract(thread, x, temp); +} + +inline uint32_t BigIntHelper::SubHelper(uint32_t x, uint32_t y, uint32_t &bigIntCarry) +{ + uint32_t minuSub = x - y; + if (minuSub > x) { + bigIntCarry += 1; + } + return minuSub; +} + +ComparisonResult BigInt::Compare(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y) +{ + if (!LessThan(thread, x, y)) { + if (!LessThan(thread, y, x)) { + return ComparisonResult::EQUAL; + } + return ComparisonResult::GREAT; + } + return ComparisonResult::LESS; +} + +bool BigInt::LessThan(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y) +{ + [[maybe_unused]] EcmaHandleScope scope(thread); + JSHandle xHandle(thread, x); + JSHandle yHandle(thread, y); + return LessThan(xHandle, yHandle); +} + +bool BigInt::LessThan(const JSHandle &x, const JSHandle &y) +{ + bool xSignFlag = x->GetSign(); + bool ySignFlag = y->GetSign(); + auto minSize = static_cast(x->GetLength() - y->GetLength()); + uint32_t i = x->GetLength() - 1; + if (xSignFlag != ySignFlag) { + return xSignFlag; + } + if (minSize != 0 && xSignFlag) { + return minSize > 0; + } + if (minSize != 0 && !xSignFlag) { + return minSize <= 0; + } + while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) { + i--; + } + if ((x->GetDigit(i) > y->GetDigit(i))) { + return xSignFlag; + } + if ((x->GetDigit(i) < y->GetDigit(i))) { + return !xSignFlag; + } + return false; +} + +JSHandle BigInt::SignedRightShift(JSThread *thread, JSHandle x, JSHandle y) +{ + bool xIsNull = (x->GetDigit(0) == 0U); + bool yIsNull = (y->GetDigit(0) == 0U); + if (xIsNull || yIsNull) { + return x; + } + if (y->GetSign()) { + return LeftShiftHelper(thread, x, y); + } + return RightShiftHelper(thread, x, y); +} + +JSHandle BigInt::RightShiftHelper(JSThread *thread, JSHandle x, JSHandle y) +{ + std::string shiftBinay = BigIntHelper::GetBinary(x); + std::string revTemp = std::string(shiftBinay.rbegin(), shiftBinay.rend()); + for (uint32_t i = 0; i < y->GetLength(); i++) { + revTemp = revTemp.erase(0, y->GetDigit(i)); + } + std::string finalBinay = std::string(revTemp.rbegin(), revTemp.rend()); + if (finalBinay.empty()) { + finalBinay = "0"; + } + JSHandle BigInt = BigIntHelper::SetBigInt(thread, finalBinay, BINARY); + if (x->GetSign()) { + SetDigit(thread, BigInt, 0, BigInt->GetDigit(0) + 1); + } + BigInt->SetSign(x->GetSign()); + return BigIntHelper::RightTruncate(thread, BigInt); +} + +JSHandle BigInt::LeftShift(JSThread *thread, JSHandle x, JSHandle y) +{ + if (y->GetSign()) { + return RightShiftHelper(thread, x, y); + } + return LeftShiftHelper(thread, x, y); +} + +JSHandle BigInt::LeftShiftHelper(JSThread *thread, JSHandle x, JSHandle y) +{ + std::string shiftBinary = BigIntHelper::GetBinary(x); + for (size_t i = 0; i < y->GetLength(); i++) { + shiftBinary = shiftBinary.append(y->GetDigit(i), '0'); + } + JSHandle bigInt = BigIntHelper::SetBigInt(thread, shiftBinary, BINARY); + bigInt->SetSign(x->GetSign()); + return BigIntHelper::RightTruncate(thread, bigInt); +} + +JSHandle BigInt::UnsignedRightShift(JSThread *thread, [[maybe_unused]] JSHandle x, + [[maybe_unused]] JSHandle y) +{ + [[maybe_unused]] EcmaHandleScope scope(thread); + JSHandle exception(thread, JSTaggedValue::Exception()); + THROW_TYPE_ERROR_AND_RETURN(thread, "BigInt have no unsigned right shift, use >> instead", exception); +} + +JSHandle BigInt::Copy(JSThread *thread, JSHandle x) +{ + uint32_t len = x->GetLength(); + JSHandle temp = CreateBigInt(thread, len); + for (uint32_t i = 0; i < len; i++) { + SetDigit(thread, temp, i, x->GetDigit(i)); + } + temp->SetSign(x->GetSign()); + return temp; +} + +JSHandle BigInt::UnaryMinus(JSThread *thread, JSHandle x) +{ + if (x->IsZero()) { + return x; + } + JSHandle y = Copy(thread, x); + y->SetSign(!y->GetSign()); + return y; +} + +// 6.1.6.2.2 BigInt::bitwiseNOT ( x ) +JSHandle BigInt::BitwiseNOT(JSThread *thread, JSHandle x) +{ + // ~(-x) == ~(~(x-1)) == x-1 + // ~x == -x-1 == -(x+1) + JSHandle result = BigIntAddOne(thread, x); + if (x->GetSign()) { + result->SetSign(false); + } else { + result->SetSign(true); + } + return result; +} + +JSHandle BigInt::Exponentiate(JSThread *thread, JSHandle base, JSHandle exponent) +{ + if (exponent->GetSign()) { + JSHandle BigInt(thread, JSTaggedValue::Exception()); + THROW_RANGE_ERROR_AND_RETURN(thread, "Exponent must be positive", BigInt); + } + ASSERT(exponent->GetLength() == 1); + if (exponent->IsZero()) { + return BigIntHelper::SetBigInt(thread, "1"); + } + + if (base->IsZero()) { + return BigIntHelper::SetBigInt(thread, "0"); + } + uint32_t eValue = exponent->GetDigit(0); + if (eValue == 1) { + return base; + } + uint32_t j = exponent->GetDigit(0) - 1; + std::string a = BigIntHelper::GetBinary(base); + a = BigIntHelper::Conversion(a, DECIMAL, BINARY); + std::string b = a; + for (uint32_t i = 0; i < j; ++i) { + b = BigIntHelper::MultiplyImpl(b, a); + } + if ((exponent->GetDigit(0) & 1U) != 0U) { + if (base->GetSign()) { + b = "-" + b; + } + } + return BigIntHelper::SetBigInt(thread, b, DECIMAL); +} + +std::string BigIntHelper::MultiplyImpl(std::string &a, std::string &b) +{ + auto size1 = static_cast(a.size()); + auto size2 = static_cast(b.size()); + std::string str(size1 + size2, '0'); + for (int i = size2 - 1; i >= 0; --i) { + int mulflag = 0; + int addflag = 0; + for (int j = size1 - 1; j >= 0; --j) { + int temp1 = (b[i] - '0') * (a[j] - '0') + mulflag; + // NOLINTNEXTLINE(readability-magic-numbers) + mulflag = temp1 / 10; // 10:help to Remove single digits + // NOLINTNEXTLINE(readability-magic-numbers) + temp1 = temp1 % 10; // 10:help to Take single digit + int temp2 = str[i + j + 1] - '0' + temp1 + addflag; + // NOLINTNEXTLINE(readability-magic-numbers) + str[i + j + 1] = static_cast(temp2 % 10 + '0'); // 2 and 10 and 48 is number + // NOLINTNEXTLINE(readability-magic-numbers) + addflag = temp2 / 10; + } + str[i] += static_cast(mulflag + addflag); + } + if (str[0] == '0') { + str = str.substr(1, str.size()); + } + return str; +} + +JSHandle BigInt::Multiply(JSThread *thread, JSHandle x, JSHandle y) +{ + if (x->IsZero()) { + return x; + } + if (y->IsZero()) { + return y; + } + std::string left = BigIntHelper::GetBinary(x); + std::string right = BigIntHelper::GetBinary(y); + left = BigIntHelper::Conversion(left, DECIMAL, BINARY); + right = BigIntHelper::Conversion(right, DECIMAL, BINARY); + std::string ab = BigIntHelper::MultiplyImpl(left, right); + if (x->GetSign() != y->GetSign()) { + ab = "-" + ab; + } + return BigIntHelper::SetBigInt(thread, ab, DECIMAL); +} + +std::string BigIntHelper::DeZero(std::string &a) +{ + size_t i; + for (i = 0; i < a.length(); i++) { + // NOLINTNEXTLINE(readability-magic-numbers) + if (a.at(i) > 48) { // 48 is ascill of '0' + break; + } + } + if (i == a.length()) { + return "0"; + } + a.erase(0, i); + return a; +} + +Comparestr BigInt::ComString(std::string &a, std::string &b) +{ + if (a.length() > b.length()) { + return Comparestr::GREATER; + } + if (a.length() < b.length()) { + return Comparestr::LESS; + } + for (size_t i = 0; i < a.length(); i++) { + if (a.at(i) > b.at(i)) { + return Comparestr::GREATER; + } + if (a.at(i) < b.at(i)) { + return Comparestr::LESS; + } + } + return Comparestr::EQUAL; +} + +std::string BigIntHelper::DevStr(std::string &strValue) +{ + size_t i = 0; + for (i = 0; i < strValue.length(); i++) { + // NOLINTNEXTLINE(readability-magic-numbers) + if (strValue.at(i) >= 48 && strValue.at(i) <= 57) { // 48 and 57 is '0' and '9' + // NOLINTNEXTLINE(readability-magic-numbers) + strValue.at(i) -= 48; // 48:'0' + } + // NOLINTNEXTLINE(readability-magic-numbers) + if (strValue.at(i) >= 97 && strValue.at(i) <= 122) { // 97 and 122 is 'a' and 'z' + // NOLINTNEXTLINE(readability-magic-numbers) + strValue.at(i) -= 87; // 87 control result is greater than 10 + } + } + return strValue; +} + +std::string BigIntHelper::Minus(std::string &a, std::string &b) +{ + a = DeZero(a); + b = DeZero(b); + size_t i = 0; + int j = 0; + std::string res = "0"; + std::string result1; + std::string result2; + std::string dsymbol = "-"; + if (BigInt::ComString(a, b) == Comparestr::EQUAL) { + return res; + } + if (BigInt::ComString(a, b) == Comparestr::GREATER) { + result1 = a; + result2 = b; + } + if (BigInt::ComString(a, b) == Comparestr::LESS) { + result1 = b; + result2 = a; + j = -1; + } + reverse(result1.begin(), result1.end()); + reverse(result2.begin(), result2.end()); + result1 = DevStr(result1); + result2 = DevStr(result2); + for (i = 0; i < result2.length(); i++) { + result1.at(i) = result1.at(i) - result2.at(i); + } + for (i = 0; i < result1.length() - 1; i++) { + if (((int8_t)result1.at(i)) < 0) { + result1.at(i) += BigInt::DECIMAL; + result1.at(i + 1)--; + } + } + for (i = result1.length() - 1; i != 0; i--) { + if (result1.at(i) > 0) { + break; + } + } + result1.erase(i + 1, result1.length()); + for (i = 0; i < result1.length(); i++) { + // NOLINTNEXTLINE(readability-magic-numbers) + if (result1.at(i) >= 10) { // 10:Hexadecimal a + // NOLINTNEXTLINE(readability-magic-numbers) + result1.at(i) += 87; // 87:control result is greater than 97 + } + // NOLINTNEXTLINE(readability-magic-numbers) + if (result1.at(i) < 10) { // 10: 10:Hexadecimal a + // NOLINTNEXTLINE(readability-magic-numbers) + result1.at(i) += 48; // 48:'0' + } + } + reverse(result1.begin(), result1.end()); + if (j == -1) { + result1.insert(0, dsymbol); + } + return result1; +} + +std::string BigIntHelper::Divide(std::string &a, std::string &b) +{ + size_t i = 0; + size_t j = 0; + std::string result1; + std::string result2; + std::string dsy; + std::string quotient; + if (BigInt::ComString(a, b) == Comparestr::EQUAL) { + return "1"; + } + if (BigInt::ComString(a, b) == Comparestr::LESS) { + return "0"; + } + result1 = DeZero(a); + result2 = DeZero(b); + dsy = ""; + quotient = ""; + for (i = 0; i < result1.length(); i++) { + j = 0; + dsy += result1.at(i); + dsy = DeZero(dsy); + while (BigInt::ComString(dsy, b) == Comparestr::EQUAL || BigInt::ComString(dsy, b) == Comparestr::GREATER) { + dsy = Minus(dsy, b); + dsy = DeZero(dsy); + j++; + } + quotient += "0"; + quotient.at(i) = static_cast(j); + } + for (i = 0; i < quotient.length(); i++) { + // NOLINTNEXTLINE(readability-magic-numbers) + if (quotient.at(i) >= 10) { // 10 is number + // NOLINTNEXTLINE(readability-magic-numbers) + quotient.at(i) += 87; // 87 is number + } + // NOLINTNEXTLINE(readability-magic-numbers) + if (quotient.at(i) < 10) { // 10 is number + // NOLINTNEXTLINE(readability-magic-numbers) + quotient.at(i) += 48; // 48 is number + } + } + quotient = DeZero(quotient); + return quotient; +} + +JSHandle BigIntHelper::DivideImpl(JSThread *thread, JSHandle x, JSHandle y) +{ + std::string a = Conversion(GetBinary(x), BigInt::DECIMAL, BigInt::BINARY); + std::string b = Conversion(GetBinary(y), BigInt::DECIMAL, BigInt::BINARY); + std::string ab = Divide(a, b); + if (ab == "0") { + ab = "0"; + } else if (x->GetSign() != y->GetSign()) { + ab = "-" + ab; + } + return SetBigInt(thread, ab, BigInt::DECIMAL); +} + +JSHandle BigInt::Divide(JSThread *thread, JSHandle x, JSHandle y) +{ + if (y->IsZero()) { + JSHandle BigInt(thread, JSTaggedValue::Exception()); + THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", BigInt); + } + return BigIntHelper::DivideImpl(thread, x, y); +} + +JSHandle BigInt::Remainder(JSThread *thread, JSHandle n, JSHandle d) +{ + if (d->IsZero()) { + JSHandle BigInt(thread, JSTaggedValue::Exception()); + THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", BigInt); + } + if (n->IsZero()) { + return n; + } + JSHandle q = Divide(thread, n, d); + JSHandle p = Multiply(thread, q, d); + return Subtract(thread, n, p); +} + +JSHandle BigInt::FloorMod(JSThread *thread, JSHandle leftVal, JSHandle rightVal) +{ + if (leftVal->GetSign()) { + JSHandle quotientVal = Divide(thread, leftVal, rightVal); + if (quotientVal->IsZero()) { + return Add(thread, leftVal, rightVal); + } + JSHandle num = Multiply(thread, quotientVal, rightVal); + if (Equal(num, leftVal)) { + return Int32ToBigInt(thread, 0); + } + return Subtract(thread, leftVal, Subtract(thread, num, rightVal)); + } + return Remainder(thread, leftVal, rightVal); +} + +JSTaggedValue BigInt::AsUintN(JSThread *thread, JSTaggedNumber &bits, JSHandle bigInt) +{ + uint32_t bit = bits.ToUint32(); + if (bit == 0) { + return Int32ToBigInt(thread, 0).GetTaggedValue(); + } + if (bigInt->IsZero()) { + return bigInt.GetTaggedValue(); + } + JSHandle exponent = Int32ToBigInt(thread, bit); + JSHandle base = Int32ToBigInt(thread, 2); // 2 : base value + JSHandle tValue = Exponentiate(thread, base, exponent); + return FloorMod(thread, bigInt, tValue).GetTaggedValue(); +} + +JSTaggedValue BigInt::AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle bigInt) +{ + uint32_t bit = bits.ToUint32(); + if (bit == 0) { + return Int32ToBigInt(thread, 0).GetTaggedValue(); + } + if (bigInt->IsZero()) { + return bigInt.GetTaggedValue(); + } + JSHandle exp = Int32ToBigInt(thread, bit); + JSHandle exponent = Int32ToBigInt(thread, static_cast(bit - 1)); + JSHandle base = Int32ToBigInt(thread, 2); // 2 : base value + JSHandle tValue = Exponentiate(thread, base, exp); + JSHandle modValue = FloorMod(thread, bigInt, tValue); + JSHandle resValue = Exponentiate(thread, base, exponent); + // If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return (mod). + if (LessThan(resValue, modValue) || Equal(resValue, modValue)) { + return Subtract(thread, modValue, tValue).GetTaggedValue(); + } + return modValue.GetTaggedValue(); +} + +static JSTaggedNumber CalculateNumber(const uint64_t &sign, const uint64_t &mantissa, uint64_t &exponent) +{ + exponent = (exponent + base::DOUBLE_EXPONENT_BIAS) << base::DOUBLE_SIGNIFICAND_SIZE; + uint64_t doubleBit = sign | exponent | mantissa; + double res = 0; + if (memcpy_s(&res, sizeof(res), &doubleBit, sizeof(doubleBit)) != EOK) { + LOG_ECMA(FATAL) << "memcpy_s failed"; + UNREACHABLE(); + } + return JSTaggedNumber(res); +} + +static JSTaggedNumber Rounding(const uint64_t &sign, uint64_t &mantissa, uint64_t &exponent, bool needRound) +{ + if (needRound || (mantissa & 1U) == 1U) { + ++mantissa; + if ((mantissa >> base::DOUBLE_SIGNIFICAND_SIZE) != 0) { + mantissa = 0; + exponent++; + if (exponent > base::DOUBLE_EXPONENT_BIAS) { + return JSTaggedNumber(sign != 0U ? -base::POSITIVE_INFINITY : base::POSITIVE_INFINITY); + } + } + } + return CalculateNumber(sign, mantissa, exponent); +} + +JSTaggedNumber BigInt::BigIntToNumber(JSHandle bigInt) +{ + if (bigInt->IsZero()) { + return JSTaggedNumber(0); + } + uint32_t bigIntLen = bigInt->GetLength(); + uint32_t bigIntHead = bigInt->GetDigit(bigIntLen - 1); + uint32_t bits = BigInt::DATEBITS; + uint32_t preZero = 0; + while (bits-- != 0U) { + if (((bigIntHead >> bits) | 0U) != 0) { + break; + } + preZero++; + } + uint32_t bigIntBitLen = bigIntLen * BigInt::DATEBITS - preZero; + // if Significant bits greater than 1024 then double is infinity + bool bigIntSign = bigInt->GetSign(); + if (bigIntBitLen > (base::DOUBLE_EXPONENT_BIAS + 1)) { + return JSTaggedNumber(bigIntSign ? -base::POSITIVE_INFINITY : base::POSITIVE_INFINITY); + } + // NOLINTNEXTLINE(readability-magic-numbers) + uint64_t sign = bigIntSign ? 1ULL << 63ULL : 0; // 63 : Set the sign bit of sign to 1 + uint32_t needMoveBit = preZero + BigInt::DATEBITS + 1; + // Align to the most significant bit, then right shift 12 bits so that the head of the mantissa is in place + // NOLINTNEXTLINE(readability-magic-numbers) + auto mantissa = (static_cast(bigIntHead) << needMoveBit) >> 12ULL; // 12 mantissa just has 52 bits + auto remainMantissaBits = static_cast(needMoveBit - 12); // NOLINT(readability-magic-numbers) + auto exponent = static_cast(bigIntBitLen - 1); + auto index = static_cast(bigIntLen - 1); + uint32_t digit = 0; + if (index > 0) { + digit = bigInt->GetDigit(--index); + } else { + return CalculateNumber(sign, mantissa, exponent); + } + // pad unset mantissa + if (static_cast(remainMantissaBits) >= BigInt::DATEBITS) { + mantissa |= (static_cast(digit) << (remainMantissaBits - BigInt::DATEBITS)); + remainMantissaBits -= BigInt::DATEBITS; + index--; + } + if (remainMantissaBits > 0 && index >= 0) { + digit = bigInt->GetDigit(index); + mantissa |= (static_cast(digit) >> (BigInt::DATEBITS - remainMantissaBits)); + remainMantissaBits -= BigInt::DATEBITS; + } + // After the mantissa is filled, if the bits of BigInt have not been used up, consider the rounding problem + // The remaining bits of the current digit + int remainDigitBits = 1; + if (remainMantissaBits < 0) { + remainDigitBits = -remainMantissaBits; + } + if (remainMantissaBits == 0) { + if (index == 0) { + return CalculateNumber(sign, mantissa, exponent); + } + digit = bigInt->GetDigit(index--); + remainDigitBits = BigInt::DATEBITS; + } + uint32_t temp = 1ULL << (remainDigitBits - 1); // NOLINT(hicpp-signed-bitwise) + if ((digit & temp) == 0U) { + return CalculateNumber(sign, mantissa, exponent); + } + if ((digit & (temp - 1)) != 0) { + return Rounding(sign, mantissa, exponent, true); + } + while (index > 0) { + if (bigInt->GetDigit(index--) != 0) { + return Rounding(sign, mantissa, exponent, true); + } + } + return Rounding(sign, mantissa, exponent, false); +} + +static int CompareToBitsLen(JSHandle bigInt, uint32_t numBitLen, uint32_t &preZero) +{ + uint32_t bigIntLen = bigInt->GetLength(); + uint32_t bigIntHead = bigInt->GetDigit(bigIntLen - 1); + uint32_t bits = BigInt::DATEBITS; + while (bits != 0U) { + bits--; + if (((bigIntHead >> bits) | 0U) != 0) { + break; + } + preZero++; + } + + uint32_t bigIntBitLen = bigIntLen * BigInt::DATEBITS - preZero; + bool bigIntSign = bigInt->GetSign(); + if (bigIntBitLen > numBitLen) { + return bigIntSign ? 0 : 1; + } + + if (bigIntBitLen < numBitLen) { + return bigIntSign ? 1 : 0; + } + return -1; +} + +ComparisonResult BigInt::CompareWithNumber(JSHandle bigInt, JSHandle number) +{ + double num = number->GetNumber(); + bool numberSign = num < 0; + if (std::isnan(num)) { + return ComparisonResult::UNDEFINED; + } + if (!std::isfinite(num)) { + return (!numberSign ? ComparisonResult::LESS : ComparisonResult::GREAT); + } + // Bit operations must be of integer type + uint64_t bits = 0; + if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) { + LOG_ECMA(FATAL) << "memcpy_s failed"; + UNREACHABLE(); + } + uint32_t exponential = (bits >> base::DOUBLE_SIGNIFICAND_SIZE) & 0x7FFU; // NOLINT(readability-magic-numbers) + + // Take out bits 62-52 (11 bits in total) and subtract 1023 + auto integerDigits = static_cast(exponential - base::DOUBLE_EXPONENT_BIAS); + uint64_t mantissa = (bits & base::DOUBLE_SIGNIFICAND_MASK) | base::DOUBLE_HIDDEN_BIT; + bool bigIntSign = bigInt->GetSign(); + // Handling the opposite sign + if (!numberSign && bigIntSign) { + return ComparisonResult::LESS; + } + if (numberSign && !bigIntSign) { + return ComparisonResult::GREAT; + } + if (bigInt->IsZero() && num == 0.0) { + return ComparisonResult::EQUAL; + } + if (bigInt->IsZero() && num > 0) { + return ComparisonResult::LESS; + } + + if (integerDigits < 0) { + return bigIntSign ? ComparisonResult::LESS : ComparisonResult::GREAT; + } + + // Compare the significant bits of BigInt with the significant integer bits of double + uint32_t preZero = 0; + int res = CompareToBitsLen(bigInt, integerDigits + 1, preZero); + if (res == 0) { + return ComparisonResult::LESS; + } + if (res == 1) { + return ComparisonResult::GREAT; + } + int mantissaSize = base::DOUBLE_SIGNIFICAND_SIZE; // mantissaSize + uint32_t BigIntLen = bigInt->GetLength(); + uint32_t leftover = 0; + bool isFirstInto = true; + for (int index = static_cast(BigIntLen - 1); index >= 0; --index) { + uint32_t doubleNum = 0; + uint32_t BigIntNum = bigInt->GetDigit(index); + if (isFirstInto) { + isFirstInto = false; + leftover = mantissaSize - BigInt::DATEBITS + preZero + 1; + doubleNum = static_cast(mantissa >> leftover); + mantissa = mantissa << (64U - leftover); // NOLINT(readability-magic-numbers) 64 : double bits + if (BigIntNum > doubleNum) { + return bigIntSign ? ComparisonResult::LESS : ComparisonResult::GREAT; + } + if (BigIntNum < doubleNum) { + return bigIntSign ? ComparisonResult::GREAT : ComparisonResult::LESS; + } + } else { + leftover -= BigInt::DATEBITS; + doubleNum = static_cast(mantissa >> BigInt::DATEBITS); + mantissa = mantissa << BigInt::DATEBITS; + if (BigIntNum > doubleNum) { + return bigIntSign ? ComparisonResult::LESS : ComparisonResult::GREAT; + } + if (BigIntNum < doubleNum) { + return bigIntSign ? ComparisonResult::GREAT : ComparisonResult::LESS; + } + leftover -= BigInt::DATEBITS; + } + } + + if (mantissa != 0) { + ASSERT(leftover > 0); + return bigIntSign ? ComparisonResult::GREAT : ComparisonResult::LESS; + } + return ComparisonResult::EQUAL; +} +} // namespace panda::ecmascript diff --git a/runtime/js_bigint.h b/runtime/js_bigint.h new file mode 100644 index 000000000..28f02bca3 --- /dev/null +++ b/runtime/js_bigint.h @@ -0,0 +1,145 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_JS_BIGINT_H +#define ECMASCRIPT_JS_BIGINT_H + +#include +#include "js_object.h" +#include "plugins/ecmascript/runtime/tagged_array.h" + +namespace panda::ecmascript { +enum class Operate : uint32_t { AND = 0, OR, XOR }; +enum class Comparestr : uint32_t { EQUAL = 0, GREATER, LESS }; + +class BigInt : public TaggedObject { +public: + static Comparestr ComString(std::string &a, std::string &b); + static constexpr uint32_t DATEBITS = sizeof(uint32_t) * 8; // 8 : one-bit number of bytes + static constexpr uint32_t MAXBITS = 1024 * 1024; // 1024 * 1024 : Maximum space that can be opened up + static constexpr uint32_t MAXSIZE = MAXBITS / DATEBITS; // the maximum value of size + static constexpr uint32_t MAXOCTALVALUE = 7; // 7 : max octal value + static constexpr uint32_t BINARY = 2; // 2 : binary + + static constexpr uint32_t OCTAL = 8; // 8 : octal + static constexpr uint32_t DECIMAL = 10; // 10 : decimal + static constexpr uint32_t HEXADECIMAL = 16; // 16 : hexadecimal + CAST_CHECK(BigInt, IsBigInt); + static JSHandle CreateBigInt(JSThread *thread, uint32_t size); + + static bool Equal(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y); + static bool SameValue(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y); + static bool SameValueZero(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y); + + static void InitializationZero(JSThread *thread, JSHandle BigInt); + static JSHandle BitwiseOp(JSThread *thread, Operate op, JSHandle x, JSHandle y); + static JSHandle BitwiseAND(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle BitwiseXOR(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle BitwiseOR(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle BitwiseSubOne(JSThread *thread, JSHandle bigInt, uint32_t maxLen); + static JSHandle BitwiseAddOne(JSThread *thread, JSHandle bigInt); + static JSHandle ToString(JSThread *thread, JSHandle bigInt, + uint32_t conversionToRadix = BigInt::DECIMAL); + std::string ToStdString(JSThread *thread, uint32_t conversionToRadix) const; + + static JSHandle UnaryMinus(JSThread *thread, JSHandle x); + static JSHandle BitwiseNOT(JSThread *thread, JSHandle x); + static JSHandle Exponentiate(JSThread *thread, JSHandle base, JSHandle exponent); + static JSHandle Multiply(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle Divide(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle Remainder(JSThread *thread, JSHandle n, JSHandle d); + static JSHandle BigIntAddOne(JSThread *thread, JSHandle x); + static JSHandle BigIntSubOne(JSThread *thread, JSHandle x); + static JSHandle Copy(JSThread *thread, JSHandle x); + + static JSHandle Add(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle Subtract(JSThread *thread, JSHandle x, JSHandle y); + static bool LessThan(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y); + static ComparisonResult Compare(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y); + static JSHandle SignedRightShift(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle RightShiftHelper(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle UnsignedRightShift(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle LeftShift(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle LeftShiftHelper(JSThread *thread, JSHandle x, JSHandle y); + static JSHandle BigIntAdd(JSThread *thread, JSHandle x, JSHandle y, bool resultSign); + static JSHandle BigIntSub(JSThread *thread, JSHandle x, JSHandle y, bool resultSign); + + static JSTaggedValue NumberToBigInt(JSThread *thread, JSHandle number); + static JSHandle Int32ToBigInt(JSThread *thread, const int &number); + static JSHandle Int64ToBigInt(JSThread *thread, const int64_t &number); + static JSHandle Uint64ToBigInt(JSThread *thread, const uint64_t &number); + static void BigIntToInt64(JSThread *thread, JSHandle bigInt, int64_t *cValue, bool *lossless); + static void BigIntToUint64(JSThread *thread, JSHandle bigInt, uint64_t *cValue, bool *lossless); + static JSHandle CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t *words); + static JSHandle FloorMod(JSThread *thread, JSHandle leftVal, JSHandle rightVal); + static JSTaggedValue AsUintN(JSThread *thread, JSTaggedNumber &bits, JSHandle bigInt); + static JSTaggedValue AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle bigInt); + static JSTaggedNumber BigIntToNumber(JSHandle bigInt); + static ComparisonResult CompareWithNumber(JSHandle bigInt, JSHandle number); + inline bool IsZero() + { + return GetLength() == 1 && GetDigit(0) == 0; + } + + uint32_t GetDigit(uint32_t index) const; + static void SetDigit(JSThread *thread, JSHandle bigInt, uint32_t index, uint32_t digit); + + uint32_t GetLength() const; + + static constexpr size_t DATA_OFFSET = TaggedObjectSize(); + ACCESSORS(Data, DATA_OFFSET, BITFIELD_OFFSET); + SET_GET_PRIMITIVE_FIELD(BitField, uint32_t, BITFIELD_OFFSET, SIZE); + + static constexpr size_t SIGN_BITS = 1; + using SignBits = BitField; + + inline bool GetSign() const + { + return SignBits::Decode(GetBitField()); + } + + inline void SetSign(bool t) + { + SetBitField(SignBits::Update(GetBitField(), t)); + } + + DECL_DUMP() + DECL_VISIT_OBJECT(DATA_OFFSET, BITFIELD_OFFSET); + +private: + static bool Equal(const JSHandle &x, const JSHandle &y); + static bool LessThan(const JSHandle &x, const JSHandle &y); +}; + +class BigIntHelper { +public: + static std::string Conversion(const std::string &num, uint32_t conversionToRadix, uint32_t currentRadix); + static JSHandle SetBigInt(JSThread *thread, const std::string &numStr, + uint32_t currentRadix = BigInt::DECIMAL); + static std::string GetBinary(const JSHandle &bigInt); + static JSHandle RightTruncate(JSThread *thread, JSHandle x); + + static JSHandle DivideImpl(JSThread *thread, JSHandle x, JSHandle y); + static std::string MultiplyImpl(std::string &a, std::string &b); + static std::string DeZero(std::string &a); + static std::string Minus(std::string &a, std::string &b); + static std::string DevStr(std::string &strValue); + static std::string Divide(std::string &a, std::string &b); + + static uint32_t AddHelper(uint32_t x, uint32_t y, uint32_t &bigIntCarry); + static uint32_t SubHelper(uint32_t x, uint32_t y, uint32_t &bigIntCarry); +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_JS_BIGINT_H diff --git a/runtime/js_dataview.cpp b/runtime/js_dataview.cpp index 61296c4ce..7f77901e8 100644 --- a/runtime/js_dataview.cpp +++ b/runtime/js_dataview.cpp @@ -37,6 +37,10 @@ int32_t JSDataView::GetElementSize(DataViewType type) case DataViewType::FLOAT64: size = 8; // 8 means the length break; + case DataViewType::BIGINT64: + case DataViewType::BIGUINT64: + size = 8; // 8 means the length + break; default: UNREACHABLE(); } diff --git a/runtime/js_dataview.h b/runtime/js_dataview.h index 9bfeb393e..51b7b7739 100644 --- a/runtime/js_dataview.h +++ b/runtime/js_dataview.h @@ -19,7 +19,19 @@ #include "plugins/ecmascript/runtime/js_object.h" namespace panda::ecmascript { -enum class DataViewType : uint8_t { FLOAT32 = 0, FLOAT64, INT8, INT16, INT32, UINT8, UINT16, UINT32, UINT8_CLAMPED }; +enum class DataViewType : uint8_t { + BIGINT64 = 0, + BIGUINT64, + FLOAT32, + FLOAT64, + INT8, + INT16, + INT32, + UINT8, + UINT16, + UINT32, + UINT8_CLAMPED +}; class JSDataView : public JSObject { public: CAST_CHECK(JSDataView, IsDataView); diff --git a/runtime/js_eval.cpp b/runtime/js_eval.cpp new file mode 100644 index 000000000..4ce5155b2 --- /dev/null +++ b/runtime/js_eval.cpp @@ -0,0 +1,220 @@ +/* + * 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. + */ + +#include "js_eval.h" +#include "ecma_string.h" +#include "include/mem/panda_string.h" +#include "plugins/ecmascript/runtime/builtins/builtins_function.h" +#include "plugins/ecmascript/runtime/internal_call_params.h" +#include "plugins/ecmascript/runtime/interpreter/interpreter-inl.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "assembler/assembly-emitter.h" + +namespace panda::ecmascript { +JSTaggedValue EvalUtils::GetEvaluatedScript(JSThread *thread, const JSHandle &str, + const es2panda::CompilerOptions &options, uint32_t parserStatus) +{ + auto buffer = str->GetCString(); + + es2panda::Compiler compiler(es2panda::ScriptExtension::JS); + es2panda::SourceFile input("eval.js", std::string_view(buffer.get()), false); + std::unique_ptr program(compiler.Compile(input, options, parserStatus)); + ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory(); + + if (!program) { + const auto &err = compiler.GetError(); + JSHandle error = objectFactory->GetJSError(ErrorType::SYNTAX_ERROR, err.Message().c_str()); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error.GetTaggedValue(), JSTaggedValue::Exception()); + } + + panda_file::MemoryWriter writer; + [[maybe_unused]] bool status = pandasm::AsmEmitter::Emit(&writer, *program); + ASSERT(status); + const auto &data = writer.GetData(); + + auto pf = panda_file::OpenPandaFileFromMemory(data.data(), data.size()); + ASSERT(pf); + + auto *pandaFile = pf.get(); + auto *ecmaVM = thread->GetEcmaVM(); + + ecmaVM->AddPandaFile(pandaFile, false); + Runtime::GetCurrent()->GetClassLinker()->AddPandaFile(std::move(pf)); + + auto resolveFunc = ecmaVM->GetInvocableFunction(*pandaFile, "func_main_0"); + ASSERT(resolveFunc.HasValue()); + + return resolveFunc.Value(); +} + +JSTaggedValue EvalUtils::DirectEval(JSThread *thread, uint32_t parserStatus, JSTaggedValue arg0, + JSTaggedValue evalbindings) +{ + [[maybe_unused]] EcmaHandleScope scope(thread); + + JSHandle arg0Handle(thread, arg0); + JSHandle evalBindingsHandle(thread, evalbindings); + JSHandle argStr = JSTaggedValue::ToString(thread, arg0Handle); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, argStr.GetTaggedValue()); + + es2panda::CompilerOptions options; + options.isEval = true; + options.isDirectEval = true; + + JSHandle func(thread, GetEvaluatedScript(thread, argStr, options, parserStatus)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, func.GetTaggedValue()); + uint32_t index = 0; + + JSHandle paramFunc = JSArray::FastGetPropertyByValue(thread, evalBindingsHandle, index++); + JSHandle newTarget = JSArray::FastGetPropertyByValue(thread, evalBindingsHandle, index++); + JSHandle thisValue = JSArray::FastGetPropertyByValue(thread, evalBindingsHandle, index++); + JSHandle lexicalContext = JSArray::FastGetPropertyByValue(thread, evalBindingsHandle, index++); + + constexpr auto paramsCount = NUM_MANDATORY_JSFUNC_ARGS + 1; + ASSERT(paramsCount == index); + std::array params = {paramFunc.GetTaggedType(), newTarget.GetTaggedType(), + thisValue.GetTaggedType(), lexicalContext.GetTaggedType()}; + + return EcmaInterpreter::Execute(thread, JSHandle::Cast(func), params.size(), params.data()); +} + +JSTaggedValue EvalUtils::Eval(JSThread *thread, const JSHandle &arg0) +{ + [[maybe_unused]] EcmaHandleScope scope(thread); + + JSHandle argStr = JSTaggedValue::ToString(thread, arg0); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, argStr.GetTaggedValue()); + + es2panda::CompilerOptions options; + options.isEval = true; + JSHandle func(thread, GetEvaluatedScript(thread, argStr, options)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, func.GetTaggedValue()); + + JSHandle thisValue(thread, thread->GetGlobalObject()); + + std::array params = { + func.GetTaggedType(), JSTaggedValue::Undefined().GetRawData(), thisValue.GetTaggedType()}; + + return EcmaInterpreter::Execute(thread, JSHandle::Cast(func), params.size(), params.data()); +} + +JSTaggedValue EvalUtils::CreateDynamicFunction(EcmaRuntimeCallInfo *argv, DynamicFunctionKind kind) +{ + using BuiltinsFunction = builtins::BuiltinsFunction; + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle functionBody(thread, JSTaggedValue::Undefined()); + JSHandle functionParamStr = factory->GetEmptyString(); + uint32_t nargs = argv->GetArgsNumber(); + + if (nargs == 1) { + functionBody = BuiltinsFunction::GetCallArg(argv, 0); + } else if (nargs > 1) { + JSHandle firstParamHandle = builtins::BuiltinsFunction::GetCallArg(argv, 0); + functionParamStr = JSTaggedValue::ToString(thread, firstParamHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + uint32_t iter = 1; + + while (iter < nargs - 1) { + JSHandle commaStr = factory->NewFromCanBeCompressString(","); + functionParamStr = factory->ConcatFromString(functionParamStr, commaStr); + JSHandle paramHandle = BuiltinsFunction::GetCallArg(argv, iter); + JSHandle paramString = JSTaggedValue::ToString(thread, paramHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + functionParamStr = factory->ConcatFromString(functionParamStr, paramString); + iter++; + } + + functionBody = BuiltinsFunction::GetCallArg(argv, iter); + } + + JSHandle resultStr = factory->NewFromCanBeCompressString("("); + JSHandle functionBodyStr = factory->GetEmptyString(); + + if (!functionBody->IsUndefined()) { + functionBodyStr = JSTaggedValue::ToString(thread, functionBody); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + + if (kind == DynamicFunctionKind::ASYNC || kind == DynamicFunctionKind::ASYNC_GENERATOR) { + // '(async function' + JSHandle asyncStr = factory->NewFromCanBeCompressString("async "); + resultStr = factory->ConcatFromString(resultStr, asyncStr); + } + + // '(function' + JSHandle functionStr = factory->NewFromCanBeCompressString("function "); + resultStr = factory->ConcatFromString(resultStr, functionStr); + + if (kind == DynamicFunctionKind::GENERATOR || kind == DynamicFunctionKind::ASYNC_GENERATOR) { + // '(function*' + JSHandle asteriskStr = factory->NewFromCanBeCompressString("* "); + resultStr = factory->ConcatFromString(resultStr, asteriskStr); + } + + // '(function anonymous(' + JSHandle anonymousStr = factory->NewFromCanBeCompressString("anonymous("); + resultStr = factory->ConcatFromString(resultStr, anonymousStr); + + // '(function anonymous(params' + resultStr = factory->ConcatFromString(resultStr, functionParamStr); + + // '(function anonymous(params){' + JSHandle rightParenLeftBrace = factory->NewFromCanBeCompressString("){"); + resultStr = factory->ConcatFromString(resultStr, rightParenLeftBrace); + + // '(function anonymous(params) {body' + resultStr = factory->ConcatFromString(resultStr, functionBodyStr); + + // '(function anonymous(params) {body})' + JSHandle rightBraceRightParen = factory->NewFromCanBeCompressString("})"); + resultStr = factory->ConcatFromString(resultStr, rightBraceRightParen); + + es2panda::CompilerOptions options; + options.isEval = true; + options.isFunctionEval = true; + JSHandle func(thread, GetEvaluatedScript(thread, resultStr, options)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, func.GetTaggedValue()); + + JSHandle thisValue(thread, thread->GetGlobalObject()); + + std::array params = { + func.GetTaggedType(), JSTaggedValue::Undefined().GetRawData(), thisValue.GetTaggedType()}; + + JSHandle res( + thread, EcmaInterpreter::Execute(thread, JSHandle::Cast(func), params.size(), params.data())); + + ASSERT(res->IsCallable()); + + JSHandle newTargetHandle = argv->GetNewTarget(); + + if (newTargetHandle->IsUndefined()) { + return res.GetTaggedValue(); + } + + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSHandle newTargetProto = + JSTaggedValue::GetProperty(thread, newTargetHandle, globalConst->GetHandledPrototypeString()).GetValue(); + + if (newTargetProto->IsECMAObject()) { + JSObject::SetPrototype(thread, JSHandle::Cast(res), newTargetProto); + } + + return res.GetTaggedValue(); +} +} // namespace panda::ecmascript diff --git a/runtime/js_eval.h b/runtime/js_eval.h new file mode 100644 index 000000000..01c67f89f --- /dev/null +++ b/runtime/js_eval.h @@ -0,0 +1,42 @@ +/* + * 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_JSEVAL_H +#define ECMASCRIPT_JSEVAL_H + +#include "plugins/ecmascript/runtime/ecma_runtime_call_info.h" +#include "plugins/ecmascript/runtime/js_tagged_value-inl.h" + +namespace panda::es2panda { +struct CompilerOptions; +} // namespace panda::es2panda + +namespace panda::ecmascript { +class EvalUtils { +public: + enum class DynamicFunctionKind { NORMAL, GENERATOR, ASYNC, ASYNC_GENERATOR }; + + static JSTaggedValue DirectEval(JSThread *thread, uint32_t parserStatus, JSTaggedValue arg0, + JSTaggedValue evalbindings); + static JSTaggedValue Eval(JSThread *thread, const JSHandle &arg0); + static JSTaggedValue CreateDynamicFunction(EcmaRuntimeCallInfo *argv, DynamicFunctionKind kind); + +private: + static JSTaggedValue GetEvaluatedScript(JSThread *thread, const JSHandle &str, + const es2panda::CompilerOptions &options, uint32_t parserStatus = 0); +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_JSEVAL_H diff --git a/runtime/js_function.h b/runtime/js_function.h index 82527c7f0..e5ec65c88 100644 --- a/runtime/js_function.h +++ b/runtime/js_function.h @@ -336,6 +336,21 @@ public: DECL_DUMP() }; +class JSConstructorFunction : public JSFunction { +public: + enum class PrivateFieldKind { FIELD, METHOD, GET, SET, STATIC_FIELD, STATIC_METHOD, STATIC_GET, STATIC_SET }; + + CAST_CHECK(JSConstructorFunction, IsClassConstructor); + + static constexpr size_t COMPUTED_FIELDS_OFFSET = JSFunction::SIZE; + ACCESSORS(ComputedFields, COMPUTED_FIELDS_OFFSET, PRIVATE_FIELDS_OFFSET); + ACCESSORS(PrivateFields, PRIVATE_FIELDS_OFFSET, SIZE); + + DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, COMPUTED_FIELDS_OFFSET, SIZE) + + DECL_DUMP() +}; + class JSBoundFunction : public JSFunctionBase { public: CAST_CHECK(JSBoundFunction, IsBoundFunction); diff --git a/runtime/js_hclass.h b/runtime/js_hclass.h index 66aba5172..0f73c3fcf 100644 --- a/runtime/js_hclass.h +++ b/runtime/js_hclass.h @@ -134,13 +134,16 @@ class ProtoChangeDetails; JS_INT32_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_UINT32_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_FLOAT32_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ - JS_FLOAT64_ARRAY, /* JS_TYPED_ARRAY_END ///////////////////////////////////////////////////////////// */ \ + JS_FLOAT64_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ + JS_BIGINT64_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ + JS_BIGUINT64_ARRAY, /* JS_TYPED_ARRAY_END ///////////////////////////////////////////////////////////// */ \ JS_PRIMITIVE_REF, /* number\boolean\string. SPECIAL indexed objects end, DON'T CHANGE HERE ////////-PADDING */ \ JS_GLOBAL_OBJECT, /* JS_OBJECT_END/////////////////////////////////////////////////////////////////-PADDING */ \ JS_PROXY, /* ECMA_OBJECT_END ////////////////////////////////////////////////////////////////////////////// */ \ \ - HCLASS, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \ - STRING, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \ + HCLASS, /* ////////////////////////////////////////////////////////////////////////////////////////-PADDING */ \ + STRING, /* ////////////////////////////////////////////////////////////////////////////////////////-PADDING */ \ + BIGINT, /* ////////////////////////////////////////////////////////////////////////////////////////-PADDING */ \ TAGGED_ARRAY, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \ TAGGED_DICTIONARY, /* /////////////////////////////////////////////////////////////////////////////-PADDING */ \ LINKED_HASH_SET, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */ \ @@ -199,7 +202,7 @@ class ProtoChangeDetails; TAGGED_ARRAY_END = LINKED_HASH_MAP, /* ///////////////////////////////////////////////////////////-PADDING */ \ \ JS_TYPED_ARRAY_BEGIN = JS_TYPED_ARRAY, /* /////////////////////////////////////////////////////////-PADDING */ \ - JS_TYPED_ARRAY_END = JS_FLOAT64_ARRAY /* /////////////////////////////////////////////////////////-PADDING */ + JS_TYPED_ARRAY_END = JS_BIGUINT64_ARRAY /* ////////////////////////////////////////////////////////-PADDING */ enum class JSType : uint8_t { JSTYPE_DECL, @@ -408,6 +411,11 @@ public: return GetObjectType() == JSType::JS_ARRAY; } + inline bool IsBigInt() const + { + return GetObjectType() == JSType::BIGINT; + } + inline bool IsTypedArray() const { JSType js_type = GetObjectType(); @@ -464,6 +472,16 @@ public: return GetObjectType() == JSType::JS_FLOAT64_ARRAY; } + inline bool IsJSBigInt64Array() const + { + return GetObjectType() == JSType::JS_BIGINT64_ARRAY; + } + + inline bool IsJSBigUint64Array() const + { + return GetObjectType() == JSType::JS_BIGUINT64_ARRAY; + } + inline bool IsJsGlobalEnv() const { return GetObjectType() == JSType::GLOBAL_ENV; diff --git a/runtime/js_number_format.cpp b/runtime/js_number_format.cpp index 0321a72a5..5329fea2b 100644 --- a/runtime/js_number_format.cpp +++ b/runtime/js_number_format.cpp @@ -689,8 +689,18 @@ JSHandle JSNumberFormat::FormatNumeric(JSThread *thread, const JS ASSERT(icuNumberFormat != nullptr); UErrorCode status = U_ZERO_ERROR; - double number = x.GetNumber(); - icu::number::FormattedNumber formattedNumber = icuNumberFormat->formatDouble(number, status); + icu::number::FormattedNumber formattedNumber; + if (x.IsBigInt()) { + [[maybe_unused]] EcmaHandleScope scope(thread); + + JSHandle bigint(thread, x); + JSHandle bigintStr = BigInt::ToString(thread, bigint); + std::string stdString = bigintStr->GetCString().get(); + formattedNumber = icuNumberFormat->formatDecimal(icu::StringPiece(stdString), status); + } else { + double number = x.GetNumber(); + formattedNumber = icuNumberFormat->formatDouble(number, status); + } if (U_FAILURE(status) != 0) { JSHandle errorResult(thread, JSTaggedValue::Exception()); THROW_RANGE_ERROR_AND_RETURN(thread, "icu formatter format failed", errorResult); diff --git a/runtime/js_object.h b/runtime/js_object.h index 094eb29d3..4a779543f 100644 --- a/runtime/js_object.h +++ b/runtime/js_object.h @@ -529,6 +529,7 @@ public: bool IsArguments() const; bool IsDate() const; bool IsJSArray() const; + bool IsBigInt() const; bool IsJSMap() const; bool IsJSSet() const; bool IsJSRegExp() const; diff --git a/runtime/js_primitive_ref.h b/runtime/js_primitive_ref.h index 9436c53c6..8b8a7ec0e 100644 --- a/runtime/js_primitive_ref.h +++ b/runtime/js_primitive_ref.h @@ -27,6 +27,7 @@ enum class PrimitiveType : uint8_t { PRIMITIVE_NUMBER, PRIMITIVE_STRING, PRIMITIVE_SYMBOL, + PRIMITIVE_BIGINT, }; class JSPrimitiveRef : public JSObject { diff --git a/runtime/js_tagged_value-inl.h b/runtime/js_tagged_value-inl.h index f4b844d1d..649877be3 100644 --- a/runtime/js_tagged_value-inl.h +++ b/runtime/js_tagged_value-inl.h @@ -25,6 +25,7 @@ #include "plugins/ecmascript/runtime/ecma_macros.h" #include "plugins/ecmascript/runtime/ecma_runtime_call_info.h" #include "plugins/ecmascript/runtime/ecma_string-inl.h" +#include "plugins/ecmascript/runtime/js_bigint.h" #include "plugins/ecmascript/runtime/js_hclass-inl.h" #include "plugins/ecmascript/runtime/js_object.h" #include "plugins/ecmascript/runtime/js_proxy.h" @@ -67,6 +68,11 @@ inline bool JSTaggedValue::ToBoolean() const } } + if (IsBigInt()) { + BigInt *bigint = BigInt::Cast(GetTaggedObject()); + return !bigint->IsZero(); + } + if (IsHeapObject()) { TaggedObject *obj = GetTaggedObject(); if (IsString()) { @@ -80,6 +86,23 @@ inline bool JSTaggedValue::ToBoolean() const UNREACHABLE(); } +inline JSHandle JSTaggedValue::ToNumeric(JSThread *thread, JSHandle tagged) +{ + // 1. Let primValue be ? ToPrimitive(value, number) + + JSHandle primValue(thread, ToPrimitive(thread, tagged, PREFER_NUMBER)); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); + // 2. If Type(primValue) is BigInt, return primValue. + if (primValue->IsBigInt()) { + return primValue; + } + // 3. Return ? ToNumber(primValue). + JSTaggedNumber number = ToNumber(thread, primValue); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); + JSHandle value(thread, number); + return value; +} + inline JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, const JSHandle &tagged) { if (tagged->IsInt() || tagged->IsDouble()) { @@ -131,10 +154,85 @@ inline JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, const JSHandleIsSymbol()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a number", JSTaggedNumber::Exception()); } + if (tagged->IsBigInt()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a BigInt value to a number", JSTaggedNumber::Exception()); + } THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a number", JSTaggedNumber::Exception()); } +inline JSTaggedValue JSTaggedValue::ToBigInt(JSThread *thread, const JSHandle &tagged) +{ + JSHandle primValue(thread, ToPrimitive(thread, tagged)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + switch (primValue->GetRawData()) { + case JSTaggedValue::VALUE_UNDEFINED: + case JSTaggedValue::VALUE_NULL: { + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a undefine or null value to a BigInt", + JSTaggedValue::Exception()); + } + case JSTaggedValue::VALUE_TRUE: { + return BigInt::Int32ToBigInt(thread, 1).GetTaggedValue(); + } + case JSTaggedValue::VALUE_FALSE: { + return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue(); + } + default: { + break; + } + } + + if (primValue->IsNumber()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Number value to a BigInt", JSTaggedNumber::Exception()); + } + if (primValue->IsString()) { + JSHandle value(thread, base::NumberHelper::StringToBigInt(thread, primValue)); + if (value->IsBigInt()) { + return value.GetTaggedValue(); + } + THROW_SYNTAX_ERROR_AND_RETURN(thread, + "Cannot convert string to a BigInt," + "because not allow Infinity, decimal points, or exponents", + JSTaggedValue::Exception()); + } + if (primValue->IsSymbol()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a BigInt", JSTaggedNumber::Exception()); + } + if (primValue->IsBigInt()) { + return primValue.GetTaggedValue(); + } + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a BigInt", JSTaggedNumber::Exception()); +} + +inline JSTaggedValue JSTaggedValue::ToBigInt64(JSThread *thread, const JSHandle &tagged) +{ + JSHandle value(thread, ToBigInt(thread, tagged)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle exponent = BigInt::Int32ToBigInt(thread, 64); // NOLINT: 64 : bits + JSHandle exponentone = BigInt::Int32ToBigInt(thread, 63); // NOLINT: 63 : bits + JSHandle base = BigInt::Int32ToBigInt(thread, 2); // 2 : base value + JSHandle tVal = BigInt::Exponentiate(thread, base, exponent); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle int64bitVal = BigInt::FloorMod(thread, value, tVal); + JSHandle resValue = BigInt::Exponentiate(thread, base, exponentone); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (!BigInt::LessThan(thread, int64bitVal.GetTaggedValue(), resValue.GetTaggedValue())) { + return BigInt::Subtract(thread, int64bitVal, tVal).GetTaggedValue(); + } + return int64bitVal.GetTaggedValue(); +} + +inline JSTaggedValue JSTaggedValue::ToBigUint64(JSThread *thread, const JSHandle &tagged) +{ + JSHandle value(thread, ToBigInt(thread, tagged)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle exponent = BigInt::Int32ToBigInt(thread, 64); // NOLINT: 64 : exponet value + JSHandle base = BigInt::Int32ToBigInt(thread, 2); // 2 : base value + JSHandle tVal = BigInt::Exponentiate(thread, base, exponent); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return BigInt::FloorMod(thread, value, tVal).GetTaggedValue(); +} + inline JSTaggedNumber JSTaggedValue::ToInteger(JSThread *thread, const JSHandle &tagged) { JSTaggedNumber number = ToNumber(thread, tagged); @@ -325,7 +423,7 @@ inline bool JSTaggedValue::StrictNumberEquals(double x, double y) return x == y; } -inline bool JSTaggedValue::StrictEqual([[maybe_unused]] const JSThread *thread, const JSHandle &x, +inline bool JSTaggedValue::StrictEqual([[maybe_unused]] JSThread *thread, const JSHandle &x, const JSHandle &y) { if (x->IsNumber() && y->IsNumber()) { @@ -339,6 +437,11 @@ inline bool JSTaggedValue::StrictEqual([[maybe_unused]] const JSThread *thread, if (x->IsString() && y->IsString()) { return EcmaString::StringsAreEqual(x.GetObject(), y.GetObject()); } + + if (x->IsBigInt() && y->IsBigInt()) { + return BigInt::Equal(thread, x.GetTaggedValue(), y.GetTaggedValue()); + } + return false; } @@ -572,6 +675,11 @@ inline bool JSTaggedValue::IsJSArray() const return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSArray(); } +inline bool JSTaggedValue::IsBigInt() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsBigInt(); +} + inline bool JSTaggedValue::IsStableJSArray(JSThread *thread) const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableJSArray() && @@ -645,6 +753,16 @@ inline bool JSTaggedValue::IsJSFloat64Array() const return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSFloat64Array(); } +inline bool JSTaggedValue::IsJSBigInt64Array() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSBigInt64Array(); +} + +inline bool JSTaggedValue::IsJSBigUint64Array() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSBigUint64Array(); +} + inline bool JSTaggedValue::IsJSMap() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSMap(); diff --git a/runtime/js_tagged_value.cpp b/runtime/js_tagged_value.cpp index 71c011cd4..42f4d168e 100644 --- a/runtime/js_tagged_value.cpp +++ b/runtime/js_tagged_value.cpp @@ -120,6 +120,9 @@ bool JSTaggedValue::Equal(JSThread *thread, const JSHandle &x, co RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber()); } + if (y->IsBigInt()) { + return Equal(thread, y, x); + } if (y->IsBoolean()) { JSTaggedNumber yNumber = ToNumber(thread, y); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); @@ -143,6 +146,9 @@ bool JSTaggedValue::Equal(JSThread *thread, const JSHandle &x, co RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); return StrictNumberEquals(xNumber.GetNumber(), y->ExtractNumber()); } + if (y->IsBigInt()) { + return Equal(thread, y, x); + } if (y->IsBoolean()) { JSTaggedNumber xNumber = ToNumber(thread, x); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); @@ -168,6 +174,9 @@ bool JSTaggedValue::Equal(JSThread *thread, const JSHandle &x, co if (y->IsSymbol()) { return x.GetTaggedValue() == y.GetTaggedValue(); } + if (y->IsBigInt()) { + return Equal(thread, y, x); + } if (y->IsHeapObject() && y->IsECMAObject()) { JSHandle yPrimitive(thread, ToPrimitive(thread, y)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); @@ -176,6 +185,34 @@ bool JSTaggedValue::Equal(JSThread *thread, const JSHandle &x, co return false; } + if (x->IsBigInt()) { + if (y->IsBigInt()) { + return BigInt::Equal(thread, x.GetTaggedValue(), y.GetTaggedValue()); + } + if (y->IsString()) { + JSHandle yNumber(thread, base::NumberHelper::StringToBigInt(thread, y)); + if (!yNumber->IsBigInt()) { + return false; + } + return BigInt::Equal(thread, x.GetTaggedValue(), yNumber.GetTaggedValue()); + } + if (y->IsBoolean()) { + JSHandle yNumber(thread, ToBigInt(thread, y)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); + return BigInt::Equal(thread, x.GetTaggedValue(), yNumber.GetTaggedValue()); + } + if (y->IsNumber()) { + JSHandle bigint = JSHandle::Cast(x); + return BigInt::CompareWithNumber(bigint, y) == ComparisonResult::EQUAL; + } + if (y->IsHeapObject() && !y->IsSymbol()) { + JSHandle yPrimitive(thread, ToPrimitive(thread, y)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); + return Equal(thread, x, yPrimitive); + } + return false; + } + if (x->IsHeapObject()) { if (y->IsHeapObject()) { // if same type, must call Type::StrictEqual() @@ -185,7 +222,7 @@ bool JSTaggedValue::Equal(JSThread *thread, const JSHandle &x, co return StrictEqual(thread, x, y); } } - if (y->IsNumber() || y->IsStringOrSymbol() || y->IsBoolean()) { + if (y->IsNumber() || y->IsStringOrSymbol() || y->IsBoolean() || y->IsBigInt()) { JSHandle x_primitive(thread, ToPrimitive(thread, x)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); return Equal(thread, x_primitive, y); @@ -233,6 +270,35 @@ ComparisonResult JSTaggedValue::Compare(JSThread *thread, const JSHandleIsBigInt()) { + if (primY->IsNumber()) { + JSHandle bigint = JSHandle::Cast(primX); + return BigInt::CompareWithNumber(bigint, primY); + } + if (primY->IsString()) { + JSHandle bigY(thread, base::NumberHelper::StringToBigInt(thread, primY)); + if (!bigY->IsBigInt()) { + return ComparisonResult::UNDEFINED; + } + return BigInt::Compare(thread, primX.GetTaggedValue(), bigY.GetTaggedValue()); + } + JSHandle bigY(thread, ToBigInt(thread, primY)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED); + return BigInt::Compare(thread, primX.GetTaggedValue(), bigY.GetTaggedValue()); + } + + if (primY->IsBigInt()) { + ComparisonResult res = Compare(thread, primY, primX); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED); + if (res == ComparisonResult::GREAT) { + return ComparisonResult::LESS; + } + if (res == ComparisonResult::LESS) { + return ComparisonResult::GREAT; + } + return res; + } + JSTaggedNumber xNumber = ToNumber(thread, x); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED); JSTaggedNumber yNumber = ToNumber(thread, y); @@ -342,6 +408,11 @@ JSHandle JSTaggedValue::ToString(JSThread *thread, const JSHandleIsBigInt()) { + JSHandle taggedValue(tagged); + return BigInt::ToString(thread, taggedValue); + } + auto empty_str = globalConst->GetHandledEmptyString(); if (tagged->IsECMAObject()) { JSHandle primValue(thread, ToPrimitive(thread, tagged, PREFER_STRING)); @@ -405,6 +476,9 @@ JSHandle JSTaggedValue::ToObject(JSThread *thread, const JSHandleIsString()) { return JSHandle::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, tagged)); } + if (tagged->IsBigInt()) { + return JSHandle::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, tagged)); + } THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown object value to a JSObject", JSHandle(thread, JSTaggedValue::Exception())); } @@ -760,6 +834,10 @@ JSHandle JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const return JSHandle(thread, env->GetSymbolFunction().GetObject()->GetFunctionPrototype()); } + if (obj->IsBigInt()) { + return JSHandle(thread, + env->GetBigIntFunction().GetObject()->GetFunctionPrototype()); + } return obj; } diff --git a/runtime/js_tagged_value.h b/runtime/js_tagged_value.h index ba83d8a4c..970bd94fa 100644 --- a/runtime/js_tagged_value.h +++ b/runtime/js_tagged_value.h @@ -137,6 +137,10 @@ public: PreferredPrimitiveType type = NO_PREFERENCE); bool ToBoolean() const; static JSTaggedNumber ToNumber(JSThread *thread, const JSHandle &tagged); + static JSHandle ToNumeric(JSThread *thread, JSHandle tagged); + static JSTaggedValue ToBigInt(JSThread *thread, const JSHandle &tagged); + static JSTaggedValue ToBigInt64(JSThread *thread, const JSHandle &tagged); + static JSTaggedValue ToBigUint64(JSThread *thread, const JSHandle &tagged); static JSTaggedNumber ToInteger(JSThread *thread, const JSHandle &tagged); static int32_t ToInt32(JSThread *thread, const JSHandle &tagged); static uint32_t ToUint32(JSThread *thread, const JSHandle &tagged); @@ -171,7 +175,7 @@ public: static bool SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y); static bool Less(JSThread *thread, const JSHandle &x, const JSHandle &y); static bool Equal(JSThread *thread, const JSHandle &x, const JSHandle &y); - static bool StrictEqual(const JSThread *thread, const JSHandle &x, const JSHandle &y); + static bool StrictEqual(JSThread *thread, const JSHandle &x, const JSHandle &y); static bool SameValueNumberic(const JSTaggedValue &x, const JSTaggedValue &y); // ES6 7.4 Operations on Iterator Objects @@ -233,6 +237,7 @@ public: bool IsJSError() const; bool IsArray(JSThread *thread) const; bool IsJSArray() const; + bool IsBigInt() const; bool IsStableJSArray(JSThread *thread) const; bool IsStableJSArguments(JSThread *thread) const; bool HasStableElements(JSThread *thread) const; @@ -247,6 +252,8 @@ public: bool IsJSUint32Array() const; bool IsJSFloat32Array() const; bool IsJSFloat64Array() const; + bool IsJSBigInt64Array() const; + bool IsJSBigUint64Array() const; bool IsArguments() const; bool IsDate() const; bool IsBoundFunction() const; diff --git a/runtime/js_typed_array.cpp b/runtime/js_typed_array.cpp index cc2893e37..0ec57c30f 100644 --- a/runtime/js_typed_array.cpp +++ b/runtime/js_typed_array.cpp @@ -361,7 +361,7 @@ OperationResult JSTypedArray::IntegerIndexedElementGet(JSThread *thread, const J // We use buffer without handle and GC can move it. So we have to get buffer each time. // To make developer get buffer each time use scope and don't populate buffer into function's scope. JSTaggedValue buffer = JSTypedArray::Cast(*typedarrayObj)->GetViewedArrayBuffer(); - result = BuiltinsArrayBuffer::GetValueFromBuffer(buffer, byteIndex, elementType, true); + result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true); } return OperationResult(thread, result, PropertyMetaData(true)); } @@ -398,7 +398,7 @@ bool JSTypedArray::FastCopyElementToArray(JSThread *thread, const JSHandleSet(thread, index, result); } return true; @@ -443,7 +443,7 @@ OperationResult JSTypedArray::FastElementGet(JSThread *thread, const JSHandleGetViewedArrayBuffer(); - JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(buffer, byteIndex, elementType, true); + JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true); return OperationResult(thread, result, PropertyMetaData(true)); } } @@ -458,8 +458,14 @@ bool JSTypedArray::IntegerIndexedElementSet(JSThread *thread, const JSHandleIsTypedArray()); - // 3. Let numValue be ToNumber(value). - JSTaggedNumber numVal = JSTaggedValue::ToNumber(thread, value); + // 3. If O.[[ContentType]] is BigInt, let numValue be ? ToBigInt(value). + JSHandle numValueHandle; + ContentType contentType = JSHandle::Cast(typedarray)->GetContentType(); + if (contentType == ContentType::BigInt) { + numValueHandle = JSHandle(thread, JSTaggedValue::ToBigInt(thread, value)); + } else { + numValueHandle = JSHandle(thread, JSTaggedValue::ToNumber(thread, value)); + } // 4. ReturnIfAbrupt(numValue). RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); @@ -511,7 +517,7 @@ bool JSTypedArray::IntegerIndexedElementSet(JSThread *thread, const JSHandleGetViewedArrayBuffer(); - BuiltinsArrayBuffer::SetValueInBuffer(buffer, byteIndex, elementType, numVal, true); + BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer, byteIndex, elementType, numValueHandle, true); } // 17. Return true. return true; diff --git a/runtime/js_typed_array.h b/runtime/js_typed_array.h index a9a4278e7..043596dbe 100644 --- a/runtime/js_typed_array.h +++ b/runtime/js_typed_array.h @@ -20,6 +20,7 @@ #include "js_object.h" namespace panda::ecmascript { +enum class ContentType : uint8_t { None = 1, Number, BigInt }; class JSTypedArray : public JSObject { public: static JSTypedArray *Cast(ObjectHeader *object) @@ -87,7 +88,8 @@ public: ACCESSORS(TypedArrayName, TYPED_ARRAY_NAME_OFFSET, BYTE_LENGTH_OFFSET) ACCESSORS(ByteLength, BYTE_LENGTH_OFFSET, BYTE_OFFSET_OFFSET) ACCESSORS(ByteOffset, BYTE_OFFSET_OFFSET, ARRAY_LENGTH_OFFSET) - ACCESSORS(ArrayLength, ARRAY_LENGTH_OFFSET, SIZE) + ACCESSORS(ArrayLength, ARRAY_LENGTH_OFFSET, CONTENT_TYPE_OFFSET) + SET_GET_PRIMITIVE_FIELD(ContentType, ContentType, CONTENT_TYPE_OFFSET, SIZE) static const uint32_t MAX_TYPED_ARRAY_INDEX = MAX_ELEMENT_INDEX; DECL_DUMP() diff --git a/runtime/literal_data_extractor.cpp b/runtime/literal_data_extractor.cpp index 9314e7166..20ea8a5a1 100644 --- a/runtime/literal_data_extractor.cpp +++ b/runtime/literal_data_extractor.cpp @@ -92,6 +92,13 @@ void LiteralDataExtractor::ExtractObjectDatas(JSThread *thread, const panda_file jt = jsFunc.GetTaggedValue(); break; } + case LiteralTag::ASYNCMETHOD: { + ASSERT(pft != nullptr); + uint32_t methodId = std::get(value); + JSHandle jsFunc = pft->DefineMethodInLiteral(methodId, FunctionKind::ASYNC_FUNCTION); + jt = jsFunc.GetTaggedValue(); + break; + } case LiteralTag::ACCESSOR: { JSHandle accessor = factory->NewAccessorData(); jt = JSTaggedValue(accessor.GetTaggedValue()); @@ -170,6 +177,13 @@ JSHandle LiteralDataExtractor::GetDatasIgnoreType(JSThread *thread, jt = jsFunc.GetTaggedValue(); break; } + case LiteralTag::ASYNCMETHOD: { + ASSERT(pft != nullptr); + uint32_t methodId = std::get(value); + JSHandle jsFunc = pft->DefineMethodInLiteral(methodId, FunctionKind::ASYNC_FUNCTION); + jt = jsFunc.GetTaggedValue(); + break; + } case LiteralTag::ACCESSOR: { JSHandle accessor = factory->NewAccessorData(); jt = accessor.GetTaggedValue(); diff --git a/runtime/mem/object_xray-inl.h b/runtime/mem/object_xray-inl.h index b1410b32c..2fc91233e 100644 --- a/runtime/mem/object_xray-inl.h +++ b/runtime/mem/object_xray-inl.h @@ -34,6 +34,7 @@ #include "plugins/ecmascript/runtime/js_async_function.h" #include "plugins/ecmascript/runtime/js_async_from_sync_iterator_object.h" #include "plugins/ecmascript/runtime/js_async_generator_object.h" +#include "plugins/ecmascript/runtime/js_bigint.h" #include "plugins/ecmascript/runtime/js_collator.h" #include "plugins/ecmascript/runtime/js_dataview.h" #include "plugins/ecmascript/runtime/js_date.h" @@ -203,6 +204,8 @@ void ObjectXRay::VisitObjectBody(TaggedObject *object, JSHClass *klass, const Ec case JSType::JS_UINT32_ARRAY: case JSType::JS_FLOAT32_ARRAY: case JSType::JS_FLOAT64_ARRAY: + case JSType::JS_BIGINT64_ARRAY: + case JSType::JS_BIGUINT64_ARRAY: JSTypedArray::Cast(object)->VisitRangeSlot(visitor); break; case JSType::JS_PRIMITIVE_REF: @@ -218,6 +221,7 @@ void ObjectXRay::VisitObjectBody(TaggedObject *object, JSHClass *klass, const Ec } break; case JSType::STRING: + case JSType::BIGINT: case JSType::JS_NATIVE_POINTER: break; case JSType::TAGGED_ARRAY: diff --git a/runtime/object_factory.cpp b/runtime/object_factory.cpp index b11d246df..b89d90349 100644 --- a/runtime/object_factory.cpp +++ b/runtime/object_factory.cpp @@ -132,13 +132,13 @@ void ObjectFactory::ObtainRootClass([[maybe_unused]] const JSHandle & string_class_ = JSHClass::Cast(globalConst->GetStringClass().GetTaggedObject()); array_class_ = JSHClass::Cast(globalConst->GetArrayClass().GetTaggedObject()); weak_array_class_ = JSHClass::Cast(globalConst->GetWeakArrayClass().GetTaggedObject()); + big_int_class_ = JSHClass::Cast(globalConst->GetBigIntClass().GetTaggedObject()); dictionary_class_ = JSHClass::Cast(globalConst->GetDictionaryClass().GetTaggedObject()); js_native_pointer_class_ = JSHClass::Cast(globalConst->GetJSNativePointerClass().GetTaggedObject()); free_object_with_none_field_class_ = JSHClass::Cast(globalConst->GetFreeObjectWithNoneFieldClass().GetTaggedObject()); free_object_with_one_field_class_ = JSHClass::Cast(globalConst->GetFreeObjectWithOneFieldClass().GetTaggedObject()); free_object_with_two_field_class_ = JSHClass::Cast(globalConst->GetFreeObjectWithTwoFieldClass().GetTaggedObject()); - completion_record_class_ = JSHClass::Cast(globalConst->GetCompletionRecordClass().GetTaggedObject()); generator_context_class_ = JSHClass::Cast(globalConst->GetGeneratorContextClass().GetTaggedObject()); program_class_ = JSHClass::Cast(globalConst->GetProgramClass().GetTaggedObject()); @@ -546,6 +546,16 @@ JSHandle ObjectFactory::NewJSArray() return JSHandle(NewJSObjectByConstructor(JSHandle(function), function)); } +JSHandle ObjectFactory::NewBigInt() +{ + NewObjectHook(); + TaggedObject *header = heap_helper_.AllocateYoungGenerationOrHugeObject(big_int_class_); + JSHandle obj(thread_, BigInt::Cast(header)); + obj->SetData(thread_, JSTaggedValue::Undefined()); + obj->SetSign(false); + return obj; +} + JSHandle ObjectFactory::NewJSForinIterator(const JSHandle &obj) { JSHandle env = vm_->GetGlobalEnv(); @@ -776,6 +786,8 @@ JSHandle ObjectFactory::NewJSObjectByConstructor(const JSHandleSetViewedArrayBuffer(thread_, JSTaggedValue::Undefined()); JSTypedArray::Cast(*obj)->SetTypedArrayName(thread_, JSTaggedValue::Undefined()); JSTypedArray::Cast(*obj)->SetByteLength(thread_, JSTaggedValue(0)); @@ -1294,6 +1306,9 @@ JSHandle ObjectFactory::NewJSPrimitiveRef(PrimitiveType type, co case PrimitiveType::PRIMITIVE_BOOLEAN: function = env->GetBooleanFunction(); break; + case PrimitiveType::PRIMITIVE_BIGINT: + function = env->GetBigIntFunction(); + break; default: break; } diff --git a/runtime/object_factory.h b/runtime/object_factory.h index 4267fdc6d..253d95d43 100644 --- a/runtime/object_factory.h +++ b/runtime/object_factory.h @@ -31,6 +31,7 @@ namespace panda::ecmascript { class JSObject; class JSArray; +class BigInt; class JSSymbol; class JSFunctionBase; class JSFunction; @@ -223,6 +224,7 @@ public: const JSHandle &data); JSHandle NewJSArray(); + JSHandle NewBigInt(); JSHandle NewJSProxy(const JSHandle &target, const JSHandle &handler); JSHandle NewJSRealm(); @@ -415,11 +417,11 @@ private: JSHClass *string_class_ {nullptr}; JSHClass *array_class_ {nullptr}; JSHClass *weak_array_class_ {nullptr}; + JSHClass *big_int_class_ {nullptr}; JSHClass *dictionary_class_ {nullptr}; JSHClass *free_object_with_none_field_class_ {nullptr}; JSHClass *free_object_with_one_field_class_ {nullptr}; JSHClass *free_object_with_two_field_class_ {nullptr}; - JSHClass *completion_record_class_ {nullptr}; JSHClass *generator_context_class_ {nullptr}; JSHClass *env_class_ {nullptr}; diff --git a/runtime/runtime_call_id.h b/runtime/runtime_call_id.h index 80ca59ba6..454fabd6f 100644 --- a/runtime/runtime_call_id.h +++ b/runtime/runtime_call_id.h @@ -20,222 +20,227 @@ namespace panda::ecmascript { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define INTERPRETER_CALLER_LIST(V) \ - V(RunInternal) \ - V(Ldnan) \ - V(Ldinfinity) \ - V(Ldglobalthis) \ - V(Ldundefined) \ - V(Ldboolean) \ - V(Ldnumber) \ - V(Ldstring) \ - V(Ldbigint) \ - V(Ldnull) \ - V(Ldsymbol) \ - V(Ldfunction) \ - V(Ldglobal) \ - V(Ldtrue) \ - V(Ldfalse) \ - V(Tonumber) \ - V(Toboolean) \ - V(Add2Dyn) \ - V(Sub2Dyn) \ - V(Mul2Dyn) \ - V(Div2Dyn) \ - V(Mod2Dyn) \ - V(EqDyn) \ - V(NotEqDyn) \ - V(LessDyn) \ - V(LessEqDyn) \ - V(GreaterDyn) \ - V(GreaterEqDyn) \ - V(StrictNotEqDyn) \ - V(StrictEqDyn) \ - V(Shl2Dyn) \ - V(Shr2Dyn) \ - V(Ashr2Dyn) \ - V(And2Dyn) \ - V(Or2Dyn) \ - V(Xor2Dyn) \ - V(NegDyn) \ - V(NotDyn) \ - V(IncDyn) \ - V(DecDyn) \ - V(ExpDyn) \ - V(ThrowDyn) \ - V(LdObjByIndexDyn) \ - V(StObjByIndexDyn) \ - V(LdObjByNameDyn) \ - V(StObjByNameDyn) \ - V(LdObjByValueDyn) \ - V(StObjByValueDyn) \ - V(StOwnByNameDyn) \ - V(StOwnByIdDyn) \ - V(StOwnByValueDyn) \ - V(Trygetobjprop) \ - V(Delobjprop) \ - V(Defineglobalvar) \ - V(Definelocalvar) \ - V(Definefuncexpr) \ - V(DefinefuncDyn) \ - V(DefineNCFuncDyn) \ - V(NewobjDynrange) \ - V(RefeqDyn) \ - V(TypeofDyn) \ - V(LdnewobjrangeDyn) \ - V(IsInDyn) \ - V(InstanceofDyn) \ - V(NewobjspreadDyn) \ - V(CallArg0Dyn) \ - V(CallArg1Dyn) \ - V(CallArg2Dyn) \ - V(CallArg3Dyn) \ - V(CallThisRangeDyn) \ - V(CallRangeDyn) \ - V(CallSpreadDyn) \ - V(NewlexenvDyn) \ - V(CopylexenvDyn) \ - V(StlexvarDyn) \ - V(LdlexvarDyn) \ - V(LdlexenvDyn) \ - V(GetPropIterator) \ - V(CreateIterResultObj) \ - V(DefineGeneratorFunc) \ - V(SuspendGenerator) \ - V(SuspendAsyncGenerator) \ - V(ResumeGenerator) \ - V(GetResumeMode) \ - V(CreateGeneratorObj) \ - V(SetGeneratorState) \ - V(CreateAsyncGeneratorObj) \ - V(DefineAsyncFunc) \ - V(DefineGetterSetterByValue) \ - V(DefineAsyncGeneratorFunc) \ - V(AsyncFunctionEnter) \ - V(AsyncFunctionAwait) \ - V(AsyncFunctionResolve) \ - V(AsyncFunctionReject) \ - V(AsyncGeneratorResolve) \ - V(AsyncGeneratorReject) \ - V(ThrowUndefined) \ - V(ThrowConstAssignment) \ - V(ThrowUndefinedIfHole) \ - V(Copyrestargs) \ - V(Trystobjprop) \ - V(GetMethod) \ - V(GetTemplateObject) \ - V(GetIterator) \ - V(GetAsyncIterator) \ - V(ThrowIfNotObject) \ - V(ThrowThrowNotExists) \ - V(CreateObjectWithExcludedKeys) \ - V(ThrowPatternNonCoercible) \ - V(IterNext) \ - V(CloseIterator) \ - V(StArraySpread) \ - V(GetCallSpreadArgs) \ - V(LoadICByName) \ - V(LoadMissedICByName) \ - V(GetPropertyByName) \ - V(LoadICByValue) \ - V(LoadMissedICByValue) \ - V(StoreICByName) \ - V(StoreMissedICByName) \ - V(StoreICByValue) \ - V(StoreMissedICByValue) \ - V(NotifyInlineCache) \ - V(CompressCollector_RunPhases) \ - V(MixSpaceCollector_RunPhases) \ - V(SemiSpaceCollector_RunPhases) \ - V(LoadGlobalICByName) \ - V(StoreGlobalICByName) \ - V(StoreICWithHandler) \ - V(StorePrototype) \ - V(StoreWithTransition) \ - V(StoreField) \ - V(StoreGlobal) \ - V(LoadPrototype) \ - V(LoadICWithHandler) \ - V(StoreElement) \ - V(CallGetter) \ - V(CallSetter) \ - V(AddPropertyByName) \ - V(AddPropertyByIndex) \ - V(GetPropertyByIndex) \ - V(GetPropertyByValue) \ - V(SetPropertyByIndex) \ - V(SetPropertyByValue) \ - V(FastTypeOf) \ - V(FastSetPropertyByIndex) \ - V(FastSetPropertyByValue) \ - V(FastGetPropertyByName) \ - V(FastGetPropertyByValue) \ - V(FastGetPropertyByIndex) \ - V(NewLexicalEnvDyn) \ - V(SetElement) \ - V(SetGlobalOwnProperty) \ - V(SetOwnPropertyByName) \ - V(SetOwnElement) \ - V(FastSetProperty) \ - V(FastGetProperty) \ - V(FindOwnProperty) \ - V(HasOwnProperty) \ - V(ExecuteNative) \ - V(Execute) \ - V(ToJSTaggedValueWithInt32) \ - V(ToJSTaggedValueWithUint32) \ - V(ThrowIfSuperNotCorrectCall) \ - V(CreateEmptyArray) \ - V(CreateEmptyObject) \ - V(CreateObjectWithBuffer) \ - V(CreateObjectHavingMethod) \ - V(SetObjectWithProto) \ - V(ImportModule) \ - V(StModuleVar) \ - V(CopyModule) \ - V(LdModvarByName) \ - V(CreateRegExpWithLiteral) \ - V(CreateArrayWithBuffer) \ - V(GetNextPropName) \ - V(CopyDataProperties) \ - V(GetUnmapedArgs) \ - V(TryStGlobalByName) \ - V(LdGlobalVar) \ - V(StGlobalVar) \ - V(TryUpdateGlobalRecord) \ - V(LdGlobalRecord) \ - V(StGlobalRecord) \ - V(ThrowReferenceError) \ - V(ThrowTypeError) \ - V(ThrowSyntaxError) \ - V(NewClassFunc) \ - V(DefineClass) \ - V(SuperCall) \ - V(SuperCallSpread) \ - V(DefineMethod) \ - V(LdSuperByValue) \ - V(StSuperByValue) \ - V(ThrowDeleteSuperProperty) \ - V(GetIteratorNext) \ - V(ModWithTSType) \ - V(MulWithTSType) \ - V(SubWithTSType) \ - V(DivWithTSType) \ - V(AddWithTSType) \ - V(GetBitOPDate) \ - V(ShlWithTSType) \ - V(ShrWithTSType) \ - V(AshrWithTSType) \ - V(AndWithTSType) \ - V(OrWithTSType) \ - V(XorWithTSType) \ - V(EqualWithIC) \ - V(NotEqualWithIC) \ - V(Compare) \ - V(LessDynWithIC) \ - V(LessEqDynWithIC) \ - V(GreaterDynWithIC) \ - V(GreaterEqDynWithIC) \ +#define INTERPRETER_CALLER_LIST(V) \ + V(RunInternal) \ + V(Ldnan) \ + V(Ldinfinity) \ + V(Ldglobalthis) \ + V(Ldundefined) \ + V(Ldboolean) \ + V(Ldnumber) \ + V(Ldstring) \ + V(Ldbigint) \ + V(Ldnull) \ + V(Ldsymbol) \ + V(Ldfunction) \ + V(Ldglobal) \ + V(Ldtrue) \ + V(Ldfalse) \ + V(Tonumber) \ + V(Toboolean) \ + V(Add2Dyn) \ + V(Sub2Dyn) \ + V(Mul2Dyn) \ + V(Div2Dyn) \ + V(Mod2Dyn) \ + V(EqDyn) \ + V(NotEqDyn) \ + V(LessDyn) \ + V(LessEqDyn) \ + V(GreaterDyn) \ + V(GreaterEqDyn) \ + V(StrictNotEqDyn) \ + V(StrictEqDyn) \ + V(Shl2Dyn) \ + V(Shr2Dyn) \ + V(Ashr2Dyn) \ + V(And2Dyn) \ + V(Or2Dyn) \ + V(Xor2Dyn) \ + V(NegDyn) \ + V(NotDyn) \ + V(IncDyn) \ + V(DecDyn) \ + V(ExpDyn) \ + V(ThrowDyn) \ + V(LdObjByIndexDyn) \ + V(StObjByIndexDyn) \ + V(LdObjByNameDyn) \ + V(StObjByNameDyn) \ + V(LdObjByValueDyn) \ + V(StObjByValueDyn) \ + V(StOwnByNameDyn) \ + V(StOwnByIdDyn) \ + V(StOwnByValueDyn) \ + V(Trygetobjprop) \ + V(Delobjprop) \ + V(Defineglobalvar) \ + V(Definelocalvar) \ + V(Definefuncexpr) \ + V(DefinefuncDyn) \ + V(DefineNCFuncDyn) \ + V(NewobjDynrange) \ + V(RefeqDyn) \ + V(TypeofDyn) \ + V(LdnewobjrangeDyn) \ + V(IsInDyn) \ + V(InstanceofDyn) \ + V(NewobjspreadDyn) \ + V(CallArg0Dyn) \ + V(CallArg1Dyn) \ + V(CallArg2Dyn) \ + V(CallArg3Dyn) \ + V(CallThisRangeDyn) \ + V(CallRangeDyn) \ + V(CallSpreadDyn) \ + V(NewlexenvDyn) \ + V(CopylexenvDyn) \ + V(StLexVarDyn) \ + V(StLexDyn) \ + V(LdLexVarDyn) \ + V(LdLexDyn) \ + V(LdlexenvDyn) \ + V(GetPropIterator) \ + V(CreateIterResultObj) \ + V(DefineGeneratorFunc) \ + V(SuspendGenerator) \ + V(SuspendAsyncGenerator) \ + V(ResumeGenerator) \ + V(GetResumeMode) \ + V(CreateGeneratorObj) \ + V(SetGeneratorState) \ + V(CreateAsyncGeneratorObj) \ + V(DefineAsyncFunc) \ + V(DefineGetterSetterByValue) \ + V(DefineAsyncGeneratorFunc) \ + V(AsyncFunctionEnter) \ + V(AsyncFunctionAwait) \ + V(AsyncFunctionResolve) \ + V(AsyncFunctionReject) \ + V(AsyncGeneratorResolve) \ + V(AsyncGeneratorReject) \ + V(ThrowUndefined) \ + V(ThrowConstAssignment) \ + V(ThrowTdz) \ + V(Copyrestargs) \ + V(Trystobjprop) \ + V(GetMethod) \ + V(GetTemplateObject) \ + V(GetIterator) \ + V(GetAsyncIterator) \ + V(ThrowIfNotObject) \ + V(ThrowThrowNotExists) \ + V(CreateObjectWithExcludedKeys) \ + V(ThrowPatternNonCoercible) \ + V(IterNext) \ + V(CloseIterator) \ + V(StArraySpread) \ + V(GetCallSpreadArgs) \ + V(LoadICByName) \ + V(LoadMissedICByName) \ + V(GetPropertyByName) \ + V(LoadICByValue) \ + V(LoadMissedICByValue) \ + V(StoreICByName) \ + V(StoreMissedICByName) \ + V(StoreICByValue) \ + V(StoreMissedICByValue) \ + V(NotifyInlineCache) \ + V(CompressCollector_RunPhases) \ + V(MixSpaceCollector_RunPhases) \ + V(SemiSpaceCollector_RunPhases) \ + V(LoadGlobalICByName) \ + V(StoreGlobalICByName) \ + V(StoreICWithHandler) \ + V(StorePrototype) \ + V(StoreWithTransition) \ + V(StoreField) \ + V(StoreGlobal) \ + V(LoadPrototype) \ + V(LoadICWithHandler) \ + V(StoreElement) \ + V(CallGetter) \ + V(CallSetter) \ + V(AddPropertyByName) \ + V(AddPropertyByIndex) \ + V(GetPropertyByIndex) \ + V(GetPropertyByValue) \ + V(SetPropertyByIndex) \ + V(SetPropertyByValue) \ + V(FastTypeOf) \ + V(FastSetPropertyByIndex) \ + V(FastSetPropertyByValue) \ + V(FastGetPropertyByName) \ + V(FastGetPropertyByValue) \ + V(FastGetPropertyByIndex) \ + V(NewLexicalEnvDyn) \ + V(SetElement) \ + V(SetGlobalOwnProperty) \ + V(SetOwnPropertyByName) \ + V(SetOwnElement) \ + V(FastSetProperty) \ + V(FastGetProperty) \ + V(FindOwnProperty) \ + V(HasOwnProperty) \ + V(ExecuteNative) \ + V(Execute) \ + V(ToJSTaggedValueWithInt32) \ + V(ToJSTaggedValueWithUint32) \ + V(ThrowIfSuperNotCorrectCall) \ + V(CreateEmptyArray) \ + V(CreateEmptyObject) \ + V(CreateObjectWithBuffer) \ + V(CreateObjectHavingMethod) \ + V(SetObjectWithProto) \ + V(ImportModule) \ + V(StModuleVar) \ + V(CopyModule) \ + V(LdModvarByName) \ + V(CreateRegExpWithLiteral) \ + V(CreateArrayWithBuffer) \ + V(GetNextPropName) \ + V(CopyDataProperties) \ + V(GetUnmapedArgs) \ + V(TryStGlobalByName) \ + V(LdGlobalVar) \ + V(StGlobalVar) \ + V(ThrowReferenceError) \ + V(ThrowTypeError) \ + V(ThrowSyntaxError) \ + V(NewClassFunc) \ + V(ClassFieldAdd) \ + V(DefineClassPrivateFields) \ + V(ClassPrivateMethodOrAccessorAdd) \ + V(ClassPrivateFieldAdd) \ + V(ClassPrivateFieldGet) \ + V(ClassPrivateFieldSet) \ + V(ClassPrivateFieldIn) \ + V(SuperCall) \ + V(SuperCallSpread) \ + V(DefineMethod) \ + V(LdSuperByValue) \ + V(StSuperByValue) \ + V(ThrowDeleteSuperProperty) \ + V(GetIteratorNext) \ + V(ModWithTSType) \ + V(MulWithTSType) \ + V(SubWithTSType) \ + V(DivWithTSType) \ + V(AddWithTSType) \ + V(GetBitOPDate) \ + V(ShlWithTSType) \ + V(ShrWithTSType) \ + V(AshrWithTSType) \ + V(AndWithTSType) \ + V(OrWithTSType) \ + V(XorWithTSType) \ + V(EqualWithIC) \ + V(NotEqualWithIC) \ + V(Compare) \ + V(LessDynWithIC) \ + V(LessEqDynWithIC) \ + V(GreaterDynWithIC) \ + V(GreaterEqDynWithIC) \ V(SetPropertyByName) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define BUITINS_API_LIST(V) \ @@ -400,6 +405,13 @@ namespace panda::ecmascript { V(Number, ToString) \ V(Number, ValueOf) \ V(Number, ThisNumberValue) \ + V(BigInt, Constructor) \ + V(BigInt, AsUintN) \ + V(BigInt, AsIntN) \ + V(BigInt, ToLocaleString) \ + V(BigInt, ToString) \ + V(BigInt, ValueOf) \ + V(BigInt, ThisBigIntValue) \ V(Object, Constructor) \ V(Object, Assign) \ V(Object, Create) \ diff --git a/runtime/runtime_sources.gn b/runtime/runtime_sources.gn index 1d47ca330..e63c2f349 100644 --- a/runtime/runtime_sources.gn +++ b/runtime/runtime_sources.gn @@ -31,6 +31,7 @@ srcs = [ "builtins/builtins_async_function.cpp", "builtins/builtins_async_generator.cpp", "builtins/builtins_async_iterator.cpp", + "builtins/builtins_bigint.cpp", "builtins/builtins_boolean.cpp", "builtins/builtins_dataview.cpp", "builtins/builtins_date.cpp", @@ -93,8 +94,10 @@ srcs = [ "js_async_from_sync_iterator_object.cpp", "js_async_function.cpp", "js_async_generator_object.cpp", + "js_bigint.cpp", "js_dataview.cpp", "js_date.cpp", + "js_eval.cpp", "js_for_in_iterator.cpp", "js_function.cpp", "js_generator_object.cpp", diff --git a/subproject_sources.gn b/subproject_sources.gn index c081de6b9..c955c50ee 100644 --- a/subproject_sources.gn +++ b/subproject_sources.gn @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("//ark/runtime_core/ark_config.gni") + srcs_assembler_path = "assembler/assembler_sources.gn" srcs_isa_path = "isa/isa_sources.gn" srcs_runtime_path = "runtime/runtime_sources.gn" @@ -36,4 +38,12 @@ arkbytecodeopt_deps = [ arkruntime_deps = [ "../../ark-third-party/icu:shared_icui18n", "../../ark-third-party/icu:shared_icuuc", + "../../assembler:libarkassembler_frontend_static", + "../../libpandafile:libarkfile_frontend_static", + "es2panda:libes2panda_frontend_static", +] +arkruntime_sub_configs = [ + "es2panda:libes2panda_public_config", + "../../assembler:arkassembler_public_config", + "../../libpandafile:arkfile_public_config", ] diff --git a/tests/runtime/CMakeLists.txt b/tests/runtime/CMakeLists.txt index 7b85cf8da..5bce15871 100644 --- a/tests/runtime/CMakeLists.txt +++ b/tests/runtime/CMakeLists.txt @@ -55,6 +55,7 @@ set(ECMASCRIPT_TAGGEDVALUE_TESTS_SOURCES set(ECMASCRIPT_BUILTINS_BASIC_TESTS_SOURCES common/builtins_test.cpp + builtins/builtins_bigint_test.cpp builtins/builtins_boolean_test.cpp builtins/builtins_symbol_test.cpp builtins/builtins_set_test.cpp @@ -232,7 +233,7 @@ if(TARGET arkruntime4ecmascript_builtins_basic_tests) target_include_directories(arkruntime4ecmascript_builtins_basic_tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) - target_compile_options(arkruntime4ecmascript_builtins_basic_tests PUBLIC "-Wno-ignored-attributes") + target_compile_options(arkruntime4ecmascript_builtins_basic_tests PUBLIC "-Wno-ignored-attributes" "-DICU_PATH=\"${ICU_ROOT}/ohos_icu4j/data\"") endif() #3.1 panda_add_gtest( diff --git a/tests/runtime/builtins/builtins_bigint_test.cpp b/tests/runtime/builtins/builtins_bigint_test.cpp new file mode 100644 index 000000000..8b7efd23f --- /dev/null +++ b/tests/runtime/builtins/builtins_bigint_test.cpp @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugins/ecmascript/runtime/builtins/builtins_bigint.h" +#include "plugins/ecmascript/runtime/global_env.h" +#include "plugins/ecmascript/runtime/js_bigint.h" +#include "plugins/ecmascript/runtime/js_primitive_ref.h" +#include "plugins/ecmascript/tests/runtime/common/test_helper.h" + +using namespace panda::ecmascript; +using namespace panda::ecmascript::builtins; +using BuiltinsBase = panda::ecmascript::base::BuiltinsBase; + +namespace panda::test { +using BigInt = ecmascript::BigInt; +class BuiltinsBigIntTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + } + + void TearDown() override + { + TestHelper::DestroyEcmaVMWithScope(instance, scope); + } + + PandaVM *instance {nullptr}; + EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; + +private: + ecmascript::JSHandle methodFunction_; +}; + +// new BigInt(123) +TEST_F(BuiltinsBigIntTest, BigIntConstructor1) +{ + JSHandle numericValue(thread, JSTaggedValue(123)); + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get()); + JSTaggedValue result = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result.IsBigInt()); +} + +// new BigInt("456") +TEST_F(BuiltinsBigIntTest, BigIntConstructor2) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("456"); + + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get()); + JSTaggedValue result = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result.IsBigInt()); +} + +// AsIntN(64, (2 ^ 63 - 1)) +TEST_F(BuiltinsBigIntTest, AsIntN1) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("9223372036854775807"); + int bit = 64; // 64-bit + + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast(bit))); + ecmaRuntimeCallInfo->SetCallArg(1, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get()); + JSTaggedValue result = BuiltinsBigInt::AsIntN(ecmaRuntimeCallInfo.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result.IsBigInt()); + JSHandle bigIntHandle(thread, result); + JSHandle resultStr = BigInt::ToString(thread, bigIntHandle); + JSHandle str = factory->NewFromCanBeCompressString("9223372036854775807"); + EXPECT_EQ(resultStr->Compare(*str), 0); +} + +// AsIntN(64, (2 ^ 63)) +TEST_F(BuiltinsBigIntTest, AsIntN2) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("9223372036854775808"); + int bit = 64; // 64-bit + + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast(bit))); + ecmaRuntimeCallInfo->SetCallArg(1, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get()); + JSTaggedValue result = BuiltinsBigInt::AsIntN(ecmaRuntimeCallInfo.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result.IsBigInt()); + JSHandle bigIntHandle(thread, result); + JSHandle resultStr = BigInt::ToString(thread, bigIntHandle); + JSHandle str = factory->NewFromCanBeCompressString("-9223372036854775808"); + EXPECT_EQ(resultStr->Compare(*str), 0); +} + +// AsUintN(64, (2 ^ 64 - 1)) +TEST_F(BuiltinsBigIntTest, AsUintN1) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("18446744073709551615"); + int bit = 64; // 64-bit + + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast(bit))); + ecmaRuntimeCallInfo->SetCallArg(1, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get()); + JSTaggedValue result = BuiltinsBigInt::AsUintN(ecmaRuntimeCallInfo.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result.IsBigInt()); + JSHandle bigIntHandle(thread, result); + JSHandle resultStr = BigInt::ToString(thread, bigIntHandle); + JSHandle str = factory->NewFromCanBeCompressString("18446744073709551615"); + EXPECT_EQ(resultStr->Compare(*str), 0); +} + +// AsUintN(64, (2 ^ 64)) +TEST_F(BuiltinsBigIntTest, AsUintN2) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("18446744073709551616"); + int bit = 64; // 64-bit + + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast(bit))); + ecmaRuntimeCallInfo->SetCallArg(1, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get()); + JSTaggedValue result = BuiltinsBigInt::AsUintN(ecmaRuntimeCallInfo.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result.IsBigInt()); + JSHandle bigIntHandle(thread, result); + JSHandle resultStr = BigInt::ToString(thread, bigIntHandle); + JSHandle str = factory->NewFromCanBeCompressString("0"); + EXPECT_EQ(resultStr->Compare(*str), 0); +} + +// using locale +TEST_F(BuiltinsBigIntTest, ToLocaleString1) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("123456789123456789"); + + auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get()); + JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1.get()); + TestHelper::TearDownFrame(thread, prev); + + JSHandle bigIntHandle(thread, result1); + JSHandle locale = factory->NewFromCanBeCompressString("de-DE"); + + auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); + ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue()); + ecmaRuntimeCallInfo2->SetCallArg(0, locale.GetTaggedValue()); + ecmaRuntimeCallInfo2->SetCallArg(1, JSTaggedValue::Undefined()); + + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2.get()); + JSTaggedValue result2 = BuiltinsBigInt::ToLocaleString(ecmaRuntimeCallInfo2.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result2.IsString()); + JSHandle ecmaStrHandle(thread, result2); + JSHandle resultStr = factory->NewFromCanBeCompressString("123.456.789.123.456.789"); + EXPECT_EQ(ecmaStrHandle->Compare(*resultStr), 0); +} + +// using locale and options +TEST_F(BuiltinsBigIntTest, ToLocaleString2) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + JSHandle objFun = env->GetObjectFunction(); + JSHandle optionsObj = factory->NewJSObjectByConstructor(JSHandle(objFun), objFun); + JSHandle numericValue = factory->NewFromCanBeCompressString("123456789123456789"); + JSHandle formatStyle = thread->GlobalConstants()->GetHandledStyleString(); + JSHandle styleKey(factory->NewFromCanBeCompressString("currency")); + JSHandle styleValue(factory->NewFromCanBeCompressString("EUR")); + + auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get()); + JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1.get()); + TestHelper::TearDownFrame(thread, prev); + + JSHandle bigIntHandle(thread, result1); + JSHandle locale = factory->NewFromCanBeCompressString("de-DE"); + JSObject::SetProperty(thread, optionsObj, formatStyle, styleKey); + JSObject::SetProperty(thread, optionsObj, styleKey, styleValue); + + auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); + ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue()); + ecmaRuntimeCallInfo2->SetCallArg(0, locale.GetTaggedValue()); + ecmaRuntimeCallInfo2->SetCallArg(1, optionsObj.GetTaggedValue()); + + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2.get()); + JSTaggedValue result2 = BuiltinsBigInt::ToLocaleString(ecmaRuntimeCallInfo2.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result2.IsString()); + JSHandle ecmaStrHandle(thread, result2); + EXPECT_STREQ("123.456.789.123.456.789,00 €", PandaString(ecmaStrHandle->GetCString().get()).c_str()); +} + +// 17.ToStirng() +TEST_F(BuiltinsBigIntTest, ToString1) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("17"); + + auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get()); + JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1.get()); + TestHelper::TearDownFrame(thread, prev); + + JSHandle bigIntHandle(thread, result1); + auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue()); + ecmaRuntimeCallInfo2->SetCallArg(0, JSTaggedValue::Undefined()); + + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2.get()); + JSTaggedValue result2 = BuiltinsBigInt::ToString(ecmaRuntimeCallInfo2.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result2.IsString()); + JSHandle ecmaStrHandle(thread, result2); + EXPECT_STREQ("17", PandaString(ecmaStrHandle->GetCString().get()).c_str()); +} + +// -0.ToStirng() +TEST_F(BuiltinsBigIntTest, ToString2) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("-0"); + + auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get()); + JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1.get()); + TestHelper::TearDownFrame(thread, prev); + + JSHandle bigIntHandle(thread, result1); + auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue()); + ecmaRuntimeCallInfo2->SetCallArg(0, JSTaggedValue::Undefined()); + + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2.get()); + JSTaggedValue result2 = BuiltinsBigInt::ToString(ecmaRuntimeCallInfo2.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result2.IsString()); + JSHandle ecmaStrHandle(thread, result2); + EXPECT_STREQ("0", PandaString(ecmaStrHandle->GetCString().get()).c_str()); +} + +// -10.ToStirng(2) +TEST_F(BuiltinsBigIntTest, ToString3) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("-10"); + + auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get()); + JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1.get()); + TestHelper::TearDownFrame(thread, prev); + + JSHandle bigIntHandle(thread, result1); + JSHandle radix(thread, JSTaggedValue(2)); + auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue()); + ecmaRuntimeCallInfo2->SetCallArg(0, radix.GetTaggedValue()); + + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2.get()); + JSTaggedValue result2 = BuiltinsBigInt::ToString(ecmaRuntimeCallInfo2.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result2.IsString()); + JSHandle ecmaStrHandle(thread, result2); + EXPECT_STREQ("-1010", PandaString(ecmaStrHandle->GetCString().get()).c_str()); +} + +// 254.ToStirng(16) +TEST_F(BuiltinsBigIntTest, ToString4) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("254"); + + auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get()); + JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1.get()); + TestHelper::TearDownFrame(thread, prev); + + JSHandle bigIntHandle(thread, result1); + JSHandle radix(thread, JSTaggedValue(16)); + auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue()); + ecmaRuntimeCallInfo2->SetCallArg(0, radix.GetTaggedValue()); + + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2.get()); + JSTaggedValue result2 = BuiltinsBigInt::ToString(ecmaRuntimeCallInfo2.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_TRUE(result2.IsString()); + JSHandle ecmaStrHandle(thread, result2); + EXPECT_STREQ("fe", PandaString(ecmaStrHandle->GetCString().get()).c_str()); +} + +// BigInt.ValueOf +TEST_F(BuiltinsBigIntTest, ValueOf1) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("-65536"); + + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get()); + JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo.get()); + TestHelper::TearDownFrame(thread, prev); + + JSHandle bigIntHandle(thread, result1); + auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); + ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue()); + + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2.get()); + JSTaggedValue result2 = BuiltinsBigInt::ValueOf(ecmaRuntimeCallInfo2.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(BigInt::SameValue(thread, result1, result2), true); +} + +// Object.ValueOf +TEST_F(BuiltinsBigIntTest, ValueOf2) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle numericValue = factory->NewFromCanBeCompressString("65535"); + + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetCallArg(0, numericValue.GetTaggedValue()); + + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get()); + JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo.get()); + TestHelper::TearDownFrame(thread, prev); + + JSHandle bigIntHandle(thread, result1); + JSHandle bigIntObj(bigIntHandle); + + JSHandle jsPrimitiveRef = factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, bigIntObj); + auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); + ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo2->SetThis(jsPrimitiveRef.GetTaggedValue()); + + prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2.get()); + JSTaggedValue result2 = BuiltinsBigInt::ValueOf(ecmaRuntimeCallInfo2.get()); + TestHelper::TearDownFrame(thread, prev); + + EXPECT_EQ(BigInt::SameValue(thread, bigIntHandle.GetTaggedValue(), result2), true); +} + +// testcases of NumberToBigint() +TEST_F(BuiltinsBigIntTest, NumberToBigint) +{ + JSHandle number(thread, JSTaggedValue::Undefined()); + JSHandle bigint(thread, JSTaggedValue::Undefined()); + + number = JSHandle(thread, JSTaggedValue(base::MAX_VALUE)); + bigint = JSHandle(thread, BigInt::NumberToBigInt(thread, number)); + ASSERT_TRUE(bigint->IsBigInt()); + bool compareRes = JSTaggedValue::Equal(thread, number, bigint); + ASSERT_TRUE(compareRes); + + number = JSHandle(thread, JSTaggedValue(-base::MAX_VALUE)); + bigint = JSHandle(thread, BigInt::NumberToBigInt(thread, number)); + ASSERT_TRUE(bigint->IsBigInt()); + compareRes = JSTaggedValue::Equal(thread, number, bigint); + ASSERT_TRUE(JSHandle::Cast(bigint)->GetSign()); + ASSERT_TRUE(compareRes); + + number = JSHandle(thread, JSTaggedValue(-0xffffffff)); + bigint = JSHandle(thread, BigInt::NumberToBigInt(thread, number)); + ASSERT_TRUE(bigint->IsBigInt()); + compareRes = JSTaggedValue::Equal(thread, number, bigint); + ASSERT_TRUE(compareRes); + + number = JSHandle(thread, JSTaggedValue(0)); + bigint = JSHandle(thread, BigInt::NumberToBigInt(thread, number)); + ASSERT_TRUE(bigint->IsBigInt()); + compareRes = JSTaggedValue::Equal(thread, number, bigint); + ASSERT_TRUE(compareRes); +} + +// testcases of BigintToNumber() +TEST_F(BuiltinsBigIntTest, BigintToNumber) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle bigint(thread, JSTaggedValue::Undefined()); + JSTaggedNumber number(0); + + JSHandle parma(factory->NewFromCanBeCompressString("0xffff")); + bigint = JSHandle(thread, JSTaggedValue::ToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + number = BigInt::BigIntToNumber(JSHandle::Cast(bigint)); + ASSERT_EQ(number.GetNumber(), static_cast(0xffff)); + + parma = JSHandle( + factory->NewFromCanBeCompressString("0xfffffffffffff8000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000")); + bigint = JSHandle(thread, JSTaggedValue::ToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + number = BigInt::BigIntToNumber(JSHandle::Cast(bigint)); + ASSERT_EQ(number.GetNumber(), base::MAX_VALUE); + + parma = JSHandle(thread, JSTaggedValue::False()); + bigint = JSHandle(thread, JSTaggedValue::ToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + ASSERT_TRUE(JSHandle::Cast(bigint)->IsZero()); + number = BigInt::BigIntToNumber(JSHandle::Cast(bigint)); + ASSERT_EQ(number.GetNumber(), 0.0); + + parma = JSHandle(thread, JSTaggedValue(base::MAX_VALUE)); + bigint = JSHandle(thread, BigInt::NumberToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + number = BigInt::BigIntToNumber(JSHandle::Cast(bigint)); + ASSERT_EQ(number.GetNumber(), base::MAX_VALUE); + + parma = JSHandle(thread, JSTaggedValue(-base::MAX_VALUE)); + bigint = JSHandle(thread, BigInt::NumberToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + number = BigInt::BigIntToNumber(JSHandle::Cast(bigint)); + ASSERT_EQ(number.GetNumber(), -base::MAX_VALUE); + + /* + // clang-14 with ASAN release - Illegal instruction (core dumped) + parma = JSHandle(thread, JSTaggedValue(-0xffffffff)); + bigint = JSHandle(thread, BigInt::NumberToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + number = BigInt::BigIntToNumber(JSHandle::Cast(bigint)); + ASSERT_EQ(number.GetNumber(), -0xffffffff); + */ +} + +// testcases of StringToBigInt(EcmaString) +TEST_F(BuiltinsBigIntTest, StringToBigInt) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle bigint; + JSHandle str; + JSHandle parma; + + // hex string + parma = JSHandle(factory->NewFromCanBeCompressString("0xffff")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + str = BigInt::ToString(thread, JSHandle::Cast(bigint), BigInt::HEXADECIMAL); + parma = JSHandle(factory->NewFromCanBeCompressString("ffff")); + ASSERT_EQ(str->Compare(reinterpret_cast(parma->GetRawData())), 0); + + parma = JSHandle(factory->NewFromCanBeCompressString("0XFFFF")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + str = BigInt::ToString(thread, JSHandle::Cast(bigint), BigInt::HEXADECIMAL); + parma = JSHandle(factory->NewFromCanBeCompressString("ffff")); + ASSERT_EQ(str->Compare(reinterpret_cast(parma->GetRawData())), 0); + + // binary string + parma = JSHandle(factory->NewFromCanBeCompressString("0b11111111")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + str = BigInt::ToString(thread, JSHandle::Cast(bigint), BigInt::BINARY); + parma = JSHandle(factory->NewFromCanBeCompressString("11111111")); + ASSERT_EQ(str->Compare(reinterpret_cast(parma->GetRawData())), 0); + + parma = JSHandle(factory->NewFromCanBeCompressString("0B11111111")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + str = BigInt::ToString(thread, JSHandle::Cast(bigint), BigInt::BINARY); + parma = JSHandle(factory->NewFromCanBeCompressString("11111111")); + ASSERT_EQ(str->Compare(reinterpret_cast(parma->GetRawData())), 0); + + // octal string + parma = JSHandle(factory->NewFromCanBeCompressString("0o123456")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + str = BigInt::ToString(thread, JSHandle::Cast(bigint), BigInt::OCTAL); + parma = JSHandle(factory->NewFromCanBeCompressString("123456")); + ASSERT_EQ(str->Compare(reinterpret_cast(parma->GetRawData())), 0); + + parma = JSHandle(factory->NewFromCanBeCompressString("0O123456")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + str = BigInt::ToString(thread, JSHandle::Cast(bigint), BigInt::OCTAL); + parma = JSHandle(factory->NewFromCanBeCompressString("123456")); + ASSERT_EQ(str->Compare(reinterpret_cast(parma->GetRawData())), 0); + + // decimal string + parma = JSHandle(factory->NewFromCanBeCompressString("999999999")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + str = BigInt::ToString(thread, JSHandle::Cast(bigint)); + ASSERT_EQ(str->Compare(reinterpret_cast(parma->GetRawData())), 0); + + // string has space + parma = JSHandle(factory->NewFromCanBeCompressString(" 123 ")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + JSHandle number(thread, JSTaggedValue(static_cast(123))); + bool compareRes = JSTaggedValue::Equal(thread, bigint, number); + ASSERT_TRUE(compareRes); + + parma = JSHandle(factory->NewFromCanBeCompressString("123 ")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + number = JSHandle(thread, JSTaggedValue(static_cast(123))); + compareRes = JSTaggedValue::Equal(thread, bigint, number); + ASSERT_TRUE(compareRes); + + parma = JSHandle(factory->NewFromCanBeCompressString(" 123")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + number = JSHandle(thread, JSTaggedValue(static_cast(123))); + compareRes = JSTaggedValue::Equal(thread, bigint, number); + ASSERT_TRUE(compareRes); + + parma = JSHandle(factory->NewFromCanBeCompressString("")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + ASSERT_TRUE(JSHandle::Cast(bigint)->IsZero()); + + parma = JSHandle(factory->NewFromCanBeCompressString(" ")); + bigint = JSHandle(thread, base::NumberHelper::StringToBigInt(thread, parma)); + ASSERT_TRUE(bigint->IsBigInt()); + ASSERT_TRUE(JSHandle::Cast(bigint)->IsZero()); +} +} // namespace panda::test diff --git a/tests/runtime/common/js_serializer_test.cpp b/tests/runtime/common/js_serializer_test.cpp index 84c9fc623..049d88579 100644 --- a/tests/runtime/common/js_serializer_test.cpp +++ b/tests/runtime/common/js_serializer_test.cpp @@ -824,8 +824,10 @@ TEST_F(JSSerializerTest, SerializeJSArrayBuffer) thread->GetEcmaVM()->GetFactory()->NewJSArrayBufferData(jsArrayBuffer, byteLength); jsArrayBuffer->SetArrayBufferByteLength(thread, JSTaggedValue(static_cast(byteLength))); JSHandle obj = JSHandle(jsArrayBuffer); - BuiltinsArrayBuffer::SetValueInBuffer(obj.GetTaggedValue(), 1, DataViewType::UINT8, JSTaggedNumber(7), true); - BuiltinsArrayBuffer::SetValueInBuffer(obj.GetTaggedValue(), 3, DataViewType::UINT8, JSTaggedNumber(17), true); + JSHandle number(thread, JSTaggedValue(7)); + BuiltinsArrayBuffer::SetValueInBuffer(thread, obj.GetTaggedValue(), 1, DataViewType::UINT8, number, true); + number = JSHandle(thread, JSTaggedValue(17)); + BuiltinsArrayBuffer::SetValueInBuffer(thread, obj.GetTaggedValue(), 3, DataViewType::UINT8, number, true); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(jsArrayBuffer)); @@ -919,9 +921,11 @@ JSArrayBuffer *CreateTestJSArrayBuffer(JSThread *thread) jsArrayBuffer->SetArrayBufferByteLength(thread, JSTaggedValue(static_cast(byteLength))); JSHandle obj = JSHandle(jsArrayBuffer); // 7 : test case - BuiltinsArrayBuffer::SetValueInBuffer(obj.GetTaggedValue(), 1, DataViewType::UINT8, JSTaggedNumber(7), true); + JSHandle number(thread, JSTaggedValue(7)); + BuiltinsArrayBuffer::SetValueInBuffer(thread, obj.GetTaggedValue(), 1, DataViewType::UINT8, number, true); // 3, 17 : test case - BuiltinsArrayBuffer::SetValueInBuffer(obj.GetTaggedValue(), 3, DataViewType::UINT8, JSTaggedNumber(17), true); + number = JSHandle(thread, JSTaggedValue(17)); + BuiltinsArrayBuffer::SetValueInBuffer(thread, obj.GetTaggedValue(), 3, DataViewType::UINT8, number, true); return *jsArrayBuffer; } diff --git a/tests/runtime/common/test_helper.h b/tests/runtime/common/test_helper.h index d2a0662a2..95661a0ef 100644 --- a/tests/runtime/common/test_helper.h +++ b/tests/runtime/common/test_helper.h @@ -45,6 +45,9 @@ public: bool enter_managed_code = true) { RuntimeOptions options; +#if defined(ICU_PATH) + options.SetIcuDataPath(ICU_PATH); +#endif options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); options.SetLoadRuntimes({"ecmascript"}); diff --git a/tests/runtime/tooling/js/GetVariable.js b/tests/runtime/tooling/js/GetVariable.js index 3b9d5c201..3a5340b41 100644 --- a/tests/runtime/tooling/js/GetVariable.js +++ b/tests/runtime/tooling/js/GetVariable.js @@ -13,15 +13,15 @@ * limitations under the License. */ -function getVariable(bl1, bl2, i1, i2, d, obj) { +let getVariable = function(bl1, bl2, i1, i2, d, obj) { // check variables in native code // ! use variables here for correct debug info return (bl1 + bl2 + i1 + i2 + d + obj); } getVariable( - false, true, - -2147483648, 2147483647, + false, true, + -2147483648, 2147483647, 1.5, "new_string" ); -- Gitee