blob: 17b7869f65050e8a3913b979b4a94af2a827bf35 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
struct BailoutConstantValue {
public:
void InitIntConstValue(int32 value) { this->type = TyInt32; this->u.intConst.value = (IntConstType)value; };
void InitIntConstValue(IntConstType value, IRType type) {
Assert(IRType_IsSignedInt(type));
this->type = type; this->u.intConst.value = value;
};
void InitVarConstValue(Js::Var value);
void InitFloatConstValue(FloatConstType value) { this->type = TyFloat64; this->u.floatConst.value = value; }
bool IsEqual(const BailoutConstantValue & bailoutConstValue);
public:
IRType type;
union
{
struct sIntConst
{
IntConstType value;
} intConst;
struct sVarConst
{
Js::Var value;
} varConst;
struct sFloatConst
{
FloatConstType value;
} floatConst;
} u;
Js::Var ToVar(Func* func) const;
};
enum InlineeFrameInfoValueType
{
InlineeFrameInfoValueType_None,
InlineeFrameInfoValueType_Sym,
InlineeFrameInfoValueType_Const
};
struct InlineFrameInfoValue
{
InlineeFrameInfoValueType type;
union
{
StackSym* sym;
BailoutConstantValue constValue;
};
bool IsConst() { return this->type == InlineeFrameInfoValueType_Const; }
InlineFrameInfoValue() : type(InlineeFrameInfoValueType_None), sym(nullptr) {}
InlineFrameInfoValue(StackSym* sym) : type(InlineeFrameInfoValueType_Sym), sym(sym) {}
InlineFrameInfoValue(BailoutConstantValue value) : type(InlineeFrameInfoValueType_Const), constValue(value) {}
};
struct InlineeFrameInfo;
struct InlineeFrameRecord
{
int functionOffset;
int inlineDepth;
uint inlineeStartOffset;
int* argOffsets;
Js::Var * constants;
InlineeFrameRecord* parent;
uint argCount;
BVUnit floatArgs;
BVUnit losslessInt32Args;
template<class Fnc>
void MapOffsets(Fnc callback)
{
callback(functionOffset);
for (uint i = 0; i < argCount; i++)
{
callback(argOffsets[i]);
}
}
#if DBG_DUMP
uint constantCount;
Js::FunctionBody* functionBody;
InlineeFrameInfo* frameInfo;
#endif
// Fields are zero initialized any way
InlineeFrameRecord(uint argCount, Js::FunctionBody* functionBody, InlineeFrameInfo* frameInfo) : argCount(argCount)
#if DBG_DUMP
, functionBody(functionBody)
, frameInfo(frameInfo)
#endif
{}
static InlineeFrameRecord* New(NativeCodeData::Allocator* alloc, uint argCount, uint constantCount, intptr_t functionBodyAddr, InlineeFrameInfo* frameInfo)
{
InlineeFrameRecord* record = NativeCodeDataNewZ(alloc, InlineeFrameRecord, argCount, (Js::FunctionBody*)functionBodyAddr, frameInfo);
record->argOffsets = (int*)NativeCodeDataNewArrayNoFixup(alloc, IntType<DataDesc_InlineeFrameRecord_ArgOffsets>, argCount);
record->constants = (Js::Var*)NativeCodeDataNewArrayNoFixup(alloc, VarType<DataDesc_InlineeFrameRecord_Constants>, constantCount);
DebugOnly(record->constantCount = constantCount);
return record;
}
void PopulateParent(Func* func);
void RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostInlinee, Js::JavascriptCallStackLayout* callstack);
void Finalize(Func* inlinee, uint currentOffset);
#if DBG_DUMP
void Dump() const;
void DumpOffset(int offset) const;
#endif
void Fixup(NativeCodeData::DataChunk* chunkList)
{
FixupNativeDataPointer(argOffsets, chunkList);
FixupNativeDataPointer(constants, chunkList);
FixupNativeDataPointer(parent, chunkList);
}
private:
void Restore(Js::FunctionBody* functionBody, InlinedFrameLayout *outerMostFrame, Js::JavascriptCallStackLayout * layout) const;
Js::Var Restore(int offset, bool isFloat64, bool isInt32, Js::JavascriptCallStackLayout * layout, Js::FunctionBody* functionBody) const;
InlineeFrameRecord* Reverse();
};
struct NativeOffsetInlineeFramePair
{
uint32 offset;
InlineeFrameRecord* record;
};
struct NativeOffsetInlineeFrameRecordOffset
{
uint32 offset;
uint32 recordOffset;
static uint32 InvalidRecordOffset;
};
struct InlineeFrameInfo
{
typedef JsUtil::List<InlineFrameInfoValue, JitArenaAllocator, /*isLeaf*/ false> ArgList;
InlineFrameInfoValue function;
ArgList* arguments;
InlineeFrameRecord* record;
BVSparse<JitArenaAllocator>* floatSyms;
BVSparse<JitArenaAllocator>* intSyms;
BVSparse<JitArenaAllocator>* simd128F4Syms;
BVSparse<JitArenaAllocator>* simd128I4Syms;
BVSparse<JitArenaAllocator>* simd128I8Syms;
BVSparse<JitArenaAllocator>* simd128I16Syms;
BVSparse<JitArenaAllocator>* simd128U4Syms;
BVSparse<JitArenaAllocator>* simd128U8Syms;
BVSparse<JitArenaAllocator>* simd128U16Syms;
bool isRecorded;
static InlineeFrameInfo* New(JitArenaAllocator* alloc)
{
InlineeFrameInfo* frameInfo = JitAnewStructZ(alloc, InlineeFrameInfo);
frameInfo->arguments = JitAnew(alloc, ArgList, alloc);
return frameInfo;
}
template<class Fn>
void IterateSyms(Fn callback, bool inReverse = false)
{
auto iterator = [=](uint index, InlineFrameInfoValue& value)
{
if (value.type == InlineeFrameInfoValueType_Sym)
{
callback(value.sym);
}
Assert(value.type != InlineeFrameInfoValueType_None);
};
if (inReverse && function.type == InlineeFrameInfoValueType_Sym)
{
callback(function.sym);
}
if (inReverse)
{
arguments->ReverseMap(iterator);
}
else
{
arguments->Map(iterator);
}
Assert(function.type != InlineeFrameInfoValueType_None);
if (!inReverse && function.type == InlineeFrameInfoValueType_Sym)
{
callback(function.sym);
}
}
void AllocateRecord(Func* func, intptr_t functionBodyAddr);
#if DBG_DUMP
void Dump() const;
#endif
};