/* * 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 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 &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(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 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 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::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(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::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::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(panda::ecmascript::Representation::OBJECT))); Label isInt(env); Label notInt(env); Branch(TaggedIsInt(value), &isInt, ¬Int); Bind(&isInt); { resultRep = GetWord64Constant(static_cast(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(panda::ecmascript::Representation::DOUBLE)); Jump(&exit); } Bind(¬Double); { resultRep = GetWord64Constant(static_cast(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(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(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 repCaseLabels = { intLabel, doubleLabel, numberLabel, objectLabel, }; // 4 : 4 means that there are 4 args in total. std::array keyValues = { static_cast(panda::ecmascript::Representation::INT), static_cast(panda::ecmascript::Representation::DOUBLE), static_cast(panda::ecmascript::Representation::NUMBER), static_cast(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(panda::ecmascript::Representation::OBJECT))), ¬ObjectNewRep, &isObjectNewRep); Bind(¬ObjectNewRep); { resultRep = GetWord64Constant(static_cast(panda::ecmascript::Representation::NUMBER)); Jump(&exit); } Bind(&isObjectNewRep); { resultRep = GetWord64Constant(static_cast(panda::ecmascript::Representation::MIXED)); Jump(&exit); } } Bind(&objectLabel); { resultRep = GetWord64Constant(static_cast(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