diff --git a/compiler/intrinsics_type_resolving_ecmascript.cpp b/compiler/intrinsics_type_resolving_ecmascript.cpp index 65b63c9807a4f5ac4576e0395cfde166888013c2..c5cae8209aa4b9c414b76653b177890f8eac3730 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.cpp +++ b/compiler/intrinsics_type_resolving_ecmascript.cpp @@ -166,6 +166,47 @@ Inst *InsertLoadObject(Inst *input, uint32_t type_id, RuntimeInterface::MethodPt return load_object; } +void InsertCheckJSArrayLength(Inst *obj, Inst *index, Inst *insert_after, RuntimeInterface::MethodPtr method, + uint32_t pc) +{ + auto curr_bb = insert_after->GetBasicBlock(); + auto graph = curr_bb->GetGraph(); + // Insert Load Object length field for JsArray object + auto length = InsertLoadObject(obj, TypeIdMixin::MEM_DYN_ARRAY_LENGTH_ID, method, pc, nullptr, + ObjectType::MEM_DYN_ARRAY_LENGTH, insert_after, DataType::INT32); + + auto cmp_inst = graph->CreateInstCompare(DataType::BOOL, pc, ConditionCode::CC_LT); + auto if_inst = graph->CreateInstIfImm(DataType::BOOL, pc, ConditionCode::CC_NE, 0); + cmp_inst->SetInput(0, index); + cmp_inst->SetInput(1, length); + cmp_inst->SetOperandsType(DataType::INT32); + if_inst->SetInput(0, cmp_inst); + if_inst->SetOperandsType(DataType::BOOL); + length->InsertAfter(cmp_inst); + cmp_inst->InsertAfter(if_inst); + // Split block by call instruction + auto curr_cont_bb = curr_bb->SplitBlockAfterInstruction(if_inst, true); + auto store_bb = graph->CreateEmptyBlock(curr_bb); + curr_bb->GetLoop()->AppendBlock(store_bb); + curr_bb->AddSucc(store_bb); + store_bb->AddSucc(curr_cont_bb); + // calculate new length + auto add = graph->CreateInstAdd(DataType::INT32, pc); + add->SetInput(0, index); + add->SetInput(1, graph->FindOrCreateConstant(1)); + // Store new length + auto store_length = graph->CreateInstStoreObject(DataType::INT32, pc); + store_length->SetMethod(method); + store_length->SetObjField(nullptr); + store_length->SetTypeId(TypeIdMixin::MEM_DYN_ARRAY_LENGTH_ID); + store_length->SetObjectType(ObjectType::MEM_DYN_ARRAY_LENGTH); + store_length->SetInput(0, obj); + store_length->SetInput(1, add); + store_length->SetNeedBarrier(false); + store_bb->AppendInst(add); + add->InsertAfter(store_length); +} + template Inst *InsertMemFromFieldInlined(IntrinsicInst *intrinsic, Inst *obj_inst, Inst *insert_after, uint32_t offset) { @@ -668,6 +709,9 @@ void TypesResolving::InlineObjByValueFromElements(IntrinsicInst *intrinsic) store_array->SetInput(2, intrinsic->GetInput(2).GetInst()); store_array->SetNeedBarrier(true); bounds_check->InsertAfter(store_array); + if (named_access_profile_[0].type == RuntimeInterface::NamedAccessProfileType::ARRAY_ELEMENT) { + InsertCheckJSArrayLength(cast_value, cast_value_int, bounds_check, save_state->GetMethod(), pc); + } } intrinsic->SetInlined(false); intrinsic->GetBasicBlock()->RemoveInst(intrinsic); @@ -685,6 +729,10 @@ bool TypesResolving::InlineObjByValue(IntrinsicInst *intrinsic) } ASSERT(!named_access_profile_.empty()); if (named_access_profile_[0].key == 0) { + // we need to fix length for ARRAY_ELEMENT + if (named_access_profile_.size() == 2 && named_access_profile_[0].type != named_access_profile_[1].type) { + return false; + } InlineObjByValueFromElements(intrinsic); return true; } diff --git a/runtime/compiler/ecmascript_runtime_interface.cpp b/runtime/compiler/ecmascript_runtime_interface.cpp index a4393d6fc5449568b39ffdd32d20801345640e74..9ecb89da6fcdeabf00ef66f59885414c00b798e6 100644 --- a/runtime/compiler/ecmascript_runtime_interface.cpp +++ b/runtime/compiler/ecmascript_runtime_interface.cpp @@ -487,7 +487,11 @@ bool EcmaRuntimeInterface::AddElementInfo(ArenaVector *p return false; } - profile->push_back({klass, 0, 0, 0, NamedAccessProfileType::ELEMENT}); + if (HandlerBase::IsJSArray(handler_info)) { + profile->push_back({klass, 0, 0, 0, NamedAccessProfileType::ARRAY_ELEMENT}); + } else { + profile->push_back({klass, 0, 0, 0, NamedAccessProfileType::ELEMENT}); + } return true; } diff --git a/runtime/compiler/ecmascript_runtime_interface.h b/runtime/compiler/ecmascript_runtime_interface.h index 865730649164c3f66338e9596418d7978e53960f..04ef97c4341166cee280b59e35621367fc95c16c 100644 --- a/runtime/compiler/ecmascript_runtime_interface.h +++ b/runtime/compiler/ecmascript_runtime_interface.h @@ -94,6 +94,11 @@ public: return panda::cross_values::GetJsprotoChangeMarkerHasChangedOffset(arch); } + size_t GetDynArrayLenthOffset(Arch arch) const override + { + return panda::cross_values::GetJsarrayLengthOffset(arch); + } + EntrypointId GetGlobalVarEntrypointId() override { return EntrypointId::GET_GLOBAL_VAR_ADDRESS; diff --git a/tests/checked/obj_by_value.js b/tests/checked/obj_by_value.js index b5e387040e26f80aed3bdb0caf9e9f89de936576..d875a0fa299c6fdc3d7a1ced201a1f7e2ca07f14 100644 --- a/tests/checked/obj_by_value.js +++ b/tests/checked/obj_by_value.js @@ -114,6 +114,23 @@ //! EVENT /DeoptimizationReason,.*test_value_store_single_class.*ANY_TYPE_CHECK/ //! EVENT_NEXT /DeoptimizationReason,.*test_value_load_single_class.*INLINE_IC/ //! EVENT_NEXT /DeoptimizationReason,.*test_value_store_two_classes.*ANY_TYPE_CHECK/ +//! METHOD "test_value_store_with_update_length" +//! PASS_BEFORE "Scheduler" +//! INST "AnyTypeCheck ECMASCRIPT_HEAP_OBJECT_TYPE" +//! INST_NEXT "CastAnyTypeValue" +//! INST_NEXT /LoadObject.*Class/ +//! INST_NEXT "ClassImmediate" +//! INST_NEXT "Compare" +//! INST_NEXT "DeoptimizeIf" +//! INST_NEXT "AnyTypeCheck ECMASCRIPT_INT_TYPE" +//! INST_NEXT /LoadObject.*Elements/ +//! INST_NEXT "LenArray" +//! INST_NEXT "BoundsCheck" +//! INST_NEXT /LoadObject.*Length/ +//! INST_NEXT "If" +//! INST_NEXT "StoreArray" +//! INST_NOT "Intrinsic.StObjByValue" + function test_value_store_single_class(a, b) { a[b] = 2 @@ -147,6 +164,10 @@ function test_value_load_key(a, b) { return a[b] + 3 } +function test_value_store_with_update_length(a, b) { + a[b] = 9 +} + let a = {} let c = {} let b1 = 1 @@ -166,6 +187,12 @@ d[b1] = 30 let k = {} let s = "key" +var array = [0] +for (var j = 0; j < 100; j++) { + array[j] = j; +} +let b4 = 30 + for (let i = 0 ; i < 50; i++) { test_value_store_single_class(a, b1) let res = test_value_load_single_class(a, b1) @@ -222,7 +249,11 @@ for (let i = 0 ; i < 50; i++) { if (res != 10) { throw "test_value_store_key is failed for - incorrect return value: " + res; } -} + array.length = 10 + test_value_store_with_update_length(array, b4) + if (array.length != 31) { + throw "test_value_store_with_update_length is failed for - incorrect lenth: " + array.length; + }} test_value_store_single_class(a, d1) test_value_load_single_class(c, b1)