!6776 Implement hash calculation for numbers and objects

Merge pull request !6776 from udav/hash
This commit is contained in:
openharmony_ci 2024-04-09 12:31:24 +00:00 committed by Gitee
commit e4f5cab36b
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
21 changed files with 394 additions and 51 deletions

View File

@ -1178,7 +1178,7 @@ uint64_t RandomGenerator::XorShift64(uint64_t *pVal)
return x * GET_MULTIPLY;
}
void RandomGenerator::InitRandom()
void RandomGenerator::InitRandom(JSThread *thread)
{
struct timeval tv;
gettimeofday(&tv, NULL);
@ -1187,6 +1187,7 @@ void RandomGenerator::InitRandom()
if (randomState_ == 0) {
randomState_ = 1;
}
thread->SetRandomStatePtr(&randomState_);
}
double RandomGenerator::NextDouble()

View File

@ -171,7 +171,7 @@ private:
// The value is used in xorshift64* random generator to generate result.
class RandomGenerator {
public:
static void InitRandom();
static void InitRandom(JSThread *thread);
static double NextDouble();
static int32_t GenerateIdentityHash();
static int32_t Next(int bits);

View File

@ -1557,7 +1557,7 @@ void Builtins::InitializeMath(const JSHandle<GlobalEnv> &env, const JSHandle<JST
[[maybe_unused]] EcmaHandleScope scope(thread_);
JSHandle<JSHClass> mathClass = factory_->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, objFuncPrototypeVal);
JSHandle<JSObject> mathObject = factory_->NewJSObjectWithInit(mathClass);
RandomGenerator::InitRandom();
RandomGenerator::InitRandom(thread_);
for (const base::BuiltinFunctionEntry &entry: Math::GetMathFunctions()) {
SetFunction(env, mathObject, entry.GetName(), entry.GetEntrypoint(),

View File

@ -29,6 +29,7 @@
#include "ecmascript/property_detector-inl.h"
#include "ecmascript/js_arraybuffer.h"
#include "ecmascript/interpreter/fast_runtime_stub-inl.h"
#include "ecmascript/linked_hash_table.h"
#include "builtins_typedarray.h"
#include "ecmascript/jit/jit.h"
@ -250,6 +251,15 @@ JSTaggedValue BuiltinsArkTools::CheckCircularImport(EcmaRuntimeCallInfo *info)
return JSTaggedValue::Undefined();
}
JSTaggedValue BuiltinsArkTools::HashCode(EcmaRuntimeCallInfo *info)
{
ASSERT(info);
JSThread *thread = info->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> key = GetCallArg(info, 0);
return JSTaggedValue(LinkedHash::Hash(thread, key.GetTaggedValue()));
}
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
JSTaggedValue BuiltinsArkTools::StartCpuProfiler(EcmaRuntimeCallInfo *info)
{

View File

@ -49,7 +49,8 @@
V("printTypedOpProfilerAndReset", PrintTypedOpProfilerAndReset, 1, INVALID) \
V("isOnHeap", IsOnHeap, 1, INVALID) \
V("checkDeoptStatus", CheckDeoptStatus, 2, INVALID) \
V("checkCircularImport", CheckCircularImport, 2, INVALID)
V("checkCircularImport", CheckCircularImport, 2, INVALID) \
V("hashCode", HashCode, 1, ArkToolsHashCode)
#define BUILTIN_ARK_TOOLS_FUNCTIONS_REGRESS(V) \
V("prepareFunctionForOptimization", PrepareFunctionForOptimization, 1, INVALID) \
@ -170,6 +171,8 @@ public:
static JSTaggedValue CheckCircularImport(EcmaRuntimeCallInfo *info);
static JSTaggedValue HashCode(EcmaRuntimeCallInfo *info);
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
static JSTaggedValue StartCpuProfiler(EcmaRuntimeCallInfo *info);

View File

@ -126,6 +126,7 @@ libark_jsoptimizer_sources = [
"gate_accessor.cpp",
"graph_editor.cpp",
"graph_linearizer.cpp",
"hash_stub_builder.cpp",
"hcr_circuit_builder.cpp",
"hcr_gate_meta_data.cpp",
"ic_stub_builder.cpp",

View File

@ -31,7 +31,8 @@ namespace panda::ecmascript::kungfu {
BUILTINS_METHOD_STUB_LIST(D, D, D) \
BUILTINS_WITH_CONTAINERS_STUB_BUILDER(D) \
BUILTINS_CONSTRUCTOR_STUB_LIST(V) \
AOT_AND_BUILTINS_STUB_LIST(V)
AOT_AND_BUILTINS_STUB_LIST(V) \
BUILTINS_ARKTOOLS_STUB_BUILDER(D)
#define BUILTINS_METHOD_STUB_LIST(V, T, D) \
BUILTINS_WITH_STRING_STUB_BUILDER(V) \
@ -147,6 +148,9 @@ namespace panda::ecmascript::kungfu {
V(ReplaceAllElements, ArrayList, ContainersCommonFuncCall, ARRAYLIST_REPLACEALLELEMENTS, JS_POINTER) \
V(ReplaceAllElements, Vector, ContainersCommonFuncCall, VECTOR_REPLACEALLELEMENTS, JS_POINTER)
#define BUILTINS_ARKTOOLS_STUB_BUILDER(V) \
V(HashCode, ArkTools, Undefined())
#define BUILTINS_CONSTRUCTOR_STUB_LIST(V) \
V(BooleanConstructor) \
V(NumberConstructor) \

View File

@ -31,6 +31,7 @@
#include "ecmascript/compiler/new_object_stub_builder.h"
#include "ecmascript/compiler/stub_builder-inl.h"
#include "ecmascript/compiler/stub_builder.h"
#include "ecmascript/compiler/hash_stub_builder.h"
#include "ecmascript/compiler/variable_type.h"
#include "ecmascript/js_date.h"
#include "ecmascript/js_primitive_ref.h"
@ -217,6 +218,28 @@ BUILTINS_METHOD_STUB_LIST(DECLARE_BUILTINS_STUB_BUILDER, DECLARE_BUILTINS_STUB_B
#undef DECLARE_BUILTINS_STUB_BUILDER1
#undef DECLARE_BUILTINS_COLLECTION_STUB_BUILDER
DECLARE_BUILTINS(ArkToolsHashCode)
{
(void) nativeCode;
(void) func;
(void) newTarget;
(void) thisValue;
auto env = GetEnvironment();
GateRef key = GetCallArg0(numArgs);
Label irHash(env);
Label rtHash(env);
BRANCH(IntPtrEqual(numArgs, IntPtr(1)), &irHash, &rtHash);
Bind(&irHash);
{
HashStubBuilder hashBuilder(this, glue);
GateRef hash = hashBuilder.GetHash(key);
Return(env->GetBuilder()->Int32ToTaggedPtr(hash));
}
Bind(&rtHash);
Return(CallRuntime(glue, RTSTUB_ID(GetLinkedHash), { key }));
}
// aot and builtins public stub function
#define DECLARE_AOT_AND_BUILTINS_STUB_BUILDER(stubName, method, type, initValue) \
DECLARE_BUILTINS(stubName) \

View File

@ -16,6 +16,7 @@
#include "ecmascript/compiler/builtins/linked_hashtable_stub_builder.h"
#include "ecmascript/compiler/builtins/builtins_stubs.h"
#include "ecmascript/compiler/hash_stub_builder.h"
#include "ecmascript/compiler/new_object_stub_builder.h"
#include "ecmascript/linked_hash_table.h"
#include "ecmascript/js_set.h"
@ -72,7 +73,8 @@ void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Reh
}
Bind(&notWeak);
GateRef hash = GetHash(*key);
HashStubBuilder hashBuilder(this, glue_);
GateRef hash = hashBuilder.GetHash(*key);
GateRef bucket = HashToBucket(newTable, hash);
InsertNewEntry(newTable, bucket, *desEntry);
GateRef desIndex = EntryToIndex(newTable, *desEntry);
@ -222,45 +224,6 @@ GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::
return ret;
}
template <typename LinkedHashTableType, typename LinkedHashTableObject>
GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GetHash(GateRef key)
{
auto env = GetEnvironment();
Label entryLabel(env);
Label exit(env);
env->SubCfgEntry(&entryLabel);
DEFVARIABLE(res, VariableType::INT32(), Int32(0));
Label symbolKey(env);
Label stringCheck(env);
BRANCH(TaggedIsSymbol(key), &symbolKey, &stringCheck);
Bind(&symbolKey);
{
res = Load(VariableType::INT32(), key, IntPtr(JSSymbol::HASHFIELD_OFFSET));
Jump(&exit);
}
Bind(&stringCheck);
Label stringKey(env);
Label slowGetHash(env);
BRANCH(TaggedIsString(key), &stringKey, &slowGetHash);
Bind(&stringKey);
{
res = GetHashcodeFromString(glue_, key);
Jump(&exit);
}
Bind(&slowGetHash);
{
// GetHash();
GateRef hash = CallRuntime(glue_, RTSTUB_ID(GetLinkedHash), { key });
res = GetInt32OfTInt(hash);
Jump(&exit);
}
Bind(&exit);
auto ret = *res;
env->SubCfgExit();
return ret;
}
template <typename LinkedHashTableType, typename LinkedHashTableObject>
GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::HashObjectIsMatch(
GateRef key, GateRef other)
@ -543,7 +506,8 @@ GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::
env->SubCfgEntry(&cfgEntry);
Label exit(env);
DEFVARIABLE(res, VariableType::JS_ANY(), linkedTable);
GateRef hash = GetHash(key);
HashStubBuilder hashBuilder(this, glue_);
GateRef hash = hashBuilder.GetHash(key);
GateRef entry = FindElement(linkedTable, key, hash);
Label findEntry(env);
Label notFind(env);
@ -589,7 +553,8 @@ GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::
env->SubCfgEntry(&cfgEntry);
Label exit(env);
DEFVARIABLE(res, VariableType::JS_ANY(), TaggedFalse());
GateRef hash = GetHash(key);
HashStubBuilder hashBuilder(this, glue_);
GateRef hash = hashBuilder.GetHash(key);
GateRef entry = FindElement(linkedTable, key, hash);
Label findEntry(env);
BRANCH(Int32Equal(entry, Int32(-1)), &exit, &findEntry);
@ -624,7 +589,9 @@ GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::
GateRef size = GetNumberOfElements(linkedTable);
BRANCH(Int32Equal(size, Int32(0)), &exit, &nonEmpty);
Bind(&nonEmpty);
GateRef hash = GetHash(key);
HashStubBuilder hashBuilder(this, glue_);
GateRef hash = hashBuilder.GetHash(key);
GateRef entry = FindElement(linkedTable, key, hash);
Label findEntry(env);
BRANCH(Int32Equal(entry, Int32(-1)), &exit, &findEntry);
@ -747,7 +714,8 @@ GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::
env->SubCfgEntry(&cfgEntry);
Label exit(env);
DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
GateRef hash = GetHash(key);
HashStubBuilder hashBuilder(this, glue_);
GateRef hash = hashBuilder.GetHash(key);
GateRef entry = FindElement(linkedTable, key, hash);
Label findEntry(env);
Branch(Int32Equal(entry, Int32(-1)), &exit, &findEntry);

View File

@ -56,7 +56,6 @@ private:
return Int32Add(bucket, Int32(LinkedHashTableType::ELEMENTS_START_INDEX));
}
GateRef GetHash(GateRef key);
GateRef HashObjectIsMatch(GateRef key, GateRef other);
GateRef FindElement(GateRef linkedTable, GateRef key, GateRef hash);
GateRef GetKey(GateRef linkedTable, GateRef entry)

View File

@ -719,6 +719,8 @@ public:
GateRef NumberToString(GateRef number);
GateRef TaggedPointerToInt64(GateRef x);
GateRef GetLengthFromString(GateRef value);
GateRef Rotl(GateRef word, uint32_t shift);
GateRef CalcHashcodeForInt(GateRef value);
GateRef GetHashcodeFromString(GateRef glue, GateRef value);
GateRef TryGetHashcodeFromString(GateRef string);
GateRef IsIntegerString(GateRef string);

View File

@ -0,0 +1,89 @@
/*
* 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 "ecmascript/compiler/hash_stub_builder.h"
namespace panda::ecmascript::kungfu {
GateRef HashStubBuilder::GetHash(GateRef key)
{
auto env = GetEnvironment();
Label entryLabel(env);
Label exit(env);
env->SubCfgEntry(&entryLabel);
DEFVARIABLE(res, VariableType::INT32(), Int32(0));
Label slowGetHash(env);
Label symbolKey(env);
Label stringCheck(env);
BRANCH(TaggedIsSymbol(key), &symbolKey, &stringCheck);
Bind(&symbolKey);
res = Load(VariableType::INT32(), key, IntPtr(JSSymbol::HASHFIELD_OFFSET));
Jump(&exit);
Bind(&stringCheck);
Label stringKey(env);
Label objectCheck(env);
BRANCH(TaggedIsString(key), &stringKey, &objectCheck);
Bind(&stringKey);
res = GetHashcodeFromString(glue_, key);
Jump(&exit);
Bind(&objectCheck);
Label heapObjectKey(env);
Label numberCheck(env);
BRANCH(TaggedIsHeapObject(key), &heapObjectKey, &numberCheck);
Bind(&heapObjectKey);
Label ecmaObjectKey(env);
BRANCH(TaggedObjectIsEcmaObject(key), &ecmaObjectKey, &slowGetHash);
Bind(&ecmaObjectKey);
CalcHashcodeForObject(glue_, key, &res, &exit);
Bind(&numberCheck);
Label numberKey(env);
BRANCH(TaggedIsNumber(key), &numberKey, &slowGetHash);
Bind(&numberKey);
CalcHashcodeForNumber(key, &res, &exit);
Bind(&slowGetHash);
res = GetInt32OfTInt(CallRuntime(glue_, RTSTUB_ID(GetLinkedHash), { key }));
Jump(&exit);
Bind(&exit);
auto ret = *res;
env->SubCfgExit();
return ret;
}
void HashStubBuilder::CalcHashcodeForNumber(GateRef key, Variable *res, Label *exit)
{
auto env = GetEnvironment();
Label doubleKey(env);
Label intKey(env);
BRANCH(TaggedIsDouble(key), &doubleKey, &intKey);
Bind(&doubleKey);
{
CalcHashcodeForDouble(key, res, exit);
}
Bind(&intKey);
{
*res = CalcHashcodeForInt(key);
Jump(exit);
}
}
} // namespace panda::ecmascript::kungfu

View File

@ -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.
*/
#ifndef ECMASCRIPT_COMPILER_HASH_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_HASH_STUB_BUILDER_H
#include "ecmascript/compiler/builtins/builtins_string_stub_builder.h"
#include "ecmascript/compiler/profiler_operation.h"
#include "ecmascript/compiler/stub_builder.h"
namespace panda::ecmascript::kungfu {
class HashStubBuilder : public StubBuilder {
public:
explicit HashStubBuilder(StubBuilder *parent, GateRef glue)
: StubBuilder(parent), glue_(glue) {}
~HashStubBuilder() override = default;
NO_MOVE_SEMANTIC(HashStubBuilder);
NO_COPY_SEMANTIC(HashStubBuilder);
void GenerateCircuit() override {}
GateRef GetHash(GateRef key);
private:
void CalcHashcodeForNumber(GateRef key, Variable *res, Label *exit);
GateRef glue_;
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_HASH_STUB_BUILDER_H

View File

@ -13,6 +13,8 @@
* limitations under the License.
*/
#include "libpandabase/utils/hash.h"
#include "ecmascript/compiler/mcr_circuit_builder.h"
#include "ecmascript/compiler/circuit_builder.h"
@ -1214,6 +1216,43 @@ GateRef CircuitBuilder::GetLengthFromString(GateRef value)
return Int32LSR(len, Int32(EcmaString::STRING_LENGTH_SHIFT_COUNT));
}
GateRef CircuitBuilder::Rotl(GateRef word, uint32_t shift)
{
static constexpr uint32_t MAX_BITS = 32;
return Int32Or(Int32LSL(word, Int32(shift)), Int32LSR(word, Int32(MAX_BITS - shift)));
}
GateRef CircuitBuilder::CalcHashcodeForInt(GateRef value)
{
GateRef rawVal = ChangeTaggedPointerToInt64(value);
GateRef low = TruncInt64ToInt32(rawVal);
GateRef k1 = Int32Mul(low, Int32(MurmurHash32Const::C1));
GateRef k2 = Rotl(k1, MurmurHash32Const::MAIN_FIRST_SHIFT);
GateRef k3 = Int32Mul(k2, Int32(MurmurHash32Const::C2));
GateRef hash1 = Int32Xor(Int32(DEFAULT_SEED), k3);
GateRef hash2 = Rotl(hash1, MurmurHash32Const::MAIN_SECOND_SHIFT);
GateRef hash3 = Int32Add(Int32Mul(hash2, Int32(MurmurHash32Const::MAIN_MULTIPLICATOR)),
Int32(MurmurHash32Const::MAIN_CONSTANT));
GateRef high = TruncInt64ToInt32(Int64LSR(rawVal, Int64(32U)));
GateRef k4 = Int32Mul(high, Int32(MurmurHash32Const::C1));
GateRef k5 = Rotl(k4, MurmurHash32Const::MAIN_FIRST_SHIFT);
GateRef k6 = Int32Mul(k5, Int32(MurmurHash32Const::C2));
GateRef hash4 = Int32Xor(hash3, k6);
GateRef hash5 = Rotl(hash4, MurmurHash32Const::MAIN_SECOND_SHIFT);
GateRef hash6 = Int32Add(Int32Mul(hash5, Int32(MurmurHash32Const::MAIN_MULTIPLICATOR)),
Int32(MurmurHash32Const::MAIN_CONSTANT));
GateRef hash7 = Int32Xor(hash6, Int32(8U));
// Finalize
GateRef hash8 = Int32Xor(hash7, Int32LSR(hash7, Int32(MurmurHash32Const::FINALIZE_FIRST_SHIFT)));
GateRef hash9 = Int32Mul(hash8, Int32(MurmurHash32Const::FINALIZE_FIRST_MULTIPLICATOR));
GateRef hash10 = Int32Xor(hash9, Int32LSR(hash9, Int32(MurmurHash32Const::FINALIZE_SECOND_SHIFT)));
GateRef hash11 = Int32Mul(hash10, Int32(MurmurHash32Const::FINALIZE_SECOND_MULTIPLICATOR));
GateRef hash12 = Int32Xor(hash11, Int32LSR(hash11, Int32(MurmurHash32Const::FINALIZE_THIRD_SHIFT)));
return hash12;
}
GateRef CircuitBuilder::GetHashcodeFromString(GateRef glue, GateRef value)
{
ASSERT(!GetCircuit()->IsOptimizedJSFunctionFrame());

View File

@ -1069,6 +1069,12 @@ inline void StubBuilder::SetPropertiesArray(VariableType type, GateRef glue, Gat
Store(type, glue, object, propertiesOffset, propsArray);
}
inline GateRef StubBuilder::GetHash(GateRef object)
{
GateRef hashOffset = IntPtr(ECMAObject::HASH_OFFSET);
return Load(VariableType::JS_ANY(), object, hashOffset);
}
inline void StubBuilder::SetHash(GateRef glue, GateRef object, GateRef hash)
{
GateRef hashOffset = IntPtr(ECMAObject::HASH_OFFSET);

View File

@ -6737,6 +6737,107 @@ void StubBuilder::ReturnExceptionIfAbruptCompletion(GateRef glue)
return;
}
GateRef StubBuilder::CalcHashcodeForInt(GateRef value)
{
return env_->GetBuilder()->CalcHashcodeForInt(value);
}
GateRef StubBuilder::CanDoubleRepresentInt(GateRef exp, GateRef expBits, GateRef fractionBits)
{
GateRef isNanOrInf = Int64Equal(expBits, Int64(base::DOUBLE_EXPONENT_MASK));
GateRef isSubnormal = BoolAnd(
Int64Equal(expBits, Int64(0)),
Int64NotEqual(fractionBits, Int64(0)));
GateRef hasFraction = Int64NotEqual(
Int64And(
Int64LSL(fractionBits, exp),
Int64(base::DOUBLE_SIGNIFICAND_MASK)),
Int64(0));
GateRef badExp = BoolOr(
Int64LessThan(exp, Int64(0)),
Int64GreaterThanOrEqual(exp, Int64(31U)));
return BoolOr(BoolOr(BoolOr(isNanOrInf, isSubnormal), badExp), hasFraction);
}
void StubBuilder::CalcHashcodeForDouble(GateRef x, Variable *res, Label *exit)
{
auto env = GetEnvironment();
GateRef xInt64 = Int64Sub(ChangeTaggedPointerToInt64(x), Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
GateRef fractionBits = Int64And(xInt64, Int64(base::DOUBLE_SIGNIFICAND_MASK));
GateRef expBits = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
GateRef signBit = Int64And(xInt64, Int64(base::DOUBLE_SIGN_MASK));
GateRef isZero = BoolAnd(
Int64Equal(expBits, Int64(0)),
Int64Equal(fractionBits, Int64(0)));
Label zero(env);
Label nonZero(env);
BRANCH(isZero, &zero, &nonZero);
Bind(&nonZero);
{
DEFVARIABLE(value, VariableType::JS_ANY(), x);
// exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
GateRef exp = Int64Sub(
Int64LSR(expBits, Int64(base::DOUBLE_SIGNIFICAND_SIZE)),
Int64(base::DOUBLE_EXPONENT_BIAS));
Label convertToInt(env);
Label calcHash(env);
BRANCH(CanDoubleRepresentInt(exp, expBits, fractionBits), &calcHash, &convertToInt);
Bind(&convertToInt);
{
GateRef shift = Int64Sub(Int64(base::DOUBLE_SIGNIFICAND_SIZE), exp);
GateRef intVal = Int64Add(
Int64LSL(Int64(1), exp),
Int64LSR(fractionBits, shift));
DEFVARIABLE(intVariable, VariableType::INT64(), intVal);
Label negate(env);
Label pass(env);
BRANCH(Int64NotEqual(signBit, Int64(0)), &negate, &pass);
Bind(&negate);
{
intVariable = Int64Sub(Int64(0), intVal);
Jump(&pass);
}
Bind(&pass);
value = IntToTaggedPtr(TruncInt64ToInt32(*intVariable));
Jump(&calcHash);
}
Bind(&calcHash);
{
*res = env_->GetBuilder()->CalcHashcodeForInt(*value);
Jump(exit);
}
}
Bind(&zero);
*res = env_->GetBuilder()->CalcHashcodeForInt(IntToTaggedPtr(Int32(0)));
Jump(exit);
}
void StubBuilder::CalcHashcodeForObject(GateRef glue, GateRef value, Variable *res, Label *exit)
{
auto env = GetEnvironment();
GateRef hash = GetHash(value);
*res = TruncInt64ToInt32(TaggedCastToIntPtr(hash));
Label calcHash(env);
BRANCH(Int32Equal(**res, Int32(0)), &calcHash, exit);
Bind(&calcHash);
GateRef offset = IntPtr(JSThread::GlueData::GetRandomStatePtrOffset(env_->Is32Bit()));
GateRef randomStatePtr = Load(VariableType::NATIVE_POINTER(), glue, offset);
GateRef randomState = Load(VariableType::INT64(), randomStatePtr, IntPtr(0));
GateRef k1 = Int64Xor(randomState, Int64LSR(randomState, Int64(base::RIGHT12)));
GateRef k2 = Int64Xor(k1, Int64LSL(k1, Int64(base::LEFT25)));
GateRef k3 = Int64Xor(k2, Int64LSR(k2, Int64(base::RIGHT27)));
Store(VariableType::INT64(), glue, randomStatePtr, IntPtr(0), k3);
GateRef k4 = Int64Mul(k3, Int64(base::GET_MULTIPLY));
GateRef k5 = Int64LSR(k4, Int64(base::INT64_BITS - base::INT32_BITS));
GateRef k6 = Int32And(TruncInt64ToInt32(k5), Int32(INT32_MAX));
SetHash(glue, value, IntToTaggedPtr(k6));
*res = k6;
Jump(exit);
}
GateRef StubBuilder::GetHashcodeFromString(GateRef glue, GateRef value)
{
return env_->GetBuilder()->GetHashcodeFromString(glue, value);

View File

@ -322,6 +322,7 @@ public:
GateRef GetPropertiesArray(GateRef object);
// SetProperties in js_object.h
void SetPropertiesArray(VariableType type, GateRef glue, GateRef object, GateRef propsArray);
GateRef GetHash(GateRef object);
void SetHash(GateRef glue, GateRef object, GateRef hash);
GateRef GetLengthOfTaggedArray(GateRef array);
GateRef GetLengthOfJSTypedArray(GateRef array);
@ -452,6 +453,9 @@ public:
GateRef GetLayoutFromHClass(GateRef hClass);
GateRef GetBitFieldFromHClass(GateRef hClass);
GateRef GetLengthFromString(GateRef value);
GateRef CalcHashcodeForInt(GateRef value);
void CalcHashcodeForDouble(GateRef value, Variable *res, Label *exit);
void CalcHashcodeForObject(GateRef glue, GateRef value, Variable *res, Label *exit);
GateRef GetHashcodeFromString(GateRef glue, GateRef value);
inline GateRef IsIntegerString(GateRef string);
inline void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger);
@ -863,6 +867,7 @@ private:
void InitializeArguments();
void CheckDetectorName(GateRef glue, GateRef key, Label *fallthrough, Label *slow);
bool IsCallModeSupportPGO(JSCallMode mode);
GateRef CanDoubleRepresentInt(GateRef exp, GateRef expBits, GateRef fractionBits);
CallSignature *callSignature_ {nullptr};
Environment *env_;

View File

@ -149,7 +149,7 @@ void EcmaVM::PreFork()
void EcmaVM::PostFork()
{
RandomGenerator::InitRandom();
RandomGenerator::InitRandom(GetAssociatedJSThread());
heap_->SetHeapMode(HeapMode::SHARE);
GetAssociatedJSThread()->PostFork();
Taskpool::GetCurrentTaskpool()->Initialize();

View File

@ -836,6 +836,11 @@ public:
return glueData_.propertiesGrowStep_;
}
void SetRandomStatePtr(uint64_t *ptr)
{
glueData_.randomStatePtr_ = reinterpret_cast<uintptr_t>(ptr);
}
struct GlueData : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
BCStubEntries,
JSTaggedValue,
@ -868,6 +873,7 @@ public:
BuiltinEntries,
base::AlignedBool,
base::AlignedPointer,
base::AlignedPointer,
base::AlignedUint32> {
enum class Index : size_t {
BCStubEntriesIndex = 0,
@ -901,6 +907,7 @@ public:
BuiltinEntriesIndex,
IsTracingIndex,
unsharedConstpoolsIndex,
RandomStatePtrIndex,
stateAndFlagsIndex,
NumOfMembers
};
@ -1087,6 +1094,11 @@ public:
return GetOffset<static_cast<size_t>(Index::stateAndFlagsIndex)>(isArch32);
}
static size_t GetRandomStatePtrOffset(bool isArch32)
{
return GetOffset<static_cast<size_t>(Index::RandomStatePtrIndex)>(isArch32);
}
alignas(EAS) BCStubEntries bcStubEntries_;
alignas(EAS) JSTaggedValue exception_ {JSTaggedValue::Hole()};
alignas(EAS) JSTaggedValue globalObject_ {JSTaggedValue::Hole()};
@ -1118,6 +1130,7 @@ public:
alignas(EAS) BuiltinEntries builtinEntries_;
alignas(EAS) bool isTracing_ {false};
alignas(EAS) uintptr_t unsharedConstpools_ {0};
alignas(EAS) uintptr_t randomStatePtr_ {0};
alignas(EAS) ThreadStateAndFlags stateAndFlags_ {};
};
STATIC_ASSERT_EQ_ARCH(sizeof(GlueData), GlueData::SizeArch32, GlueData::SizeArch64);

View File

@ -16,3 +16,4 @@ value
-1
-2
undefined
success

View File

@ -32,3 +32,40 @@ for (let i = 0; i < 4; ++i) {
let value = map.get(i);
print(value);
}
map = new Map();
let key = Number.parseFloat("1392210229");
map.set(key, "success");
let value = map.get(key);
print(value);
function check(key) {
let irHash = ArkTools.hashCode(key);
let rtHash = ArkTools.hashCode(key, true);
if (irHash != rtHash) {
throw new Error("Mismatch hash for " + key + ": expected " + rtHash + ", but got " + irHash);
}
}
check(0);
check(1);
check(-1);
check(1.5);
check(-1.5);
check(Number.EPSILON);
check(Number.NaN);
check(Number.MIN_VALUE);
check(Number.MAX_VALUE);
check(Number.MIN_SAFE_INTEGER);
check(Number.MIN_SAFE_INTEGER - 1);
check(Number.MAX_SAFE_INTEGER);
check(Number.MAX_SAFE_INTEGER + 1);
check(Number.NaN);
check(Number.POSITIVE_INFINITY);
check(Number.NEGATIVE_INFINITY);
check(Number.parseFloat("+0.0"));
check(Number.parseFloat("-0.0"));
// regression test
check(Number.parseFloat("1392210229"));