summaryrefslogtreecommitdiffstats
path: root/vm/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'vm/compiler')
-rw-r--r--vm/compiler/Compiler.c14
-rw-r--r--vm/compiler/Compiler.h5
-rw-r--r--vm/compiler/CompilerIR.h3
-rw-r--r--vm/compiler/Frontend.c11
-rw-r--r--vm/compiler/IntermediateRep.c3
-rw-r--r--vm/compiler/Loop.c6
-rw-r--r--vm/compiler/Utility.c18
-rw-r--r--vm/compiler/codegen/arm/Assemble.c6
-rw-r--r--vm/compiler/codegen/arm/CodegenCommon.c3
-rw-r--r--vm/compiler/codegen/arm/CodegenDriver.c26
-rw-r--r--vm/compiler/codegen/arm/RallocUtil.c12
-rw-r--r--vm/compiler/codegen/arm/Thumb/Factory.c30
-rw-r--r--vm/compiler/codegen/arm/Thumb2/Factory.c2
-rw-r--r--vm/compiler/codegen/arm/Thumb2/Gen.c4
14 files changed, 89 insertions, 54 deletions
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index 13749ac50..597fbb246 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -479,11 +479,17 @@ static void *compilerThreadStart(void *arg)
if (gDvmJit.haltCompilerThread) {
LOGD("Compiler shutdown in progress - discarding request");
} else if (!gDvmJit.codeCacheFull) {
- /* If compilation failed, use interpret-template */
- if (!dvmCompilerDoWork(&work)) {
- work.result.codeAddress = gDvmJit.interpretTemplate;
+ bool compileOK = false;
+ jmp_buf jmpBuf;
+ work.bailPtr = &jmpBuf;
+ bool aborted = setjmp(jmpBuf);
+ if (!aborted) {
+ compileOK = dvmCompilerDoWork(&work);
}
- if (!work.result.discardResult) {
+ if (aborted || !compileOK) {
+ dvmCompilerArenaReset();
+ work.result.codeAddress = gDvmJit.interpretTemplate;
+ } else if (!work.result.discardResult) {
dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
work.result.instructionSet);
}
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index de3068697..f264c5b16 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -15,6 +15,7 @@
*/
#include <Thread.h>
+#include <setjmp.h>
#ifndef _DALVIK_VM_COMPILER
#define _DALVIK_VM_COMPILER
@@ -56,6 +57,7 @@ typedef struct CompilerWorkOrder {
WorkOrderKind kind;
void* info;
JitTranslationInfo result;
+ jmp_buf *bailPtr;
} CompilerWorkOrder;
/* Chain cell for predicted method invocation */
@@ -152,7 +154,7 @@ bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info);
void *dvmCheckCodeCache(void *method);
bool dvmCompileMethod(const Method *method, JitTranslationInfo *info);
bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts,
- JitTranslationInfo *info);
+ JitTranslationInfo *info, jmp_buf *bailPtr);
void dvmCompilerDumpStats(void);
void dvmCompilerDrainQueue(void);
void dvmJitUnchainAll(void);
@@ -185,5 +187,4 @@ void dvmCompilerDataFlowAnalysisDispatcher(struct CompilationUnit *cUnit,
void dvmCompilerStateRefresh(void);
JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
const struct JitEntry *desc);
-
#endif /* _DALVIK_VM_COMPILER */
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 00892faaf..00a45f920 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -157,6 +157,7 @@ typedef struct CompilationUnit {
LIR *chainingCellBottom;
struct RegisterPool *regPool;
int optRound; // round number to tell an LIR's age
+ jmp_buf *bailPtr;
JitInstructionSetType instructionSet;
/* Number of total regs used in the whole cUnit after SSA transformation */
int numSSARegs;
@@ -195,6 +196,8 @@ void dvmCompilerInsertLIRBefore(LIR *currentLIR, LIR *newLIR);
void dvmCompilerInsertLIRAfter(LIR *currentLIR, LIR *newLIR);
+void dvmCompilerAbort(CompilationUnit *cUnit);
+
/* Debug Utilities */
void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit);
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index 0c8a8df0e..d97001ff5 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -286,7 +286,7 @@ bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
* bytecode into machine code.
*/
bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
- JitTranslationInfo *info)
+ JitTranslationInfo *info, jmp_buf *bailPtr)
{
const DexCode *dexCode = dvmGetMethodCode(desc->method);
const JitTraceRun* currRun = &desc->trace[0];
@@ -316,6 +316,9 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
methodStats = analyzeMethodBody(desc->method);
#endif
+ /* Set the recover buffer pointer */
+ cUnit.bailPtr = bailPtr;
+
/* Initialize the printMe flag */
cUnit.printMe = gDvmJit.printMe;
@@ -760,7 +763,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
/* Halve the instruction count and retry again */
} else {
- return dvmCompileTrace(desc, cUnit.numInsts / 2, info);
+ return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr);
}
}
@@ -896,7 +899,7 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
if (numBlocks != cUnit.numBlocks) {
LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
- dvmAbort();
+ dvmCompilerAbort(&cUnit);
}
/* Connect the basic blocks through the taken links */
@@ -930,7 +933,7 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
if (j == numBlocks && !isInvoke) {
LOGE("Target not found for insn %x: expect target %x\n",
curBB->lastMIRInsn->offset, target);
- dvmAbort();
+ dvmCompilerAbort(&cUnit);
}
}
}
diff --git a/vm/compiler/IntermediateRep.c b/vm/compiler/IntermediateRep.c
index 018d8907a..b3e64907b 100644
--- a/vm/compiler/IntermediateRep.c
+++ b/vm/compiler/IntermediateRep.c
@@ -81,8 +81,7 @@ void dvmCompilerAppendLIR(CompilationUnit *cUnit, LIR *lir)
*/
void dvmCompilerInsertLIRBefore(LIR *currentLIR, LIR *newLIR)
{
- if (currentLIR->prev == NULL)
- dvmAbort();
+ assert(currentLIR->prev != NULL);
LIR *prevLIR = currentLIR->prev;
prevLIR->next = newLIR;
diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c
index e996ca2ee..ef76c508f 100644
--- a/vm/compiler/Loop.c
+++ b/vm/compiler/Loop.c
@@ -314,7 +314,8 @@ static bool doLoopBodyCodeMotion(CompilationUnit *cUnit)
break;
default:
refIdx = 0;
- dvmAbort();
+ LOGE("Jit: bad case in doLoopBodyCodeMotion");
+ dvmCompilerAbort(cUnit);
}
int useIdx = refIdx + 1;
@@ -449,7 +450,8 @@ static void genHoistedChecks(CompilationUnit *cUnit)
dvmCompilerAppendMIR(entry, boundCheckMIR);
}
} else {
- dvmAbort();
+ LOGE("Jit: bad case in genHoistedChecks");
+ dvmCompilerAbort(cUnit);
}
}
diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c
index 26bb3d082..83caab745 100644
--- a/vm/compiler/Utility.c
+++ b/vm/compiler/Utility.c
@@ -66,11 +66,7 @@ retry:
* could go above the limit we need to enhance the allocation
* mechanism.
*/
- if (size > ARENA_DEFAULT_SIZE) {
- LOGE("Requesting %d bytes which exceed the maximal size allowed\n",
- size);
- dvmAbort();
- }
+ assert(size <= ARENA_DEFAULT_SIZE);
/* Time to allocate a new arena */
ArenaMemBlock *newArena = (ArenaMemBlock *)
malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
@@ -281,3 +277,15 @@ void dvmDebugBitVector(char *msg, const BitVector *bv, int length)
}
}
}
+
+void dvmCompilerAbort(CompilationUnit *cUnit)
+{
+ LOGE("Jit: aborting trace compilation, reverting to interpreter");
+ /* Force a traceback in debug builds */
+ assert(0);
+ /*
+ * Abort translation and force to interpret-only for this trace
+ * Matching setjmp in compiler thread work loop in Compiler.c.
+ */
+ longjmp(*cUnit->bailPtr, 1);
+}
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 28dafe710..0d7895f23 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -934,7 +934,7 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
int delta = target - pc;
if (delta & 0x3) {
LOGE("PC-rel distance is not multiples of 4: %d\n", delta);
- dvmAbort();
+ dvmCompilerAbort(cUnit);
}
if ((lir->opCode == kThumb2LdrPcRel12) && (delta > 4091)) {
return true;
@@ -978,7 +978,7 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
int delta = target - pc;
if (delta > 2046 || delta < -2048) {
LOGE("Unconditional branch distance out of range: %d\n", delta);
- dvmAbort();
+ dvmCompilerAbort(cUnit);
}
lir->operands[0] = delta >> 1;
} else if (lir->opCode == kThumbBlx1) {
@@ -1626,7 +1626,7 @@ u4* dvmJitUnchain(void* codeAddr)
default:
targetOffset = 0; // make gcc happy
LOGE("Unexpected chaining type: %d", i);
- dvmAbort();
+ dvmAbort(); // dvmAbort OK here - can't safely recover
}
COMPILER_TRACE_CHAINING(
LOGD("Jit Runtime: unchaining 0x%x", (int)pChainCells));
diff --git a/vm/compiler/codegen/arm/CodegenCommon.c b/vm/compiler/codegen/arm/CodegenCommon.c
index 6d2ddcd40..8f5c11da4 100644
--- a/vm/compiler/codegen/arm/CodegenCommon.c
+++ b/vm/compiler/codegen/arm/CodegenCommon.c
@@ -60,7 +60,8 @@ static void setMemRefType(ArmLIR *lir, bool isLoad, int memType)
break;
default:
LOGE("Jit: invalid memref kind - %d", memType);
- dvmAbort();
+ assert(0); // Bail if debug build, set worst-case in the field
+ *maskPtr |= ENCODE_ALL;
}
}
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index 8502f4882..434dbbfa4 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -612,7 +612,7 @@ static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir,
}
default:
LOGE("Invalid long arith op");
- dvmAbort();
+ dvmCompilerAbort(cUnit);
}
if (!callOut) {
genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
@@ -716,7 +716,7 @@ static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir,
default:
LOGE("Invalid word arith op: 0x%x(%d)",
mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
- dvmAbort();
+ dvmCompilerAbort(cUnit);
}
if (!callOut) {
rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
@@ -1836,7 +1836,7 @@ static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
default:
cond = 0;
LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
- dvmAbort();
+ dvmCompilerAbort(cUnit);
}
genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
/* This mostly likely will be optimized away in a later phase */
@@ -2234,7 +2234,7 @@ static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
default:
cond = 0;
LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
- dvmAbort();
+ dvmCompilerAbort(cUnit);
}
genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
/* This mostly likely will be optimized away in a later phase */
@@ -3106,7 +3106,7 @@ static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
case INLINE_MATH_SIN:
break; /* Handle with C routine */
default:
- dvmAbort();
+ dvmCompilerAbort(cUnit);
}
dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
dvmCompilerClobberCallRegs(cUnit);
@@ -3723,7 +3723,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
mir->offset,
dalvikOpCode, getOpcodeName(dalvikOpCode),
dalvikFormat);
- dvmAbort();
+ dvmCompilerAbort(cUnit);
break;
}
}
@@ -3804,8 +3804,7 @@ gen_fallthrough:
#endif
default:
LOGE("Bad blocktype %d", blockList[blockId]->blockType);
- dvmAbort();
- break;
+ dvmCompilerAbort(cUnit);
}
}
}
@@ -3851,19 +3850,22 @@ bool dvmCompilerDoWork(CompilerWorkOrder *work)
break;
case kWorkOrderTrace:
/* Start compilation with maximally allowed trace length */
- res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
+ res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
+ work->bailPtr);
break;
case kWorkOrderTraceDebug: {
bool oldPrintMe = gDvmJit.printMe;
gDvmJit.printMe = true;
/* Start compilation with maximally allowed trace length */
- res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
+ res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
+ work->bailPtr);
gDvmJit.printMe = oldPrintMe;;
break;
}
default:
res = false;
- dvmAbort();
+ LOGE("Jit: unknown work order type");
+ assert(0); // Bail if debug build, discard oteherwise
}
return res;
}
@@ -3923,7 +3925,7 @@ bool dvmCompilerArchInit()
if (EncodingMap[i].opCode != i) {
LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
EncodingMap[i].name, i, EncodingMap[i].opCode);
- dvmAbort();
+ dvmAbort(); // OK to dvmAbort - build error
}
}
diff --git a/vm/compiler/codegen/arm/RallocUtil.c b/vm/compiler/codegen/arm/RallocUtil.c
index 131df2c7b..6d83e73e0 100644
--- a/vm/compiler/codegen/arm/RallocUtil.c
+++ b/vm/compiler/codegen/arm/RallocUtil.c
@@ -123,7 +123,7 @@ static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg)
}
}
LOGE("Tried to get info on a non-existant temp: r%d",reg);
- dvmAbort(); // FIXME: abort translation intead of vm
+ dvmCompilerAbort(cUnit);
return NULL;
}
@@ -249,7 +249,7 @@ static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
}
if (required) {
LOGE("No free temp registers");
- dvmAbort(); // FIXME: abort translation instead of vm
+ dvmCompilerAbort(cUnit);
}
return -1; // No register available
}
@@ -298,7 +298,7 @@ extern int dvmCompilerAllocTempDouble(CompilationUnit *cUnit)
next += 2;
}
LOGE("No free temp registers");
- dvmAbort(); // FIXME: abort translation instead of vm
+ dvmCompilerAbort(cUnit);
return -1;
}
@@ -359,7 +359,7 @@ static RegisterInfo *allocLive(CompilationUnit *cUnit, int sReg,
break;
default:
LOGE("Invalid register type");
- dvmAbort(); //FIXME: abort translation instead of vm
+ dvmCompilerAbort(cUnit);
}
return res;
}
@@ -386,7 +386,7 @@ extern void dvmCompilerFreeTemp(CompilationUnit *cUnit, int reg)
}
}
LOGE("Tried to free a non-existant temp: r%d",reg);
- dvmAbort(); // FIXME: abort translation instead of vm
+ dvmCompilerAbort(cUnit);
}
/*
@@ -460,7 +460,7 @@ extern void dvmCompilerLockTemp(CompilationUnit *cUnit, int reg)
}
}
LOGE("Tried to lock a non-existant temp: r%d",reg);
- dvmAbort(); // FIXME: abort translation instead of vm
+ dvmCompilerAbort(cUnit);
}
static void lockArgRegs(CompilationUnit *cUnit)
diff --git a/vm/compiler/codegen/arm/Thumb/Factory.c b/vm/compiler/codegen/arm/Thumb/Factory.c
index 0a4428043..ba6492293 100644
--- a/vm/compiler/codegen/arm/Thumb/Factory.c
+++ b/vm/compiler/codegen/arm/Thumb/Factory.c
@@ -124,7 +124,8 @@ static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
opCode = kThumbBUncond;
break;
default:
- dvmAbort(); // FIXME: abort trace instead of VM
+ LOGE("Jit: bad case in opNone");
+ dvmCompilerAbort(cUnit);
}
return newLIR0(cUnit, opCode);
}
@@ -145,7 +146,8 @@ static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
opCode = kThumbPop;
break;
default:
- dvmAbort(); // FIXME: abort trace instead of VM
+ LOGE("Jit: bad case in opCondBranch");
+ dvmCompilerAbort(cUnit);
}
return newLIR1(cUnit, opCode, value);
}
@@ -158,7 +160,8 @@ static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
opCode = kThumbBlxR;
break;
default:
- dvmAbort(); // FIXME: abort trace instead of VM
+ LOGE("Jit: bad case in opReg");
+ dvmCompilerAbort(cUnit);
}
return newLIR1(cUnit, opCode, rDestSrc);
}
@@ -203,7 +206,8 @@ static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
}
break;
default:
- dvmAbort(); // FIXME: abort trace instead of VM
+ LOGE("Jit: bad case in opRegImm");
+ dvmCompilerAbort(cUnit);
break;
}
if (shortForm)
@@ -323,7 +327,8 @@ static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
}
return res;
default:
- dvmAbort(); // FIXME - abort trace instead of VM
+ LOGE("Jit: bad case in opRegRegImm");
+ dvmCompilerAbort(cUnit);
break;
}
if (shortForm)
@@ -420,7 +425,8 @@ static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
opRegRegImm(cUnit, kOpLsr, rDestSrc1, rDestSrc1, 16);
return res;
default:
- dvmAbort(); // FIXME - abort trace instead of VM
+ LOGE("Jit: bad case in opRegReg");
+ dvmCompilerAbort(cUnit);
break;
}
return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
@@ -465,7 +471,8 @@ static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
opCode = kThumbLdrsbRRR;
break;
default:
- dvmAbort(); // FIXME: abort trace instead of VM
+ LOGE("Jit: bad case in loadBaseIndexed");
+ dvmCompilerAbort(cUnit);
}
res = newLIR3(cUnit, opCode, rDest, rBase, rNewIndex);
#if defined(WITH_SELF_VERIFICATION)
@@ -502,7 +509,8 @@ static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
opCode = kThumbStrbRRR;
break;
default:
- dvmAbort(); // FIXME - abort trace instead of VM
+ LOGE("Jit: bad case in storeBaseIndexed");
+ dvmCompilerAbort(cUnit);
}
res = newLIR3(cUnit, opCode, rSrc, rBase, rNewIndex);
#if defined(WITH_SELF_VERIFICATION)
@@ -619,7 +627,8 @@ static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
opCode = kThumbLdrsbRRR;
break;
default:
- dvmAbort(); // FIXME - abort trace instead of VM
+ LOGE("Jit: bad case in loadBaseIndexedBody");
+ dvmCompilerAbort(cUnit);
}
if (shortForm) {
load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
@@ -736,7 +745,8 @@ static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
}
break;
default:
- dvmAbort(); // FIXME - abort trace instead of VM
+ LOGE("Jit: bad case in storeBaseIndexedBody");
+ dvmCompilerAbort(cUnit);
}
if (shortForm) {
store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
diff --git a/vm/compiler/codegen/arm/Thumb2/Factory.c b/vm/compiler/codegen/arm/Thumb2/Factory.c
index c4d2c2824..eb361934c 100644
--- a/vm/compiler/codegen/arm/Thumb2/Factory.c
+++ b/vm/compiler/codegen/arm/Thumb2/Factory.c
@@ -163,7 +163,7 @@ static ArmLIR *loadConstantValue(CompilationUnit *cUnit, int rDest, int value)
return res;
}
/* No shortcut - go ahead and use literal pool */
- ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
+ ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
if (dataTarget == NULL) {
dataTarget = addWordData(cUnit, value, false);
}
diff --git a/vm/compiler/codegen/arm/Thumb2/Gen.c b/vm/compiler/codegen/arm/Thumb2/Gen.c
index b51cdd4bb..8a574b3ca 100644
--- a/vm/compiler/codegen/arm/Thumb2/Gen.c
+++ b/vm/compiler/codegen/arm/Thumb2/Gen.c
@@ -142,8 +142,8 @@ static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code,
case 0:
break;
default:
- assert(0);
- dvmAbort();
+ LOGE("Jit: bad case in genIT");
+ dvmCompilerAbort(cUnit);
}
mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
(1 << (3 - strlen(guide)));