!4156 Fix stobjbyvalue for empty or COW array

Merge pull request !4156 from hzzhouzebin/FixStobjbyvalue
This commit is contained in:
openharmony_ci 2023-06-04 10:54:12 +00:00 committed by Gitee
commit 4b04dda813
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
15 changed files with 172 additions and 106 deletions

View File

@ -535,6 +535,12 @@ GateRef CircuitBuilder::TaggedFalse()
return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_FALSE, GateType::TaggedValue());
}
GateRef CircuitBuilder::GetLengthFromTaggedArray(GateRef array)
{
GateRef offset = IntPtr(TaggedArray::LENGTH_OFFSET);
return Load(VariableType::INT32(), array, offset);
}
GateRef CircuitBuilder::GetValueFromTaggedArray(GateRef array, GateRef index)
{
GateRef offset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
@ -873,29 +879,30 @@ GateRef CircuitBuilder::TypedConditionJump(GateRef x, GateType xType)
return jumpOp;
}
template<TypedLoadOp Op>
GateRef CircuitBuilder::LoadElement(GateRef receiver, GateRef index)
template <TypedLoadOp Op>
GateRef CircuitBuilder::LoadElement(GateRef receiver, GateRef index, GateRef length)
{
auto opIdx = static_cast<uint64_t>(Op);
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto ret = GetCircuit()->NewGate(GetCircuit()->LoadElement(opIdx), MachineType::I64,
{ currentControl, currentDepend, receiver, index }, GateType::AnyType());
{currentControl, currentDepend, receiver, index, length}, GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
template<TypedStoreOp Op>
GateRef CircuitBuilder::StoreElement(GateRef receiver, GateRef index, GateRef value)
template <TypedStoreOp Op>
GateRef CircuitBuilder::StoreElement(GateRef receiver, GateRef index, GateRef value, GateRef length)
{
auto opIdx = static_cast<uint64_t>(Op);
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto ret = GetCircuit()->NewGate(GetCircuit()->StoreElement(opIdx), MachineType::NOVALUE,
{ currentControl, currentDepend, receiver, index, value }, GateType::AnyType());
auto ret =
GetCircuit()->NewGate(GetCircuit()->StoreElement(opIdx), MachineType::NOVALUE,
{currentControl, currentDepend, receiver, index, value, length}, GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;

View File

@ -221,6 +221,25 @@ GateRef CircuitBuilder::IndexCheck(GateType type, GateRef gate, GateRef index)
return ret;
}
GateRef CircuitBuilder::IsJsCOWArray(GateRef obj)
{
// Elements of JSArray are shared and properties are not yet.
GateRef elements = GetElementsArray(obj);
GateRef objectType = GetObjectType(LoadHClass(elements));
return IsCOWArray(objectType);
}
GateRef CircuitBuilder::IsCOWArray(GateRef objectType)
{
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::COW_TAGGED_ARRAY)));
}
GateRef CircuitBuilder::GetElementsArray(GateRef object)
{
GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET);
return Load(VariableType::JS_POINTER(), object, elementsOffset);
}
MachineType CircuitBuilder::GetMachineTypeOfValueType(ValueType type)
{
switch (type) {

View File

@ -269,6 +269,9 @@ public:
GateRef Sqrt(GateRef param);
MachineType GetMachineTypeOfValueType(ValueType type);
GateType GetGateTypeOfValueType(ValueType type);
GateRef IsJsCOWArray(GateRef obj);
GateRef IsCOWArray(GateRef objectType);
GateRef GetElementsArray(GateRef object);
GateRef Convert(GateRef gate, ValueType src, ValueType dst);
GateRef ConvertBoolToTaggedBoolean(GateRef gate);
GateRef ConvertTaggedBooleanToBool(GateRef gate);
@ -475,6 +478,7 @@ public:
inline GateRef IntPtrGreaterThan(GateRef x, GateRef y);
template<OpCode Op, MachineType Type>
inline GateRef BinaryOp(GateRef x, GateRef y);
inline GateRef GetLengthFromTaggedArray(GateRef array);
inline GateRef GetValueFromTaggedArray(GateRef array, GateRef index);
inline void SetValueToTaggedArray(VariableType valType, GateRef glue, GateRef array, GateRef index, GateRef val);
GateRef TaggedIsString(GateRef obj);
@ -497,9 +501,9 @@ public:
// middle ir: object operations
GateRef ToLength(GateRef receiver);
template<TypedLoadOp Op>
GateRef LoadElement(GateRef receiver, GateRef index);
GateRef LoadElement(GateRef receiver, GateRef index, GateRef length);
template<TypedStoreOp Op>
GateRef StoreElement(GateRef receiver, GateRef index, GateRef value);
GateRef StoreElement(GateRef receiver, GateRef index, GateRef value, GateRef length);
GateRef LoadProperty(GateRef receiver, GateRef propertyLookupResult, bool isFunction);
GateRef StoreProperty(GateRef receiver, GateRef propertyLookupResult, GateRef value);
GateRef LoadArrayLength(GateRef array);

View File

@ -78,29 +78,34 @@ enum class TypedJumpOp : uint8_t {
TYPED_JNEZ,
};
#define GATE_META_DATA_DEOPT_REASON(V) \
V(NotInt, NOTINT) \
V(NotDouble, NOTDOUBLE) \
V(NotNumber, NOTNUMBER) \
V(NotBool, NOTBOOL) \
V(NotHeapObject, NOTHEAPOBJECT) \
V(NotStableArray, NOTSARRAY) \
V(NotF32Array, NOTF32ARRAY) \
V(InconsistentHClass, INCONSISTENTHCLASS) \
V(NotNewObj, NOTNEWOBJ) \
V(NotArrayIndex, NOTARRAYIDX) \
V(NotF32ArrayIndex, NOTF32ARRAYIDX) \
V(NotIncOverflow, NOTINCOV) \
V(NotDecOverflow, NOTDECOV) \
V(NotNegativeOverflow, NOTNEGOV) \
V(NotCallTarget, NOTCALLTGT) \
V(NotJSCallTarget, NOTJSCALLTGT) \
V(DivideZero, DIVZERO) \
V(NegativeIndex, NEGTIVEINDEX) \
V(LargeIndex, LARGEINDEX) \
V(InlineFail, INLINEFAIL) \
V(NotJSFastCallTarget, NOTJSFASTCALLTGT)
enum class DeoptType : uint8_t {
NOTCHECK = 0,
NOTINT,
NOTDOUBLE,
NOTNUMBER,
NOTBOOL,
NOTHEAPOBJECT,
NOTSARRAY,
NOTF32ARRAY,
INCONSISTENTHCLASS,
NOTNEWOBJ,
NOTARRAYIDX,
NOTF32ARRAYIDX,
NOTINCOV,
NOTDECOV,
NOTNEGOV,
NOTCALLTGT,
NOTJSCALLTGT,
DIVZERO,
NEGTIVEINDEX,
LARGEINDEX,
INLINEFAIL,
NOTJSFASTCALLTGT,
#define DECLARE_DEOPT_TYPE(NAME, TYPE) TYPE,
GATE_META_DATA_DEOPT_REASON(DECLARE_DEOPT_TYPE)
#undef DECLARE_DEOPT_TYPE
};
enum class ICmpCondition : uint8_t {
@ -295,8 +300,8 @@ std::string MachineTypeToStr(MachineType machineType);
V(HeapAlloc, HEAP_ALLOC, GateFlags::NONE_FLAG, 1, 1, 1) \
V(LoadConstOffset, LOAD_CONST_OFFSET, GateFlags::NO_WRITE, 0, 1, 1) \
V(StoreConstOffset, STORE_CONST_OFFSET, GateFlags::NONE_FLAG, 1, 1, 2) \
V(LoadElement, LOAD_ELEMENT, GateFlags::NO_WRITE, 1, 1, 2) \
V(StoreElement, STORE_ELEMENT, GateFlags::NONE_FLAG, 1, 1, 3) \
V(LoadElement, LOAD_ELEMENT, GateFlags::NO_WRITE, 1, 1, 3) \
V(StoreElement, STORE_ELEMENT, GateFlags::NONE_FLAG, 1, 1, 4) \
V(RestoreRegister, RESTORE_REGISTER, GateFlags::NONE_FLAG, 0, 1, 0) \
V(ConstData, CONST_DATA, GateFlags::NONE_FLAG, 0, 0, 1) \
V(Constant, CONSTANT, GateFlags::NONE_FLAG, 0, 0, 0) \

View File

@ -922,8 +922,7 @@ inline GateRef StubBuilder::GetSetterFromAccessor(GateRef accessor)
inline GateRef StubBuilder::GetElementsArray(GateRef object)
{
GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET);
return Load(VariableType::JS_POINTER(), object, elementsOffset);
return env_->GetBuilder()->GetElementsArray(object);
}
inline void StubBuilder::SetElementsArray(VariableType type, GateRef glue, GateRef object, GateRef elementsArray)
@ -1234,13 +1233,8 @@ inline GateRef StubBuilder::IsJsCOWArray(GateRef obj)
{
// Elements of JSArray are shared and properties are not yet.
GateRef elements = GetElementsArray(obj);
return IsCOWArray(elements);
}
inline GateRef StubBuilder::IsCOWArray(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::COW_TAGGED_ARRAY)));
GateRef objectType = GetObjectType(LoadHClass(elements));
return env_->GetBuilder()->IsCOWArray(objectType);
}
inline GateRef StubBuilder::IsWritable(GateRef attr)

