MCPcopy Create free account
hub / github.com/AutoHotkey/AutoHotkey / ExpandArgs

Method ExpandArgs

source/script_expression.cpp:2036–2303  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

2034
2035
2036ResultType Line::ExpandArgs(ResultToken *aResultTokens)
2037// aResultTokens is non-null if the caller wants results that aren't strings. Caller is
2038// responsible for freeing the tokens either after successful use or before aborting, on failure.
2039// Returns OK, FAIL, or EARLY_EXIT. EARLY_EXIT occurs when a function-call inside an expression
2040// used the EXIT command to terminate the thread.
2041{
2042 // The counterpart of sArgDeref kept on our stack to protect it from recursion caused by
2043 // the calling of functions in the script:
2044 LPTSTR arg_deref[MAX_ARGS];
2045 int i;
2046
2047 // Make two passes through this line's arg list. This is done because the performance of
2048 // realloc() is worse than doing a free() and malloc() because the former often does a memcpy()
2049 // in addition to the latter's steps. In addition, realloc() as much as doubles the memory
2050 // load on the system during the brief time that both the old and the new blocks of memory exist.
2051 // First pass: determine how much space will be needed to do all the args and allocate
2052 // more memory if needed. Second pass: dereference the args into the buffer.
2053
2054 // First pass. It takes into account the same things as 2nd pass.
2055 size_t space_needed = GetExpandedArgSize();
2056 if (space_needed == VARSIZE_ERROR)
2057 return FAIL; // It will have already displayed the error.
2058
2059 // Only allocate the buf at the last possible moment, when it's sure the buffer will be used
2060 // (improves performance when only a short script with no derefs is being run):
2061 if (space_needed > sDerefBufSize)
2062 {
2063 // KNOWN LIMITATION: The memory utilization of *recursive* user-defined functions is rather high because
2064 // of the size of DEREF_BUF_EXPAND_INCREMENT, which is used to create a new deref buffer for each layer
2065 // of recursion. Due to limited stack space, the limit of recursion is about 300 to 800 layers depending
2066 // on the build. For 800 layers on Unicode, about 25MB (32KB*800) of memory would be temporarily allocated,
2067 // which in a worst-case scenario would cause swapping and kill performance. However, on most systems it
2068 // wouldn't be an issue, and the bigger problem is that recursion may be limited to ~300 layers.
2069 size_t increments_needed = space_needed / DEREF_BUF_EXPAND_INCREMENT;
2070 if (space_needed % DEREF_BUF_EXPAND_INCREMENT) // Need one more if above division truncated it.
2071 ++increments_needed;
2072 size_t new_buf_size = increments_needed * DEREF_BUF_EXPAND_INCREMENT;
2073 if (sDerefBuf)
2074 {
2075 // Do a free() and malloc(), which should be far more efficient than realloc(), especially if
2076 // there is a large amount of memory involved here (realloc's ability to do an in-place resize
2077 // might be unlikely for anything other than small blocks; see compiler's realloc.c):
2078 free(sDerefBuf);
2079 if (sDerefBufSize > LARGE_DEREF_BUF_SIZE)
2080 --sLargeDerefBufs;
2081 }
2082 if ( !(sDerefBuf = tmalloc(new_buf_size)) )
2083 {
2084 // Error msg was formerly: "Ran out of memory while attempting to dereference this line's parameters."
2085 sDerefBufSize = 0; // Reset so that it can make another attempt, possibly smaller, next time.
2086 return MemoryError();
2087 }
2088 sDerefBufSize = new_buf_size;
2089 if (sDerefBufSize > LARGE_DEREF_BUF_SIZE)
2090 ++sLargeDerefBufs;
2091 }
2092
2093 // Always init our_buf_marker even if zero iterations, because we want to enforce

Callers 1

ExecUntilMethod · 0.80

Calls 5

MemoryErrorFunction · 0.85
CopyValueFromMethod · 0.80
VarUnsetErrorMethod · 0.80
ContentsMethod · 0.45

Tested by

no test coverage detected