Compare commits
109
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d59c187fe | ||
|
|
d8bed612b0 | ||
|
|
41da12e756 | ||
|
|
18fcba4c82 | ||
|
|
41462bf4fa | ||
|
|
4e13219dfb | ||
|
|
4d2add8f0f | ||
|
|
854eec9e0f | ||
|
|
849acd6e96 | ||
|
|
b5c0305e8b | ||
|
|
a8ee0b7831 | ||
|
|
a989f1616a | ||
|
|
af76b69dcd | ||
|
|
ab224ed8ee | ||
|
|
68dfdc609e | ||
|
|
10ccda4936 | ||
|
|
c718bb66ac | ||
|
|
5dad1c5205 | ||
|
|
270a615a09 | ||
|
|
4a21f51055 | ||
|
|
532b8988c1 | ||
|
|
b2423f72cf | ||
|
|
3903b017ec | ||
|
|
3c76eb88e8 | ||
|
|
544626ba84 | ||
|
|
b5f51d5007 | ||
|
|
a20873ddab | ||
|
|
68d7745b27 | ||
|
|
c8b0ad64d1 | ||
|
|
a097532afd | ||
|
|
7b43d03c2b | ||
|
|
fdf63d1e28 | ||
|
|
17f4b04d10 | ||
|
|
2a3000c25e | ||
|
|
546d781de9 | ||
|
|
e7d31b9449 | ||
|
|
d2b951b436 | ||
|
|
79f58ebfb3 | ||
|
|
2797b611e3 | ||
|
|
7da4d96216 | ||
|
|
15425ace0b | ||
|
|
7390940817 | ||
|
|
7484715183 | ||
|
|
bcc14fb740 | ||
|
|
90dba8327c | ||
|
|
db5a66dd2c | ||
|
|
82c027f092 | ||
|
|
e7da373e0c | ||
|
|
2a26edf602 | ||
|
|
c929650e2f | ||
|
|
b1a3a83b3d | ||
|
|
fb728f1f53 | ||
|
|
b3b9cb8d35 | ||
|
|
251b09c99a | ||
|
|
43cea24ef3 | ||
|
|
2debf51b24 | ||
|
|
f677af67e2 | ||
|
|
622cb44fa4 | ||
|
|
50c73b80d3 | ||
|
|
b24c54bed3 | ||
|
|
c74bb69040 | ||
|
|
4b5869de07 | ||
|
|
d421fc1bdf | ||
|
|
6c3b503dbd | ||
|
|
68afad0c67 | ||
|
|
7965559c05 | ||
|
|
18b0700dbe | ||
|
|
4ee4a959b9 | ||
|
|
0a18b6e286 | ||
|
|
5c0e6b295a | ||
|
|
45e4dfd471 | ||
|
|
89acc1c033 | ||
|
|
be69161b43 | ||
|
|
025d1997eb | ||
|
|
648841a413 | ||
|
|
276bcea418 | ||
|
|
1ac9419646 | ||
|
|
c0b55c5efd | ||
|
|
643a9ae4b0 | ||
|
|
6880761727 | ||
|
|
119cc47a41 | ||
|
|
72a0fab411 | ||
|
|
7f79d3446c | ||
|
|
c7e9f685b7 | ||
|
|
06cfc15d05 | ||
|
|
c52117cb0c | ||
|
|
143dd064c6 | ||
|
|
43d07e03c7 | ||
|
|
a425618034 | ||
|
|
b5f1bdb187 | ||
|
|
007c00ed28 | ||
|
|
13a2a82c81 | ||
|
|
b55a06a8a5 | ||
|
|
87d602d36b | ||
|
|
472c40ee51 | ||
|
|
06130c47bf | ||
|
|
bf048c0574 | ||
|
|
8654042602 | ||
|
|
11832ca791 | ||
|
|
e516af3ee3 | ||
|
|
27e4c0fd0a | ||
|
|
5f10b318a9 | ||
|
|
45f9ea1e07 | ||
|
|
9cebbfe5c2 | ||
|
|
15f3cf55c9 | ||
|
|
b12676f0d0 | ||
|
|
cac74426e8 | ||
|
|
41c4cbfb48 | ||
|
|
64e39b2d5a |
@@ -1,3 +1,87 @@
|
||||
2013-06-09 Donal K. Fellows <dkf@users.sf.net>
|
||||
|
||||
* generic/tclCompCmdsSZ.c (TclCompileTryCmd): [Bug 779d38b996]:
|
||||
Rewrote the [try] compiler to generate better code in some cases and
|
||||
to behave correctly in others; when an error happens during the
|
||||
processing of an exception-trap clause or a finally clause, the
|
||||
*original* return options are now captured in a -during option, even
|
||||
when fully compiled.
|
||||
|
||||
2013-06-05 Donal K. Fellows <dkf@users.sf.net>
|
||||
|
||||
* generic/tclExecute.c (INST_EXPAND_DROP): [Bugs 2835313, 3614226]:
|
||||
New opcode to allow resetting the stack to get rid of an expansion,
|
||||
restoring the stack to a known state in the process.
|
||||
* generic/tclCompile.c, generic/tclCompCmds.c: Adjusted the compilers
|
||||
for [break] and [continue] to get stack cleanup right in the majority
|
||||
of cases.
|
||||
* tests/for.test (for-7.*): Set of tests for these evil cases.
|
||||
|
||||
2013-06-04 Jan Nijtmans <nijtmans@users.sf.net>
|
||||
|
||||
* unix/tcl.m4: Eliminate NO_VIZ macro as current zlib uses HAVE_HIDDEN
|
||||
instead. One more last-moment fix for FreeBSD by Pietro Cerutti
|
||||
|
||||
2013-06-03 Miguel Sofer <msofer@users.sf.net>
|
||||
|
||||
* generic/tclExecute.c: fix for perf bug detected by Kieran
|
||||
(https://groups.google.com/forum/?fromgroups#!topic/comp.lang.tcl/vfpI3bc-DkQ),
|
||||
diagnosed by dgp to be a close relative of [Bug 781585], which was
|
||||
fixed by commit [f46fb50cb3]. This bug was introduced by myself in
|
||||
commit [cbfe055d8c].
|
||||
|
||||
2013-06-03 Donal K. Fellows <dkf@users.sf.net>
|
||||
|
||||
* generic/tclCompCmds.c (TclCompileBreakCmd, TclCompileContinueCmd):
|
||||
Added code to allow [break] and [continue] to be issued as a jump (in
|
||||
the most common cases) rather than using the more expensive exception
|
||||
processing path in the bytecode engine. [Bug 3614226]: Partial fix for
|
||||
the issues relating to cleaning up the stack when dealing with [break]
|
||||
and [continue].
|
||||
|
||||
2013-05-27 Harald Oehlmann <oehhar@users.sf.net>
|
||||
|
||||
* library/msgcat/msgcat.tcl: [Bug 3036566]: Also get locale from
|
||||
registry key HCU\Control Panel\Desktop : PreferredUILanguages to honor
|
||||
installed language packs on Vista+.
|
||||
Bumped msgcat version to 1.5.2
|
||||
|
||||
2013-05-22 Andreas Kupries <andreask@activestate.com>
|
||||
|
||||
* tclCompile.c: Removed duplicate const qualifier causing the HP
|
||||
native cc to error out.
|
||||
|
||||
2013-05-22 Donal K. Fellows <dkf@users.sf.net>
|
||||
|
||||
* generic/tclUtf.c (TclUtfCasecmp): [Bug 3613609]: Replace problematic
|
||||
uses of strcasecmp with a proper UTF-8-aware version. Affects both
|
||||
[lsearch -nocase] and [lsort -nocase].
|
||||
|
||||
2013-05-22 Donal K. Fellows <dkf@users.sf.net>
|
||||
|
||||
* doc/file.n: [Bug 3613671]: Added note to portability section on the
|
||||
fact that [file owned] does not produce useful results on Windows.
|
||||
|
||||
2013-05-20 Donal K. Fellows <dkf@users.sf.net>
|
||||
|
||||
* unix/tclUnixFCmd.c (DefaultTempDir): [Bug 3613567]: Corrected logic
|
||||
for checking return code of access() system call, which was inverted.
|
||||
|
||||
2013-05-19 Jan Nijtmans <nijtmans@users.sf.net>
|
||||
|
||||
* unix/tcl.m4: Fix for FreeBSD, and remove support for older
|
||||
* unix/configure: FreeBSD versions. Patch by Pietro Cerutti.
|
||||
|
||||
2013-05-18 Donal K. Fellows <dkf@users.sf.net>
|
||||
|
||||
* generic/tclCompCmdsGR.c: Split tclCompCmds.c again to keep size of
|
||||
code down.
|
||||
|
||||
2013-05-16 Jan Nijtmans <nijtmans@users.sf.net>
|
||||
|
||||
* generic/tclBasic.c: Add panic in order to detect incompatible
|
||||
mingw32 sys/stat.h and sys/time.h headers.
|
||||
|
||||
2013-05-13 Jan Nijtmans <nijtmans@users.sf.net>
|
||||
|
||||
* compat/zlib/*: Upgrade to zlib 1.2.8
|
||||
@@ -27,10 +111,9 @@
|
||||
2013-04-30 Andreas Kupries <andreask@activestate.com>
|
||||
|
||||
* library/platform/platform.tcl (::platform::LibcVersion):
|
||||
* library/platform/pkgIndex.tcl: Followup to the 2013-01-30
|
||||
change. The RE become too restrictive again. SuSe added a
|
||||
timestamp after the version. Loosened up a bit. Bumped package
|
||||
to version 1.0.12.
|
||||
* library/platform/pkgIndex.tcl: Followup to the 2013-01-30 change.
|
||||
The RE become too restrictive again. SuSe added a timestamp after the
|
||||
version. Loosened up a bit. Bumped package to version 1.0.12.
|
||||
|
||||
2013-04-29 Donal K. Fellows <dkf@users.sf.net>
|
||||
|
||||
@@ -49,8 +132,8 @@
|
||||
2013-04-19 Jan Nijtmans <nijtmans@users.sf.net>
|
||||
|
||||
* generic/tclDecls.h: Implement many Tcl_*Var* functions and
|
||||
Tcl_GetIndexFromObj as (faster/stack-saving) macros around resp
|
||||
their Tcl_*Var*2 equivalent and Tcl_GetIndexFromObjStruct.
|
||||
Tcl_GetIndexFromObj as (faster/stack-saving) macros around resp their
|
||||
Tcl_*Var*2 equivalent and Tcl_GetIndexFromObjStruct.
|
||||
|
||||
2013-04-12 Jan Nijtmans <nijtmans@users.sf.net>
|
||||
|
||||
@@ -59,16 +142,16 @@
|
||||
|
||||
2013-04-08 Don Porter <dgp@users.sourceforge.net>
|
||||
|
||||
* generic/regc_color.c: [Bug 3610026] Stop crash when the number of
|
||||
* generic/regerrs.h: "colors" in a regular expression overflows
|
||||
* generic/regex.h: a short int. Thanks to Heikki Linnakangas
|
||||
* generic/regguts.h: for the report and the patch.
|
||||
* generic/regc_color.c: [Bug 3610026]: Stop crash when the number of
|
||||
* generic/regerrs.h: "colors" in a regular expression overflows a
|
||||
* generic/regex.h: short int. Thanks to Heikki Linnakangas for
|
||||
* generic/regguts.h: the report and the patch.
|
||||
* tests/regexp.test:
|
||||
|
||||
2013-04-04 Reinhard Max <max@suse.de>
|
||||
|
||||
* library/http/http.tcl (http::geturl): Allow URLs that don't have
|
||||
a path, but a query query, e.g. http://example.com?foo=bar .
|
||||
* library/http/http.tcl (http::geturl): Allow URLs that don't have a
|
||||
path, but a query query, e.g. http://example.com?foo=bar
|
||||
* Bump the http package to 2.8.7.
|
||||
|
||||
2013-03-22 Venkat Iyer <venkat@comit.com>
|
||||
@@ -100,12 +183,12 @@
|
||||
|
||||
2013-03-21 Don Porter <dgp@users.sourceforge.net>
|
||||
|
||||
* library/auto.tcl: [Bug 2102614] Add ensemble indexing support
|
||||
* tests/autoMkindex.test: to [auto_mkindex]. Thanks Brian Griffin.
|
||||
* library/auto.tcl: [Bug 2102614]: Add ensemble indexing support to
|
||||
* tests/autoMkindex.test: [auto_mkindex]. Thanks Brian Griffin.
|
||||
|
||||
2013-03-19 Don Porter <dgp@users.sourceforge.net>
|
||||
|
||||
* generic/tclFCmd.c: [Bug 3597000] Consistent [file copy] result.
|
||||
* generic/tclFCmd.c: [Bug 3597000]: Consistent [file copy] result.
|
||||
* tests/fileSystem.test:
|
||||
|
||||
2013-03-19 Jan Nijtmans <nijtmans@users.sf.net>
|
||||
@@ -125,20 +208,20 @@
|
||||
|
||||
2013-03-11 Don Porter <dgp@users.sourceforge.net>
|
||||
|
||||
* generic/tclCompile.c: [Bugs 3607246,3607372] Unbalanced refcounts
|
||||
* generic/tclCompile.c: [Bugs 3607246,3607372]: Unbalanced refcounts
|
||||
* generic/tclLiteral.c: of literals in the global literal table.
|
||||
|
||||
2013-03-06 Don Porter <dgp@users.sourceforge.net>
|
||||
|
||||
* generic/regc_nfa.c: [Bugs 3604074,3606683] Rewrite of the
|
||||
* generic/regcomp.c: fixempties() routine (and supporting
|
||||
routines) to completely eliminate the infinite loop hazard.
|
||||
Thanks to Tom Lane for the much improved solution.
|
||||
* generic/regc_nfa.c: [Bugs 3604074,3606683]: Rewrite of the
|
||||
* generic/regcomp.c: fixempties() routine (and supporting routines)
|
||||
to completely eliminate the infinite loop hazard. Thanks to Tom Lane
|
||||
for the much improved solution.
|
||||
|
||||
2013-02-28 Don Porter <dgp@users.sourceforge.net>
|
||||
|
||||
* generic/tclLiteral.c: Revise TclReleaseLiteral() to tolerate a
|
||||
NULL interp argument.
|
||||
* generic/tclLiteral.c: Revise TclReleaseLiteral() to tolerate a NULL
|
||||
interp argument.
|
||||
|
||||
* generic/tclCompile.c: Update callers and revise mistaken comments.
|
||||
* generic/tclProc.c:
|
||||
@@ -4833,8 +4916,7 @@
|
||||
2010-05-19 Alexandre Ferrieux <ferrieux@users.sourceforge.net>
|
||||
|
||||
* tests/dict.test: Add missing tests for [Bug 3004007], fixed under
|
||||
the radar on 2010-02-24 (dkf): EIAS violation in
|
||||
list-dict conversions.
|
||||
the radar on 2010-02-24 (dkf): EIAS violation in list-dict conversions
|
||||
|
||||
2010-05-19 Jan Nijtmans <nijtmans@users.sf.net>
|
||||
|
||||
@@ -6688,10 +6770,9 @@
|
||||
|
||||
2009-11-11 Alexandre Ferrieux <ferrieux@users.sourceforge.net>
|
||||
|
||||
* generic/tclIO.c: Fix [Bug 2888099] (close discards ENOSPC error)
|
||||
by saving the errno from the first of two
|
||||
FlushChannel()s. Uneasy to test; might need
|
||||
specific channel drivers. Four-hands with aku.
|
||||
* generic/tclIO.c: Fix [Bug 2888099] (close discards ENOSPC error) by
|
||||
saving the errno from the first of two FlushChannel()s. Uneasy to
|
||||
test; might need specific channel drivers. Four-hands with aku.
|
||||
|
||||
2009-11-10 Pat Thoyts <patthoyts@users.sourceforge.net>
|
||||
|
||||
|
||||
@@ -8163,3 +8163,7 @@ Dropped support for OS X versions less than 10.4 (Tiger) (fellows)
|
||||
2012-12-13 (bug fix) crash: [zlib gunzip $data -header noSuchNs::var] (porter)
|
||||
|
||||
--- Released 8.6.0, December 20, 2012 --- See ChangeLog for details ---
|
||||
|
||||
2013-05-08 (bug fix)[3036566] Honor language packs on Vista+ to get initial locale (oehlmann)
|
||||
=> msgcat 1.5.2
|
||||
|
||||
|
||||
@@ -481,6 +481,13 @@ Returns \fB1\fR if file \fIname\fR is writable by the current user,
|
||||
.
|
||||
These commands always operate using the real user and group identifiers,
|
||||
not the effective ones.
|
||||
.TP
|
||||
\fBWindows\fR\0\0\0\0
|
||||
.
|
||||
The \fbfile owned\fR subcommand currently always reports that the current user
|
||||
is the owner of the file, without regard for what the operating system
|
||||
believes to be true, making an ownership test useless. This issue (#3613671)
|
||||
may be fixed in a future release of Tcl.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
This procedure shows how to search for C files in a given directory
|
||||
|
||||
+4
-3
@@ -35,7 +35,7 @@ msgcat \- Tcl message catalog
|
||||
\fB::msgcat::mcflmset \fIsrc-trans-list\fR
|
||||
.VE "TIP 404"
|
||||
.sp
|
||||
\fB::msgcat::mcunknown \fIlocale src-string\fR
|
||||
\fB::msgcat::mcunknown \fIlocale src-string\fR ?\fIarg arg ...\fR?
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
@@ -157,12 +157,13 @@ translate-string\fR ?\fIsrc-string translate-string ...\fR?}
|
||||
of \fB::msgcat::mcflset\fR. The function returns the number of translations set.
|
||||
.VE "TIP 404"
|
||||
.TP
|
||||
\fB::msgcat::mcunknown \fIlocale src-string\fR
|
||||
\fB::msgcat::mcunknown \fIlocale src-string\fR ?\fIarg arg ...\fR?
|
||||
.
|
||||
This routine is called by \fB::msgcat::mc\fR in the case when
|
||||
a translation for \fIsrc-string\fR is not defined in the
|
||||
current locale. The default action is to return
|
||||
\fIsrc-string\fR. This procedure can be redefined by the
|
||||
\fIsrc-string\fR passed by format if there are any arguments. This
|
||||
procedure can be redefined by the
|
||||
application, for example to log error messages for each unknown
|
||||
string. The \fB::msgcat::mcunknown\fR procedure is invoked at the
|
||||
same stack context as the call to \fB::msgcat::mc\fR. The return value
|
||||
|
||||
+3
-3
@@ -341,12 +341,12 @@ struct subre {
|
||||
#define CAP 010 /* capturing parens below */
|
||||
#define BACKR 020 /* back reference below */
|
||||
#define INUSE 0100 /* in use in final tree */
|
||||
#define LOCAL 03 /* bits which may not propagate up */
|
||||
#define NOPROP 03 /* bits which may not propagate up */
|
||||
#define LMIX(f) ((f)<<2) /* LONGER -> MIXED */
|
||||
#define SMIX(f) ((f)<<1) /* SHORTER -> MIXED */
|
||||
#define UP(f) (((f)&~LOCAL) | (LMIX(f) & SMIX(f) & MIXED))
|
||||
#define UP(f) (((f)&~NOPROP) | (LMIX(f) & SMIX(f) & MIXED))
|
||||
#define MESSY(f) ((f)&(MIXED|CAP|BACKR))
|
||||
#define PREF(f) ((f)&LOCAL)
|
||||
#define PREF(f) ((f)&NOPROP)
|
||||
#define PREF2(f1, f2) ((PREF(f1) != 0) ? PREF(f1) : PREF(f2))
|
||||
#define COMBINE(f1, f2) (UP((f1)|(f2)) | PREF2(f1, f2))
|
||||
short retry; /* index into retry memory */
|
||||
|
||||
+6
-4
@@ -329,10 +329,12 @@ typedef long LONG;
|
||||
* in ANSI C; maps them to type "char *" in non-ANSI systems.
|
||||
*/
|
||||
|
||||
#ifndef NO_VOID
|
||||
# define VOID void
|
||||
#else
|
||||
# define VOID char
|
||||
#ifndef __VXWORKS__
|
||||
# ifndef NO_VOID
|
||||
# define VOID void
|
||||
# else
|
||||
# define VOID char
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
+7
-31
@@ -20,7 +20,7 @@
|
||||
*- break and continue - if exception ranges can be sorted out.
|
||||
*- foreach_start4, foreach_step4
|
||||
*- returnImm, returnStk
|
||||
*- expandStart, expandStkTop, invokeExpanded, listExpanded
|
||||
*- expandStart, expandStkTop, invokeExpanded, expandDrop
|
||||
*- dictFirst, dictNext, dictDone
|
||||
*- dictUpdateStart, dictUpdateEnd
|
||||
*- jumpTable testing
|
||||
@@ -323,29 +323,6 @@ static const Tcl_ObjType assembleCodeType = {
|
||||
NULL /* setFromAnyProc */
|
||||
};
|
||||
|
||||
/*
|
||||
* TIP #280: Remember the per-word line information of the current command. An
|
||||
* index is used instead of a pointer as recursive compilation may reallocate,
|
||||
* i.e. move, the array. This is also the reason to save the nuloc now, it may
|
||||
* change during the course of the function.
|
||||
*
|
||||
* Macro to encapsulate the variable definition and setup.
|
||||
*/
|
||||
|
||||
#define DefineLineInformation \
|
||||
ExtCmdLoc *mapPtr = envPtr->extCmdMapPtr; \
|
||||
int eclIndex = mapPtr->nuloc - 1
|
||||
|
||||
#define SetLineInformation(word) \
|
||||
envPtr->line = mapPtr->loc[eclIndex].line[(word)]; \
|
||||
envPtr->clNext = mapPtr->loc[eclIndex].next[(word)]
|
||||
|
||||
/*
|
||||
* Flags bits used by PushVarName.
|
||||
*/
|
||||
|
||||
#define TCL_NO_LARGE_INDEX 1 /* Do not return localIndex value > 255 */
|
||||
|
||||
/*
|
||||
* Source instructions recognized in the Tcl Assembly Language (TAL)
|
||||
*/
|
||||
@@ -410,9 +387,8 @@ static const TalInstDesc TalInstructionTable[] = {
|
||||
{"incrArrayStkImm", ASSEM_SINT1, INST_INCR_ARRAY_STK_IMM,2, 1},
|
||||
{"incrImm", ASSEM_LVT1_SINT1,
|
||||
INST_INCR_SCALAR1_IMM, 0, 1},
|
||||
{"incrStk", ASSEM_1BYTE, INST_INCR_SCALAR_STK, 2, 1},
|
||||
{"incrStkImm", ASSEM_SINT1, INST_INCR_SCALAR_STK_IMM,
|
||||
1, 1},
|
||||
{"incrStk", ASSEM_1BYTE, INST_INCR_STK, 2, 1},
|
||||
{"incrStkImm", ASSEM_SINT1, INST_INCR_STK_IMM, 1, 1},
|
||||
{"infoLevelArgs", ASSEM_1BYTE, INST_INFO_LEVEL_ARGS, 1, 1},
|
||||
{"infoLevelNumber", ASSEM_1BYTE, INST_INFO_LEVEL_NUM, 0, 1},
|
||||
{"invokeStk", ASSEM_INVOKE, (INST_INVOKE_STK1 << 8
|
||||
@@ -448,7 +424,7 @@ static const TalInstDesc TalInstructionTable[] = {
|
||||
{"loadArray", ASSEM_LVT, (INST_LOAD_ARRAY1<<8
|
||||
| INST_LOAD_ARRAY4), 1, 1},
|
||||
{"loadArrayStk", ASSEM_1BYTE, INST_LOAD_ARRAY_STK, 2, 1},
|
||||
{"loadStk", ASSEM_1BYTE, INST_LOAD_SCALAR_STK, 1, 1},
|
||||
{"loadStk", ASSEM_1BYTE, INST_LOAD_STK, 1, 1},
|
||||
{"lor", ASSEM_1BYTE, INST_LOR, 2, 1},
|
||||
{"lsetFlat", ASSEM_LSET_FLAT,INST_LSET_FLAT, INT_MIN,1},
|
||||
{"lsetList", ASSEM_1BYTE, INST_LSET_LIST, 3, 1},
|
||||
@@ -475,7 +451,7 @@ static const TalInstDesc TalInstructionTable[] = {
|
||||
{"storeArray", ASSEM_LVT, (INST_STORE_ARRAY1<<8
|
||||
| INST_STORE_ARRAY4), 2, 1},
|
||||
{"storeArrayStk", ASSEM_1BYTE, INST_STORE_ARRAY_STK, 3, 1},
|
||||
{"storeStk", ASSEM_1BYTE, INST_STORE_SCALAR_STK, 2, 1},
|
||||
{"storeStk", ASSEM_1BYTE, INST_STORE_STK, 2, 1},
|
||||
{"strcmp", ASSEM_1BYTE, INST_STR_CMP, 2, 1},
|
||||
{"streq", ASSEM_1BYTE, INST_STR_EQ, 2, 1},
|
||||
{"strfind", ASSEM_1BYTE, INST_STR_FIND, 2, 1},
|
||||
@@ -674,7 +650,7 @@ BBEmitOpcode(
|
||||
}
|
||||
|
||||
TclEmitInt1(op, envPtr);
|
||||
envPtr->atCmdStart = ((op) == INST_START_CMD);
|
||||
TclUpdateAtCmdStart(op, envPtr);
|
||||
BBUpdateStackReqs(bbPtr, tblIdx, count);
|
||||
}
|
||||
|
||||
@@ -735,7 +711,7 @@ BBEmitInst1or4(
|
||||
} else {
|
||||
TclEmitInt4(param, envPtr);
|
||||
}
|
||||
envPtr->atCmdStart = ((op) == INST_START_CMD);
|
||||
TclUpdateAtCmdStart(op, envPtr);
|
||||
BBUpdateStackReqs(bbPtr, tblIdx, count);
|
||||
}
|
||||
|
||||
|
||||
@@ -486,6 +486,17 @@ Tcl_CreateInterp(void)
|
||||
Tcl_Panic("Tcl_CallFrame must not be smaller than CallFrame");
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
if (sizeof(time_t) != 4) {
|
||||
/*NOTREACHED*/
|
||||
Tcl_Panic("sys/time.h is not compatible with MSVC");
|
||||
}
|
||||
if (sizeof(Tcl_StatBuf) != 48) {
|
||||
/*NOTREACHED*/
|
||||
Tcl_Panic("sys/stat.h is not compatible with MSVC");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cancelTableInitialized == 0) {
|
||||
Tcl_MutexLock(&cancelLock);
|
||||
if (cancelTableInitialized == 0) {
|
||||
|
||||
+7
-6
@@ -3005,7 +3005,7 @@ Tcl_LsearchObjCmd(
|
||||
dataType = INTEGER;
|
||||
break;
|
||||
case LSEARCH_NOCASE: /* -nocase */
|
||||
strCmpFn = strcasecmp;
|
||||
strCmpFn = TclUtfCasecmp;
|
||||
noCase = 1;
|
||||
break;
|
||||
case LSEARCH_NOT: /* -not */
|
||||
@@ -3400,7 +3400,7 @@ Tcl_LsearchObjCmd(
|
||||
*/
|
||||
|
||||
if (noCase) {
|
||||
match = (strcasecmp(bytes, patternBytes) == 0);
|
||||
match = (TclUtfCasecmp(bytes, patternBytes) == 0);
|
||||
} else {
|
||||
match = (memcmp(bytes, patternBytes,
|
||||
(size_t) length) == 0);
|
||||
@@ -3645,7 +3645,8 @@ Tcl_LsortObjCmd(
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *const objv[]) /* Argument values. */
|
||||
{
|
||||
int i, j, index, indices, length, nocase = 0, sortMode, indexc;
|
||||
int i, j, index, indices, length, nocase = 0, indexc;
|
||||
int sortMode = SORTMODE_ASCII;
|
||||
int group, groupSize, groupOffset, idx, allocatedIndexVector = 0;
|
||||
Tcl_Obj *resultPtr, *cmdPtr, **listObjPtrs, *listObj, *indexPtr;
|
||||
SortElement *elementArray, *elementPtr;
|
||||
@@ -3991,7 +3992,7 @@ Tcl_LsortObjCmd(
|
||||
goto done1;
|
||||
}
|
||||
elementArray[i].collationKey.intValue = a;
|
||||
} else if (sortInfo.sortMode == SORTMODE_REAL) {
|
||||
} else if (sortMode == SORTMODE_REAL) {
|
||||
double a;
|
||||
|
||||
if (Tcl_GetDoubleFromObj(sortInfo.interp, indexPtr,
|
||||
@@ -4088,7 +4089,7 @@ Tcl_LsortObjCmd(
|
||||
TclStackFree(interp, elementArray);
|
||||
|
||||
done:
|
||||
if (sortInfo.sortMode == SORTMODE_COMMAND) {
|
||||
if (sortMode == SORTMODE_COMMAND) {
|
||||
TclDecrRefCount(sortInfo.compareCmdPtr);
|
||||
TclDecrRefCount(listObj);
|
||||
sortInfo.compareCmdPtr = NULL;
|
||||
@@ -4233,7 +4234,7 @@ SortCompare(
|
||||
order = strcmp(elemPtr1->collationKey.strValuePtr,
|
||||
elemPtr2->collationKey.strValuePtr);
|
||||
} else if (infoPtr->sortMode == SORTMODE_ASCII_NC) {
|
||||
order = strcasecmp(elemPtr1->collationKey.strValuePtr,
|
||||
order = TclUtfCasecmp(elemPtr1->collationKey.strValuePtr,
|
||||
elemPtr2->collationKey.strValuePtr);
|
||||
} else if (infoPtr->sortMode == SORTMODE_DICTIONARY) {
|
||||
order = DictionaryCompare(elemPtr1->collationKey.strValuePtr,
|
||||
|
||||
+1
-1
@@ -3527,7 +3527,7 @@ TclNRSwitchObjCmd(
|
||||
i++;
|
||||
goto finishedOptions;
|
||||
case OPT_NOCASE:
|
||||
strCmpFn = strcasecmp;
|
||||
strCmpFn = TclUtfCasecmp;
|
||||
noCase = 1;
|
||||
break;
|
||||
|
||||
|
||||
+267
-3338
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+402
-502
File diff suppressed because it is too large
Load Diff
+387
-190
@@ -51,7 +51,7 @@ static int traceInitialized = 0;
|
||||
* existence of a procedure call frame to distinguish these.
|
||||
*/
|
||||
|
||||
const InstructionDesc const tclInstructionTable[] = {
|
||||
InstructionDesc const tclInstructionTable[] = {
|
||||
/* Name Bytes stackEffect #Opnds Operand types */
|
||||
{"done", 1, -1, 0, {OPERAND_NONE}},
|
||||
/* Finish ByteCode execution and return stktop (top stack item) */
|
||||
@@ -283,8 +283,9 @@ const InstructionDesc const tclInstructionTable[] = {
|
||||
* NOTE: the stack effects of expandStkTop and invokeExpanded are wrong -
|
||||
* but it cannot be done right at compile time, the stack effect is only
|
||||
* known at run time. The value for invokeExpanded is estimated better at
|
||||
* compile time. See the comments further down in this file, where
|
||||
* INST_INVOKE_EXPANDED is emitted.
|
||||
* compile time.
|
||||
* See the comments further down in this file, where INST_INVOKE_EXPANDED
|
||||
* is emitted.
|
||||
*/
|
||||
{"expandStart", 1, 0, 0, {OPERAND_NONE}},
|
||||
/* Start of command with {*} (expanded) arguments */
|
||||
@@ -309,7 +310,7 @@ const InstructionDesc const tclInstructionTable[] = {
|
||||
{"pushReturnOpts", 1, +1, 0, {OPERAND_NONE}},
|
||||
/* Push the interpreter's return option dictionary as an object on the
|
||||
* stack. */
|
||||
{"returnStk", 1, -2, 0, {OPERAND_NONE}},
|
||||
{"returnStk", 1, -1, 0, {OPERAND_NONE}},
|
||||
/* Compiled [return]; options and result are on the stack, code and
|
||||
* level are in the options. */
|
||||
|
||||
@@ -382,7 +383,8 @@ const InstructionDesc const tclInstructionTable[] = {
|
||||
/* finds namespace and otherName in stack, links to local variable at
|
||||
* index op1. Leaves the namespace on stack. */
|
||||
{"syntax", 9, -1, 2, {OPERAND_INT4, OPERAND_UINT4}},
|
||||
/* Compiled bytecodes to signal syntax error. */
|
||||
/* Compiled bytecodes to signal syntax error. Equivalent to returnImm
|
||||
* except for the ERR_ALREADY_LOGGED flag in the interpreter. */
|
||||
{"reverse", 5, 0, 1, {OPERAND_UINT4}},
|
||||
/* Reverse the order of the arg elements at the top of stack */
|
||||
|
||||
@@ -430,7 +432,7 @@ const InstructionDesc const tclInstructionTable[] = {
|
||||
/* Map variable contents back into a dictionary in a variable. Part of
|
||||
* [dict with].
|
||||
* Stack: ... dictVarName path keyList => ... */
|
||||
{"dictRecombineImm", 1, -2, 1, {OPERAND_LVT4}},
|
||||
{"dictRecombineImm", 5, -2, 1, {OPERAND_LVT4}},
|
||||
/* Map variable contents back into a dictionary in the local variable
|
||||
* indicated by the LVT index. Part of [dict with].
|
||||
* Stack: ... path keyList => ... */
|
||||
@@ -539,6 +541,10 @@ const InstructionDesc const tclInstructionTable[] = {
|
||||
* list and pushes that resulting list onto the stack.
|
||||
* Stack: ... list1 list2 => ... [lconcat list1 list2] */
|
||||
|
||||
{"expandDrop", 1, 0, 0, {OPERAND_NONE}},
|
||||
/* Drops an element from the auxiliary stack, popping stack elements
|
||||
* until the matching stack depth is reached. */
|
||||
|
||||
{NULL, 0, 0, 0, {OPERAND_NONE}}
|
||||
};
|
||||
|
||||
@@ -556,20 +562,20 @@ static void EnterCmdExtentData(CompileEnv *envPtr,
|
||||
int cmdNumber, int numSrcBytes, int numCodeBytes);
|
||||
static void EnterCmdStartData(CompileEnv *envPtr,
|
||||
int cmdNumber, int srcOffset, int codeOffset);
|
||||
static Command * FindCommandFromToken(Tcl_Interp *interp,
|
||||
Tcl_Token *tokenPtr, Tcl_Namespace *namespacePtr);
|
||||
static Command * FindCompiledCommandFromToken(Tcl_Interp *interp,
|
||||
Tcl_Token *tokenPtr);
|
||||
static void FreeByteCodeInternalRep(Tcl_Obj *objPtr);
|
||||
static void FreeSubstCodeInternalRep(Tcl_Obj *objPtr);
|
||||
static int GetCmdLocEncodingSize(CompileEnv *envPtr);
|
||||
static int IsCompactibleCompileEnv(Tcl_Interp *interp,
|
||||
CompileEnv *envPtr);
|
||||
static void PeepholeOptimize(CompileEnv *envPtr);
|
||||
#ifdef TCL_COMPILE_STATS
|
||||
static void RecordByteCodeStats(ByteCode *codePtr);
|
||||
#endif /* TCL_COMPILE_STATS */
|
||||
static void RegisterAuxDataType(const AuxDataType *typePtr);
|
||||
static int SetByteCodeFromAny(Tcl_Interp *interp,
|
||||
Tcl_Obj *objPtr);
|
||||
static void StartExpanding(CompileEnv *envPtr);
|
||||
static int FormatInstruction(ByteCode *codePtr,
|
||||
const unsigned char *pc, Tcl_Obj *bufferObj);
|
||||
static void PrintSourceToObj(Tcl_Obj *appendObj,
|
||||
@@ -624,6 +630,13 @@ static const Tcl_ObjType tclInstNameType = {
|
||||
UpdateStringOfInstName, /* updateStringProc */
|
||||
NULL, /* setFromAnyProc */
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper macros.
|
||||
*/
|
||||
|
||||
#define TclIncrUInt4AtPtr(ptr, delta) \
|
||||
TclStoreInt4AtPtr(TclGetUInt4AtPtr(ptr)+(delta), (ptr));
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -737,7 +750,9 @@ TclSetByteCodeFromAny(
|
||||
}
|
||||
compEnv.atCmdStart = 2; /* The disabling magic. */
|
||||
TclCompileScript(interp, stringPtr, length, &compEnv);
|
||||
assert (compEnv.atCmdStart > 1);
|
||||
TclEmitOpcode(INST_DONE, &compEnv);
|
||||
assert (compEnv.atCmdStart > 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -745,7 +760,7 @@ TclSetByteCodeFromAny(
|
||||
* instruction generator boundaries.
|
||||
*/
|
||||
|
||||
PeepholeOptimize(&compEnv);
|
||||
TclOptimizeBytecode(&compEnv);
|
||||
|
||||
/*
|
||||
* Invoke the compilation hook procedure if one exists.
|
||||
@@ -1076,141 +1091,16 @@ IsCompactibleCompileEnv(
|
||||
case INST_NSUPVAR:
|
||||
case INST_VARIABLE:
|
||||
return 0;
|
||||
default:
|
||||
size = tclInstructionTable[*pc].numBytes;
|
||||
assert (size > 0);
|
||||
break;
|
||||
}
|
||||
size = tclInstructionTable[*pc].numBytes;
|
||||
assert (size > 0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* PeepholeOptimize --
|
||||
*
|
||||
* A very simple peephole optimizer for bytecode.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
PeepholeOptimize(
|
||||
CompileEnv *envPtr)
|
||||
{
|
||||
unsigned char *pc, *prev1 = NULL, *prev2 = NULL, *target;
|
||||
int size, isNew;
|
||||
Tcl_HashTable targets;
|
||||
Tcl_HashEntry *hPtr;
|
||||
Tcl_HashSearch hSearch;
|
||||
|
||||
/*
|
||||
* Find places where we should be careful about replacing instructions
|
||||
* because they are the targets of various types of jumps.
|
||||
*/
|
||||
|
||||
Tcl_InitHashTable(&targets, TCL_ONE_WORD_KEYS);
|
||||
for (pc = envPtr->codeStart ; pc < envPtr->codeNext ; pc += size) {
|
||||
size = tclInstructionTable[*pc].numBytes;
|
||||
switch (*pc) {
|
||||
case INST_JUMP1:
|
||||
case INST_JUMP_TRUE1:
|
||||
case INST_JUMP_FALSE1:
|
||||
target = pc + TclGetInt1AtPtr(pc+1);
|
||||
goto storeTarget;
|
||||
case INST_JUMP4:
|
||||
case INST_JUMP_TRUE4:
|
||||
case INST_JUMP_FALSE4:
|
||||
target = pc + TclGetInt4AtPtr(pc+1);
|
||||
goto storeTarget;
|
||||
case INST_BEGIN_CATCH4:
|
||||
target = envPtr->codeStart + envPtr->exceptArrayPtr[
|
||||
TclGetUInt4AtPtr(pc+1)].codeOffset;
|
||||
storeTarget:
|
||||
(void) Tcl_CreateHashEntry(&targets, (void *) target, &isNew);
|
||||
break;
|
||||
case INST_JUMP_TABLE:
|
||||
hPtr = Tcl_FirstHashEntry(
|
||||
&JUMPTABLEINFO(envPtr, pc+1)->hashTable, &hSearch);
|
||||
for (; hPtr ; hPtr = Tcl_NextHashEntry(&hSearch)) {
|
||||
target = pc + PTR2INT(Tcl_GetHashValue(hPtr));
|
||||
(void) Tcl_CreateHashEntry(&targets, (void *) target, &isNew);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace PUSH/POP sequences (when non-hazardous) with NOPs.
|
||||
*/
|
||||
|
||||
(void) Tcl_CreateHashEntry(&targets, (void *) pc, &isNew);
|
||||
for (pc = envPtr->codeStart ; pc < envPtr->codeNext ; pc += size) {
|
||||
int blank = 0, i;
|
||||
|
||||
size = tclInstructionTable[*pc].numBytes;
|
||||
prev2 = prev1;
|
||||
prev1 = pc;
|
||||
if (Tcl_FindHashEntry(&targets, (void *) (pc + size))) {
|
||||
continue;
|
||||
}
|
||||
switch (*pc) {
|
||||
case INST_PUSH1:
|
||||
while (*(pc+size) == INST_NOP) {
|
||||
size++;
|
||||
}
|
||||
if (*(pc+size) == INST_POP) {
|
||||
blank = size + 1;
|
||||
} else if (*(pc+size) == INST_CONCAT1
|
||||
&& TclGetUInt1AtPtr(pc + size + 1) == 2) {
|
||||
Tcl_Obj *litPtr = TclFetchLiteral(envPtr,
|
||||
TclGetUInt1AtPtr(pc + 1));
|
||||
int numBytes;
|
||||
|
||||
(void) Tcl_GetStringFromObj(litPtr, &numBytes);
|
||||
if (numBytes == 0) {
|
||||
blank = size + 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case INST_PUSH4:
|
||||
while (*(pc+size) == INST_NOP) {
|
||||
size++;
|
||||
}
|
||||
if (*(pc+size) == INST_POP) {
|
||||
blank = size + 1;
|
||||
} else if (*(pc+size) == INST_CONCAT1
|
||||
&& TclGetUInt1AtPtr(pc + size + 1) == 2) {
|
||||
Tcl_Obj *litPtr = TclFetchLiteral(envPtr,
|
||||
TclGetUInt4AtPtr(pc + 1));
|
||||
int numBytes;
|
||||
|
||||
(void) Tcl_GetStringFromObj(litPtr, &numBytes);
|
||||
if (numBytes == 0) {
|
||||
blank = size + 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (blank > 0) {
|
||||
for (i=0 ; i<blank ; i++) {
|
||||
*(pc + i) = INST_NOP;
|
||||
}
|
||||
size = blank;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Trim a trailing double DONE.
|
||||
*/
|
||||
|
||||
if (prev1 && prev2 && *prev1 == INST_DONE && *prev2 == INST_DONE
|
||||
&& !Tcl_FindHashEntry(&targets, (void *) prev1)) {
|
||||
envPtr->codeNext--;
|
||||
}
|
||||
Tcl_DeleteHashTable(&targets);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -1458,6 +1348,7 @@ TclInitCompileEnv(
|
||||
envPtr->mallocedLiteralArray = 0;
|
||||
|
||||
envPtr->exceptArrayPtr = envPtr->staticExceptArraySpace;
|
||||
envPtr->exceptAuxArrayPtr = envPtr->staticExAuxArraySpace;
|
||||
envPtr->exceptArrayNext = 0;
|
||||
envPtr->exceptArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES;
|
||||
envPtr->mallocedExceptArray = 0;
|
||||
@@ -1466,6 +1357,7 @@ TclInitCompileEnv(
|
||||
envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE;
|
||||
envPtr->mallocedCmdMap = 0;
|
||||
envPtr->atCmdStart = 1;
|
||||
envPtr->expandCount = 0;
|
||||
|
||||
/*
|
||||
* TIP #280: Set up the extended command location information, based on
|
||||
@@ -1670,6 +1562,7 @@ TclFreeCompileEnv(
|
||||
}
|
||||
if (envPtr->mallocedExceptArray) {
|
||||
ckfree(envPtr->exceptArrayPtr);
|
||||
ckfree(envPtr->exceptAuxArrayPtr);
|
||||
}
|
||||
if (envPtr->mallocedCmdMap) {
|
||||
ckfree(envPtr->cmdMapPtr);
|
||||
@@ -1776,7 +1669,7 @@ TclWordKnownAtCompileTime(
|
||||
/*
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* FindCommandFromToken --
|
||||
* FindCompiledCommandFromToken --
|
||||
*
|
||||
* A simple helper that looks up a command's compiler from its token.
|
||||
*
|
||||
@@ -1784,15 +1677,20 @@ TclWordKnownAtCompileTime(
|
||||
*/
|
||||
|
||||
static Command *
|
||||
FindCommandFromToken(
|
||||
FindCompiledCommandFromToken(
|
||||
Tcl_Interp *interp,
|
||||
Tcl_Token *tokenPtr,
|
||||
Tcl_Namespace *namespacePtr)
|
||||
Tcl_Token *tokenPtr)
|
||||
{
|
||||
Tcl_DString ds;
|
||||
Command *cmdPtr;
|
||||
|
||||
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
|
||||
/*
|
||||
* If we have a non-trivial token or are suppressing compilation, we stop
|
||||
* right now.
|
||||
*/
|
||||
|
||||
if ((tokenPtr->type != TCL_TOKEN_SIMPLE_WORD)
|
||||
|| (((Interp *) interp)->flags & DONT_COMPILE_CMDS_INLINE)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1805,8 +1703,8 @@ FindCommandFromToken(
|
||||
|
||||
Tcl_DStringInit(&ds);
|
||||
TclDStringAppendToken(&ds, &tokenPtr[1]);
|
||||
cmdPtr = (Command *) Tcl_FindCommand(interp, Tcl_DStringValue(&ds),
|
||||
namespacePtr, /*flags*/ 0);
|
||||
cmdPtr = (Command *) Tcl_FindCommand(interp, Tcl_DStringValue(&ds), NULL,
|
||||
/*flags*/ 0);
|
||||
if (cmdPtr != NULL && (cmdPtr->compileProc == NULL
|
||||
|| (cmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION)
|
||||
|| (cmdPtr->flags & CMD_HAS_EXEC_TRACES))) {
|
||||
@@ -1845,7 +1743,6 @@ TclCompileScript(
|
||||
* first null character. */
|
||||
CompileEnv *envPtr) /* Holds resulting instructions. */
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
int lastTopLevelCmdIndex = -1;
|
||||
/* Index of most recent toplevel command in
|
||||
* the command location table. Initialized to
|
||||
@@ -1854,7 +1751,6 @@ TclCompileScript(
|
||||
* code. Init. to avoid compiler warning. */
|
||||
unsigned char *entryCodeNext = envPtr->codeNext;
|
||||
const char *p, *next;
|
||||
Namespace *cmdNsPtr;
|
||||
Command *cmdPtr;
|
||||
Tcl_Token *tokenPtr;
|
||||
int bytesLeft, isFirstCmd, wordIdx, currCmdIndex, commandLength, objIndex;
|
||||
@@ -1873,12 +1769,6 @@ TclCompileScript(
|
||||
Tcl_ResetResult(interp);
|
||||
isFirstCmd = 1;
|
||||
|
||||
if (envPtr->procPtr != NULL) {
|
||||
cmdNsPtr = envPtr->procPtr->cmdPtr->nsPtr;
|
||||
} else {
|
||||
cmdNsPtr = NULL; /* use current NS */
|
||||
}
|
||||
|
||||
/*
|
||||
* Each iteration through the following loop compiles the next command
|
||||
* from the script.
|
||||
@@ -1916,8 +1806,7 @@ TclCompileScript(
|
||||
parsePtr->commandStart - envPtr->source);
|
||||
|
||||
if (parsePtr->numWords > 0) {
|
||||
int expand = 0; /* Set to the relevant expansion instruction
|
||||
* if there are dynamic expansions to
|
||||
int expand = 0; /* Set if there are dynamic expansions to
|
||||
* handle */
|
||||
|
||||
/*
|
||||
@@ -1971,7 +1860,7 @@ TclCompileScript(
|
||||
wordIdx < parsePtr->numWords;
|
||||
wordIdx++, tokenPtr += tokenPtr->numComponents + 1) {
|
||||
if (tokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
|
||||
expand = INST_INVOKE_EXPANDED;
|
||||
expand = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1980,13 +1869,13 @@ TclCompileScript(
|
||||
* If expansion was requested, check if the command declares that
|
||||
* it knows how to compile it. Note that if expansion is requested
|
||||
* for the first word, this check will fail as the token type will
|
||||
* inhibit it. (That check is done inside FindCommandFromToken.)
|
||||
* This is as it should be.
|
||||
* inhibit it. (Checked inside FindCompiledCommandFromToken.) This
|
||||
* is as it should be.
|
||||
*/
|
||||
|
||||
if (expand) {
|
||||
cmdPtr = FindCommandFromToken(interp, parsePtr->tokenPtr,
|
||||
(Tcl_Namespace *) cmdNsPtr);
|
||||
cmdPtr = FindCompiledCommandFromToken(interp,
|
||||
parsePtr->tokenPtr);
|
||||
if (cmdPtr && (cmdPtr->flags & CMD_COMPILES_EXPANDED)) {
|
||||
expand = 0;
|
||||
}
|
||||
@@ -2005,7 +1894,7 @@ TclCompileScript(
|
||||
*/
|
||||
|
||||
if (expand) {
|
||||
TclEmitOpcode(INST_EXPAND_START, envPtr);
|
||||
StartExpanding(envPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2030,9 +1919,13 @@ TclCompileScript(
|
||||
for (wordIdx = 0, tokenPtr = parsePtr->tokenPtr;
|
||||
wordIdx < parsePtr->numWords; wordIdx++,
|
||||
tokenPtr += tokenPtr->numComponents + 1) {
|
||||
/*
|
||||
* Note the parse location information.
|
||||
*/
|
||||
|
||||
envPtr->line = eclPtr->loc[wlineat].line[wordIdx];
|
||||
envPtr->clNext = eclPtr->loc[wlineat].next[wordIdx];
|
||||
|
||||
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
|
||||
/*
|
||||
* The word is not a simple string of characters.
|
||||
@@ -2055,26 +1948,21 @@ TclCompileScript(
|
||||
*/
|
||||
|
||||
if ((wordIdx == 0) && !expand) {
|
||||
cmdPtr = FindCommandFromToken(interp, tokenPtr,
|
||||
(Tcl_Namespace *) cmdNsPtr);
|
||||
|
||||
if ((cmdPtr != NULL)
|
||||
&& !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) {
|
||||
int code, savedNumCmds = envPtr->numCommands;
|
||||
cmdPtr = FindCompiledCommandFromToken(interp, tokenPtr);
|
||||
if (cmdPtr) {
|
||||
int savedNumCmds = envPtr->numCommands;
|
||||
unsigned savedCodeNext =
|
||||
envPtr->codeNext - envPtr->codeStart;
|
||||
int update = 0;
|
||||
#ifdef TCL_COMPILE_DEBUG
|
||||
int startStackDepth = envPtr->currStackDepth;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Mark the start of the command; the proper bytecode
|
||||
* length will be updated later. There is no need to
|
||||
* do this for the first bytecode in the compile env,
|
||||
* as the check is done before calling
|
||||
* TclNRExecuteByteCode(). Do emit an INST_START_CMD in
|
||||
* special cases where the first bytecode is in a
|
||||
* TclNRExecuteByteCode(). Do emit an INST_START_CMD
|
||||
* in special cases where the first bytecode is in a
|
||||
* loop, to insure that the corresponding command is
|
||||
* counted properly. Compilers for commands able to
|
||||
* produce such a beast (currently 'while 1' only) set
|
||||
@@ -2095,10 +1983,7 @@ TclCompileScript(
|
||||
* INST_START_CMD's operands, so be careful!
|
||||
*/
|
||||
|
||||
unsigned char *fixPtr = envPtr->codeNext - 4;
|
||||
|
||||
TclStoreInt4AtPtr(TclGetUInt4AtPtr(fixPtr)+1,
|
||||
fixPtr);
|
||||
TclIncrUInt4AtPtr(envPtr->codeNext - 4, 1)
|
||||
}
|
||||
} else if (envPtr->atCmdStart == 0) {
|
||||
TclEmitInstInt4(INST_START_CMD, 0, envPtr);
|
||||
@@ -2106,10 +1991,8 @@ TclCompileScript(
|
||||
update = 1;
|
||||
}
|
||||
|
||||
code = cmdPtr->compileProc(interp, parsePtr, cmdPtr,
|
||||
envPtr);
|
||||
|
||||
if (code == TCL_OK) {
|
||||
if (cmdPtr->compileProc(interp, parsePtr, cmdPtr,
|
||||
envPtr) == TCL_OK) {
|
||||
/*
|
||||
* Confirm that the command compiler generated a
|
||||
* single value on the stack as its result. This
|
||||
@@ -2152,10 +2035,7 @@ TclCompileScript(
|
||||
* operands, so be careful!
|
||||
*/
|
||||
|
||||
unsigned char *fixPtr = envPtr->codeNext - 4;
|
||||
|
||||
TclStoreInt4AtPtr(TclGetUInt4AtPtr(fixPtr)-1,
|
||||
fixPtr);
|
||||
TclIncrUInt4AtPtr(envPtr->codeNext - 4, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2167,6 +2047,12 @@ TclCompileScript(
|
||||
|
||||
envPtr->numCommands = savedNumCmds;
|
||||
envPtr->codeNext = envPtr->codeStart + savedCodeNext;
|
||||
|
||||
/*
|
||||
* And the stack depth too!! [Bug 3614102].
|
||||
*/
|
||||
|
||||
envPtr->currStackDepth = startStackDepth;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2178,7 +2064,7 @@ TclCompileScript(
|
||||
|
||||
objIndex = TclRegisterNewCmdLiteral(envPtr,
|
||||
tokenPtr[1].start, tokenPtr[1].size);
|
||||
if (cmdPtr != NULL) {
|
||||
if (cmdPtr) {
|
||||
TclSetCmdNameObj(interp,
|
||||
TclFetchLiteral(envPtr, objIndex), cmdPtr);
|
||||
}
|
||||
@@ -2225,12 +2111,10 @@ TclCompileScript(
|
||||
* Note that the estimates are not correct while the command
|
||||
* is being prepared and run, INST_EXPAND_STKTOP is not
|
||||
* stack-neutral in general.
|
||||
*
|
||||
* The opcode that may be issued here (assumed to be non-zero)
|
||||
* is INST_INVOKE_EXPANDED.
|
||||
*/
|
||||
|
||||
TclEmitOpcode(expand, envPtr);
|
||||
TclEmitOpcode(INST_INVOKE_EXPANDED, envPtr);
|
||||
envPtr->expandCount--;
|
||||
TclAdjustStackDepth(1 - wordIdx, envPtr);
|
||||
} else if (wordIdx > 0) {
|
||||
/*
|
||||
@@ -2382,7 +2266,7 @@ TclCompileVarSubst(
|
||||
|
||||
if (tokenPtr->numComponents == 1) {
|
||||
if (localVar < 0) {
|
||||
TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);
|
||||
TclEmitOpcode(INST_LOAD_STK, envPtr);
|
||||
} else if (localVar <= 255) {
|
||||
TclEmitInstInt1(INST_LOAD_SCALAR1, localVar, envPtr);
|
||||
} else {
|
||||
@@ -3362,6 +3246,7 @@ TclCreateExceptRange(
|
||||
* new ExceptionRange structure. */
|
||||
{
|
||||
register ExceptionRange *rangePtr;
|
||||
register ExceptionAux *auxPtr;
|
||||
int index = envPtr->exceptArrayNext;
|
||||
|
||||
if (index >= envPtr->exceptArrayEnd) {
|
||||
@@ -3373,12 +3258,16 @@ TclCreateExceptRange(
|
||||
|
||||
size_t currBytes =
|
||||
envPtr->exceptArrayNext * sizeof(ExceptionRange);
|
||||
size_t currBytes2 = envPtr->exceptArrayNext * sizeof(ExceptionAux);
|
||||
int newElems = 2*envPtr->exceptArrayEnd;
|
||||
size_t newBytes = newElems * sizeof(ExceptionRange);
|
||||
size_t newBytes2 = newElems * sizeof(ExceptionAux);
|
||||
|
||||
if (envPtr->mallocedExceptArray) {
|
||||
envPtr->exceptArrayPtr =
|
||||
ckrealloc(envPtr->exceptArrayPtr, newBytes);
|
||||
envPtr->exceptAuxArrayPtr =
|
||||
ckrealloc(envPtr->exceptAuxArrayPtr, newBytes2);
|
||||
} else {
|
||||
/*
|
||||
* envPtr->exceptArrayPtr isn't a ckalloc'd pointer, so we must
|
||||
@@ -3386,9 +3275,12 @@ TclCreateExceptRange(
|
||||
*/
|
||||
|
||||
ExceptionRange *newPtr = ckalloc(newBytes);
|
||||
ExceptionAux *newPtr2 = ckalloc(newBytes2);
|
||||
|
||||
memcpy(newPtr, envPtr->exceptArrayPtr, currBytes);
|
||||
memcpy(newPtr2, envPtr->exceptAuxArrayPtr, currBytes2);
|
||||
envPtr->exceptArrayPtr = newPtr;
|
||||
envPtr->exceptAuxArrayPtr = newPtr2;
|
||||
envPtr->mallocedExceptArray = 1;
|
||||
}
|
||||
envPtr->exceptArrayEnd = newElems;
|
||||
@@ -3403,9 +3295,298 @@ TclCreateExceptRange(
|
||||
rangePtr->breakOffset = -1;
|
||||
rangePtr->continueOffset = -1;
|
||||
rangePtr->catchOffset = -1;
|
||||
auxPtr = &envPtr->exceptAuxArrayPtr[index];
|
||||
auxPtr->supportsContinue = 1;
|
||||
auxPtr->stackDepth = envPtr->currStackDepth;
|
||||
auxPtr->expandTarget = envPtr->expandCount;
|
||||
auxPtr->expandTargetDepth = -1;
|
||||
auxPtr->numBreakTargets = 0;
|
||||
auxPtr->breakTargets = NULL;
|
||||
auxPtr->allocBreakTargets = 0;
|
||||
auxPtr->numContinueTargets = 0;
|
||||
auxPtr->continueTargets = NULL;
|
||||
auxPtr->allocContinueTargets = 0;
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* TclGetInnermostExceptionRange --
|
||||
*
|
||||
* Returns the innermost exception range that covers the current code
|
||||
* creation point, and (optionally) the stack depth that is expected at
|
||||
* that point. Relies on the fact that the range has a numCodeBytes = -1
|
||||
* when it is being populated and that inner ranges come after outer
|
||||
* ranges.
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
ExceptionRange *
|
||||
TclGetInnermostExceptionRange(
|
||||
CompileEnv *envPtr,
|
||||
int returnCode,
|
||||
ExceptionAux **auxPtrPtr)
|
||||
{
|
||||
int exnIdx = -1, i;
|
||||
|
||||
for (i=0 ; i<envPtr->exceptArrayNext ; i++) {
|
||||
ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[i];
|
||||
|
||||
if (CurrentOffset(envPtr) >= rangePtr->codeOffset &&
|
||||
(rangePtr->numCodeBytes == -1 || CurrentOffset(envPtr) <
|
||||
rangePtr->codeOffset+rangePtr->numCodeBytes) &&
|
||||
(returnCode != TCL_CONTINUE ||
|
||||
envPtr->exceptAuxArrayPtr[i].supportsContinue)) {
|
||||
exnIdx = i;
|
||||
}
|
||||
}
|
||||
if (exnIdx == -1) {
|
||||
return NULL;
|
||||
}
|
||||
if (auxPtrPtr) {
|
||||
*auxPtrPtr = &envPtr->exceptAuxArrayPtr[exnIdx];
|
||||
}
|
||||
return &envPtr->exceptArrayPtr[exnIdx];
|
||||
}
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* TclAddLoopBreakFixup, TclAddLoopContinueFixup --
|
||||
*
|
||||
* Adds a place that wants to break/continue to the loop exception range
|
||||
* tracking that will be fixed up once the loop can be finalized. These
|
||||
* functions will generate an INST_JUMP4 that will be fixed up during the
|
||||
* loop finalization.
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
TclAddLoopBreakFixup(
|
||||
CompileEnv *envPtr,
|
||||
ExceptionAux *auxPtr)
|
||||
{
|
||||
int range = auxPtr - envPtr->exceptAuxArrayPtr;
|
||||
|
||||
if (envPtr->exceptArrayPtr[range].type != LOOP_EXCEPTION_RANGE) {
|
||||
Tcl_Panic("trying to add 'break' fixup to full exception range");
|
||||
}
|
||||
|
||||
if (++auxPtr->numBreakTargets > auxPtr->allocBreakTargets) {
|
||||
auxPtr->allocBreakTargets *= 2;
|
||||
auxPtr->allocBreakTargets += 2;
|
||||
if (auxPtr->breakTargets) {
|
||||
auxPtr->breakTargets = ckrealloc(auxPtr->breakTargets,
|
||||
sizeof(int) * auxPtr->allocBreakTargets);
|
||||
} else {
|
||||
auxPtr->breakTargets =
|
||||
ckalloc(sizeof(int) * auxPtr->allocBreakTargets);
|
||||
}
|
||||
}
|
||||
auxPtr->breakTargets[auxPtr->numBreakTargets - 1] = CurrentOffset(envPtr);
|
||||
TclEmitInstInt4(INST_JUMP4, 0, envPtr);
|
||||
}
|
||||
|
||||
void
|
||||
TclAddLoopContinueFixup(
|
||||
CompileEnv *envPtr,
|
||||
ExceptionAux *auxPtr)
|
||||
{
|
||||
int range = auxPtr - envPtr->exceptAuxArrayPtr;
|
||||
|
||||
if (envPtr->exceptArrayPtr[range].type != LOOP_EXCEPTION_RANGE) {
|
||||
Tcl_Panic("trying to add 'continue' fixup to full exception range");
|
||||
}
|
||||
|
||||
if (++auxPtr->numContinueTargets > auxPtr->allocContinueTargets) {
|
||||
auxPtr->allocContinueTargets *= 2;
|
||||
auxPtr->allocContinueTargets += 2;
|
||||
if (auxPtr->continueTargets) {
|
||||
auxPtr->continueTargets = ckrealloc(auxPtr->continueTargets,
|
||||
sizeof(int) * auxPtr->allocContinueTargets);
|
||||
} else {
|
||||
auxPtr->continueTargets =
|
||||
ckalloc(sizeof(int) * auxPtr->allocContinueTargets);
|
||||
}
|
||||
}
|
||||
auxPtr->continueTargets[auxPtr->numContinueTargets - 1] =
|
||||
CurrentOffset(envPtr);
|
||||
TclEmitInstInt4(INST_JUMP4, 0, envPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* TclCleanupStackForBreakContinue --
|
||||
*
|
||||
* Ditch the extra elements from the auxiliary stack and the main
|
||||
* stack. How to do this exactly depends on whether there are any
|
||||
* elements on the auxiliary stack to pop.
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
TclCleanupStackForBreakContinue(
|
||||
CompileEnv *envPtr,
|
||||
ExceptionAux *auxPtr)
|
||||
{
|
||||
int toPop = envPtr->expandCount - auxPtr->expandTarget;
|
||||
|
||||
if (toPop > 0) {
|
||||
while (toPop > 0) {
|
||||
TclEmitOpcode(INST_EXPAND_DROP, envPtr);
|
||||
toPop--;
|
||||
}
|
||||
toPop = auxPtr->expandTargetDepth - auxPtr->stackDepth;
|
||||
while (toPop > 0) {
|
||||
TclEmitOpcode(INST_POP, envPtr);
|
||||
TclAdjustStackDepth(1, envPtr);
|
||||
toPop--;
|
||||
}
|
||||
} else {
|
||||
toPop = envPtr->currStackDepth - auxPtr->stackDepth;
|
||||
while (toPop > 0) {
|
||||
TclEmitOpcode(INST_POP, envPtr);
|
||||
TclAdjustStackDepth(1, envPtr);
|
||||
toPop--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* StartExpanding --
|
||||
*
|
||||
* Pushes an INST_EXPAND_START and does some additional housekeeping so
|
||||
* that the [break] and [continue] compilers can use an exception-free
|
||||
* issue to discard it.
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
StartExpanding(
|
||||
CompileEnv *envPtr)
|
||||
{
|
||||
int i;
|
||||
|
||||
TclEmitOpcode(INST_EXPAND_START, envPtr);
|
||||
|
||||
/*
|
||||
* Update inner exception ranges with information about the environment
|
||||
* where this expansion started.
|
||||
*/
|
||||
|
||||
for (i=0 ; i<envPtr->exceptArrayNext ; i++) {
|
||||
ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[i];
|
||||
ExceptionAux *auxPtr = &envPtr->exceptAuxArrayPtr[i];
|
||||
|
||||
/*
|
||||
* Ignore loops unless they're still being built.
|
||||
*/
|
||||
|
||||
if (rangePtr->codeOffset > CurrentOffset(envPtr)) {
|
||||
continue;
|
||||
}
|
||||
if (rangePtr->numCodeBytes != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adequate condition: further out loops and further in exceptions
|
||||
* don't actually need this information.
|
||||
*/
|
||||
|
||||
if (auxPtr->expandTarget == envPtr->expandCount) {
|
||||
auxPtr->expandTargetDepth = envPtr->currStackDepth;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There's now one more expansion being processed on the auxiliary stack.
|
||||
*/
|
||||
|
||||
envPtr->expandCount++;
|
||||
}
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* TclFinalizeLoopExceptionRange --
|
||||
*
|
||||
* Finalizes a loop exception range, binding the registered [break] and
|
||||
* [continue] implementations so that they jump to the correct place.
|
||||
* Note that this must only be called after *all* the exception range
|
||||
* target offsets have been set.
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
TclFinalizeLoopExceptionRange(
|
||||
CompileEnv *envPtr,
|
||||
int range)
|
||||
{
|
||||
ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[range];
|
||||
ExceptionAux *auxPtr = &envPtr->exceptAuxArrayPtr[range];
|
||||
int i, offset;
|
||||
unsigned char *site;
|
||||
|
||||
if (rangePtr->type != LOOP_EXCEPTION_RANGE) {
|
||||
Tcl_Panic("trying to finalize a loop exception range");
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the jump fixups. Note that these are always issued as INST_JUMP4 so
|
||||
* there is no need to fuss around with updating code offsets.
|
||||
*/
|
||||
|
||||
for (i=0 ; i<auxPtr->numBreakTargets ; i++) {
|
||||
site = envPtr->codeStart + auxPtr->breakTargets[i];
|
||||
offset = rangePtr->breakOffset - auxPtr->breakTargets[i];
|
||||
TclUpdateInstInt4AtPc(INST_JUMP4, offset, site);
|
||||
}
|
||||
for (i=0 ; i<auxPtr->numContinueTargets ; i++) {
|
||||
site = envPtr->codeStart + auxPtr->continueTargets[i];
|
||||
if (rangePtr->continueOffset == -1) {
|
||||
int j;
|
||||
|
||||
/*
|
||||
* WTF? Can't bind, so revert to an INST_CONTINUE. Not enough
|
||||
* space to do anything else.
|
||||
*/
|
||||
|
||||
*site = INST_CONTINUE;
|
||||
for (j=0 ; j<4 ; j++) {
|
||||
*++site = INST_NOP;
|
||||
}
|
||||
} else {
|
||||
offset = rangePtr->continueOffset - auxPtr->continueTargets[i];
|
||||
TclUpdateInstInt4AtPc(INST_JUMP4, offset, site);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop the arrays we were holding the only reference to.
|
||||
*/
|
||||
|
||||
if (auxPtr->breakTargets) {
|
||||
ckfree(auxPtr->breakTargets);
|
||||
auxPtr->breakTargets = NULL;
|
||||
auxPtr->numBreakTargets = 0;
|
||||
}
|
||||
if (auxPtr->continueTargets) {
|
||||
ckfree(auxPtr->continueTargets);
|
||||
auxPtr->continueTargets = NULL;
|
||||
auxPtr->numContinueTargets = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -3766,6 +3947,22 @@ TclFixupForwardJump(
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 0 ; k < envPtr->exceptArrayNext ; k++) {
|
||||
ExceptionAux *auxPtr = &envPtr->exceptAuxArrayPtr[k];
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<auxPtr->numBreakTargets ; i++) {
|
||||
if (jumpFixupPtr->codeOffset < auxPtr->breakTargets[i]) {
|
||||
auxPtr->breakTargets[i] += 3;
|
||||
}
|
||||
}
|
||||
for (i=0 ; i<auxPtr->numContinueTargets ; i++) {
|
||||
if (jumpFixupPtr->codeOffset < auxPtr->continueTargets[i]) {
|
||||
auxPtr->continueTargets[i] += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TIP #280: Adjust the mapping from PC values to the per-command
|
||||
* information about arguments and their line numbers.
|
||||
|
||||
+158
-6
@@ -99,6 +99,54 @@ typedef struct ExceptionRange {
|
||||
* offset for any "exception" in range. */
|
||||
} ExceptionRange;
|
||||
|
||||
/*
|
||||
* Auxiliary data used when issuing (currently just loop) exception ranges,
|
||||
* but which is not required during execution.
|
||||
*/
|
||||
|
||||
typedef struct ExceptionAux {
|
||||
int supportsContinue; /* Whether this exception range will have a
|
||||
* continueOffset created for it; if it is a
|
||||
* loop exception range that *doesn't* have
|
||||
* one (see [for] next-clause) then we must
|
||||
* not pick up the range when scanning for a
|
||||
* target to continue to. */
|
||||
int stackDepth; /* The stack depth at the point where the
|
||||
* exception range was created. This is used
|
||||
* to calculate the number of POPs required to
|
||||
* restore the stack to its prior state. */
|
||||
int expandTarget; /* The number of expansions expected on the
|
||||
* auxData stack at the time the loop starts;
|
||||
* we can't currently discard them except by
|
||||
* doing INST_INVOKE_EXPANDED; this is a known
|
||||
* problem. */
|
||||
int expandTargetDepth; /* The stack depth expected at the outermost
|
||||
* expansion within the loop. Not meaningful
|
||||
* if there are no open expansions between the
|
||||
* looping level and the point of jump
|
||||
* issue. */
|
||||
int numBreakTargets; /* The number of [break]s that want to be
|
||||
* targeted to the place where this loop
|
||||
* exception will be bound to. */
|
||||
int *breakTargets; /* The offsets of the INST_JUMP4 instructions
|
||||
* issued by the [break]s that we must
|
||||
* update. Note that resizing a jump (via
|
||||
* TclFixupForwardJump) can cause the contents
|
||||
* of this array to be updated. When
|
||||
* numBreakTargets==0, this is NULL. */
|
||||
int allocBreakTargets; /* The size of the breakTargets array. */
|
||||
int numContinueTargets; /* The number of [continue]s that want to be
|
||||
* targeted to the place where this loop
|
||||
* exception will be bound to. */
|
||||
int *continueTargets; /* The offsets of the INST_JUMP4 instructions
|
||||
* issued by the [continue]s that we must
|
||||
* update. Note that resizing a jump (via
|
||||
* TclFixupForwardJump) can cause the contents
|
||||
* of this array to be updated. When
|
||||
* numContinueTargets==0, this is NULL. */
|
||||
int allocContinueTargets; /* The size of the continueTargets array. */
|
||||
} ExceptionAux;
|
||||
|
||||
/*
|
||||
* Structure used to map between instruction pc and source locations. It
|
||||
* defines for each compiled Tcl command its code's starting offset and its
|
||||
@@ -275,6 +323,11 @@ typedef struct CompileEnv {
|
||||
* entry. */
|
||||
int mallocedExceptArray; /* 1 if ExceptionRange array was expanded and
|
||||
* exceptArrayPtr points in heap, else 0. */
|
||||
ExceptionAux *exceptAuxArrayPtr;
|
||||
/* Array of information used to restore the
|
||||
* state when processing BREAK/CONTINUE
|
||||
* exceptions. Must be the same size as the
|
||||
* exceptArrayPtr. */
|
||||
CmdLocation *cmdMapPtr; /* Points to start of CmdLocation array.
|
||||
* numCommands is the index of the next entry
|
||||
* to use; (numCommands-1) is the entry index
|
||||
@@ -296,6 +349,9 @@ typedef struct CompileEnv {
|
||||
/* Initial storage of LiteralEntry array. */
|
||||
ExceptionRange staticExceptArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
|
||||
/* Initial ExceptionRange array storage. */
|
||||
ExceptionAux staticExAuxArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
|
||||
/* Initial static except auxiliary info array
|
||||
* storage. */
|
||||
CmdLocation staticCmdMapSpace[COMPILEENV_INIT_CMD_MAP_SIZE];
|
||||
/* Initial storage for cmd location map. */
|
||||
AuxData staticAuxDataArraySpace[COMPILEENV_INIT_AUX_DATA_SIZE];
|
||||
@@ -312,6 +368,10 @@ typedef struct CompileEnv {
|
||||
* inefficient. If set to 2, that instruction
|
||||
* should not be issued at all (by the generic
|
||||
* part of the command compiler). */
|
||||
int expandCount; /* Number of INST_EXPAND_START instructions
|
||||
* encountered that have not yet been paired
|
||||
* with a corresponding
|
||||
* INST_INVOKE_EXPANDED. */
|
||||
ContLineLoc *clLoc; /* If not NULL, the table holding the
|
||||
* locations of the invisible continuation
|
||||
* lines in the input script, to adjust the
|
||||
@@ -717,8 +777,10 @@ typedef struct ByteCode {
|
||||
|
||||
#define INST_LIST_CONCAT 164
|
||||
|
||||
#define INST_EXPAND_DROP 165
|
||||
|
||||
/* The last opcode */
|
||||
#define LAST_INST_OPCODE 164
|
||||
#define LAST_INST_OPCODE 165
|
||||
|
||||
/*
|
||||
* Table describing the Tcl bytecode instructions: their name (for displaying
|
||||
@@ -930,6 +992,8 @@ MODULE_SCOPE ByteCode * TclCompileObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
|
||||
*/
|
||||
|
||||
MODULE_SCOPE void TclCleanupByteCode(ByteCode *codePtr);
|
||||
MODULE_SCOPE void TclCleanupStackForBreakContinue(CompileEnv *envPtr,
|
||||
ExceptionAux *auxPtr);
|
||||
MODULE_SCOPE void TclCompileCmdWord(Tcl_Interp *interp,
|
||||
Tcl_Token *tokenPtr, int count,
|
||||
CompileEnv *envPtr);
|
||||
@@ -984,10 +1048,19 @@ MODULE_SCOPE void TclInitCompileEnv(Tcl_Interp *interp,
|
||||
int numBytes, const CmdFrame *invoker, int word);
|
||||
MODULE_SCOPE void TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr);
|
||||
MODULE_SCOPE void TclInitLiteralTable(LiteralTable *tablePtr);
|
||||
MODULE_SCOPE ExceptionRange *TclGetInnermostExceptionRange(CompileEnv *envPtr,
|
||||
int returnCode, ExceptionAux **auxPtrPtr);
|
||||
MODULE_SCOPE void TclAddLoopBreakFixup(CompileEnv *envPtr,
|
||||
ExceptionAux *auxPtr);
|
||||
MODULE_SCOPE void TclAddLoopContinueFixup(CompileEnv *envPtr,
|
||||
ExceptionAux *auxPtr);
|
||||
MODULE_SCOPE void TclFinalizeLoopExceptionRange(CompileEnv *envPtr,
|
||||
int range);
|
||||
#ifdef TCL_COMPILE_STATS
|
||||
MODULE_SCOPE char * TclLiteralStats(LiteralTable *tablePtr);
|
||||
MODULE_SCOPE int TclLog2(int value);
|
||||
#endif
|
||||
MODULE_SCOPE void TclOptimizeBytecode(CompileEnv *envPtr);
|
||||
#ifdef TCL_COMPILE_DEBUG
|
||||
MODULE_SCOPE void TclPrintByteCodeObj(Tcl_Interp *interp,
|
||||
Tcl_Obj *objPtr);
|
||||
@@ -998,6 +1071,10 @@ MODULE_SCOPE void TclPrintObject(FILE *outFile,
|
||||
Tcl_Obj *objPtr, int maxChars);
|
||||
MODULE_SCOPE void TclPrintSource(FILE *outFile,
|
||||
const char *string, int maxChars);
|
||||
MODULE_SCOPE void TclPushVarName(Tcl_Interp *interp,
|
||||
Tcl_Token *varTokenPtr, CompileEnv *envPtr,
|
||||
int flags, int *localIndexPtr,
|
||||
int *isScalarPtr, int line, int *clNext);
|
||||
MODULE_SCOPE int TclRegisterLiteral(CompileEnv *envPtr,
|
||||
char *bytes, int length, int flags);
|
||||
MODULE_SCOPE void TclReleaseLiteral(Tcl_Interp *interp, Tcl_Obj *objPtr);
|
||||
@@ -1353,15 +1430,19 @@ MODULE_SCOPE Tcl_Obj *TclNewInstNameObj(unsigned char inst);
|
||||
TclCompileTokens((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \
|
||||
(envPtr));
|
||||
/*
|
||||
* Convenience macro for use when pushing literals. The ANSI C "prototype" for
|
||||
* this macro is:
|
||||
* Convenience macros for use when pushing literals. The ANSI C "prototype" for
|
||||
* these macros are:
|
||||
*
|
||||
* static void PushLiteral(CompileEnv *envPtr,
|
||||
* const char *string, int length);
|
||||
* static void PushStringLiteral(CompileEnv *envPtr,
|
||||
* const char *string);
|
||||
*/
|
||||
|
||||
#define PushLiteral(envPtr, string, length) \
|
||||
TclEmitPush(TclRegisterNewLiteral((envPtr), (string), (length)), (envPtr))
|
||||
#define PushStringLiteral(envPtr, string) \
|
||||
PushLiteral((envPtr), (string), (int) (sizeof(string "") - 1))
|
||||
|
||||
/*
|
||||
* Macro to advance to the next token; it is more mnemonic than the address
|
||||
@@ -1390,14 +1471,11 @@ MODULE_SCOPE Tcl_Obj *TclNewInstNameObj(unsigned char inst);
|
||||
* of LOOP ranges is an interesting datum for debugging purposes, and that is
|
||||
* what we compute now.
|
||||
*
|
||||
* static int DeclareExceptionRange(CompileEnv *envPtr, int type);
|
||||
* static int ExceptionRangeStarts(CompileEnv *envPtr, int index);
|
||||
* static void ExceptionRangeEnds(CompileEnv *envPtr, int index);
|
||||
* static void ExceptionRangeTarget(CompileEnv *envPtr, int index, LABEL);
|
||||
*/
|
||||
|
||||
#define DeclareExceptionRange(envPtr, type) \
|
||||
(TclCreateExceptRange((type), (envPtr)))
|
||||
#define ExceptionRangeStarts(envPtr, index) \
|
||||
(((envPtr)->exceptDepth++), \
|
||||
((envPtr)->maxExceptDepth = \
|
||||
@@ -1427,6 +1505,80 @@ MODULE_SCOPE Tcl_Obj *TclNewInstNameObj(unsigned char inst);
|
||||
TclRegisterLiteral(envPtr, Tcl_DStringValue(dsPtr), \
|
||||
Tcl_DStringLength(dsPtr), /*flags*/ 0)
|
||||
|
||||
/*
|
||||
* Macro that encapsulates an efficiency trick that avoids a function call for
|
||||
* the simplest of compiles. The ANSI C "prototype" for this macro is:
|
||||
*
|
||||
* static void CompileWord(CompileEnv *envPtr, Tcl_Token *tokenPtr,
|
||||
* Tcl_Interp *interp, int word);
|
||||
*/
|
||||
|
||||
#define CompileWord(envPtr, tokenPtr, interp, word) \
|
||||
if ((tokenPtr)->type == TCL_TOKEN_SIMPLE_WORD) { \
|
||||
TclEmitPush(TclRegisterNewLiteral((envPtr), (tokenPtr)[1].start, \
|
||||
(tokenPtr)[1].size), (envPtr)); \
|
||||
} else { \
|
||||
envPtr->line = mapPtr->loc[eclIndex].line[word]; \
|
||||
envPtr->clNext = mapPtr->loc[eclIndex].next[word]; \
|
||||
TclCompileTokens((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \
|
||||
(envPtr)); \
|
||||
}
|
||||
|
||||
/*
|
||||
* TIP #280: Remember the per-word line information of the current command. An
|
||||
* index is used instead of a pointer as recursive compilation may reallocate,
|
||||
* i.e. move, the array. This is also the reason to save the nuloc now, it may
|
||||
* change during the course of the function.
|
||||
*
|
||||
* Macro to encapsulate the variable definition and setup.
|
||||
*/
|
||||
|
||||
#define DefineLineInformation \
|
||||
ExtCmdLoc *mapPtr = envPtr->extCmdMapPtr; \
|
||||
int eclIndex = mapPtr->nuloc - 1
|
||||
|
||||
#define SetLineInformation(word) \
|
||||
envPtr->line = mapPtr->loc[eclIndex].line[(word)]; \
|
||||
envPtr->clNext = mapPtr->loc[eclIndex].next[(word)]
|
||||
|
||||
#define PushVarNameWord(i,v,e,f,l,sc,word) \
|
||||
TclPushVarName(i,v,e,f,l,sc, \
|
||||
mapPtr->loc[eclIndex].line[(word)], \
|
||||
mapPtr->loc[eclIndex].next[(word)])
|
||||
|
||||
/*
|
||||
* Often want to issue one of two versions of an instruction based on whether
|
||||
* the argument will fit in a single byte or not. This makes it much clearer.
|
||||
*/
|
||||
|
||||
#define Emit14Inst(nm,idx,envPtr) \
|
||||
if (idx <= 255) { \
|
||||
TclEmitInstInt1(nm##1,idx,envPtr); \
|
||||
} else { \
|
||||
TclEmitInstInt4(nm##4,idx,envPtr); \
|
||||
}
|
||||
|
||||
/*
|
||||
* How to get an anonymous local variable (used for holding temporary values
|
||||
* off the stack) or a local simple scalar.
|
||||
*/
|
||||
|
||||
#define AnonymousLocal(envPtr) \
|
||||
(TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1, (envPtr)))
|
||||
#define LocalScalar(chars,len,envPtr) \
|
||||
(!TclIsLocalScalar((chars), (len)) ? -1 : \
|
||||
TclFindCompiledLocal((chars), (len), /*create*/ 1, (envPtr)))
|
||||
#define LocalScalarFromToken(tokenPtr,envPtr) \
|
||||
((tokenPtr)->type != TCL_TOKEN_SIMPLE_WORD ? -1 : \
|
||||
LocalScalar((tokenPtr)[1].start, (tokenPtr)[1].size, (envPtr)))
|
||||
|
||||
/*
|
||||
* Flags bits used by TclPushVarName.
|
||||
*/
|
||||
|
||||
#define TCL_NO_LARGE_INDEX 1 /* Do not return localIndex value > 255 */
|
||||
#define TCL_NO_ELEMENT 2 /* Do not push the array element. */
|
||||
|
||||
/*
|
||||
* DTrace probe macros (NOPs if DTrace support is not enabled).
|
||||
*/
|
||||
|
||||
+33
-17
@@ -257,7 +257,7 @@ VarHashCreateVar(
|
||||
|
||||
/* Verify the stack depth, only when no expansion is in progress */
|
||||
|
||||
#if TCL_COMPILE_DEBUG
|
||||
#ifdef TCL_COMPILE_DEBUG
|
||||
#define CHECK_STACK() \
|
||||
do { \
|
||||
ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, \
|
||||
@@ -724,7 +724,7 @@ static Tcl_Obj ** GrowEvaluationStack(ExecEnv *eePtr, int growth,
|
||||
static void IllegalExprOperandType(Tcl_Interp *interp,
|
||||
const unsigned char *pc, Tcl_Obj *opndPtr);
|
||||
static void InitByteCodeExecution(Tcl_Interp *interp);
|
||||
static inline int OFFSET(void *ptr);
|
||||
static inline int wordSkip(void *ptr);
|
||||
static void ReleaseDictIterator(Tcl_Obj *objPtr);
|
||||
/* Useful elsewhere, make available in tclInt.h or stubs? */
|
||||
static Tcl_Obj ** StackAllocWords(Tcl_Interp *interp, int numWords);
|
||||
@@ -1001,13 +1001,13 @@ TclFinalizeExecution(void)
|
||||
(TCL_ALLOCALIGN/sizeof(Tcl_Obj *))
|
||||
|
||||
/*
|
||||
* OFFSET computes how many words have to be skipped until the next aligned
|
||||
* wordSkip computes how many words have to be skipped until the next aligned
|
||||
* word. Note that we are only interested in the low order bits of ptr, so
|
||||
* that any possible information loss in PTR2INT is of no consequence.
|
||||
*/
|
||||
|
||||
static inline int
|
||||
OFFSET(
|
||||
wordSkip(
|
||||
void *ptr)
|
||||
{
|
||||
int mask = TCL_ALLOCALIGN-1;
|
||||
@@ -1020,7 +1020,7 @@ OFFSET(
|
||||
*/
|
||||
|
||||
#define MEMSTART(markerPtr) \
|
||||
((markerPtr) + OFFSET(markerPtr))
|
||||
((markerPtr) + wordSkip(markerPtr))
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -1065,7 +1065,7 @@ GrowEvaluationStack(
|
||||
} else {
|
||||
#ifndef PURIFY
|
||||
Tcl_Obj **tmpMarkerPtr = esPtr->tosPtr + 1;
|
||||
int offset = OFFSET(tmpMarkerPtr);
|
||||
int offset = wordSkip(tmpMarkerPtr);
|
||||
|
||||
if (needed + offset < 0) {
|
||||
/*
|
||||
@@ -2142,11 +2142,6 @@ TEBCresume(
|
||||
|
||||
CACHE_STACK_INFO();
|
||||
if (result == TCL_OK) {
|
||||
#ifndef TCL_COMPILE_DEBUG
|
||||
if (*pc == INST_POP) {
|
||||
NEXT_INST_V(1, cleanup, 0);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Push the call's object result and continue execution with the
|
||||
* next instruction.
|
||||
@@ -2155,8 +2150,6 @@ TEBCresume(
|
||||
TRACE_WITH_OBJ(("%u => ... after \"%.20s\": TCL_OK, result=",
|
||||
objc, cmdNameBuf), Tcl_GetObjResult(interp));
|
||||
|
||||
objResultPtr = Tcl_GetObjResult(interp);
|
||||
|
||||
/*
|
||||
* Reset the interp's result to avoid possible duplications of
|
||||
* large objects [Bug 781585]. We do not call Tcl_ResetResult to
|
||||
@@ -2168,9 +2161,16 @@ TEBCresume(
|
||||
* the refCount it had in its role of iPtr->objResultPtr.
|
||||
*/
|
||||
|
||||
objResultPtr = Tcl_GetObjResult(interp);
|
||||
TclNewObj(objPtr);
|
||||
Tcl_IncrRefCount(objPtr);
|
||||
iPtr->objResultPtr = objPtr;
|
||||
#ifndef TCL_COMPILE_DEBUG
|
||||
if (*pc == INST_POP) {
|
||||
TclDecrRefCount(objResultPtr);
|
||||
NEXT_INST_V(1, cleanup, 0);
|
||||
}
|
||||
#endif
|
||||
NEXT_INST_V(0, cleanup, -1);
|
||||
}
|
||||
|
||||
@@ -2630,7 +2630,7 @@ TEBCresume(
|
||||
Tcl_Panic("max size for a Tcl value (%d bytes) exceeded",
|
||||
INT_MAX);
|
||||
}
|
||||
#if !TCL_COMPILE_DEBUG
|
||||
#ifndef TCL_COMPILE_DEBUG
|
||||
if (bytes != tclEmptyStringRep && !Tcl_IsShared(objResultPtr)) {
|
||||
TclFreeIntRep(objResultPtr);
|
||||
objResultPtr->bytes = ckrealloc(bytes, length+appendLen+1);
|
||||
@@ -2666,7 +2666,7 @@ TEBCresume(
|
||||
Tcl_Panic("max size for a Tcl value (%d bytes) exceeded",
|
||||
INT_MAX);
|
||||
}
|
||||
#if !TCL_COMPILE_DEBUG
|
||||
#ifndef TCL_COMPILE_DEBUG
|
||||
if (!Tcl_IsShared(objResultPtr)) {
|
||||
bytes = (char *) Tcl_SetByteArrayLength(objResultPtr,
|
||||
length + appendLen);
|
||||
@@ -2718,6 +2718,22 @@ TEBCresume(
|
||||
PUSH_TAUX_OBJ(objPtr);
|
||||
NEXT_INST_F(1, 0, 0);
|
||||
|
||||
case INST_EXPAND_DROP:
|
||||
/*
|
||||
* Drops an element of the auxObjList, popping stack elements to
|
||||
* restore the stack to the state before the point where the aux
|
||||
* element was created.
|
||||
*/
|
||||
|
||||
CLANG_ASSERT(auxObjList);
|
||||
objc = CURR_DEPTH - auxObjList->internalRep.ptrAndLongRep.value;
|
||||
POP_TAUX_OBJ();
|
||||
#ifdef TCL_COMPILE_DEBUG
|
||||
/* Ugly abuse! */
|
||||
starting = 1;
|
||||
#endif
|
||||
NEXT_INST_V(1, objc, 0);
|
||||
|
||||
case INST_EXPAND_STKTOP: {
|
||||
int i;
|
||||
ptrdiff_t moved;
|
||||
@@ -6824,7 +6840,7 @@ TEBCresume(
|
||||
*/
|
||||
|
||||
processExceptionReturn:
|
||||
#if TCL_COMPILE_DEBUG
|
||||
#ifdef TCL_COMPILE_DEBUG
|
||||
switch (*pc) {
|
||||
case INST_INVOKE_STK1:
|
||||
opnd = TclGetUInt1AtPtr(pc+1);
|
||||
@@ -6881,7 +6897,7 @@ TEBCresume(
|
||||
rangePtr->codeOffset, rangePtr->continueOffset));
|
||||
NEXT_INST_F(0, 0, 0);
|
||||
}
|
||||
#if TCL_COMPILE_DEBUG
|
||||
#ifdef TCL_COMPILE_DEBUG
|
||||
if (traceInstructions) {
|
||||
objPtr = Tcl_GetObjResult(interp);
|
||||
if ((result != TCL_ERROR) && (result != TCL_RETURN)) {
|
||||
|
||||
@@ -3225,6 +3225,9 @@ Tcl_LoadFile(
|
||||
*/
|
||||
|
||||
copyToPtr = TclpTempFileNameForLibrary(interp, pathPtr);
|
||||
if (copyToPtr == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_IncrRefCount(copyToPtr);
|
||||
|
||||
copyFsPtr = Tcl_FSGetFileSystemForPath(copyToPtr);
|
||||
|
||||
@@ -3094,6 +3094,7 @@ MODULE_SCOPE int TclTrimLeft(const char *bytes, int numBytes,
|
||||
const char *trim, int numTrim);
|
||||
MODULE_SCOPE int TclTrimRight(const char *bytes, int numBytes,
|
||||
const char *trim, int numTrim);
|
||||
MODULE_SCOPE int TclUtfCasecmp(const char *cs, const char *ct);
|
||||
MODULE_SCOPE Tcl_Obj * TclpNativeToNormalized(ClientData clientData);
|
||||
MODULE_SCOPE Tcl_Obj * TclpFilesystemPathType(Tcl_Obj *pathPtr);
|
||||
MODULE_SCOPE int TclpDlopen(Tcl_Interp *interp, Tcl_Obj *pathPtr,
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* tclOptimize.c --
|
||||
*
|
||||
* This file contains the bytecode optimizer.
|
||||
*
|
||||
* Copyright (c) 2013 by Donal Fellows.
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution of
|
||||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
#include "tclInt.h"
|
||||
#include "tclCompile.h"
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
|
||||
static void AdvanceJumps(CompileEnv *envPtr);
|
||||
static void ConvertZeroEffectToNOP(CompileEnv *envPtr);
|
||||
static void LocateTargetAddresses(CompileEnv *envPtr,
|
||||
Tcl_HashTable *tablePtr);
|
||||
static void TrimUnreachable(CompileEnv *envPtr);
|
||||
|
||||
/*
|
||||
* Helper macros.
|
||||
*/
|
||||
|
||||
#define DefineTargetAddress(tablePtr, address) \
|
||||
((void) Tcl_CreateHashEntry((tablePtr), (void *) (address), &isNew))
|
||||
#define IsTargetAddress(tablePtr, address) \
|
||||
(Tcl_FindHashEntry((tablePtr), (void *) (address)) != NULL)
|
||||
#define AddrLength(address) \
|
||||
(tclInstructionTable[*(unsigned char *)(address)].numBytes)
|
||||
#define InstLength(instruction) \
|
||||
(tclInstructionTable[(unsigned char)(instruction)].numBytes)
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* LocateTargetAddresses --
|
||||
*
|
||||
* Populate a hash table with places that we need to be careful around
|
||||
* because they're the targets of various kinds of jumps and other
|
||||
* non-local behavior.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
LocateTargetAddresses(
|
||||
CompileEnv *envPtr,
|
||||
Tcl_HashTable *tablePtr)
|
||||
{
|
||||
unsigned char *currentInstPtr, *targetInstPtr;
|
||||
int isNew, i;
|
||||
Tcl_HashEntry *hPtr;
|
||||
Tcl_HashSearch hSearch;
|
||||
|
||||
Tcl_InitHashTable(tablePtr, TCL_ONE_WORD_KEYS);
|
||||
|
||||
/*
|
||||
* The starts of commands represent target addresses.
|
||||
*/
|
||||
|
||||
for (i=0 ; i<envPtr->numCommands ; i++) {
|
||||
DefineTargetAddress(tablePtr,
|
||||
envPtr->codeStart + envPtr->cmdMapPtr[i].codeOffset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find places where we should be careful about replacing instructions
|
||||
* because they are the targets of various types of jumps.
|
||||
*/
|
||||
|
||||
for (currentInstPtr = envPtr->codeStart ;
|
||||
currentInstPtr < envPtr->codeNext ;
|
||||
currentInstPtr += AddrLength(currentInstPtr)) {
|
||||
switch (*currentInstPtr) {
|
||||
case INST_JUMP1:
|
||||
case INST_JUMP_TRUE1:
|
||||
case INST_JUMP_FALSE1:
|
||||
targetInstPtr = currentInstPtr+TclGetInt1AtPtr(currentInstPtr+1);
|
||||
goto storeTarget;
|
||||
case INST_JUMP4:
|
||||
case INST_JUMP_TRUE4:
|
||||
case INST_JUMP_FALSE4:
|
||||
targetInstPtr = currentInstPtr+TclGetInt4AtPtr(currentInstPtr+1);
|
||||
goto storeTarget;
|
||||
case INST_BEGIN_CATCH4:
|
||||
targetInstPtr = envPtr->codeStart + envPtr->exceptArrayPtr[
|
||||
TclGetUInt4AtPtr(currentInstPtr+1)].codeOffset;
|
||||
storeTarget:
|
||||
DefineTargetAddress(tablePtr, targetInstPtr);
|
||||
break;
|
||||
case INST_JUMP_TABLE:
|
||||
hPtr = Tcl_FirstHashEntry(
|
||||
&JUMPTABLEINFO(envPtr, currentInstPtr+1)->hashTable,
|
||||
&hSearch);
|
||||
for (; hPtr ; hPtr = Tcl_NextHashEntry(&hSearch)) {
|
||||
targetInstPtr = currentInstPtr +
|
||||
PTR2INT(Tcl_GetHashValue(hPtr));
|
||||
DefineTargetAddress(tablePtr, targetInstPtr);
|
||||
}
|
||||
break;
|
||||
case INST_RETURN_CODE_BRANCH:
|
||||
for (i=TCL_ERROR ; i<TCL_CONTINUE+1 ; i++) {
|
||||
DefineTargetAddress(tablePtr, currentInstPtr + 2*i - 1);
|
||||
}
|
||||
break;
|
||||
case INST_START_CMD:
|
||||
assert (envPtr->atCmdStart < 2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a marker *after* the last bytecode instruction. WARNING: points to
|
||||
* one past the end!
|
||||
*/
|
||||
|
||||
DefineTargetAddress(tablePtr, currentInstPtr);
|
||||
|
||||
/*
|
||||
* Enter in the targets of exception ranges.
|
||||
*/
|
||||
|
||||
for (i=0 ; i<envPtr->exceptArrayNext ; i++) {
|
||||
ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[i];
|
||||
|
||||
if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
|
||||
targetInstPtr = envPtr->codeStart + rangePtr->catchOffset;
|
||||
DefineTargetAddress(tablePtr, targetInstPtr);
|
||||
} else {
|
||||
targetInstPtr = envPtr->codeStart + rangePtr->breakOffset;
|
||||
DefineTargetAddress(tablePtr, targetInstPtr);
|
||||
if (rangePtr->continueOffset >= 0) {
|
||||
targetInstPtr = envPtr->codeStart + rangePtr->continueOffset;
|
||||
DefineTargetAddress(tablePtr, targetInstPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* TrimUnreachable --
|
||||
*
|
||||
* Converts code that provably can't be executed into NOPs and reduces
|
||||
* the overall reported length of the bytecode where that is possible.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
TrimUnreachable(
|
||||
CompileEnv *envPtr)
|
||||
{
|
||||
unsigned char *currentInstPtr;
|
||||
Tcl_HashTable targets;
|
||||
|
||||
LocateTargetAddresses(envPtr, &targets);
|
||||
|
||||
for (currentInstPtr = envPtr->codeStart ;
|
||||
currentInstPtr < envPtr->codeNext-1 ;
|
||||
currentInstPtr += AddrLength(currentInstPtr)) {
|
||||
int clear = 0;
|
||||
|
||||
if (*currentInstPtr != INST_DONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (!IsTargetAddress(&targets, currentInstPtr + 1 + clear)) {
|
||||
clear += AddrLength(currentInstPtr + 1 + clear);
|
||||
}
|
||||
if (currentInstPtr + 1 + clear == envPtr->codeNext) {
|
||||
envPtr->codeNext -= clear;
|
||||
} else {
|
||||
while (clear --> 0) {
|
||||
*(currentInstPtr + 1 + clear) = INST_NOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_DeleteHashTable(&targets);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* ConvertZeroEffectToNOP --
|
||||
*
|
||||
* Replace PUSH/POP sequences (when non-hazardous) with NOPs. Also
|
||||
* replace PUSH empty/CONCAT and TRY_CVT_NUMERIC (when followed by an
|
||||
* operation that guarantees the check for arithmeticity) and eliminate
|
||||
* LNOT when we can invert the following JUMP condition.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
ConvertZeroEffectToNOP(
|
||||
CompileEnv *envPtr)
|
||||
{
|
||||
unsigned char *currentInstPtr;
|
||||
int size;
|
||||
Tcl_HashTable targets;
|
||||
|
||||
LocateTargetAddresses(envPtr, &targets);
|
||||
for (currentInstPtr = envPtr->codeStart ;
|
||||
currentInstPtr < envPtr->codeNext ; currentInstPtr += size) {
|
||||
int blank = 0, i, nextInst;
|
||||
|
||||
size = AddrLength(currentInstPtr);
|
||||
while (*(currentInstPtr+size) == INST_NOP) {
|
||||
if (IsTargetAddress(&targets, currentInstPtr + size)) {
|
||||
break;
|
||||
}
|
||||
size += InstLength(INST_NOP);
|
||||
}
|
||||
if (IsTargetAddress(&targets, currentInstPtr + size)) {
|
||||
continue;
|
||||
}
|
||||
nextInst = *(currentInstPtr + size);
|
||||
switch (*currentInstPtr) {
|
||||
case INST_PUSH1:
|
||||
if (nextInst == INST_POP) {
|
||||
blank = size + InstLength(nextInst);
|
||||
} else if (nextInst == INST_CONCAT1
|
||||
&& TclGetUInt1AtPtr(currentInstPtr + size + 1) == 2) {
|
||||
Tcl_Obj *litPtr = TclFetchLiteral(envPtr,
|
||||
TclGetUInt1AtPtr(currentInstPtr + 1));
|
||||
int numBytes;
|
||||
|
||||
(void) Tcl_GetStringFromObj(litPtr, &numBytes);
|
||||
if (numBytes == 0) {
|
||||
blank = size + InstLength(nextInst);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case INST_PUSH4:
|
||||
if (nextInst == INST_POP) {
|
||||
blank = size + 1;
|
||||
} else if (nextInst == INST_CONCAT1
|
||||
&& TclGetUInt1AtPtr(currentInstPtr + size + 1) == 2) {
|
||||
Tcl_Obj *litPtr = TclFetchLiteral(envPtr,
|
||||
TclGetUInt4AtPtr(currentInstPtr + 1));
|
||||
int numBytes;
|
||||
|
||||
(void) Tcl_GetStringFromObj(litPtr, &numBytes);
|
||||
if (numBytes == 0) {
|
||||
blank = size + InstLength(nextInst);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case INST_LNOT:
|
||||
switch (nextInst) {
|
||||
case INST_JUMP_TRUE1:
|
||||
blank = size;
|
||||
*(currentInstPtr + size) = INST_JUMP_FALSE1;
|
||||
break;
|
||||
case INST_JUMP_FALSE1:
|
||||
blank = size;
|
||||
*(currentInstPtr + size) = INST_JUMP_TRUE1;
|
||||
break;
|
||||
case INST_JUMP_TRUE4:
|
||||
blank = size;
|
||||
*(currentInstPtr + size) = INST_JUMP_FALSE4;
|
||||
break;
|
||||
case INST_JUMP_FALSE4:
|
||||
blank = size;
|
||||
*(currentInstPtr + size) = INST_JUMP_TRUE4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case INST_TRY_CVT_TO_NUMERIC:
|
||||
switch (nextInst) {
|
||||
case INST_JUMP_TRUE1:
|
||||
case INST_JUMP_TRUE4:
|
||||
case INST_JUMP_FALSE1:
|
||||
case INST_JUMP_FALSE4:
|
||||
case INST_INCR_SCALAR1:
|
||||
case INST_INCR_ARRAY1:
|
||||
case INST_INCR_ARRAY_STK:
|
||||
case INST_INCR_SCALAR_STK:
|
||||
case INST_INCR_STK:
|
||||
case INST_LOR:
|
||||
case INST_LAND:
|
||||
case INST_EQ:
|
||||
case INST_NEQ:
|
||||
case INST_LT:
|
||||
case INST_LE:
|
||||
case INST_GT:
|
||||
case INST_GE:
|
||||
case INST_MOD:
|
||||
case INST_LSHIFT:
|
||||
case INST_RSHIFT:
|
||||
case INST_BITOR:
|
||||
case INST_BITXOR:
|
||||
case INST_BITAND:
|
||||
case INST_EXPON:
|
||||
case INST_ADD:
|
||||
case INST_SUB:
|
||||
case INST_DIV:
|
||||
case INST_MULT:
|
||||
case INST_LNOT:
|
||||
case INST_BITNOT:
|
||||
case INST_UMINUS:
|
||||
case INST_UPLUS:
|
||||
case INST_TRY_CVT_TO_NUMERIC:
|
||||
blank = size;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (blank > 0) {
|
||||
for (i=0 ; i<blank ; i++) {
|
||||
*(currentInstPtr + i) = INST_NOP;
|
||||
}
|
||||
size = blank;
|
||||
}
|
||||
}
|
||||
Tcl_DeleteHashTable(&targets);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* AdvanceJumps --
|
||||
*
|
||||
* Advance jumps past NOPs and chained JUMPs. After this runs, the only
|
||||
* JUMPs that jump to a NOP or a JUMP will be length-1 ones that run out
|
||||
* of room in their opcode to be targeted to where they really belong.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
AdvanceJumps(
|
||||
CompileEnv *envPtr)
|
||||
{
|
||||
unsigned char *currentInstPtr;
|
||||
|
||||
for (currentInstPtr = envPtr->codeStart ;
|
||||
currentInstPtr < envPtr->codeNext-1 ;
|
||||
currentInstPtr += AddrLength(currentInstPtr)) {
|
||||
int offset, delta;
|
||||
|
||||
switch (*currentInstPtr) {
|
||||
case INST_JUMP1:
|
||||
case INST_JUMP_TRUE1:
|
||||
case INST_JUMP_FALSE1:
|
||||
offset = TclGetInt1AtPtr(currentInstPtr + 1);
|
||||
for (delta=0 ; offset+delta != 0 ;) {
|
||||
if (offset + delta < -128 || offset + delta > 127) {
|
||||
break;
|
||||
}
|
||||
offset += delta;
|
||||
switch (*(currentInstPtr + offset)) {
|
||||
case INST_NOP:
|
||||
delta = InstLength(INST_NOP);
|
||||
continue;
|
||||
case INST_JUMP1:
|
||||
delta = TclGetInt1AtPtr(currentInstPtr + offset + 1);
|
||||
continue;
|
||||
case INST_JUMP4:
|
||||
delta = TclGetInt4AtPtr(currentInstPtr + offset + 1);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
TclStoreInt1AtPtr(offset, currentInstPtr + 1);
|
||||
continue;
|
||||
|
||||
case INST_JUMP4:
|
||||
case INST_JUMP_TRUE4:
|
||||
case INST_JUMP_FALSE4:
|
||||
for (offset = TclGetInt4AtPtr(currentInstPtr + 1); offset!=0 ;) {
|
||||
switch (*(currentInstPtr + offset)) {
|
||||
case INST_NOP:
|
||||
offset += InstLength(INST_NOP);
|
||||
continue;
|
||||
case INST_JUMP1:
|
||||
offset += TclGetInt1AtPtr(currentInstPtr + offset + 1);
|
||||
continue;
|
||||
case INST_JUMP4:
|
||||
offset += TclGetInt4AtPtr(currentInstPtr + offset + 1);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
TclStoreInt4AtPtr(offset, currentInstPtr + 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* TclOptimizeBytecode --
|
||||
*
|
||||
* A very simple peephole optimizer for bytecode.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
TclOptimizeBytecode(
|
||||
CompileEnv *envPtr)
|
||||
{
|
||||
ConvertZeroEffectToNOP(envPtr);
|
||||
AdvanceJumps(envPtr);
|
||||
TrimUnreachable(envPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: c
|
||||
* c-basic-offset: 4
|
||||
* fill-column: 78
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -1102,6 +1102,46 @@ Tcl_UtfNcasecmp(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_UtfNcasecmp --
|
||||
*
|
||||
* Compare UTF chars of string cs to string ct case insensitively.
|
||||
* Replacement for strcasecmp in Tcl core, in places where UTF-8 should
|
||||
* be handled.
|
||||
*
|
||||
* Results:
|
||||
* Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclUtfCasecmp(
|
||||
const char *cs, /* UTF string to compare to ct. */
|
||||
const char *ct) /* UTF string cs is compared to. */
|
||||
{
|
||||
while (*cs && *ct) {
|
||||
Tcl_UniChar ch1, ch2;
|
||||
|
||||
cs += TclUtfToUniChar(cs, &ch1);
|
||||
ct += TclUtfToUniChar(ct, &ch2);
|
||||
if (ch1 != ch2) {
|
||||
ch1 = Tcl_UniCharToLower(ch1);
|
||||
ch2 = Tcl_UniCharToLower(ch2);
|
||||
if (ch1 != ch2) {
|
||||
return ch1 - ch2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UCHAR(*cs) - UCHAR(*ct);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
|
||||
+22
-17
@@ -13,7 +13,7 @@
|
||||
package require Tcl 8.5
|
||||
# When the version number changes, be sure to update the pkgIndex.tcl file,
|
||||
# and the installation directory in the Makefiles.
|
||||
package provide msgcat 1.5.1
|
||||
package provide msgcat 1.5.2
|
||||
|
||||
namespace eval msgcat {
|
||||
namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \
|
||||
@@ -541,8 +541,11 @@ proc msgcat::Init {} {
|
||||
# settings, or fall back on locale of "C".
|
||||
#
|
||||
|
||||
# First check registry value LocalName present from Windows Vista
|
||||
# which contains the local string as RFC5646, composed of:
|
||||
# On Vista and later:
|
||||
# HCU/Control Panel/Desktop : PreferredUILanguages is for language packs,
|
||||
# HCU/Control Pannel/International : localName is the default locale.
|
||||
#
|
||||
# They contain the local string as RFC5646, composed of:
|
||||
# [a-z]{2,3} : language
|
||||
# -[a-z]{4} : script (optional, translated by table Latn->latin)
|
||||
# -[a-z]{2}|[0-9]{3} : territory (optional, numerical region codes not used)
|
||||
@@ -550,23 +553,25 @@ proc msgcat::Init {} {
|
||||
# Those are translated to local strings.
|
||||
# Examples: de-CH -> de_ch, sr-Latn-CS -> sr_cs@latin, es-419 -> es
|
||||
#
|
||||
set key {HKEY_CURRENT_USER\Control Panel\International}
|
||||
if {![catch {registry get $key LocaleName} localeName]
|
||||
&& [regexp {^([a-z]{2,3})(?:-([a-z]{4}))?(?:-([a-z]{2}))?(?:-.+)?$}\
|
||||
[string tolower $localeName] match locale script territory]} {
|
||||
if {"" ne $territory} {
|
||||
append locale _ $territory
|
||||
}
|
||||
set modifierDict [dict create latn latin cyrl cyrillic]
|
||||
if {[dict exists $modifierDict $script]} {
|
||||
append locale @ [dict get $modifierDict $script]
|
||||
}
|
||||
if {![catch {mclocale [ConvertLocale $locale]}]} {
|
||||
return
|
||||
foreach key {{HKEY_CURRENT_USER\Control Panel\Desktop} {HKEY_CURRENT_USER\Control Panel\International}}\
|
||||
value {PreferredUILanguages localeName} {
|
||||
if {![catch {registry get $key $value} localeName]
|
||||
&& [regexp {^([a-z]{2,3})(?:-([a-z]{4}))?(?:-([a-z]{2}))?(?:-.+)?$}\
|
||||
[string tolower $localeName] match locale script territory]} {
|
||||
if {"" ne $territory} {
|
||||
append locale _ $territory
|
||||
}
|
||||
set modifierDict [dict create latn latin cyrl cyrillic]
|
||||
if {[dict exists $modifierDict $script]} {
|
||||
append locale @ [dict get $modifierDict $script]
|
||||
}
|
||||
if {![catch {mclocale [ConvertLocale $locale]}]} {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# then check key locale which contains a numerical language ID
|
||||
# then check value locale which contains a numerical language ID
|
||||
if {[catch {
|
||||
set locale [registry get $key "locale"]
|
||||
}]} {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
if {![package vsatisfies [package provide Tcl] 8.5]} {return}
|
||||
package ifneeded msgcat 1.5.1 [list source [file join $dir msgcat.tcl]]
|
||||
package ifneeded msgcat 1.5.2 [list source [file join $dir msgcat.tcl]]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package ifneeded platform 1.0.11 [list source [file join $dir platform.tcl]]
|
||||
package ifneeded platform 1.0.12 [list source [file join $dir platform.tcl]]
|
||||
package ifneeded platform::shell 1.1.4 [list source [file join $dir shell.tcl]]
|
||||
|
||||
|
||||
@@ -417,6 +417,15 @@ test cmdIL-4.34 {SortCompare procedure, -ascii option with -nocase option} {
|
||||
test cmdIL-4.35 {SortCompare procedure, -ascii option with -nocase option} {
|
||||
lsort -ascii -nocase {d E c B a D35 d300 100 20}
|
||||
} {100 20 a B c d d300 D35 E}
|
||||
test cmdIL-4.36 {SortCompare procedure, UTF-8 with -nocase option} {
|
||||
scan [lsort -ascii -nocase [list \u101 \u100]] %c%c%c
|
||||
} {257 32 256}
|
||||
test cmdIL-4.37 {SortCompare procedure, UTF-8 with -nocase option} {
|
||||
scan [lsort -ascii -nocase [list a\u0000a a]] %c%c%c%c%c
|
||||
} {97 32 97 0 97}
|
||||
test cmdIL-4.38 {SortCompare procedure, UTF-8 with -nocase option} {
|
||||
scan [lsort -ascii -nocase [list a a\u0000a]] %c%c%c%c%c
|
||||
} {97 32 97 0 97}
|
||||
|
||||
test cmdIL-5.1 {lsort with list style index} {
|
||||
lsort -ascii -decreasing -index {0 1} {
|
||||
|
||||
@@ -707,6 +707,12 @@ test compile-18.19 {disassembler - basics} -setup {
|
||||
} -cleanup {
|
||||
foo destroy
|
||||
} -match glob -result *
|
||||
|
||||
test compile-19.0 {Bug 3614102: reset stack housekeeping} -body {
|
||||
# This will panic in a --enable-symbols=compile build, unless bug is fixed.
|
||||
apply {{} {list [if 1]}}
|
||||
} -returnCodes error -match glob -result *
|
||||
|
||||
# TODO sometime - check that bytecode from tbcload is *not* disassembled.
|
||||
|
||||
# cleanup
|
||||
|
||||
@@ -668,6 +668,24 @@ test dict-14.20 {dict for stack space compilation: bug 1903325} {
|
||||
concat "c=$y,$args"
|
||||
}} {} 1 2 3
|
||||
} {c=1,2 3}
|
||||
test dict-14.21 {compiled dict for and break} {
|
||||
apply {{} {
|
||||
dict for {a b} {c d e f} {
|
||||
lappend result $a,$b
|
||||
break
|
||||
}
|
||||
return $result
|
||||
}}
|
||||
} c,d
|
||||
test dict-14.22 {dict for and exception range depths: Bug 3614382} {
|
||||
apply {{} {
|
||||
dict for {a b} {c d} {
|
||||
dict for {e f} {g h} {
|
||||
return 5
|
||||
}
|
||||
}
|
||||
}}
|
||||
} 5
|
||||
# There's probably a lot more tests to add here. Really ought to use a
|
||||
# coverage tool for this job...
|
||||
|
||||
|
||||
+137
-9
@@ -17,6 +17,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} {
|
||||
}
|
||||
|
||||
testConstraint memory [llength [info commands memory]]
|
||||
customMatch pairwise {apply {{a b} {
|
||||
string equal [lindex $b 0] [lindex $b 1]
|
||||
}}}
|
||||
namespace eval ::tcl::test::error {
|
||||
if {[testConstraint memory]} {
|
||||
proc getbytes {} {
|
||||
@@ -601,21 +604,21 @@ test error-16.7 {try with variable assignment and propagation #2} {
|
||||
}
|
||||
list $em [dict get $opts -errorcode]
|
||||
} {bar FOO}
|
||||
test error-16.8 {exception chaining (try=ok, handler=error)} {
|
||||
test error-16.8 {exception chaining (try=ok, handler=error)} -body {
|
||||
#FIXME is the intent of this test correct?
|
||||
catch {
|
||||
try { list a b c } on ok {em opts} { throw BAR baz }
|
||||
} tryem tryopts
|
||||
string equal $opts [dict get $tryopts -during]
|
||||
} {1}
|
||||
test error-16.9 {exception chaining (try=error, handler=error)} {
|
||||
list $opts [dict get $tryopts -during]
|
||||
} -match pairwise -result equal
|
||||
test error-16.9 {exception chaining (try=error, handler=error)} -body {
|
||||
# The exception off the handler should chain to the exception off the
|
||||
# try-body (using the -during option)
|
||||
catch {
|
||||
try { throw FOO bar } trap {} {em opts} { throw BAR baz }
|
||||
} tryem tryopts
|
||||
string equal $opts [dict get $tryopts -during]
|
||||
} {1}
|
||||
list $opts [dict get $tryopts -during]
|
||||
} -match pairwise -result equal
|
||||
test error-16.10 {no exception chaining when handler is successful} {
|
||||
catch {
|
||||
try { throw FOO bar } trap {} {em opts} { list d e f }
|
||||
@@ -628,6 +631,131 @@ test error-16.11 {no exception chaining when handler is a non-error exception} {
|
||||
} tryem tryopts
|
||||
dict exists $tryopts -during
|
||||
} {0}
|
||||
test error-16.12 {compiled try with successfully executed handler} {
|
||||
apply {{} {
|
||||
try { throw FOO bar } trap FOO {} { list a b c }
|
||||
}}
|
||||
} {a b c}
|
||||
test error-16.13 {compiled try with exception (error) in handler} -body {
|
||||
apply {{} {
|
||||
try { throw FOO bar } trap FOO {} { throw BAR foo }
|
||||
}}
|
||||
} -returnCodes error -result {foo}
|
||||
test error-16.14 {compiled try with exception (return) in handler} -body {
|
||||
apply {{} {
|
||||
list [catch {
|
||||
try { throw FOO bar } trap FOO {} { return BAR }
|
||||
} msg] $msg
|
||||
}}
|
||||
} -result {2 BAR}
|
||||
test error-16.15 {compiled try with exception (break) in handler} {
|
||||
apply {{} {
|
||||
for { set i 5 } { $i < 10 } { incr i } {
|
||||
try { throw FOO bar } trap FOO {} { break }
|
||||
}
|
||||
return $i
|
||||
}}
|
||||
} {5}
|
||||
test error-16.16 {compiled try with exception (continue) in handler} {
|
||||
apply {{} {
|
||||
for { set i 5 } { $i < 10 } { incr i } {
|
||||
try { throw FOO bar } trap FOO {} { continue }
|
||||
incr i 20
|
||||
}
|
||||
return $i
|
||||
}}
|
||||
} {10}
|
||||
test error-16.17 {compiled try with variable assignment and propagation #1} {
|
||||
# Ensure that the handler variables preserve the exception off the
|
||||
# try-body, and are not modified by the exception off the handler
|
||||
apply {{} {
|
||||
catch {
|
||||
try { throw FOO bar } trap FOO {em} { throw BAR baz }
|
||||
}
|
||||
return $em
|
||||
}}
|
||||
} {bar}
|
||||
test error-16.18 {compiled try with variable assignment and propagation #2} {
|
||||
apply {{} {
|
||||
catch {
|
||||
try { throw FOO bar } trap FOO {em opts} { throw BAR baz }
|
||||
}
|
||||
list $em [dict get $opts -errorcode]
|
||||
}}
|
||||
} {bar FOO}
|
||||
test error-16.19 {compiled try exception chaining (try=ok, handler=error)} -body {
|
||||
#FIXME is the intent of this test correct?
|
||||
apply {{} {
|
||||
catch {
|
||||
try { list a b c } on ok {em opts} { throw BAR baz }
|
||||
} tryem tryopts
|
||||
list $opts [dict get $tryopts -during]
|
||||
}}
|
||||
} -match pairwise -result equal
|
||||
test error-16.20 {compiled try exception chaining (try=error, handler=error)} -body {
|
||||
# The exception off the handler should chain to the exception off the
|
||||
# try-body (using the -during option)
|
||||
apply {{} {
|
||||
catch {
|
||||
try { throw FOO bar } trap {} {em opts} { throw BAR baz }
|
||||
} tryem tryopts
|
||||
list $opts [dict get $tryopts -during]
|
||||
}}
|
||||
} -match pairwise -result equal
|
||||
test error-16.21 {compiled try exception chaining (try=error, finally=error)} {
|
||||
# The exception off the handler should chain to the exception off the
|
||||
# try-body (using the -during option)
|
||||
apply {{} {
|
||||
catch {
|
||||
try { throw FOO bar } finally { throw BAR baz }
|
||||
} tryem tryopts
|
||||
dict get $tryopts -during -errorcode
|
||||
}}
|
||||
} FOO
|
||||
test error-16.22 {compiled try: no exception chaining when handler is successful} {
|
||||
apply {{} {
|
||||
catch {
|
||||
try { throw FOO bar } trap {} {em opts} { list d e f }
|
||||
} tryem tryopts
|
||||
dict exists $tryopts -during
|
||||
}}
|
||||
} {0}
|
||||
test error-16.23 {compiled try: no exception chaining when handler is a non-error exception} {
|
||||
apply {{} {
|
||||
catch {
|
||||
try { throw FOO bar } trap {} {em opts} { break }
|
||||
} tryem tryopts
|
||||
dict exists $tryopts -during
|
||||
}}
|
||||
} {0}
|
||||
test error-16.24 {compiled try exception chaining (try=ok, handler=error, finally=error)} -body {
|
||||
apply {{} {
|
||||
catch {
|
||||
try {
|
||||
list a b c
|
||||
} on ok {em opts} {
|
||||
throw BAR baz
|
||||
} finally {
|
||||
throw DING dong
|
||||
}
|
||||
} tryem tryopts
|
||||
list $opts [dict get $tryopts -during -during]
|
||||
}}
|
||||
} -match pairwise -result equal
|
||||
test error-16.25 {compiled try exception chaining (all errors)} -body {
|
||||
apply {{} {
|
||||
catch {
|
||||
try {
|
||||
throw FOO bar
|
||||
} on error {em opts} {
|
||||
throw BAR baz
|
||||
} finally {
|
||||
throw DING dong
|
||||
}
|
||||
} tryem tryopts
|
||||
list $opts [dict get $tryopts -during -during]
|
||||
}}
|
||||
} -match pairwise -result equal
|
||||
|
||||
# try tests - finally
|
||||
|
||||
@@ -709,15 +837,15 @@ test error-18.5 {exception in finally doesn't affect variable assignment} {
|
||||
}
|
||||
list $em [dict get $opts -errorcode]
|
||||
} {bar FOO}
|
||||
test error-18.6 {exception chaining in finally (try=ok)} {
|
||||
test error-18.6 {exception chaining in finally (try=ok)} -body {
|
||||
catch {
|
||||
list a b c
|
||||
} em expopts
|
||||
catch {
|
||||
try { list a b c } finally { throw BAR foo }
|
||||
} em opts
|
||||
string equal $expopts [dict get $opts -during]
|
||||
} {1}
|
||||
list $expopts [dict get $opts -during]
|
||||
} -match pairwise -result equal
|
||||
test error-18.7 {exception chaining in finally (try=error)} {
|
||||
catch {
|
||||
try { throw FOO bar } finally { throw BAR baz }
|
||||
|
||||
+128
-6
@@ -14,6 +14,12 @@ if {[lsearch [namespace children] ::tcltest] == -1} {
|
||||
namespace import -force ::tcltest::*
|
||||
}
|
||||
|
||||
# Used for constraining memory leak tests
|
||||
testConstraint memory [llength [info commands memory]]
|
||||
if {[testConstraint memory]} {
|
||||
proc meminfo {} {lindex [split [memory info] "\n"] 3 3}
|
||||
}
|
||||
|
||||
# Basic "for" operation.
|
||||
|
||||
test for-1.1 {TclCompileForCmd: missing initial command} {
|
||||
@@ -345,7 +351,6 @@ proc formatMail {} {
|
||||
64 { UNIX (Solaris 2.* and SunOS, other systems soon to follow). Easy to install} \
|
||||
65 { binary packages are now for sale at the Sun Labs Tcl/Tk Shop. Check it out!} \
|
||||
}
|
||||
|
||||
set result ""
|
||||
set NL "
|
||||
"
|
||||
@@ -365,7 +370,6 @@ proc formatMail {} {
|
||||
} else {
|
||||
set break 1
|
||||
}
|
||||
|
||||
set xmailer 0
|
||||
set inheaders 1
|
||||
set last [array size lines]
|
||||
@@ -386,9 +390,7 @@ proc formatMail {} {
|
||||
set limit 55
|
||||
} else {
|
||||
set limit 55
|
||||
|
||||
# Decide whether or not to break the body line
|
||||
|
||||
if {$plen > 0} {
|
||||
if {[string first {> } $line] == 0} {
|
||||
# This is quoted text from previous message, don't reformat
|
||||
@@ -431,7 +433,7 @@ proc formatMail {} {
|
||||
set climit [expr $limit-1]
|
||||
set cutoff 50
|
||||
set continuation 0
|
||||
|
||||
|
||||
while {[string length $line] > $limit} {
|
||||
for {set c [expr $limit-1]} {$c >= $cutoff} {incr c -1} {
|
||||
set char [string index $line $c]
|
||||
@@ -824,7 +826,127 @@ test for-6.18 {Tcl_ForObjCmd: for command result} {
|
||||
1 {invoked "continue" outside of a loop} \
|
||||
]
|
||||
|
||||
|
||||
test for-7.1 {Bug 3614226: ensure that break cleans up the stack} memory {
|
||||
apply {{} {
|
||||
# Can't use [memtest]; must be careful when we change stack frames
|
||||
set end [meminfo]
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
for {set x 0} {$x < 5} {incr x} {
|
||||
list a b c [break] d e f
|
||||
}
|
||||
set tmp $end
|
||||
set end [meminfo]
|
||||
}
|
||||
expr {$end - $tmp}
|
||||
}}
|
||||
} 0
|
||||
test for-7.2 {Bug 3614226: ensure that continue cleans up the stack} memory {
|
||||
apply {{} {
|
||||
# Can't use [memtest]; must be careful when we change stack frames
|
||||
set end [meminfo]
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
for {set x 0} {$x < 5} {incr x} {
|
||||
list a b c [continue] d e f
|
||||
}
|
||||
set tmp $end
|
||||
set end [meminfo]
|
||||
}
|
||||
expr {$end - $tmp}
|
||||
}}
|
||||
} 0
|
||||
test for-7.3 {Bug 3614226: ensure that break cleans up the expansion stack} memory {
|
||||
apply {{} {
|
||||
# Can't use [memtest]; must be careful when we change stack frames
|
||||
set end [meminfo]
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
for {set x 0} {[incr x]<50} {} {
|
||||
puts {*}[puts a b c {*}[break] d e f]
|
||||
}
|
||||
set tmp $end
|
||||
set end [meminfo]
|
||||
}
|
||||
expr {$end - $tmp}
|
||||
}}
|
||||
} 0
|
||||
test for-7.4 {Bug 3614226: ensure that continue cleans up the expansion stack} memory {
|
||||
apply {{} {
|
||||
# Can't use [memtest]; must be careful when we change stack frames
|
||||
set end [meminfo]
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
for {set x 0} {[incr x]<50} {} {
|
||||
puts {*}[puts a b c {*}[continue] d e f]
|
||||
}
|
||||
set tmp $end
|
||||
set end [meminfo]
|
||||
}
|
||||
expr {$end - $tmp}
|
||||
}}
|
||||
} 0
|
||||
test for-7.5 {Bug 3614226: ensure that break cleans up the combination of main and expansion stack} memory {
|
||||
apply {{} {
|
||||
set l [lrepeat 50 p q r]
|
||||
# Can't use [memtest]; must be careful when we change stack frames
|
||||
set end [meminfo]
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
for {set x 0} {[incr x]<50} {} {
|
||||
puts [puts {*}$l {*}[puts a b c {*}$l {*}[break] d e f]]
|
||||
}
|
||||
set tmp $end
|
||||
set end [meminfo]
|
||||
}
|
||||
expr {$end - $tmp}
|
||||
}}
|
||||
} 0
|
||||
test for-7.6 {Bug 3614226: ensure that continue cleans up the combination of main and expansion stack} memory {
|
||||
apply {{} {
|
||||
set l [lrepeat 50 p q r]
|
||||
# Can't use [memtest]; must be careful when we change stack frames
|
||||
set end [meminfo]
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
for {set x 0} {[incr x]<50} {} {
|
||||
puts [puts {*}$l {*}[puts a b c {*}$l {*}[continue] d e f]]
|
||||
}
|
||||
set tmp $end
|
||||
set end [meminfo]
|
||||
}
|
||||
expr {$end - $tmp}
|
||||
}}
|
||||
} 0
|
||||
test for-7.7 {Bug 3614226: ensure that break only cleans up the right amount} memory {
|
||||
apply {{} {
|
||||
set l [lrepeat 50 p q r]
|
||||
# Can't use [memtest]; must be careful when we change stack frames
|
||||
set end [meminfo]
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
unset -nocomplain {*}[for {set x 0} {[incr x]<50} {} {
|
||||
puts [puts {*}$l {*}[puts a b c {*}$l {*}[break] d e f]]
|
||||
}]
|
||||
set tmp $end
|
||||
set end [meminfo]
|
||||
}
|
||||
expr {$end - $tmp}
|
||||
}}
|
||||
} 0
|
||||
test for-7.8 {Bug 3614226: ensure that continue only cleans up the right amount} memory {
|
||||
apply {{} {
|
||||
set l [lrepeat 50 p q r]
|
||||
# Can't use [memtest]; must be careful when we change stack frames
|
||||
set end [meminfo]
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
unset -nocomplain {*}[for {set x 0} {[incr x]<50} {} {
|
||||
puts [puts {*}$l {*}[puts a b c {*}$l {*}[continue] d e f]]
|
||||
}]
|
||||
set tmp $end
|
||||
set end [meminfo]
|
||||
}
|
||||
expr {$end - $tmp}
|
||||
}}
|
||||
} 0
|
||||
|
||||
# cleanup
|
||||
::tcltest::cleanupTests
|
||||
return
|
||||
|
||||
# Local Variables:
|
||||
# mode: tcl
|
||||
# End:
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ proc httpdAccept {newsock ipaddr port} {
|
||||
fconfigure $newsock -blocking 0 -translation {auto crlf}
|
||||
httpd_log $newsock Connect $ipaddr $port
|
||||
set data(ipaddr) $ipaddr
|
||||
fileevent $newsock readable [list httpdRead $newsock]
|
||||
after 50 [list fileevent $newsock readable [list httpdRead $newsock]]
|
||||
}
|
||||
|
||||
# read data from a client request
|
||||
|
||||
+18
-10
@@ -291,24 +291,24 @@ XTTEST_OBJS = xtTestInit.o tclTest.o tclTestObj.o tclTestProcBodyObj.o \
|
||||
tclThreadTest.o tclUnixTest.o tclXtNotify.o tclXtTest.o
|
||||
|
||||
GENERIC_OBJS = regcomp.o regexec.o regfree.o regerror.o tclAlloc.o \
|
||||
tclAsync.o tclBasic.o tclBinary.o tclCkalloc.o tclClock.o \
|
||||
tclCmdAH.o tclCmdIL.o tclCmdMZ.o tclCompCmds.o tclCompCmdsSZ.o \
|
||||
tclCompExpr.o tclCompile.o tclConfig.o tclDate.o tclDictObj.o \
|
||||
tclAssembly.o tclAsync.o tclBasic.o tclBinary.o tclCkalloc.o \
|
||||
tclClock.o tclCmdAH.o tclCmdIL.o tclCmdMZ.o \
|
||||
tclCompCmds.o tclCompCmdsGR.o tclCompCmdsSZ.o tclCompExpr.o \
|
||||
tclCompile.o tclConfig.o tclDate.o tclDictObj.o \
|
||||
tclEncoding.o tclEnsemble.o \
|
||||
tclEnv.o tclEvent.o tclExecute.o tclFCmd.o tclFileName.o tclGet.o \
|
||||
tclHash.o tclHistory.o tclIndexObj.o tclInterp.o tclIO.o tclIOCmd.o \
|
||||
tclIORChan.o tclIORTrans.o tclIOGT.o tclIOSock.o tclIOUtil.o \
|
||||
tclLink.o tclListObj.o \
|
||||
tclLiteral.o tclLoad.o tclMain.o tclNamesp.o tclNotify.o \
|
||||
tclObj.o tclPanic.o tclParse.o tclPathObj.o tclPipe.o \
|
||||
tclObj.o tclOptimize.o tclPanic.o tclParse.o tclPathObj.o tclPipe.o \
|
||||
tclPkg.o tclPkgConfig.o tclPosixStr.o \
|
||||
tclPreserve.o tclProc.o tclRegexp.o \
|
||||
tclResolve.o tclResult.o tclScan.o tclStringObj.o \
|
||||
tclStrToD.o tclThread.o \
|
||||
tclThreadAlloc.o tclThreadJoin.o tclThreadStorage.o tclStubInit.o \
|
||||
tclTimer.o tclTrace.o tclUtf.o tclUtil.o tclVar.o tclZlib.o \
|
||||
tclTomMathInterface.o \
|
||||
tclAssembly.o
|
||||
tclTomMathInterface.o
|
||||
|
||||
OO_OBJS = tclOO.o tclOOBasic.o tclOOCall.o tclOODefineCmds.o tclOOInfo.o \
|
||||
tclOOMethod.o tclOOStubInit.o
|
||||
@@ -395,6 +395,7 @@ GENERIC_SRCS = \
|
||||
$(GENERIC_DIR)/tclCmdIL.c \
|
||||
$(GENERIC_DIR)/tclCmdMZ.c \
|
||||
$(GENERIC_DIR)/tclCompCmds.c \
|
||||
$(GENERIC_DIR)/tclCompCmdsGR.c \
|
||||
$(GENERIC_DIR)/tclCompCmdsSZ.c \
|
||||
$(GENERIC_DIR)/tclCompExpr.c \
|
||||
$(GENERIC_DIR)/tclCompile.c \
|
||||
@@ -428,6 +429,7 @@ GENERIC_SRCS = \
|
||||
$(GENERIC_DIR)/tclNamesp.c \
|
||||
$(GENERIC_DIR)/tclNotify.c \
|
||||
$(GENERIC_DIR)/tclObj.c \
|
||||
$(GENERIC_DIR)/tclOptimize.c \
|
||||
$(GENERIC_DIR)/tclParse.c \
|
||||
$(GENERIC_DIR)/tclPathObj.c \
|
||||
$(GENERIC_DIR)/tclPipe.c \
|
||||
@@ -838,13 +840,13 @@ install-libraries: libraries
|
||||
do \
|
||||
$(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/opt0.4; \
|
||||
done;
|
||||
@echo "Installing package msgcat 1.5.1 as a Tcl Module";
|
||||
@$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/msgcat-1.5.1.tm;
|
||||
@echo "Installing package msgcat 1.5.2 as a Tcl Module";
|
||||
@$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/msgcat-1.5.2.tm;
|
||||
@echo "Installing package tcltest 2.3.5 as a Tcl Module";
|
||||
@$(INSTALL_DATA) $(TOP_DIR)/library/tcltest/tcltest.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/tcltest-2.3.5.tm;
|
||||
|
||||
@echo "Installing package platform 1.0.11 as a Tcl Module";
|
||||
@$(INSTALL_DATA) $(TOP_DIR)/library/platform/platform.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/platform-1.0.11.tm;
|
||||
@echo "Installing package platform 1.0.12 as a Tcl Module";
|
||||
@$(INSTALL_DATA) $(TOP_DIR)/library/platform/platform.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/platform-1.0.12.tm;
|
||||
@echo "Installing package platform::shell 1.1.4 as a Tcl Module";
|
||||
@$(INSTALL_DATA) $(TOP_DIR)/library/platform/shell.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/platform/shell-1.1.4.tm;
|
||||
|
||||
@@ -1077,6 +1079,9 @@ tclDate.o: $(GENERIC_DIR)/tclDate.c
|
||||
tclCompCmds.o: $(GENERIC_DIR)/tclCompCmds.c $(COMPILEHDR)
|
||||
$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCompCmds.c
|
||||
|
||||
tclCompCmdsGR.o: $(GENERIC_DIR)/tclCompCmdsGR.c $(COMPILEHDR)
|
||||
$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCompCmdsGR.c
|
||||
|
||||
tclCompCmdsSZ.o: $(GENERIC_DIR)/tclCompCmdsSZ.c $(COMPILEHDR)
|
||||
$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCompCmdsSZ.c
|
||||
|
||||
@@ -1161,6 +1166,9 @@ tclLiteral.o: $(GENERIC_DIR)/tclLiteral.c $(COMPILEHDR)
|
||||
tclObj.o: $(GENERIC_DIR)/tclObj.c $(COMPILEHDR) $(MATHHDRS)
|
||||
$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclObj.c
|
||||
|
||||
tclOptimize.o: $(GENERIC_DIR)/tclOptimize.c $(COMPILEHDR)
|
||||
$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclOptimize.c
|
||||
|
||||
tclLoad.o: $(GENERIC_DIR)/tclLoad.c
|
||||
$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLoad.c
|
||||
|
||||
|
||||
Vendored
+9
-75
@@ -6617,6 +6617,11 @@ cat >>confdefs.h <<\_ACEOF
|
||||
_ACEOF
|
||||
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define HAVE_HIDDEN 1
|
||||
_ACEOF
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
@@ -7719,63 +7724,6 @@ fi
|
||||
CC_SEARCH_FLAGS=""
|
||||
LD_SEARCH_FLAGS=""
|
||||
;;
|
||||
NetBSD-1.*|FreeBSD-[1-2].*)
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD="ld -Bshareable -x"
|
||||
SHLIB_SUFFIX=".so"
|
||||
DL_OBJS="tclLoadDl.o"
|
||||
DL_LIBS=""
|
||||
if test $doRpath = yes; then
|
||||
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: checking for ELF" >&5
|
||||
echo $ECHO_N "checking for ELF... $ECHO_C" >&6
|
||||
if test "${tcl_cv_ld_elf+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
#ifdef __ELF__
|
||||
yes
|
||||
#endif
|
||||
|
||||
_ACEOF
|
||||
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
|
||||
$EGREP "yes" >/dev/null 2>&1; then
|
||||
tcl_cv_ld_elf=yes
|
||||
else
|
||||
tcl_cv_ld_elf=no
|
||||
fi
|
||||
rm -f conftest*
|
||||
|
||||
fi
|
||||
echo "$as_me:$LINENO: result: $tcl_cv_ld_elf" >&5
|
||||
echo "${ECHO_T}$tcl_cv_ld_elf" >&6
|
||||
if test $tcl_cv_ld_elf = yes; then
|
||||
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so'
|
||||
|
||||
else
|
||||
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Ancient FreeBSD doesn't handle version numbers with dots.
|
||||
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
;;
|
||||
OpenBSD-*)
|
||||
arch=`arch -s`
|
||||
case "$arch" in
|
||||
@@ -7861,9 +7809,8 @@ fi
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
;;
|
||||
NetBSD-*|FreeBSD-[3-4].*)
|
||||
# FreeBSD 3.* and greater have ELF.
|
||||
# NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs
|
||||
NetBSD-*)
|
||||
# NetBSD has ELF and can use 'cc -shared' to build shared libs
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
|
||||
SHLIB_SUFFIX=".so"
|
||||
@@ -7885,20 +7832,12 @@ fi
|
||||
|
||||
fi
|
||||
|
||||
case $system in
|
||||
FreeBSD-3.*)
|
||||
# FreeBSD-3 doesn't handle version numbers with dots.
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
FreeBSD-*)
|
||||
# This configuration from FreeBSD Ports.
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD="${CC} -shared"
|
||||
TCL_SHLIB_LD_EXTRAS="-soname \$@"
|
||||
TCL_SHLIB_LD_EXTRAS="-Wl,-soname=\$@"
|
||||
SHLIB_SUFFIX=".so"
|
||||
DL_OBJS="tclLoadDl.o"
|
||||
DL_LIBS=""
|
||||
@@ -7906,7 +7845,7 @@ fi
|
||||
if test $doRpath = yes; then
|
||||
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
|
||||
LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
fi
|
||||
|
||||
if test "${TCL_THREADS}" = "1"; then
|
||||
@@ -9115,11 +9054,6 @@ cat >>confdefs.h <<\_ACEOF
|
||||
_ACEOF
|
||||
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define NO_VIZ
|
||||
_ACEOF
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
+5
-40
@@ -1067,6 +1067,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
AC_DEFINE(MODULE_SCOPE,
|
||||
[extern __attribute__((__visibility__("hidden")))],
|
||||
[Compiler support for module scope symbols])
|
||||
AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols])
|
||||
])
|
||||
])
|
||||
|
||||
@@ -1469,32 +1470,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
CC_SEARCH_FLAGS=""
|
||||
LD_SEARCH_FLAGS=""
|
||||
;;
|
||||
NetBSD-1.*|FreeBSD-[[1-2]].*)
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD="ld -Bshareable -x"
|
||||
SHLIB_SUFFIX=".so"
|
||||
DL_OBJS="tclLoadDl.o"
|
||||
DL_LIBS=""
|
||||
AS_IF([test $doRpath = yes], [
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
|
||||
AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [
|
||||
AC_EGREP_CPP(yes, [
|
||||
#ifdef __ELF__
|
||||
yes
|
||||
#endif
|
||||
], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)])
|
||||
AS_IF([test $tcl_cv_ld_elf = yes], [
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so'
|
||||
], [
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
|
||||
])
|
||||
|
||||
# Ancient FreeBSD doesn't handle version numbers with dots.
|
||||
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
;;
|
||||
OpenBSD-*)
|
||||
arch=`arch -s`
|
||||
case "$arch" in
|
||||
@@ -1546,9 +1521,8 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
;;
|
||||
NetBSD-*|FreeBSD-[[3-4]].*)
|
||||
# FreeBSD 3.* and greater have ELF.
|
||||
# NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs
|
||||
NetBSD-*)
|
||||
# NetBSD has ELF and can use 'cc -shared' to build shared libs
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
|
||||
SHLIB_SUFFIX=".so"
|
||||
@@ -1564,27 +1538,19 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
])
|
||||
case $system in
|
||||
FreeBSD-3.*)
|
||||
# FreeBSD-3 doesn't handle version numbers with dots.
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
FreeBSD-*)
|
||||
# This configuration from FreeBSD Ports.
|
||||
SHLIB_CFLAGS="-fPIC"
|
||||
SHLIB_LD="${CC} -shared"
|
||||
TCL_SHLIB_LD_EXTRAS="-soname \$[@]"
|
||||
TCL_SHLIB_LD_EXTRAS="-Wl,-soname=\$[@]"
|
||||
SHLIB_SUFFIX=".so"
|
||||
DL_OBJS="tclLoadDl.o"
|
||||
DL_LIBS=""
|
||||
LDFLAGS=""
|
||||
AS_IF([test $doRpath = yes], [
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
|
||||
LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
|
||||
AS_IF([test "${TCL_THREADS}" = "1"], [
|
||||
# The -pthread needs to go in the LDFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
@@ -2075,7 +2041,6 @@ dnl # preprocessing tests use only CPPFLAGS.
|
||||
AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [
|
||||
AC_DEFINE(MODULE_SCOPE, [extern],
|
||||
[No Compiler support for module scope symbols])
|
||||
AC_DEFINE(NO_VIZ, [], [No visibility attribute])
|
||||
])
|
||||
|
||||
AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [
|
||||
|
||||
+2
-2
@@ -343,8 +343,8 @@
|
||||
/* Do we have <values.h>? */
|
||||
#undef NO_VALUES_H
|
||||
|
||||
/* No visibility attribute */
|
||||
#undef NO_VIZ
|
||||
/* Compiler support for module scope symbols */
|
||||
#undef HAVE_HIDDEN
|
||||
|
||||
/* Do we have wait3() */
|
||||
#undef NO_WAIT3
|
||||
|
||||
+2
-2
@@ -2226,13 +2226,13 @@ DefaultTempDir(void)
|
||||
|
||||
dir = getenv("TMPDIR");
|
||||
if (dir && dir[0] && stat(dir, &buf) == 0 && S_ISDIR(buf.st_mode)
|
||||
&& access(dir, W_OK)) {
|
||||
&& access(dir, W_OK) == 0) {
|
||||
return dir;
|
||||
}
|
||||
|
||||
#ifdef P_tmpdir
|
||||
dir = P_tmpdir;
|
||||
if (stat(dir, &buf) == 0 && S_ISDIR(buf.st_mode) && access(dir, W_OK)) {
|
||||
if (stat(dir, &buf)==0 && S_ISDIR(buf.st_mode) && access(dir, W_OK)==0) {
|
||||
return dir;
|
||||
}
|
||||
#endif
|
||||
|
||||
+6
-4
@@ -225,6 +225,7 @@ GENERIC_OBJS = \
|
||||
tclCmdIL.$(OBJEXT) \
|
||||
tclCmdMZ.$(OBJEXT) \
|
||||
tclCompCmds.$(OBJEXT) \
|
||||
tclCompCmdsGR.$(OBJEXT) \
|
||||
tclCompCmdsSZ.$(OBJEXT) \
|
||||
tclCompExpr.$(OBJEXT) \
|
||||
tclCompile.$(OBJEXT) \
|
||||
@@ -266,6 +267,7 @@ GENERIC_OBJS = \
|
||||
tclOOMethod.$(OBJEXT) \
|
||||
tclOOStubInit.$(OBJEXT) \
|
||||
tclObj.$(OBJEXT) \
|
||||
tclOptimize.$(OBJEXT) \
|
||||
tclPanic.$(OBJEXT) \
|
||||
tclParse.$(OBJEXT) \
|
||||
tclPathObj.$(OBJEXT) \
|
||||
@@ -646,12 +648,12 @@ install-libraries: libraries install-tzdata install-msgs
|
||||
do \
|
||||
$(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/opt0.4"; \
|
||||
done;
|
||||
@echo "Installing package msgcat 1.5.1 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.5.1.tm;
|
||||
@echo "Installing package msgcat 1.5.2 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.5.2.tm;
|
||||
@echo "Installing package tcltest 2.3.5 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/tcltest-2.3.5.tm;
|
||||
@echo "Installing package platform 1.0.11 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/platform/platform.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/platform-1.0.11.tm;
|
||||
@echo "Installing package platform 1.0.12 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/platform/platform.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/platform-1.0.12.tm;
|
||||
@echo "Installing package platform::shell 1.1.4 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/platform/shell.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/platform/shell-1.1.4.tm;
|
||||
@echo "Installing encodings";
|
||||
|
||||
Vendored
-4
@@ -4377,10 +4377,6 @@ else
|
||||
|
||||
ZLIB_OBJS=\${ZLIB_OBJS}
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define NO_VIZ 1
|
||||
_ACEOF
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@ AS_IF([test "$tcl_ok" = "yes"], [
|
||||
])
|
||||
], [
|
||||
AC_SUBST(ZLIB_OBJS,[\${ZLIB_OBJS}])
|
||||
AC_DEFINE_UNQUOTED(NO_VIZ, 1)
|
||||
])
|
||||
AC_DEFINE(HAVE_ZLIB, 1, [Is there an installed zlib?])
|
||||
|
||||
|
||||
@@ -200,6 +200,7 @@ TCLOBJS = \
|
||||
$(TMPDIR)\tclCmdIL.obj \
|
||||
$(TMPDIR)\tclCmdMZ.obj \
|
||||
$(TMPDIR)\tclCompCmds.obj \
|
||||
$(TMPDIR)\tclCompCmdsGR.obj \
|
||||
$(TMPDIR)\tclCompCmdsSZ.obj \
|
||||
$(TMPDIR)\tclCompExpr.obj \
|
||||
$(TMPDIR)\tclCompile.obj \
|
||||
@@ -238,6 +239,7 @@ TCLOBJS = \
|
||||
$(TMPDIR)\tclOOMethod.obj \
|
||||
$(TMPDIR)\tclOOStubInit.obj \
|
||||
$(TMPDIR)\tclObj.obj \
|
||||
$(TMPDIR)\tclOptimize.obj \
|
||||
$(TMPDIR)\tclPanic.obj \
|
||||
$(TMPDIR)\tclParse.obj \
|
||||
$(TMPDIR)\tclPipe.obj \
|
||||
|
||||
@@ -274,6 +274,7 @@ COREOBJS = \
|
||||
$(TMP_DIR)\tclCmdIL.obj \
|
||||
$(TMP_DIR)\tclCmdMZ.obj \
|
||||
$(TMP_DIR)\tclCompCmds.obj \
|
||||
$(TMP_DIR)\tclCompCmdsGR.obj \
|
||||
$(TMP_DIR)\tclCompCmdsSZ.obj \
|
||||
$(TMP_DIR)\tclCompExpr.obj \
|
||||
$(TMP_DIR)\tclCompile.obj \
|
||||
@@ -315,6 +316,7 @@ COREOBJS = \
|
||||
$(TMP_DIR)\tclOOMethod.obj \
|
||||
$(TMP_DIR)\tclOOStubInit.obj \
|
||||
$(TMP_DIR)\tclObj.obj \
|
||||
$(TMP_DIR)\tclOptimize.obj \
|
||||
$(TMP_DIR)\tclPanic.obj \
|
||||
$(TMP_DIR)\tclParse.obj \
|
||||
$(TMP_DIR)\tclPathObj.obj \
|
||||
|
||||
+2
-2
@@ -280,7 +280,7 @@ NativeGetTime(
|
||||
Tcl_Time *timePtr,
|
||||
ClientData clientData)
|
||||
{
|
||||
struct timeb t;
|
||||
struct _timeb t;
|
||||
int useFtime = 1; /* Flag == TRUE if we need to fall back on
|
||||
* ftime rather than using the perf counter. */
|
||||
|
||||
@@ -446,7 +446,7 @@ NativeGetTime(
|
||||
* High resolution timer is not available. Just use ftime.
|
||||
*/
|
||||
|
||||
ftime(&t);
|
||||
_ftime(&t);
|
||||
timePtr->sec = (long)t.time;
|
||||
timePtr->usec = t.millitm * 1000;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user