/* * 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/compiler/stub-inl.h" #include "ecmascript/js_api_arraylist.h" #include "ecmascript/js_object.h" #include "ecmascript/message_string.h" #include "ecmascript/tagged_hash_table-inl.h" #include "libpandabase/macros.h" namespace panda::ecmascript::kungfu { Stub::Label::Label(Environment *env) { impl_ = env->NewLabel(env); } GateRef Stub::Variable::AddPhiOperand(GateRef val) { ASSERT(IsSelector(val)); Label label = env_->GetLabelFromSelector(val); size_t idx = 0; for (auto pred : label.GetPredecessors()) { auto preVal = pred.ReadVariable(this); ASSERT(!env_->GetCircuit()->GetOpCode(preVal).IsNop()); idx++; val = AddOperandToSelector(val, idx, preVal); } return TryRemoveTrivialPhi(val); } GateRef Stub::Variable::AddOperandToSelector(GateRef val, size_t idx, GateRef in) { env_->GetCircuit()->NewIn(val, idx, in); return val; } GateRef Stub::Variable::TryRemoveTrivialPhi(GateRef 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 valusses: not trivial } same = op; } if (same == nullptr) { // the phi is unreachable or in the start block GateType type = env_->GetCircuit()->GetGateType(phiVal); same = env_->GetCircuit()->LoadGatePtr(env_->GetCircuitBuilder().UndefineConstant(type)); } auto same_addr_shift = env_->GetCircuit()->SaveGatePtr(same); // 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()); auto result = TryRemoveTrivialPhi(out_addr_shift); if (same_addr_shift == out_addr_shift) { same_addr_shift = result; } } } return same_addr_shift; } 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, GateRef value) { valueMap_[var] = value; } GateRef LabelImpl::ReadVariable(Variable *var) { if (valueMap_.find(var) != valueMap_.end()) { auto result = valueMap_.at(var); if (!env_->GetCircuit()->GetOpCode(result).IsNop()) { return result; } } return ReadVariableRecursive(var); } GateRef LabelImpl::ReadVariableRecursive(Variable *var) { GateRef val; MachineType machineType = CircuitBuilder::GetMachineTypeFromStubMachineType(var->Type()); if (!IsSealed()) { // only loopheader gate will be not sealed int valueCounts = static_cast(predecessors_.size()) + 1; if (machineType == MachineType::NOVALUE) { val = env_->GetCircuitBuilder().NewSelectorGate( OpCode(OpCode::DEPEND_SELECTOR), predeControl_, valueCounts, var->Type()); } else { val = env_->GetCircuitBuilder().NewSelectorGate( OpCode(OpCode::VALUE_SELECTOR), machineType, predeControl_, valueCounts, var->Type()); } env_->AddSelectorToLabel(val, Label(this)); incompletePhis_[var] = val; } else if (predecessors_.size() == 1) { val = predecessors_[0]->ReadVariable(var); } else { if (machineType == MachineType::NOVALUE) { val = env_->GetCircuitBuilder().NewSelectorGate( OpCode(OpCode::DEPEND_SELECTOR), predeControl_, predecessors_.size(), var->Type()); } else { val = env_->GetCircuitBuilder().NewSelectorGate( OpCode(OpCode::VALUE_SELECTOR), machineType, predeControl_, predecessors_.size(), var->Type()); } 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; } GateRef 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 : 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(GateRef condition, Label *trueLabel, Label *falseLabel) { auto currentLabel = env_.GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); GateRef ifBranch = env_.GetCircuitBuilder().Branch(currentControl, condition); currentLabel->SetControl(ifBranch); GateRef ifTrue = env_.GetCircuitBuilder().NewIfTrue(ifBranch); trueLabel->AppendPredecessor(env_.GetCurrentLabel()); trueLabel->MergeControl(ifTrue); GateRef ifFalse = env_.GetCircuitBuilder().NewIfFalse(ifBranch); falseLabel->AppendPredecessor(env_.GetCurrentLabel()); falseLabel->MergeControl(ifFalse); env_.SetCurrentLabel(nullptr); } void Stub::Switch(GateRef index, Label *defaultLabel, int64_t *keysValue, Label *keysLabel, int numberOfKeys) { auto currentLabel = env_.GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); GateRef switchBranch = env_.GetCircuitBuilder().SwitchBranch(currentControl, index, numberOfKeys); currentLabel->SetControl(switchBranch); for (int i = 0; i < numberOfKeys; i++) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) GateRef 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); } GateRef 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); } // FindElementWithCache in ecmascript/layout_info-inl.h GateRef Stub::FindElementWithCache(GateRef glue, GateRef layoutInfo, GateRef hClass, GateRef key, GateRef propsNum) { auto env = GetEnvironment(); Label subEntry(env); env->PushCurrentLabel(&subEntry); DEFVARIABLE(result, StubMachineType::INT32, GetInt32Constant(-1)); DEFVARIABLE(i, StubMachineType::INT32, GetInt32Constant(0)); Label exit(env); Label notExceedUpper(env); Label exceedUpper(env); Label afterExceedCon(env); // 9 : Builtins Object properties number is nine Branch(Int32LessThanOrEqual(propsNum, GetInt32Constant(9)), ¬ExceedUpper, &exceedUpper); { Bind(¬ExceedUpper); Label loopHead(env); Label loopEnd(env); Label afterLoop(env); Jump(&loopHead); LoopBegin(&loopHead); { Label propsNumIsZero(env); Label propsNumNotZero(env); Branch(Int32Equal(propsNum, GetInt32Constant(0)), &propsNumIsZero, &propsNumNotZero); Bind(&propsNumIsZero); Jump(&afterLoop); Bind(&propsNumNotZero); GateRef elementAddr = GetPropertiesAddrFromLayoutInfo(layoutInfo); GateRef keyInProperty = Load(StubMachineType::UINT64, elementAddr, IntPtrMul(ChangeInt32ToIntPtr(*i), GetIntPtrConstant(sizeof(panda::ecmascript::Properties)))); Label equal(env); Label notEqual(env); Label afterEqualCon(env); Branch(Int64Equal(keyInProperty, key), &equal, ¬Equal); Bind(&equal); result = *i; Jump(&exit); Bind(¬Equal); Jump(&afterEqualCon); Bind(&afterEqualCon); i = Int32Add(*i, GetInt32Constant(1)); Branch(UInt32LessThan(*i, propsNum), &loopEnd, &afterLoop); Bind(&loopEnd); LoopEnd(&loopHead); } Bind(&afterLoop); result = GetInt32Constant(-1); Jump(&exit); Bind(&exceedUpper); Jump(&afterExceedCon); } Bind(&afterExceedCon); result = TaggedCastToInt32(CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(FindElementWithCache)), { hClass, key, IntBuildTaggedTypeWithNoGC(propsNum) })); Jump(&exit); Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::FindElementFromNumberDictionary(GateRef glue, GateRef elements, GateRef index) { auto env = GetEnvironment(); Label subentry(env); env->PushCurrentLabel(&subentry); DEFVARIABLE(result, StubMachineType::INT32, GetInt32Constant(-1)); Label exit(env); GateRef capcityoffset = IntPtrMul(GetIntPtrConstant(JSTaggedValue::TaggedTypeSize()), GetIntPtrConstant(TaggedHashTable::SIZE_INDEX)); GateRef dataoffset = GetIntPtrConstant(TaggedArray::DATA_OFFSET); GateRef capacity = TaggedCastToInt32(Load(StubMachineType::UINT64, elements, IntPtrAdd(dataoffset, capcityoffset))); DEFVARIABLE(count, StubMachineType::INT32, GetInt32Constant(1)); GateRef len = GetInt32Constant(sizeof(int) / sizeof(uint8_t)); GateRef hash = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(GetHash32)), { IntBuildTaggedTypeWithNoGC(index), IntBuildTaggedTypeWithNoGC(len) }); DEFVARIABLE(entry, StubMachineType::INT32, Int32And(TruncInt64ToInt32(ChangeTaggedPointerToInt64(hash)), Int32Sub(capacity, GetInt32Constant(1)))); Label loopHead(env); Label loopEnd(env); Label afterLoop(env); Jump(&loopHead); LoopBegin(&loopHead); GateRef element = GetKeyFromDictionary(StubMachineType::TAGGED, 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 = GetInt32Constant(-1); Jump(&exit); Bind(¬Undefined); Label isMatch(env); Label notMatch(env); Branch(Int32Equal(index, TaggedCastToInt32(element)), &isMatch, ¬Match); Bind(&isMatch); result = *entry; Jump(&exit); Bind(¬Match); Jump(&loopEnd); Bind(&loopEnd); entry = GetNextPositionForHash(*entry, *count, capacity); count = Int32Add(*count, GetInt32Constant(1)); LoopEnd(&loopHead); Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } // int TaggedHashTable::FindEntry(const JSTaggedValue &key) in tagged_hash_table-inl.h GateRef Stub::FindEntryFromNameDictionary(GateRef glue, GateRef elements, GateRef key) { auto env = GetEnvironment(); Label funcEntry(env); env->PushCurrentLabel(&funcEntry); Label exit(env); DEFVARIABLE(result, StubMachineType::INT32, GetInt32Constant(-1)); GateRef capcityoffset = IntPtrMul(GetIntPtrConstant(JSTaggedValue::TaggedTypeSize()), GetIntPtrConstant(TaggedHashTable::SIZE_INDEX)); GateRef dataoffset = GetIntPtrConstant(TaggedArray::DATA_OFFSET); GateRef capacity = TaggedCastToInt32(Load(StubMachineType::UINT64, elements, IntPtrAdd(dataoffset, capcityoffset))); DEFVARIABLE(count, StubMachineType::INT32, GetInt32Constant(1)); DEFVARIABLE(hash, StubMachineType::INT32, GetInt32Constant(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(StubMachineType::UINT64, key, GetIntPtrConstant(JSSymbol::HASHFIELD_OFFSET))); Jump(&beforeDefineHash); } Bind(¬Symbol); { Label isString(env); Label notString(env); Branch(IsString(key), &isString, ¬String); Bind(&isString); { hash = TruncInt64ToInt32(ChangeTaggedPointerToInt64(CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(StringGetHashCode)), { key }))); Jump(&beforeDefineHash); } Bind(¬String); { Jump(&beforeDefineHash); } } Bind(&beforeDefineHash); // GetFirstPosition(hash, size) DEFVARIABLE(entry, StubMachineType::INT32, Int32And(*hash, Int32Sub(capacity, GetInt32Constant(1)))); Jump(&loopHead); LoopBegin(&loopHead); { GateRef element = GetKeyFromDictionary(StubMachineType::TAGGED, 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 = GetInt32Constant(-1); Jump(&exit); } Bind(¬Undefined); { Label isMatch(env); Label notMatch(env); Branch(Int64Equal(key, element), &isMatch, ¬Match); { Bind(&isMatch); { result = *entry; Jump(&exit); } Bind(¬Match); { Jump(&loopEnd); } } } } } } Bind(&loopEnd); { entry = GetNextPositionForHash(*entry, *count, capacity); count = Int32Add(*count, GetInt32Constant(1)); LoopEnd(&loopHead); } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::IsMatchInTransitionDictionary(GateRef element, GateRef key, GateRef metaData, GateRef attr) { return TruncInt32ToInt1(Int32And(ZExtInt1ToInt32(Int64Equal(element, key)), ZExtInt1ToInt32(Int32Equal(metaData, attr)))); } // metaData is int32 type GateRef Stub::FindEntryFromTransitionDictionary(GateRef glue, GateRef elements, GateRef key, GateRef metaData) { auto env = GetEnvironment(); Label funcEntry(env); env->PushCurrentLabel(&funcEntry); Label exit(env); DEFVARIABLE(result, StubMachineType::INT32, GetInt32Constant(-1)); GateRef capcityoffset = IntPtrMul(GetIntPtrConstant(JSTaggedValue::TaggedTypeSize()), GetIntPtrConstant(TaggedHashTable::SIZE_INDEX)); GateRef dataoffset = GetIntPtrConstant(TaggedArray::DATA_OFFSET); GateRef capacity = TaggedCastToInt32(Load(StubMachineType::UINT64, elements, IntPtrAdd(dataoffset, capcityoffset))); DEFVARIABLE(count, StubMachineType::INT32, GetInt32Constant(1)); DEFVARIABLE(hash, StubMachineType::INT32, GetInt32Constant(0)); // TransitionDictionary::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(StubMachineType::UINT64, key, GetIntPtrConstant(panda::ecmascript::JSSymbol::HASHFIELD_OFFSET))); Jump(&beforeDefineHash); } Bind(¬Symbol); { Label isString(env); Label notString(env); Branch(IsString(key), &isString, ¬String); Bind(&isString); { hash = TruncInt64ToInt32(ChangeTaggedPointerToInt64(CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(StringGetHashCode)), { key }))); Jump(&beforeDefineHash); } Bind(¬String); { Jump(&beforeDefineHash); } } Bind(&beforeDefineHash); hash = Int32Add(*hash, metaData); // GetFirstPosition(hash, size) DEFVARIABLE(entry, StubMachineType::INT32, Int32And(*hash, Int32Sub(capacity, GetInt32Constant(1)))); Jump(&loopHead); LoopBegin(&loopHead); { GateRef element = GetKeyFromDictionary(StubMachineType::TAGGED, 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 = GetInt32Constant(-1); Jump(&exit); } Bind(¬Undefined); { Label isMatch(env); Label notMatch(env); Branch( IsMatchInTransitionDictionary(element, key, metaData, GetAttributesFromDictionary(elements, *entry)), &isMatch, ¬Match); { Bind(&isMatch); { result = *entry; Jump(&exit); } Bind(¬Match); { Jump(&loopEnd); } } } } } } Bind(&loopEnd); { entry = GetNextPositionForHash(*entry, *count, capacity); count = Int32Add(*count, GetInt32Constant(1)); LoopEnd(&loopHead); } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::JSObjectGetProperty(StubMachineType returnType, GateRef obj, GateRef hClass, GateRef attr) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); DEFVARIABLE(result, returnType, GetUndefinedConstant(returnType)); Label inlinedProp(env); Label notInlinedProp(env); GateRef attrOffset = GetOffsetFieldInPropAttr(attr); Branch(IsInlinedProperty(attr), &inlinedProp, ¬InlinedProp); { Bind(&inlinedProp); { // GetPropertyInlinedProps GateRef inlinedPropsStart = GetInlinedPropsStartFromHClass(hClass); GateRef propOffset = Int32Mul( Int32Add(inlinedPropsStart, attrOffset), GetInt32Constant(JSTaggedValue::TaggedTypeSize())); result = Load(returnType, obj, ZExtInt32ToInt64(propOffset)); Jump(&exit); } Bind(¬InlinedProp); { // compute outOfLineProp offset, get it and return GateRef array = Load(StubMachineType::UINT64, obj, GetIntPtrConstant(JSObject::PROPERTIES_OFFSET)); result = GetValueFromTaggedArray(returnType, array, Int32Sub(attrOffset, GetInlinedPropertiesFromHClass(hClass))); Jump(&exit); } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } void Stub::JSObjectSetProperty(GateRef glue, GateRef obj, GateRef hClass, GateRef attr, GateRef value) { auto env = GetEnvironment(); Label subEntry(env); env->PushCurrentLabel(&subEntry); Label exit(env); Label inlinedProp(env); Label notInlinedProp(env); GateRef attrOffset = GetOffsetFieldInPropAttr(attr); Branch(IsInlinedProperty(attr), &inlinedProp, ¬InlinedProp); { Bind(&inlinedProp); { SetPropertyInlinedProps(glue, obj, hClass, value, attrOffset); Jump(&exit); } Bind(¬InlinedProp); { // compute outOfLineProp offset, get it and return GateRef array = Load(StubMachineType::TAGGED_POINTER, obj, GetIntPtrConstant(JSObject::PROPERTIES_OFFSET)); SetValueToTaggedArray(StubMachineType::TAGGED, glue, array, Int32Sub(attrOffset, GetInlinedPropertiesFromHClass(hClass)), value); Jump(&exit); } } Bind(&exit); env->PopCurrentLabel(); return; } GateRef Stub::ComputePropertyCapacityInJSObj(GateRef oldLength) { auto env = GetEnvironment(); Label subEntry(env); env->PushCurrentLabel(&subEntry); Label exit(env); DEFVARIABLE(result, StubMachineType::UINT32, GetInt32Constant(0)); GateRef newL = Int32Add(oldLength, GetInt32Constant(JSObject::PROPERTIES_GROW_SIZE)); Label reachMax(env); Label notReachMax(env); Branch(Int32GreaterThan(newL, GetInt32Constant(PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES)), &reachMax, ¬ReachMax); { Bind(&reachMax); result = GetInt32Constant(PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES); Jump(&exit); Bind(¬ReachMax); result = newL; Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::CallSetterUtil(GateRef glue, GateRef holder, GateRef accessor, GateRef value) { auto env = GetEnvironment(); Label subEntry(env); env->PushCurrentLabel(&subEntry); Label exit(env); DEFVARIABLE(result, StubMachineType::UINT64, GetUndefinedConstant(StubMachineType::UINT64)); GateRef callRes = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CallSetter)), { accessor, holder, value, TaggedTrue() }); Label callSuccess(env); Label callFail(env); Branch(TaggedIsTrue(callRes), &callSuccess, &callFail); { Bind(&callSuccess); result = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); Bind(&callFail); result = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::ShouldCallSetter(GateRef receiver, GateRef holder, GateRef accessor, GateRef attr) { auto env = GetEnvironment(); Label subEntry(env); env->PushCurrentLabel(&subEntry); Label exit(env); DEFVARIABLE(result, StubMachineType::BOOL, TrueConstant()); Label isInternal(env); Label notInternal(env); Branch(IsAccessorInternal(accessor), &isInternal, ¬Internal); Bind(&isInternal); { Label receiverEqualsHolder(env); Label receiverNotEqualsHolder(env); Branch(Int64Equal(receiver, holder), &receiverEqualsHolder, &receiverNotEqualsHolder); Bind(&receiverEqualsHolder); { result = IsWritable(attr); Jump(&exit); } Bind(&receiverNotEqualsHolder); { result = FalseConstant(); Jump(&exit); } } Bind(¬Internal); { result = TrueConstant(); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } void Stub::JSHClassAddProperty(GateRef glue, GateRef receiver, GateRef key, GateRef attr) { auto env = GetEnvironment(); Label subEntry(env); env->PushCurrentLabel(&subEntry); Label exit(env); GateRef hclass = LoadHClass(receiver); GateRef metaData = GetPropertyMetaDataFromAttr(attr); GateRef newDyn = FindTransitions(glue, receiver, hclass, key, metaData); Label findHClass(env); Label notFindHClass(env); Branch(Int64Equal(newDyn, GetInt64Constant(JSTaggedValue::VALUE_NULL)), ¬FindHClass, &findHClass); Bind(&findHClass); { Jump(&exit); } Bind(¬FindHClass); { GateRef type = GetObjectType(hclass); GateRef size = Int32Mul(GetInlinedPropsStartFromHClass(hclass), GetInt32Constant(JSTaggedValue::TaggedTypeSize())); GateRef inlineProps = GetInlinedPropertiesFromHClass(hclass); GateRef newJshclass = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(NewEcmaDynClass)), { IntBuildTaggedTypeWithNoGC(size), IntBuildTaggedTypeWithNoGC(type), IntBuildTaggedTypeWithNoGC(inlineProps) }); CopyAllHClass(glue, newJshclass, hclass); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(UpdateLayOutAndAddTransition)), { hclass, newJshclass, key, IntBuildTaggedTypeWithNoGC(attr) }); #if ECMASCRIPT_ENABLE_IC NotifyHClassChanged(glue, hclass, newJshclass); #endif StoreHClass(glue, receiver, newJshclass); Jump(&exit); } Bind(&exit); env->PopCurrentLabel(); return; } // if condition:objHandle->IsJSArray() && // keyHandle.GetTaggedValue() == thread->GlobalConstants()->GetConstructorString() GateRef Stub::SetHasConstructorCondition(GateRef glue, GateRef receiver, GateRef key) { GateRef gConstOffset = IntPtrAdd(glue, GetIntPtrConstant(env_.GetGlueOffset(JSThread::GlueID::GLOBAL_CONST))); GateRef gCtorStr = Load(StubMachineType::TAGGED, gConstOffset, Int64Mul(GetInt64Constant(sizeof(JSTaggedValue)), GetInt64Constant(static_cast(ConstantIndex::CONSTRUCTOR_STRING_INDEX)))); GateRef isCtorStr = Int64Equal(key, gCtorStr); return Int32NotEqual( Int32And(SExtInt1ToInt32(IsJsArray(receiver)), SExtInt1ToInt32(isCtorStr)), GetInt32Constant(0)); } // Note: set return exit node GateRef Stub::AddPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value, GateRef propertyAttributes) { auto env = GetEnvironment(); Label subentry(env); env->PushCurrentLabel(&subentry); Label exit(env); DEFVARIABLE(result, StubMachineType::UINT64, GetUndefinedConstant(StubMachineType::UINT64)); Label setHasCtor(env); Label notSetHasCtor(env); Label afterCtorCon(env); GateRef hClass = LoadHClass(receiver); Branch(SetHasConstructorCondition(glue, receiver, key), &setHasCtor, ¬SetHasCtor); { Bind(&setHasCtor); SetHasConstructorToHClass(glue, hClass, GetInt32Constant(1)); Jump(&afterCtorCon); Bind(¬SetHasCtor); Jump(&afterCtorCon); } Bind(&afterCtorCon); // 0x111 : default attribute for property: writable, enumerable, configurable DEFVARIABLE(attr, StubMachineType::UINT32, propertyAttributes); GateRef numberOfProps = GetNumberOfPropsFromHClass(hClass); GateRef inlinedProperties = GetInlinedPropertiesFromHClass(hClass); Label hasUnusedInProps(env); Label noUnusedInProps(env); Label afterInPropsCon(env); Branch(UInt32LessThan(numberOfProps, inlinedProperties), &hasUnusedInProps, &noUnusedInProps); { Bind(&noUnusedInProps); Jump(&afterInPropsCon); Bind(&hasUnusedInProps); { SetPropertyInlinedProps(glue, receiver, hClass, value, numberOfProps); attr = SetOffsetFieldInPropAttr(*attr, numberOfProps); attr = SetIsInlinePropsFieldInPropAttr(*attr, GetInt32Constant(1)); // 1: set inInlineProps true JSHClassAddProperty(glue, receiver, key, *attr); result = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); } } Bind(&afterInPropsCon); DEFVARIABLE(array, StubMachineType::TAGGED_POINTER, GetPropertiesArray(receiver)); DEFVARIABLE(length, StubMachineType::UINT32, GetLengthOfTaggedArray(*array)); Label lenIsZero(env); Label lenNotZero(env); Label afterLenCon(env); Branch(Int32Equal(*length, GetInt32Constant(0)), &lenIsZero, &lenNotZero); { Bind(&lenIsZero); { length = GetInt32Constant(JSObject::MIN_PROPERTIES_LENGTH); array = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(NewTaggedArray)), { IntBuildTaggedTypeWithNoGC(*length) }); SetPropertiesArray(glue, receiver, *array); Jump(&afterLenCon); } Bind(&lenNotZero); Jump(&afterLenCon); } Bind(&afterLenCon); Label isDictMode(env); Label notDictMode(env); Branch(IsDictionaryMode(*array), &isDictMode, ¬DictMode); { Bind(&isDictMode); { GateRef res = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(NameDictPutIfAbsent)), { receiver, *array, key, value, IntBuildTaggedTypeWithNoGC(*attr), TaggedFalse() }); SetPropertiesArray(glue, receiver, res); Jump(&exit); } Bind(¬DictMode); { attr = SetIsInlinePropsFieldInPropAttr(*attr, GetInt32Constant(0)); GateRef outProps = Int32Sub(numberOfProps, inlinedProperties); Label isArrayFull(env); Label arrayNotFull(env); Label afterArrLenCon(env); Branch(Int32Equal(*length, outProps), &isArrayFull, &arrayNotFull); { Bind(&isArrayFull); { Label ChangeToDict(env); Label notChangeToDict(env); Label afterDictChangeCon(env); Branch(Int32Equal(*length, GetInt32Constant(JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS)), &ChangeToDict, ¬ChangeToDict); { Bind(&ChangeToDict); { attr = SetDictionaryOrderFieldInPropAttr(*attr, GetInt32Constant(PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES)); GateRef res = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(NameDictPutIfAbsent)), { receiver, *array, key, value, IntBuildTaggedTypeWithNoGC(*attr), TaggedTrue() }); SetPropertiesArray(glue, receiver, res); result = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); } Bind(¬ChangeToDict); Jump(&afterDictChangeCon); } Bind(&afterDictChangeCon); GateRef capacity = ComputePropertyCapacityInJSObj(*length); array = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CopyArray)), { *array, IntBuildTaggedTypeWithNoGC(*length), IntBuildTaggedTypeWithNoGC(capacity) }); SetPropertiesArray(glue, receiver, *array); Jump(&afterArrLenCon); } Bind(&arrayNotFull); Jump(&afterArrLenCon); } Bind(&afterArrLenCon); { attr = SetOffsetFieldInPropAttr(*attr, numberOfProps); JSHClassAddProperty(glue, receiver, key, *attr); SetValueToTaggedArray(StubMachineType::TAGGED, glue, *array, outProps, value); Jump(&exit); } } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } void Stub::ThrowTypeAndReturn(GateRef glue, int messageId, GateRef val) { GateRef msgIntId = GetInt32Constant(messageId); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(msgIntId) }); Return(val); } GateRef Stub::TaggedToRepresentation(GateRef value) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); DEFVARIABLE(resultRep, StubMachineType::INT64, GetInt64Constant(static_cast(Representation::OBJECT))); Label isInt(env); Label notInt(env); Branch(TaggedIsInt(value), &isInt, ¬Int); Bind(&isInt); { resultRep = GetInt64Constant(static_cast(Representation::INT)); Jump(&exit); } Bind(¬Int); { Label isDouble(env); Label notDouble(env); Branch(TaggedIsDouble(value), &isDouble, ¬Double); Bind(&isDouble); { resultRep = GetInt64Constant(static_cast(Representation::DOUBLE)); Jump(&exit); } Bind(¬Double); { resultRep = GetInt64Constant(static_cast(Representation::OBJECT)); Jump(&exit); } } Bind(&exit); auto ret = *resultRep; env->PopCurrentLabel(); return ret; } GateRef Stub::Store(StubMachineType type, GateRef glue, GateRef base, GateRef offset, GateRef value) { auto depend = env_.GetCurrentLabel()->GetDepend(); GateRef result; if (env_.IsArch64Bit()) { GateRef ptr = Int64Add(base, offset); if (type == StubMachineType::NATIVE_POINTER) { type = StubMachineType::INT64; } result = env_.GetCircuitBuilder().NewStoreGate(type, ptr, value, depend); env_.GetCurrentLabel()->SetDepend(result); } else if (env_.IsArch32Bit()) { if (type == StubMachineType::NATIVE_POINTER) { type = StubMachineType::INT32; } GateRef ptr = Int32Add(base, offset); result = env_.GetCircuitBuilder().NewStoreGate(type, ptr, value, depend); env_.GetCurrentLabel()->SetDepend(result); } else { UNREACHABLE(); } if (type == StubMachineType::TAGGED_POINTER || type == StubMachineType::TAGGED) { SetValueWithBarrier(glue, base, offset, value); } return result; } void Stub::SetValueWithBarrier(GateRef glue, GateRef obj, GateRef offset, GateRef value) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label isHeapObject(env); Label isVailedIndex(env); Label notValidIndex(env); Label marking(env); Branch(TaggedIsHeapObject(value), &isHeapObject, &exit); Bind(&isHeapObject); { GateRef objectRegion = ObjectAddressToRange(obj); GateRef valueRegion = ObjectAddressToRange(value); GateRef slotAddr = IntPtrAdd(TaggedCastToIntPtr(obj), offset); GateRef objectNotInYoung = BoolNot(InYoungGeneration(glue, objectRegion)); GateRef valueRegionInYoung = InYoungGeneration(glue, valueRegion); Branch(BoolAnd(objectNotInYoung, valueRegionInYoung), &isVailedIndex, ¬ValidIndex); Bind(&isVailedIndex); { GateRef offset = GetIntPtrConstant(Region::GetOldToNewSetOffset(env_.Is32Bit())); auto oldToNewSet = Load(StubMachineType::NATIVE_POINTER, objectRegion, offset); Label isNullPtr(env); Label notNullPtr(env); Branch(IntptrEuqal(oldToNewSet, GetIntPtrConstant(0)), &isNullPtr, ¬NullPtr); Bind(¬NullPtr); { // 1. bit_offset set AddrToBitOffset(address) GateRef bitOffset = AddrToBitOffset(oldToNewSet, slotAddr); // bit_offset >> LOG_BITSPERWORD // 2. bitmap_[GetWordIdx(bit_offset)] |= GetBitMask(bit_offset) // 2.0: wordIdx GetWordIdx(bit_offset) uint64_t logBitsPerWord = BitmapHelper::LogBitsPerWord(env_.Is32Bit()); GateRef wordIdx = IntPtrLSR(bitOffset, GetIntPtrConstant(logBitsPerWord)); // 2.1 bitmap_[wordIdx] GateRef bitmapoffset = GetIntPtrConstant(0); GateRef bitmap = IntPtrAdd(oldToNewSet, bitmapoffset); GateRef bitmapdata = Load(StubMachineType::NATIVE_POINTER, bitmap, GetIntPtrConstant(0)); GateRef bitmapAddr = IntPtrAdd(bitmapdata, IntPtrMul(wordIdx, GetIntPtrConstant(GetIntPtrSize()))); // 2.2 bitmap_[wordIdx] |= GetBitMask(bit_offset); GateRef oldmapValue = Load(StubMachineType::NATIVE_POINTER, bitmapAddr, GetIntPtrConstant(0)); Store(StubMachineType::NATIVE_POINTER, glue, bitmapAddr, GetIntPtrConstant(0), IntPtrOr(oldmapValue, GetBitMask(bitOffset))); Jump(¬ValidIndex); } Bind(&isNullPtr); { CallRuntimeTrampoline(glue, GetIntPtrConstant(FAST_STUB_ID(InsertOldToNewRememberedSet)), { PtrBuildTaggedWithNoGC(objectRegion), PtrBuildTaggedWithNoGC(slotAddr) }); Jump(¬ValidIndex); } } Bind(¬ValidIndex); { CallRuntimeTrampoline(glue, GetIntPtrConstant(FAST_STUB_ID(MarkingBarrier)), { PtrBuildTaggedWithNoGC(slotAddr), PtrBuildTaggedWithNoGC(objectRegion), PtrBuildTaggedWithNoGC(value), PtrBuildTaggedWithNoGC(valueRegion) }); Jump(&exit); } } Bind(&exit); env->PopCurrentLabel(); return; } GateRef Stub::TaggedIsString(GateRef obj) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); DEFVARIABLE(result, StubMachineType::BOOL, FalseConstant()); Label isHeapObject(env); Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit); Bind(&isHeapObject); { result = Int32Equal(GetObjectType(LoadHClass(obj)), GetInt32Constant(static_cast(JSType::STRING))); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::TaggedIsStringOrSymbol(GateRef obj) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); DEFVARIABLE(result, StubMachineType::BOOL, FalseConstant()); Label isHeapObject(env); Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit); Bind(&isHeapObject); { GateRef objType = GetObjectType(LoadHClass(obj)); result = Int32Equal(objType, GetInt32Constant(static_cast(JSType::STRING))); Label isString(env); Label notString(env); Branch(*result, &exit, ¬String); Bind(¬String); { result = Int32Equal(objType, GetInt32Constant(static_cast(JSType::SYMBOL))); Jump(&exit); } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::IsUtf16String(GateRef string) { // compressedStringsEnabled fixed to true constant GateRef len = Load(StubMachineType::UINT32, string, GetIntPtrConstant(EcmaString::MIX_LENGTH_OFFSET)); return Int32Equal( Int32And(len, GetInt32Constant(EcmaString::STRING_COMPRESSED_BIT)), GetInt32Constant(EcmaString::STRING_UNCOMPRESSED)); } GateRef Stub::IsUtf8String(GateRef string) { // compressedStringsEnabled fixed to true constant GateRef len = Load(StubMachineType::UINT32, string, GetIntPtrConstant(EcmaString::MIX_LENGTH_OFFSET)); return Int32Equal( Int32And(len, GetInt32Constant(EcmaString::STRING_COMPRESSED_BIT)), GetInt32Constant(EcmaString::STRING_COMPRESSED)); } GateRef Stub::IsInternalString(GateRef string) { // compressedStringsEnabled fixed to true constant GateRef len = Load(StubMachineType::UINT32, string, GetIntPtrConstant(EcmaString::MIX_LENGTH_OFFSET)); return Int32NotEqual( Int32And(len, GetInt32Constant(EcmaString::STRING_INTERN_BIT)), GetInt32Constant(0)); } GateRef Stub::IsDigit(GateRef ch) { return TruncInt32ToInt1( Int32And(SExtInt1ToInt32(Int32LessThanOrEqual(ch, GetInt32Constant('9'))), SExtInt1ToInt32(Int32GreaterThanOrEqual(ch, GetInt32Constant('0'))))); } GateRef Stub::StringToElementIndex(GateRef string) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); DEFVARIABLE(result, StubMachineType::INT32, GetInt32Constant(-1)); Label greatThanZero(env); Label inRange(env); GateRef len = Load(StubMachineType::UINT32, string, GetIntPtrConstant(EcmaString::MIX_LENGTH_OFFSET)); len = UInt32LSR(len, GetInt32Constant(2)); // 2 : 2 means len must be right shift 2 bits Branch(Int32Equal(len, GetInt32Constant(0)), &exit, &greatThanZero); Bind(&greatThanZero); Branch(Int32GreaterThan(len, GetInt32Constant(MAX_INDEX_LEN)), &exit, &inRange); Bind(&inRange); { GateRef dataUtf16 = IntPtrAdd(string, GetIntPtrConstant(EcmaString::DATA_OFFSET)); DEFVARIABLE(c, StubMachineType::UINT32, GetInt32Constant(0)); Label isUtf16(env); Label isUtf8(env); Label getChar1(env); GateRef isUtf16String = IsUtf16String(string); Branch(isUtf16String, &isUtf16, &isUtf8); Bind(&isUtf16); { c = ZExtInt16ToInt32(Load(StubMachineType::INT16, dataUtf16)); Jump(&getChar1); } Bind(&isUtf8); { c = ZExtInt8ToInt32(Load(StubMachineType::INT8, dataUtf16)); Jump(&getChar1); } Bind(&getChar1); { Label isDigitZero(env); Label notDigitZero(env); Branch(Int32Equal(*c, GetInt32Constant('0')), &isDigitZero, ¬DigitZero); Bind(&isDigitZero); { Label lengthIsOne(env); Branch(Int32Equal(len, GetInt32Constant(1)), &lengthIsOne, &exit); Bind(&lengthIsOne); { result = GetInt32Constant(0); Jump(&exit); } } Bind(¬DigitZero); { Label isDigit(env); DEFVARIABLE(i, StubMachineType::UINT32, GetInt32Constant(1)); DEFVARIABLE(n, StubMachineType::UINT32, Int32Sub(*c, GetInt32Constant('0'))); Branch(IsDigit(*c), &isDigit, &exit); Label loopHead(env); Label loopEnd(env); Label afterLoop(env); Bind(&isDigit); Branch(UInt32LessThan(*i, len), &loopHead, &afterLoop); LoopBegin(&loopHead); { Label isUtf16(env); Label notUtf16(env); Label getChar2(env); Branch(isUtf16String, &isUtf16, ¬Utf16); Bind(&isUtf16); { // 2 : 2 means utf16 char width is two bytes auto charOffset = IntPtrMul(ChangeInt32ToIntPtr(*i), GetIntPtrConstant(2)); c = ZExtInt16ToInt32(Load(StubMachineType::INT16, dataUtf16, charOffset)); Jump(&getChar2); } Bind(¬Utf16); { c = ZExtInt8ToInt32(Load(StubMachineType::INT8, dataUtf16, ChangeInt32ToIntPtr(*i))); Jump(&getChar2); } Bind(&getChar2); { Label isDigit2(env); Label notDigit2(env); Branch(IsDigit(*c), &isDigit2, ¬Digit2); Bind(&isDigit2); { // 10 means the base of digit is 10. n = Int32Add(Int32Mul(*n, GetInt32Constant(10)), Int32Sub(*c, GetInt32Constant('0'))); i = Int32Add(*i, GetInt32Constant(1)); Branch(UInt32LessThan(*i, len), &loopEnd, &afterLoop); } Bind(¬Digit2); Jump(&exit); } } Bind(&loopEnd); LoopEnd(&loopHead); Bind(&afterLoop); { Label lessThanMaxIndex(env); Branch(UInt32LessThan(*n, GetInt32Constant(JSObject::MAX_ELEMENT_INDEX)), &lessThanMaxIndex, &exit); Bind(&lessThanMaxIndex); { result = *n; Jump(&exit); } } } } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::TryToElementsIndex(GateRef key) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label isKeyInt(env); Label notKeyInt(env); DEFVARIABLE(resultKey, StubMachineType::INT32, GetInt32Constant(-1)); Branch(TaggedIsInt(key), &isKeyInt, ¬KeyInt); Bind(&isKeyInt); { resultKey = TaggedCastToInt32(key); Jump(&exit); } Bind(¬KeyInt); { Label isString(env); Label notString(env); Branch(TaggedIsString(key), &isString, ¬String); Bind(&isString); { resultKey = StringToElementIndex(key); Jump(&exit); } Bind(¬String); { Label isDouble(env); Branch(TaggedIsDouble(key), &isDouble, &exit); Bind(&isDouble); { GateRef number = TaggedCastToDouble(key); GateRef integer = ChangeFloat64ToInt32(number); Label isEqual(env); Branch(DoubleEqual(number, ChangeInt32ToFloat64(integer)), &isEqual, &exit); Bind(&isEqual); { resultKey = integer; Jump(&exit); } } } } Bind(&exit); auto ret = *resultKey; env->PopCurrentLabel(); return ret; } GateRef Stub::LoadFromField(GateRef receiver, GateRef handlerInfo) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label handlerInfoIsInlinedProps(env); Label handlerInfoNotInlinedProps(env); DEFVARIABLE(result, StubMachineType::TAGGED, GetUndefinedConstant()); GateRef index = HandlerBaseGetOffset(handlerInfo); Branch(HandlerBaseIsInlinedProperty(handlerInfo), &handlerInfoIsInlinedProps, &handlerInfoNotInlinedProps); Bind(&handlerInfoIsInlinedProps); { result = Load(StubMachineType::TAGGED, receiver, IntPtrMul(ChangeInt32ToIntPtr(index), GetIntPtrConstant(JSTaggedValue::TaggedTypeSize()))); Jump(&exit); } Bind(&handlerInfoNotInlinedProps); { result = GetValueFromTaggedArray(StubMachineType::TAGGED, GetPropertiesArray(receiver), index); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::LoadGlobal(GateRef cell) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label cellIsInvalid(env); Label cellNotInvalid(env); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid); Bind(&cellIsInvalid); { Jump(&exit); } Bind(&cellNotInvalid); { result = GetValueFromPropertyBox(cell); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::CheckPolyHClass(GateRef cachedValue, GateRef hclass) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label loopHead(env); Label loopEnd(env); Label iLessLength(env); Label hasHclass(env); Label cachedValueNotWeak(env); DEFVARIABLE(i, StubMachineType::UINT32, GetInt32Constant(0)); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); Branch(TaggedIsWeak(cachedValue), &exit, &cachedValueNotWeak); Bind(&cachedValueNotWeak); { GateRef length = GetLengthOfTaggedArray(cachedValue); Jump(&loopHead); LoopBegin(&loopHead); { Branch(UInt32LessThan(*i, length), &iLessLength, &exit); Bind(&iLessLength); { GateRef element = GetValueFromTaggedArray(StubMachineType::TAGGED, cachedValue, *i); Branch(Int64Equal(TaggedCastToWeakReferentUnChecked(element), hclass), &hasHclass, &loopEnd); Bind(&hasHclass); result = GetValueFromTaggedArray(StubMachineType::TAGGED, cachedValue, Int32Add(*i, GetInt32Constant(1))); Jump(&exit); } Bind(&loopEnd); i = Int32Add(*i, GetInt32Constant(2)); // 2 means one ic, two slot LoopEnd(&loopHead); } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::LoadICWithHandler(GateRef glue, GateRef receiver, GateRef argHolder, GateRef argHandler) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label handlerIsInt(env); Label handlerNotInt(env); Label handlerInfoIsField(env); Label handlerInfoNotField(env); Label handlerInfoIsNonExist(env); Label handlerInfoNotNonExist(env); Label handlerIsPrototypeHandler(env); Label handlerNotPrototypeHandler(env); Label cellHasChanged(env); Label loopHead(env); Label loopEnd(env); DEFVARIABLE(result, StubMachineType::TAGGED, GetUndefinedConstant()); DEFVARIABLE(holder, StubMachineType::TAGGED, argHolder); DEFVARIABLE(handler, StubMachineType::TAGGED, argHandler); Jump(&loopHead); LoopBegin(&loopHead); { Branch(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt); Bind(&handlerIsInt); { GateRef handlerInfo = TaggedCastToInt32(*handler); Branch(IsField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField); Bind(&handlerInfoIsField); { result = LoadFromField(*holder, handlerInfo); Jump(&exit); } Bind(&handlerInfoNotField); { Branch(IsNonExist(handlerInfo), &handlerInfoIsNonExist, &handlerInfoNotNonExist); Bind(&handlerInfoIsNonExist); Jump(&exit); Bind(&handlerInfoNotNonExist); GateRef accessor = LoadFromField(*holder, handlerInfo); result = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CallGetter2)), { receiver, *holder, accessor }); Jump(&exit); } } Bind(&handlerNotInt); Branch(TaggedIsPrototypeHandler(*handler), &handlerIsPrototypeHandler, &handlerNotPrototypeHandler); Bind(&handlerIsPrototypeHandler); { GateRef cellValue = GetProtoCell(*handler); Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd); Bind(&cellHasChanged); { result = GetHoleConstant(); Jump(&exit); } Bind(&loopEnd); holder = GetPrototypeHandlerHolder(*handler); handler = GetPrototypeHandlerHandlerInfo(*handler); LoopEnd(&loopHead); } } Bind(&handlerNotPrototypeHandler); result = LoadGlobal(*handler); Jump(&exit); Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::LoadElement(GateRef receiver, GateRef key) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label indexLessZero(env); Label indexNotLessZero(env); Label lengthLessIndex(env); Label lengthNotLessIndex(env); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); GateRef index = TryToElementsIndex(key); Branch(UInt32LessThan(index, GetInt32Constant(0)), &indexLessZero, &indexNotLessZero); Bind(&indexLessZero); { Jump(&exit); } Bind(&indexNotLessZero); { GateRef elements = GetElementsArray(receiver); Branch(Int32LessThanOrEqual(GetLengthOfTaggedArray(elements), index), &lengthLessIndex, &lengthNotLessIndex); Bind(&lengthLessIndex); Jump(&exit); Bind(&lengthNotLessIndex); result = GetValueFromTaggedArray(StubMachineType::TAGGED, elements, index); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::ICStoreElement(GateRef glue, GateRef receiver, GateRef key, GateRef value, GateRef handler) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label indexLessZero(env); Label indexNotLessZero(env); Label handerInfoIsJSArray(env); Label handerInfoNotJSArray(env); Label indexGreaterLength(env); Label indexGreaterCapacity(env); Label callRuntime(env); Label storeElement(env); Label handlerIsInt(env); Label handlerNotInt(env); Label cellHasChanged(env); Label cellHasNotChanged(env); Label loopHead(env); Label loopEnd(env); DEFVARIABLE(result, StubMachineType::UINT64, GetHoleConstant(StubMachineType::UINT64)); DEFVARIABLE(varHandler, StubMachineType::TAGGED, handler); GateRef index = TryToElementsIndex(key); Branch(UInt32LessThan(index, GetInt32Constant(0)), &indexLessZero, &indexNotLessZero); Bind(&indexLessZero); { Jump(&exit); } Bind(&indexNotLessZero); { Jump(&loopHead); LoopBegin(&loopHead); Branch(TaggedIsInt(*varHandler), &handlerIsInt, &handlerNotInt); Bind(&handlerIsInt); { GateRef handlerInfo = TaggedCastToInt32(handler); Branch(HandlerBaseIsJSArray(handlerInfo), &handerInfoIsJSArray, &handerInfoNotJSArray); Bind(&handerInfoIsJSArray); { GateRef oldLength = GetArrayLength(receiver); Branch(Int32GreaterThanOrEqual(index, oldLength), &indexGreaterLength, &handerInfoNotJSArray); Bind(&indexGreaterLength); Store(StubMachineType::UINT64, glue, receiver, GetIntPtrConstant(panda::ecmascript::JSArray::LENGTH_OFFSET), IntBuildTaggedWithNoGC(Int32Add(index, GetInt32Constant(1)))); Jump(&handerInfoNotJSArray); } Bind(&handerInfoNotJSArray); { GateRef elements = GetElementsArray(receiver); GateRef capacity = GetLengthOfTaggedArray(elements); Branch(Int32GreaterThanOrEqual(index, capacity), &callRuntime, &storeElement); Bind(&callRuntime); { result = ChangeTaggedPointerToInt64(CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(TaggedArraySetValue)), { receiver, value, elements, IntBuildTaggedTypeWithNoGC(index), IntBuildTaggedTypeWithNoGC(capacity) })); Jump(&exit); } Bind(&storeElement); { SetValueToTaggedArray(StubMachineType::TAGGED, glue, elements, index, value); result = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); } } } Bind(&handlerNotInt); { GateRef cellValue = GetProtoCell(*varHandler); Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd); Bind(&cellHasChanged); { Jump(&exit); } Bind(&loopEnd); { varHandler = GetPrototypeHandlerHandlerInfo(*varHandler); LoopEnd(&loopHead); } } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::GetArrayLength(GateRef object) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label lengthIsInt(env); Label lengthNotInt(env); DEFVARIABLE(result, StubMachineType::UINT32, GetInt32Constant(0)); GateRef lengthOffset = GetIntPtrConstant(panda::ecmascript::JSArray::LENGTH_OFFSET); GateRef length = Load(StubMachineType::UINT64, object, lengthOffset); Branch(TaggedIsInt(length), &lengthIsInt, &lengthNotInt); Bind(&lengthIsInt); { result = TaggedCastToInt32(length); Jump(&exit); } Bind(&lengthNotInt); { result = ChangeFloat64ToInt32(TaggedCastToDouble(length)); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef argHolder, GateRef value, GateRef argHandler) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label handlerIsInt(env); Label handlerNotInt(env); Label handlerInfoIsField(env); Label handlerInfoNotField(env); Label handlerIsTransitionHandler(env); Label handlerNotTransitionHandler(env); Label handlerIsPrototypeHandler(env); Label handlerNotPrototypeHandler(env); Label handlerIsPropertyBox(env); Label handlerNotPropertyBox(env); Label cellHasChanged(env); Label loopHead(env); Label loopEnd(env); DEFVARIABLE(result, StubMachineType::UINT64, GetUndefinedConstant(StubMachineType::UINT64)); DEFVARIABLE(holder, StubMachineType::TAGGED, argHolder); DEFVARIABLE(handler, StubMachineType::TAGGED, argHandler); Jump(&loopHead); LoopBegin(&loopHead); { Branch(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt); Bind(&handlerIsInt); { GateRef handlerInfo = TaggedCastToInt32(*handler); Branch(IsField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField); Bind(&handlerInfoIsField); { StoreField(glue, receiver, value, handlerInfo); Jump(&exit); } Bind(&handlerInfoNotField); { GateRef accessor = LoadFromField(*holder, handlerInfo); result = ChangeTaggedPointerToInt64(CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CallSetter2)), { receiver, value, accessor })); Jump(&exit); } } Bind(&handlerNotInt); { Branch(TaggedIsTransitionHandler(*handler), &handlerIsTransitionHandler, &handlerNotTransitionHandler); Bind(&handlerIsTransitionHandler); { StoreWithTransition(glue, receiver, value, *handler); Jump(&exit); } Bind(&handlerNotTransitionHandler); { Branch(TaggedIsPrototypeHandler(*handler), &handlerIsPrototypeHandler, &handlerNotPrototypeHandler); Bind(&handlerNotPrototypeHandler); { Branch(TaggedIsPropertyBox(*handler), &handlerIsPropertyBox, &handlerNotPropertyBox); Bind(&handlerIsPropertyBox); StoreGlobal(glue, value, *handler); Jump(&exit); Bind(&handlerNotPropertyBox); Jump(&exit); } } } Bind(&handlerIsPrototypeHandler); { GateRef cellValue = GetProtoCell(*handler); Branch(GetHasChanged(cellValue), &cellHasChanged, &loopEnd); Bind(&cellHasChanged); { result = GetHoleConstant(StubMachineType::UINT64); Jump(&exit); } Bind(&loopEnd); { holder = GetPrototypeHandlerHolder(*handler); handler = GetPrototypeHandlerHandlerInfo(*handler); LoopEnd(&loopHead); } } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } void Stub::StoreField(GateRef glue, GateRef receiver, GateRef value, GateRef handler) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label handlerIsInlinedProperty(env); Label handlerNotInlinedProperty(env); GateRef index = HandlerBaseGetOffset(handler); Branch(HandlerBaseIsInlinedProperty(handler), &handlerIsInlinedProperty, &handlerNotInlinedProperty); Bind(&handlerIsInlinedProperty); { Store(StubMachineType::TAGGED, glue, receiver, IntPtrMul(ChangeInt32ToIntPtr(index), GetIntPtrConstant(JSTaggedValue::TaggedTypeSize())), value); Jump(&exit); } Bind(&handlerNotInlinedProperty); { GateRef array = GetPropertiesArray(receiver); SetValueToTaggedArray(StubMachineType::TAGGED, glue, array, index, value); Jump(&exit); } Bind(&exit); env->PopCurrentLabel(); } void Stub::StoreWithTransition(GateRef glue, GateRef receiver, GateRef value, GateRef handler) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label handlerInfoIsInlinedProps(env); Label handlerInfoNotInlinedProps(env); Label indexMoreCapacity(env); Label indexLessCapacity(env); GateRef newHClass = GetTransitionFromHClass(handler); StoreHClass(glue, receiver, newHClass); GateRef handlerInfo = TaggedCastToInt32(GetTransitionHandlerInfo(handler)); Branch(HandlerBaseIsInlinedProperty(handlerInfo), &handlerInfoIsInlinedProps, &handlerInfoNotInlinedProps); Bind(&handlerInfoNotInlinedProps); { GateRef array = GetPropertiesArray(receiver); GateRef capacity = GetLengthOfTaggedArray(array); GateRef index = HandlerBaseGetOffset(handlerInfo); Branch(Int32GreaterThanOrEqual(index, capacity), &indexMoreCapacity, &indexLessCapacity); Bind(&indexMoreCapacity); { CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(PropertiesSetValue)), { receiver, value, array, IntBuildTaggedTypeWithNoGC(capacity), IntBuildTaggedTypeWithNoGC(index) }); Jump(&exit); } Bind(&indexLessCapacity); { Store(StubMachineType::UINT64, glue, IntPtrAdd(array, GetIntPtrConstant(TaggedArray::DATA_OFFSET)), IntPtrMul(ChangeInt32ToIntPtr(index), GetIntPtrConstant(JSTaggedValue::TaggedTypeSize())), value); Jump(&exit); } } Bind(&handlerInfoIsInlinedProps); { StoreField(glue, receiver, value, handlerInfo); Jump(&exit); } Bind(&exit); env->PopCurrentLabel(); } GateRef Stub::StoreGlobal(GateRef glue, GateRef value, GateRef cell) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label cellIsInvalid(env); Label cellNotInvalid(env); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid); Bind(&cellIsInvalid); { Jump(&exit); } Bind(&cellNotInvalid); { Store(StubMachineType::TAGGED, glue, cell, GetIntPtrConstant(PropertyBox::VALUE_OFFSET), value); result = GetUndefinedConstant(); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::GetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); DEFVARIABLE(holder, StubMachineType::TAGGED, receiver); Label exit(env); Label loopHead(env); Label loopEnd(env); Label loopExit(env); Label afterLoop(env); Jump(&loopHead); LoopBegin(&loopHead); { GateRef hclass = LoadHClass(*holder); GateRef jsType = GetObjectType(hclass); Label isSpecialIndexed(env); Label notSpecialIndexed(env); Branch(IsSpecialIndexedObj(jsType), &isSpecialIndexed, ¬SpecialIndexed); Bind(&isSpecialIndexed); { Label isSpecialContainer(env); Label notSpecialContainer(env); // Add SpecialContainer Branch(IsSpecialContainer(jsType), &isSpecialContainer, ¬SpecialContainer); Bind(&isSpecialContainer); { result = GetContainerProperty(glue, *holder, index, jsType); Jump(&exit); } Bind(¬SpecialContainer); { result = GetHoleConstant(); Jump(&exit); } } Bind(¬SpecialIndexed); { GateRef elements = GetElementsArray(*holder); Label isDictionaryElement(env); Label notDictionaryElement(env); Branch(IsDictionaryElement(hclass), &isDictionaryElement, ¬DictionaryElement); Bind(¬DictionaryElement); { Label lessThanLength(env); Label notLessThanLength(env); Branch(UInt32LessThan(index, GetLengthOfTaggedArray(elements)), &lessThanLength, ¬LessThanLength); Bind(&lessThanLength); { Label notHole(env); Label isHole(env); GateRef value = GetValueFromTaggedArray(StubMachineType::TAGGED, elements, index); Branch(TaggedIsNotHole(value), ¬Hole, &isHole); Bind(¬Hole); { result = value; Jump(&exit); } Bind(&isHole); { Jump(&loopExit); } } Bind(¬LessThanLength); { result = GetHoleConstant(); Jump(&exit); } } Bind(&isDictionaryElement); { GateRef entry = FindElementFromNumberDictionary(glue, elements, index); Label notNegtiveOne(env); Label negtiveOne(env); Branch(Int32NotEqual(entry, GetInt32Constant(-1)), ¬NegtiveOne, &negtiveOne); Bind(¬NegtiveOne); { GateRef attr = GetAttributesFromDictionary(elements, entry); GateRef value = GetValueFromDictionary(StubMachineType::TAGGED, elements, entry); Label isAccessor(env); Label notAccessor(env); Branch(IsAccessor(attr), &isAccessor, ¬Accessor); Bind(&isAccessor); { Label isInternal(env); Label notInternal(env); Branch(IsAccessorInternal(value), &isInternal, ¬Internal); Bind(&isInternal); { result = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CallInternalGetter)), { value, *holder }); Jump(&exit); } Bind(¬Internal); { result = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CallGetter)), { value, receiver }); Jump(&exit); } } Bind(¬Accessor); { result = value; Jump(&exit); } } Bind(&negtiveOne); Jump(&loopExit); } Bind(&loopExit); { holder = GetPrototypeFromHClass(LoadHClass(*holder)); Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop); } } Bind(&loopEnd); LoopEnd(&loopHead); Bind(&afterLoop); { result = GetUndefinedConstant(); Jump(&exit); } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::GetPropertyByName(GateRef glue, GateRef receiver, GateRef key) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); DEFVARIABLE(holder, StubMachineType::TAGGED, receiver); Label exit(env); Label loopHead(env); Label loopEnd(env); Label loopExit(env); Label afterLoop(env); // a do-while loop Jump(&loopHead); LoopBegin(&loopHead); { // auto *hclass = holder.GetTaggedObject()->GetClass() // JSType jsType = hclass->GetObjectType() GateRef hClass = LoadHClass(*holder); GateRef jsType = GetObjectType(hClass); Label isSIndexObj(env); Label notSIndexObj(env); // if branch condition : IsSpecialIndexedObj(jsType) Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, ¬SIndexObj); Bind(&isSIndexObj); { result = GetHoleConstant(); Jump(&exit); } Bind(¬SIndexObj); { Label isDicMode(env); Label notDicMode(env); // if branch condition : LIKELY(!hclass->IsDictionaryMode()) Branch(IsDictionaryModeByHClass(hClass), &isDicMode, ¬DicMode); Bind(¬DicMode); { // LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject()) GateRef layOutInfo = GetLayoutFromHClass(hClass); // int propsNumber = hclass->NumberOfPropsFromHClass() GateRef propsNum = GetNumberOfPropsFromHClass(hClass); // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber) GateRef entry = FindElementWithCache(glue, layOutInfo, hClass, key, propsNum); Label hasEntry(env); Label noEntry(env); // if branch condition : entry != -1 Branch(Int32NotEqual(entry, GetInt32Constant(-1)), &hasEntry, &noEntry); Bind(&hasEntry); { // PropertyAttributes attr(layoutInfo->GetAttr(entry)) GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entry); GateRef attr = TaggedCastToInt32(propAttr); // auto value = JSObject::Cast(holder)->GetProperty(hclass, attr) GateRef value = JSObjectGetProperty(StubMachineType::TAGGED, *holder, hClass, attr); Label isAccessor(env); Label notAccessor(env); Branch(IsAccessor(attr), &isAccessor, ¬Accessor); Bind(&isAccessor); { Label isInternal(env); Label notInternal(env); Branch(IsAccessorInternal(value), &isInternal, ¬Internal); Bind(&isInternal); { result = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CallInternalGetter)), { value, *holder }); Jump(&exit); } Bind(¬Internal); { result = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CallGetter)), { value, receiver }); Jump(&exit); } } Bind(¬Accessor); { result = value; Jump(&exit); } } Bind(&noEntry); { Jump(&loopExit); } } Bind(&isDicMode); { GateRef array = GetPropertiesArray(*holder); // int entry = dict->FindEntry(key) GateRef entry = FindEntryFromNameDictionary(glue, array, key); Label notNegtiveOne(env); Label negtiveOne(env); // if branch condition : entry != -1 Branch(Int32NotEqual(entry, GetInt32Constant(-1)), ¬NegtiveOne, &negtiveOne); Bind(¬NegtiveOne); { // auto value = dict->GetValue(entry) GateRef attr = GetAttributesFromDictionary(array, entry); // auto attr = dict->GetAttributes(entry) GateRef value = GetValueFromDictionary(StubMachineType::TAGGED, array, entry); Label isAccessor1(env); Label notAccessor1(env); // if branch condition : UNLIKELY(attr.IsAccessor()) Branch(IsAccessor(attr), &isAccessor1, ¬Accessor1); Bind(&isAccessor1); { Label isInternal1(env); Label notInternal1(env); Branch(IsAccessorInternal(value), &isInternal1, ¬Internal1); Bind(&isInternal1); { result = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CallInternalGetter)), { value, *holder }); Jump(&exit); } Bind(¬Internal1); { result = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CallGetter)), { value, receiver }); Jump(&exit); } } Bind(¬Accessor1); { result = value; Jump(&exit); } } Bind(&negtiveOne); Jump(&loopExit); } Bind(&loopExit); { // holder = hclass->GetPrototype() holder = GetPrototypeFromHClass(LoadHClass(*holder)); // loop condition for a do-while loop Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop); } } Bind(&loopEnd); LoopEnd(&loopHead); Bind(&afterLoop); { result = GetUndefinedConstant(); Jump(&exit); } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } void Stub::CopyAllHClass(GateRef glue, GateRef dstHClass, GateRef srcHClass) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); auto proto = GetPrototypeFromHClass(srcHClass); SetPrototypeToHClass(StubMachineType::INT64, glue, dstHClass, proto); SetBitFieldToHClass(glue, dstHClass, GetBitFieldFromHClass(srcHClass)); SetNumberOfPropsToHClass(glue, dstHClass, GetNumberOfPropsFromHClass(srcHClass)); SetTransitionsToHClass(StubMachineType::INT64, glue, dstHClass, GetInt64Constant(JSTaggedValue::VALUE_NULL)); SetProtoChangeDetailsToHClass(StubMachineType::INT64, glue, dstHClass, GetInt64Constant(JSTaggedValue::VALUE_NULL)); SetEnumCacheToHClass(StubMachineType::INT64, glue, dstHClass, GetInt64Constant(JSTaggedValue::VALUE_NULL)); SetLayoutToHClass(StubMachineType::INT64, glue, dstHClass, GetLayoutFromHClass(srcHClass)); env->PopCurrentLabel(); return; } GateRef Stub::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, GateRef key, GateRef metaData) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); GateRef transitionOffset = GetIntPtrConstant(JSHClass::TRANSTIONS_OFFSET); GateRef transition = Load(StubMachineType::TAGGED_POINTER, hclass, transitionOffset); DEFVARIABLE(result, StubMachineType::TAGGED, transition); Label notNull(env); Branch(Int64Equal(transition, GetInt64Constant(JSTaggedValue::VALUE_NULL)), &exit, ¬Null); Bind(¬Null); { Label isJSHClass(env); Label notJSHClass(env); Branch(IsJSHClass(transition), &isJSHClass, ¬JSHClass); Bind(&isJSHClass); { GateRef propNums = GetNumberOfPropsFromHClass(transition); GateRef last = Int32Sub(propNums, GetInt32Constant(1)); GateRef layoutInfo = GetLayoutFromHClass(transition); GateRef cachedKey = GetKeyFromLayoutInfo(layoutInfo, last); GateRef cachedAttr = TaggedCastToInt32(GetPropAttrFromLayoutInfo(layoutInfo, last)); GateRef cachedMetaData = GetPropertyMetaDataFromAttr(cachedAttr); Label keyMatch(env); Label isMatch(env); Label notMatch(env); Branch(Int64Equal(cachedKey, key), &keyMatch, ¬Match); Bind(&keyMatch); { Branch(Int32Equal(metaData, cachedMetaData), &isMatch, ¬Match); Bind(&isMatch); { #if ECMASCRIPT_ENABLE_IC NotifyHClassChanged(glue, hclass, transition); #endif StoreHClass(glue, receiver, transition); Jump(&exit); } } Bind(¬Match); { result = GetNullConstant(); Jump(&exit); } } Bind(¬JSHClass); { // need to find from dictionary GateRef entry = FindEntryFromTransitionDictionary(glue, transition, key, metaData); Label isFound(env); Label notFound(env); Branch(Int32NotEqual(entry, GetInt32Constant(-1)), &isFound, ¬Found); Bind(&isFound); auto newHClass = GetValueFromDictionary( StubMachineType::TAGGED_POINTER, transition, entry); result = newHClass; #if ECMASCRIPT_ENABLE_IC NotifyHClassChanged(glue, hclass, newHClass); #endif StoreHClass(glue, receiver, newHClass); Jump(&exit); Bind(¬Found); result = GetNullConstant(); Jump(&exit); } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); DEFVARIABLE(returnValue, StubMachineType::UINT64, GetHoleConstant(StubMachineType::UINT64)); DEFVARIABLE(holder, StubMachineType::TAGGED, receiver); Label exit(env); Label loopHead(env); Label loopEnd(env); Label loopExit(env); Label afterLoop(env); Jump(&loopHead); LoopBegin(&loopHead); { GateRef hclass = LoadHClass(*holder); GateRef jsType = GetObjectType(hclass); Label isSpecialIndex(env); Label notSpecialIndex(env); Branch(IsSpecialIndexedObj(jsType), &isSpecialIndex, ¬SpecialIndex); Bind(&isSpecialIndex); { returnValue = GetHoleConstant(StubMachineType::UINT64); Jump(&exit); } Bind(¬SpecialIndex); { GateRef elements = GetElementsArray(*holder); Label isDictionaryElement(env); Label notDictionaryElement(env); Branch(IsDictionaryElement(hclass), &isDictionaryElement, ¬DictionaryElement); Bind(¬DictionaryElement); { Label isReceiver(env); Label notReceiver(env); Branch(Int64Equal(*holder, receiver), &isReceiver, ¬Receiver); Bind(&isReceiver); { GateRef length = GetLengthOfTaggedArray(elements); Label inRange(env); Branch(Int64LessThan(index, length), &inRange, &loopExit); Bind(&inRange); { GateRef value1 = GetValueFromTaggedArray(StubMachineType::TAGGED, elements, index); Label notHole(env); Branch(Int64NotEqual(value1, GetHoleConstant()), ¬Hole, &loopExit); Bind(¬Hole); { SetValueToTaggedArray(StubMachineType::TAGGED, glue, elements, index, value); returnValue = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); } } } Bind(¬Receiver); Jump(&afterLoop); } Bind(&isDictionaryElement); returnValue = GetHoleConstant(StubMachineType::UINT64); Jump(&exit); } Bind(&loopExit); { holder = GetPrototypeFromHClass(LoadHClass(*holder)); Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop); } } Bind(&loopEnd); LoopEnd(&loopHead); Bind(&afterLoop); { Label isExtensible(env); Label notExtensible(env); Branch(IsExtensible(receiver), &isExtensible, ¬Extensible); Bind(&isExtensible); { GateRef result = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(AddElementInternal)), { receiver, IntBuildTaggedTypeWithNoGC(index), value, IntBuildTaggedTypeWithNoGC(GetInt32Constant(PropertyAttributes::GetDefaultAttributes())) }); Label success(env); Label failed(env); Branch(TaggedIsTrue(result), &success, &failed); Bind(&success); returnValue = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); Bind(&failed); returnValue = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(¬Extensible); { GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); returnValue = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } } Bind(&exit); auto ret = *returnValue; env->PopCurrentLabel(); return ret; } GateRef Stub::SetPropertyByName(GateRef glue, GateRef receiver, GateRef key, GateRef value) { auto env = GetEnvironment(); Label entryPass(env); env->PushCurrentLabel(&entryPass); DEFVARIABLE(result, StubMachineType::UINT64, GetHoleConstant(StubMachineType::UINT64)); DEFVARIABLE(holder, StubMachineType::TAGGED_POINTER, receiver); Label exit(env); Label loopHead(env); Label loopEnd(env); Label loopExit(env); Label afterLoop(env); // a do-while loop Jump(&loopHead); LoopBegin(&loopHead); { // auto *hclass = holder.GetTaggedObject()->GetClass() // JSType jsType = hclass->GetObjectType() GateRef hClass = LoadHClass(*holder); GateRef jsType = GetObjectType(hClass); Label isSIndexObj(env); Label notSIndexObj(env); // if branch condition : IsSpecialIndexedObj(jsType) Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, ¬SIndexObj); Bind(&isSIndexObj); { Label isSpecialContainer(env); Label notSpecialContainer(env); // Add SpecialContainer Branch(IsSpecialContainer(jsType), &isSpecialContainer, ¬SpecialContainer); Bind(&isSpecialContainer); { GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(CanNotSetPropertyOnContainer)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); result = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(¬SpecialContainer); { result = GetHoleConstant(StubMachineType::UINT64); Jump(&exit); } } Bind(¬SIndexObj); { Label isDicMode(env); Label notDicMode(env); // if branch condition : LIKELY(!hclass->IsDictionaryMode()) Branch(IsDictionaryModeByHClass(hClass), &isDicMode, ¬DicMode); Bind(¬DicMode); { // LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject()) GateRef layOutInfo = GetLayoutFromHClass(hClass); // int propsNumber = hclass->NumberOfPropsFromHClass() GateRef propsNum = GetNumberOfPropsFromHClass(hClass); // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber) GateRef entry = FindElementWithCache(glue, layOutInfo, hClass, key, propsNum); Label hasEntry(env); Label noEntry(env); // if branch condition : entry != -1 Branch(Int32NotEqual(entry, GetInt32Constant(-1)), &hasEntry, &noEntry); Bind(&hasEntry); { // PropertyAttributes attr(layoutInfo->GetAttr(entry)) GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entry); GateRef attr = TaggedCastToInt32(propAttr); Label isAccessor(env); Label notAccessor(env); Label afterIsAccessor(env); Branch(IsAccessor(attr), &isAccessor, ¬Accessor); Bind(&isAccessor); { // auto accessor = JSObject::Cast(holder)->GetProperty(hclass, attr) GateRef accessor = JSObjectGetProperty(StubMachineType::TAGGED, *holder, hClass, attr); Label shouldCall(env); Label shouldNotCall(env); // ShouldCallSetter(receiver, *holder, accessor, attr) Branch(ShouldCallSetter(receiver, *holder, accessor, attr), &shouldCall, &shouldNotCall); { Bind(&shouldCall); result = CallSetterUtil(glue, receiver, accessor, value); Jump(&exit); Bind(&shouldNotCall); Jump(&afterIsAccessor); } } Bind(¬Accessor); Jump(&afterIsAccessor); Bind(&afterIsAccessor); { Label writable(env); Label notWritable(env); Label afterIsWritable(env); Branch(IsWritable(attr), &writable, ¬Writable); { Bind(&writable); Jump(&afterIsWritable); Bind(¬Writable); GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); result = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(&afterIsWritable); { Label holdEqualsRecv(env); Label holdNotEqualsRecv(env); Label afterComp(env); Branch(Int64Equal(*holder, receiver), &holdEqualsRecv, &holdNotEqualsRecv); { Bind(&holdEqualsRecv); Jump(&afterComp); Bind(&holdNotEqualsRecv); Jump(&afterLoop); } Bind(&afterComp); // JSObject::Cast(holder)->SetProperty(thread, hclass, attr, value) // return JSTaggedValue::Undefined() JSObjectSetProperty(glue, *holder, hClass, attr, value); result = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); } } } Bind(&noEntry); { Jump(&loopExit); } } Bind(&isDicMode); { GateRef array = GetPropertiesArray(*holder); // int entry = dict->FindEntry(key) GateRef entry1 = FindEntryFromNameDictionary(glue, array, key); Label notNegtiveOne(env); Label negtiveOne(env); // if branch condition : entry != -1 Branch(Int32NotEqual(entry1, GetInt32Constant(-1)), ¬NegtiveOne, &negtiveOne); Bind(¬NegtiveOne); { // auto attr = dict->GetAttributes(entry) GateRef attr1 = GetAttributesFromDictionary(array, entry1); Label isAccessor1(env); Label notAccessor1(env); Label afterIsAccessor1(env); // if branch condition : UNLIKELY(attr.IsAccessor()) Branch(IsAccessor(attr1), &isAccessor1, ¬Accessor1); Bind(&isAccessor1); { Label isInternal1(env); Label notInternal1(env); // auto accessor = dict->GetValue(entry) GateRef accessor1 = GetValueFromDictionary(StubMachineType::TAGGED, array, entry1); Label shouldCall1(env); Label shouldNotCall1(env); Branch(ShouldCallSetter(receiver, *holder, accessor1, attr1), &shouldCall1, &shouldNotCall1); Bind(&shouldCall1); result = CallSetterUtil(glue, receiver, accessor1, value); Jump(&exit); Bind(&shouldNotCall1); Jump(&afterIsAccessor1); } Bind(¬Accessor1); Jump(&afterIsAccessor1); Bind(&afterIsAccessor1); { Label writable1(env); Label notWritable1(env); Label afterIsWritable1(env); Branch(IsWritable(attr1), &writable1, ¬Writable1); { Bind(&writable1); Jump(&afterIsWritable1); Bind(¬Writable1); GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); result = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(&afterIsWritable1); { Label holdEqualsRecv1(env); Label holdNotEqualsRecv1(env); Label afterComp1(env); Branch(Int64Equal(*holder, receiver), &holdEqualsRecv1, &holdNotEqualsRecv1); { Bind(&holdEqualsRecv1); Jump(&afterComp1); Bind(&holdNotEqualsRecv1); Jump(&afterLoop); } Bind(&afterComp1); // dict->UpdateValue(thread, entry, value) // return JSTaggedValue::Undefined() UpdateValueInDict(glue, array, entry1, value); result = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); } } } Bind(&negtiveOne); Jump(&loopExit); } Bind(&loopExit); { // holder = hclass->GetPrototype() holder = GetPrototypeFromHClass(LoadHClass(*holder)); // loop condition for a do-while loop Branch(TaggedIsHeapObject(*holder), &loopEnd, &afterLoop); } } } Bind(&loopEnd); LoopEnd(&loopHead); Bind(&afterLoop); { Label extensible(env); Label inextensible(env); Label afterExtenCon(env); Branch(IsExtensible(receiver), &extensible, &inextensible); { Bind(&extensible); Jump(&afterExtenCon); Bind(&inextensible); GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); result = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(&afterExtenCon); result = AddPropertyByName(glue, receiver, key, value, GetInt32Constant(PropertyAttributes::GetDefaultAttributes())); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::SetPropertyByNameWithOwn(GateRef glue, GateRef receiver, GateRef key, GateRef value) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); DEFVARIABLE(result, StubMachineType::UINT64, GetHoleConstant(StubMachineType::UINT64)); DEFVARIABLE(holder, StubMachineType::TAGGED_POINTER, receiver); Label exit(env); Label ifEnd(env); // auto *hclass = holder.GetTaggedObject()->GetClass() // JSType jsType = hclass->GetObjectType() GateRef hClass = LoadHClass(*holder); GateRef jsType = GetObjectType(hClass); Label isSIndexObj(env); Label notSIndexObj(env); // if branch condition : IsSpecialIndexedObj(jsType) Branch(IsSpecialIndexedObj(jsType), &isSIndexObj, ¬SIndexObj); Bind(&isSIndexObj); { Label isSpecialContainer(env); Label notSpecialContainer(env); // Add SpecialContainer Branch(IsSpecialContainer(jsType), &isSpecialContainer, ¬SpecialContainer); Bind(&isSpecialContainer); { GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(CanNotSetPropertyOnContainer)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); result = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(¬SpecialContainer); { result = GetHoleConstant(StubMachineType::UINT64); Jump(&exit); } } Bind(¬SIndexObj); { Label isDicMode(env); Label notDicMode(env); // if branch condition : LIKELY(!hclass->IsDictionaryMode()) Branch(IsDictionaryModeByHClass(hClass), &isDicMode, ¬DicMode); Bind(¬DicMode); { // LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject()) GateRef layOutInfo = GetLayoutFromHClass(hClass); // int propsNumber = hclass->NumberOfPropsFromHClass() GateRef propsNum = GetNumberOfPropsFromHClass(hClass); // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber) GateRef entry = FindElementWithCache(glue, layOutInfo, hClass, key, propsNum); Label hasEntry(env); Label noEntry(env); // if branch condition : entry != -1 Branch(Int32NotEqual(entry, GetInt32Constant(-1)), &hasEntry, &noEntry); Bind(&hasEntry); { // PropertyAttributes attr(layoutInfo->GetAttr(entry)) GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entry); GateRef attr = TaggedCastToInt32(propAttr); Label isAccessor(env); Label notAccessor(env); Label afterIsAccessor(env); Branch(IsAccessor(attr), &isAccessor, ¬Accessor); Bind(&isAccessor); { // auto accessor = JSObject::Cast(holder)->GetProperty(hclass, attr) GateRef accessor = JSObjectGetProperty(StubMachineType::TAGGED, *holder, hClass, attr); Label shouldCall(env); Label shouldNotCall(env); // ShouldCallSetter(receiver, *holder, accessor, attr) Branch(ShouldCallSetter(receiver, *holder, accessor, attr), &shouldCall, &shouldNotCall); { Bind(&shouldCall); result = CallSetterUtil(glue, receiver, accessor, value); Jump(&exit); Bind(&shouldNotCall); Jump(&afterIsAccessor); } } Bind(¬Accessor); Jump(&afterIsAccessor); Bind(&afterIsAccessor); { Label writable(env); Label notWritable(env); Label afterIsWritable(env); Branch(IsWritable(attr), &writable, ¬Writable); { Bind(&writable); Jump(&afterIsWritable); Bind(¬Writable); GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); result = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(&afterIsWritable); { Label holdEqualsRecv(env); Label holdNotEqualsRecv(env); Label afterComp(env); Branch(Int64Equal(*holder, receiver), &holdEqualsRecv, &holdNotEqualsRecv); { Bind(&holdEqualsRecv); Jump(&afterComp); Bind(&holdNotEqualsRecv); Jump(&ifEnd); } Bind(&afterComp); // JSObject::Cast(holder)->SetProperty(thread, hclass, attr, value) // return JSTaggedValue::Undefined() JSObjectSetProperty(glue, *holder, hClass, attr, value); result = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); } } } Bind(&noEntry); { Jump(&ifEnd); } } Bind(&isDicMode); { // TaggedArray *array = TaggedArray::Cast(JSObject::Cast(holder)->GetPropertiesArray().GetTaggedObject()) GateRef array = GetPropertiesArray(*holder); // int entry = dict->FindEntry(key) GateRef entry1 = FindEntryFromNameDictionary(glue, array, key); Label notNegtiveOne(env); Label negtiveOne(env); // if branch condition : entry != -1 Branch(Int32NotEqual(entry1, GetInt32Constant(-1)), ¬NegtiveOne, &negtiveOne); Bind(¬NegtiveOne); { // auto attr = dict->GetAttributes(entry) GateRef attr1 = GetAttributesFromDictionary(array, entry1); Label isAccessor1(env); Label notAccessor1(env); Label afterIsAccessor1(env); // if branch condition : UNLIKELY(attr.IsAccessor()) Branch(IsAccessor(attr1), &isAccessor1, ¬Accessor1); Bind(&isAccessor1); { Label isInternal1(env); Label notInternal1(env); // auto accessor = dict->GetValue(entry) GateRef accessor1 = GetValueFromDictionary(StubMachineType::TAGGED, array, entry1); Label shouldCall1(env); Label shouldNotCall1(env); Branch(ShouldCallSetter(receiver, *holder, accessor1, attr1), &shouldCall1, &shouldNotCall1); Bind(&shouldCall1); result = CallSetterUtil(glue, receiver, accessor1, value); Jump(&exit); Bind(&shouldNotCall1); Jump(&afterIsAccessor1); } Bind(¬Accessor1); Jump(&afterIsAccessor1); Bind(&afterIsAccessor1); { Label writable1(env); Label notWritable1(env); Label afterIsWritable1(env); Branch(IsWritable(attr1), &writable1, ¬Writable1); { Bind(&writable1); Jump(&afterIsWritable1); Bind(¬Writable1); GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); result = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(&afterIsWritable1); { Label holdEqualsRecv1(env); Label holdNotEqualsRecv1(env); Label afterComp1(env); Branch(Int64Equal(*holder, receiver), &holdEqualsRecv1, &holdNotEqualsRecv1); { Bind(&holdEqualsRecv1); Jump(&afterComp1); Bind(&holdNotEqualsRecv1); Jump(&ifEnd); } Bind(&afterComp1); // dict->UpdateValue(thread, entry, value) // return JSTaggedValue::Undefined() UpdateValueInDict(glue, array, entry1, value); result = GetUndefinedConstant(StubMachineType::UINT64); Jump(&exit); } } } Bind(&negtiveOne); Jump(&ifEnd); } } Bind(&ifEnd); { Label extensible(env); Label inextensible(env); Label afterExtenCon(env); Branch(IsExtensible(receiver), &extensible, &inextensible); { Bind(&extensible); Jump(&afterExtenCon); Bind(&inextensible); GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); result = GetExceptionConstant(StubMachineType::UINT64); Jump(&exit); } Bind(&afterExtenCon); result = AddPropertyByName(glue, receiver, key, value, GetInt32Constant(PropertyAttributes::GetDefaultAttributes())); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } void Stub::NotifyHClassChanged(GateRef glue, GateRef oldHClass, GateRef newHClass) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); Label isProtoType(env); Branch(IsProtoTypeHClass(oldHClass), &isProtoType, &exit); Bind(&isProtoType); { Label notEqualHClass(env); Branch(Int64Equal(oldHClass, newHClass), &exit, ¬EqualHClass); Bind(¬EqualHClass); { SetIsProtoTypeToHClass(glue, newHClass, TrueConstant()); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(NoticeThroughChainAndRefreshUser)), { oldHClass, newHClass }); Jump(&exit); } } Bind(&exit); env->PopCurrentLabel(); return; } GateRef Stub::GetContainerProperty(GateRef glue, GateRef receiver, GateRef index, GateRef jsType) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); DEFVARIABLE(result, StubMachineType::TAGGED, GetUndefinedConstant()); Label arrayListLabel(env); Label queueLabel(env); Label defaultLabel(env); std::array repCaseLabels = { // 2 : 2 means that there are 2 args in total. arrayListLabel, queueLabel, }; std::array keyValues = { // 2 : 2 means that there are 2 args in total. static_cast(JSType::JS_API_ARRAY_LIST), static_cast(JSType::JS_QUEUE), }; // 2 : 2 means that there are 2 cases. Switch(ZExtInt32ToInt64(jsType), &defaultLabel, keyValues.data(), repCaseLabels.data(), 2); Bind(&arrayListLabel); { result = JSArrayListGet(glue, receiver, index); Jump(&exit); } Bind(&queueLabel); { Jump(&exit); } Bind(&defaultLabel); { Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::FastEqual(GateRef left, GateRef right) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); Label leftEqualRight(env); Label leftNotEqualRight(env); Label exit(env); Branch(Int64Equal(left, right), &leftEqualRight, &leftNotEqualRight); Bind(&leftEqualRight); { Label leftIsDouble(env); Label leftNotDoubleOrLeftNotNan(env); Branch(TaggedIsDouble(left), &leftIsDouble, &leftNotDoubleOrLeftNotNan); Bind(&leftIsDouble); { GateRef doubleLeft = TaggedCastToDouble(left); Label leftIsNan(env); Branch(DoubleIsNAN(doubleLeft), &leftIsNan, &leftNotDoubleOrLeftNotNan); Bind(&leftIsNan); { result = ChangeInt64ToTagged(TaggedFalse()); Jump(&exit); } } Bind(&leftNotDoubleOrLeftNotNan); { result = ChangeInt64ToTagged(TaggedTrue()); Jump(&exit); } } Bind(&leftNotEqualRight); { Label leftIsNumber(env); Label leftNotNumberOrLeftNotIntOrRightNotInt(env); Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrLeftNotIntOrRightNotInt); Bind(&leftIsNumber); { Label leftIsInt(env); Branch(TaggedIsInt(left), &leftIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt); Bind(&leftIsInt); { Label rightIsInt(env); Branch(TaggedIsInt(right), &rightIsInt, &leftNotNumberOrLeftNotIntOrRightNotInt); Bind(&rightIsInt); { result = ChangeInt64ToTagged(TaggedFalse()); Jump(&exit); } } } Bind(&leftNotNumberOrLeftNotIntOrRightNotInt); { Label rightIsUndefinedOrNull(env); Label leftOrRightNotUndefinedOrNull(env); Branch(TaggedIsUndefinedOrNull(right), &rightIsUndefinedOrNull, &leftOrRightNotUndefinedOrNull); Bind(&rightIsUndefinedOrNull); { Label leftIsHeapObject(env); Label leftNotHeapObject(env); Branch(TaggedIsHeapObject(left), &leftIsHeapObject, &leftNotHeapObject); Bind(&leftIsHeapObject); { result = ChangeInt64ToTagged(TaggedFalse()); Jump(&exit); } Bind(&leftNotHeapObject); { Label leftIsUndefinedOrNull(env); Branch(TaggedIsUndefinedOrNull(left), &leftIsUndefinedOrNull, &leftOrRightNotUndefinedOrNull); Bind(&leftIsUndefinedOrNull); { result = ChangeInt64ToTagged(TaggedTrue()); Jump(&exit); } } } Bind(&leftOrRightNotUndefinedOrNull); { Label leftIsBool(env); Label leftNotBoolOrRightNotSpecial(env); Branch(TaggedIsBoolean(left), &leftIsBool, &leftNotBoolOrRightNotSpecial); Bind(&leftIsBool); { Label rightIsSpecial(env); Branch(TaggedIsSpecial(right), &rightIsSpecial, &leftNotBoolOrRightNotSpecial); Bind(&rightIsSpecial); { result = ChangeInt64ToTagged(TaggedFalse()); Jump(&exit); } } Bind(&leftNotBoolOrRightNotSpecial); { Jump(&exit); } } } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::FastMul(GateRef left, GateRef right) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); DEFVARIABLE(doubleLeft, StubMachineType::FLOAT64, GetDoubleConstant(0)); DEFVARIABLE(doubleRight, StubMachineType::FLOAT64, GetDoubleConstant(0)); Label leftIsNumber(env); Label leftNotNumberOrRightNotNumber(env); Label leftIsNumberAndRightIsNumber(env); Label leftIsDoubleAndRightIsDouble(env); Label exit(env); Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber); Bind(&leftIsNumber); { Label rightIsNumber(env); Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber); Bind(&rightIsNumber); { Label leftIsInt(env); Label leftNotInt(env); Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt); Bind(&leftIsInt); { doubleLeft = ChangeInt32ToFloat64(TaggedCastToInt32(left)); Jump(&leftIsNumberAndRightIsNumber); } Bind(&leftNotInt); { doubleLeft = TaggedCastToDouble(left); Jump(&leftIsNumberAndRightIsNumber); } } } Bind(&leftNotNumberOrRightNotNumber); { Jump(&exit); } Bind(&leftIsNumberAndRightIsNumber); { Label rightIsInt(env); Label rightNotInt(env); Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt); Bind(&rightIsInt); { doubleRight = ChangeInt32ToFloat64(TaggedCastToInt32(right)); Jump(&leftIsDoubleAndRightIsDouble); } Bind(&rightNotInt); { doubleRight = TaggedCastToDouble(right); Jump(&leftIsDoubleAndRightIsDouble); } } Bind(&leftIsDoubleAndRightIsDouble); { result = DoubleBuildTaggedWithNoGC(DoubleMul(*doubleLeft, *doubleRight)); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::FastDiv(GateRef left, GateRef right) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); DEFVARIABLE(doubleLeft, StubMachineType::FLOAT64, GetDoubleConstant(0)); DEFVARIABLE(doubleRight, StubMachineType::FLOAT64, GetDoubleConstant(0)); Label leftIsNumber(env); Label leftNotNumberOrRightNotNumber(env); Label leftIsNumberAndRightIsNumber(env); Label leftIsDoubleAndRightIsDouble(env); Label exit(env); Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber); Bind(&leftIsNumber); { Label rightIsNumber(env); Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber); Bind(&rightIsNumber); { Label leftIsInt(env); Label leftNotInt(env); Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt); Bind(&leftIsInt); { doubleLeft = ChangeInt32ToFloat64(TaggedCastToInt32(left)); Jump(&leftIsNumberAndRightIsNumber); } Bind(&leftNotInt); { doubleLeft = TaggedCastToDouble(left); Jump(&leftIsNumberAndRightIsNumber); } } } Bind(&leftNotNumberOrRightNotNumber); { Jump(&exit); } Bind(&leftIsNumberAndRightIsNumber); { Label rightIsInt(env); Label rightNotInt(env); Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt); Bind(&rightIsInt); { doubleRight = ChangeInt32ToFloat64(TaggedCastToInt32(right)); Jump(&leftIsDoubleAndRightIsDouble); } Bind(&rightNotInt); { doubleRight = TaggedCastToDouble(right); Jump(&leftIsDoubleAndRightIsDouble); } } Bind(&leftIsDoubleAndRightIsDouble); { Label rightIsZero(env); Label rightNotZero(env); Branch(DoubleEqual(*doubleRight, GetDoubleConstant(0.0)), &rightIsZero, &rightNotZero); Bind(&rightIsZero); { Label leftIsZero(env); Label leftNotZero(env); Label leftIsZeroOrNan(env); Label leftNotZeroAndNotNan(env); Branch(DoubleEqual(*doubleLeft, GetDoubleConstant(0.0)), &leftIsZero, &leftNotZero); Bind(&leftIsZero); { Jump(&leftIsZeroOrNan); } Bind(&leftNotZero); { Label leftIsNan(env); Branch(DoubleIsNAN(*doubleLeft), &leftIsNan, &leftNotZeroAndNotNan); Bind(&leftIsNan); { Jump(&leftIsZeroOrNan); } } Bind(&leftIsZeroOrNan); { result = DoubleBuildTaggedWithNoGC(GetDoubleConstant(base::NAN_VALUE)); Jump(&exit); } Bind(&leftNotZeroAndNotNan); { GateRef intLeftTmp = CastDoubleToInt64(*doubleLeft); GateRef intRightTmp = CastDoubleToInt64(*doubleRight); GateRef flagBit = Int64And(Int64Xor(intLeftTmp, intRightTmp), GetInt64Constant(base::DOUBLE_SIGN_MASK)); GateRef tmpResult = Int64Xor(flagBit, CastDoubleToInt64(GetDoubleConstant(base::POSITIVE_INFINITY))); result = DoubleBuildTaggedWithNoGC(CastInt64ToFloat64(tmpResult)); Jump(&exit); } } Bind(&rightNotZero); { result = DoubleBuildTaggedWithNoGC(DoubleDiv(*doubleLeft, *doubleRight)); Jump(&exit); } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::FastMod(GateRef glue, GateRef left, GateRef right) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); DEFVARIABLE(intLeft, StubMachineType::INT32, GetInt32Constant(0)); DEFVARIABLE(intRight, StubMachineType::INT32, GetInt32Constant(0)); DEFVARIABLE(doubleLeft, StubMachineType::FLOAT64, GetDoubleConstant(0)); DEFVARIABLE(doubleRight, StubMachineType::FLOAT64, GetDoubleConstant(0)); Label leftIsInt(env); Label leftNotIntOrRightNotInt(env); Label exit(env); Branch(TaggedIsInt(left), &leftIsInt, &leftNotIntOrRightNotInt); Bind(&leftIsInt); { Label rightIsInt(env); Branch(TaggedIsInt(right), &rightIsInt, &leftNotIntOrRightNotInt); Bind(&rightIsInt); { intLeft = TaggedCastToInt32(left); intRight = TaggedCastToInt32(right); Label leftGreaterZero(env); Branch(Int32GreaterThan(*intLeft, GetInt32Constant(0)), &leftGreaterZero, &leftNotIntOrRightNotInt); Bind(&leftGreaterZero); { Label rightGreaterZero(env); Branch(Int32GreaterThan(*intRight, GetInt32Constant(0)), &rightGreaterZero, &leftNotIntOrRightNotInt); Bind(&rightGreaterZero); { result = IntBuildTaggedWithNoGC(Int32Mod(*intLeft, *intRight)); Jump(&exit); } } } } Bind(&leftNotIntOrRightNotInt); { Label leftIsNumber(env); Label leftNotNumberOrRightNotNumber(env); Label leftIsNumberAndRightIsNumber(env); Label leftIsDoubleAndRightIsDouble(env); Branch(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber); Bind(&leftIsNumber); { Label rightIsNumber(env); Branch(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber); Bind(&rightIsNumber); { Label leftIsInt1(env); Label leftNotInt1(env); Branch(TaggedIsInt(left), &leftIsInt1, &leftNotInt1); Bind(&leftIsInt1); { doubleLeft = ChangeInt32ToFloat64(TaggedCastToInt32(left)); Jump(&leftIsNumberAndRightIsNumber); } Bind(&leftNotInt1); { doubleLeft = TaggedCastToDouble(left); Jump(&leftIsNumberAndRightIsNumber); } } } Bind(&leftNotNumberOrRightNotNumber); { Jump(&exit); } Bind(&leftIsNumberAndRightIsNumber); { Label rightIsInt1(env); Label rightNotInt1(env); Branch(TaggedIsInt(right), &rightIsInt1, &rightNotInt1); Bind(&rightIsInt1); { doubleRight = ChangeInt32ToFloat64(TaggedCastToInt32(right)); Jump(&leftIsDoubleAndRightIsDouble); } Bind(&rightNotInt1); { doubleRight = TaggedCastToDouble(right); Jump(&leftIsDoubleAndRightIsDouble); } } Bind(&leftIsDoubleAndRightIsDouble); { Label rightNotZero(env); Label rightIsZeroOrNanOrLeftIsNanOrInf(env); Label rightNotZeroAndNanAndLeftNotNanAndInf(env); Branch(DoubleEqual(*doubleRight, GetDoubleConstant(0.0)), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotZero); Bind(&rightNotZero); { Label rightNotNan(env); Branch(DoubleIsNAN(*doubleRight), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotNan); Bind(&rightNotNan); { Label leftNotNan(env); Branch(DoubleIsNAN(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf, &leftNotNan); Bind(&leftNotNan); { Branch(DoubleIsINF(*doubleLeft), &rightIsZeroOrNanOrLeftIsNanOrInf, &rightNotZeroAndNanAndLeftNotNanAndInf); } } } Bind(&rightIsZeroOrNanOrLeftIsNanOrInf); { result = DoubleBuildTaggedWithNoGC(GetDoubleConstant(base::NAN_VALUE)); Jump(&exit); } Bind(&rightNotZeroAndNanAndLeftNotNanAndInf); { Label leftNotZero(env); Label leftIsZeroOrRightIsInf(env); Branch(DoubleEqual(*doubleLeft, GetDoubleConstant(0.0)), &leftIsZeroOrRightIsInf, &leftNotZero); Bind(&leftNotZero); { Label rightNotInf(env); Branch(DoubleIsINF(*doubleRight), &leftIsZeroOrRightIsInf, &rightNotInf); Bind(&rightNotInf); { doubleLeft = TaggedCastToDouble(CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(FloatMod)), { DoubleBuildTaggedTypeWithNoGC(*doubleLeft), DoubleBuildTaggedTypeWithNoGC(*doubleRight) })); result = DoubleBuildTaggedWithNoGC(*doubleLeft); Jump(&exit); } } Bind(&leftIsZeroOrRightIsInf); { result = DoubleBuildTaggedWithNoGC(*doubleLeft); Jump(&exit); } } } } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::GetGlobalOwnProperty(GateRef glue, GateRef receiver, GateRef key) { auto env = GetEnvironment(); Label entryLabel(env); env->PushCurrentLabel(&entryLabel); DEFVARIABLE(result, StubMachineType::TAGGED, GetHoleConstant()); GateRef properties = GetPropertiesFromJSObject(receiver); GateRef entry = FindEntryFromNameDictionary(glue, properties, key); Label notNegtiveOne(env); Label exit(env); Branch(Int32NotEqual(entry, GetInt32Constant(-1)), ¬NegtiveOne, &exit); Bind(¬NegtiveOne); { result = GetValueFromGlobalDictionary(properties, entry); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } GateRef Stub::JSArrayListGet(GateRef glue, GateRef receiver, GateRef index) { auto env = GetEnvironment(); Label entry(env); env->PushCurrentLabel(&entry); Label exit(env); DEFVARIABLE(result, StubMachineType::TAGGED, GetUndefinedConstant()); GateRef lengthOffset = GetIntPtrConstant(panda::ecmascript::JSAPIArrayList::LENGTH_OFFSET); GateRef length = TaggedCastToInt32(Load(StubMachineType::UINT64, receiver, lengthOffset)); Label isVailedIndex(env); Label notValidIndex(env); Branch(TruncInt32ToInt1(Int32And(ZExtInt1ToInt32(Int32GreaterThanOrEqual(index, GetInt32Constant(0))), ZExtInt1ToInt32(UInt32LessThan(index, length)))), &isVailedIndex, ¬ValidIndex); Bind(&isVailedIndex); { GateRef elements = GetElementsArray(receiver); result = GetValueFromTaggedArray(StubMachineType::TAGGED, elements, index); Jump(&exit); } Bind(¬ValidIndex); { GateRef taggedId = GetInt32Constant(GET_MESSAGE_STRING_ID(GetPropertyOutOfBounds)); CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ThrowTypeError)), { IntBuildTaggedTypeWithNoGC(taggedId) }); result = GetExceptionConstant(); Jump(&exit); } Bind(&exit); auto ret = *result; env->PopCurrentLabel(); return ret; } } // namespace panda::ecmascript::kungfu