View File

@ -313,7 +313,6 @@ public:
GateRef IsJsArray(GateRef obj);
GateRef IsByteArray(GateRef obj);
GateRef IsJsCOWArray(GateRef obj);
GateRef IsCOWArray(GateRef obj);
GateRef IsJSObject(GateRef obj);
GateRef IsWritable(GateRef attr);
GateRef IsAccessor(GateRef attr);

View File

@ -109,9 +109,9 @@ HWTEST_F_L0(LoweringRelateGateTests, HeapAllocTest)
builder.Store(VariableType::JS_POINTER(), glue, array, builder.IntPtr(0), arg1);
builder.StoreElement<ecmascript::kungfu::TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(array, builder.IntPtr(0),
builder.ToTaggedInt(builder.Int64(0)));
builder.ToTaggedInt(builder.Int64(0)), builder.Undefined());
builder.StoreElement<ecmascript::kungfu::TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(array, builder.IntPtr(1),
builder.ToTaggedInt(builder.Int64(1)));
builder.ToTaggedInt(builder.Int64(1)), builder.Undefined());
builder.StoreProperty(array, lengthString, builder.ToTaggedInt(builder.Int64(2)));
auto length = builder.LoadProperty(array, lengthString, false);
Label less2(&builder);
@ -121,8 +121,8 @@ HWTEST_F_L0(LoweringRelateGateTests, HeapAllocTest)
GateType::AnyType(), PGOSampleType::NoneType());
builder.Branch(condtion, &less2, &notLess2);
builder.Bind(&less2);
auto ret =
builder.LoadElement<ecmascript::kungfu::TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(array, builder.IntPtr(1));
auto ret = builder.LoadElement<ecmascript::kungfu::TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(array, builder.IntPtr(1),
builder.Undefined());
builder.Return(ret);
builder.Bind(&notLess2);
builder.Return(builder.Int64(-1));

