[v8-users] Re: PSA: Removing deprecated v8::EmbedderHeapTracer

2022-12-19 Thread Michael Lippautz
+v8-users 

On Mon, Dec 19, 2022 at 3:12 PM Michael Lippautz 
wrote:

> Hi all,
>
> v8::EmbedderHeapTracer
> <https://source.chromium.org/chromium/chromium/src/+/main:v8/include/v8-embedder-heap.h;l=77?q=EmbedderHeapTracer&ss=chromium>
> has been deprecated on V8's API for some time now. All our investment in
> managed C++ at this point is in Oilpan
> <https://v8.dev/blog/oilpan-library> and future integrations with new V8
> features. EmbedderHeapTracer already requires special handling for most
> parts in the GC and our test coverage is limited to our unit tests.
>
> Going forward we will only support v8::TracedReference
> <https://source.chromium.org/chromium/chromium/src/+/main:v8/include/v8-traced-handle.h;l=193?q=v8::TracedReference&ss=chromium>
>  in
> combination with v8::CppHeap
> <https://source.chromium.org/chromium/chromium/src/+/main:v8/include/v8-cppgc.h;l=103?q=v8::CppHeap&ss=chromium>.
> We plan to remove EmbedderHeapTracer in V8 11.1 (Chromium M111) which you
> can follow on the tracking bug
> <https://bugs.chromium.org/p/v8/issues/detail?id=13207>.
>
> This does not change any of the existing APIs around Local, Global,
> Persistent and alike.
>
> Cheers, Michael
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/v8-users/CAH%2BmL5A6wKN%3DGj3LoMJ5Dj%3Da8zcfHtq49byr3kiJUH-h-AeKAQ%40mail.gmail.com.


Re: [v8-users] Re: Failed to cross compile v8 for iOS: error: unknown directive .type PushAllRegistersAndIterateStack

2020-05-11 Thread Michael Lippautz
Thank you for reporting! The issue will be tracked in
https://bugs.chromium.org/p/v8/issues/detail?id=10517.

On Mon, May 11, 2020 at 6:49 AM Jakob Gruber  wrote:

> +Michael Lippautz 
>
> On Fri, May 8, 2020 at 3:25 PM 许超前  wrote:
>
>> I compiled latest v8 on macOS catalina(10.15.4), with the following gn
>> args:
>>
>> enable_ios_bitcode = true
>>
>> ios_deployment_target = 10
>>
>> is_component_build = false
>>
>> is_debug = false
>>
>> target_cpu = "arm64"  # "x64" for a simulator build.
>>
>> target_os = "ios"
>>
>> use_custom_libcxx = false # Use Xcode's libcxx.
>>
>> use_xcode_clang = true
>>
>> v8_enable_i18n_support = false# Produces a smaller binary.
>>
>> v8_monolithic = true  # Enable the v8_monolith target.
>>
>> v8_use_external_startup_data = false  # The snaphot is included in the
>> binary.
>>
>> --
>> --
>> v8-users mailing list
>> v8-users@googlegroups.com
>> http://groups.google.com/group/v8-users
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "v8-users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to v8-users+unsubscr...@googlegroups.com.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/v8-users/e25b0852-e834-4d39-b937-40dad8c8a713%40googlegroups.com
>> <https://groups.google.com/d/msgid/v8-users/e25b0852-e834-4d39-b937-40dad8c8a713%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/v8-users/CAH%2BmL5B25iwNrfLCbML_ZL0xL-t5phEVcZwZ3AbeKjk%3DBnrTZg%40mail.gmail.com.


Re: [v8-users] GC tracing changes in V8 7.2?

2019-01-30 Thread Michael Lippautz
On Wed, Jan 30, 2019 at 9:15 PM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> One more low-level question (where it seems like implementation details
> matter to embedders):
>
> Based on what you've said, an object may or may not be "black" on
> allocation. It seems, though, that I need to do different things depending
> on the color. If it is allocated black, then I need to arrange to trace the
> object myself to register all its outgoing references. If it is white, then
> I need to call RegisterExternalReference(), and V8 will trace it later. If
> it's gray, I don't need to do anything.
>
> But if I don't know the color, it seems I need to *both* call
> RegisterExternalReference() and initiate my own trace to cover all bases.
> But in the case that it's not already-black, this will result in a
> redundant trace later on.
>
>
The redundant trace can be avoided by having a color marker on the C++
object itself so that it only traces through it once.

Ultimately, solving all those issues leads to having a fully trace-based
system with marking colors on the C++ side too. We went that way because we
need a system to collect reference cycles and the easiest way to do so is
by basing the whole system on tracing.


> Is it best to live with this potential redundant trace, or is there some
> way I can detect the color after allocation?
>

There's no way to detect the color as we have changed the internal
implementation in the past and may do so in future.

-Michael

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] GC tracing changes in V8 7.2?

2019-01-30 Thread Michael Lippautz
On Wed, Jan 30, 2019 at 8:35 PM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> Hi Michael,
>
> Thanks, I think I now see the problem: I had assumed that newly-allocated
> objects were always marked immediately on allocation, since they are
> clearly reachable at that time. But, now that I think about it, I suppose
> that would make it hard to quickly collect short-lived objects.
>

That's the reason why we allocate white in the young generation, yes.


>
> I think realistically the current embedding API requires an understanding
> of implementation details to use correctly. Since there is no written
> guide, the only way I've been able to understand how the pieces fit
> together is by understanding implementation details. In particular I think
> the concept of write barriers and when to use them is not very intuitive to
> those who haven't studied garbage collection. Once I get this sorted out I
> may try to write a beginner's guide from that perspective.
>

Well, barriers are only needed for incremental (and concurrent) collection.
>From an embedder perspective all references reported by V8 can be traced
after EmbedderHeapTracer::EnterFinalPause() is called which would mean that
there's no incremental collection and barriers are unnecessary.


>
> --
>
> The TracedGlobal API looks like a good addition to make embedders' lives
> easier, but it might turn out it doesn't quite fit with the model we've
> settled on in our code. Specifically, we want to allocate JS wrapper
> objects for a C++ object lazily, on the first time the object is directly
> referenced from JS. This makes it tricky to use V8 handles to link C++
> objects together, because there may not be a JS object yet for the handle
> to point to. Instead, we reference the C++ object directly, and the C++
> object holds a handle to its own JS wrapper which is allocated lazily. If
> each reference from another C++ object required its own TracedHandle, then
> we'd have to keep a reverse mapping of all the references pointing to an
> object so that we could initialize all of the TracedHandles when the
> wrapper is lazily allocated.
>

I don't think I can follow :)

It looks like you may be doing something similar as Blink where the JS
object is lazily created. Once the JS object is there we have edges in both
directions. See ScriptWrappable
.
At the point where we create the JS wrapper we know the C++ object and can
create the links in both directions.


>
> A further problem is that the parent object may itself not have any
> wrapper allocated, but may have references from C++ which we considered to
> be strong references. Consider e.g. the case of a Request object containing
> a Headers object. Imagine the Headers object has a JS wrapper but the
> Request object does not, and is only referenced from C++. In this case, the
> reference from Request -> Headers will never be traced, and so we need to
> treat the Headers wrapper as having a strong reference. Later on, a wrapper
> may be allocated for the Request. Once that happens, then we only need a
> strong reference on the Request wrapper itself, and we can rely on tracing
> to find the Headers wrapper.
>

We suggest using actually tracing for C++ to solve this problem. This way
objects are traced through until they reach entry points into V8.

It's more engineering effort but simple to reason about.


>
> So, the problem here is that over the lifetime of a reference between two
> C++ objects, the reference's nature can change between being C++-only (no
> V8 handle), being a strong V8 handle, and being a traced V8 handle. So it
> doesn't seem like we can simply drop in a TracedGlobal here, unfortunately.
>
> That said, if you would prefer that we move towards using weak handles
> strictly for registering the destructor callback, and strictly use
> TracedGlobal for traced handles, then I think we can work with that by
> having a scheme where each object potentially holds three different handles
> to its own wrapper:
> - A weak independent handle, to get the weak callback.
>

