mirror of
https://github.com/openharmony/ark_js_runtime.git
synced 2026-07-22 07:35:27 -04:00
50ee964a21
Signed-off-by: wupengyong <wupengyong@huawei.com> Change-Id: I085d81d00b00a0b49daa0d28af591b83dc1c9759
796 lines
28 KiB
C++
796 lines
28 KiB
C++
/*
|
|
* 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 "ecmascript/compiler/stub.h"
|
|
|
|
#include "ecmascript/compiler/llvm_ir_builder.h"
|
|
#include "ecmascript/js_object.h"
|
|
#include "ecmascript/tagged_hash_table-inl.h"
|
|
#include "libpandabase/macros.h"
|
|
|
|
namespace kungfu {
|
|
using LabelImpl = Stub::Label::LabelImpl;
|
|
|
|
Stub::Label::Label(Environment *env)
|
|
{
|
|
impl_ = env->NewLabel(env);
|
|
}
|
|
|
|
AddrShift Stub::Variable::AddPhiOperand(AddrShift val)
|
|
{
|
|
ASSERT(IsSelector(val));
|
|
Label label = env_->GetLabelFromSelector(val);
|
|
size_t idx = 0;
|
|
for (auto pred : label.GetPredecessors()) {
|
|
idx++;
|
|
val = AddOperandToSelector(val, idx, pred.ReadVariable(this));
|
|
}
|
|
|
|
return TryRemoveTrivialPhi(val);
|
|
}
|
|
|
|
AddrShift Stub::Variable::AddOperandToSelector(AddrShift val, size_t idx, AddrShift in)
|
|
{
|
|
env_->GetCircuit()->NewIn(val, idx, in);
|
|
return val;
|
|
}
|
|
|
|
AddrShift Stub::Variable::TryRemoveTrivialPhi(AddrShift phiVal)
|
|
{
|
|
Gate *phi = env_->GetCircuit()->LoadGatePtr(phiVal);
|
|
Gate *same = nullptr;
|
|
for (size_t i = 1; i < phi->GetNumIns(); ++i) {
|
|
In *phiIn = phi->GetIn(i);
|
|
Gate *op = (!phiIn->IsGateNull()) ? phiIn->GetGate() : nullptr;
|
|
if (op == same || op == phi) {
|
|
continue; // unique value or self-reference
|
|
}
|
|
if (same != nullptr) {
|
|
return phiVal; // the phi merges at least two values: not trivial
|
|
}
|
|
same = op;
|
|
}
|
|
if (same == nullptr) {
|
|
// the phi is unreachable or in the start block
|
|
same = env_->GetCircuit()->LoadGatePtr(env_->GetCircuitBuilder().UndefineConstant());
|
|
}
|
|
|
|
// remove the trivial phi
|
|
// get all users of phi except self
|
|
std::vector<Out *> outs;
|
|
if (!phi->IsFirstOutNull()) {
|
|
Out *phiOut = phi->GetFirstOut();
|
|
while (!phiOut->IsNextOutNull()) {
|
|
if (phiOut->GetGate() != phi) {
|
|
// remove phi
|
|
outs.push_back(phiOut);
|
|
}
|
|
phiOut = phiOut->GetNextOut();
|
|
}
|
|
// save last phi out
|
|
if (phiOut->GetGate() != phi) {
|
|
outs.push_back(phiOut);
|
|
}
|
|
}
|
|
// reroute all outs of phi to same and remove phi
|
|
RerouteOuts(outs, same);
|
|
phi->DeleteGate();
|
|
|
|
// try to recursiveby remove all phi users, which might have vecome trivial
|
|
for (auto out : outs) {
|
|
if (IsSelector(out->GetGate())) {
|
|
auto out_addr_shift = env_->GetCircuit()->SaveGatePtr(out->GetGate());
|
|
TryRemoveTrivialPhi(out_addr_shift);
|
|
}
|
|
}
|
|
return env_->GetCircuit()->SaveGatePtr(same);
|
|
}
|
|
|
|
void Stub::Variable::RerouteOuts(const std::vector<Out *> &outs, Gate *newGate)
|
|
{
|
|
// reroute all outs to new node
|
|
for (auto out : outs) {
|
|
size_t idx = out->GetIndex();
|
|
out->GetGate()->ModifyIn(idx, newGate);
|
|
}
|
|
}
|
|
|
|
void LabelImpl::Seal()
|
|
{
|
|
for (auto &[variable, gate] : incompletePhis_) {
|
|
variable->AddPhiOperand(gate);
|
|
}
|
|
isSealed_ = true;
|
|
}
|
|
|
|
void LabelImpl::WriteVariable(Variable *var, AddrShift value)
|
|
{
|
|
valueMap_[var] = value;
|
|
}
|
|
|
|
AddrShift LabelImpl::ReadVariable(Variable *var)
|
|
{
|
|
if (valueMap_.find(var) != valueMap_.end()) {
|
|
return valueMap_.at(var);
|
|
}
|
|
return ReadVariableRecursive(var);
|
|
}
|
|
|
|
AddrShift LabelImpl::ReadVariableRecursive(Variable *var)
|
|
{
|
|
AddrShift val;
|
|
OpCode opcode = CircuitBuilder::GetSelectOpCodeFromMachineType(var->Type());
|
|
if (!IsSealed()) {
|
|
// only loopheader gate will be not sealed
|
|
int valueCounts = static_cast<int>(this->predecessors_.size()) + 1;
|
|
|
|
val = env_->GetCircuitBuilder().NewSelectorGate(opcode, predeControl_, valueCounts);
|
|
env_->AddSelectorToLabel(val, Label(this));
|
|
incompletePhis_[var] = val;
|
|
} else if (predecessors_.size() == 1) {
|
|
val = predecessors_[0]->ReadVariable(var);
|
|
} else {
|
|
val = env_->GetCircuitBuilder().NewSelectorGate(opcode, predeControl_, this->predecessors_.size());
|
|
env_->AddSelectorToLabel(val, Label(this));
|
|
WriteVariable(var, val);
|
|
val = var->AddPhiOperand(val);
|
|
}
|
|
WriteVariable(var, val);
|
|
return val;
|
|
}
|
|
|
|
void LabelImpl::Bind()
|
|
{
|
|
ASSERT(!predecessors_.empty());
|
|
if (IsLoopHead()) {
|
|
// 2 means input number of depend selector gate
|
|
loopDepend_ = env_->GetCircuitBuilder().NewSelectorGate(OpCode(OpCode::DEPEND_SELECTOR), predeControl_, 2);
|
|
env_->GetCircuit()->NewIn(loopDepend_, 1, predecessors_[0]->GetDepend());
|
|
depend_ = loopDepend_;
|
|
}
|
|
if (IsNeedSeal()) {
|
|
Seal();
|
|
MergeAllControl();
|
|
MergeAllDepend();
|
|
}
|
|
}
|
|
|
|
void LabelImpl::MergeAllControl()
|
|
{
|
|
if (predecessors_.size() < 2) { // 2 : Loop Head only support two predecessors_
|
|
return;
|
|
}
|
|
|
|
if (IsLoopHead()) {
|
|
ASSERT(predecessors_.size() == 2); // 2 : Loop Head only support two predecessors_
|
|
ASSERT(otherPredeControls_.size() == 1);
|
|
env_->GetCircuit()->NewIn(predeControl_, 1, otherPredeControls_[0]);
|
|
return;
|
|
}
|
|
|
|
// merge all control of predecessors_
|
|
std::vector<AddrShift> inGates(predecessors_.size());
|
|
size_t i = 0;
|
|
ASSERT(predeControl_ != -1);
|
|
ASSERT((otherPredeControls_.size() + 1) == predecessors_.size());
|
|
inGates[i++] = predeControl_;
|
|
for (auto in : otherPredeControls_) {
|
|
inGates[i++] = in;
|
|
}
|
|
|
|
AddrShift merge = env_->GetCircuitBuilder().NewMerge(inGates.data(), inGates.size());
|
|
predeControl_ = merge;
|
|
control_ = merge;
|
|
}
|
|
|
|
void LabelImpl::MergeAllDepend()
|
|
{
|
|
if (IsControlCase()) {
|
|
// Add depend_relay to current label
|
|
auto denpendEntry = Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY));
|
|
dependRelay_ = env_->GetCircuitBuilder().NewDependRelay(predeControl_, denpendEntry);
|
|
}
|
|
|
|
if (predecessors_.size() < 2) { // 2 : Loop Head only support two predecessors_
|
|
depend_ = predecessors_[0]->GetDepend();
|
|
if (dependRelay_ != -1) {
|
|
depend_ = env_->GetCircuitBuilder().NewDependAnd({depend_, dependRelay_});
|
|
}
|
|
return;
|
|
}
|
|
if (IsLoopHead()) {
|
|
ASSERT(predecessors_.size() == 2); // 2 : Loop Head only support two predecessors_
|
|
// Add loop depend to in of depend_seclector
|
|
ASSERT(loopDepend_ != -1);
|
|
// 2 mean 3rd input gate for loopDepend_(depend_selector)
|
|
env_->GetCircuit()->NewIn(loopDepend_, 2, predecessors_[1]->GetDepend());
|
|
return;
|
|
}
|
|
|
|
// Merge all depends to depend_seclector
|
|
std::vector<AddrShift> dependsList;
|
|
for (auto prede : this->GetPredecessors()) {
|
|
dependsList.push_back(prede->GetDepend());
|
|
}
|
|
depend_ = env_->GetCircuitBuilder().NewSelectorGate(OpCode(OpCode::DEPEND_SELECTOR), predeControl_, dependsList,
|
|
dependsList.size());
|
|
}
|
|
|
|
void LabelImpl::AppendPredecessor(LabelImpl *predecessor)
|
|
{
|
|
if (predecessor != nullptr) {
|
|
predecessors_.push_back(predecessor);
|
|
}
|
|
}
|
|
|
|
bool LabelImpl::IsNeedSeal() const
|
|
{
|
|
auto control = env_->GetCircuit()->LoadGatePtr(predeControl_);
|
|
auto numsInList = control->GetOpCode().GetOpCodeNumInsArray(control->GetBitField());
|
|
return predecessors_.size() >= numsInList[0];
|
|
}
|
|
|
|
bool LabelImpl::IsLoopHead() const
|
|
{
|
|
return env_->GetCircuit()->IsLoopHead(predeControl_);
|
|
}
|
|
|
|
bool LabelImpl::IsControlCase() const
|
|
{
|
|
return env_->GetCircuit()->IsControlCase(predeControl_);
|
|
}
|
|
|
|
Stub::Environment::Environment(size_t arguments, Circuit *circuit)
|
|
: circuit_(circuit), builder_(circuit), arguments_(arguments)
|
|
{
|
|
for (size_t i = 0; i < arguments; i++) {
|
|
arguments_[i] = builder_.NewArguments(i);
|
|
}
|
|
entry_ = Label(NewLabel(this, Circuit::GetCircuitRoot(OpCode(OpCode::STATE_ENTRY))));
|
|
currentLabel_ = &entry_;
|
|
currentLabel_->Seal();
|
|
auto depend_entry = Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY));
|
|
currentLabel_->SetDepend(depend_entry);
|
|
}
|
|
|
|
Stub::Environment::~Environment()
|
|
{
|
|
for (auto label : rawlabels_) {
|
|
delete label;
|
|
}
|
|
}
|
|
|
|
void Stub::Jump(Label *label)
|
|
{
|
|
ASSERT(label);
|
|
auto currentLabel = env_.GetCurrentLabel();
|
|
auto currentControl = currentLabel->GetControl();
|
|
auto jump = env_.GetCircuitBuilder().Goto(currentControl);
|
|
currentLabel->SetControl(jump);
|
|
label->AppendPredecessor(currentLabel);
|
|
label->MergeControl(currentLabel->GetControl());
|
|
env_.SetCurrentLabel(nullptr);
|
|
}
|
|
|
|
void Stub::Branch(AddrShift condition, Label *trueLabel, Label *falseLabel)
|
|
{
|
|
auto currentLabel = env_.GetCurrentLabel();
|
|
auto currentControl = currentLabel->GetControl();
|
|
AddrShift ifBranch = env_.GetCircuitBuilder().Branch(currentControl, condition);
|
|
currentLabel->SetControl(ifBranch);
|
|
AddrShift ifTrue = env_.GetCircuitBuilder().NewIfTrue(ifBranch);
|
|
trueLabel->AppendPredecessor(env_.GetCurrentLabel());
|
|
trueLabel->MergeControl(ifTrue);
|
|
AddrShift ifFalse = env_.GetCircuitBuilder().NewIfFalse(ifBranch);
|
|
falseLabel->AppendPredecessor(env_.GetCurrentLabel());
|
|
falseLabel->MergeControl(ifFalse);
|
|
env_.SetCurrentLabel(nullptr);
|
|
}
|
|
|
|
void Stub::Switch(AddrShift index, Label *defaultLabel, int32_t *keysValue, Label *keysLabel, int numberOfKeys)
|
|
{
|
|
auto currentLabel = env_.GetCurrentLabel();
|
|
auto currentControl = currentLabel->GetControl();
|
|
AddrShift switchBranch = env_.GetCircuitBuilder().SwitchBranch(currentControl, index, numberOfKeys);
|
|
currentLabel->SetControl(switchBranch);
|
|
for (int i = 0; i < numberOfKeys; i++) {
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
|
AddrShift switchCase = env_.GetCircuitBuilder().NewSwitchCase(switchBranch, keysValue[i]);
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
|
keysLabel[i].AppendPredecessor(currentLabel);
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
|
keysLabel[i].MergeControl(switchCase);
|
|
}
|
|
|
|
AddrShift defaultCase = env_.GetCircuitBuilder().NewDefaultCase(switchBranch);
|
|
defaultLabel->AppendPredecessor(currentLabel);
|
|
defaultLabel->MergeControl(defaultCase);
|
|
env_.SetCurrentLabel(nullptr);
|
|
}
|
|
|
|
void Stub::LoopBegin(Label *loopHead)
|
|
{
|
|
ASSERT(loopHead);
|
|
auto loopControl = env_.GetCircuitBuilder().LoopBegin(loopHead->GetControl());
|
|
loopHead->SetControl(loopControl);
|
|
loopHead->SetPreControl(loopControl);
|
|
loopHead->Bind();
|
|
env_.SetCurrentLabel(loopHead);
|
|
}
|
|
|
|
void Stub::LoopEnd(Label *loopHead)
|
|
{
|
|
ASSERT(loopHead);
|
|
auto currentLabel = env_.GetCurrentLabel();
|
|
auto currentControl = currentLabel->GetControl();
|
|
auto loopend = env_.GetCircuitBuilder().LoopEnd(currentControl);
|
|
currentLabel->SetControl(loopend);
|
|
loopHead->AppendPredecessor(currentLabel);
|
|
loopHead->MergeControl(loopend);
|
|
loopHead->Seal();
|
|
loopHead->MergeAllControl();
|
|
loopHead->MergeAllDepend();
|
|
env_.SetCurrentLabel(nullptr);
|
|
}
|
|
|
|
AddrShift Stub::FixLoadType(AddrShift x)
|
|
{
|
|
if (PtrValueCode() == ValueCode::INT64) {
|
|
return SExtInt32ToInt64(x);
|
|
}
|
|
if (PtrValueCode() == ValueCode::INT32) {
|
|
return TruncInt64ToInt32(x);
|
|
}
|
|
UNREACHABLE();
|
|
}
|
|
|
|
AddrShift Stub::LoadFromObject(MachineType type, AddrShift object, AddrShift offset)
|
|
{
|
|
AddrShift elementsOffset = GetInteger32Constant(panda::ecmascript::JSObject::ELEMENTS_OFFSET);
|
|
if (PtrValueCode() == ValueCode::INT64) {
|
|
elementsOffset = SExtInt32ToInt64(elementsOffset);
|
|
}
|
|
// load elements in object
|
|
AddrShift elements = Load(MachineType::UINT64_TYPE, object, elementsOffset);
|
|
// load index in tagged array
|
|
AddrShift dataOffset =
|
|
Int32Add(GetInteger32Constant(panda::coretypes::Array::GetDataOffset()),
|
|
Int32Mul(offset, GetInteger32Constant(panda::ecmascript::JSTaggedValue::TaggedTypeSize())));
|
|
if (PtrValueCode() == ValueCode::INT64) {
|
|
dataOffset = SExtInt32ToInt64(dataOffset);
|
|
}
|
|
return Load(type, ChangeInt64ToPointer(elements), dataOffset);
|
|
}
|
|
|
|
AddrShift Stub::FindElementFromNumberDictionary(AddrShift thread, AddrShift elements, AddrShift key)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subentry(env);
|
|
env->PushCurrentLabel(&subentry);
|
|
DEFVARIABLE(result, INT32_TYPE, GetInteger32Constant(-1));
|
|
Label exit(env);
|
|
AddrShift capcityoffset =
|
|
PtrMul(GetPtrConstant(panda::ecmascript::JSTaggedValue::TaggedTypeSize()),
|
|
GetPtrConstant(panda::ecmascript::TaggedHashTable<panda::ecmascript::NumberDictionary>::SIZE_INDEX));
|
|
AddrShift dataoffset = GetPtrConstant(panda::coretypes::Array::GetDataOffset());
|
|
AddrShift capacity = TaggedCastToInt32(Load(TAGGED_TYPE, elements, PtrAdd(dataoffset, capcityoffset)));
|
|
DEFVARIABLE(count, INT32_TYPE, GetInteger32Constant(1));
|
|
|
|
AddrShift pKey = Alloca(static_cast<int>(MachineRep::K_WORD32));
|
|
AddrShift keyStore = Store(INT32_TYPE, pKey, GetPtrConstant(0), TaggedCastToInt32(key));
|
|
StubDescriptor *getHash32Descriptor = GET_STUBDESCRIPTOR(GetHash32);
|
|
AddrShift len = GetInteger32Constant(sizeof(int) / sizeof(uint8_t));
|
|
AddrShift hash =
|
|
CallRuntime(getHash32Descriptor, thread, GetWord64Constant(FAST_STUB_ID(GetHash32)), keyStore, {pKey, len});
|
|
DEFVARIABLE(entry, INT32_TYPE, Word32And(hash, Int32Sub(capacity, GetInteger32Constant(1))));
|
|
Label loopHead(env);
|
|
Label loopEnd(env);
|
|
Label afterLoop(env);
|
|
Jump(&loopHead);
|
|
LoopBegin(&loopHead);
|
|
AddrShift element = GetKeyFromNumberDictionary(elements, *entry);
|
|
Label isHole(env);
|
|
Label notHole(env);
|
|
Branch(TaggedIsHole(element), &isHole, ¬Hole);
|
|
Bind(&isHole);
|
|
Jump(&loopEnd);
|
|
Bind(¬Hole);
|
|
Label isUndefined(env);
|
|
Label notUndefined(env);
|
|
Branch(TaggedIsUndefined(element), &isUndefined, ¬Undefined);
|
|
Bind(&isUndefined);
|
|
result = GetInteger32Constant(-1);
|
|
Jump(&exit);
|
|
Bind(¬Undefined);
|
|
Label isMatch(env);
|
|
Label notMatch(env);
|
|
Branch(IsMatchInNumberDictionary(key, element), &isMatch, ¬Match);
|
|
Bind(&isMatch);
|
|
result = *entry;
|
|
Jump(&exit);
|
|
Bind(¬Match);
|
|
Jump(&loopEnd);
|
|
Bind(&loopEnd);
|
|
entry = Word32And(Int32Add(*entry, *count), Int32Sub(capacity, GetInteger32Constant(1)));
|
|
count = Int32Add(*count, GetInteger32Constant(1));
|
|
LoopEnd(&loopHead);
|
|
Bind(&exit);
|
|
auto ret = *result;
|
|
env->PopCurrentLabel();
|
|
return ret;
|
|
}
|
|
|
|
AddrShift Stub::IsMatchInNumberDictionary(AddrShift key, AddrShift other)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label entry(env);
|
|
env->PushCurrentLabel(&entry);
|
|
Label exit(env);
|
|
DEFVARIABLE(result, BOOL_TYPE, FalseConstant());
|
|
Label isHole(env);
|
|
Label notHole(env);
|
|
Label isUndefined(env);
|
|
Label notUndefined(env);
|
|
Branch(TaggedIsHole(key), &isHole, ¬Hole);
|
|
Bind(&isHole);
|
|
Jump(&exit);
|
|
Bind(¬Hole);
|
|
Branch(TaggedIsUndefined(key), &isUndefined, ¬Undefined);
|
|
Bind(&isUndefined);
|
|
Jump(&exit);
|
|
Bind(¬Undefined);
|
|
Label keyIsInt(env);
|
|
Label keyNotInt(env);
|
|
Label otherIsInt(env);
|
|
Label otherNotInt(env);
|
|
Branch(TaggedIsInt(key), &keyIsInt, &keyNotInt);
|
|
Bind(&keyIsInt);
|
|
Branch(TaggedIsInt(other), &otherIsInt, &otherNotInt);
|
|
Bind(&otherIsInt);
|
|
result = Word32Equal(TaggedCastToInt32(key), TaggedCastToInt32(other));
|
|
Jump(&exit);
|
|
Bind(&otherNotInt);
|
|
Jump(&exit);
|
|
Bind(&keyNotInt);
|
|
Jump(&exit);
|
|
Bind(&exit);
|
|
auto ret = *result;
|
|
env->PopCurrentLabel();
|
|
return ret;
|
|
}
|
|
|
|
AddrShift Stub::GetKeyFromNumberDictionary(AddrShift elements, AddrShift entry)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subentry(env);
|
|
env->PushCurrentLabel(&subentry);
|
|
Label exit(env);
|
|
DEFVARIABLE(result, TAGGED_TYPE, GetUndefinedConstant());
|
|
Label ltZero(env);
|
|
Label notLtZero(env);
|
|
Label gtLength(env);
|
|
Label notGtLength(env);
|
|
AddrShift dictionaryLength = Load(INT32_TYPE, elements, GetPtrConstant(panda::coretypes::Array::GetLengthOffset()));
|
|
AddrShift arrayIndex =
|
|
Int32Add(GetInteger32Constant(panda::ecmascript::NumberDictionary::TABLE_HEADER_SIZE),
|
|
Int32Mul(entry, GetInteger32Constant(panda::ecmascript::NumberDictionary::ENTRY_SIZE)));
|
|
Branch(Int32LessThan(arrayIndex, GetInteger32Constant(0)), <Zero, ¬LtZero);
|
|
Bind(<Zero);
|
|
Jump(&exit);
|
|
Bind(¬LtZero);
|
|
Branch(Int32GreaterThan(arrayIndex, dictionaryLength), >Length, ¬GtLength);
|
|
Bind(>Length);
|
|
Jump(&exit);
|
|
Bind(¬GtLength);
|
|
result = GetValueFromTaggedArray(elements, arrayIndex);
|
|
Jump(&exit);
|
|
Bind(&exit);
|
|
auto ret = *result;
|
|
env->PopCurrentLabel();
|
|
return ret;
|
|
}
|
|
|
|
// int TaggedHashTable<Derived>::FindEntry(const JSTaggedValue &key) in tagged_hash_table-inl.h
|
|
AddrShift Stub::FindEntryFromNameDictionary(AddrShift thread, AddrShift elements, AddrShift key)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label funcEntry(env);
|
|
env->PushCurrentLabel(&funcEntry);
|
|
Label exit(env);
|
|
DEFVARIABLE(result, INT32_TYPE, GetInteger32Constant(-1));
|
|
AddrShift capcityoffset =
|
|
PtrMul(GetPtrConstant(panda::ecmascript::JSTaggedValue::TaggedTypeSize()),
|
|
GetPtrConstant(panda::ecmascript::TaggedHashTable<panda::ecmascript::NumberDictionary>::SIZE_INDEX));
|
|
AddrShift dataoffset = GetPtrConstant(panda::coretypes::Array::GetDataOffset());
|
|
AddrShift capacity = TaggedCastToInt32(Load(TAGGED_TYPE, elements, PtrAdd(dataoffset, capcityoffset)));
|
|
DEFVARIABLE(count, INT32_TYPE, GetInteger32Constant(1));
|
|
DEFVARIABLE(hash, INT32_TYPE, GetInteger32Constant(0));
|
|
// NameDictionary::hash
|
|
Label isSymbol(env);
|
|
Label notSymbol(env);
|
|
Label loopHead(env);
|
|
Label loopEnd(env);
|
|
Label afterLoop(env);
|
|
Label beforeDefineHash(env);
|
|
Branch(IsSymbol(key), &isSymbol, ¬Symbol);
|
|
Bind(&isSymbol);
|
|
{
|
|
hash = TaggedCastToInt32(Load(TAGGED_TYPE, key, GetPtrConstant(panda::ecmascript::JSSymbol::HASHFIELD_OFFSET)));
|
|
Jump(&beforeDefineHash);
|
|
}
|
|
Bind(¬Symbol);
|
|
{
|
|
Label isString(env);
|
|
Label notString(env);
|
|
Branch(IsString(key), &isString, ¬String);
|
|
Bind(&isString);
|
|
{
|
|
StubDescriptor *stringGetHashCode = GET_STUBDESCRIPTOR(StringGetHashCode);
|
|
hash = CallRuntime(stringGetHashCode, thread, GetWord64Constant(FAST_STUB_ID(StringGetHashCode)), {key});
|
|
Jump(&beforeDefineHash);
|
|
}
|
|
Bind(¬String);
|
|
{
|
|
Jump(&beforeDefineHash);
|
|
}
|
|
}
|
|
Bind(&beforeDefineHash);
|
|
// GetFirstPosition(hash, size)
|
|
DEFVARIABLE(entry, INT32_TYPE, Word32And(*hash, Int32Sub(capacity, GetInteger32Constant(1))));
|
|
Jump(&loopHead);
|
|
LoopBegin(&loopHead);
|
|
{
|
|
AddrShift element = GetKeyFromNumberDictionary(elements, *entry);
|
|
Label isHole(env);
|
|
Label notHole(env);
|
|
Branch(TaggedIsHole(element), &isHole, ¬Hole);
|
|
{
|
|
Bind(&isHole);
|
|
{
|
|
Jump(&loopEnd);
|
|
}
|
|
Bind(¬Hole);
|
|
{
|
|
Label isUndefined(env);
|
|
Label notUndefined(env);
|
|
Branch(TaggedIsUndefined(element), &isUndefined, ¬Undefined);
|
|
{
|
|
Bind(&isUndefined);
|
|
{
|
|
result = GetInteger32Constant(-1);
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬Undefined);
|
|
{
|
|
Label isMatch(env);
|
|
Label notMatch(env);
|
|
Branch(Word64Equal(key, element), &isMatch, ¬Match);
|
|
{
|
|
Bind(&isMatch);
|
|
{
|
|
result = *entry;
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬Match);
|
|
{
|
|
Jump(&loopEnd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Bind(&loopEnd);
|
|
{
|
|
entry = Word32And(Int32Add(*entry, *count), Int32Sub(capacity, GetInteger32Constant(1)));
|
|
count = Int32Add(*count, GetInteger32Constant(1));
|
|
LoopEnd(&loopHead);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
auto ret = *result;
|
|
env->PopCurrentLabel();
|
|
return ret;
|
|
}
|
|
|
|
AddrShift Stub::JSObjectGetProperty(AddrShift obj, AddrShift hClass, AddrShift attr)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label entry(env);
|
|
env->PushCurrentLabel(&entry);
|
|
Label exit(env);
|
|
DEFVARIABLE(result, TAGGED_TYPE, GetUndefinedConstant());
|
|
Label inlinedProp(env);
|
|
Label notInlinedProp(env);
|
|
AddrShift attrOffset = PropAttrGetOffset(attr);
|
|
Branch(IsInlinedProperty(attr), &inlinedProp, ¬InlinedProp);
|
|
{
|
|
Bind(&inlinedProp);
|
|
{
|
|
// GetPropertyInlinedProps
|
|
AddrShift hClassObjectSize = GetObjectSizeFromHClass(hClass);
|
|
AddrShift propOffset = Int32Sub(
|
|
ChangeInt64ToInt32(hClassObjectSize),
|
|
Int32Mul(Int32Sub(
|
|
GetInteger32Constant(panda::ecmascript::JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS), attrOffset),
|
|
GetInteger32Constant(panda::ecmascript::JSTaggedValue::TaggedTypeSize())));
|
|
result = Int64BuildTagged(Load(UINT64_TYPE, obj, ZExtInt32ToInt64(propOffset)));
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬InlinedProp);
|
|
{
|
|
// compute outOfLineProp offset, get it and return
|
|
AddrShift array = Load(UINT64_TYPE, obj, GetPtrConstant(panda::ecmascript::JSObject::PROPERTIES_OFFSET));
|
|
result = GetValueFromTaggedArray(array, Int32Sub(attrOffset,
|
|
GetInteger32Constant(panda::ecmascript::JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS)));
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
auto ret = *result;
|
|
env->PopCurrentLabel();
|
|
return ret;
|
|
}
|
|
|
|
void Stub::ThrowTypeAndReturn(AddrShift thread, int messageId, AddrShift val)
|
|
{
|
|
AddrShift taggedId = GetInteger32Constant(messageId);
|
|
StubDescriptor *throwTypeError = GET_STUBDESCRIPTOR(ThrowTypeError);
|
|
CallRuntime(throwTypeError, thread, GetWord64Constant(FAST_STUB_ID(ThrowTypeError)),
|
|
{thread, taggedId});
|
|
Return(val);
|
|
}
|
|
|
|
AddrShift Stub::TaggedToRepresentation(AddrShift value)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label entry(env);
|
|
env->PushCurrentLabel(&entry);
|
|
Label exit(env);
|
|
DEFVARIABLE(resultRep, INT64_TYPE,
|
|
GetWord64Constant(static_cast<int32_t>(panda::ecmascript::Representation::OBJECT)));
|
|
Label isInt(env);
|
|
Label notInt(env);
|
|
|
|
Branch(TaggedIsInt(value), &isInt, ¬Int);
|
|
Bind(&isInt);
|
|
{
|
|
resultRep = GetWord64Constant(static_cast<int32_t>(panda::ecmascript::Representation::INT));
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬Int);
|
|
{
|
|
Label isDouble(env);
|
|
Label notDouble(env);
|
|
Branch(TaggedIsDouble(value), &isDouble, ¬Double);
|
|
Bind(&isDouble);
|
|
{
|
|
resultRep = GetWord64Constant(static_cast<int32_t>(panda::ecmascript::Representation::DOUBLE));
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬Double);
|
|
{
|
|
resultRep = GetWord64Constant(static_cast<int32_t>(panda::ecmascript::Representation::OBJECT));
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
auto ret = *resultRep;
|
|
env->PopCurrentLabel();
|
|
return ret;
|
|
}
|
|
|
|
AddrShift Stub::UpdateRepresention(AddrShift oldRep, AddrShift value)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label entry(env);
|
|
env->PushCurrentLabel(&entry);
|
|
Label exit(env);
|
|
DEFVARIABLE(resultRep, INT64_TYPE, oldRep);
|
|
Label isMixedRep(env);
|
|
Label notMiexedRep(env);
|
|
Branch(Word64Equal(oldRep, GetWord64Constant(static_cast<int64_t>(panda::ecmascript::Representation::MIXED))),
|
|
&isMixedRep, ¬MiexedRep);
|
|
Bind(&isMixedRep);
|
|
Jump(&exit);
|
|
Bind(¬MiexedRep);
|
|
{
|
|
AddrShift newRep = TaggedToRepresentation(value);
|
|
Label isNoneRep(env);
|
|
Label notNoneRep(env);
|
|
Branch(Word64Equal(oldRep, GetWord64Constant(static_cast<int64_t>(panda::ecmascript::Representation::NONE))),
|
|
&isNoneRep, ¬NoneRep);
|
|
Bind(&isNoneRep);
|
|
{
|
|
resultRep = newRep;
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬NoneRep);
|
|
{
|
|
Label isEqaulNewRep(env);
|
|
Label notEqaualNewRep(env);
|
|
Branch(Word64NotEqual(oldRep, newRep), &isEqaulNewRep, ¬EqaualNewRep);
|
|
Bind(&isEqaulNewRep);
|
|
{
|
|
resultRep = newRep;
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬EqaualNewRep);
|
|
{
|
|
Label defaultLabel(env);
|
|
Label intLabel(env);
|
|
Label doubleLabel(env);
|
|
Label numberLabel(env);
|
|
Label objectLabel(env);
|
|
// 4 : 4 means that there are 4 args in total.
|
|
std::array<Label, 4> repCaseLabels = {
|
|
intLabel,
|
|
doubleLabel,
|
|
numberLabel,
|
|
objectLabel,
|
|
};
|
|
// 4 : 4 means that there are 4 args in total.
|
|
std::array<int32_t, 4> keyValues = {
|
|
static_cast<int32_t>(panda::ecmascript::Representation::INT),
|
|
static_cast<int32_t>(panda::ecmascript::Representation::DOUBLE),
|
|
static_cast<int32_t>(panda::ecmascript::Representation::NUMBER),
|
|
static_cast<int32_t>(panda::ecmascript::Representation::OBJECT),
|
|
};
|
|
// 4 : 4 means that there are 4 cases in total.
|
|
Switch(oldRep, &defaultLabel, keyValues.data(), repCaseLabels.data(), 4);
|
|
Bind(&intLabel);
|
|
Jump(&numberLabel);
|
|
Bind(&doubleLabel);
|
|
Jump(&numberLabel);
|
|
Bind(&numberLabel);
|
|
{
|
|
Label isObjectNewRep(env);
|
|
Label notObjectNewRep(env);
|
|
Branch(Word64NotEqual(newRep, GetWord64Constant(
|
|
static_cast<int32_t>(panda::ecmascript::Representation::OBJECT))),
|
|
¬ObjectNewRep, &isObjectNewRep);
|
|
Bind(¬ObjectNewRep);
|
|
{
|
|
resultRep = GetWord64Constant(static_cast<int32_t>(panda::ecmascript::Representation::NUMBER));
|
|
Jump(&exit);
|
|
}
|
|
Bind(&isObjectNewRep);
|
|
{
|
|
resultRep = GetWord64Constant(static_cast<int32_t>(panda::ecmascript::Representation::MIXED));
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&objectLabel);
|
|
{
|
|
resultRep = GetWord64Constant(static_cast<int32_t>(panda::ecmascript::Representation::MIXED));
|
|
Jump(&exit);
|
|
}
|
|
Bind(&defaultLabel);
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
auto ret = *resultRep;
|
|
env->PopCurrentLabel();
|
|
return ret;
|
|
}
|
|
|
|
void Stub::UpdateAndStoreRepresention(AddrShift hclass, AddrShift value)
|
|
{
|
|
AddrShift newRep = UpdateRepresention(GetElementRepresentation(hclass), value);
|
|
SetElementRepresentation(hclass, newRep);
|
|
}
|
|
} // namespace kungfu
|