View File

@ -213,6 +213,7 @@ void TSHCRLowering::Lower(GateRef gate)
break;
case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
LowerTypedStObjByValue(gate);
break;
case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
@ -650,7 +651,7 @@ void TSHCRLowering::LowerTypedLdObjByIndex(GateRef gate)
GateRef result = Circuit::NullGate();
if (tsManager_->IsFloat32ArrayType(receiverType)) {
result = builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, index);
result = builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, index, builder_.Undefined());
} else {
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
@ -686,7 +687,7 @@ void TSHCRLowering::LowerTypedStObjByIndex(GateRef gate)
builder_.IndexCheck(receiverType, receiver, index);
if (tsManager_->IsFloat32ArrayType(receiverType)) {
builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value);
builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value, builder_.Undefined());
} else {
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
@ -713,7 +714,7 @@ void TSHCRLowering::LowerTypedLdObjByValue(GateRef gate, bool isThis)
GateType receiverType = acc_.GetGateType(receiver);
GateType propKeyType = acc_.GetGateType(propKey);
receiverType = tsManager_->TryNarrowUnionType(receiverType);
if (!tsManager_->IsArrayTypeKind(receiverType) || !propKeyType.IsNumberType()) { // slowpath
if (!tsManager_->IsArrayTypeKind(receiverType) || !propKeyType.IsNumberType()) { // slowpath
return;
}
@ -722,21 +723,21 @@ void TSHCRLowering::LowerTypedLdObjByValue(GateRef gate, bool isThis)
builder_.StableArrayCheck(receiver);
GateRef length = builder_.LoadArrayLength(receiver);
propKey = builder_.IndexCheck(receiverType, length, propKey);
GateRef result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_ELEMENT>(receiver, propKey);
GateRef result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_ELEMENT>(receiver, propKey, length);
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
}
void TSHCRLowering::LowerTypedStObjByValue(GateRef gate)
{
ASSERT(acc_.GetNumValueIn(gate) == 4); // 4: num of value ins
GateRef receiver = acc_.GetValueIn(gate, 1); // 1: receiver
GateRef propKey = acc_.GetValueIn(gate, 2); // 2: key
GateRef value = acc_.GetValueIn(gate, 3); // 3: value
ASSERT(acc_.GetNumValueIn(gate) == 4); // 4: num of value ins
GateRef receiver = acc_.GetValueIn(gate, 1); // 1: receiver
GateRef propKey = acc_.GetValueIn(gate, 2); // 2: key
GateRef value = acc_.GetValueIn(gate, 3); // 3: value
GateType receiverType = acc_.GetGateType(receiver);
GateType propKeyType = acc_.GetGateType(propKey);
receiverType = tsManager_->TryNarrowUnionType(receiverType);
if (!tsManager_->IsArrayTypeKind(receiverType) || !propKeyType.IsNumberType()) { // slowpath
if (!tsManager_->IsArrayTypeKind(receiverType) || !propKeyType.IsNumberType()) { // slowpath
return;
}
@ -744,7 +745,7 @@ void TSHCRLowering::LowerTypedStObjByValue(GateRef gate)
builder_.StableArrayCheck(receiver);
GateRef length = builder_.LoadArrayLength(receiver);
builder_.IndexCheck(receiverType, length, propKey);
builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value, length);
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
}

View File

@ -537,11 +537,23 @@ void TypeMCRLowering::LowerArrayLoadElement(GateRef gate)
Environment env(gate, circuit_, &builder_);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef index = acc_.GetValueIn(gate, 1);
GateRef element = builder_.LoadConstOffset(
VariableType::JS_POINTER(), receiver, JSObject::ELEMENTS_OFFSET);
GateRef result = builder_.GetValueFromTaggedArray(element, index);
result = builder_.ConvertHoleAsUndefined(result);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
GateRef length = acc_.GetValueIn(gate, 2); // length
ASSERT(!acc_.IsConstantUndefined(length));
GateRef element = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, JSObject::ELEMENTS_OFFSET);
GateRef arrayLength = builder_.GetLengthFromTaggedArray(element);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
Label accessValue(&builder_);
Label exit(&builder_);
GateRef hasEntityValue = builder_.Int32LessThanOrEqual(length, arrayLength);
builder_.Branch(hasEntityValue, &accessValue, &exit);
builder_.Bind(&accessValue);
{
result = builder_.GetValueFromTaggedArray(element, index);
result = builder_.ConvertHoleAsUndefined(*result);
builder_.Jump(&exit);
};
builder_.Bind(&exit);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
// for Float32Array
@ -604,11 +616,20 @@ void TypeMCRLowering::LowerStoreElement(GateRef gate, GateRef glue)
void TypeMCRLowering::LowerArrayStoreElement(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef receiver = acc_.GetValueIn(gate, 0); // 0: receiver
GateRef index = acc_.GetValueIn(gate, 1); // 1: index
GateRef value = acc_.GetValueIn(gate, 2); // 2: value
GateRef element = builder_.LoadConstOffset(
VariableType::JS_POINTER(), receiver, JSObject::ELEMENTS_OFFSET);
GateRef receiver = acc_.GetValueIn(gate, 0); // 0: receiver
GateRef index = acc_.GetValueIn(gate, 1); // 1: index
GateRef value = acc_.GetValueIn(gate, 2); // 2: value
GateRef length = acc_.GetValueIn(gate, 3); // 3: length
ASSERT(!acc_.IsConstantUndefined(length));
GateRef currentDepend = builder_.GetDepend();
GateRef element = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, JSObject::ELEMENTS_OFFSET);
GateRef arrayLength = builder_.GetLengthFromTaggedArray(element);
GateRef hasEntityValue = builder_.Int32LessThanOrEqual(length, arrayLength);
GateRef notCOWArray = builder_.BoolNot(builder_.IsJsCOWArray(receiver));
GateRef frameState = acc_.FindNearestFrameState(currentDepend);
builder_.DeoptCheck(builder_.BoolAnd(hasEntityValue, notCOWArray), frameState, DeoptType::NOTSARRAY);
builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue, element, index, value);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}