The weak callback is only for the destructor, right? How do you
differentiate between a C++ object without JS wrapper (lazy creation) and a
C++ object that should be destructed?


> - A strong handle, when any non-traced references exist from C++, to keep
> the wrapper alive.
>

These should usually be temporary (ideally Local) and looks fine to me.


> - A TracedGlobal, when any traced references exist from C++, used to
> implement tracing.
>
> Let me know if you think it would be a good idea for me to implement that
> instead of relying on one handle and doing SetWeak()/ClearWeak().
>
--
>
> Also, another technical question clarifying something you said: If an
> object is first discovered and marked during "final pause" (e.g. because it
> has a strong pers

Re: [v8-users] GC tracing changes in V8 7.2?

2019-01-30 Thread Michael Lippautz
On Mon, Jan 28, 2019 at 11:12 PM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> I'm still working on this off-and-on. The issue is not as urgent as it
> sounds because in the case that a wrapper object is collected prematurely,
> we simply remake it as needed. Still, this could cause issues if scripts
> add JS properties on native objects and expect them to stay there, but the
> issues seems to be affecting only a handful of specific scripts on our
> platform and none of them happen to do that... Still, we do need to fix the
> issue for future scripts.
>
>
We are currently reworking APIs around the use of EmbedderHeapTracer and
how it is used with V8 handles. In 7.4 we introduced a new type
(TracedGlobal) that is tied to the use case of tracing through the embedder
heap. This type is treated as root for scavenges unless explicitly opted in
into treating it as non-root.

We advise against switching handles from strong to weak and vice versa as
it is hard to follow what's going on exactly.


> On Wed, Jan 16, 2019 at 2:23 AM Michael Lippautz 
> wrote:
>
>> - The ClearWeak part should work if there's a final GC pause interrupting
>> whatever is done with C++ stack.
>>
>
> Sorry, I'm a GC noob. What happens in the "final GC pause", exactly? What
> does it mean for it to "interrupt whatever is done with the C++ stack"?
>

Final pause is when the garbage collector finalizes the current cycle. The
stack is re-scanned if needed. Handles are also re-scanned. So, if some
handles is made strong by called ClearWeak() it will be considered as
strong root during this phase.

"interrupt whatever is done in C++" was referring to the embedder situation
where there's the V8 garbage collection is usually triggered when there's a
native C++ stack. All of V8's objects are held through Local or some sort
of Persistent handle when this happens.


>
> Does ClearWeak() implicitly mark the object, if tracing is already
> in-progress? Or is that what happens in the final GC pause? Does that
> object get traced?
>

No to all of it. As mentioned above, it will be discovered as strong root
during root scanning.


>
> Looking at the code, it seems like ClearWeak() does not mark the object.
> So I guess I should probably RegisterExternalReference() after ClearWeak()?
> Normally a strong reference would be a root and so would be marked at the
> beginning of the trace cycle, but if ClearWeak() happens mid-cycle it seems
> like there's an issue.
>

ClearWeak makes the handle strong. It should be discovered during root
scanning.


>
> However, this doesn't seem to fit the pattern of the problems I'm seeing
> in production.
>
>
>> - The SetWeak after being done may or may not require a manual
>> registering call, depending on how EmbedderHeapTracer is implemented.
>>
>
>> In Blink we implemented regular traced garbage collection for the
>> EmbedderHeapTracer. This means that the object containing such an
>> interesting references may have been processed by the EmbedderHeapTracer
>> already. If the reference is then just marked as weak with SetWeak() the GC
>> misses out on it as it never sees the containing object again. Blink emits
>> a RegisterExternalReference() call for such objects. The general concept
>> for solving mutation in the graph while a garbage collector is running is
>> called (write barrier).
>>
>
> Not sure I follow. RegisterExternalReference() is only meaningful on
> objects that are currently white, right? But before SetWeak(), the handle
> was strong, making it a root. Roots should have been marked gray at the
> start of the tracer cycle?
>
>
This is an implementation detail, but yeah, V8 marks the full root set,
including the handles, at the beginning of incremental marking. If the
handle was strong at this point the object is transitioning through the
marking phase. V8 also re-scans roots before finalizing the current cycle.

The embedder should not reason about object colors as they are an
implementation detail.


> In my case, I think the objects are frequently newly-allocated at the time
> SetWeak() is called. But a newly-allocated object should be marked black at
> allocation, right?
>
>
Depends and is an implementation detail. It is not safe to assume that new
objects are allocated black during GC. (It does not hold for new space for
various optimization reasons.)

So, if you want to use tracing and create a new reference of that sort
using SetWeak() you also need to register the object using
RegisterExternalReference. (In future, just use TracedGlobal and pass it to
EmbedderHeapTracer::RegisterEmbedderReference.)


> Thanks again for the help! Hopefully we'll be able

Re: [v8-users] GC tracing changes in V8 7.2?

2019-01-16 Thread Michael Lippautz
On Tue, Jan 15, 2019 at 7:12 PM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> Thanks, Michael, this gives me a better idea of what to look for.
>
> I'm a little surprised because I had always assumed that tracing was
> triggered during allocation. When else does it run?
>

We used to run the embedder tracing only as part of incremental tasks. For
Blink this guarantees V8 that there's no relevant C++ stack when invoking
the EmbedderHeapTracer.

Since 7.2 we are also able to run it as part of allocations.


>
> Also, what counts as allocation? Does allocating a new persistent handle
> in itself count, or is it strictly allocating objects?
>

Allocating JS objects on the managed heap. This does not include persistent
handles themselves


>
> I've designed my code such that when a reference to an object exists on
> the C++ stack, I call ClearWeak() on the persistent handle. Once all C++
> stack references go away, I call SetWeak() again. Could this possibly
> confuse the tracer if a trace is in-progress? Should I, for example, be
> calling RegisterExternalReference() after SetWeak()?
>

- The ClearWeak part should work if there's a final GC pause interrupting
whatever is done with C++ stack.
- The SetWeak after being done may or may not require a manual registering
call, depending on how EmbedderHeapTracer is implemented.

In Blink we implemented regular traced garbage collection for the
EmbedderHeapTracer. This means that the object containing such an
interesting references may have been processed by the EmbedderHeapTracer
already. If the reference is then just marked as weak with SetWeak() the GC
misses out on it as it never sees the containing object again. Blink emits
a RegisterExternalReference() call for such objects. The general concept
for solving mutation in the graph while a garbage collector is running is
called (write barrier).

You can check whether this is the problem by disabling incremental marking
for wrappers (--no_incremental_marking_wrappers).

-Michael

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] GC tracing changes in V8 7.2?

2019-01-15 Thread Michael Lippautz
V8 started to call to EmbedderHeapTracer during incremental marking steps
that happen on allocation.

This could mean that there is C++ stack sitting on top of entering V8. Any
chance that there are C++ objects holding traced V8 references that cannot
be found by the EmbedderHeapTracer? E.g., this could happen when a C++
object is only reachable from stack without a proper stack scanning
mechanism.

The CL landed 
here.

-Michael

On Tue, Jan 15, 2019 at 3:01 AM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> Hi v8-users,
>
> Upon upgrading to V8 7.2, we're seeing GC collecting objects more
> aggressively than before. It looks like we have another bug with our GC
> integration, as we're occasionally seeing objects collected that should be
> reachable using EmbedderHeapTracer.
>
> I'm trying to isolate the issue (so far I haven't been able to reproduce
> outside of prod). But, meanwhile, are there any big changes to GC tracing
> in 7.2 that might hint at what I'm getting wrong? The release blog post
> didn't seem to mention anything: https://v8.dev/blog/v8-release-72
>
> -Kenton
>
> --
> --
> v8-users mailing list
> v8-users@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to the Google Groups
> "v8-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to v8-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] Re: Fatal error in ScavengerCollector::CollectGarbage(), what did I do wrong?

