StructureStubInfo.h [plain text]
#pragma once
#include "CodeBlock.h"
#include "CodeOrigin.h"
#include "Instruction.h"
#include "JITStubRoutine.h"
#include "MacroAssembler.h"
#include "Options.h"
#include "RegisterSet.h"
#include "Structure.h"
#include "StructureSet.h"
#include "StructureStubClearingWatchpoint.h"
namespace JSC {
#if ENABLE(JIT)
class AccessCase;
class AccessGenerationResult;
class PolymorphicAccess;
enum class AccessType : int8_t {
Get,
GetWithThis,
GetDirect,
TryGet,
Put,
In,
InstanceOf
};
enum class CacheType : int8_t {
Unset,
GetByIdSelf,
PutByIdReplace,
InByIdSelf,
Stub,
ArrayLength
};
class StructureStubInfo {
WTF_MAKE_NONCOPYABLE(StructureStubInfo);
WTF_MAKE_FAST_ALLOCATED;
public:
StructureStubInfo(AccessType);
~StructureStubInfo();
void initGetByIdSelf(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
void initArrayLength();
void initPutByIdReplace(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
void initInByIdSelf(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
AccessGenerationResult addAccessCase(const GCSafeConcurrentJSLocker&, CodeBlock*, const Identifier&, std::unique_ptr<AccessCase>);
void reset(CodeBlock*);
void deref();
void aboutToDie();
void visitWeakReferences(CodeBlock*);
bool propagateTransitions(SlotVisitor&);
ALWAYS_INLINE bool considerCaching(CodeBlock* codeBlock, Structure* structure)
{
if (!structure) {
sawNonCell = true;
return false;
}
everConsidered = true;
if (!countdown) {
WTF::incrementWithSaturation(repatchCount);
if (repatchCount > Options::repatchCountForCoolDown()) {
repatchCount = 0;
countdown = WTF::leftShiftWithSaturation(
static_cast<uint8_t>(Options::initialCoolDownCount()),
numberOfCoolDowns,
static_cast<uint8_t>(std::numeric_limits<uint8_t>::max() - 1));
WTF::incrementWithSaturation(numberOfCoolDowns);
bufferingCountdown = 0;
return true;
}
if (!bufferingCountdown) {
return true;
}
bufferingCountdown--;
bool isNewlyAdded = bufferedStructures.add(structure);
if (isNewlyAdded) {
VM& vm = *codeBlock->vm();
vm.heap.writeBarrier(codeBlock);
}
return isNewlyAdded;
}
countdown--;
return false;
}
bool containsPC(void* pc) const;
CodeOrigin codeOrigin;
CallSiteIndex callSiteIndex;
union {
struct {
WriteBarrierBase<Structure> baseObjectStructure;
PropertyOffset offset;
} byIdSelf;
PolymorphicAccess* stub;
} u;
StructureSet bufferedStructures;
struct {
CodeLocationLabel<JITStubRoutinePtrTag> start; RegisterSet usedRegisters;
uint32_t inlineSize;
int32_t deltaFromStartToSlowPathCallLocation;
int32_t deltaFromStartToSlowPathStart;
int8_t baseGPR;
int8_t valueGPR;
int8_t thisGPR;
#if USE(JSVALUE32_64)
int8_t valueTagGPR;
int8_t baseTagGPR;
int8_t thisTagGPR;
#endif
} patch;
CodeLocationCall<JSInternalPtrTag> slowPathCallLocation() { return patch.start.callAtOffset<JSInternalPtrTag>(patch.deltaFromStartToSlowPathCallLocation); }
CodeLocationLabel<JSInternalPtrTag> doneLocation() { return patch.start.labelAtOffset<JSInternalPtrTag>(patch.inlineSize); }
CodeLocationLabel<JITStubRoutinePtrTag> slowPathStartLocation() { return patch.start.labelAtOffset(patch.deltaFromStartToSlowPathStart); }
CodeLocationJump<JSInternalPtrTag> patchableJump()
{
ASSERT(accessType == AccessType::InstanceOf);
return patch.start.jumpAtOffset<JSInternalPtrTag>(0);
}
JSValueRegs valueRegs() const
{
return JSValueRegs(
#if USE(JSVALUE32_64)
static_cast<GPRReg>(patch.valueTagGPR),
#endif
static_cast<GPRReg>(patch.valueGPR));
}
AccessType accessType;
CacheType cacheType;
uint8_t countdown; uint8_t repatchCount;
uint8_t numberOfCoolDowns;
uint8_t bufferingCountdown;
bool resetByGC : 1;
bool tookSlowPath : 1;
bool everConsidered : 1;
bool prototypeIsKnownObject : 1; bool sawNonCell : 1;
};
inline CodeOrigin getStructureStubInfoCodeOrigin(StructureStubInfo& structureStubInfo)
{
return structureStubInfo.codeOrigin;
}
inline J_JITOperation_ESsiJI appropriateOptimizingGetByIdFunction(AccessType type)
{
switch (type) {
case AccessType::Get:
return operationGetByIdOptimize;
case AccessType::TryGet:
return operationTryGetByIdOptimize;
case AccessType::GetDirect:
return operationGetByIdDirectOptimize;
case AccessType::GetWithThis:
default:
ASSERT_NOT_REACHED();
return nullptr;
}
}
inline J_JITOperation_EJI appropriateGenericGetByIdFunction(AccessType type)
{
switch (type) {
case AccessType::Get:
return operationGetByIdGeneric;
case AccessType::TryGet:
return operationTryGetByIdGeneric;
case AccessType::GetDirect:
return operationGetByIdDirectGeneric;
case AccessType::GetWithThis:
default:
ASSERT_NOT_REACHED();
return nullptr;
}
}
#else
class StructureStubInfo;
#endif // ENABLE(JIT)
typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap;
}