View File

@ -35,6 +35,7 @@ foreach(file, test_js_files) {
dst_file = rebase_path(test_abc)
extra_args = [ "--module" ]
extra_args += [ "--merge-abc" ]
extra_args += [ "--type-extractor" ]
in_puts = [ test_js ]
out_puts = [ test_abc ]

View File

@ -397,47 +397,15 @@ void Deoptimizier::Dump(Method* method, kungfu::DeoptType type, size_t depth)
std::string Deoptimizier::DisplayItems(DeoptType type)
{
switch (type) {
case DeoptType::NOTINT:
return "NOT INT";
case DeoptType::DIVZERO:
return "DIV ZERO";
case DeoptType::NOTDOUBLE:
return "NOT DOUBLE";
case DeoptType::NOTNUMBER:
return "NOT NUMBER";
case DeoptType::NOTBOOL:
return "NOT BOOL";
case DeoptType::NOTHEAPOBJECT:
return "NOT HEAP OBJECT";
case DeoptType::NOTSARRAY:
return "NOT SARRAY";
case DeoptType::NOTF32ARRAY:
return "NOT F32ARRAY";
case DeoptType::INCONSISTENTHCLASS:
return "INCONSISTENT HCLASS";
case DeoptType::NOTNEWOBJ:
return "NOT NEWOBJ TYPE";
case DeoptType::NOTARRAYIDX:
return "NOT ARRAY IDX";
case DeoptType::NOTF32ARRAYIDX:
return "NOT F32 ARRAY IDX";
case DeoptType::NOTINCOV:
return "NOT INC OVERFLOW";
case DeoptType::NOTDECOV:
return "NOT DEC OVERFLOW";
case DeoptType::NOTNEGOV:
return "NOT NEG OVERFLOW";
case DeoptType::NOTCALLTGT:
return "NOT CALL TARGET";
case DeoptType::NOTJSCALLTGT:
return "NOT JS CALL TARGET";
case DeoptType::INLINEFAIL:
return "INLINE FAILED";
default: {
return "NOT CHECK";
}
const std::map<DeoptType, const char *> strMap = {
#define DEOPT_NAME_MAP(NAME, TYPE) {DeoptType::TYPE, #NAME},
GATE_META_DATA_DEOPT_REASON(DEOPT_NAME_MAP)
#undef DEOPT_NAME_MAP
};
if (strMap.count(type) > 0) {
return strMap.at(type);
}
return "DeoptType-" + std::to_string(static_cast<uint8_t>(type));
}
// layout of frameWriter

View File

@ -12,3 +12,4 @@
# limitations under the License.
true
true

View File

@ -20,3 +20,14 @@ let array:A[] = [undefined];
for (let i = 0; i < array.length; i++) {
print(array[i]===undefined);
}
class ParticleSystemCPU {
private _arrayTest: number[];
constructor() {
this._arrayTest = new Array(10);
print(this._arrayTest[9] === undefined);
}
}
var system: ParticleSystemCPU[] = [new ParticleSystemCPU()];

View File

@ -15,9 +15,13 @@
hello
helloworld
200
999
100
hello
helloworld
1
19
helloworld 1
world hello
11
3

View File

@ -28,6 +28,11 @@ array[second] = 200;
print(array[first]);
print(array[second]);
let arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr[0] = 999;
print(arr[0])
// test object
let phrase: { 0: string, "100": string | number, fullPhrase: any } = {
0 : "100",
@ -48,7 +53,33 @@ phrase[hundred] = 1;
print(phrase[first]);
print(phrase[hundred]);
// test class
class ParticleSystemCPU {
private _arrayTest: number[];
constructor() {
this._arrayTest = new Array(10);
this._arrayTest[9] = 19;
print(this._arrayTest[9]); // 19
}
}
var system: ParticleSystemCPU[] = [new ParticleSystemCPU()];
// test getter and setter
print(phrase.fullPhrase);
phrase.fullPhrase = "world hello";
print(phrase.fullPhrase);
// test COW array
function generateCOWArray() : number[] {
return [0, 1, 2, 3, 4]
}
let arrayA : number [] = generateCOWArray();
let arrayB : number [] = generateCOWArray();
arrayB[3] = 11;
print(arrayB[3]) // expect 11
print(arrayA[3]) // expect 3