2018-12-12 Thread Michael Lippautz
No worries, running with TSAN for such repros would've immediately flushed
it out as the global handle system is designed for single-threaded
execution and intentionally avoids use of atomics.

Cheers, -Michael

On Thu, Dec 13, 2018 at 2:28 AM Kenton Varda  wrote:

> On Tue, Dec 11, 2018 at 1:02 PM Kenton Varda 
> wrote:
>
>> On Tue, Dec 11, 2018 at 11:13 AM Michael Lippautz 
>> wrote:
>>
>>> I really hope that handles are only access from the same thread the GC
>>> is running on. Otherwise, you would need a v8::Locker to synchronize that
>>> access.
>>>
>>
>> Right, the isolate mutex is locked any time we're manipulating handles.
>>
>
> ... or so I thought.
>
> It turns out in some buggy cases a destructor for a C++ object was
> executing without locking the isolate mutex. Before my refactoring, this
> resulted in the destruction of a persistent handle, which apparently didn't
> cause any visible concurrency issues. After my refactoring, this ended up
> invoking SetWeak() on a handle without destroying it. If this happened to
> occur at the wrong time during a scavenge, it could cause the object to be
> scavenged twice.
>
> In retrospect I obviously should have thought of this earlier.
>
> I've now added some asserts and template hacks to catch this class of
> error.
>
> Thanks for the hint and sorry for wasting your time!
>
> -Kenton
>
>>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] Re: Fatal error in ScavengerCollector::CollectGarbage(), what did I do wrong?

2018-12-11 Thread Michael Lippautz
On Tue, Dec 11, 2018 at 6:27 PM Kenton Varda  wrote:

> Hi Michael,
>
> Thanks for looking at this!
>
> I wish I could come up with a simple repro. Currently my only repro
> involves running load test traffic (captured from production) through a
> test instance for about a minute before the crash happens.
>
> My refactoring does a bunch of things differently from before and it's
> hard to revert them one by one. There's one big main thing that is
> different: Previously, for each wrapper, I'd create one weak persistent
> handle for the purpose of receiving a callback to delete the object, and
> then additional persistent handles for each reference held by some other
> native object (which may or may not be weak depending on whether the holder
> is itself GC traceable). In the new code, I instead keep only one
> persistent handle per wrapper, and I separately track a "strong reference
> count"; when the strong refcount becomes zero I call SetWeak(), and when it
> becomes non-zero I call ClearWeak(). So the same handle may switch between
> weak and non-weak.
>
> This transitioning between weak and non-weak seems like it could confuse
> the scavenger *if* it happened during scavenging. However, AFAICT, there's
> no way this could happen, since there are no callbacks into application
> code during scavenging except for weak callbacks... and in my case, those
> weak callbacks are actually never called during scavenging, because I have
> a scavenge prologue callback that iterates over all weak handles to wrapper
> objects and calls MarkActive() on them.
>
>
I really hope that handles are only access from the same thread the GC is
running on. Otherwise, you would need a v8::Locker to synchronize that
access.

Also, you are marking *all* handles with MarkActive()? That should
essentially make all of the handles strong for the Scavenger.

That contradicts with the crash happening
after IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles which deals with
weak handles that are not marked as active. (Assuming you did not use
MarkIndependent()).


> I don't expect you to be able to figure this out for me, but do you have
> any hints for debugging strategies I should try?
>

Essentially, it looks like you are scavenging a root node twice, which is
why you already see it in ToSpace when it's getting added through the
visitor.

The relevant functions are in src/global-handles.{h,cc} and called
throughout scavenging in this order:
1. IdentifyWeakUnmodifiedObjects
:
Makes nodes active that V8 thinks should be active in addition to those
that already had MarkActive() called on them.
2. IterateNewSpaceStrongAndDependentRoots
:
Scavenges strong handles and those that are active.
3. MarkNewSpaceWeakUnmodifiedObjectsPending
:
Identifies nodes that require finalizers.
4. IterateNewSpaceWeakUnmodifiedRootsForFinalizers
:
Scavengers nodes that require finalizers.
5. IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles
:
Resets weak handles or scavenges them.  Scavenging here just means updating
the forwarding pointer from FromSpace to ToSpace as the object itself has
already been scavenged if we don't need to reset it.

The sets of handles that are scavenged should be disjoint in 2), 4) and 5).
Whenever a node is already pointing directly to ToSpace that should be a
bug and some other method probably scavenged it in the same run before.

The interesting part is then why multiple methods match the same node for
scavenging.

Cheers, -Michael

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] Re: Fatal error in ScavengerCollector::CollectGarbage(), what did I do wrong?

2018-12-11 Thread Michael Lippautz
I think this issue is a symptom of visiting a root (global handle) twice
during a Scavenge. I've checked all paths in global handles iteration and
it looks like they are mutually exclusive, as they should be.

Is there  any chance you can provide some sort of repro?

Also, which kind of API calls are involved? E.g.: Weak callbacks,
finalizers, GC callbacks, MarkActive, MarkIndependent, etc

-Michael

On Tue, Dec 11, 2018 at 10:01 AM Michael Lippautz 
wrote:

