Index: build/make/win.properties =================================================================== --- build/make/win.properties (revision 518952) +++ build/make/win.properties (working copy) @@ -90,7 +90,7 @@ # http.proxyPort= # Default building mode, either release or debug -BUILD_CFG=debug +BUILD_CFG=release # Default C compiler, either icl or msvc CXX=msvc Index: build/make/lnx.properties =================================================================== --- build/make/lnx.properties (revision 518952) +++ build/make/lnx.properties (working copy) @@ -91,7 +91,7 @@ # http.proxyPort= # Default building mode, either release or debug -BUILD_CFG=debug +BUILD_CFG=release # Default C compiler, either icc or gcc CXX=gcc Index: vm/jitrino/config/em64t/server.emconf =================================================================== --- vm/jitrino/config/em64t/server.emconf (revision 518952) +++ vm/jitrino/config/em64t/server.emconf (working copy) @@ -62,8 +62,8 @@ -XDjit.SD2_OPT.path=opt_init,translator,optimizer,hir2lir,codegen --XDjit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,inline,uce,purge,simplify,dce,uce,so2-,simplify,dce,uce,escape,hvn,dce,uce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,abcd,dce,uce,gcm,dessa,statprof,markglobals --XDjit.SD2_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-XDjit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,inline,uce,purge,simplify,dce,uce,so2-,simplify,dce,uce,hvn,dce,uce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,abcd,dce,uce,gcm,dessa,fastArrayFill,statprof,markglobals +-XDjit.SD2_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method -XDjit.SD2_OPT.path.dce1=cg_dce -XDjit.SD2_OPT.path.dce2=cg_dce -XDjit.SD2_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 Index: vm/jitrino/config/ia32/server.emconf =================================================================== --- vm/jitrino/config/ia32/server.emconf (revision 518952) +++ vm/jitrino/config/ia32/server.emconf (working copy) @@ -63,8 +63,8 @@ -XDjit.SD2_OPT.path=opt_init,translator,optimizer,hir2lir,codegen --XDjit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,inline,uce,purge,simplify,dce,uce,lazyexc,so2-,simplify,dce,uce,escape,inline_helpers,purge,simplify,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,abcd,dce,uce,gcm,dessa,statprof,markglobals --XDjit.SD2_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method +-XDjit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,inline,uce,purge,simplify,dce,uce,lazyexc,so2-,simplify,dce,uce,escape,inline_helpers,purge,simplify,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,abcd,dce,uce,gcm,dessa,fastArrayFill,statprof,markglobals +-XDjit.SD2_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,layout,copy,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method -XDjit.SD2_OPT.path.dce1=cg_dce -XDjit.SD2_OPT.path.dce2=cg_dce -XDjit.SD2_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 Index: vm/jitrino/src/codegenerator/ia32/Ia32EarlyPropagation.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32EarlyPropagation.cpp (revision 518952) +++ vm/jitrino/src/codegenerator/ia32/Ia32EarlyPropagation.cpp (working copy) @@ -131,12 +131,22 @@ opndInfo.sourceOpndId = EmptyUint32; } } + /* + Here is the previous version to test whether the inst is copy or not. bool isCopy = inst->getMnemonic() == Mnemonic_MOV ||( (inst->getMnemonic() == Mnemonic_ADD || inst->getMnemonic() == Mnemonic_SUB) && inst->getOpnd(3)->isPlacedIn(OpndKind_Imm) && inst->getOpnd(3)->getImmValue()==0 && inst->getOpnd(3)->getRuntimeInfo()==NULL ); + It considered special case of 'dst = src +/- 0' as copy. + In fact there are more similar cases like 'IMUL src, 1 ; shift src, 0' etc. + Such checks are obsolete now, Should as peephole takes care about such copies. + Anyway, the code above had a bug: 'inst->getOpnd(3)' crashes in instructions + in native form (like ADD def_use, use). + */ + const bool isCopy = inst->getMnemonic() == Mnemonic_MOV; + if (isCopy){ // CopyPseudoInst or mov Opnd * defOpnd = inst->getOpnd(0); Opnd * srcOpnd = inst->getOpnd(1); Index: vm/jitrino/src/codegenerator/ia32/Ia32FastArrayFilling.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32FastArrayFilling.cpp (revision 0) +++ vm/jitrino/src/codegenerator/ia32/Ia32FastArrayFilling.cpp (revision 0) @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Nikolay A. Sidelnikov + * @version $Revision: 1.6 $ + */ +#include "Ia32IRManager.h" + +namespace Jitrino +{ +namespace Ia32 { + +class FastArrayFilling: public SessionAction { + + void runImpl(); +}; + +static ActionFactory _faf("cg_fastArrayFill"); + +void +FastArrayFilling::runImpl() +{ + const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = nodes.rbegin(),end = nodes.rend();it!=end; ++it) { + Node* bb = *it; + if (!bb->isBlockNode()) { + continue; + } + if(bb->isEmpty()) { + continue; + } + + //find basic block with only instruction: internal helper fill_array_with_const + Inst * inst = (Inst*)bb->getLastInst(); + if (inst->getMnemonic() != Mnemonic_CALL) { + continue; + } + + Opnd::RuntimeInfo * rt = inst->getOpnd(((ControlTransferInst*)inst)->getTargetOpndIndex())->getRuntimeInfo(); + + if (!rt || rt->getKind() != Opnd::RuntimeInfo::Kind_InternalHelperAddress) { + continue; + } + + std::string str = std::string((const char*)rt->getValue(0)); + if (str != "fill_array_with_const") { + continue; + } + + //replace the internal helper with a sequence of instructions + inst->unlink(); + + ControlFlowGraph * fg = irManager->getFlowGraph(); + Edge * outEdge = bb->getOutEdges().front(); + Node * nextNode = outEdge->getTargetNode(); + + //extract operands from the internal helper instruction + Inst::Opnds opnds(inst, Inst::OpndRole_Use|Inst::OpndRole_Explicit|Inst::OpndRole_Auxilary); + Inst::Opnds::iterator ito = opnds.begin()+1; + +// Opnd* args[4] = {valueOp, arrayRef, arrayBound, baseOp}; + Opnd * value = inst->getOpnd(ito++); + Opnd * arrayRef = inst->getOpnd(ito++); + Opnd * arrayBound = inst->getOpnd(ito++); + Opnd * arrayBase = inst->getOpnd(ito++); + + //number of operands must be 5. First operand is the internal helper address + assert(ito == opnds.end()); + + //insert preparing instructions for filling loop + //LEA instruction loads address of the end of an array + + TypeManager& tm = irManager->getTypeManager(); + + Type * int32Type = tm.getInt32Type(); + Type * intPtrType = tm.getIntPtrType(); + Type * elemType = arrayRef->getType()->asArrayType()->getElementType(); + //memory operand should contains only operand with managed pointer type + Type * ptrToIntType = tm.getManagedPtrType(int32Type); + + Opnd * arrayEnd = irManager->newOpnd(intPtrType); + Opnd * scale = irManager->newImmOpnd(int32Type, getByteSize(irManager->getTypeSize(elemType))); + if (arrayEnd->getSize() > arrayBound->getSize()) { + bb->appendInst(irManager->newInst(Mnemonic_MOVZX, arrayEnd, arrayBound)); + } else { + bb->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, arrayEnd, arrayBound)); + } + bb->appendInst(irManager->newInst(Mnemonic_LEA, arrayEnd, irManager->newMemOpnd(arrayEnd->getType(), arrayBase, arrayEnd, scale))); + + //load an address of the first element + Opnd * index = irManager->newOpnd(ptrToIntType); + bb->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, index, arrayBase)); + + Node * loopNode = fg->createNode(Node::Kind_Block); + + //insert filling instructions + Opnd * memOp1 = irManager->newMemOpndAutoKind(value->getType(), index); + Opnd * memOp2 = irManager->newMemOpndAutoKind(value->getType(), index,irManager->newImmOpnd(int32Type,4)); + loopNode->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, memOp1, value)); + loopNode->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, memOp2, value)); + + //increment the element address + Opnd * incOp = irManager->newImmOpnd(intPtrType,8); + loopNode->appendInst(irManager->newInst(Mnemonic_ADD, index, incOp)); + + //compare the element address with the end of the array + loopNode->appendInst(irManager->newInst(Mnemonic_CMP, index, arrayEnd)); + + fg->replaceEdgeTarget(outEdge, loopNode); + + loopNode->appendInst(irManager->newBranchInst(Mnemonic_JL, loopNode, nextNode)); + fg->addEdge(loopNode, loopNode, 0.95); + fg->addEdge(loopNode, nextNode, 0.05); + } +} + +}} Index: vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (revision 518952) +++ vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (working copy) @@ -156,6 +156,10 @@ profileAccessInterface->value_profiler_add_value(mpHandle, index, value); } +void __stdcall fill_array_with_const(uint32 copyOp, uint32 arrayRef, uint32 arrayBound, uint32 baseOp) { + assert(0); + return; +} //_______________________________________________________________________________________________________________ uint32 InstCodeSelector::_tauUnsafe; @@ -177,6 +181,8 @@ irManager.registerInternalHelperInfo("initialize_array", IRManager::InternalHelperInfo((void*)&initialize_array,&CallingConvention_STDCALL)); irManager.registerInternalHelperInfo("add_value_profile_value", IRManager::InternalHelperInfo((void*)&add_value_profile_value,&CallingConvention_STDCALL)); + + irManager.registerInternalHelperInfo("fill_array_with_const", IRManager::InternalHelperInfo((void*)&fill_array_with_const,&CallingConvention_STDCALL)); } //_______________________________________________________________________________________________________________ @@ -2837,9 +2843,19 @@ appendInsts(irManager.newInternalRuntimeHelperCallInst("add_value_profile_value", nArgs, newArgs, dstOpnd)); break; } + case FillArrayWithConst: + { + assert(numArgs == 4); + Opnd * newArgs[4] = {(Opnd *)args[0], (Opnd *)args[1], (Opnd *)args[2], (Opnd *)args[3]}; + appendInsts(irManager.newInternalRuntimeHelperCallInst("fill_array_with_const", numArgs, newArgs, dstOpnd)); + break; + } default: + { assert(0); + break; } + } return dstOpnd; } Index: vm/jitrino/src/codegenerator/CodeGenIntfc.h =================================================================== --- vm/jitrino/src/codegenerator/CodeGenIntfc.h (revision 518952) +++ vm/jitrino/src/codegenerator/CodeGenIntfc.h (working copy) @@ -166,6 +166,7 @@ public: enum Id { InitializeArray, + FillArrayWithConst, PseudoCanThrow, SaveThisState, ReadThisState, Index: vm/jitrino/src/optimizer/FastArrayFilling.cpp =================================================================== --- vm/jitrino/src/optimizer/FastArrayFilling.cpp (revision 0) +++ vm/jitrino/src/optimizer/FastArrayFilling.cpp (revision 0) @@ -0,0 +1,269 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* @author Intel, Nikolay A. Sidelnikov +* @version $Revision: 1.20.8.1.4.4 $ +* +*/ + +#include "escapeanalyzer.h" +#include "Log.h" +#include "Inst.h" +#include "Dominator.h" +#include "globalopndanalyzer.h" +#include "optimizer.h" +#include "FlowGraph.h" +#include "LoopTree.h" + +#include + +namespace Jitrino { + + struct LoopEdges + { + Edge * outEdge; + Edge * inEdge; + Edge * backEdge; + + LoopEdges() : outEdge(NULL), inEdge(NULL), backEdge(NULL) {} ; + }; + +DEFINE_SESSION_ACTION(FastArrayFillPass, fastArrayFill, "Fast Array Filling") + +void +FastArrayFillPass::_run(IRManager& irManager) +{ + LoopTree * info = irManager.getLoopTree(); + if (!info->isValid()) { + info->rebuild(false); + } + if (!info->hasLoops()) { + return; + } + + MemoryManager tmm(1024,"FastArrayInitPass::insertFastArrayInit"); + Edges loopEdges(tmm); + StlMap loopInfo(tmm); + + const Nodes& nodes = irManager.getFlowGraph().getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (!info->isLoopHeader(node)) { + continue; + } + //compute number of nodes of the loop + Nodes loopNodes = info->getLoopNode(node,false)->getNodesInLoop(); + unsigned sz = loopNodes.size(); + if (sz!=3) { + continue; + } + + if (info->isBackEdge(node->getInEdges().front())) { + loopInfo[node].backEdge = node->getInEdges().front(); + loopInfo[node].inEdge = node->getInEdges().back(); + } else { + loopInfo[node].inEdge = node->getInEdges().front(); + loopInfo[node].backEdge = node->getInEdges().back(); + } + loopInfo[node].outEdge = info->isLoopExit(node->getOutEdges().front())? node->getOutEdges().front() : node->getOutEdges().back(); + } + + //check found loops for pattern + for(StlMap::const_iterator it = loopInfo.begin(); it != loopInfo.end(); ++it) { + + Edge * backEdge = it->second.backEdge; + Edge * inEdge = it->second.inEdge; + Edge * outEdge = it->second.outEdge; + + Node * startNode = backEdge->getSourceNode(); + Opnd * index = NULL; + Opnd * tmpIndex = NULL; + Opnd * constValue = NULL; + Opnd * address = NULL; + Opnd * arrayBase = NULL; + Opnd * arrayRef = NULL; + Opnd* inc = NULL; + Opnd * arrayBound = NULL; + Opnd * fillBound = NULL; + Opnd *startIndex; + Inst * inst = ((Inst *)startNode->getLastInst()); + bool found = false; + + //check StVar + if (inst->getOpcode() == Op_StVar) { + index = inst->getDst(); + inc = inst->getSrc(0); + inst = inst->getPrevInst(); + //check Add + if (inst->getOpcode() == Op_Add) { + Opnd* addOp = inst->getSrc(1); + tmpIndex = inst->getSrc(0); + //check Add operands + if (inst->getDst() == inc && + addOp->getInst()->getOpcode() == Op_LdConstant && + ((ConstInst *)addOp->getInst())->getValue().i4 == 1) + { + inst = inst->getPrevInst(); + //check StInd + if (inst->getOpcode() == Op_TauStInd) { + constValue = inst->getSrc(0); + address = inst->getSrc(1); + inst = inst->getPrevInst(); + //check AddIndex + if (inst->getOpcode() == Op_AddScaledIndex && inst->getDst() == address && + inst->getSrc(1) == tmpIndex) + { + arrayBase = inst->getSrc(0); + inst = inst->getPrevInst(); + //check Label aka beginning of BB + if (inst->getOpcode() == Op_Label) { + found = true; + } + } + } + } + } + } + if (!found) { + continue; + } + startNode = startNode->getInEdges().front()->getSourceNode(); + inst = ((Inst *)startNode->getLastInst()); + + //check CheckUpperBound + if (inst->getOpcode() == Op_TauCheckUpperBound && inst->getSrc(0) == tmpIndex && inst->getPrevInst()->getOpcode() == Op_Label) { + arrayBound = inst->getSrc(1); + } else { + continue; + } + + startNode = startNode->getInEdges().front()->getSourceNode(); + inst = ((Inst *)startNode->getLastInst()); + found = false; + //check Branch + if (inst->getOpcode() == Op_Branch && inst->getSrc(0) == tmpIndex) { + fillBound = inst->getSrc(1); + inst = inst->getPrevInst(); + //check LdVar and Label + if (inst->getOpcode() == Op_LdVar && inst->getSrc(0) == index && inst->getDst() == tmpIndex && inst->getPrevInst()->getOpcode() == Op_Label) { + found = true; + } + } + if (!found) { + continue; + } + + startNode = inEdge->getSourceNode(); + inst = ((Inst *)startNode->getLastInst()); + found = false; + + //check StVar + if (inst->getOpcode() == Op_StVar && inst->getDst() == index) { + startIndex = inst->getSrc(0); + inst = inst->getPrevInst(); + //check StInd + if (inst->getOpcode() == Op_TauStInd && inst->getSrc(0) == constValue && inst->getSrc(1) == arrayBase) { + inst = inst->getPrevInst(); + //check LdBase + if (inst->getOpcode() == Op_LdArrayBaseAddr && inst->getDst() == arrayBase && inst->getPrevInst()->getOpcode() == Op_Label) { + arrayRef = inst->getSrc(0); + found = true; + } + } + } + if (!found) { + continue; + } + + startNode = startNode->getInEdges().front()->getSourceNode(); + inst = ((Inst *)startNode->getLastInst()); + found = false; + + //check CheckUpperBound + ConstInst * cInst = (ConstInst *)inst->getSrc(0)->getInst(); + if (inst->getOpcode() == Op_TauCheckUpperBound && cInst && cInst->getValue().i4 == 0 ) { + inst = inst->getPrevInst(); + //check ArrayLength and Label + if (inst->getOpcode() == Op_TauArrayLen && inst->getSrc(0) == arrayRef && inst->getDst() == arrayBound && inst->getPrevInst()->getOpcode() == Op_Label) { + found = true; + } + } + if (!found) { + continue; + } + + //now we found our pattern + + inEdge = startNode->getInEdges().front(); + + //get a new constant + int val = ((ConstInst*)constValue->getInst())->getValue().i4; + switch (((Type*)arrayRef->getType()->asArrayType()->getElementType())->tag) { + case Type::Int8: + case Type::Boolean: + case Type::UInt8: + val |= (val << 8); + val |= (val << 16); + break; + case Type::Int16: + case Type::UInt16: + case Type::Char: + val |= (val << 16); + break; + case Type::Int32: + case Type::UInt32: + case Type::UIntPtr: + case Type::IntPtr: + break; + default: + continue; + break; + } + + ControlFlowGraph& fg = irManager.getFlowGraph(); + Node * preheader = fg.splitNodeAtInstruction(inst, true, false, irManager.getInstFactory().makeLabel()); + Inst * cmp = irManager.getInstFactory().makeBranch(Cmp_NE_Un, arrayBound->getType()->tag, arrayBound, fillBound, (LabelInst *)preheader->getFirstInst()); + startNode->appendInst(cmp); + + Node * prepNode = fg.createBlockNode(irManager.getInstFactory().makeLabel()); + fg.addEdge(startNode,prepNode); + + OpndManager& opndManager = irManager.getOpndManager(); + + Opnd * copyOp = opndManager.createArgOpnd(irManager.getTypeManager().getInt32Type()); + Inst * copyInst = irManager.getInstFactory().makeLdConst(copyOp,val); + prepNode->appendInst(copyInst); + + Opnd *baseOp = opndManager.createArgOpnd(irManager.getTypeManager().getIntPtrType()); + Inst * ldBaseInst = irManager.getInstFactory().makeLdArrayBaseAddr(arrayRef->getType()->asArrayType()->getElementType(),baseOp, arrayRef); + prepNode->appendInst(ldBaseInst); + + Opnd* args[4] = {copyOp, arrayRef, arrayBound, baseOp}; + + // add jit helper + Inst* initInst = irManager.getInstFactory().makeJitHelperCall( + OpndManager::getNullOpnd(), FillArrayWithConst, 4, args); + prepNode->appendInst(initInst); + + fg.addEdge(prepNode, outEdge->getTargetNode()); + + } +} +} + + Index: vm/jitrino/src/optimizer/Inst.cpp =================================================================== --- vm/jitrino/src/optimizer/Inst.cpp (revision 518952) +++ vm/jitrino/src/optimizer/Inst.cpp (working copy) @@ -468,6 +468,8 @@ os << "LockedCmpExchange"; break; case AddValueProfileValue: os << "AddValueProfileValue"; break; + case FillArrayWithConst: + os << "FillArrayWithConst"; break; default: assert(0); break; } Index: vm/jitrino/src/optimizer/CodeSelectors.cpp =================================================================== --- vm/jitrino/src/optimizer/CodeSelectors.cpp (revision 518952) +++ vm/jitrino/src/optimizer/CodeSelectors.cpp (working copy) @@ -409,6 +409,7 @@ case ReadThisState: return JitHelperCallOp::ReadThisState; case LockedCompareAndExchange: return JitHelperCallOp::LockedCompareAndExchange; case AddValueProfileValue: return JitHelperCallOp::AddValueProfileValue; + case FillArrayWithConst: return JitHelperCallOp::FillArrayWithConst; } assert(0); return JitHelperCallOp::InitializeArray; // to keep compiler quiet Index: vm/jitrino/src/optimizer/Opcode.h =================================================================== --- vm/jitrino/src/optimizer/Opcode.h (revision 518952) +++ vm/jitrino/src/optimizer/Opcode.h (working copy) @@ -271,6 +271,7 @@ enum JitHelperCallId { InitializeArray, + FillArrayWithConst, PseudoCanThrow, SaveThisState, //todo: replace with GetTLS + offset sequence ReadThisState, //todo: replace with GetTLS + offset sequence