bool SkipRange()
{
    int savedObjPtr = g_pCompilerData->obj_ptr;
    bool savedStringPatchEnable = g_pCompilerData->str_patch_enable;
    g_pCompilerData->str_patch_enable = false;
    bool bRange;
    if (!CompileRange(bRange))
    {
        return false;
    }
    g_pCompilerData->str_patch_enable = savedStringPatchEnable;
    g_pCompilerData->obj_ptr = savedObjPtr;
    return true;
}
void CBasicBlock::Compile()
{
#ifndef AOT_USE_CACHE

	Framework::CMemStream stream;
	{
		static
#ifdef AOT_BUILD_CACHE
		    __declspec(thread)
#endif
		        CMipsJitter* jitter = nullptr;
		if(jitter == nullptr)
		{
			Jitter::CCodeGen* codeGen = Jitter::CreateCodeGen();
			jitter = new CMipsJitter(codeGen);

			for(unsigned int i = 0; i < 4; i++)
			{
				jitter->SetVariableAsConstant(
				    offsetof(CMIPS, m_State.nGPR[CMIPS::R0].nV[i]),
				    0);
			}
		}

		jitter->SetStream(&stream);
		jitter->Begin();
		CompileRange(jitter);
		//		codeGen.DumpVariables(0);
		//		codeGen.EndQuota();
		jitter->End();
	}

	m_function = CMemoryFunction(stream.GetBuffer(), stream.GetSize());

#ifdef VTUNE_ENABLED
	if(iJIT_IsProfilingActive() == iJIT_SAMPLING_ON)
	{
		iJIT_Method_Load jmethod = {};
		jmethod.method_id = iJIT_GetNewMethodID();
		jmethod.class_file_name = "";
		jmethod.source_file_name = __FILE__;

		jmethod.method_load_address = m_function.GetCode();
		jmethod.method_size = m_function.GetSize();
		jmethod.line_number_size = 0;

		auto functionName = string_format("BasicBlock_0x%08X_0x%08X", m_begin, m_end);

		jmethod.method_name = const_cast<char*>(functionName.c_str());
		iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, reinterpret_cast<void*>(&jmethod));
	}
#endif

#endif

#ifdef AOT_ENABLED

	size_t blockSize = ((m_end - m_begin) / 4) + 1;
	auto blockData = new uint32[blockSize];

	for(uint32 i = 0; i < blockSize; i++)
	{
		blockData[i] = m_context.m_pMemoryMap->GetWord(m_begin + (i * 4));
	}

	uint32 blockChecksum = crc32(0, reinterpret_cast<Bytef*>(blockData), blockSize * 4);

#endif

#ifdef AOT_USE_CACHE

	AOT_BLOCK* blocksBegin = &_aot_firstBlock;
	AOT_BLOCK* blocksEnd = blocksBegin + _aot_blockCount;

	AOT_BLOCK blockRef = {blockChecksum, m_begin, m_end, nullptr};

	static const auto blockComparer =
	    [](const AOT_BLOCK& item1, const AOT_BLOCK& item2) {
		    return item1.key < item2.key;
	    };

	//	assert(std::is_sorted(blocksBegin, blocksEnd, blockComparer));

	bool blockExists = std::binary_search(blocksBegin, blocksEnd, blockRef, blockComparer);
	auto blockIterator = std::lower_bound(blocksBegin, blocksEnd, blockRef, blockComparer);

	assert(blockExists);
	assert(blockIterator != blocksEnd);
	assert(blockIterator->key.crc == blockChecksum);
	assert(blockIterator->key.begin == m_begin);
	assert(blockIterator->key.end == m_end);

	m_function = reinterpret_cast<void (*)(void*)>(blockIterator->fct);

#endif

#ifdef AOT_BUILD_CACHE
	{
		std::lock_guard<std::mutex> lock(m_aotBlockOutputStreamMutex);

		m_aotBlockOutputStream->Write32(blockChecksum);
		m_aotBlockOutputStream->Write32(m_begin);
		m_aotBlockOutputStream->Write32(m_end);
		m_aotBlockOutputStream->Write(blockData, blockSize * 4);
	}