> Thanks for the thorough description. There's indeed something off here.
>
> It could either be filtering in the roots visitor (like the patch you
> suggested) or that we need another processing phase after iterating those
> roots.
>
> I've opened https://crbug.com/v8/8571 to track this. Will investigate and
> report back there.
>
> -Michael
>
> On Thu, Dec 6, 2018 at 10:43 PM 'Kenton Varda' via v8-users <
> v8-users@googlegroups.com> wrote:
>
>> Seems to have something to do with this block in
>> ScavengerCollector::CollectGarbage():
>>
>>
>> https://cs.chromium.org/chromium/src/v8/src/heap/scavenger.cc?q=root_scavenge_visitor&sq=package:chromium&g=0&l=211-227
>>
>> {
>>   // Scavenge weak global handles.
>>   TRACE_GC(heap_->tracer(),
>>
>> GCTracer::Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_PROCESS);
>>   isolate_->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending(
>>   &IsUnscavengedHeapObject);
>>   isolate_->global_handles()
>>   ->IterateNewSpaceWeakUnmodifiedRootsForFinalizers(
>>   &root_scavenge_visitor);
>>   scavengers[kMainThreadId]->Process();
>>
>>   DCHECK(copied_list.IsEmpty());
>>   DCHECK(promotion_list.IsEmpty());
>>   isolate_->global_handles()
>>   ->IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles(
>>   &root_scavenge_visitor, &IsUnscavengedHeapObject);
>> }
>>
>>
>> The call to IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles() at the
>> end of the block appears to cause the crash by visiting a handle for an
>> object that is already in ToSpace. This triggers a DCHECK at the start of
>> ScavengeObject(), or in release builds adds the handle to copied_list which
>> triggers the aforementioned CHECK in ~Worklist().
>>
>> The following patch appears to stop the crash:
>>
>> diff --git a/src/heap/scavenger.cc b/src/heap/scavenger.cc
>> index 4c63ed099a..b2f0991350 100644
>> --- a/src/heap/scavenger.cc
>> +++ b/src/heap/scavenger.cc
>> @@ -443,6 +443,7 @@ void RootScavengeVisitor::ScavengePointer(Object** p)
>> {
>>Object* object = *p;
>>DCHECK(!HasWeakHeapObjectTag(object));
>>if (!Heap::InNewSpace(object)) return;
>> +  if (!Heap::InFromSpace(object)) return;
>>
>>scavenger_->ScavengeObject(reinterpret_cast(p),
>>   reinterpret_cast(object));
>>
>>
>> But I have no idea if this is really correct, nor do I understand how my
>> refactoring caused this problem.
>>
>> Under what situations could the last line of the block above end up
>> visiting an object in ToSpace?
>>
>> One idea I had was that maybe a handle was created (or marked weak?)
>> *during* scavenging, but I don't know how I could have done that:
>> AFAICT, the only callbacks into into my application code that happen during
>> scavenging are the weak callbacks, but I've verified they aren't doing
>> anything with handles other than resetting the handle they were called on.
>>
>> Any ideas?
>>
>> -Kenton
>>
>> On Wed, Dec 5, 2018 at 5:23 PM 'Kenton Varda' via v8-users <
>> v8-users@googlegroups.com> wrote:
>>
>>> Whoops, correction: It's actually copied_list that has work left, not
>>> promotion_list.
>>>
>>> On Wednesday, December 5, 2018 at 3:37:20 PM UTC-8, Kenton Varda wrote:
>>>>
>>>> Hi v8-users,
>>>>
>>>> I recently refactored the way that I integrate with V8's garbage
>>>> collection in my application, and after the refactor I am (very rarely)
>>>> hitting a fatal error that I don't understand:
>>>>
>>>> #
>>>> # Fatal error in , line 0
>>>> # Check failed: IsEmpty().
>>>> #
>>>>
>>>> stack:
>>>>  base/platform/platform-posix.cc:402 v8::base::OS::Abort()
>>>>  base/logging.cc:171 V8_Fatal(char const*, 

Re: [v8-users] Re: Fatal error in ScavengerCollector::CollectGarbage(), what did I do wrong?

2018-12-11 Thread Michael Lippautz
Thanks for the thorough description. There's indeed something off here.

It could either be filtering in the roots visitor (like the patch you
suggested) or that we need another processing phase after iterating those
roots.

I've opened https://crbug.com/v8/8571 to track this. Will investigate and
report back there.

-Michael

On Thu, Dec 6, 2018 at 10:43 PM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> Seems to have something to do with this block in
> ScavengerCollector::CollectGarbage():
>
>
> https://cs.chromium.org/chromium/src/v8/src/heap/scavenger.cc?q=root_scavenge_visitor&sq=package:chromium&g=0&l=211-227
>
> {
>   // Scavenge weak global handles.
>   TRACE_GC(heap_->tracer(),
>
> GCTracer::Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_PROCESS);
>   isolate_->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending(
>   &IsUnscavengedHeapObject);
>   isolate_->global_handles()
>   ->IterateNewSpaceWeakUnmodifiedRootsForFinalizers(
>   &root_scavenge_visitor);
>   scavengers[kMainThreadId]->Process();
>
>   DCHECK(copied_list.IsEmpty());
>   DCHECK(promotion_list.IsEmpty());
>   isolate_->global_handles()
>   ->IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles(
>   &root_scavenge_visitor, &IsUnscavengedHeapObject);
> }
>
>
> The call to IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles() at the
> end of the block appears to cause the crash by visiting a handle for an
> object that is already in ToSpace. This triggers a DCHECK at the start of
> ScavengeObject(), or in release builds adds the handle to copied_list which
> triggers the aforementioned CHECK in ~Worklist().
>
> The following patch appears to stop the crash:
>
> diff --git a/src/heap/scavenger.cc b/src/heap/scavenger.cc
> index 4c63ed099a..b2f0991350 100644
> --- a/src/heap/scavenger.cc
> +++ b/src/heap/scavenger.cc
> @@ -443,6 +443,7 @@ void RootScavengeVisitor::ScavengePointer(Object** p) {
>Object* object = *p;
>DCHECK(!HasWeakHeapObjectTag(object));
>if (!Heap::InNewSpace(object)) return;
> +  if (!Heap::InFromSpace(object)) return;
>
>scavenger_->ScavengeObject(reinterpret_cast(p),
>   reinterpret_cast(object));
>
>
> But I have no idea if this is really correct, nor do I understand how my
> refactoring caused this problem.
>
> Under what situations could the last line of the block above end up
> visiting an object in ToSpace?
>
> One idea I had was that maybe a handle was created (or marked weak?)
> *during* scavenging, but I don't know how I could have done that: AFAICT,
> the only callbacks into into my application code that happen during
> scavenging are the weak callbacks, but I've verified they aren't doing
> anything with handles other than resetting the handle they were called on.
>
> Any ideas?
>
> -Kenton
>
> On Wed, Dec 5, 2018 at 5:23 PM 'Kenton Varda' via v8-users <
> v8-users@googlegroups.com> wrote:
>
>> Whoops, correction: It's actually copied_list that has work left, not
>> promotion_list.
>>
>> On Wednesday, December 5, 2018 at 3:37:20 PM UTC-8, Kenton Varda wrote:
>>>
>>> Hi v8-users,
>>>
>>> I recently refactored the way that I integrate with V8's garbage
>>> collection in my application, and after the refactor I am (very rarely)
>>> hitting a fatal error that I don't understand:
>>>
>>> #
>>> # Fatal error in , line 0
>>> # Check failed: IsEmpty().
>>> #
>>>
>>> stack:
>>>  base/platform/platform-posix.cc:402 v8::base::OS::Abort()
>>>  base/logging.cc:171 V8_Fatal(char const*, int, char const*, ...)
>>>  heap/worklist.h:72
>>> v8::internal::Worklist,
>>> 256>::~Worklist()
>>>  heap/scavenger.cc:288
>>> v8::internal::ScavengerCollector::CollectGarbage()
>>>  heap/heap.cc:1931 v8::internal::Heap::Scavenge()
>>>  heap/heap.cc:1649
>>> v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector,
>>> v8::GCCallbackFlags)
>>>  heap/heap.cc:1292
>>> v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace,
>>> v8::internal::GarbageCollectionReason, v8::GCCallbackFlags)
>>>  heap/heap.cc:4264
>>> v8::internal::Heap::AllocateRawWithLightRetry(int,
>>> v8::internal::AllocationSpace, v8::internal::AllocationAlignment)
>>>  heap/heap.cc:4278
>>> v8::internal::Heap::AllocateRawWithRetryOrFail(int,
>>> v8::internal::AllocationSpace, v8::internal::AllocationAlignment)
>>>  heap/factory.cc:120 AllocateRawWithImmortalMap
>>>  heap/factory.cc:972  (inlined by) NewRawTwoByteString
>>>  heap/factory.cc:636
>>> v8::internal::Factory::NewStringFromUtf8(v8::internal::Vector,
>>> v8::internal::PretenureFlag)
>>>  api.cc:6459 NewString
>>>  api.cc:6519  (inlined by) NewFromUtf8
>>> (... application code ...)
>>>
>>> It looks like the Worklist being destroyed here is
>>> Scavenger::PromotionList::regular_object_promotion_list_. This Worklist is
>>> being destroyed at the end of Scavenger

Re: [v8-users] What are the threading considerations for EmbedderHeapTracer?

2018-10-03 Thread Michael Lippautz
On Tue, Oct 2, 2018 at 10:12 PM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> On Tue, Oct 2, 2018 at 11:10 AM Michael Lippautz 
> wrote:
>
>> Glad that your setup works for you now. Is your project open source? In
>> any case, let us know if you encounter any further issues.
>>
>
> This is all for the Cloudflare Workers runtime.
> https://developers.cloudflare.com/workers/about/
>
> At present it is not open source. But, I'd very much like to release our
> C++<->V8 glue layer at some point soon. We've used a lot of template/macro
> magic to make it pretty painless to export a C++ interface to JavaScript.
>

Cool :)


