blob: ae44dddcd52dc1cf77ccd6fc13199025ee128199 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
// Turn this on to enable magic constants in byte code (useful for debugging)
//#define BYTE_CODE_MAGIC_CONSTANTS
#include "ByteCode/ByteCodeSerializeFlags.h"
namespace Js
{
// Some things are obscured by xor. This helps catch cases in which, for example, indirect property ids
// are mistakenly mixed with actual property IDs.
#if DBG & VALIDATE_SERIALIZED_BYTECODE
#define SERIALIZER_OBSCURE_PROPERTY_ID 0xdef00000
#define SERIALIZER_OBSCURE_NONBUILTIN_PROPERTY_ID 0xdeb00000
#define SERIALIZER_OBSCURE_LITERAL_OBJECT_ID 0xded00000
#else
#define SERIALIZER_OBSCURE_PROPERTY_ID 0x00000000
#define SERIALIZER_OBSCURE_NONBUILTIN_PROPERTY_ID 0x00000000
#define SERIALIZER_OBSCURE_LITERAL_OBJECT_ID 0x00000000
#endif
class ByteCodeBufferReader;
enum SerializedAuxiliaryKind : byte
{
sakVarArrayIntCount = 1,
sakVarArrayVarCount = 2,
sakPropertyIdArray = 3,
sakFuncInfoArray = 4,
sakIntArray = 5,
sakFloatArray = 6
};
// Tightly pack serialized structures
#pragma pack(push, 1)
// Describes the kind of auxiliary
struct SerializedAuxiliary
{
#ifdef BYTE_CODE_MAGIC_CONSTANTS
int auxMagic; // magicStartOfAux
#endif
uint offset;
SerializedAuxiliaryKind kind;
SerializedAuxiliary(uint offset, SerializedAuxiliaryKind kind);
};
// The in-memory layout of the serialized analog of VarArray
struct SerializedVarArray : SerializedAuxiliary
{
#ifdef BYTE_CODE_MAGIC_CONSTANTS
int magic; // magicStartOfAuxVarArray
#endif
int varCount;
SerializedVarArray(uint offset, bool isVarCount, int varCount);
};
struct SerializedIntArray : SerializedAuxiliary
{
#ifdef BYTE_CODE_MAGIC_CONSTANTS
int magic; // magicStartOfAuxIntArray
#endif
int intCount;
SerializedIntArray(uint offset, int intCount);
};
struct SerializedFloatArray : SerializedAuxiliary
{
#ifdef BYTE_CODE_MAGIC_CONSTANTS
int magic; // magicStartOfAuxFltArray
#endif
int floatCount;
SerializedFloatArray(uint offset, int floatCount);
};
// The in-memory layout of the serialized analog of PropertyIdArray
struct SerializedPropertyIdArray : SerializedAuxiliary
{
#ifdef BYTE_CODE_MAGIC_CONSTANTS
int magic; // magicStartOfAuxPropIdArray
#endif
int propertyCount;
int extraSlots;
bool hadDuplicates;
bool has__proto__;
SerializedPropertyIdArray(uint offset, int propertyCount, int extraSlots, bool hadDuplicates, bool has__proto__);
};
// The in-memory layout of the serialized analog of FuncInfoArray
struct SerializedFuncInfoArray : SerializedAuxiliary
{
#ifdef BYTE_CODE_MAGIC_CONSTANTS
int magic; // magicStartOfAuxFuncInfoArray
#endif
int count;
SerializedFuncInfoArray(uint offset, int count);
};
#pragma pack(pop)
// Holds information about the deserialized bytecode cache. Contains fast inline functions
// for the lookup hit case. The slower deserialization of VarArray, etc are in the .cpp.
class ByteCodeCache
{
ByteCodeBufferReader * reader;
const byte * raw;
PropertyId * propertyIds;
int propertyCount;
int builtInPropertyCount;
public:
ByteCodeCache(ScriptContext * scriptContext, ByteCodeBufferReader * reader, int builtInPropertyCount);
void PopulateLookupPropertyId(ScriptContext * scriptContext, int realArrayOffset);
ByteCodeBufferReader* GetReader()
{
return reader;
}
// Convert a serialized propertyID into a real one.
inline PropertyId LookupPropertyId(PropertyId obscuredIdInCache) const
{
auto unobscured = obscuredIdInCache ^ SERIALIZER_OBSCURE_PROPERTY_ID;
if (unobscured < builtInPropertyCount || unobscured==/*nil*/0xffffffff)
{
return unobscured; // This is a built in property id
}
auto realOffset = unobscured - builtInPropertyCount;
Assert(realOffset<propertyCount);
Assert(propertyIds[realOffset]!=-1);
return propertyIds[realOffset];
}
// Convert a serialized propertyID into a real one.
inline PropertyId LookupNonBuiltinPropertyId(PropertyId obscuredIdInCache) const
{
auto realOffset = obscuredIdInCache ^ SERIALIZER_OBSCURE_NONBUILTIN_PROPERTY_ID;
Assert(realOffset<propertyCount);
Assert(propertyIds[realOffset]!=-1);
return propertyIds[realOffset];
}
// Get the raw byte code buffer.
inline const byte * GetBuffer() const
{
return raw;
}
};
// Methods for serializing and deserializing function bodies.
struct ByteCodeSerializer
{
// Serialize a function body.
static HRESULT SerializeToBuffer(ScriptContext * scriptContext, ArenaAllocator * alloc, DWORD sourceCodeLength, LPCUTF8 utf8Source, FunctionBody * function, SRCINFO const* srcInfo, bool allocateBuffer, byte ** buffer, DWORD * bufferBytes, DWORD dwFlags = 0);
// Deserialize a function body. The content of utf8Source must be the same as was originally passed to SerializeToBuffer
static HRESULT DeserializeFromBuffer(ScriptContext * scriptContext, uint32 scriptFlags, LPCUTF8 utf8Source, SRCINFO const * srcInfo, byte * buffer, NativeModule *nativeModule, FunctionBody** function, uint sourceIndex = Js::Constants::InvalidSourceIndex);
static HRESULT DeserializeFromBuffer(ScriptContext * scriptContext, uint32 scriptFlags, ISourceHolder* sourceHolder, SRCINFO const * srcInfo, byte * buffer, NativeModule *nativeModule, FunctionBody** function, uint sourceIndex = Js::Constants::InvalidSourceIndex);
static FunctionBody* DeserializeFunction(ScriptContext* scriptContext, DeferDeserializeFunctionInfo* deferredFunction);
// This lib doesn't directly depend on the generated interfaces. Ensure the same codes with a C_ASSERT
static const HRESULT CantGenerate = 0x80020201L;
static const HRESULT InvalidByteCode = 0x80020202L;
static void ReadSourceInfo(const DeferDeserializeFunctionInfo* deferredFunction, int& lineNumber, int& columnNumber, bool& m_isEval, bool& m_isDynamicFunction);
private:
static HRESULT DeserializeFromBufferInternal(ScriptContext * scriptContext, uint32 scriptFlags, LPCUTF8 utf8Source, ISourceHolder* sourceHolder, SRCINFO const * srcInfo, byte * buffer, NativeModule *nativeModule, FunctionBody** function, uint sourceIndex = Js::Constants::InvalidSourceIndex);
};
}