#endif
}
bool CompileCase(int column, int param)
{
    param = param; // stop warning

    if (!BlockStack_CompileConstant())
    {
        return false;
    }
    if (!CompileExpression())
    {
        return false;
    }
    if (!g_pElementizer->GetElement(type_end))
    {
        return false;
    }

    int savedSourcePtr = g_pElementizer->GetSourcePtr();
    int otherSourcePtr = 0;
    bool bOther = false;
    int caseCount = 0;

    bool bEof = false;
    while (!bEof)
    {
        if (!g_pElementizer->GetNext(bEof))
        {
            return false;
        }
        if (bEof)
        {
            break;
        }
        if (g_pElementizer->GetType() == type_end)
        {
            continue;
        }
        s_column = g_pElementizer->GetColumn();
        g_pElementizer->Backup();
        if (s_column <= column)
        {
            break;
        }

        if (bOther) // if we have OTHER: it should have been the last case, so we shouldn't get here again
        {
            g_pCompilerData->error = true;
            g_pCompilerData->error_msg = g_pErrorStrings[error_omblc];
            return false;
        }

        if (g_pElementizer->GetType() == type_other)
        {
            bOther = true;
            if (!g_pElementizer->GetNext(bEof)) // get/skip 'other'
            {
                return false;
            }
            otherSourcePtr = g_pCompilerData->source_start; // save the pointer to the beginning of 'other'
        }
        else
        {
            caseCount++;
            if (caseCount > case_limit)
            {
                g_pCompilerData->error = true;
                g_pCompilerData->error_msg = g_pErrorStrings[error_loxce];
                return false;
            }
            while (1)
            {
                bool bRange = false;
                if (!CompileRange(bRange))
                {
                    return false;
                }
                if (!EnterObj(bRange ? 0x0E : 0x0D)) // enter bytecode for case range or case value into obj
                {
                    return false;
                }
                if (!BlockStack_CompileAddress(caseCount))
                {
                    return false;
                }
                if (!g_pElementizer->CheckElement(type_comma))
                {
                    break;
                }
            }
        }
        if (!g_pElementizer->GetElement(type_colon))
        {
            return false;
        }
        if (!SkipBlock(s_column))
        {
            return false;
        }
    }

    if (caseCount == 0)
    {
        g_pCompilerData->error = true;
        g_pCompilerData->error_msg = g_pErrorStrings[error_nce];
        return false;
    }

    if (bOther)
    {
        // set the source pointer to where the OTHER is at, then get it to set the column
        g_pElementizer->SetSourcePtr(otherSourcePtr);
        if (!g_pElementizer->GetNext(bEof))
        {
            return false;
        }
        int new_column = g_pElementizer->GetColumn();
        // skip the colon
        if (!g_pElementizer->GetNext(bEof))
        {
            return false;
        }
        if (!CompileBlock(new_column))
        {
            return false;
        }
    }
    if (!EnterObj(0x0C)) // casedone, end of range checks
    {
        return false;
    }
    g_pElementizer->SetSourcePtr(savedSourcePtr);
    caseCount = 0;
    bOther = false;
    bEof = false;

    while(!bEof)
    {
        if (!g_pElementizer->GetNext(bEof))
        {
            return false;
        }
        if (bEof)
        {
            break;
        }
        if (g_pElementizer->GetType() == type_end)
        {
            continue;
        }
        s_column = g_pElementizer->GetColumn();
        g_pElementizer->Backup();
        if (s_column <= column)
        {
            break;
        }

        if (g_pElementizer->GetType() == type_other)
        {
            // skip over other, already compiled
            if (!g_pElementizer->GetNext(bEof))
            {
                return false;
            }
            if (!g_pElementizer->GetNext(bEof))
            {
                return false;
            }
            if (!SkipBlock(s_column))
            {
                return false;
            }
        }
        else
        {
            // skip over range/values(s), allready compiled
            while (1)
            {
                if (!SkipRange())
                {
                    return false;
                }
                if (!g_pElementizer->CheckElement(type_comma))
                {
                    break;
                }
            }
            caseCount++;
            BlockStack_Write(caseCount, g_pCompilerData->obj_ptr);
            if (!g_pElementizer->GetElement(type_colon))
            {
                return false;
            }
            if (!CompileBlock(s_column))
            {
                return false;
            }
            if (!EnterObj(0x0C))    // casedone
            {
                return false;
            }
        }
    }
    BlockStack_Write(0, g_pCompilerData->obj_ptr);
    return true;
}