>
> * When allocating a new native object, I check if a trace pass is in
>>> progress (i.e. TracePrologue() has been called but TraceEpilogue() has
>>> not). If so, I add the object to the list of objects that needs to be
>>> traced. This handles the specific case that you mentioned, where the object
>>> is allocated already-marked, and hence won't otherwise be traced as part of
>>> the current tracing pass. It looks like I can't actually do the trace
>>> synchronously when the object is created -- V8 doesn't expect
>>> RegisterExternalReference() to be called at this time and crashes. Instead,
>>> by adding it to the list, my tracer's IsTracingDone() now returns false,
>>> which leads V8 to call AdvanceTracing() at some future point, which is
>>> where I can then trace the object.
>>>
>>
>> Delaying is usually better as depending on scheduling and idleness it has
>> the potential to run in a less-busy phase of execution. That depends on the
>> kind of platform you are running on though.
>>
>> On a first look, the synchronous call to RegisterExternalReference should
>> also work though. Any chance you can pass along what's happening via bug or
>> email?
>>
>
> If I call RegisterExternalReference() without checking if a trace is in
> progress, I pretty immediately get this unhelpful error dump:
>
> #
> # Fatal error in , line 0
> # unreachable code
> #
> #
> #
> #FailureMessage Object: 0x7f638f70b980
>
> Followed by a segfault with this stack trace:
>
> :? v8::internal::ConcurrentMarking::Run(int,
> v8::internal::ConcurrentMarking::TaskState*)
> ??:? v8::platform::WorkerThread::Run()
> platform-posix.cc:? v8::base::ThreadEntry(void*)
> glibc-2.24/nptl/pthread_create.c:333 start_thread
> glibc-2.24/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:97 clone
>
> It looks like if make sure only to call it if a trace is in progress, then
> it works fine.
>

Yes, that's correct. RegisterExternalReference() requires tracing to be in
progress. However, you should be able to call it from anywhere on the main
thread, e.g., also when V8 registers a reference through
RegisterV8References
<https://cs.chromium.org/chromium/src/v8/include/v8.h?q=EmbedderHeapTracer&sq=package:chromium&g=0&l=6961>.
What I meant is that there's no need to *only* process the objects during
AdvanceTracing
<https://cs.chromium.org/chromium/src/v8/include/v8.h?q=EmbedderHeapTracer&sq=package:chromium&g=0&l=7001>
.


>
> * It's possible that a newly-created object will be destroyed before
>>> tracing progresses, if all handles go out-of-scope. Hence, the object's
>>> weak callback must also check if a trace is in progress, and must then
>>> remove the object from the list of objects to be traced. Otherwise,
>>> AdvanceTracing() will end up tracing a dangling pointer.
>>>
>>
>> How can it go away? IIRC, then you set up the Scavenger correctly so that
>> it would be strong and the currently running Mark-Compact GC should not be
>> able to finish without tracing it.
>>
>
> I may have misspoke slightly here: it appears the effect I was seeing is
> *not* necessarily related to newly-created objects. Let me restate.
>
> It appears that it's possible that an object registered with
> EmbedderHeapTracer::RegisterV8References() can actually be collected (i.e.
> its weak callback is called) between then and
> EmbedderHeapTracer::AdvanceTracing(). So, in RegisterV8References() I have
> to make sure to put all the pointers in a map. When an object is destroyed
> while tracing is active, I have to go remove it from the tracer's map. In
> AdvanceTracing() I can then trace whatever is still in the map at that
> point.
>
> I'm not sure what mechanism causes the object to be destroyed immediately
> after it has been registered for tracing. But, AFAICT, the 

Re: [v8-users] What are the threading considerations for EmbedderHeapTracer?

2018-10-02 Thread Michael Lippautz
Glad that your setup works for you now. Is your project open source? In any
case, let us know if you encounter any further issues.

I also have a few followup questions below to make sure nothing is wrong
and potentially improve V8's handling there.

On Tue, Oct 2, 2018 at 6:34 PM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> I figured this out.
>
> First, some misunderstandings:
>
> 1) --predictable was a red herring. It fixed the specific reproduction
> case I had (seemingly by accident), but did not actually fix the general
> problem (and had some negative side-effects).
>

That's what I thought, yeah.


>
> 2) The term "write barrier" was confusing me because I'm not well-read in
> GC literature and I was thinking of a write barrier between threads. So I
> was assuming you were telling me that I was missing some thread
> synchronization, but given that only scavenges are multi-threaded and they
> don't trace through native objects, I didn't get it. But now I've figured
> out that this is actually a garbage collection term that is not necessarily
> related to threading.
>
>
Yes, I should've been more specific. Glad you figured it out.


> 3) I didn't fully realize that GC being incremental means that V8
> interleaves calls to the tracer with regular code execution, meaning that
> new objects could be created while a trace is in progress. This has almost
> all the same implications as being multi-threaded, without the actual
> threading.
>
>
It's slightly simpler as it avoids concurrent access on objects and all the
challenges that come with that.


>
> So, here's specifically what I did (in the hopes that it helps someone in
> the future):
>
> * When allocating a new native object, I check if a trace pass is in
> progress (i.e. TracePrologue() has been called but TraceEpilogue() has
> not). If so, I add the object to the list of objects that needs to be
> traced. This handles the specific case that you mentioned, where the object
> is allocated already-marked, and hence won't otherwise be traced as part of
> the current tracing pass. It looks like I can't actually do the trace
> synchronously when the object is created -- V8 doesn't expect
> RegisterExternalReference() to be called at this time and crashes. Instead,
> by adding it to the list, my tracer's IsTracingDone() now returns false,
> which leads V8 to call AdvanceTracing() at some future point, which is
> where I can then trace the object.
>

Delaying is usually better as depending on scheduling and idleness it has
the potential to run in a less-busy phase of execution. That depends on the
kind of platform you are running on though.

On a first look, the synchronous call to RegisterExternalReference should
also work though. Any chance you can pass along what's happening via bug or
email?


> * It's possible that a newly-created object will be destroyed before
> tracing progresses, if all handles go out-of-scope. Hence, the object's
> weak callback must also check if a trace is in progress, and must then
> remove the object from the list of objects to be traced. Otherwise,
> AdvanceTracing() will end up tracing a dangling pointer.
>

How can it go away? IIRC, then you set up the Scavenger correctly so that
it would be strong and the currently running Mark-Compact GC should not be
able to finish without tracing it.


>
> * If a native object can be modified after creation to add new weak
> handles, then of course we run into a similar problem: The parent object
> may already have been traced during the current cycle, and so the child
> needs to be traced immediately. At present this case does not actually come
> up in the objects we've instrumented, but it will at some point. I guess I
> will either need to re-queue the parent object to be traced again, or I'll
> need to specifically record that the new handle needs to have
> RegisterExternalRefreence() called when tracing next advances.
>
>
The is the problem of graph mutation during incremental (or concurrent)
garbage collections. As already said, we rely on write barriers to re-visit
such objects. You can follow the Blink implementation here
.
It uses a wrapping type that intercepts each write as manually
instrumenting code with write barriers is way too error prone for us.

Cheers, -Michael

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] What are the threading considerations for EmbedderHeapTracer?

2018-09-26 Thread Michael Lippautz
Two more ideas:
- V8 is using incremental marking for such wrappers which means that the
C++ graph should either (a) be immutable during marking or (b) should keep
the marking state consistent with e.g. write barriers.
- Specific issue: When creating an API object while marking is running, V8
may allocate the object as already marked (called black allocation). This
means that RegisterV8References() will not be called as the objects are not
discovered by the marker. In Blink, we thus issue a write barrier for such
objects when establishing a new link
<https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h?type=cs&q=SetNativeInfoInternal&sq=package:chromium&g=0&l=118>
.

We've some embedders that don't want to implement the incremental version
and they thus set the flag incremental_marking_wrappers
<https://cs.chromium.org/chromium/src/v8/src/flag-definitions.h?q=incremental_marking_wrappers&sq=package:chromium&g=0&l=712>
to false. You could try disabling that flag but also dropping predictable.

