aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/beam_emu.c2
-rw-r--r--erts/emulator/beam/beam_load.c181
-rw-r--r--erts/emulator/beam/erl_bits.h2
-rw-r--r--erts/emulator/beam/ops.tab2
-rw-r--r--erts/emulator/drivers/common/inet_drv.c4
-rw-r--r--erts/emulator/hipe/hipe_mode_switch.c7
-rw-r--r--erts/emulator/test/bs_construct_SUITE.erl17
-rw-r--r--erts/emulator/test/hibernate_SUITE.erl31
-rwxr-xr-xerts/emulator/utils/beam_makeops71
-rw-r--r--erts/lib_src/common/erl_misc_utils.c2
-rw-r--r--erts/lib_src/common/erl_printf_format.c4
-rw-r--r--lib/ic/doc/src/notes.xml18
-rw-r--r--lib/ic/src/ic_pp.erl472
-rw-r--r--lib/ic/src/ic_pragma.erl19
-rw-r--r--lib/ic/vsn.mk2
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl1
-rw-r--r--lib/stdlib/doc/src/gen_fsm.xml2
-rw-r--r--lib/stdlib/src/timer.erl2
-rw-r--r--lib/xmerl/include/xmerl_xsd.hrl1
-rw-r--r--lib/xmerl/src/xmerl_scan.erl2
-rw-r--r--lib/xmerl/src/xmerl_xsd.erl43
-rw-r--r--lib/xmerl/test/xmerl_SUITE.erl13
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/misc.tar.gzbin47121 -> 47340 bytes
-rw-r--r--lib/xmerl/test/xmerl_xsd_SUITE.erl7
24 files changed, 546 insertions, 359 deletions
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index fb90a7d4f7..937b3d9e53 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -3561,7 +3561,7 @@ void process_main(void)
* Operands: NotUsed Live Dst
*/
do_bs_init_bits_known:
- num_bytes = (num_bits+7) >> 3;
+ num_bytes = ((Uint64)num_bits+(Uint64)7) >> 3;
if (num_bits & 7) {
alloc += ERL_SUB_BIN_SIZE;
}
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 57fe25453d..eb10ae59a8 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -332,20 +332,22 @@ typedef struct {
Eterm* func_tab[1]; /* Pointers to each function. */
} LoadedCode;
-#define GetTagAndValue(Stp, Tag, Val) \
- do { \
- BeamInstr __w; \
- GetByte(Stp, __w); \
- Tag = __w & 0x07; \
- if ((__w & 0x08) == 0) { \
- Val = __w >> 4; \
- } else if ((__w & 0x10) == 0) { \
- Val = ((__w >> 5) << 8); \
- GetByte(Stp, __w); \
- Val |= __w; \
- } else { \
- if (!get_int_val(Stp, __w, &(Val))) goto load_error; \
- } \
+#define GetTagAndValue(Stp, Tag, Val) \
+ do { \
+ BeamInstr __w; \
+ GetByte(Stp, __w); \
+ Tag = __w & 0x07; \
+ if ((__w & 0x08) == 0) { \
+ Val = __w >> 4; \
+ } else if ((__w & 0x10) == 0) { \
+ Val = ((__w >> 5) << 8); \
+ GetByte(Stp, __w); \
+ Val |= __w; \
+ } else { \
+ int __res = get_tag_and_value(Stp, __w, (Tag), &(Val)); \
+ if (__res < 0) goto load_error; \
+ Tag = (unsigned) __res; \
+ } \
} while (0)
@@ -489,8 +491,8 @@ static void load_printf(int line, LoaderState* context, char *fmt, ...);
static int transform_engine(LoaderState* st);
static void id_to_string(Uint id, char* s);
static void new_genop(LoaderState* stp);
-static int get_int_val(LoaderState* stp, Uint len_code, BeamInstr* result);
-static int get_erlang_integer(LoaderState* stp, Uint len_code, BeamInstr* result);
+static int get_tag_and_value(LoaderState* stp, Uint len_code,
+ unsigned tag, BeamInstr* result);
static int new_label(LoaderState* stp);
static void new_literal_patch(LoaderState* stp, int pos);
static void new_string_patch(LoaderState* stp, int pos);
@@ -1470,46 +1472,15 @@ load_code(LoaderState* stp)
last_op->arity = 0;
ASSERT(arity <= MAX_OPARGS);
-#define GetValue(Stp, First, Val) \
- do { \
- if (((First) & 0x08) == 0) { \
- Val = (First) >> 4; \
- } else if (((First) & 0x10) == 0) { \
- BeamInstr __w; \
- GetByte(Stp, __w); \
- Val = (((First) >> 5) << 8) | __w; \
- } else { \
- if (!get_int_val(Stp, (First), &(Val))) goto load_error; \
- } \
- } while (0)
-
for (arg = 0; arg < arity; arg++) {
- BeamInstr first;
-
- GetByte(stp, first);
- last_op->a[arg].type = first & 0x07;
+ GetTagAndValue(stp, last_op->a[arg].type, last_op->a[arg].val);
switch (last_op->a[arg].type) {
case TAG_i:
- if ((first & 0x08) == 0) {
- last_op->a[arg].val = first >> 4;
- } else if ((first & 0x10) == 0) {
- BeamInstr w;
- GetByte(stp, w);
- ASSERT(first < 0x800);
- last_op->a[arg].val = ((first >> 5) << 8) | w;
- } else {
- int i = get_erlang_integer(stp, first, &(last_op->a[arg].val));
- if (i < 0) {
- goto load_error;
- }
- last_op->a[arg].type = i;
- }
- break;
case TAG_u:
- GetValue(stp, first, last_op->a[arg].val);
+ case TAG_q:
+ case TAG_o:
break;
case TAG_x:
- GetValue(stp, first, last_op->a[arg].val);
if (last_op->a[arg].val == 0) {
last_op->a[arg].type = TAG_r;
} else if (last_op->a[arg].val >= MAX_REG) {
@@ -1518,7 +1489,6 @@ load_code(LoaderState* stp)
}
break;
case TAG_y:
- GetValue(stp, first, last_op->a[arg].val);
if (last_op->a[arg].val >= MAX_REG) {
LoadError1(stp, "invalid y register number: %u",
last_op->a[arg].val);
@@ -1526,7 +1496,6 @@ load_code(LoaderState* stp)
last_op->a[arg].val += CP_SIZE;
break;
case TAG_a:
- GetValue(stp, first, last_op->a[arg].val);
if (last_op->a[arg].val == 0) {
last_op->a[arg].type = TAG_n;
} else if (last_op->a[arg].val >= stp->num_atoms) {
@@ -1536,7 +1505,6 @@ load_code(LoaderState* stp)
}
break;
case TAG_f:
- GetValue(stp, first, last_op->a[arg].val);
if (last_op->a[arg].val == 0) {
last_op->a[arg].type = TAG_p;
} else if (last_op->a[arg].val >= stp->num_labels) {
@@ -1544,7 +1512,6 @@ load_code(LoaderState* stp)
}
break;
case TAG_h:
- GetValue(stp, first, last_op->a[arg].val);
if (last_op->a[arg].val > 65535) {
LoadError1(stp, "invalid range for character data type: %u",
last_op->a[arg].val);
@@ -1552,11 +1519,9 @@ load_code(LoaderState* stp)
break;
case TAG_z:
{
- BeamInstr ext_tag;
unsigned tag;
- GetValue(stp, first, ext_tag);
- switch (ext_tag) {
+ switch (last_op->a[arg].val) {
case 0: /* Floating point number */
{
Eterm* hp;
@@ -1648,7 +1613,8 @@ load_code(LoaderState* stp)
break;
}
default:
- LoadError1(stp, "invalid extended tag %d", ext_tag);
+ LoadError1(stp, "invalid extended tag %d",
+ last_op->a[arg].val);
break;
}
}
@@ -1659,7 +1625,6 @@ load_code(LoaderState* stp)
}
last_op->arity++;
}
-#undef GetValue
ASSERT(arity == last_op->arity);
@@ -2562,13 +2527,8 @@ should_gen_heap_bin(LoaderState* stp, GenOpArg Src)
static int
binary_too_big(LoaderState* stp, GenOpArg Size)
{
- return Size.type == TAG_u && ((Size.val >> (8*sizeof(Uint)-3)) != 0);
-}
-
-static int
-binary_too_big_bits(LoaderState* stp, GenOpArg Size)
-{
- return Size.type == TAG_u && (((Size.val+7)/8) >> (8*sizeof(Uint)-3) != 0);
+ return Size.type == TAG_o ||
+ (Size.type == TAG_u && ((Size.val >> (8*sizeof(Uint)-3)) != 0));
}
static GenOp*
@@ -4317,41 +4277,9 @@ load_printf(int line, LoaderState* context, char *fmt,...)
erts_send_error_to_logger(context->group_leader, dsbufp);
}
-
-static int
-get_int_val(LoaderState* stp, Uint len_code, BeamInstr* result)
-{
- Uint count;
- Uint val;
-
- len_code >>= 5;
- ASSERT(len_code < 8);
- if (len_code == 7) {
- LoadError0(stp, "can't load integers bigger than 8 bytes yet\n");
- }
- count = len_code + 2;
- if (count == 5) {
- Uint msb;
- GetByte(stp, msb);
- if (msb == 0) {
- count--;
- }
- GetInt(stp, 4, *result);
- } else if (count <= 4) {
- GetInt(stp, count, val);
- *result = ((val << 8*(sizeof(val)-count)) >> 8*(sizeof(val)-count));
- } else {
- LoadError1(stp, "too big integer; %d bytes\n", count);
- }
- return 1;
-
- load_error:
- return 0;
-}
-
-
static int
-get_erlang_integer(LoaderState* stp, Uint len_code, BeamInstr* result)
+get_tag_and_value(LoaderState* stp, Uint len_code,
+ unsigned tag, BeamInstr* result)
{
Uint count;
Sint val;
@@ -4371,17 +4299,62 @@ get_erlang_integer(LoaderState* stp, Uint len_code, BeamInstr* result)
if (len_code < 7) {
count = len_code + 2;
} else {
- Uint tag;
+ unsigned sztag;
UWord len_word;
ASSERT(len_code == 7);
- GetTagAndValue(stp, tag, len_word);
- VerifyTag(stp, TAG_u, tag);
+ GetTagAndValue(stp, sztag, len_word);
+ VerifyTag(stp, sztag, TAG_u);
count = len_word + 9;
}
/*
- * Handle values up to the size of an int, meaning either a small or bignum.
+ * The value for tags except TAG_i must be an unsigned integer
+ * fitting in an Uint. If it does not fit, we'll indicate overflow
+ * by changing the tag to TAG_o.
+ */
+
+ if (tag != TAG_i) {
+ if (count == sizeof(Uint)+1) {
+ Uint msb;
+
+ /*
+ * The encoded value has one more byte than an Uint.
+ * It will still fit in an Uint if the most significant
+ * byte is 0.
+ */
+ GetByte(stp, msb);
+ GetInt(stp, sizeof(Uint), *result);
+ if (msb != 0) {
+ /* Overflow: Negative or too big. */
+ return TAG_o;
+ }
+ } else if (count == sizeof(Uint)) {
+ /*
+ * The value must be positive (or the encoded value would
+ * have been one byte longer).
+ */
+ GetInt(stp, count, *result);
+ } else if (count < sizeof(Uint)) {
+ GetInt(stp, count, *result);
+
+ /*
+ * If the sign bit is set, the value is negative
+ * (not allowed).
+ */
+ if (*result & ((Uint)1 << (count*8-1))) {
+ return TAG_o;
+ }
+ } else {
+ GetInt(stp, count, *result);
+ return TAG_o;
+ }
+ return tag;
+ }
+
+ /*
+ * TAG_i: First handle values up to the size of an Uint (i.e. either
+ * a small or a bignum).
*/
if (count <= sizeof(val)) {
diff --git a/erts/emulator/beam/erl_bits.h b/erts/emulator/beam/erl_bits.h
index 0f67733fa4..3309ea706b 100644
--- a/erts/emulator/beam/erl_bits.h
+++ b/erts/emulator/beam/erl_bits.h
@@ -150,7 +150,7 @@ void erts_bits_destroy_state(ERL_BITS_PROTO_0);
* NBYTES(x) returns the number of bytes needed to store x bits.
*/
-#define NBYTES(x) (((x) + 7) >> 3)
+#define NBYTES(x) (((Uint64)(x) + (Uint64) 7) >> 3)
#define BYTE_OFFSET(ofs) ((Uint) (ofs) >> 3)
#define BIT_OFFSET(ofs) ((ofs) & 7)
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 8a5763b4bb..304ce22ef2 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -1236,7 +1236,7 @@ i_bs_init_heap I I I d
i_bs_init_heap_bin_heap I I I d
-bs_init_bits Fail Sz Words Regs Flags Dst | binary_too_big_bits(Sz) => system_limit Fail
+bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail
bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init_bits Sz Regs Dst
bs_init_bits Fail Sz=u Words Regs Flags Dst => i_bs_init_bits_heap Sz Words Regs Dst
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 40c4a0df08..ebc4469a23 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -3709,6 +3709,8 @@ static int inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
/* check that it is a socket and that the socket is bound */
if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*) &name, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
+ if (name.sa.sa_family != domain)
+ return ctl_error(EINVAL, rbuf, rsize);
desc->s = s;
if ((desc->event = sock_create_event(desc)) == INVALID_EVENT)
return ctl_error(sock_errno(), rbuf, rsize);
@@ -9739,7 +9741,7 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
if (desc->active || (len != 8))
return ctl_error(EINVAL, rbuf, rsize);
timeout = get_int32(buf);
- /* The 2nd arg, Length(4), is ignored for both UDP ans SCTP protocols,
+ /* The 2nd arg, Length(4), is ignored for both UDP and SCTP protocols,
since they are msg-oriented. */
if (enq_async(desc, tbuf, PACKET_REQ_RECV) < 0)
diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c
index 16f8fb1347..e3e8367b62 100644
--- a/erts/emulator/hipe/hipe_mode_switch.c
+++ b/erts/emulator/hipe/hipe_mode_switch.c
@@ -346,7 +346,12 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[])
p->arity = callee_arity;
}
- /* If process is in P_WAITING state, we schedule the next process */
+ /* Schedule next process if current process was hibernated or is waiting
+ for messages */
+ if (p->flags & F_HIBERNATE_SCHED) {
+ p->flags &= ~F_HIBERNATE_SCHED;
+ goto do_schedule;
+ }
if (p->status == P_WAITING) {
goto do_schedule;
}
diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl
index 1959803385..7fdf36711b 100644
--- a/erts/emulator/test/bs_construct_SUITE.erl
+++ b/erts/emulator/test/bs_construct_SUITE.erl
@@ -553,6 +553,11 @@ huge_float_check({'EXIT',{badarg,_}}) -> ok.
huge_binary(Config) when is_list(Config) ->
?line 16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>),
+ ?line garbage_collect(),
+ ?line id(<<0:((1 bsl 32)-1)>>),
+ ?line garbage_collect(),
+ ?line id(<<0:(id((1 bsl 32)-1))>>),
+ ?line garbage_collect(),
ok.
system_limit(Config) when is_list(Config) ->
@@ -565,6 +570,10 @@ system_limit(Config) when is_list(Config) ->
?line {'EXIT',{system_limit,_}} =
(catch <<(id(<<>>))/binary,0:(id(1 bsl 100))>>),
+ %% Would fail to load.
+ ?line {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 67)>>),
+ ?line {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 64)+1)>>),
+
case WordSize of
4 ->
system_limit_32();
@@ -581,6 +590,14 @@ system_limit_32() ->
?line {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:536870912/unit:8>>),
?line {'EXIT',{system_limit,_}} =
(catch <<0:(id(8)),42:(id(536870912))/unit:8>>),
+
+ %% The size would be silently truncated, resulting in a crash.
+ ?line {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 35)>>),
+ ?line {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 32)+1)>>),
+
+ %% Would fail to load.
+ ?line {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 43)>>),
+ ?line {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 40)+1)>>),
ok.
badarg(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/hibernate_SUITE.erl b/erts/emulator/test/hibernate_SUITE.erl
index 203fa6b48e..82a0aad189 100644
--- a/erts/emulator/test/hibernate_SUITE.erl
+++ b/erts/emulator/test/hibernate_SUITE.erl
@@ -25,16 +25,16 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
basic/1,dynamic_call/1,min_heap_size/1,bad_args/1,
- messages_in_queue/1,undefined_mfa/1, no_heap/1]).
+ messages_in_queue/1,undefined_mfa/1,no_heap/1,wake_up_and_bif_trap/1]).
%% Used by test cases.
--export([basic_hibernator/1,dynamic_call_hibernator/2,messages_in_queue_restart/2, no_heap_loop/0]).
+-export([basic_hibernator/1,dynamic_call_hibernator/2,messages_in_queue_restart/2, no_heap_loop/0,characters_to_list_trap/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[basic, dynamic_call, min_heap_size, bad_args, messages_in_queue,
- undefined_mfa, no_heap].
+ undefined_mfa, no_heap, wake_up_and_bif_trap].
groups() ->
[].
@@ -384,6 +384,31 @@ clean_dict() ->
lists:foreach(fun ({Key, _}) -> erase(Key) end, Dict).
%%
+%% Wake up and then immediatly bif trap with a lengthy computation.
+%%
+
+wake_up_and_bif_trap(doc) -> [];
+wake_up_and_bif_trap(suite) -> [];
+wake_up_and_bif_trap(Config) when is_list(Config) ->
+ ?line Self = self(),
+ ?line Pid = spawn_link(fun() -> erlang:hibernate(?MODULE, characters_to_list_trap, [Self]) end),
+ ?line Pid ! wakeup,
+ ?line receive
+ {ok, Pid0} when Pid0 =:= Pid -> ok
+ after 5000 ->
+ ?line ?t:fail(process_blocked)
+ end,
+ ?line unlink(Pid),
+ ?line exit(Pid, bye).
+
+%% Lengthy computation that traps (in characters_to_list_trap_3).
+characters_to_list_trap(Parent) ->
+ Bin0 = <<"abcdefghijklmnopqrstuvwxz0123456789">>,
+ Bin = binary:copy(Bin0, 1500),
+ unicode:characters_to_list(Bin),
+ Parent ! {ok, self()}.
+
+%%
%% Misc
%%
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index e7c57142c0..354439b5e3 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -67,6 +67,10 @@ my $max_gen_operands = 8;
# Must be even. The beam_load.c file must be updated, too.
my $max_spec_operands = 6;
+# The maximum number of primitive genop_types.
+
+my $max_genop_types = 16;
+
my %gen_opnum;
my %num_specific;
my %gen_to_spec;
@@ -106,7 +110,7 @@ my @pred_table;
# Operand types for generic instructions.
my $compiler_types = "uiaxyfhz";
-my $loader_types = "nprvlq";
+my $loader_types = "nprvlqo";
my $genop_types = $compiler_types . $loader_types;
#
@@ -142,34 +146,61 @@ my %arg_size = ('r' => 0, # x(0) - x register zero
my %type_bit;
my @tag_type;
+sub define_type_bit {
+ my($tag,$val) = @_;
+ defined $type_bit{$tag} and
+ sanity("the tag '$tag' has already been defined with the value ",
+ $type_bit{$tag});
+ $type_bit{$tag} = $val;
+}
+
{
my($bit) = 1;
my(%bit);
foreach (split('', $genop_types)) {
push(@tag_type, $_);
- $type_bit{$_} = $bit;
+ define_type_bit($_, $bit);
$bit{$_} = $bit;
$bit *= 2;
}
# Composed types.
- $type_bit{'d'} = $type_bit{'x'} | $type_bit{'y'} | $type_bit{'r'};
- $type_bit{'c'} = $type_bit{'i'} | $type_bit{'a'} | $type_bit{'n'} | $type_bit{'q'};
- $type_bit{'s'} = $type_bit{'d'} | $type_bit{'i'} | $type_bit{'a'} | $type_bit{'n'};
- $type_bit{'j'} = $type_bit{'f'} | $type_bit{'p'};
+ define_type_bit('d', $type_bit{'x'} | $type_bit{'y'} | $type_bit{'r'});
+ define_type_bit('c', $type_bit{'i'} | $type_bit{'a'} |
+ $type_bit{'n'} | $type_bit{'q'});
+ define_type_bit('s', $type_bit{'d'} | $type_bit{'i'} |
+ $type_bit{'a'} | $type_bit{'n'});
+ define_type_bit('j', $type_bit{'f'} | $type_bit{'p'});
# Aliases (for matching purposes).
- $type_bit{'I'} = $type_bit{'u'};
- $type_bit{'t'} = $type_bit{'u'};
- $type_bit{'A'} = $type_bit{'u'};
- $type_bit{'L'} = $type_bit{'u'};
- $type_bit{'b'} = $type_bit{'u'};
- $type_bit{'N'} = $type_bit{'u'};
- $type_bit{'U'} = $type_bit{'u'};
- $type_bit{'e'} = $type_bit{'u'};
- $type_bit{'P'} = $type_bit{'u'};
- $type_bit{'Q'} = $type_bit{'u'};
+ define_type_bit('I', $type_bit{'u'});
+ define_type_bit('t', $type_bit{'u'});
+ define_type_bit('A', $type_bit{'u'});
+ define_type_bit('L', $type_bit{'u'});
+ define_type_bit('b', $type_bit{'u'});
+ define_type_bit('N', $type_bit{'u'});
+ define_type_bit('U', $type_bit{'u'});
+ define_type_bit('e', $type_bit{'u'});
+ define_type_bit('P', $type_bit{'u'});
+ define_type_bit('Q', $type_bit{'u'});
+}
+
+#
+# Sanity checks.
+#
+
+{
+ if (@tag_type > $max_genop_types) {
+ sanity("\$max_genop_types is $max_genop_types, ",
+ "but there are ", scalar(@tag_type),
+ " primitive tags defined\n");
+ }
+
+ foreach my $tag (@tag_type) {
+ sanity("tag '$tag': primitive tags must be named with lowercase letters")
+ unless $tag =~ /^[a-z]$/;
+ }
}
#
@@ -436,12 +467,12 @@ sub emulator_output {
#
my(@bits) = (0) x ($max_spec_operands/2);
- my($shift) = 16;
my($i);
for ($i = 0; $i < $max_spec_operands && defined $args[$i]; $i++) {
my $t = $args[$i];
if (defined $type_bit{$t}) {
- $bits[int($i/2)] |= $type_bit{$t} << (16*($i%2));
+ my $shift = $max_genop_types * ($i % 2);
+ $bits[int($i/2)] |= $type_bit{$t} << $shift;
}
}
@@ -753,6 +784,10 @@ sub error {
die $where, @message, "\n";
}
+sub sanity {
+ die "internal error: ", @_, "\n";
+}
+
sub comment {
my($lang, @comments) = @_;
my($prefix);
diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c
index 5dbf98c7d1..35b148990a 100644
--- a/erts/lib_src/common/erl_misc_utils.c
+++ b/erts/lib_src/common/erl_misc_utils.c
@@ -1511,7 +1511,7 @@ const char* parse_topology_spec_group(erts_cpu_info_t *cpuinfo, const char* xml,
}
}
- if (cacheLevel == 0) {
+ if (parentCacheLevel == 0) {
*core_p = 0;
*processor_p = (*processor_p)++;
} else {
diff --git a/erts/lib_src/common/erl_printf_format.c b/erts/lib_src/common/erl_printf_format.c
index fba3fd723c..473791dce4 100644
--- a/erts/lib_src/common/erl_printf_format.c
+++ b/erts/lib_src/common/erl_printf_format.c
@@ -388,7 +388,7 @@ static int fmt_double(fmtfn_t fn,void*arg,double val,
max_size++;
if (precision)
max_size += precision;
- else if (fmt && FMTF_alt)
+ else if (fmt & FMTF_alt)
max_size++;
break;
case FMTC_E:
@@ -402,7 +402,7 @@ static int fmt_double(fmtfn_t fn,void*arg,double val,
max_size += 4;
if (precision)
max_size += precision;
- else if (fmt && FMTF_alt)
+ else if (fmt & FMTF_alt)
max_size++;
aexp = exp >= 0 ? exp : -exp;
if (aexp < 100)
diff --git a/lib/ic/doc/src/notes.xml b/lib/ic/doc/src/notes.xml
index 5f6c31069c..de519d5f84 100644
--- a/lib/ic/doc/src/notes.xml
+++ b/lib/ic/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1998</year><year>2010</year>
+ <year>1998</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,22 @@
</header>
<section>
+ <title>IC 4.2.27</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>
+ Reduced compile overhead (Thanks to Haitao Li).</p>
+ <p>
+ Own Id: OTP-9460 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
<title>IC 4.2.26</title>
<section>
diff --git a/lib/ic/src/ic_pp.erl b/lib/ic/src/ic_pp.erl
index db06118d32..6f09d049da 100644
--- a/lib/ic/src/ic_pp.erl
+++ b/lib/ic/src/ic_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -92,6 +92,14 @@
%%
%%======================================================================================
+%% Multiple Include Optimization
+%%
+%% Algorithm described at:
+%% http://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html
+-record(mio, {valid = true, %% multiple include valid
+ cmacro, %% controlling macro of the current conditional directive
+ depth = 0, %% conditional directive depth
+ included = []}).
@@ -130,7 +138,7 @@ run(FileList, FileName, IncDir, Flags) ->
%%----------------------------------------------------------
%% Run the second phase, i.e expand macros
%%----------------------------------------------------------
- {Out, Err, War, _Defs, IfCou} = expand(File, FileName, IncDir, Flags),
+ {Out, Err, War, _Defs, _Mio, IfCou} = expand(File, FileName, IncDir, Flags),
%%----------------------------------------------------------
%% Check if all #if #ifdef #ifndef have a matching #endif
@@ -155,9 +163,9 @@ run(FileList, FileName, IncDir, Flags) ->
%% The entry for all included files
%%
%%
-%% Output {Out, Defs, Err, War}
+%% Output {Out, Err, War, Defs, MultipleIncludeValid}
%%======================================================================================
-run_include(FileName, FileList, _Out, Defs, Err, War, IncLine, IncFile, IncDir) ->
+run_include(FileName, FileList, _Out, Defs, Err, War, IncLine, IncFile, IncDir, Mio) ->
%%----------------------------------------------------------
%% Run the first phase, i.e tokenise the file
@@ -169,18 +177,21 @@ run_include(FileName, FileList, _Out, Defs, Err, War, IncLine, IncFile, IncDir)
%%----------------------------------------------------------
%% Run the second phase, i.e expand macros
%%----------------------------------------------------------
-
- %% Try first pass without file info start/end
- {OutT, ErrT, WarT, DefsT, IfCouT} =
- expand(File, Defs, Err, War, [FileName|IncFile], IncDir),
-
- {Out2, Err2, War2, Defs2, IfCou2} =
- case only_nls(OutT) of
- true -> %% The file is defined before
- {["\n"], ErrT, WarT, DefsT, IfCouT};
- false -> %% The file is not defined before, try second pass
- expand([FileInfoStart|File]++FileInfoEnd, Defs, Err, War, [FileName|IncFile], IncDir)
- end,
+ {Out2, Err2, War2, Defs2, Mio2, IfCou2} =
+ expand([FileInfoStart|File]++FileInfoEnd, Defs, Err, War,
+ [FileName|IncFile], IncDir,
+ #mio{included=Mio#mio.included}),
+
+ MergeIncluded = sets:to_list(sets:from_list(Mio#mio.included ++ Mio2#mio.included)),
+
+ Mio3 =
+ case {Mio2#mio.valid, Mio2#mio.cmacro} of
+ {V, Macro} when V == false;
+ Macro == undefined ->
+ update_mio(Mio#mio{included=MergeIncluded});
+ {true, _} ->
+ update_mio({include, FileName}, Mio#mio{included=MergeIncluded})
+ end,
%%----------------------------------------------------------
%% Check if all #if #ifdef #ifndef have a matching #endif
@@ -192,26 +203,7 @@ run_include(FileName, FileList, _Out, Defs, Err, War, IncLine, IncFile, IncDir)
[]
end,
- {Out2, Defs2, Err2++IfError, War2}.
-
-
-
-%% Return true if there is no data
-%% other than new lines
-only_nls([]) ->
- true;
-only_nls(["\n"|Rem]) ->
- only_nls(Rem);
-only_nls(["\r","\n"|Rem]) ->
- only_nls(Rem);
-only_nls([_|_Rem]) ->
- false.
-
-
-
-
-
-
+ {Out2, Defs2, Err2++IfError, War2, Mio3}.
@@ -647,87 +639,86 @@ expand(List, FileName, IncDir, Flags) ->
%% Get all definitions from preprocessor commnads
%% and merge them on top of the file collected.
CLDefs = get_cmd_line_defs(Flags),
- expand(List, [], [], CLDefs, [FileName], IncDir, check_all, [], [], 1, FileName).
-
-expand(List, Defs, Err, War, [FileName|IncFile], IncDir) ->
- expand(List, [], [], Defs, [FileName|IncFile], IncDir, check_all, Err, War, 1, FileName).
+ expand(List, [], [], CLDefs, [FileName], IncDir, #mio{}, check_all, [], [], 1, FileName).
+expand(List, Defs, Err, War, [FileName|IncFile], IncDir, Mio) ->
+ expand(List, [], [], Defs, [FileName|IncFile], IncDir, Mio, check_all, Err, War, 1, FileName).
%%=======================================================
%% Main loop for the expansion
%%=======================================================
-expand([], Out, _SelfRef, Defs, _IncFile, _IncDir, IfCou, Err, War, _L, _FN) ->
+expand([], Out, _SelfRef, Defs, _IncFile, _IncDir, Mio, IfCou, Err, War, _L, _FN) ->
% io:format("~n ===============~n"),
% io:format(" definitions ~p~n",[lists:reverse(Defs)]),
% io:format(" found warnings ~p~n",[lists:reverse(War)]),
% io:format(" found errors ~p~n",[lists:reverse(Err)]),
% io:format(" ===============~n~n~n"),
- {Out, Err, War, Defs, IfCou};
+ {Out, Err, War, Defs, Mio, IfCou};
-expand([{file_info, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, Str++Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+expand([{file_info, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
+ expand(Rem, Str++Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN);
%%---------------------------------------
%% Searching for endif,
%% i.e skip all source lines until matching
%% end if is encountered
%%---------------------------------------
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN)
+expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN)
when Command == "ifdef" ->
{_Removed, Rem2, _Nl} = read_to_nl(Rem),
IfCou2 = {endif, Endif+1, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err, War, L, FN);
+ expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err, War, L, FN);
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN)
+expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN)
when Command == "ifndef" ->
{_Removed, Rem2, _Nl} = read_to_nl(Rem),
IfCou2 = {endif, Endif+1, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err, War, L, FN);
+ expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err, War, L, FN);
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN)
+expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN)
when Command == "if" ->
- case pp_command(Command, Rem, Defs, IncDir, Err, War, L, FN) of
+ case pp_command(Command, Rem, Defs, IncDir, Mio, Err, War, L, FN) of
{{'if', true}, Rem2, Err2, War2, Nl} ->
IfCou2 = {endif, Endif+1, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN);
+ expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN);
%% {{'if', false}, Rem2, Err2, War2, Nl} -> Not implemented yet
{{'if', error}, Rem2, Err2, War2, Nl} ->
IfCou2 = {endif, Endif, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN)
+ expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN)
end;
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN)
+expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN)
when Command == "endif" ->
{_Removed, Rem2, Nl} = read_to_nl(Rem),
case Endif of
1 ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, check_all, Err, War, L+Nl, FN);
_ ->
IfCou2 = {endif, Endif-1, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err, War, L+Nl, FN)
+ expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err, War, L+Nl, FN)
end;
-expand([{command,_Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) ->
+expand([{command,_Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN) ->
{_Removed, Rem2, _Nl} = read_to_nl(Rem),
IfCou2 = {endif, Endif, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err, War, L, FN);
+ expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err, War, L, FN);
%% Solves a bug when spaces in front of hashmark !
-expand([space | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) ->
- expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN);
+expand([space | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN) ->
+ expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN);
-expand([{nl,_Nl} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) ->
- expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN);
+expand([{nl,_Nl} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN) ->
+ expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN);
-expand([_X | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) ->
+expand([_X | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN) ->
{_Removed, Rem2, Nl} = read_to_nl(Rem),
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN);
@@ -736,121 +727,132 @@ expand([_X | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine},
%%---------------------------------------
%% Check all tokens
%%---------------------------------------
-expand([{nl, _N} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, [$\n | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L+1, FN);
+expand([{nl, _N} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
+ expand(Rem, [$\n | Out], SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L+1, FN);
-expand([space | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, [?space | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+expand([space | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
+ expand(Rem, [?space | Out], SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN);
-expand([space_exp | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, [?space | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+expand([space_exp | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
+ expand(Rem, [?space | Out], SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN);
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L, FN) ->
- case pp_command(Command, Rem, Defs, IncDir, Err, War, L, FN) of
+expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, check_all, Err, War, L, FN) ->
+ case pp_command(Command, Rem, Defs, IncDir, Mio, Err, War, L, FN) of
{define, Rem2, Defs2, Err2, War2, Nl} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs2, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ expand(Rem2, Out2, SelfRef, Defs2, IncFile, IncDir, update_mio(Mio), check_all, Err2, War2, L+Nl, FN);
{undef, Rem2, Defs2, Err2, War2, Nl} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs2, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ expand(Rem2, Out2, SelfRef, Defs2, IncFile, IncDir, update_mio(Mio), check_all, Err2, War2, L+Nl, FN);
{{include, ok}, FileName, FileCont, Rem2, Nl, Err2, War2} ->
- {Out3, Defs3, Err3, War3} =
- run_include(FileName, FileCont, Out, Defs, Err2, War2, L+Nl, IncFile, IncDir),
+ {Out3, Defs3, Err3, War3, Mio2} =
+ run_include(FileName, FileCont, Out, Defs, Err2, War2, L+Nl, IncFile, IncDir, Mio),
Nls = [],
Out4 = Out3++Nls++Out,
- expand(Rem2, Out4, SelfRef, Defs3, IncFile, IncDir, check_all, Err3, War3, L+Nl, FN);
+ expand(Rem2, Out4, SelfRef, Defs3, IncFile, IncDir, Mio2, check_all, Err3, War3, L+Nl, FN);
{{include, error}, Rem2, Nl, Err2, War2} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err2, War2, L+Nl, FN);
+
+ {{include, skip}, Rem2} ->
+ Out2 = [$\n|Out],
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err, War, L+1, FN);
{{ifdef, true}, Rem2, Err2, War2, Nl} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
IfCou2 = {endif, 1, L},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN);
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN);
{{ifdef, false}, Rem2, Err2, War2, Nl} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ Mio2 = update_mio(ifdef, Mio),
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err2, War2, L+Nl, FN);
{{ifndef, true}, Rem2, Err2, War2, Nl} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
IfCou2 = {endif, 1, L},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN);
- {{ifndef, false}, Rem2, Err2, War2, Nl} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN);
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN);
+ {{ifndef, false}, Macro, Rem2, Err2, War2, Nl} ->
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ Mio2 = update_mio({ifudef, Macro}, Mio),
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err2, War2, L+Nl, FN);
{endif, Rem2, Err2, War2, Nl} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ Mio2 = update_mio(endif, Mio),
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err2, War2, L+Nl, FN);
{{'if', true}, Rem2, Err2, War2, Nl} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
IfCou2 = {endif, 1, L},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN);
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN);
%% {{'if', false}, Removed, Rem2, Nl} -> Not implemented at present
{{'if', error}, Rem2, Err2, War2, Nl} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ Mio2 = update_mio('if', Mio),
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err2, War2, L+Nl, FN);
{'else', {_Removed, Rem2, Nl}} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
Err2 = {FN, L, "`else' command is not implemented at present"},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN);
+ Mio2 = update_mio('else', Mio),
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, [Err2|Err], War, L+Nl, FN);
{'elif', {_Removed, Rem2, Nl}} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
Err2 = {FN, L, "`elif' command is not implemented at present"},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN);
+ Mio2 = update_mio('elif', Mio),
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, [Err2|Err], War, L+Nl, FN);
{warning, {WarningText, Rem2, Nl}} ->
[FileName|_More] = IncFile,
War2 = {FileName, L, "warning: #warning "++detokenise(WarningText)},
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, [War2|War], L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err, [War2|War], L+Nl, FN);
{error, {ErrorText, Rem2, Nl}} ->
[FileName|_More] = IncFile,
Err2 = {FileName, L, detokenise(ErrorText)},
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, [Err2|Err], War, L+Nl, FN);
{{line, ok}, {_Removed, Rem2, Nl}, L2, FN2, LineText} ->
Out2 = lists:duplicate(Nl,$\n)++LineText++Out,
[_X|IF] = IncFile,
IncFile2 = [FN2|IF],
- expand(Rem2, Out2, SelfRef, Defs, IncFile2, IncDir, check_all, Err, War, L2, FN2);
+ expand(Rem2, Out2, SelfRef, Defs, IncFile2, IncDir, update_mio(Mio), check_all, Err, War, L2, FN2);
{{line, error}, {_Removed, Rem2, Nl}, Err2} ->
- Out2 = [lists:duplicate(Nl,$\n)|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN);
+ Out2 = lists:duplicate(Nl,$\n) ++ Out,
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, [Err2|Err], War, L+Nl, FN);
hash_mark ->
- expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L, FN);
+ expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, Mio, check_all, Err, War, L, FN);
{pragma, Rem2, Nl, Text} ->
Out2 = lists:duplicate(Nl,$\n)++Text++Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN);
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err, War, L+Nl, FN);
{ident, Rem2, Nl, Text} ->
Out2 = lists:duplicate(Nl,$\n)++Text++Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN);
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err, War, L+Nl, FN);
{not_recognised, {Removed, Rem2, Nl}} ->
Text = lists:reverse([$#|Command]),
RemovedS = lists:reverse([?space|detokenise(Removed)]),
Out2 = [$\n|RemovedS]++Text++Out,
+ Mio2 = update_mio(Mio),
case Command of
[X|_T] when ?is_upper(X) ->
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN);
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err, War, L+Nl, FN);
[X|_T] when ?is_lower(X) ->
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN);
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err, War, L+Nl, FN);
[X|_T] when ?is_underline(X) ->
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN);
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err, War, L+Nl, FN);
_ ->
Err2 = {FN, L, "invalid preprocessing directive name"},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN)
+ expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, [Err2|Err], War, L+Nl, FN)
end;
Else ->
@@ -859,19 +861,19 @@ expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, check_all
end;
-expand([{var, "__LINE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
+expand([{var, "__LINE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
LL = io_lib:format("~p",[L]),
- expand(Rem, [LL | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+ expand(Rem, [LL | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{var, "__FILE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, [$",FN,$" | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+expand([{var, "__FILE__"}|Rem], Out, SelfRef, Defs, IncFile, Mio, IncDir, IfCou, Err, War, L, FN) ->
+ expand(Rem, [$",FN,$" | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{var, "__DATE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
+expand([{var, "__DATE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
{{Y,M,D},{_H,_Mi,_S}} = calendar:universal_time(),
Date = io_lib:format("\"~s ~p ~p\"",[month(M),D,Y]),
- expand(Rem, [Date | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+ expand(Rem, [Date | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{var, "__TIME__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
+expand([{var, "__TIME__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
{{_Y,_M,_D},{H,Mi,S}} = calendar:universal_time(),
HS = if H < 10 -> "0"++integer_to_list(H);
true -> integer_to_list(H)
@@ -883,40 +885,40 @@ expand([{var, "__TIME__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err,
true -> integer_to_list(S)
end,
Time = io_lib:format("\"~s:~s:~s\"",[HS,MiS,SS]),
- expand(Rem, [Time | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+ expand(Rem, [Time | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{var, "__INCLUDE_LEVEL__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
+expand([{var, "__INCLUDE_LEVEL__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
IL = io_lib:format("~p",[length(IncFile)-1]),
- expand(Rem, [IL | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+ expand(Rem, [IL | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{var, "__BASE_FILE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
+expand([{var, "__BASE_FILE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
[BF|_T] = lists:reverse(IncFile),
- expand(Rem, [$",BF,$" | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+ expand(Rem, [$",BF,$" | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{var, Var} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
+expand([{var, Var} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
{Out2, Err2, War2, Rem2, SelfRef2} =
source_line(Var, Rem, SelfRef, Defs, Err, War, L, FN),
- expand(Rem2, [Out2 | Out], SelfRef2, Defs, IncFile, IncDir, IfCou, Err2, War2, L, FN);
+ expand(Rem2, [Out2 | Out], SelfRef2, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err2, War2, L, FN);
-expand([{char, Char} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, [Char | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+expand([{char, Char} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
+ expand(Rem, [Char | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{number, Number} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, [Number | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+expand([{number, Number} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
+ expand(Rem, [Number | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{expanded, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, [Str | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+expand([{expanded, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
+ expand(Rem, [Str | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{self_ref, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
+expand([{self_ref, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
SelfRef2 = lists:delete(Str,SelfRef),
- expand(Rem, Out, SelfRef2, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+ expand(Rem, Out, SelfRef2, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{string, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, [$", Str, $" | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN);
+expand([{string, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
+ expand(Rem, [$", Str, $" | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-expand([{string_part, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) ->
+expand([{string_part, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
{Str2, Rem2, Nl} = expand_string_part([$"|Str], Rem),
- expand(Rem2, [Str2| Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L+Nl, FN).
+ expand(Rem2, [Str2| Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L+Nl, FN).
@@ -954,13 +956,14 @@ expand_string_part([{string_part, Str_part} | Rem], Str, Nl) ->
get_cmd_line_defs(Flags) ->
Adjusted = parse_cmd_line(Flags,[]),
- {_Out, _Err, _War, Defs, _IfCou} =
+ {_Out, _Err, _War, Defs, _IfCou, _Mio} =
expand(tokenise(Adjusted,""),
[],
[],
[],
[],
[],
+ #mio{},
check_all,
[],
[],
@@ -1030,10 +1033,10 @@ collect_undefine([C|Rest],Found) ->
%%======================================================================================
%%======================================================================================
-pp_command(Command, [space|File], Defs, IncDir, Err, War, L, FN) ->
- pp_command(Command, File, Defs, IncDir, Err, War, L, FN);
+pp_command(Command, [space|File], Defs, IncDir, Mio, Err, War, L, FN) ->
+ pp_command(Command, File, Defs, IncDir, Mio, Err, War, L, FN);
-pp_command(Command, File, Defs, IncDir, Err, War, L, FN) ->
+pp_command(Command, File, Defs, IncDir, Mio, Err, War, L, FN) ->
case Command of
%%----------------------------------------
@@ -1081,14 +1084,16 @@ pp_command(Command, File, Defs, IncDir, Err, War, L, FN) ->
%% #include
%%----------------------------------------
"include" ->
- case include(File, IncDir) of
- {error, Rem, Nl, Err2} ->
- {{include, error}, Rem, Nl, [{FN, L, Err2}|Err], War};
- {error, Rem, Nl, Err2, NameNl} ->
- {{include, error}, Rem, Nl, [{FN, L+ NameNl, Err2}|Err], War};
- {ok, FileName, FileCont, Rem, Nl} ->
- {{include, ok}, FileName, FileCont, Rem, Nl, Err, War}
- end;
+ case include(File, IncDir, Mio) of
+ {error, Rem, Nl, Err2} ->
+ {{include, error}, Rem, Nl, [{FN, L, Err2}|Err], War};
+ {error, Rem, Nl, Err2, NameNl} ->
+ {{include, error}, Rem, Nl, [{FN, L+ NameNl, Err2}|Err], War};
+ {ok, FileNamePath, FileCont, Rem, Nl} ->
+ {{include, ok}, FileNamePath, FileCont, Rem, Nl, Err, War};
+ {skip, Rem} ->
+ {{include, skip}, Rem}
+ end;
%%----------------------------------------
%% #ifdef
@@ -1127,14 +1132,14 @@ pp_command(Command, File, Defs, IncDir, Err, War, L, FN) ->
yes ->
{{ifndef, true}, Rem, Err2, War2, Nl};
no ->
- {{ifndef, false}, Rem, Err2, War2, Nl}
+ {{ifndef, false}, Name, Rem, Err2, War2, Nl}
end;
{ok, Rem, Name, No_of_para, _Parameters, _Macro, Err2, War2, Nl} ->
case is_defined_before(Name, No_of_para, Defs) of
yes ->
{{ifndef, true}, Rem, Err2, War2, Nl};
no ->
- {{ifndef, false}, Rem, Err2, War2, Nl}
+ {{ifndef, false}, Name, Rem, Err2, War2, Nl}
end
end;
@@ -1408,29 +1413,32 @@ undef(_Rem) ->
%%===============================================================
%%===============================================================
-include(File, IncDir) ->
+include(File, IncDir, Mio) ->
case include2(File) of
- {ok, FileName, Rem, Nl, FileType} ->
- %% The error handling is lite strange just to make it compatible to gcc
- case {read_inc_file(FileName, IncDir), Nl, FileType} of
- {{ok, FileList, FileNamePath}, _, _} ->
- {ok, FileNamePath, FileList, Rem, Nl};
- {{error, Text}, _, own_file} ->
- NameNl = count_nl(FileName,0),
- Error = lists:flatten(io_lib:format("~s: ~s",[FileName,Text])),
- {error, Rem, Nl, Error, NameNl};
- {{error, Text}, 1, sys_file} ->
- NameNl = count_nl(FileName,0),
- Error = lists:flatten(io_lib:format("~s: ~s",[FileName,Text])),
- {error, Rem, Nl, Error, NameNl};
- {{error, _Text}, _, sys_file} ->
- {error, Rem, Nl, "`#include' expects \"FILENAME\" or <FILENAME>"}
- end;
-
- {error, {_Removed, Rem, Nl}} ->
- {error, Rem, Nl, "`#include' expects \"FILENAME\" or <FILENAME>"}
+ {ok, FileName, Rem, Nl, FileType} ->
+ Result = read_inc_file(FileName, IncDir, Mio),
+ case {Result, Nl, FileType} of
+ {{ok, FileNamePath, FileCont}, _, _} ->
+ {ok, FileNamePath, FileCont, Rem, Nl};
+ {skip, _, _} ->
+ {skip, Rem};
+ {{error, Text}, _, own_file} ->
+ NameNl = count_nl(FileName,0),
+ Error = lists:flatten(io_lib:format("~s: ~s",[FileName,Text])),
+ {error, Rem, Nl, Error, NameNl};
+ {{error, Text}, 1, sys_file} ->
+ NameNl = count_nl(FileName,0),
+ Error = lists:flatten(io_lib:format("~s: ~s",[FileName,Text])),
+ {error, Rem, Nl, Error, NameNl};
+ {{error, _Text}, _, sys_file} ->
+ {error, Rem, Nl, "`#include' expects \"FILENAME\" or <FILENAME>"}
+ end;
+ {error, {_Removed, Rem, Nl}} ->
+ {error, Rem, Nl, "`#include' expects \#FILENAME\" or <FILENAME>"}
end.
+
+
count_nl([],Nl) ->
Nl;
count_nl([$\n|T],Nl) ->
@@ -1909,18 +1917,37 @@ include_dir(Flags,IncDir) ->
%% Read a included file. Try current dir first then the IncDir list
%%===============================================================
-read_inc_file(FileName, IncDir) ->
- case catch file:read_file(FileName) of
- {ok, Bin} ->
- FileList = binary_to_list(Bin),
- {ok, FileList, FileName};
+read_inc_file(FileName, IncDir, Mio) ->
+ case find_inc_file(FileName, IncDir) of
+ {ok, AbsFile} ->
+ %% is included before?
+ case lists:member(FileName, Mio#mio.included) of
+ false ->
+ case catch file:read_file(AbsFile) of
+ {ok, Bin} ->
+ FileList = binary_to_list(Bin),
+ {ok, AbsFile, FileList};
+ {error, Text} ->
+ {error, Text}
+ end;
+ true ->
+ skip
+ end;
+ {error, Text} ->
+ {error, Text}
+ end.
+
+find_inc_file(FileName, IncDir) ->
+ case catch file:read_file_info(FileName) of
+ {ok, _} ->
+ {ok, FileName};
{error, _} ->
- read_inc_file2(FileName, IncDir)
+ find_inc_file2(FileName, IncDir)
end.
-read_inc_file2(_FileName, []) ->
+find_inc_file2(_FileName, []) ->
{error, "No such file or directory"};
-read_inc_file2(FileName, [D|Rem]) ->
+find_inc_file2(FileName, [D|Rem]) ->
Dir = case lists:last(D) of
$/ ->
D;
@@ -1928,17 +1955,14 @@ read_inc_file2(FileName, [D|Rem]) ->
D++"/"
end,
- case catch file:read_file(Dir++FileName) of
- {ok, Bin} ->
- FileList = binary_to_list(Bin),
- {ok, FileList, Dir++FileName};
+ case catch file:read_file_info(Dir++FileName) of
+ {ok, _} ->
+ {ok, Dir++FileName};
{error, _} ->
- read_inc_file2(FileName, Rem)
+ find_inc_file2(FileName, Rem)
end.
-
-
%%===============================================================
%% Read parameters of a macro or a variable in a source line
%%===============================================================
@@ -2135,5 +2159,73 @@ month(11) -> "Nov";
month(12) -> "Dec".
+%% Multiple Include Optimization
+%%
+%% Algorithm described at:
+%% http://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html
+update_mio({include, FileName}, #mio{included=Inc}=Mio) ->
+ Mio#mio{valid=false, included=[FileName|Inc]};
+
+%% valid=false & cmacro=undefined indicates it is already decided this file is
+%% not subject to MIO
+update_mio(_, #mio{valid=false, depth=0, cmacro=undefined}=Mio) ->
+ Mio;
+
+%% if valid=true, there is no non-whitespace tokens before this ifudef
+update_mio({'ifudef', Macro}, #mio{valid=true, depth=0, cmacro=undefined}=Mio) ->
+ Mio#mio{valid=false, cmacro=Macro, depth=1};
+
+%% detect any tokens before top level #ifudef
+update_mio(_, #mio{valid=true, depth=0, cmacro=undefined}=Mio) ->
+ Mio#mio{valid=false};
+
+%% If cmacro is alreay set, this is after the top level #endif
+update_mio({'ifudef', _}, #mio{valid=true, depth=0}=Mio) ->
+ Mio#mio{valid=false, cmacro=undefined};
+
+%% non-top level conditional, just update depth
+update_mio({'ifudef', _}, #mio{depth=D}=Mio) when D > 0 ->
+ Mio#mio{depth=D+1};
+update_mio('ifdef', #mio{depth=D}=Mio) ->
+ Mio#mio{depth=D+1};
+update_mio('if', #mio{depth=D}=Mio) ->
+ Mio#mio{depth=D+1};
+
+%% top level #else #elif invalidates multiple include optimization
+update_mio('else', #mio{depth=1}=Mio) ->
+ Mio#mio{valid=false, cmacro=undefined};
+update_mio('else', Mio) ->
+ Mio;
+update_mio('elif', #mio{depth=1}=Mio) ->
+ Mio#mio{valid=false, cmacro=undefined};
+update_mio('elif', Mio) ->
+ Mio;
+
+%% AT exit to top level, if the controlling macro is not set, this could be the
+%% end of a non-ifudef conditional block, or there were tokens before entering
+%% the #ifudef block. In either way, this invalidates the MIO
+%%
+%% It doesn't matter if `valid` is true at the time of exiting, it is set to
+%% true. This will be used to detect if more tokens are following the top
+%% level #endif.
+update_mio('endif', #mio{depth=1, cmacro=undefined}=Mio) ->
+ Mio#mio{valid=false, depth=0};
+update_mio('endif', #mio{depth=1}=Mio) ->
+ Mio#mio{valid=true, depth=0};
+update_mio('endif', #mio{depth=D}=Mio) when D > 1 ->
+ Mio#mio{valid=true, depth=D-1};
+
+%%if more tokens are following the top level #endif.
+update_mio('endif', #mio{depth=1, cmacro=undefined}=Mio) ->
+ Mio#mio{valid=false, depth=0};
+update_mio('endif', #mio{depth=D}=Mio) when D > 0 ->
+ Mio#mio{valid=true, depth=D-1};
+update_mio(_, Mio) ->
+ Mio#mio{valid=false}.
+
+%% clear `valid`, this doesn't matter since #endif will restore it if
+%% appropriate
+update_mio(Mio) ->
+ Mio#mio{valid=false}.
diff --git a/lib/ic/src/ic_pragma.erl b/lib/ic/src/ic_pragma.erl
index 45cb64c9c8..7f2216b9dc 100644
--- a/lib/ic/src/ic_pragma.erl
+++ b/lib/ic/src/ic_pragma.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1600,9 +1600,8 @@ remove_inheriters(S,RS,InheriterList) ->
[_OneOnly] ->
ReducedInhList;
_Other ->
- EtsList = ets:tab2list(S),
CleanList =
- [X || X <- EtsList, element(1,X) == inherits],
+ ets:match(S, {inherits,'_','_'}),
% CodeOptList =
% [X || X <- EtsList, element(1,X) == codeopt],
NoInheriters =remove_inheriters2(S,ReducedInhList,CleanList),
@@ -1648,9 +1647,8 @@ remove_inh([X],[Y],List,EtsList) ->
%%% from others in the list
%%%----------------------------------------------
remove_inherited(S,InheriterList) ->
- EtsList = ets:tab2list(S),
CleanList =
- [X || X <- EtsList, element(1,X) == inherits],
+ ets:match(S, {inherits, '_', '_'}),
remove_inherited(S,InheriterList,CleanList).
@@ -1694,11 +1692,8 @@ remove_inhed([X],[Y],List,EtsList) ->
%% are inherited from scope in the list
%%%----------------------------------------------
get_inherited(S,Scope,OpScopeList) ->
- EtsList = ets:tab2list(S),
- [[element(3,X)] || X <- EtsList,
- element(1,X) == inherits,
- element(2,X) == Scope,
- member([element(3,X)],OpScopeList)].
+ EtsList1 = ets:match(S, {inherits, Scope, '$1'}),
+ [X || X <- EtsList1, member(X, OpScopeList)].
@@ -1771,9 +1766,7 @@ inherits2(_X,Y,Z,EtsList) ->
%% false otherwise
%%
is_inherited_by(Interface1,Interface2,PragmaTab) ->
- FullList = ets:tab2list(PragmaTab),
- InheritsList =
- [X || X <- FullList, element(1,X) == inherits],
+ InheritsList = ets:match(PragmaTab, {inherits, '_', '_'}),
inherits(Interface2,Interface1,InheritsList).
diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk
index 6d6c7fa625..6561ccd2a7 100644
--- a/lib/ic/vsn.mk
+++ b/lib/ic/vsn.mk
@@ -1 +1 @@
-IC_VSN = 4.2.26
+IC_VSN = 4.2.27
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index d8a5519195..b734d7fd98 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -400,6 +400,7 @@ open_fd(Config) when is_list(Config) ->
{ok,S1} = gen_udp:open(0),
{ok,P2} = inet:port(S1),
{ok,FD} = prim_inet:getfd(S1),
+ {error,einval} = gen_udp:open(P2, [inet6, {fd,FD}]),
{ok,S2} = gen_udp:open(P2, [{fd,FD}]),
{ok,S3} = gen_udp:open(0),
{ok,P3} = inet:port(S3),
diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml
index d15383c621..4900a8f0ef 100644
--- a/lib/stdlib/doc/src/gen_fsm.xml
+++ b/lib/stdlib/doc/src/gen_fsm.xml
@@ -438,7 +438,7 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
<fsummary>Initialize process and internal state name and state data.</fsummary>
<type>
<v>Args = term()</v>
- <v>Return = {ok,StateName,StateData} | {ok,StateName,StateData,Timeout}</v>
+ <v>Result = {ok,StateName,StateData} | {ok,StateName,StateData,Timeout}</v>
<v>&nbsp;&nbsp;| {ok,StateName,StateData,hibernate}</v>
<v>&nbsp;&nbsp;| {stop,Reason} | ignore</v>
<v>&nbsp;StateName = atom()</v>
diff --git a/lib/stdlib/src/timer.erl b/lib/stdlib/src/timer.erl
index e3d6c905b6..689e42051f 100644
--- a/lib/stdlib/src/timer.erl
+++ b/lib/stdlib/src/timer.erl
@@ -199,7 +199,7 @@ tc(M, F, A) ->
%% Calculate the time difference (in microseconds) of two
%% erlang:now() timestamps, T2-T1.
%%
--spec now_diff(T1, T2) -> Tdiff when
+-spec now_diff(T2, T1) -> Tdiff when
T1 :: erlang:timestamp(),
T2 :: erlang:timestamp(),
Tdiff :: integer().
diff --git a/lib/xmerl/include/xmerl_xsd.hrl b/lib/xmerl/include/xmerl_xsd.hrl
index b527accc8c..6dad7d8ff0 100644
--- a/lib/xmerl/include/xmerl_xsd.hrl
+++ b/lib/xmerl/include/xmerl_xsd.hrl
@@ -36,6 +36,7 @@
schema_name,
vsn,
schema_preprocessed=false,
+ external_xsd_base=false,
xsd_base,
xml_options=[],
scope=[],
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index 059c8f21b6..e598c5f56d 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -2276,7 +2276,7 @@ scan_att_chars([H|T], S0, H, Acc, TmpAcc,AttType,IsNorm) -> % End quote
true ->
normalize(Acc,S,IsNorm)
end,
- {lists:reverse(Acc2), T, S2,IsNorm2};
+ {lists:flatten(lists:reverse(Acc2)), T, S2,IsNorm2};
scan_att_chars("&" ++ T, S0, Delim, Acc, TmpAcc,AT,IsNorm) -> % Reference
?bump_col(1),
{ExpRef, T1, S1} = scan_reference(T, S),
diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl
index e56f1470c0..f003cc74ba 100644
--- a/lib/xmerl/src/xmerl_xsd.erl
+++ b/lib/xmerl/src/xmerl_xsd.erl
@@ -287,10 +287,19 @@ process_schema(Schema) ->
%% error reason. The error reason may be a list of several errors
%% or a single error encountered during the processing.
process_schema(Schema,Options) when is_list(Options) ->
- S = initiate_state(Options,Schema),
- process_schema2(xmerl_scan:file(filename:join(S#xsd_state.xsd_base, Schema)),S,Schema);
-process_schema(Schema,State) when is_record(State,xsd_state) ->
- process_schema2(xmerl_scan:file(filename:join(State#xsd_state.xsd_base, Schema)),State,Schema).
+ State = initiate_state(Options,Schema),
+ process_schema(Schema, State);
+process_schema(Schema, State=#xsd_state{fetch_fun=Fetch})->
+ case Fetch(Schema, State) of
+ {ok,{file,File},_} ->
+ process_schema2(xmerl_scan:file(File), State, Schema);
+ {ok,{string,Str},_} ->
+ process_schema2(xmerl_scan:string(Str), State, Schema);
+ {ok,[],_} ->
+ {error,enoent};
+ Err ->
+ Err
+ end.
process_schema2(Err={error,_},_,_) ->
Err;
@@ -319,12 +328,9 @@ process_schemas(Schemas) ->
%% error reason. The error reason may be a list of several errors
%% or a single error encountered during the processing.
process_schemas(Schemas=[{_,Schema}|_],Options) when is_list(Options) ->
- process_schemas(Schemas,initiate_state(Options,Schema));
+ State = initiate_state(Options,Schema),
+ process_schemas(Schemas, State);
process_schemas([{_NS,Schema}|Rest],State=#xsd_state{fetch_fun=Fetch}) ->
-%% case process_external_schema_once(Schema,if_list_to_atom(NS),State) of
-%% S when is_record(S,xsd_state) ->
-%% case process_schema(filename:join([State#xsd_state.xsd_base,Schema]),State) of
-%% {ok,S} ->
Res=
case Fetch(Schema,State) of
{ok,{file,File},_} ->
@@ -345,20 +351,20 @@ process_schemas([{_NS,Schema}|Rest],State=#xsd_state{fetch_fun=Fetch}) ->
process_schemas([],S) when is_record(S,xsd_state) ->
{ok,S}.
-
initiate_state(Opts,Schema) ->
XSDBase = filename:dirname(Schema),
{{state,S},RestOpts}=new_state(Opts),
S2 = create_tables(S),
- initiate_state2(S2#xsd_state{schema_name = Schema,
- xsd_base = XSDBase,
- fetch_fun = fun fetch/2},RestOpts).
+ S3 = initiate_state2(S2#xsd_state{schema_name = Schema, xsd_base=XSDBase,
+ fetch_fun = fun fetch/2},
+ RestOpts).
+
initiate_state2(S,[]) ->
S;
initiate_state2(S,[{tab2file,Bool}|T]) ->
initiate_state2(S#xsd_state{tab2file=Bool},T);
-initiate_state2(S,[{xsdbase,XSDBase}|T]) ->
- initiate_state2(S#xsd_state{xsd_base=XSDBase},T);
+initiate_state2(S,[{xsdbase, XSDBase}|T]) ->
+ initiate_state2(S#xsd_state{xsd_base=XSDBase, external_xsd_base=true},T);
initiate_state2(S,[{fetch_fun,FetchFun}|T]) ->
initiate_state2(S#xsd_state{fetch_fun=FetchFun},T);
initiate_state2(S,[{fetch_path,FetchPath}|T]) ->
@@ -5232,7 +5238,12 @@ fetch(URI,S) ->
[] -> %% empty systemliteral
[];
_ ->
- filename:join(S#xsd_state.xsd_base, URI)
+ case S#xsd_state.external_xsd_base of
+ true ->
+ filename:join(S#xsd_state.xsd_base, URI);
+ false ->
+ filename:join(S#xsd_state.xsd_base, filename:basename(URI))
+ end
end,
Path = path_locate(S#xsd_state.fetch_path, Filename, Fullname),
?dbg("fetch(~p) -> {file, ~p}.~n", [URI, Path]),
diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl
index 392b2522e8..0c809dbcb6 100644
--- a/lib/xmerl/test/xmerl_SUITE.erl
+++ b/lib/xmerl/test/xmerl_SUITE.erl
@@ -57,7 +57,8 @@ groups() ->
{eventp_tests, [], [sax_parse_and_export]},
{ticket_tests, [],
[ticket_5998, ticket_7211, ticket_7214, ticket_7430,
- ticket_6873, ticket_7496, ticket_8156, ticket_8697]},
+ ticket_6873, ticket_7496, ticket_8156, ticket_8697,
+ ticket_9411]},
{app_test, [], [{xmerl_app_test, all}]},
{appup_test, [], [{xmerl_appup_test, all}]}].
@@ -575,7 +576,17 @@ ticket_8697(Config) ->
?line [16#545C] = HexEntityText,
ok.
+ticket_9411(suite) -> [];
+ticket_9411(doc) ->
+ ["Test that xmerl_scan handles attribute that contains for example &quot"];
+ticket_9411(Config) ->
+ DataDir = ?config(data_dir,Config),
+ ?line {ok, Schema} = xmerl_xsd:process_schema(filename:join([DataDir,"misc/ticket_9411.xsd"])),
+ ?line {ok, Bin} = file:read_file(filename:join([DataDir,"misc/ticket_9411.xml"])),
+ ?line Xml = erlang:binary_to_list(Bin),
+ ?line {E, _} = xmerl_scan:string(Xml),
+ ?line {E, _} = xmerl_xsd:validate(E, Schema).
diff --git a/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz b/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz
index c48a6f897b..fef7431845 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz
+++ b/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz
Binary files differ
diff --git a/lib/xmerl/test/xmerl_xsd_SUITE.erl b/lib/xmerl/test/xmerl_xsd_SUITE.erl
index a0d3b1e667..421fa48054 100644
--- a/lib/xmerl/test/xmerl_xsd_SUITE.erl
+++ b/lib/xmerl/test/xmerl_xsd_SUITE.erl
@@ -62,7 +62,7 @@ groups() ->
sis2, state2file_file2state, union]},
{ticket_tests, [],
[ticket_6910, ticket_7165, ticket_7190, ticket_7288,
- ticket_7736, ticket_8599]},
+ ticket_7736, ticket_8599, ticket_9410]},
{facets, [],
[length, minLength, maxLength, pattern, enumeration,
whiteSpace, maxInclusive, maxExclusive, minExclusive,
@@ -1146,3 +1146,8 @@ ticket_8599(Config) ->
?line {{xmlElement,persons,persons,_,_,_,_,_,_,_,_,_},_GlobalState} = xmerl_xsd:validate(E, S).
+
+ticket_9410(suite) -> [];
+ticket_9410(Config) ->
+ file:set_cwd(filename:join([?config(data_dir,Config),".."])),
+ ?line {ok, _S} = xmerl_xsd:process_schema("xmerl_xsd_SUITE_data/small.xsd").