The concern is that we need Foo.nestHost == Rational.nestHost and that
the common nestHost includes both Foo and Rational as nestMembers. To
do that, we need to load the nestHost class (if it isn't already).
Getting the interaction between the access check and the additional
class loads right
Here are two examples of where a B2 class could safely and
beneficially use B2.val:
value class Rational {
Rational[] harmonicSeq(int n) {
Rational.val[] rs = new Rational.val[n];
for (int i=0; irationals could be flat.
; some value classes encapsulate the val
type; some value classes further relax the integrity requirements of instances
on the heap, to get better flattening and performance, when their semantics
don't require it.
It's an orthogonal choice whether the default is "val is private&q
And with Rational.val requiring atomic access, we can only flatten it
if the underlying HW supports it (in this case, 2 ints fits nicely in
64bits so we're good). Larger .val's can only be flattened if marked
as "non-atomic" (the B3n case). And because there's no tearing,
handing out the flat
The val type for B2 should not exist at all
So B2 is really a B3a whose value projection is encapsulated.
and here you lost me, .ref and .val are supposed to be projection
types not classes, at runtime there is only one class.
And apparently I have to say this again It's fine
asses are
treated uniformly (ref-default, have a val); some value classes
encapsulate the val type; some value classes further relax the integrity
requirements of instances on the heap, to get better flattening and
performance, when their semantics don't require it.
It's an orthogonal
This makes no sense. We are not introducing a notion of reference type into the
spec. The spec is already completely riddled with the concept of references and
reference types. In fact many of the constraints that influence the current
design come from that fact.
Sent from my iPad
> On Jun 6,
omeone tore it and
then boxed it. I don't see how we defend against this, but the
non-atomic label should be enough of a warning.)
On 5/6/2022 10:04 AM, Brian Goetz wrote:
In this model, (non-atomic B3).ref takes the place of (non-atomic B2)
in the stacking I've been discussing.
On 6/3/2022 1:39 PM, Remi Forax wrote:
*From: *"Brian Goetz"
*To: *"daniel smith" ,
"valhalla-spec-experts"
*Sent: *Friday, June 3, 2022 6:21:26 PM
*Subject
There is no chance to get any calling-convention optimization here,
since the concrete class name will not show up in any method descriptor
(or preload attribute). There is no chance to get any heap flattening
here, since the concrete class name will not show up in any field
descriptor or `new
worst case, that's `public null-marked
class...`; in the best case it's just `language-level 22;` or what
have you.) But I still think it's the right thing to do anyway.
On Thu, May 12, 2022 at 10:18 AM Brian Goetz
wrote:
>> * Exclamation f
* Exclamation fatigue would be very real, so assume there is some way to make
`!` the default for some scope
+1
Yes, I think it's a dead end to expect users to sprinkle '!' everywhere they
don't want nulls—this is usually the informal default in common programming
practice, so we need som
On Thu, May 12, 2022 at 5:22 AM Brian Goetz
wrote:
- there is a nullability-injecting conversion from T! to T? (this
is a widening conversion)
I think we'd expect full subtyping here, right? It needs to work for
covariant arrays, covariant returns, type argument bounds
Here is my current concept of this beast:
The next installment of this is: how does assignment and conversion
work? Presumably, it starts with:
- there is a null-discarding conversion from T? to T! (this is a
narrowing conversion)
- there is a nullability-injecting conversion from T! t
a distraction at this point, as much as to
gauge sentiment on whether this is worth exploring further, and gather
considerations I may have missed in this brief summary.
On 5/8/2022 12:32 PM, Brian Goetz wrote:
To track the progress of the spiral:
- We originally came up with the B2/B3 d
Yes, Doug posted some data a while back about sorting, where the
breakeven between sorting references and taking the indirection hit and
sorting values and taking the "more memory movement" hit was not
obvious. Flattening means ... flattening. Sometimes it means faster,
but sometimes not. Thi
- (the controversial one) Atomicity is simply too confusing and
potentially astonishing to piggyback on "primitive-ness" or
"reference-ness" in a codes-like-a-class world.
(Controversial with me at least; I keep thinking who are these people
who can understand the rest of how to
So where this brings us is back to something that might feel like
the four-bucket approach in the third bullet above, but with two
big differences: atomicity is an explicit property of a class,
rather than a property of reference-ness, and a B3.ref is not
necessarily the sam
relative to B2, yielding two
types, one of which sheds some footprint
- non-atomic B3 gives up atomicity relative to B3, gaining more
flatness, for both type projections
On 5/6/2022 10:04 AM, Brian Goetz wrote:
Thinking more about Dan's concerns here ...
On 5/5/2022 6:00 PM, Dan Sm
Thinking more about Dan's concerns here ...
On 5/5/2022 6:00 PM, Dan Smith wrote:
This is significant because the primary reason to declare a B2 rather
than a B3 is to guarantee that the all-zeros value cannot be created.
This is a little bit of a circular argument; it takes a property that a
Maybe :) But I don't want to prune this exploration just yet.
On 5/5/2022 6:00 PM, Dan Smith wrote:
On May 5, 2022, at 1:21 PM, Brian Goetz wrote:
Let's write this out more explicitly. Suppose that T1 writes a non-null value
(d, t, true), and T2 writes null as (0, 0, false). The
Let's write this out more explicitly. Suppose that T1 writes a non-null value
(d, t, true), and T2 writes null as (0, 0, false). Then it would be possible
to observe (0, 0, true), which means that we would be conceivably exposing the
zero value to the user, even though a B2 class might wan
There are lots of other things to discuss here, including a discussion
of what does non-atomic B2 really mean, and whether there are
additional risks that come from tearing _between the null and the
fields_.
So, let's discuss non-atomic B2s. (First, note that atomicity is only
relevant in
The current stacking discussion is motivated by several factors:
- experiences prototyping both B2 and B3
- recently discovered hardware improvements in atomic operations
(e.g., Intel's recent specification strengthening around 128-bit vector
loads and stores)
- further thought on the conseq
ersion below might not be part of the final answer, but let's let
the process play out, I think we're making progress.
On 5/4/2022 3:36 PM, Brian Goetz wrote:
Pulling farther, there's a bucket-inversion we might be able to pull
here, just by moving some terminology around:
As the topic has turned to how Valhalla will extend into the language
syntax, we've had a significant uptick of postings on the
valhalla-spec-comments list.
As a public service announcement, let me remind people of the role of
the -comments list:
- Postings should be self-contained; think "
;https://urldefense.com/v3/__https://www.reddit.com/r/java/search/?q=*22data*20in*20java*20programs*22__;JSUlJSU!!ACWV5N9M2RV99hQ!NPBDak8nHT2gphJA0fD58S9nj9V1-O5xUyBd2nxtpk2hxoVd-9j08O_pZ8jje-dwBjEwf_GjQo7MMfgr$>
twice (if reddit can find something to complain about, they usually do!).
On Wed, May 4,
What *is* identity? I'll claim it's exactly like an ordinary immutable
field-based property, with one special provision: it is *always*
auto-assigned to be unique, and thus can never be copied. That feels
to me like it tells the whole story. So the difference between these
kinds of objects
- A term for those non-identity classes which do not _require_ a
reference. These must have a valid zero, and give rise to two
types, what we've been calling the "ref" and "val" projections.
I like "zero-default" (as opposite of null-default) but mostly because
it's a valid hyph
Let's talk about terminology. (This is getting dangerously close to a
call-for-bikeshed, so let's exercise restraint.)
Currently, we have primitives and classes/references, where primitives
have box/wrapper reference companions. The original goal of Bucket 3
was to model primitive/box pairs.
Just to record a constraint: there's somewhat of a conflict between the
idea of "make ref the default", as Kevin advocated, and universal
generics, which we need to keep in mind as we stack the whole tower.
If a B3 class gives us Foo and Foo.val, then Map::get (currently) has no
way to declare
Just so we don't lose this history, a reminder that back when we settled on the 3
buckets, we viewed it as a useful simplification from a more general approach with lots
of "knobs". Instead of asking developers to think about 3-4 mostly-orthogonal
properties and set them all appropriately,
About six months ago we started working on flattening references in
calling conventions in the Valhalla repos. We use the Preload attribute
to force preloading of classes that are known to be (or expected to be)
value classes, but which are referenced only via L descriptors, so that
at the (ea
I threw a lot of ideas out there, and people have reacted to various corners of
them. That’s fair; it’s a lot to take in at once. Let me focus on what I
think the most important bit of what I wrote is, which is, where we get
permission for relaxation of atomicity.
Until now, we’ve been trea
On Apr 28, 2022, at 9:09 AM, Remi Forax
mailto:fo...@univ-mlv.fr>> wrote:
1/ There is a difference between Foo and Foo.ref for generics, Foo is a class
while Foo.ref is a type.
The idea of using Complex.val means that the relationship is reversed,
Complex is the type and Complex.val is
(somehow two versions of this got sent, along with some cut and paste from
another thread; please disregard whatever looks weird.)
> On Apr 27, 2022, at 5:50 PM, Brian Goetz wrote:
>
> Let me try and put some more color on the bike shed (but, again, let’s focus
> on model, not
around:
null-default value class LocalDate { }
which says that LocalDate must use the nullable (LocalDate) form, not the
non-nullable (LocalDate.val/zero/bang) form.
On 4/22/2022 2:24 PM, Brian Goetz wrote:
I think I have a restack of Dan's idea that feels like fewer buckets.
We have t
are decoupled, I'm unclear on what the
VM would offer in that case. Thoughts?
How does "__non-atomic __non-id class B2a { }" fit with the "no new
nulls" requirements?
--Dan
On Wed, Apr 27, 2022 at 12:45 PM Brian Goetz
mailto:brian.go...@oracle.com>> wrote:
Here’
Let me try and put some more color on the bike shed (but, again, let’s focus on
model, not syntax, for now.)
We have two axes of variation we want to express with non-identity classes:
atomicity constraints, and whether there is an additional zero-default
companion type. These can be mostly or
Writing immutable objects in Java is hard, there is already a check list:
- be sure that your class in not only unmodifiable but really immutable,
storing a mutable class in a field is an issue
- do you have declared all fields final, otherwise you have a publication
issue
- your construct
Here’s some considerations for stacking the user model. (Again, please let’s
resist the temptation to jump to the answer and then defend it.)
We have a stacking today which says:
- B1 is ordinary identity classes, giving rise to a single reference type
- B2 are identity-free classes, giving
Several people have asked why I am so paranoid about tearing. This mail is
about tearing; there’ll be another about user model stacking and performance
models. (Please, let’s try to resist the temptation to jump to “the answer”.)
Many people are tempted to say “let it tear.” The argument for
I think this analysis is largely right. On the stack (parameters, returns,
locals), the difference between B2/B3.ref and B3.val will be minimal; some
extra register allocation pressure for the null channel, and that’s it. So I
think its reasonable to say “doesn’t matter” for these.
Where B3
> It's how I interpret our requirements, I guess?
>
> The vision of B3 is "user-defined primitives": that someone can define in a
> library a type that can be used interchangeably with the existing built-in
> primitive types. (We can debate whether "primitive" is the right word here,
> but the
> so if we have
>
> primitive class Prim {
> long value;
> }
>
> class Container {
> LPrim; prim;
> }
>
> and Prim has been loaded before Container is seen by the VM, the VM can not
> decide to flatten LPrim; to a long + a bit for nullability because the VM has
> to ensure atomicity even if
How much of this is already covered by https://openjdk.java.net/jeps/390 ?
On Apr 25, 2022, at 11:12 PM, Kevin Bourrillion
mailto:kev...@google.com>> wrote:
So I want to make my class identityless. But -- whoops! -- I released it years
ago and it has lots of usages. And though I've labeled it a
I think this is getting out of hand.
Kevin presented a carefully thought out argument — which I am sure he spent
many hours on before sending — about why we might have (yet again) gotten the
defaults wrong. I think we owe it to Kevin (and all the Java developers) to
think as carefully about hi
I think this is one of the areas where opinions are going to differ, because
there is not necessarily a unitary notion of “the user”. In a small program
were one person wrote all the code, I agree that minimizing intrusion will make
that person happy. But Java’s strength is that it makes good
This seems very specific to Optional, for Optional storing null is always a
mistake, but that's not true for other VBC, by example a deadline can be typed
as an Instant with null meaning no deadline.
No, it is not specific to Optional at all. Many domains exclude null on an
ad-hoc basis.
It i
What I’m thinking here about migration is that existing APIs can say “Optional”
but field declarations can say Optional.val, getting additional footprint /
flattening benefits, without perturbing the APIs (and with cheap conversions.)
Aren't most of the migration cases (at least for existing VBC
My understanding was we were going to guide most users towards B2
values and would treat B3 as the rare, "expert" mode, for when density
really matters. Does that decrease the education problem?
I am not convinced it does, but am open minded to see if there are other things
we can do at the decl
The fact that these are "small" (at most 64 bits) is incidental, not essential;
introducing a new quadruple type would not destabilize our concept of a
primitive value.
If we can tip the user's mental model so that they believe "small is
good" for B3 values, then we aid them in hitting the swe
Let me give a brief overview of where things are with respect to flattening,
since some of this influences the user-model discussion Kevin has initiated.)
This is a very rough sketch, and not written for a general audience, so if
you’re tempted to post this to Twitter because it seems cool and
tl:dr; I find pretty much everything about this compelling. And it comes at a
good time, too, because now that we’ve figured out what we can deliver, we can
figure out the sensible stacking of the object model.
As a refresher, recall that we’ve been loosely organizing classes into buckets:
B
I think what is missing from our presentation — and likely key to succeeding —
is how to describe “compound value” in a way that feels like a thing.
Well, a `double` is already a compound value that feels like a thing. Java just
hides the internal structure instead of having us access d.exponen
I agree totally, the former are semantic properties and the latter is a side
effect of representation. But that doesn’t help us much, because if people
assume that these have the same finial field safety / integrity properties as
reference objects, they will be in for a painful surprise. So th
Overall I find a lot to like about this presentation. I’m still a little iffy
about whether we can redefine the letters o-b-j-e-c-t in this way, but that is
largely a “syntax” reaction to your statements; the substance of the statements
sounds about right.
I especially like this bit:
The way
The careful API design will be key as I can see a lot of corner cases
related to `obj.getClass().isIdentityClass() != obj.hasIdentity()`.
Do we have a sketch of what the apis for this would look like? I'm
assuming these are just for expository purposes as isIdentityClass()
really needs to retu
assert new Object().hasIdentity();
assert !new Point().hasIdentity();
But the 'hasIdentity' method can contain arbitrary logic, and doesn't
necessarily need to correlate with 'getClass().isIdentityClass()'.
More precisely, we were being held hostage to the nature of interfaces;
by using `i
On 3/23/2022 10:51 PM, Dan Smith wrote:
On Mar 22, 2022, at 5:56 PM, Dan Smith wrote:
- Variable types: I don't see a good way to get the equivalent of an
'IdentityObject' type. It would involve tracking the 'identity'
property through the whole type system, which seems like a huge
burden
My thinking on this topic has evolved a bit. At first, we thought about
conditional methods as being completely ad-hoc, such as:
interface List {
long sum();
}
Here, the sum() method exists as an island in various specializations.
This was practical in the first iteration of the te
Thanks Dan for putting the work in to provide a credible alternative.
Let me add some background for how we came up with these things. At
some point we asked ourselves, what if we had identity and value classes
from day 1? How would that affect the object model? And we concluded
at the time
I find DanH's way of presenting it more natural (and makes perfect sense
now that its been said that way): it *is* allocating something, just not
in the heap. It is requesting new storage for a new object, which might
be in the heap, or the stack, or registers. And we might find that new
objec
And how does that differ from Point.class / Point.ref.class /
Point.class.noNotThatClassTheOtherClass() ?
I realize you're not necessarily asking that question in this thread,
but I want to walk through how I would respond to it anyway.
First here is what I already take to be tr
* Could the doc make a clearer distinction (throughout) between which
facts about int/Integer are happening because we expect *all* bucket-3
classes to work that way, vs. which are special one-off tweaks for the
8 predefined types?
A "how are int/Integer special" section would indeed be use
On 2/9/2022 1:23 PM, Kevin Bourrillion wrote:
This is not based on a very deep understanding, sorry:
* WeakReference, 1-arg constructor: When given a bucket 2-or-3
instance, it seems maybe fine to just treat as strong reference? User
is saying "just hold this loosely, don't keep it alive on
I have come around to a similar conclusion. None of the models for
WR(value) are really all that justifiable, other than "throws". But we
dislike that because so much code uses WHM that we are worried about
this code all of a sudden failing. But we are trying to fix that by
distorting WR, ra
I think we're kind of stuck with a model like this, whether we admit it
or not, because we have to allow for pervasive erasure and be able to
fall back to looser linkage conventions. SO the type restriction was
always optimistic; we might say "Object restricted to QPoint", but
someone could sh
The motivation for this comes from erasure. Even if we specialize, we need to
be able to use specialized generics in an erased context, because there will be
erased clients. If we have
class Foo {
T m();
T[] arr();
}
we can use also sorts of bridging/casting tricks to ma
It certainly seems that all the choices are bad.
The "obvious" choice is to simply say that WeakReference makes no
sense, in that it sidesteps the hard semantics questions. My fear is
that this will cause new failures, where existing libraries that toss
objects into WHMs to cache derived resu
The operand of C_Class is a weird beast. It can be an internal name
(com/foo/Bar), but it can also be a *descriptor* for an array type.
Valhalla extends it to allow Q descriptors as well (but not L
descriptors -- there should be one way to say C_Class[String].)
On 1/12/2022 8:14 AM, fo...@un
Both value and primitive classes use the aconst_init / withfield
initialization protocol. The former is an L-type (QOptional is
illegal); the latter uses Q types for initialization.
Value classes
-> are L types
-> which are references
-> references can be null
-> VM manages where the nulli
Let's take a detour, and try to answer to the question, how do we do reflection
on method with Q-types ?
Given that reflection is using the class java.lang.Class, it means that we need
a class that represents a L-type and a class that represent a Q-type.
Correct. In addition to all sorts
yping relationship but a
boxing relationship so it may not work when well we will have fully
reified generics.
Rémi
*From: *"Brian Goetz"
*To: *"Remi Forax" , "valhalla-spec-experts"
Because the Q is what permits the tearing.
On 1/6/2022 1:50 PM, Remi Forax wrote:
It just occurs to me that while ACC_VALUE is a bit that change the runtime
semantics,
something the VM should take care of, ACC_PRIMITIVE is not a bit that change the
runtime semantics, only the javac translation
Just in time for Christmas, the latest State of Valhalla is available!
https://openjdk.java.net/projects/valhalla/design-notes/state-of-valhalla/01-background
https://openjdk.java.net/projects/valhalla/design-notes/state-of-valhalla/02-object-model
https://openjdk.java.net/projects/valhalla/design
Introducing new interfaces that have no methods is clearly source-
and binary compatible, so I am not particularly compelled by "some
very brittle and badly written code might break." So far, no one
has proposed any examples that would make us reconsider that.
??;
you are
to be seen in the type system but not by
example the set containing only B3 and B4 ?
Rémi
--------
*From: *"Brian Goetz"
*To: *"daniel smith" , "Dan Heidinga"
*Cc: *"John Ro
I was working on some docs and am not sure if we came to a conclusion on
the rules about who may, may not, or must declare ValueObject or
IdentityObject.
Let me see if I can chart the boundaries of the design space. I'll start
with IdentityObject since it is more constrained.
- Clearly for
Let's do an ASM thought experiment.
The descriptors live in (a) {method,field}_info metadata, and (b)
C_{Field,Method}Ref constants referred to by invoke/field access
instructions.
The stars, though, live somewhere completely different: the Preload
attribute, which is not on the instruction,
If the preload() bit is tied to the ClassDesc, do we need to worry
about a bit mask in MethodTypeDesc? Isn't the MethodTypeDesc composed
of ClassDesc returnType and ClassDesc[] of parameters? I feel like
I'm missing some complexity here...
That's how the implementation happens to work, but
This reminds me of an earlier version of the jl.constant API, where we
tried to track the varargs bit. In the end, we dropped this, because it
washed off too easily in the API. We could have a preload() bit that
travels with the ClassDesc, which would then have to be propagated into
a bit mas
It took us a while to unravel this one, but I think we did.
The JMM says that loads and stores of references, and of
32-bit-and-smaller primitive values, are atomic with respect to other
loads and stores of the same variable. This means that you'll see a
valid value, though it could be a stal
Background: the textbook definition of "primitive" is centered on
their nature of being elements-not-molecules, and I see no dispute
about it. Also, there's no disputing the fact that we're allowed to
adopt a different meaning if we so choose. So that's not even the
fatal flaw.
Yes, that's
The jl.constant API will have to be updated somewhat for Valhalla.
Since it was already on the drawing board when we designed jl.constant,
shouldn't be too bad, but there are a few subtleties. Now that the
descriptors are largely settling down, we can take a stab at this.
ClassDesc (the base
The following was received on valhalla-spec-comments.
Summary: Various syntax options for no-arg constructors of "bucket 3"
primitives, to enable users to pick a default value other than zero.
Analysis: The suggestion is well-intentioned, but it is built on some
significant misunderstandings
Or, to put it another way: success looks like yet another "got the
defaults wrong", where people should default to B2 unless they need B1,
and "pure" joins the ranks of "final" and "private" of "I shoulda been
the default."
Right, that's what you're saying?
On 11/22/2021 4:07 PM, Kevin Bourri
I wouldn't say we flipped anything. But we have made a lot of progress
on the model; at first we thought abstract supers at all were a bridge
too far, but we found the right set of constraints and it seems to fit
naturally now. So it makes sense to ask the question whether we're at
the edge,
estions about a random Java type, and guides
you towards classifying it. That helped me crystallize
the diagram, and may be useful in its own right,
or perhaps distilled into a flowchart. Stay tuned.
— John
On Nov 18, 2021, at 2:34 PM, Brian Goetz wrote:
I think it is reasonable to consider
aries.
--Dan
On Nov 18, 2021, at 5:58 PM, Remi Forax
mailto:fo...@univ-mlv.fr>> wrote:
From: "Brian Goetz" mailto:brian.go...@oracle.com>>
To: "Kevin Bourrillion" mailto:kev...@google.com>>
Cc: "Dan Hei
.
There’d be details to work out, but this is not an impossible lift. The
question is whether the return on complexity is there or not.
On Nov 18, 2021, at 5:58 PM, Remi Forax
mailto:fo...@univ-mlv.fr>> wrote:
From: "Brian Goetz"
I think it is reasonable to consider allowing bucket two classes to be
abstract. They could be extended by other classes which would either be
abstract or final. The intermediate types are polymorphic but the terminal type
is monomorphic.
A similar argument works for records.
Sent from my iPa
An implication of universal generics is that there needs to be
some common protocol that works on both vals and refs. In the
val/ref model, that protocol is objects: both vals and refs are
objects with members that can be accessed via '.'. In the
value/object model, I'm not
pec currently
calls object" and "what users understand objects to be", at least for
sake of discussion?
On 11/4/2021 12:08 PM, Kevin Bourrillion wrote:
On Thu, Nov 4, 2021 at 7:56 AM Brian Goetz wrote:
On 11/4/2021 2:54 AM, Kevin Bourrillion wrote:
Point.ref pr
To close the loop, in the initial "Eclair" discussion (which grew out of
a conversation at the last JVMLS), a primitive was a pair of classes,
where the companion class was actually an interface. We haven't
revisited "what is Point.ref" since then, but one possible way to do
this is to say exa
On 11/4/2021 2:54 AM, Kevin Bourrillion wrote:
Point.ref pr = pv; // same object… now it’s on the heap, though,
with a real live heap header
assert pr.getClass() == Point.class; // same class, but...
Why would we even want this? It would be very surprising/puzzling to me.
It
On 11/3/2021 3:00 PM, Kevin Bourrillion wrote:
Okay, let's stick a pin in proper-value-types (i.e. try to leave them
out of this discussion) for a moment...
One question is whether the existing design for the bifurcated type
hierarchy will carry right over to this split instead. (My
underst
There's lots of great stuff on subtyping in chapters 15 and 16 of TAPL
(esp 15.6, "Coercion semantics"), which might be helpful. But as a
tl;dr, I would suggest treating subtyping strictly as an is-a relation
within our nominal type system. By this interpretation, int and int
Subtyping is a
But it would lead to more
correct code. Maybe you have other ideas.
On Wed, Nov 3, 2021 at 7:05 AM Brian Goetz wrote:
Extrapolating, ACMP is a _substitutability test_; it says that
substituting one for the other would have no detectable differences.
Because all objects have a un
I really like this, it's far better than how i was seeing Valhalla,
pushing .ref into a corner is a good move.
Yes, we always disliked how prevalent .ref was; it took several rounds
of "shaking the box" to get it to stay in the corner.
I still hope that moving from B1 to B2 can be almost ba
1 - 100 of 437 matches
Mail list logo