On Tue, Sep 25, 2018 at 6:36 PM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> Hi Michael,
>
> Thanks for commenting!
>
> On Tue, Sep 25, 2018 at 6:37 AM Michael Lippautz 
> wrote:
>
>> Looks like Isolate::VisitWeakHandles
>> <https://cs.chromium.org/chromium/src/v8/src/api.cc?q=Isolate::VisitWeakHandles&sq=package:chromium&g=0&l=8852>
>> only iterates over weak handles with a non-zero class id. Any chance that
>> this one is still 0?
>>
>
> No, I set class ID to 1 just before calling SetWeak() -- for no other
> purpose than this requirement. :)
>
>

Ack.


> The symptom described here hints to the Scavenger collecting objects. From
>> the above description it looks like you wanted to preserve those objects on
>> Scavenge.
>>
>> Some ideas:
>> - Maybe class id is 0 (see above)?
>> - Maybe the handle are not SetWeak
>> <https://cs.chromium.org/chromium/src/v8/include/v8.h?type=cs&q=v8::PersistentBase::SetWeak&sq=package:chromium&g=0&l=514>
>> immediately but only after some time where a Scavenge could've happened?
>>
>
> But before calling SetWeak(), the handle would be strong, and therefore
> not collected, right? Do I need to call MarkActive() at the same time as
> SetWeak() to make sure any currently-running scavenges don't collect it?
>
>
Yip, didn't think about this one. That all should work.

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] What are the threading considerations for EmbedderHeapTracer?

2018-09-25 Thread Michael Lippautz
On Sun, Sep 23, 2018 at 7:54 PM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> Hi v8-users,
>
> I'm trying to understand how to correctly instrument my wrappers for
> multi-threaded garbage collection, and it seems I'm doing something wrong.
> Currently, my code seems to work only in --predictable mode
> (single-threaded), but I'd like to take advantage of GC in a background
> thread.
>
> When in multi-threaded mode, I observe that occasionally, when V8 traces
> into a particular wrapper, the weak handles held by that wrapper have
> already been collected. The tracing is happening, but V8 seemingly
> prematurely collects some handles before I get a chance to mark them.
>
>
fyi: The cross-component tracing used for EmbedderHeapTracer always goes
through the main thread, i.e., none of its methods are called concurrently.


> Here are the things I've done:
>
> Per-object:
>
>- When I create a new wrapper object, I give it two internal fields
>set to the native object pointer and a tracing callback function.
>- The tracing callback, when run, invokes RegisterExternalReference()
>on each persistent handle reachable through the native object.
>- Once the internal pointers are set, I invoke SetWeak() (with no
>arguments) on all handles reachable through the native object.
>
> Globally:
>
>- I call AddGCPrologueCallback() to register a callback for
>v8::kGCTypeScavenge.
>- In the scavenge callback, I call VisitWeakHandles() with a visitor
>that calls MarkActive() on every handle.
>
>
Looks like Isolate::VisitWeakHandles

only iterates over weak handles with a non-zero class id. Any chance that
this one is still 0?


>
>- I call SetEmbedderHeapTracer() to register my own heap tracer
>implementation.
>- In the heap tracer's RegisterV8References() method, I invoke each
>tracing callback using the pair of internal pointers (which calls
>RegisterExternalReference() on reachable weak handles, as described above).
>- Currently, I don't do anything in AdvanceTracing() -- I complete all
>tracing before RegisterV8References() returns. (It appears this is what
>Blink does in its unified_heap_controller.cc, so I followed the example.)
>However, if I instead only save a copy of the pointer list in
>RegisterV8References() and then do the tracing later in AdvanceTracing(),
>then I observe problems with prematurely-collected handles more often. I'd
>guess this is because the underlying problem is a race condition, in which
>another thread is collecting those handles before I get a chance to trace
>them.
>
>
The symptom described here hints to the Scavenger collecting objects. From
the above description it looks like you wanted to preserve those objects on
Scavenge.

Some ideas:
- Maybe class id is 0 (see above)?
- Maybe the handle are not SetWeak

immediately but only after some time where a Scavenge could've happened?


>
>- I don't do anything in any of the other EmbedderHeapTracer callbacks.
>
> Anything I'm missing here?
>
> I haven't been able to find any documentation on how to use these
> interfaces. Please let me know if there are docs I missed.
>
>
There's no additional documentation and you already found the existing
implementations for wrapper tracing

and unified heap garbage collections

.

The Scavenger quirks are definitely something we should document though.

Cheers, -Michael

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] ArrayBuffer::Allocator::Free() length differing from Allocate() length?

2018-03-16 Thread Michael Lippautz
Is that the exact implementation? v8::ArrayBuffer::Allocator is required to
be thread-safe [1] as V8 potentially (depends on the platform
implementation) offloads the freeing onto a different thread.

Cheers, -Michael

[1] https://cs.chromium.org/chromium/src/v8/include/v8.h?dr=CSs&l=4269


On Thu, Mar 15, 2018 at 2:36 AM 'Kenton Varda' via v8-users <
v8-users@googlegroups.com> wrote:

> Hi v8-users,
>
> We have an ArrayBufferAllocator implementation that counts how much memory
> has been allocated. It basically looks like this:
>
> class AllocatorImpl final: public v8::ArrayBuffer::Allocator {
>
> public:
>
>   AllocatorImpl(): allocated(0) {}
>
>   ~AllocatorImpl();
>
>
>   inline size_t getMemoryUsage() const { return allocated; }
>
>
>   void* Allocate(size_t length) {
>
> allocated += length;
>
> return calloc(length, 1);
>
>   }
>
>   void* AllocateUninitialized(size_t length) {
>
> allocated += length;
>
> return malloc(length);
>
>   }
>
>   void Free(void* data, size_t length) {
>
> allocated -= length;
>
> free(data);
>
>   }
>
>
> private:
>
>   size_t allocated;
>
> };
>
>
> We're observing something strange: Sometimes (very rarely!), the
> `allocated` value drops below zero and wraps around, apparently indicating
> that V8 has Free()'d more than it Allocate()ed. However, there don't seem
> to be any issues with double-frees or freeing an invalid pointer.
>
> Any idea what could lead to this? Is it possible for V8 to pass a
> different `legth` value to Free() than it passed to Allocate()?
>
> Unfortunately I have no idea how to reproduce this reliably. It only
> happens very occasionally in production. :/
>
> -Kenton
>
> --
> --
> v8-users mailing list
> v8-users@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to the Google Groups
> "v8-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to v8-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] Strange Scavenge allocation failure cause dramatical performance dropdown

2017-12-05 Thread Michael Lippautz
At first sight, the Scavenge pause times seem unrelated to your problem.

Can you take a trace using Chrome's tracing infrastructure? See [1]. This
one will help dig down into what is causing the slowdown.

Rest inlined.

[1]
https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/recording-tracing-runs

On Tue, Dec 5, 2017 at 11:24 AM Huabin Ling 
wrote:

> Hi,
>
> I'm recently developing a rendering engine for WebGL, but met a serious
> performance issue caused by Scavenge allocation failure issue.
>
>
"allocation failure" means that V8 needs to do a garbage collection
(Scavenge in this case) as the young generation is out of allocatable
memory. This usually happens when JavaScript allocates objects.


> I have a test case which add more and more sprites on the screen, when
> it's arriving at about 7000 (and stop adding more), the cost of engine is
> about 6ms per frame, but it grows to 20 ms in seconds. When I add
> --trace_gc to Chrome, I see the behavior is totally related to a huge
> amount of Scavenge allocation failure log, like the following
>
>
> [33525:0x7fa78280fc00]   955497 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   955580 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   955663 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   955747 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>

Taking those samples I see that a Scavenge happens roughly every ~83ms. The
time the Scavenge takes is 0.3ms. From a garbage collection perspective the
utilization of anything else than GC is 99.6% which is pretty good.

All Scavenges happen regularly indicating that JavaScript is allocating at
a constant rate. Also, they all take up 0.3ms which is probably as fast as
it can get.

