| 1 | /* |
| 2 | * This Source Code Form is subject to the terms of the Mozilla Public |
| 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| 5 | * |
| 6 | * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V. |
| 7 | */ |
| 8 | |
| 9 | #include "monetdb_config.h" |
| 10 | #include "opt_garbageCollector.h" |
| 11 | #include "mal_interpreter.h" |
| 12 | #include "mal_builder.h" |
| 13 | #include "mal_function.h" |
| 14 | #include "opt_prelude.h" |
| 15 | |
| 16 | /* The garbage collector is focused on removing temporary BATs only. |
| 17 | * Leaving some garbage on the stack is an issue. |
| 18 | * |
| 19 | * The end-of-life of a BAT may lay within block bracket. This calls |
| 20 | * for care, as the block may trigger a loop and then the BATs should |
| 21 | * still be there. |
| 22 | * |
| 23 | * The life time of such BATs is forcefully terminated after the block exit. |
| 24 | */ |
| 25 | str |
| 26 | OPTgarbageCollectorImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
| 27 | { |
| 28 | int i, limit; |
| 29 | InstrPtr p; |
| 30 | int actions = 0; |
| 31 | char buf[256]; |
| 32 | lng usec = GDKusec(); |
| 33 | str msg = MAL_SUCCEED; |
| 34 | char *used; |
| 35 | |
| 36 | (void) pci; |
| 37 | (void) stk; |
| 38 | if ( mb->inlineProp) |
| 39 | return 0; |
| 40 | |
| 41 | used = (char*) GDKzalloc(sizeof(char) * mb->vtop); |
| 42 | if ( used == NULL) |
| 43 | throw(MAL, "optimizer.garbagecollector" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
| 44 | |
| 45 | limit = mb->stop; |
| 46 | |
| 47 | /* variables get their name from the position */ |
| 48 | /* rename all temporaries used for ease of variable table interpretation */ |
| 49 | /* this code should not be necessary is variables always keep their position */ |
| 50 | for( i = 0; i < mb->vtop; i++){ |
| 51 | //strcpy(buf, getVarName(mb,i)); |
| 52 | if (getVarName(mb,i)[0] == 'X' && getVarName(mb,i)[1] == '_') |
| 53 | snprintf(getVarName(mb,i),IDLENGTH,"X_%d" ,i); |
| 54 | else |
| 55 | if (getVarName(mb,i)[0] == 'C' && getVarName(mb,i)[1] == '_') |
| 56 | snprintf(getVarName(mb,i),IDLENGTH,"C_%d" ,i); |
| 57 | //if(strcmp(buf, getVarName(mb,i)) ) |
| 58 | //fprintf(stderr, "non-matching name/entry %s %s\n", buf, getVarName(mb,i)); |
| 59 | } |
| 60 | |
| 61 | // move SQL query definition to the front for event profiling tools |
| 62 | p = NULL; |
| 63 | for(i = 0; i < limit; i++) |
| 64 | if(mb->stmt[i] && getModuleId(mb->stmt[i]) == querylogRef && getFunctionId(mb->stmt[i]) == defineRef ){ |
| 65 | p = getInstrPtr(mb,i); |
| 66 | break; |
| 67 | } |
| 68 | |
| 69 | if( p != NULL){ |
| 70 | for( ; i > 1; i--) |
| 71 | mb->stmt[i] = mb->stmt[i-1]; |
| 72 | mb->stmt[1] = p; |
| 73 | actions =1; |
| 74 | } |
| 75 | |
| 76 | // Actual garbage collection stuff, just mark them for re-assessment |
| 77 | p = NULL; |
| 78 | for (i = 0; i < limit; i++) { |
| 79 | p = getInstrPtr(mb, i); |
| 80 | p->gc &= ~GARBAGECONTROL; |
| 81 | p->typechk = TYPE_UNKNOWN; |
| 82 | /* Set the program counter to ease profiling */ |
| 83 | p->pc = i; |
| 84 | if ( p->token == ENDsymbol) |
| 85 | break; |
| 86 | } |
| 87 | /* A good MAL plan should end with an END instruction */ |
| 88 | if( p && p->token != ENDsymbol){ |
| 89 | throw(MAL, "optimizer.garbagecollector" , SQLSTATE(42000) "Incorrect MAL plan encountered" ); |
| 90 | } |
| 91 | getInstrPtr(mb,0)->gc |= GARBAGECONTROL; |
| 92 | GDKfree(used); |
| 93 | if( OPTdebug & OPTgarbagecollector) |
| 94 | { int k; |
| 95 | fprintf(stderr, "#Garbage collected BAT variables \n" ); |
| 96 | for ( k =0; k < mb->vtop; k++) |
| 97 | fprintf(stderr,"%10s eolife %3d begin %3d lastupd %3d end %3d\n" , |
| 98 | getVarName(mb,k), getVarEolife(mb,k), |
| 99 | getBeginScope(mb,k), getLastUpdate(mb,k), getEndScope(mb,k)); |
| 100 | chkFlow(mb); |
| 101 | if ( mb->errors != MAL_SUCCEED ){ |
| 102 | fprintf(stderr,"%s\n" ,mb->errors); |
| 103 | freeException(mb->errors); |
| 104 | mb->errors = MAL_SUCCEED; |
| 105 | } |
| 106 | fprintFunction(stderr,mb, 0, LIST_MAL_ALL); |
| 107 | fprintf(stderr, "End of GCoptimizer\n" ); |
| 108 | } |
| 109 | |
| 110 | /* leave a consistent scope admin behind */ |
| 111 | setVariableScope(mb); |
| 112 | /* Defense line against incorrect plans */ |
| 113 | if( actions > 0){ |
| 114 | chkTypes(cntxt->usermodule, mb, FALSE); |
| 115 | chkFlow(mb); |
| 116 | chkDeclarations(mb); |
| 117 | } |
| 118 | |
| 119 | /* keep all actions taken as a post block comment */ |
| 120 | usec = GDKusec()- usec; |
| 121 | snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec" ,"garbagecollector" ,actions, usec); |
| 122 | newComment(mb,buf); |
| 123 | if( actions >= 0) |
| 124 | addtoMalBlkHistory(mb); |
| 125 | |
| 126 | if( OPTdebug & OPTgarbagecollector){ |
| 127 | fprintf(stderr, "#GARBAGECOLLECTOR optimizer exit\n" ); |
| 128 | fprintFunction(stderr, mb, 0, LIST_MAL_ALL); |
| 129 | } |
| 130 | return msg; |
| 131 | } |
| 132 | |
| 133 | |