| //------------------------------------------------------------------------------------------------------- |
| // Copyright (C) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. |
| //------------------------------------------------------------------------------------------------------- |
| #include "RuntimeByteCodePch.h" |
| #if DBG_DUMP |
| |
| #if DBG |
| // Parser Includes |
| #include "RegexCommon.h" |
| #include "DebugWriter.h" |
| #include "RegexPattern.h" |
| #endif |
| |
| namespace Js |
| { |
| // Pre-order recursive dump, head first, then children. |
| void ByteCodeDumper::DumpRecursively(FunctionBody* dumpFunction) |
| { |
| dumpFunction->EnsureDeserialized(); |
| ByteCodeDumper::Dump(dumpFunction); |
| for (uint i = 0; i < dumpFunction->GetNestedCount(); i ++) |
| { |
| dumpFunction->GetNestedFunctionForExecution(i); |
| ByteCodeDumper::DumpRecursively(dumpFunction->GetNestedFunc(i)->GetFunctionBody()); |
| } |
| } |
| |
| void ByteCodeDumper::Dump(FunctionBody* dumpFunction) |
| { |
| ByteCodeReader reader; |
| reader.Create(dumpFunction); |
| StatementReader<FunctionBody::StatementMapList> statementReader; |
| statementReader.Create(dumpFunction); |
| dumpFunction->DumpFullFunctionName(); |
| Output::Print(_u(" (")); |
| ArgSlot inParamCount = dumpFunction->GetInParamsCount(); |
| for (ArgSlot paramIndex = 0; paramIndex < inParamCount; paramIndex++) |
| { |
| if (paramIndex > 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("In%hu"), paramIndex); |
| } |
| Output::Print(_u(") ")); |
| Output::Print(_u("(size: %d [%d])\n"), dumpFunction->GetByteCodeCount(), dumpFunction->GetByteCodeWithoutLDACount()); |
| #if defined(DBG) || defined(ENABLE_DEBUG_CONFIG_OPTIONS) |
| if (dumpFunction->IsInDebugMode()) |
| { |
| Output::Print(_u("[Bytecode was generated for debug mode]\n")); |
| } |
| #endif |
| #if DBG |
| if (dumpFunction->IsReparsed()) |
| { |
| Output::Print(_u("[A reparse is being done]\n")); |
| } |
| #endif |
| Output::Print( |
| _u(" %u locals (%u temps from R%u), %u inline cache\n"), |
| dumpFunction->GetLocalsCount(), |
| dumpFunction->GetTempCount(), |
| dumpFunction->GetFirstTmpReg(), |
| dumpFunction->GetInlineCacheCount()); |
| uint32 statementIndex = 0; |
| ByteCodeDumper::DumpConstantTable(dumpFunction); |
| ByteCodeDumper::DumpImplicitArgIns(dumpFunction); |
| while (true) |
| { |
| while (statementReader.AtStatementBoundary(&reader)) |
| { |
| dumpFunction->PrintStatementSourceLine(statementIndex); |
| statementIndex = statementReader.MoveNextStatementBoundary(); |
| } |
| uint byteOffset = reader.GetCurrentOffset(); |
| LayoutSize layoutSize; |
| OpCode op = reader.ReadOp(layoutSize); |
| if (op == OpCode::EndOfBlock) |
| { |
| Assert(reader.GetCurrentOffset() == dumpFunction->GetByteCode()->GetLength()); |
| break; |
| } |
| Output::Print(_u(" %04x %2s"), byteOffset, layoutSize == LargeLayout? _u("L-") : layoutSize == MediumLayout? _u("M-") : _u("")); |
| DumpOp(op, layoutSize, reader, dumpFunction); |
| if (Js::Configuration::Global.flags.Verbose) |
| { |
| int layoutStart = byteOffset + 2; // Account fo the prefix op |
| int endByteOffset = reader.GetCurrentOffset(); |
| Output::SkipToColumn(70); |
| if (layoutSize == LargeLayout) |
| { |
| Output::Print(_u("%02X "), |
| op > Js::OpCode::MaxByteSizedOpcodes? |
| Js::OpCode::ExtendedLargeLayoutPrefix : Js::OpCode::LargeLayoutPrefix); |
| } |
| else if (layoutSize == MediumLayout) |
| { |
| Output::Print(_u("%02X "), |
| op > Js::OpCode::MaxByteSizedOpcodes? |
| Js::OpCode::ExtendedMediumLayoutPrefix : Js::OpCode::MediumLayoutPrefix); |
| } |
| else |
| { |
| Assert(layoutSize == SmallLayout); |
| if (op > Js::OpCode::MaxByteSizedOpcodes) |
| { |
| Output::Print(_u("%02X "), Js::OpCode::ExtendedOpcodePrefix); |
| } |
| else |
| { |
| Output::Print(_u(" ")); |
| layoutStart--; // don't have a prefix |
| } |
| } |
| |
| Output::Print(_u("%02x"), (byte)op); |
| for (int i = layoutStart; i < endByteOffset; i++) |
| { |
| Output::Print(_u(" %02x"), reader.GetRawByte(i)); |
| } |
| } |
| Output::Print(_u("\n")); |
| } |
| if (statementReader.AtStatementBoundary(&reader)) |
| { |
| dumpFunction->PrintStatementSourceLine(statementIndex); |
| statementIndex = statementReader.MoveNextStatementBoundary(); |
| } |
| Output::Print(_u("\n")); |
| Output::Flush(); |
| } |
| |
| void ByteCodeDumper::DumpConstantTable(FunctionBody *dumpFunction) |
| { |
| Output::Print(_u(" Constant Table:\n ======== =====\n ")); |
| uint count = dumpFunction->GetConstantCount(); |
| for (RegSlot reg = FunctionBody::FirstRegSlot; reg < count; reg++) |
| { |
| DumpReg(reg); |
| Var varConst = dumpFunction->GetConstantVar(reg); |
| Assert(varConst != nullptr); |
| if (TaggedInt::Is(varConst)) |
| { |
| #if ENABLE_NATIVE_CODEGEN |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::LdC_A_I4)); |
| #else |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::Ld_A)); |
| #endif |
| DumpI4(TaggedInt::ToInt32(varConst)); |
| } |
| else if (varConst == (Js::Var)&Js::NullFrameDisplay) |
| { |
| #if ENABLE_NATIVE_CODEGEN |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::LdNullDisplay)); |
| #else |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::Ld_A)); |
| Output::Print(_u(" (NullDisplay)")); |
| #endif |
| } |
| else if (varConst == (Js::Var)&Js::StrictNullFrameDisplay) |
| { |
| #if ENABLE_NATIVE_CODEGEN |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::LdStrictNullDisplay)); |
| #else |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::Ld_A)); |
| Output::Print(_u(" (StrictNullDisplay)")); |
| #endif |
| } |
| else |
| { |
| switch (JavascriptOperators::GetTypeId(varConst)) |
| { |
| case Js::TypeIds_Undefined: |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::Ld_A)); |
| Output::Print(_u(" (undefined)")); |
| break; |
| case Js::TypeIds_Null: |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::Ld_A)); |
| Output::Print(_u(" (null)")); |
| break; |
| case Js::TypeIds_Boolean: |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName( |
| JavascriptBoolean::FromVar(varConst)->GetValue() ? OpCode::LdTrue : OpCode::LdFalse)); |
| break; |
| case Js::TypeIds_Number: |
| #if ENABLE_NATIVE_CODEGEN |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::LdC_A_R8)); |
| #else |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::Ld_A)); |
| #endif |
| Output::Print(_u("%G"), JavascriptNumber::GetValue(varConst)); |
| break; |
| case Js::TypeIds_String: |
| #if ENABLE_NATIVE_CODEGEN |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::LdStr)); |
| #else |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::Ld_A)); |
| #endif |
| Output::Print(_u(" (\"%s\")"), JavascriptString::FromVar(varConst)->GetSz()); |
| break; |
| case Js::TypeIds_GlobalObject: |
| #if ENABLE_NATIVE_CODEGEN |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::LdRoot)); |
| #else |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::Ld_A)); |
| #endif |
| break; |
| case Js::TypeIds_ModuleRoot: |
| #if ENABLE_NATIVE_CODEGEN |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::LdModuleRoot)); |
| #else |
| Output::Print(_u("%-10s"), OpCodeUtil::GetOpCodeName(OpCode::Ld_A)); |
| #endif |
| DumpI4(dumpFunction->GetModuleID()); |
| break; |
| case Js::TypeIds_ES5Array: |
| // ES5Array objects in the constant table are always string template callsite objects. |
| // If we later put other ES5Array objects in the constant table, we'll need another way |
| // to decide the constant type. |
| Output::Print(_u("%-10s"), _u("LdStringTemplate")); |
| Output::Print(_u(" (\"%s\")"), dumpFunction->GetScriptContext()->GetLibrary()->GetStringTemplateCallsiteObjectKey(varConst)); |
| break; |
| default: |
| AssertMsg(UNREACHED, "Unexpected object type in DumpConstantTable"); |
| break; |
| } |
| } |
| Output::Print(_u("\n ")); |
| } |
| Output::Print(_u("\n")); |
| } |
| |
| void ByteCodeDumper::DumpImplicitArgIns(FunctionBody * dumpFunction) |
| { |
| if (dumpFunction->GetInParamsCount() <= 1 || !dumpFunction->GetHasImplicitArgIns()) |
| { |
| return; |
| } |
| Output::Print(_u(" Implicit Arg Ins:\n ======== === ===\n ")); |
| for (RegSlot reg = 1; |
| reg < dumpFunction->GetInParamsCount(); reg++) |
| { |
| DumpReg((RegSlot)(reg + dumpFunction->GetConstantCount() - 1)); |
| // DisableJIT-TODO: Should this entire function be ifdefed? |
| #if ENABLE_NATIVE_CODEGEN |
| Output::Print(_u("%-11s"), OpCodeUtil::GetOpCodeName(Js::OpCode::ArgIn_A)); |
| #endif |
| Output::Print(_u("In%d\n "), reg); |
| } |
| if (dumpFunction->GetHasRestParameter()) |
| { |
| DumpReg(dumpFunction->GetRestParamRegSlot()); |
| #if ENABLE_NATIVE_CODEGEN |
| Output::Print(_u("%-11s"), OpCodeUtil::GetOpCodeName(Js::OpCode::ArgIn_Rest)); |
| #endif |
| Output::Print(_u("In%d\n "), dumpFunction->GetInParamsCount()); |
| } |
| Output::Print(_u("\n")); |
| } |
| |
| void ByteCodeDumper::DumpU4(uint32 value) |
| { |
| Output::Print(_u(" uint:%u "), value); |
| } |
| |
| void ByteCodeDumper::DumpI4(int value) |
| { |
| Output::Print(_u(" int:%d "), value); |
| } |
| |
| void ByteCodeDumper::DumpI8(int64 value) |
| { |
| Output::Print(_u(" int64:%lld "), value); |
| } |
| |
| void ByteCodeDumper::DumpU2(ushort value) |
| { |
| Output::Print(_u(" ushort:%d "), value); |
| } |
| |
| void ByteCodeDumper::DumpOffset(int byteOffset, ByteCodeReader const& reader) |
| { |
| Output::Print(_u(" x:%04x (%4d) "), reader.GetCurrentOffset() + byteOffset, byteOffset); |
| } |
| |
| void ByteCodeDumper::DumpAddr(void* addr) |
| { |
| Output::Print(_u(" addr:%04x "), addr); |
| } |
| |
| void ByteCodeDumper::DumpR4(float value) |
| { |
| Output::Print(_u(" float:%g "), value); |
| } |
| |
| void ByteCodeDumper::DumpR8(double value) |
| { |
| Output::Print(_u(" double:%g "), value); |
| } |
| |
| void ByteCodeDumper::DumpReg(RegSlot registerID) |
| { |
| Output::Print(_u(" R%d "), (int) registerID); |
| } |
| |
| void ByteCodeDumper::DumpReg(RegSlot_TwoByte registerID) |
| { |
| Output::Print(_u(" R%d "), (int) registerID); |
| } |
| |
| void ByteCodeDumper::DumpReg(RegSlot_OneByte registerID) |
| { |
| Output::Print(_u(" R%d "), (int) registerID); |
| } |
| |
| void ByteCodeDumper::DumpProfileId(uint id) |
| { |
| Output::Print(_u(" <%d> "), id); |
| } |
| |
| void ByteCodeDumper::DumpEmpty(OpCode op, const unaligned OpLayoutEmpty * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::CommitScope: |
| { |
| const Js::PropertyIdArray *propIds = dumpFunction->GetFormalsPropIdArray(); |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| Output::Print(_u(" %d ["), propIds->count); |
| for (uint i = 0; i < propIds->count && i < 3; i++) |
| { |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName(propIds->elements[i]); |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%s"), pPropertyName->GetBuffer()); |
| } |
| Output::Print(_u("]")); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpCallI(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| if (data->Return != Constants::NoRegister) |
| { |
| DumpReg((RegSlot)data->Return); |
| Output::Print(_u("=")); |
| } |
| Output::Print(_u(" R%d(ArgCount: %d)"), data->Function, data->ArgCount); |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpCallIExtended(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpCallI(op, data, dumpFunction, reader); |
| if (data->Options & Js::CallIExtended_SpreadArgs) |
| { |
| const Js::AuxArray<uint32> *arr = reader.ReadAuxArray<uint32>(data->SpreadAuxOffset, dumpFunction); |
| Output::Print(_u(" spreadArgs ["), arr->count); |
| for (uint i = 0; i < arr->count; i++) |
| { |
| if (i > 10) |
| { |
| Output::Print(_u(", ...")); |
| break; |
| } |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%u"), arr->elements[i]); |
| } |
| Output::Print(_u("]")); |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpCallIFlags(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpCallI(op, data, dumpFunction, reader); |
| Output::Print(_u(" <%04x> "), data->callFlags); |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpCallIExtendedFlags(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpCallIFlags(op, data, dumpFunction, reader); |
| if (data->Options & Js::CallIExtended_SpreadArgs) |
| { |
| const Js::AuxArray<uint32> *arr = reader.ReadAuxArray<uint32>(data->SpreadAuxOffset, dumpFunction); |
| Output::Print(_u(" spreadArgs ["), arr->count); |
| for (uint i = 0; i < arr->count; i++) |
| { |
| if (i > 10) |
| { |
| Output::Print(_u(", ...")); |
| break; |
| } |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%u"), arr->elements[i]); |
| } |
| Output::Print(_u("]")); |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpCallIExtendedFlagsWithICIndex(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpCallIFlags(op, data, dumpFunction, reader); |
| DumpCallIWithICIndex(op, data, dumpFunction, reader); |
| if (data->Options & Js::CallIExtended_SpreadArgs) |
| { |
| const Js::AuxArray<uint32> *arr = reader.ReadAuxArray<uint32>(data->SpreadAuxOffset, dumpFunction); |
| Output::Print(_u(" spreadArgs ["), arr->count); |
| for (uint i = 0; i < arr->count; i++) |
| { |
| if (i > 10) |
| { |
| Output::Print(_u(", ...")); |
| break; |
| } |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%u"), arr->elements[i]); |
| } |
| Output::Print(_u("]")); |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpCallIWithICIndex(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpCallI(op, data, dumpFunction, reader); |
| Output::Print(_u(" <%d> "), data->inlineCacheIndex); |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpCallIFlagsWithICIndex(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpCallI(op, data, dumpFunction, reader); |
| Output::Print(_u(" <%d> "), data->inlineCacheIndex); |
| Output::Print(_u(" <%d> "), data->callFlags); |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpCallIExtendedWithICIndex(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpCallIWithICIndex(op, data, dumpFunction, reader); |
| if (data->Options & Js::CallIExtended_SpreadArgs) |
| { |
| const Js::AuxArray<uint32> *arr = reader.ReadAuxArray<uint32>(data->SpreadAuxOffset, dumpFunction); |
| Output::Print(_u(" spreadArgs ["), arr->count); |
| for (uint i=0; i < arr->count; i++) |
| { |
| if (i > 10) |
| { |
| Output::Print(_u(", ...")); |
| break; |
| } |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%u"), arr->elements[i]); |
| } |
| Output::Print(_u("]")); |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementI(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::ProfiledLdElemI_A: |
| case OpCode::LdElemI_A: |
| case OpCode::LdMethodElem: |
| case OpCode::TypeofElem: |
| { |
| Output::Print(_u(" R%d = R%d[R%d]"), data->Value, data->Instance, data->Element); |
| break; |
| } |
| case OpCode::ProfiledStElemI_A: |
| case OpCode::ProfiledStElemI_A_Strict: |
| case OpCode::StElemI_A: |
| case OpCode::StElemI_A_Strict: |
| case OpCode::InitSetElemI: |
| case OpCode::InitGetElemI: |
| case OpCode::InitComputedProperty: |
| case OpCode::InitClassMemberComputedName: |
| case OpCode::InitClassMemberGetComputedName: |
| case OpCode::InitClassMemberSetComputedName: |
| { |
| Output::Print(_u(" R%d[R%d] = R%d"), data->Instance, data->Element, data->Value); |
| break; |
| } |
| case OpCode::DeleteElemI_A: |
| case OpCode::DeleteElemIStrict_A: |
| { |
| Output::Print(_u(" R%d[R%d]"), data->Instance, data->Element); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementI"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpReg2Int1(OpCode op, const unaligned T* data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::LdThis: |
| case OpCode::ProfiledLdThis: |
| Output::Print(_u(" R%d = R%d, %d"), data->R0, data->R1, data->C1); |
| break; |
| case OpCode::LdIndexedFrameDisplay: |
| Output::Print(_u(" R%d = [%d], R%d "), data->R0, data->C1, data->R1); |
| break; |
| case OpCode::GetCachedFunc: |
| DumpReg(data->R0); |
| Output::Print(_u("= func(")); |
| DumpReg(data->R1); |
| Output::Print(_u(",")); |
| DumpI4(data->C1); |
| Output::Print(_u(")")); |
| break; |
| default: |
| AssertMsg(false, "Unknown OpCode for OpLayoutReg2Int1"); |
| break; |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementScopedU(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| switch (op) |
| { |
| case OpCode::LdElemUndefScoped: |
| { |
| Output::Print(_u(" %s = undefined, R%d"), pPropertyName->GetBuffer(), Js::FunctionBody::RootObjectRegSlot); |
| break; |
| } |
| case OpCode::InitUndeclConsoleLetFld: |
| case OpCode::InitUndeclConsoleConstFld: |
| { |
| Output::Print(_u(" %s = undefined"), pPropertyName->GetBuffer()); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for ElementScopedU"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementU(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| switch (op) |
| { |
| case OpCode::LdElemUndef: |
| { |
| Output::Print(_u(" R%d.%s = undefined"), data->Instance, pPropertyName->GetBuffer()); |
| break; |
| } |
| // TODO: Change InitUndeclLetFld and InitUndeclConstFld to ElementU layout |
| // case OpCode::InitUndeclLetFld: |
| // case OpCode::InitUndeclConstFld: |
| // { |
| // PropertyRecord const * pPropertyName = scriptContext->GetPropertyName(data->PropertyIndex); |
| // Output::Print(_u(" R%d.%s"), data->Instance, pPropertyName->GetBuffer()); |
| // break; |
| // } |
| case OpCode::ClearAttributes: |
| { |
| Output::Print(_u(" R%d.%s.writable/enumerable/configurable = 0"), data->Instance, pPropertyName->GetBuffer()); |
| break; |
| } |
| |
| case OpCode::DeleteLocalFld: |
| Output::Print(_u(" R%d = %s "), data->Instance, pPropertyName->GetBuffer()); |
| break; |
| |
| case OpCode::StLocalFuncExpr: |
| Output::Print(_u(" %s = R%d"), pPropertyName->GetBuffer(), data->Instance); |
| break; |
| |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for ElementU"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementRootU(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| switch (op) |
| { |
| case OpCode::InitUndeclRootLetFld: |
| case OpCode::InitUndeclRootConstFld: |
| case OpCode::EnsureNoRootFld: |
| case OpCode::EnsureNoRootRedeclFld: |
| { |
| Output::Print(_u(" root.%s"), pPropertyName->GetBuffer()); |
| break; |
| } |
| case OpCode::LdLocalElemUndef: |
| { |
| Output::Print(_u(" %s = undefined"), pPropertyName->GetBuffer()); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for ElementRootU"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementScopedC(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| switch (op) |
| { |
| case OpCode::ScopedEnsureNoRedeclFld: |
| case OpCode::ScopedDeleteFld: |
| case OpCode::ScopedDeleteFldStrict: |
| { |
| Output::Print(_u(" %s, R%d"), pPropertyName->GetBuffer(), data->Value); |
| break; |
| } |
| case OpCode::ScopedInitFunc: |
| { |
| Output::Print(_u(" %s = R%d, R%d"), pPropertyName->GetBuffer(), data->Value, |
| Js::FunctionBody::RootObjectRegSlot); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementScopedC"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementC(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| switch (op) |
| { |
| case OpCode::DeleteFld: |
| case OpCode::DeleteRootFld: |
| case OpCode::DeleteFldStrict: |
| case OpCode::DeleteRootFldStrict: |
| { |
| Output::Print(_u(" R%d.%s"), data->Instance, pPropertyName->GetBuffer()); |
| break; |
| } |
| case OpCode::InitSetFld: |
| case OpCode::InitGetFld: |
| case OpCode::InitClassMemberGet: |
| case OpCode::InitClassMemberSet: |
| { |
| Output::Print(_u(" R%d.%s = (Set/Get) R%d"), data->Instance, pPropertyName->GetBuffer(), |
| data->Value); |
| break; |
| } |
| case OpCode::StFuncExpr: |
| case OpCode::InitProto: |
| { |
| Output::Print(_u(" R%d.%s = R%d"), data->Instance, pPropertyName->GetBuffer(), |
| data->Value); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementC"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementScopedC2(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| switch (op) |
| { |
| case OpCode::ScopedLdInst: |
| { |
| Output::Print(_u(" R%d, R%d = %s"), data->Value, data->Value2, pPropertyName->GetBuffer()); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementScopedC2"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementC2(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| switch (op) |
| { |
| case OpCode::LdSuperFld: |
| { |
| Output::Print(_u(" R%d = R%d(this=R%d).%s #%d"), data->Value, data->Instance, data->Value2, |
| pPropertyName->GetBuffer(), data->PropertyIdIndex); |
| break; |
| } |
| case OpCode::ProfiledLdSuperFld: |
| { |
| Output::Print(_u(" R%d = R%d(this=R%d).%s #%d"), data->Value, data->Instance, data->Value2, |
| pPropertyName->GetBuffer(), data->PropertyIdIndex); |
| DumpProfileId(data->PropertyIdIndex); |
| break; |
| } |
| case OpCode::StSuperFld: |
| { |
| Output::Print(_u(" R%d.%s(this=R%d) = R%d #%d"), data->Instance, pPropertyName->GetBuffer(), |
| data->Value2, data->Value, data->PropertyIdIndex); |
| break; |
| } |
| case OpCode::ProfiledStSuperFld: |
| { |
| Output::Print(_u(" R%d.%s(this=R%d) = R%d #%d"), data->Instance, pPropertyName->GetBuffer(), |
| data->Value2, data->Value, data->PropertyIdIndex); |
| DumpProfileId(data->PropertyIdIndex); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementC2"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpReg1Unsigned1(OpCode op, const unaligned T* data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::InvalCachedScope: |
| #if ENABLE_NATIVE_CODEGEN |
| case OpCode::NewScopeSlots: |
| #endif |
| Output::Print(_u(" R%u[%u]"), data->R0, data->C1); |
| break; |
| case OpCode::NewRegEx: |
| { |
| DumpReg(data->R0); |
| #if DBG |
| Output::Print(_u("=")); |
| UnifiedRegex::DebugWriter w; |
| dumpFunction->GetLiteralRegex(data->C1)->Print(&w); |
| #else |
| Output::Print(_u("=<regex>")); |
| #endif |
| break; |
| } |
| case OpCode::InitForInEnumerator: |
| { |
| DumpReg(data->R0); |
| DumpU4(data->C1); |
| break; |
| } |
| default: |
| DumpReg(data->R0); |
| Output::Print(_u("=")); |
| DumpU4(data->C1); |
| break; |
| }; |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementSlot(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::NewInnerStackScFunc: |
| case OpCode::NewInnerScFunc: |
| case OpCode::NewInnerScGenFunc: |
| { |
| FunctionProxy* pfuncActual = dumpFunction->GetNestedFunctionProxy((uint)data->SlotIndex); |
| Output::Print(_u(" R%d = env:R%d, %s()"), data->Value, data->Instance, |
| pfuncActual->EnsureDeserialized()->GetDisplayName()); |
| break; |
| } |
| #if ENABLE_NATIVE_CODEGEN |
| case OpCode::StSlot: |
| case OpCode::StSlotChkUndecl: |
| #endif |
| case OpCode::StObjSlot: |
| case OpCode::StObjSlotChkUndecl: |
| Output::Print(_u(" R%d[%d] = R%d "),data->Instance,data->SlotIndex,data->Value); |
| break; |
| case OpCode::LdSlot: |
| #if ENABLE_NATIVE_CODEGEN |
| case OpCode::LdSlotArr: |
| #endif |
| case OpCode::LdObjSlot: |
| Output::Print(_u(" R%d = R%d[%d] "),data->Value,data->Instance,data->SlotIndex); |
| break; |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementSlot"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementSlotI1(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::StLocalSlot: |
| case OpCode::StParamSlot: |
| case OpCode::StLocalObjSlot: |
| case OpCode::StParamObjSlot: |
| case OpCode::StLocalSlotChkUndecl: |
| case OpCode::StParamSlotChkUndecl: |
| case OpCode::StLocalObjSlotChkUndecl: |
| case OpCode::StParamObjSlotChkUndecl: |
| Output::Print(_u(" [%d] = R%d "),data->SlotIndex, data->Value); |
| break; |
| case OpCode::LdLocalSlot: |
| case OpCode::LdParamSlot: |
| case OpCode::LdEnvObj: |
| case OpCode::LdLocalObjSlot: |
| case OpCode::LdParamObjSlot: |
| Output::Print(_u(" R%d = [%d] "),data->Value, data->SlotIndex); |
| break; |
| case OpCode::NewScFunc: |
| case OpCode::NewStackScFunc: |
| case OpCode::NewScGenFunc: |
| { |
| FunctionProxy* pfuncActual = dumpFunction->GetNestedFunctionProxy((uint)data->SlotIndex); |
| Output::Print(_u(" R%d = %s()"), data->Value, |
| pfuncActual->EnsureDeserialized()->GetDisplayName()); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementSlotI1"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementSlotI2(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::StInnerSlot: |
| case OpCode::StInnerSlotChkUndecl: |
| case OpCode::StInnerObjSlot: |
| case OpCode::StInnerObjSlotChkUndecl: |
| case OpCode::StEnvSlot: |
| case OpCode::StEnvObjSlot: |
| case OpCode::StEnvSlotChkUndecl: |
| case OpCode::StEnvObjSlotChkUndecl: |
| case OpCode::StModuleSlot: |
| Output::Print(_u(" [%d][%d] = R%d "),data->SlotIndex1, data->SlotIndex2, data->Value); |
| break; |
| case OpCode::LdInnerSlot: |
| case OpCode::LdInnerObjSlot: |
| case OpCode::LdEnvSlot: |
| case OpCode::LdEnvObjSlot: |
| case OpCode::LdModuleSlot: |
| Output::Print(_u(" R%d = [%d][%d] "),data->Value, data->SlotIndex1, data->SlotIndex2); |
| break; |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementSlotI2"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementP(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyId propertyId = dumpFunction->GetPropertyIdFromCacheId(data->inlineCacheIndex); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName(propertyId); |
| switch (op) |
| { |
| case OpCode::ScopedLdFldForTypeOf: |
| case OpCode::ScopedLdFld: |
| Output::Print(_u(" R%d = %s, R%d #%d"), data->Value, pPropertyName->GetBuffer(), |
| Js::FunctionBody::RootObjectRegSlot, data->inlineCacheIndex); |
| break; |
| |
| case OpCode::ScopedStFld: |
| case OpCode::ConsoleScopedStFld: |
| case OpCode::ScopedStFldStrict: |
| Output::Print(_u(" %s = R%d, R%d #%d"), pPropertyName->GetBuffer(), data->Value, |
| Js::FunctionBody::RootObjectRegSlot, data->inlineCacheIndex); |
| break; |
| |
| case OpCode::LdLocalFld: |
| Output::Print(_u(" R%d = %s #%d"), data->Value, pPropertyName->GetBuffer(), data->inlineCacheIndex); |
| break; |
| |
| case OpCode::ProfiledLdLocalFld: |
| Output::Print(_u(" R%d = %s #%d"), data->Value, pPropertyName->GetBuffer(), data->inlineCacheIndex); |
| DumpProfileId(data->inlineCacheIndex); |
| break; |
| |
| case OpCode::StLocalFld: |
| case OpCode::InitLocalFld: |
| case OpCode::InitLocalLetFld: |
| case OpCode::InitUndeclLocalLetFld: |
| case OpCode::InitUndeclLocalConstFld: |
| Output::Print(_u(" %s = R%d #%d"), pPropertyName->GetBuffer(), data->Value, data->inlineCacheIndex); |
| break; |
| |
| case OpCode::ProfiledStLocalFld: |
| case OpCode::ProfiledInitLocalFld: |
| Output::Print(_u(" %s = R%d #%d"), pPropertyName->GetBuffer(), data->Value, data->inlineCacheIndex); |
| DumpProfileId(data->inlineCacheIndex); |
| break; |
| |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementP"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementPIndexed(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyId propertyId = dumpFunction->GetPropertyIdFromCacheId(data->inlineCacheIndex); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName(propertyId); |
| switch (op) |
| { |
| case OpCode::InitInnerFld: |
| case OpCode::InitInnerLetFld: |
| case OpCode::InitUndeclLetFld: |
| case OpCode::InitUndeclConstFld: |
| Output::Print(_u(" [%d].%s = R%d #%d"), data->scopeIndex, pPropertyName->GetBuffer(), data->Value, data->inlineCacheIndex); |
| break; |
| |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementPIndexed"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementCP(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyId propertyId = dumpFunction->GetPropertyIdFromCacheId(data->inlineCacheIndex); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName(propertyId); |
| switch (op) |
| { |
| case OpCode::LdFldForTypeOf: |
| case OpCode::LdFld: |
| case OpCode::LdFldForCallApplyTarget: |
| case OpCode::LdMethodFld: |
| case OpCode::ScopedLdMethodFld: |
| { |
| Output::Print(_u(" R%d = R%d.%s #%d"), data->Value, data->Instance, |
| pPropertyName->GetBuffer(), data->inlineCacheIndex); |
| break; |
| } |
| case OpCode::InitFld: |
| case OpCode::InitLetFld: |
| case OpCode::InitConstFld: |
| case OpCode::StFld: |
| case OpCode::StFldStrict: |
| case OpCode::InitClassMember: |
| { |
| Output::Print(_u(" R%d.%s = R%d #%d"), data->Instance, pPropertyName->GetBuffer(), |
| data->Value, data->inlineCacheIndex); |
| break; |
| } |
| case OpCode::ProfiledLdFldForTypeOf: |
| case OpCode::ProfiledLdFld: |
| case OpCode::ProfiledLdFldForCallApplyTarget: |
| case OpCode::ProfiledLdMethodFld: |
| { |
| Output::Print(_u(" R%d = R%d.%s #%d"), data->Value, data->Instance, |
| pPropertyName->GetBuffer(), data->inlineCacheIndex); |
| DumpProfileId(data->inlineCacheIndex); |
| break; |
| } |
| case OpCode::ProfiledInitFld: |
| case OpCode::ProfiledStFld: |
| case OpCode::ProfiledStFldStrict: |
| { |
| Output::Print(_u(" R%d.%s = R%d #%d"), data->Instance, pPropertyName->GetBuffer(), |
| data->Value, data->inlineCacheIndex); |
| DumpProfileId(data->inlineCacheIndex); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementCP"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementRootCP(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyId propertyId = dumpFunction->GetPropertyIdFromCacheId(data->inlineCacheIndex); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName(propertyId); |
| switch (op) |
| { |
| case OpCode::LdRootFld: |
| case OpCode::LdRootMethodFld: |
| case OpCode::LdRootFldForTypeOf: |
| { |
| Output::Print(_u(" R%d = root.%s #%d"), data->Value, |
| pPropertyName->GetBuffer(), data->inlineCacheIndex); |
| break; |
| } |
| case OpCode::InitRootFld: |
| case OpCode::InitRootLetFld: |
| case OpCode::InitRootConstFld: |
| case OpCode::StRootFld: |
| case OpCode::StRootFldStrict: |
| { |
| Output::Print(_u(" root.%s = R%d #%d"), pPropertyName->GetBuffer(), |
| data->Value, data->inlineCacheIndex); |
| break; |
| } |
| case OpCode::ProfiledLdRootFld: |
| case OpCode::ProfiledLdRootFldForTypeOf: |
| case OpCode::ProfiledLdRootMethodFld: |
| { |
| Output::Print(_u(" R%d = root.%s #%d"), data->Value, |
| pPropertyName->GetBuffer(), data->inlineCacheIndex); |
| DumpProfileId(data->inlineCacheIndex); |
| break; |
| } |
| case OpCode::ProfiledInitRootFld: |
| case OpCode::ProfiledStRootFld: |
| case OpCode::ProfiledStRootFldStrict: |
| { |
| Output::Print(_u(" root.%s = R%d #%d"), pPropertyName->GetBuffer(), |
| data->Value, data->inlineCacheIndex); |
| DumpProfileId(data->inlineCacheIndex); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementRootCP"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpElementUnsigned1(OpCode op, const unaligned T * data, Js::FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::StArrItemC_CI4: |
| case OpCode::StArrItemI_CI4: |
| case OpCode::StArrSegItem_CI4: |
| case OpCode::StArrInlineItem_CI4: |
| Output::Print(_u(" R%d["), data->Instance); |
| DumpI4(data->Element); |
| Output::Print(_u("] = R%d"), data->Value); |
| break; |
| default: |
| AssertMsg(false, "Unknown OpCode for OpLayoutElementUnsigned1"); |
| break; |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpArg(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::ProfiledArgOut_A: |
| case OpCode::ArgOut_A: |
| case OpCode::ArgOut_ANonVar: |
| { |
| Output::Print(_u(" Out%d ="), (int) data->Arg); |
| DumpReg(data->Reg); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutArg"); |
| break; |
| } |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpArgNoSrc(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case Js::OpCode::ArgOut_Env: |
| { |
| Output::Print(_u(" Out%d "), (int) data->Arg); |
| break; |
| } |
| default: |
| { |
| AssertMsg(false, "Unknown OpCode for OpLayoutArgNoSrc"); |
| break; |
| } |
| } |
| } |
| |
| void |
| ByteCodeDumper::DumpStartCall(OpCode op, const unaligned OpLayoutStartCall * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| Assert(op == OpCode::StartCall ); |
| Output::Print(_u(" ArgCount: %d"), data->ArgCount); |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpUnsigned1(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpU4(data->C1); |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpReg1(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::ObjectFreeze: |
| Output::Print(_u(" R%d.freeze()"), data->R0); |
| break; |
| default: |
| DumpReg(data->R0); |
| break; |
| } |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpReg2(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpReg(data->R0); |
| DumpReg(data->R1); |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpReg2WithICIndex(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpReg2(op, data, dumpFunction, reader); |
| Output::Print(_u(" <%d> "), data->inlineCacheIndex); |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpReg3(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::NewInnerScopeSlots: |
| Output::Print(_u(" [%d], %d, %d "), data->R0, data->R1, data->R2); |
| break; |
| |
| default: |
| DumpReg(data->R0); |
| DumpReg(data->R1); |
| DumpReg(data->R2); |
| break; |
| } |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpReg3C(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::IsInst: |
| Output::Print(_u("R%d = R%d instanceof R%d #%d"), |
| data->R0, data->R1, data->R2, data->inlineCacheIndex); |
| break; |
| default: |
| AssertMsg(false, "Unknown OpCode for OpLayoutReg3C"); |
| } |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpReg4(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpReg(data->R0); |
| DumpReg(data->R1); |
| DumpReg(data->R2); |
| DumpReg(data->R3); |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpReg2B1(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpReg(data->R0); |
| DumpReg(data->R1); |
| DumpI4(data->B2); |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpReg3B1(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpReg(data->R0); |
| DumpReg(data->R1); |
| DumpReg(data->R2); |
| DumpI4(data->B3); |
| } |
| |
| template <class T> void |
| ByteCodeDumper::DumpReg5(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpReg(data->R0); |
| DumpReg(data->R1); |
| DumpReg(data->R2); |
| DumpReg(data->R3); |
| DumpReg(data->R4); |
| } |
| |
| void |
| ByteCodeDumper::DumpW1(OpCode op, const unaligned OpLayoutW1 * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpU2(data->C1); |
| } |
| |
| void |
| ByteCodeDumper::DumpReg1Int2(OpCode op, const unaligned OpLayoutReg1Int2 * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpReg(data->R0); |
| Output::Print(_u("=")); |
| DumpI4(data->C1); |
| DumpI4(data->C2); |
| } |
| |
| void |
| ByteCodeDumper::DumpAuxNoReg(OpCode op, const unaligned OpLayoutAuxNoReg * playout, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case Js::OpCode::InitCachedFuncs: |
| { |
| const Js::FuncInfoArray *arr = reader.ReadAuxArray<FuncInfoEntry>(playout->Offset, dumpFunction); |
| Output::Print(_u(" %d ["), arr->count); |
| for (uint i = 0; i < arr->count && i < 3; i++) |
| { |
| Js::ParseableFunctionInfo *info = dumpFunction->GetNestedFunctionForExecution(arr->elements[i].nestedIndex); |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%s"), info->GetDisplayName()); |
| } |
| Output::Print(_u("]")); |
| break; |
| } |
| default: |
| AssertMsg(false, "Unknown OpCode for OpLayoutType::AuxNoReg"); |
| break; |
| } |
| } |
| |
| void |
| ByteCodeDumper::DumpAuxiliary(OpCode op, const unaligned OpLayoutAuxiliary * playout, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case OpCode::NewScObjectLiteral: |
| case OpCode::LdPropIds: |
| { |
| const Js::PropertyIdArray *propIds = reader.ReadPropertyIdArray(playout->Offset, dumpFunction); |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| DumpReg(playout->R0); |
| Output::Print(_u("= %d ["), propIds->count); |
| for (uint i=0; i< propIds->count && i < 3; i++) |
| { |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName(propIds->elements[i]); |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%s"), pPropertyName->GetBuffer()); |
| } |
| if (propIds->count >= 3) |
| { |
| Output::Print(_u(", ...")); |
| } |
| Output::Print(_u("], LiteralId %d"), playout->C1); |
| break; |
| } |
| case OpCode::StArrSegItem_A: |
| { |
| const Js::VarArray *vars = reader.ReadAuxArray<Var>(playout->Offset, dumpFunction); |
| DumpReg(playout->R0); |
| Output::Print(_u("= %d ["), vars->count); |
| uint i=0; |
| for (; i<vars->count && i < 3; i++) |
| { |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%d"), vars->elements[i]); |
| } |
| if (i != vars->count) |
| { |
| Output::Print(_u(", ...")); |
| } |
| Output::Print(_u("]")); |
| break; |
| } |
| case OpCode::NewScIntArray: |
| { |
| const Js::AuxArray<int32> *intArray = reader.ReadAuxArray<int32>(playout->Offset, dumpFunction); |
| Output::Print(_u(" R%d = %d ["), playout->R0, intArray->count); |
| uint i; |
| for (i = 0; i<intArray->count && i < 3; i++) |
| { |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%d"), intArray->elements[i]); |
| } |
| if (i != intArray->count) |
| { |
| Output::Print(_u(", ...")); |
| } |
| Output::Print(_u("]")); |
| break; |
| } |
| case OpCode::NewScFltArray: |
| { |
| const Js::AuxArray<double> *dblArray = reader.ReadAuxArray<double>(playout->Offset, dumpFunction); |
| Output::Print(_u(" R%d = %d ["), playout->R0, dblArray->count); |
| uint i; |
| for (i = 0; i<dblArray->count && i < 3; i++) |
| { |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%f"), dblArray->elements[i]); |
| } |
| if (i != dblArray->count) |
| { |
| Output::Print(_u(", ...")); |
| } |
| Output::Print(_u("]")); |
| break; |
| } |
| case OpCode::NewScObject_A: |
| { |
| const Js::VarArrayVarCount *vars = reader.ReadVarArrayVarCount(playout->Offset, dumpFunction); |
| DumpReg(playout->R0); |
| int count = Js::TaggedInt::ToInt32(vars->count); |
| Output::Print(_u("= %d ["), count); |
| int i=0; |
| for (; i<count && i < 3; i++) |
| { |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| if (TaggedInt::Is(vars->elements[i])) |
| { |
| Output::Print(_u("%d"), TaggedInt::ToInt32(vars->elements[i])); |
| } |
| else if (JavascriptNumber::Is(vars->elements[i])) |
| { |
| Output::Print(_u("%g"), JavascriptNumber::GetValue(vars->elements[i])); |
| } |
| else |
| { |
| Assert(false); |
| } |
| } |
| if (i != count) |
| { |
| Output::Print(_u(", ...")); |
| } |
| Output::Print(_u("]")); |
| break; |
| } |
| default: |
| AssertMsg(false, "Unknown OpCode for OpLayoutType::Auxiliary"); |
| break; |
| } |
| } |
| |
| void |
| ByteCodeDumper::DumpReg2Aux(OpCode op, const unaligned OpLayoutReg2Aux * playout, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| switch (op) |
| { |
| case Js::OpCode::SpreadArrayLiteral: |
| { |
| const Js::AuxArray<uint32> *arr = reader.ReadAuxArray<uint32>(playout->Offset, dumpFunction); |
| Output::Print(_u(" R%u <- R%u, %u spreadArgs ["), playout->R0, playout->R1, arr->count); |
| for (uint i = 0; i < arr->count; i++) |
| { |
| if (i > 10) |
| { |
| Output::Print(_u(", ...")); |
| break; |
| } |
| if (i != 0) |
| { |
| Output::Print(_u(", ")); |
| } |
| Output::Print(_u("%u"), arr->elements[i]); |
| } |
| Output::Print(_u("]")); |
| break; |
| } |
| default: |
| AssertMsg(false, "Unknown OpCode for OpLayoutType::Reg2Aux"); |
| break; |
| } |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpClass(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpReg(data->Constructor); |
| if (data->Extends != Js::Constants::NoRegister) |
| { |
| Output::Print(_u("extends")); |
| DumpReg((RegSlot)data->Extends); |
| } |
| } |
| |
| #ifdef BYTECODE_BRANCH_ISLAND |
| void ByteCodeDumper::DumpBrLong(OpCode op, const unaligned OpLayoutBrLong* data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpOffset(data->RelativeJumpOffset, reader); |
| } |
| #endif |
| |
| void ByteCodeDumper::DumpBr(OpCode op, const unaligned OpLayoutBr * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpOffset(data->RelativeJumpOffset, reader); |
| } |
| |
| void ByteCodeDumper::DumpBrS(OpCode op, const unaligned OpLayoutBrS * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpOffset(data->RelativeJumpOffset, reader); |
| DumpI4(data->val); |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpBrReg1(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpOffset(data->RelativeJumpOffset, reader); |
| DumpReg(data->R1); |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpBrReg1Unsigned1(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpOffset(data->RelativeJumpOffset, reader); |
| DumpReg(data->R1); |
| DumpU4(data->C2); |
| } |
| |
| template <class T> |
| void ByteCodeDumper::DumpBrReg2(OpCode op, const unaligned T * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpOffset(data->RelativeJumpOffset, reader); |
| DumpReg(data->R1); |
| DumpReg(data->R2); |
| } |
| |
| void ByteCodeDumper::DumpBrProperty(OpCode op, const unaligned OpLayoutBrProperty * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpOffset(data->RelativeJumpOffset, reader); |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| Output::Print(_u("R%d.%s"), data->Instance, pPropertyName->GetBuffer()); |
| } |
| |
| void ByteCodeDumper::DumpBrLocalProperty(OpCode op, const unaligned OpLayoutBrLocalProperty * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpOffset(data->RelativeJumpOffset, reader); |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| Output::Print(_u("%s"), pPropertyName->GetBuffer()); |
| } |
| |
| void ByteCodeDumper::DumpBrEnvProperty(OpCode op, const unaligned OpLayoutBrEnvProperty * data, FunctionBody * dumpFunction, ByteCodeReader& reader) |
| { |
| DumpOffset(data->RelativeJumpOffset, reader); |
| ScriptContext* scriptContext = dumpFunction->GetScriptContext(); |
| PropertyRecord const * pPropertyName = scriptContext->GetPropertyName( |
| dumpFunction->GetReferencedPropertyId(data->PropertyIdIndex)); |
| Output::Print(_u("[%d].%s"), data->SlotIndex, pPropertyName->GetBuffer()); |
| } |
| |
| void ByteCodeDumper::DumpOp(OpCode op, LayoutSize layoutSize, ByteCodeReader& reader, FunctionBody* dumpFunction) |
| { |
| Output::Print(_u("%-20s"), OpCodeUtil::GetOpCodeName(op)); |
| OpLayoutType nType = OpCodeUtil::GetOpCodeLayout(op); |
| switch (layoutSize * OpLayoutType::Count + nType) |
| { |
| #define LAYOUT_TYPE(layout) \ |
| case OpLayoutType::layout: \ |
| Assert(layoutSize == SmallLayout); \ |
| Dump##layout(op, reader.layout(), dumpFunction, reader); \ |
| break; |
| |
| #define LAYOUT_SCHEMA(type, layout) \ |
| case type##Layout * OpLayoutType::Count + OpLayoutType::layout: \ |
| Dump##layout(op, reader.layout##_##type(), dumpFunction, reader); \ |
| break |
| |
| #define LAYOUT_TYPE_WMS(layout) \ |
| LAYOUT_SCHEMA(Small, layout); \ |
| LAYOUT_SCHEMA(Medium, layout); \ |
| LAYOUT_SCHEMA(Large, layout); |
| |
| #define LAYOUT_TYPE_PROFILED_WMS(layout) \ |
| LAYOUT_TYPE_WMS(Profiled##layout) \ |
| LAYOUT_TYPE_WMS(layout) |
| |
| #include "LayoutTypes.h" |
| |
| default: |
| { |
| AssertMsg(false, "Unknown OpLayout"); |
| break; |
| } |
| } |
| } |
| } // namespace Js |
| #endif |