[33525:0x7fa78280fc00]   955830 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5) MB,
> 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   955913 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   955998 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   956084 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   956170 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   956254 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   956335 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   956418 ms: Scavenge 37.0 (46.5) -> 35.1 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   956502 ms: Scavenge 37.0 (46.5) -> 35.2 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   956584 ms: Scavenge 37.0 (46.5) -> 35.2 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   956667 ms: Scavenge 37.0 (46.5) -> 35.2 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> [33525:0x7fa78280fc00]   956752 ms: Scavenge 37.0 (46.5) -> 35.2 (46.5)
> MB, 0.3 / 0.0 ms  allocation failure
>
> ... (it keeps printing very fast)
>
>
> However, when I do a allocation profiling, it shows that the JS heap size
> is quite low (36mb), and I generate nearly nothing in heap
>
>
>
> 
>
>
> Some additional information, we tried very hard to reduce memory
> allocation in the engine core, so we used a lot of object pools and
> pre-generated objects, including some large array buffers, largest one is
> 2 * 6 floats, and we keep recycling / updating these objects.
>
>
> I also tried to check jit status, no hot functions is being deoptimized,
> the scavenge log is the only thing related to the strange performance drop
> down.
>
>
> Does anyone have a clue on my problem ? Thanks a lot for helping
>
>
> Huabin
>
>
> --
> --
> v8-users mailing list
> v8-users@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to the Google Groups
> "v8-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to v8-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] Peeking into scavenging work

2017-07-28 Thread Michael Lippautz
On Sat, Jul 22, 2017 at 9:59 AM Pawel Kozlowski <
pkozlowski.opensou...@gmail.com> wrote:

> Hi there!
>
> It might be more of the dev tools question than V8 question, but let me
> try it anyway...
>
> So, I'm trying to better understand how scavenger goes about its business,
> or more precisely, what ends up in the young generation space and gets
> subsequently collected.
>

For your library you can assume that any objects created by your
application will end up in the young generation.

Some internal objects can go directly to the old generation. Additionally,
there exist optimizations that allow objects to be allocated directly in
the old generation. These are special cases though and in general all
objects start in the young generation.


> I'm working on a lib where I see non-negligible scavenging pauses (±4ms
> which is significant for my use-case). After poking here and there I've
> realized that I don't understand what _exactly_ ends up int the young
> generation space. Of course I _know_ what objects I'm creating myself but
> it seems that there is more memory allocated _somewhere_ that
> makes scavenging work kicking in.
>

Maybe another library or dependency? Without JS interaction, v8 doesn't
allocate anything in the young generation.

Have you tried recording an allocation profile using DevTools? The idea
behind this profile is that dominating allocations (= the ones causing GCs)
will show up there.


>
> I'm guess I'm trying to answer the following question: what is there on
> the young generation space when scavenger kicks in. Is there any way (even
> the most obscure tooling) to "see" those objects?
>

No, as the heap architecture is an implementation detail and generations
don't exist in JS.


>
> If not, I would have 2 "proxy" question:
> - what happens (in terms of memory) when creating new DOM objects? Where
> are those allocated and what ends up on the young generation space (just a
> pointer? full DOM object?)
>

DOM objects are part of the rendering engine, Blink in V8's case. V8 lazily
allocates wrapping objects on the JS heap for those when needed. These end
up in the young generation.


> - is optimizing compiler generating any objects that end up on the young
> generation space and can trigger  scavenging work?
>

Code is not allocated in the young generation. The compiler might create a
few internal objects but nothing that should cause significant additional
scavenging work.


>
> Sorry if I'm totally confusing things here, but just starting to explore
> inner workings of memory allocation / young generation... Any guidance
> would be more than appreciated.
>
> Cheers,
> Pawel
>
>
>
Cheers, Michael

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] Cryptic out-of-memory error

