From 9169f9f41450e55dee47863111396289bdfa40ae Mon Sep 17 00:00:00 2001 From: hecunmao Date: Sat, 29 Jun 2024 16:27:07 +0800 Subject: [PATCH 1/2] Cherry-pik 7831 7446 to 4.0Release Signed-off-by: hecunmao Change-Id: I6647b735698d55264a30424757283ef0be65a5a2 --- ecmascript/base/json_stringifier.cpp | 39 +++++++++++++++++++ ecmascript/builtins/builtins_reflect.cpp | 5 +-- ecmascript/compiler/stub_builder-inl.h | 7 ++++ ecmascript/compiler/stub_builder.cpp | 34 ++++++++-------- ecmascript/compiler/stub_builder.h | 1 + test/moduletest/builtins/builtinsreflect.js | 3 ++ test/moduletest/builtins/expect_output.txt | 1 + .../jsonstringifier/expect_output.txt | 1 + .../jsonstringifier/jsonstringifier.js | 10 +++++ .../moduletest/loadicbyname/expect_output.txt | 3 ++ test/moduletest/loadicbyname/loadicbyname.js | 11 +++++- 11 files changed, 94 insertions(+), 21 deletions(-) diff --git a/ecmascript/base/json_stringifier.cpp b/ecmascript/base/json_stringifier.cpp index b9f117f743..aaba9b6737 100644 --- a/ecmascript/base/json_stringifier.cpp +++ b/ecmascript/base/json_stringifier.cpp @@ -733,6 +733,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (!enumCache.IsNull()) { JSHandle cache(thread_, enumCache); uint32_t length = cache->GetLength(); + uint32_t dictStart = length; for (uint32_t i = 0; i < length; i++) { JSTaggedValue key = cache->Get(i); if (!key.IsString()) { @@ -753,11 +754,41 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); + if (obj->GetProperties().IsDictionary()) { + dictStart = i; + handleValue_.Update(value); + hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); + break; + } } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); } + if (dictStart < length) { + propertiesArr = JSHandle(thread_, obj->GetProperties()); + JSHandle nameDic(propertiesArr); + for (uint32_t i = dictStart + 1;i < length; i++) { + JSTaggedValue key = cache->Get(i); + int hashIndex = nameDic->FindEntry(key); + PropertyAttributes attr = nameDic->GetAttributes(hashIndex); + if (!key.IsString() || hashIndex < 0 || !attr.IsEnumerable()) { + continue; + } + handleKey_.Update(key); + JSTaggedValue value = nameDic->GetValue(hashIndex); + if (UNLIKELY(value.IsAccessor())) { + value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), + JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); + } + handleValue_.Update(value); + hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); + } + } return hasContent; } int end = static_cast(jsHclass->NumberOfProps()); @@ -783,6 +814,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); @@ -808,6 +840,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); jsHclass = JSHandle(thread_, obj->GetJSHClass()); } handleValue_.Update(value); @@ -845,6 +878,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); @@ -872,10 +906,14 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl JSTaggedValue entryKey = entry.first.GetTaggedValue(); handleKey_.Update(entryKey); int index = nameDic->FindEntry(entryKey); + if (index < 0) { + continue; + } JSTaggedValue value = nameDic->GetValue(index); if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); @@ -884,6 +922,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl return hasContent; } + bool JsonStringifier::AppendJsonString(const JSHandle &obj, const JSHandle &replacer, bool hasContent) { diff --git a/ecmascript/builtins/builtins_reflect.cpp b/ecmascript/builtins/builtins_reflect.cpp index 0cd4459a71..1c6810efdd 100644 --- a/ecmascript/builtins/builtins_reflect.cpp +++ b/ecmascript/builtins/builtins_reflect.cpp @@ -138,7 +138,6 @@ JSTaggedValue BuiltinsReflect::ReflectGet(EcmaRuntimeCallInfo *argv) if (!val->IsECMAObject()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.get target is not object", JSTaggedValue::Exception()); } - JSHandle target = JSHandle::Cast(val); // 2. Let key be ? ToPropertyKey(propertyKey). JSHandle key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -146,10 +145,10 @@ JSTaggedValue BuiltinsReflect::ReflectGet(EcmaRuntimeCallInfo *argv) // a. Set receiver to target. // 4. Return ? target.[[Get]](key, receiver). if (argv->GetArgsNumber() == 2) { // 2: 2 means that there are 2 args in total - return JSObject::GetProperty(thread, target, key).GetValue().GetTaggedValue(); + return JSTaggedValue::GetProperty(thread, val, key).GetValue().GetTaggedValue(); } JSHandle receiver = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD); - return JSObject::GetProperty(thread, val, key, receiver).GetValue().GetTaggedValue(); + return JSTaggedValue::GetProperty(thread, val, key, receiver).GetValue().GetTaggedValue(); } // ecma 26.1.6 Reflect.getOwnPropertyDescriptor ( target, propertyKey ) diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index 0909b13ba1..59b0732a56 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -1425,6 +1425,13 @@ inline GateRef StubBuilder::IsInvalidPropertyBox(GateRef obj) return TaggedIsHole(value); } +inline GateRef StubBuilder::IsAccessorPropertyBox(GateRef obj) +{ + GateRef valueOffset = IntPtr(PropertyBox::VALUE_OFFSET); + GateRef value = Load(VariableType::JS_ANY(), obj, valueOffset); + return TaggedIsAccessor(value); +} + inline GateRef StubBuilder::GetValueFromPropertyBox(GateRef obj) { GateRef valueOffset = IntPtr(PropertyBox::VALUE_OFFSET); diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 8096fe58c0..d76839a508 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -1504,18 +1504,18 @@ GateRef StubBuilder::LoadGlobal(GateRef cell) Label entry(env); env->SubCfgEntry(&entry); Label exit(env); - Label cellIsInvalid(env); Label cellNotInvalid(env); + Label cellNotAccessor(env); DEFVARIABLE(result, VariableType::JS_ANY(), Hole()); - Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid); - Bind(&cellIsInvalid); - { - Jump(&exit); - } + Branch(IsInvalidPropertyBox(cell), &exit, &cellNotInvalid); Bind(&cellNotInvalid); { - result = GetValueFromPropertyBox(cell); - Jump(&exit); + Branch(IsAccessorPropertyBox(cell), &exit, &cellNotAccessor); + Bind(&cellNotAccessor); + { + result = GetValueFromPropertyBox(cell); + Jump(&exit); + } } Bind(&exit); auto ret = *result; @@ -2078,19 +2078,19 @@ GateRef StubBuilder::StoreGlobal(GateRef glue, GateRef value, GateRef cell) Label entry(env); env->SubCfgEntry(&entry); Label exit(env); - Label cellIsInvalid(env); Label cellNotInvalid(env); + Label cellIsNotAccessorData(env); DEFVARIABLE(result, VariableType::JS_ANY(), Hole()); - Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid); - Bind(&cellIsInvalid); - { - Jump(&exit); - } + Branch(IsInvalidPropertyBox(cell), &exit, &cellNotInvalid); Bind(&cellNotInvalid); { - Store(VariableType::JS_ANY(), glue, cell, IntPtr(PropertyBox::VALUE_OFFSET), value); - result = Undefined(); - Jump(&exit); + Branch(IsAccessorPropertyBox(cell), &exit, &cellIsNotAccessorData); + Bind(&cellIsNotAccessorData); + { + Store(VariableType::JS_ANY(), glue, cell, IntPtr(PropertyBox::VALUE_OFFSET), value); + result = Undefined(); + Jump(&exit); + } } Bind(&exit); auto ret = *result; diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 6026f24157..23d4af183c 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -343,6 +343,7 @@ public: GateRef HandlerBaseGetAttrIndex(GateRef attr); GateRef HandlerBaseGetRep(GateRef attr); GateRef IsInvalidPropertyBox(GateRef obj); + GateRef IsAccessorPropertyBox(GateRef obj); GateRef GetValueFromPropertyBox(GateRef obj); void SetValueToPropertyBox(GateRef glue, GateRef obj, GateRef value); GateRef GetTransitionHClass(GateRef obj); diff --git a/test/moduletest/builtins/builtinsreflect.js b/test/moduletest/builtins/builtinsreflect.js index 11517c8856..c0da3afdae 100644 --- a/test/moduletest/builtins/builtinsreflect.js +++ b/test/moduletest/builtins/builtinsreflect.js @@ -30,4 +30,7 @@ Reflect.set(v56, "length", v0) Reflect.set(v55, "length", v0, v56) print("v56.length",v56.length) +let obj = {name:"tom"}; +let pxobj = new Proxy(obj,{}); +print(Reflect.get(pxobj,"name")) print("builtins reflect end"); diff --git a/test/moduletest/builtins/expect_output.txt b/test/moduletest/builtins/expect_output.txt index f6fa46c636..4c1243c3ad 100644 --- a/test/moduletest/builtins/expect_output.txt +++ b/test/moduletest/builtins/expect_output.txt @@ -57,4 +57,5 @@ false false builtins reflect start v56.length 102630708 +tom builtins reflect end diff --git a/test/moduletest/jsonstringifier/expect_output.txt b/test/moduletest/jsonstringifier/expect_output.txt index 79df9a2fdc..e69261c64e 100644 --- a/test/moduletest/jsonstringifier/expect_output.txt +++ b/test/moduletest/jsonstringifier/expect_output.txt @@ -19,3 +19,4 @@ test successful {"a":{}} {"3":3} end JSON.stringify(globalThis) +{"a":"a","b":"b"} diff --git a/test/moduletest/jsonstringifier/jsonstringifier.js b/test/moduletest/jsonstringifier/jsonstringifier.js index 14ad4e99e0..5cacdd8ba5 100644 --- a/test/moduletest/jsonstringifier/jsonstringifier.js +++ b/test/moduletest/jsonstringifier/jsonstringifier.js @@ -95,3 +95,13 @@ Reflect.defineProperty(globalThis,"c",{ Reflect.set(globalThis,"d","d"); JSON.stringify(globalThis); print("end JSON.stringify(globalThis)") +let obj1 = { + get a(){ + this[102400] = 1; + return "a"; + }, + b:"b", +} +Object.keys(obj1); +print(JSON.stringify(obj1)); + \ No newline at end of file diff --git a/test/moduletest/loadicbyname/expect_output.txt b/test/moduletest/loadicbyname/expect_output.txt index fbdfa11ba3..ace947179c 100644 --- a/test/moduletest/loadicbyname/expect_output.txt +++ b/test/moduletest/loadicbyname/expect_output.txt @@ -12,3 +12,6 @@ # limitations under the License. false +1 +1 +load global ic with accessor success! diff --git a/test/moduletest/loadicbyname/loadicbyname.js b/test/moduletest/loadicbyname/loadicbyname.js index 2a657ae0c3..94e9af31f5 100644 --- a/test/moduletest/loadicbyname/loadicbyname.js +++ b/test/moduletest/loadicbyname/loadicbyname.js @@ -45,4 +45,13 @@ try { } catch (e) { flag1 = true; } -print(flag1); \ No newline at end of file +print(flag1); +function f(){return 1}; +Object.defineProperty(this,"g",{ + get:f, + set:f, +}) +for(let i=0;i<2;i++){ + print(g) +} +print("load global ic with accessor success!"); From 6ee1a540914f2e2292176c31e7044ecfdb0d11ce Mon Sep 17 00:00:00 2001 From: hecunmao Date: Sat, 29 Jun 2024 16:41:34 +0800 Subject: [PATCH 2/2] Cherry 7435 To 4.0Release Signed-off-by: hecunmao Change-Id: I7ed3e27ad5ae6ec8dfa6c39191c0478ffad12654 --- ecmascript/builtins/builtins_array.cpp | 8 +++++--- ecmascript/builtins/builtins_typedarray.cpp | 7 +++++-- .../builtins/tests/builtins_number_format_test.cpp | 14 +++----------- ecmascript/js_stable_array.cpp | 11 ++++++++--- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/ecmascript/builtins/builtins_array.cpp b/ecmascript/builtins/builtins_array.cpp index 96fc9b4370..bb6760735e 100644 --- a/ecmascript/builtins/builtins_array.cpp +++ b/ecmascript/builtins/builtins_array.cpp @@ -1278,6 +1278,10 @@ JSTaggedValue BuiltinsArray::Join(EcmaRuntimeCallInfo *argv) if (k > 0) { concatStr.append(sepStr); } + if (concatStr.size() > EcmaString::MAX_STRING_LENGTH) { + context->JoinStackPopFastPath(thisHandle); + THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); + } concatStr.append(nextStr); } @@ -2586,12 +2590,10 @@ JSTaggedValue BuiltinsArray::ToString(EcmaRuntimeCallInfo *argv) callbackFnHandle = JSTaggedValue::GetProperty(thread, objectPrototype, toStringKey).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } - const uint32_t argsLength = argv->GetArgsNumber(); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo *info = - EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, undefined, argsLength); + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, undefined, 0); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - info->SetCallArg(argsLength, 0, argv, 0); return JSFunction::Call(info); } diff --git a/ecmascript/builtins/builtins_typedarray.cpp b/ecmascript/builtins/builtins_typedarray.cpp index 774b1ff04a..785ddb5be5 100644 --- a/ecmascript/builtins/builtins_typedarray.cpp +++ b/ecmascript/builtins/builtins_typedarray.cpp @@ -781,7 +781,7 @@ JSTaggedValue BuiltinsTypedArray::Join(EcmaRuntimeCallInfo *argv) const GlobalEnvConstants *globalConst = thread->GlobalConstants(); return globalConst->GetEmptyString(); } - size_t allocateLength = 0; + uint64_t allocateLength = 0; bool isOneByte = (sep != BuiltinsTypedArray::SeparatorFlag::MINUS_ONE) || EcmaStringAccessor(sepStringHandle).IsUtf8(); CVector> vec; @@ -806,7 +806,10 @@ JSTaggedValue BuiltinsTypedArray::Join(EcmaRuntimeCallInfo *argv) vec.push_back(JSHandle(globalConst->GetHandledEmptyString())); } } - allocateLength += sepLength * (length - 1); + allocateLength += static_cast(sepLength) * (length - 1); + if (allocateLength > EcmaString::MAX_STRING_LENGTH) { + THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); + } if (allocateLength <= 1) { // sep unused, set isOneByte to default(true) isOneByte = true; diff --git a/ecmascript/builtins/tests/builtins_number_format_test.cpp b/ecmascript/builtins/tests/builtins_number_format_test.cpp index 85dd348bc2..8044c70346 100644 --- a/ecmascript/builtins/tests/builtins_number_format_test.cpp +++ b/ecmascript/builtins/tests/builtins_number_format_test.cpp @@ -86,7 +86,6 @@ HWTEST_F_L0(BuiltinsNumberFormatTest, NumberFormatConstructor) static JSTaggedValue BuiltinsFormatTest(JSThread *thread, JSHandle &options, JSHandle &number, JSHandle &locale) { - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle newTarget(env->GetNumberFormatFunction()); @@ -109,20 +108,13 @@ static JSTaggedValue BuiltinsFormatTest(JSThread *thread, JSHandle &op JSTaggedValue resultFunc = BuiltinsNumberFormat::Format(ecmaRuntimeCallInfo2); JSHandle jsFunction(thread, resultFunc); TestHelper::TearDownFrame(thread, prev); - JSArray *jsArray = - JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject()); - JSHandle jsObject(thread, jsArray); - PropertyDescriptor desc(thread, JSHandle(jsFunction), true, true, true); - JSHandle joinKey(factory->NewFromASCII("join")); - JSArray::DefineOwnProperty(thread, jsObject, joinKey, desc); - auto ecmaRuntimeCallInfo3 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); - ecmaRuntimeCallInfo3->SetFunction(JSTaggedValue::Undefined()); - ecmaRuntimeCallInfo3->SetThis(jsObject.GetTaggedValue()); + ecmaRuntimeCallInfo3->SetFunction(jsFunction.GetTaggedValue()); + ecmaRuntimeCallInfo3->SetThis(jsFunction.GetTaggedValue()); ecmaRuntimeCallInfo3->SetCallArg(0, number.GetTaggedValue()); prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo3); - JSTaggedValue result = BuiltinsArray::ToString(ecmaRuntimeCallInfo3); + JSTaggedValue result = JSFunction::Call(ecmaRuntimeCallInfo3); TestHelper::TearDownFrame(thread, prev); return result; } diff --git a/ecmascript/js_stable_array.cpp b/ecmascript/js_stable_array.cpp index 780e9106bd..5694b9ba56 100644 --- a/ecmascript/js_stable_array.cpp +++ b/ecmascript/js_stable_array.cpp @@ -245,7 +245,7 @@ JSTaggedValue JSStableArray::Join(JSHandle receiver, EcmaRuntimeCallInf return globalConst->GetEmptyString(); } TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject()); - size_t allocateLength = 0; + uint64_t allocateLength = 0; bool isOneByte = (sep != JSStableArray::SeparatorFlag::MINUS_ONE) || EcmaStringAccessor(sepStringHandle).IsUtf8(); CVector> vec; JSMutableHandle elementHandle(thread, JSTaggedValue::Undefined()); @@ -282,9 +282,14 @@ JSTaggedValue JSStableArray::Join(JSHandle receiver, EcmaRuntimeCallInf } } if (len > 0) { - allocateLength += sepLength * (len - 1); + allocateLength += static_cast(sepLength) * (len - 1); } - auto newString = EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), allocateLength, isOneByte); + if (allocateLength > EcmaString::MAX_STRING_LENGTH) { + context->JoinStackPopFastPath(receiverValue); + THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); + } + auto newString = + EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), static_cast(allocateLength), isOneByte); int current = 0; DISALLOW_GARBAGE_COLLECTION; for (uint32_t k = 0; k < len; k++) {