2017-05-11 Thread Michael Lippautz
V8 suffered from a virtual address space leak which was fixed and
backmerged to 57 (https://bugs.chromium.org/p/v8/issues/detail?id=5945).

Awesome it works for you now.

On Thu, May 11, 2017 at 7:04 PM Andre Cunha 
wrote:

> I have repeated the tests in V8 5.8.283.38, and indeed the problem is
> gone. The amount of virtual memory remains stable over time.
>
> With regard to the cause of the problem, I managed to create a similar
> situation (increase in virtual memory consumption without increase in
> actual memory usage) using a loop like this:
>
> while (true) {
>   usleep(100);
>   sbrk(4096 * 40);
> }
>
> I would guess that, in version 5.6, the program break of the process was
> being increased when an Isolate was allocated, some allocated pages were
> not being used, but the program break wasn't being decreased when
> Isolate::Dispose() was called. The memory the Isolate used to occupy was
> nonetheless marked free, and thus reused in subsequent allocations, but the
> allocation process would still increase the program break anyway. Since
> these extra pages were never referenced, no actual memory was allocated to
> the process, but the program break reached its limit at some point. That
> could explain the situation, but it's just a wild guess, and the problem is
> solved in 5.8 anyway.
>
> Thank you for the support.
> Andre
>
> On Thursday, May 11, 2017 at 10:45:30 AM UTC-3, Jakob Kummerow wrote:
>>
>> On Thu, May 11, 2017 at 3:38 PM, Jochen Eisinger 
>> wrote:
>>
>>> Thank you for the detailed bug report.
>>>
>>> I tried reproducing this on the latest version of V8, but couldn't
>>> observe the behavior you described.
>>>
>>> Have you considered updating to at least the latest stable version of V8?
>>>
>>
>> ...which would be branch-heads/5.8 (currently 5.8.283.38)
>>
>>
>
>>> On Wed, May 10, 2017 at 7:50 PM Andre Cunha 
>>> wrote:
>>>
>>>> I've managed to reproduce the problem using just V8's hello_world
>>>> example (source code attached). I just added a loop around the creation and
>>>> destruction of the Isolate (this is what happens in each cycle of my stress
>>>> test). When I run the process and monitor it in "top", the RES column stays
>>>> constant at around 26 MB, but the VIRT column grows indefinitely; after
>>>> about 7 minutes, the VIRT column reaches around 33 GB, and the process
>>>> crashes (the value of "CommitLimit" in my machine, got from /proc/meminfo,
>>>> is 35,511,816 kB).
>>>>
>>>> Following Michael's suggestion, I changed file src/heap/spaces.cc so
>>>> that it prints a stack trace when it's about to return NULL. I'm also
>>>> sending the stack trace attached. I use V8 5.6.326.42 in Fedora 25, x86_64.
>>>>
>>>> Just to explain why I'm doing this test: in the library I'm working on,
>>>> the user can create a certain kind of thread and send requests to it. Each
>>>> thread needs to run JS code (received from the user), so it creates its own
>>>> Isolate when it needs to, and destroys it when the Isolate is no longer
>>>> necessary. One of our stress tests involves the constant creation and
>>>> destruction of such threads, as well as constantly sending requests to the
>>>> same thread. It was in this context that I found this problem.
>>>>
>>>> On Monday, May 8, 2017 at 12:50:37 PM UTC-3, Andre Cunha wrote:
>>>>>
>>>>> @Michael Lippautz, I'll try adding a breakpoint if AllocateChunk
>>>>> returns NULL; hopefully, I'll get more information about the problem.
>>>>>
>>>>> @Jakob Kummerow, yes, I'm calling Isolate::Dispose() in every isolate
>>>>> after using it. I'll also observe the VIRT column and see if it shows any
>>>>> abnormality.
>>>>>
>>>>> Thank you!
>>>>>
>>>>> On Monday, May 8, 2017 at 11:07:44 AM UTC-3, Jakob Kummerow wrote:
>>>>>>
>>>>>> My guess would be an address space leak (should show up in the "VIRT"
>>>>>> column of "top" on Linux). Are you calling "isolate->Dispose()" on any
>>>>>> isolate you're done with?
>>>>>>
>>>>>> On Mon, May 8, 2017 at 4:01 PM, Michael Lippautz <
>>>>>> mlip...@chromium.org> wrote:
>>>>>>
>>>>>>&g

Re: [v8-users] Cryptic out-of-memory error

2017-05-08 Thread Michael Lippautz
V8 usually fails there if it cannot allocate a 512KiB page from the
operating system/

You could try hooking in AllocateChunk [1] and see why it is returning NULL
and trace back through the underlying calls.

Best, Michael

[1]:
https://cs.chromium.org/chromium/src/v8/src/heap/spaces.cc?q=AllocateChunk&sq=package:chromium&l=739

On Mon, May 8, 2017 at 3:27 PM Andre Cunha  wrote:

> Hello,
>
> I have embedded v8 into a project for the company I work for, and during
> some stress tests, I've encountered a weird out-of-memory error. After
> considerable investigation, I still have no idea of what might be going on,
> so I'm reaching out to you in hope of some insight.
>
> So here is a summary of the scenario: in each test iteration, I create an
> Isolate, run some short JS code fragments, and then destroy the isolate.
> After the execution of each code fragment, I perform some variable
> manipulations from my C++ code using V8's API, prior to running the next
> fragment. I repeat thousands of such iterations over the same input (it's
> valid), and I expect no memory leaks and no crashes. However, after about 3
> hours, V8 crashes with an out-of-memory error of no apparent reason.
>
> I have run the code though valgrind and using address sanitizing, and no
> memory leaks were detected. Additionally, I monitor memory consumption
> throughout the test; the program's memory usage is stable, without any
> peak, and when V8 crashes the system has a lot of available memory (more
> than 5 Gib). I have used V8's API to get heap usage statistics after each
> successful iteration; the values are always the same, and are shown below
> (they are included in an attached file, typical_memory.txt):
>
> ScriptEngine::Run: finished running at 2017-05-05T13:20:34
>   used_heap_size   : 46.9189 Mib
>   total_heap_size  : 66.1562 Mib
>   Space 0
> name   : new_space
> size   : 8 Mib
> used_size  : 2.47314 Mib
> available_size : 5.39404 Mib
>   Space 1
> name   : old_space
> size   : 39.5625 Mib
> used_size  : 31.6393 Mib
> available_size : 5.51526 Mib
>   Space 2
> name   : code_space
> size   : 10.4375 Mib
> used_size  : 6.16919 Mib
> available_size : 0 B
>   Space 3
> name   : map_space
> size   : 8.15625 Mib
> used_size  : 6.63733 Mib
> available_size : 80 B
>   Space 4
> name   : large_object_space
> size   : 0 B
> used_size  : 0 B
> available_size : 11.1015 Gib
>
> When V8 crashes, it prints a heap summary, which I'm sending attached
> (file heap_after_error.txt). I also save a core dump. Sometimes, the
> system crashes during the creation of an Isolate; sometimes, during the
> creation of a Context; typically, it crashes during snapshot
> deserialization. However, the top of the stack is always the same, and it's
> reproduced below (also included attached, file stacktrace.txt).
>
> #7  v8::internal::OS::Abort () at
> ../../src/base/platform/platform-posix.cc:230
> #8  0x7ff15a2f922f in v8::Utils::ReportOOMFailure
> (location=0x7ff15b20f62e "Committing semi space failed.",
> is_heap_oom=false) at ../../src/api.cc:381
> #9  0x7ff15a2f918e in v8::internal::V8::FatalProcessOutOfMemory
> (location=0x7ff15b20f62e "Committing semi space failed.",
> is_heap_oom=false) at ../../src/api.cc:352
> #10 0x7ff15aa3fefc in v8::internal::Heap::EnsureFromSpaceIsCommitted
> (this=0x7ff12c0bdde0) at ../../src/heap/heap.cc:1234
> #11 0x7ff15aa3ed34 in v8::internal::Heap::PerformGarbageCollection
> (this=0x7ff12c0bdde0, collector=v8::internal::MARK_COMPACTOR,
> gc_callback_flags=v8::kNoGCCallbackFlags) at
> ../../src/heap/heap.cc:1308
> #12 0x7ff15aa3e2ab in v8::internal::Heap::CollectGarbage
> (this=0x7ff12c0bdde0, collector=v8::internal::MARK_COMPACTOR,
> gc_reason=v8::internal::GarbageCollectionReason::kDeserializer,
> collector_reason=0x7ff15b20f07a "GC in old space requested",
> gc_callback_flags=v8::kNoGCCallbackFlags) at
> ../../src/heap/heap.cc:1002
> #13 0x7ff15a33cdee in v8::internal::Heap::CollectGarbage
> (this=0x7ff12c0bdde0, space=v8::internal::OLD_SPACE,
> gc_reason=v8::internal::GarbageCollectionReason::kDeserializer,
> callbackFlags=v8::kNoGCCallbackFlags) at ../../src/heap/heap-inl.h:681
> #14 0x7ff15aa3d069 in v8::internal::Heap::CollectAllGarbage
> (this=0x7ff12c0bdde0, flags=2,
> gc_reason=v8::internal::GarbageCollectionReason::kDeserializer,
> gc_callback_flags=v8::kNoGCCallbackFlags) at ../../src/heap/heap.cc:848
> #15 0x7ff15aa3fe84 in v8::internal::Heap::ReserveSpace
> (this=0x7ff12c0bdde0, reservations=0x7ff148fe6078, maps=0x7ff148fe60f8) at
> ../../src/heap/heap.cc:1215
>
> In the heap summary that gets printed, I have noted some apparent
> discrepancies with the typical data I get from the API (shown abo

Re: [v8-users] Memory allocation tracking in V8

2016-11-07 Thread Michael Lippautz
On Fri, Nov 4, 2016 at 4:01 PM Ivan P.  wrote:

Hello, I am porting my app to latest stable version of the V8 engine from
quite legacy V8 3.19.
I was using v8::V8::AddMemoryAllocationCallback() to set callaback on the
memory allocation actions.
But now I can't find this function. What is analog to this in the new V8? I
am porting to version 5.3.332.45


AddMemoryAllocationCallback has been removed because its semantics were not
clearly defined.

You can use Isolate::GetHeapSpaceStatistics from a combination of
(a) a GC epilogue callback registered using Isolate::AddGCEpilogueCallback
(b) an interrupt registered using Isolate::RequestInterrupt.

For coarse-grained (up to a couple %) info (a) will be enough as the GC
will kick in if memory grows above certain limits. (b) is needed if you
want more fine-grained statistics.

-Michael

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] output of --trace_gc

2015-09-16 Thread Michael Lippautz
The corresponding source can be found in
  src/heap/gc-tracer.cc

On Wed, Sep 16, 2015 at 7:02 AM dmonji  wrote:

> [29648:0xbad6f48] 2631 ms: Scavenge 8.0 (22.6) -> 4.2 (22.6) MB, 8.4 /
> 0 ms [allocation failure].
>

[:]  ms:   () ->  () MB,
 / 
[].


> [29648:0xbad6f48] 3130 ms: Mark-sweep 8.0 (22.6) -> 4.4 (22.6) MB,
> 63.0 / 0 ms (+ 69.0 ms in 55 steps since start of marking, biggest step 2.4
> ms) [GC interrupt] [GC in old space requested].
>
>
Same as above, with the addition
  ... ( / <# incremental steps> ,
biggest step ) [].

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[v8-users] Re: ArrayBuffer API triggers unnecessary mark-and-sweep events.

2015-09-01 Thread Michael Lippautz
Hi Mark,

The limits should be adjusted during Externalize(). Feel free to create a 
bug.

We have changes queued on this area that are to be landed soonish though. 
Chances are good that it gets fixed right away.

-Michael

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.