[webkit-reviews] review granted: [Bug 200898] [JSC] Make Promise implementation faster : [Attachment 377932] Patch
bugzilla-daemon at webkit.org
bugzilla-daemon at webkit.org
Tue Sep 3 22:10:10 PDT 2019
Saam Barati <sbarati at apple.com> has granted Yusuke Suzuki <ysuzuki at apple.com>'s
request for review:
Bug 200898: [JSC] Make Promise implementation faster
https://bugs.webkit.org/show_bug.cgi?id=200898
Attachment 377932: Patch
https://bugs.webkit.org/attachment.cgi?id=377932&action=review
--- Comment #73 from Saam Barati <sbarati at apple.com> ---
Comment on attachment 377932
--> https://bugs.webkit.org/attachment.cgi?id=377932
Patch
View in context: https://bugs.webkit.org/attachment.cgi?id=377932&action=review
> Source/JavaScriptCore/ChangeLog:8
> + This is the major change of the Promise implementation and it
improves JetStream2/async-fs by 62%.
> Source/JavaScriptCore/ChangeLog:10
> + 1. Make JSPromise C++ friendly
nit: in the future, it'd be nice to split these things in their own patches as
they don't seem like they need to be landed all at once.
> Source/JavaScriptCore/ChangeLog:27
> + The old JSPromise constructor was doing very inefficient thing:
JSPromise constructor is InternalFunction in C++, and in it, it
"was doing very inefficient thing" => "was very inefficient"
> Source/JavaScriptCore/ChangeLog:29
> + If we can implement JSPromise constructor in all JS code, we can
recognize `executor` and we have a chance to fully inline them.
"in all JS code" => "fully in JS"
> Source/JavaScriptCore/ChangeLog:31
> + construct is 100. If we decide inlining it, we should
reinvestigate it further.
"If we decide inlining it, we should reinvestigate it further." => "We might
want to investigate getting it inlined in the future."
Also, might be worth a bug?
> Source/JavaScriptCore/ChangeLog:33
> + We can avoid C++ <-> JS dance in such an important operation,
allocating JSPromise. This patch introduces @nakedConstructor
this is cool
> Source/JavaScriptCore/ChangeLog:46
> + When converting CreatePromise to NewPromise, we need to get the
correct structure with a specified `callee.prototype`. We mimics the mechanism
mimics => mimic
> Source/JavaScriptCore/ChangeLog:59
> + check to take a fast path. And promise reaction now handles 4
cases to handle the case not creating a promise.
the final sentence here doesn't make sense to me
> Source/JavaScriptCore/builtins/AsyncFromSyncIteratorPrototype.js:-30
> - const promiseCapability = @newPromiseCapability(@Promise);
you should add Apple copyright to this file too
> Source/JavaScriptCore/builtins/AsyncFromSyncIteratorPrototype.js:42
> + var nextDone = !!nextResult.done;
> + var nextValue = nextResult.value;
does this change the order we read the fields from the result? Isn't that
observable?
> Source/JavaScriptCore/builtins/PromiseConstructor.js:234
> + var promise = result;
what's the point of this local variable?
> Source/JavaScriptCore/builtins/PromiseConstructor.js:242
> + function @resolve(resolution) {
> + return @resolvePromiseWithFirstResolvingFunctionCallCheck(promise,
resolution);
> + }
> +
> + function @reject(reason) {
> + return @rejectPromiseWithFirstResolvingFunctionCallCheck(promise,
reason);
> + }
why give these private names instead of just "resolve" and "reject"?
> Source/JavaScriptCore/builtins/PromiseConstructor.js:270
> + function @resolve(resolution) {
> + return @resolvePromiseWithFirstResolvingFunctionCallCheck(promise,
resolution);
> + }
> +
> + function @reject(reason) {
> + return @rejectPromiseWithFirstResolvingFunctionCallCheck(promise,
reason);
> + }
ditto
> Source/JavaScriptCore/builtins/PromiseOperations.js:134
> + return @rejectPromise(promise, @makeTypeError("Resolve a promise
with itself"));
maybe "Cannot resolve a promise with itself"?
> Source/JavaScriptCore/builtins/PromiseOperations.js:146
> + if (@isPromise(resolution) && then === @then) {
maybe we should name "@then" in the global namespace to be less generic. Maybe
"@defaultPromiseThen" or something?
> Source/JavaScriptCore/bytecode/CodeBlock.cpp:1302
> + auto& cacheWriteBarrier = metadata.m_cachedCallee;
> + if (!cacheWriteBarrier || cacheWriteBarrier.unvalidatedGet() ==
JSCell::seenMultipleCalleeObjects())
> + break;
> + JSCell* cachedFunction = cacheWriteBarrier.get();
isn't this a TOCTOU bug? You load the first time and it's ok, and then you load
again on line 1302 and it's now "seenMultipleCalleeObjects". Or is this called
with the mutator paused?
> Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h:2628
> + if
(rareData->allocationProfileWatchpointSet().isStillValid()) {
> + if (Structure* structure =
rareData->objectAllocationStructure()) {
why this change? Seems unrelated to your patch
> Source/JavaScriptCore/dfg/DFGUseKind.h:58
> + PromiseObjectUse,
This seems like it's completely unused. I'd vote for removing it. You said in
your changelog that you would use this for making @isPromise faster, but I
don't see it.
> Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp:5923
> + ValueFromBlock slowResult = m_out.anchor(vmCall(pointerType(),
m_out.operation(m_node->isInternalPromise() ? operationNewInternalPromise :
operationNewPromise), m_callFrame, weakStructure(m_node->structure())));
why weakStructure here? This feels like a "strong" use case, since all objects
which have this structure might go away, but it shouldn't mean we throw this
code away, since the code might be reachable and we allocate new structures.
> Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp:6302
> + ValueFromBlock promiseStructure =
m_out.anchor(weakStructure(m_graph.registerStructure(m_node->isInternalPromise(
) ? globalObject->internalPromiseStructure() :
globalObject->promiseStructure())));
ditto: doesn't feel like it should be weak
> Source/JavaScriptCore/llint/LowLevelInterpreter64.asm:528
> + btpz value, .writeBarrierDone
why would we be putting the JSValue zero? Seems wrong.
> Source/JavaScriptCore/llint/LowLevelInterpreter64.asm:2598
> + getu(size, OpGetPromiseInternalField, m_index, t2)
this zero extends?
> Source/JavaScriptCore/llint/LowLevelInterpreter64.asm:2607
> + getu(size, OpPutPromiseInternalField, m_index, t1)
this zero extends?
> Source/JavaScriptCore/runtime/CommonSlowPaths.cpp:289
> + if (constructorAsObject->type() == JSFunctionType &&
jsCast<JSFunction*>(constructorAsObject)->canUseAllocationProfile()) {
nit: I think it's nicer to jsDynamicCast<JSFunction*> here instead of checking
type manually.
> Source/JavaScriptCore/runtime/JSGlobalObject.cpp:1684
> + visitor.append(thisObject->m_internalPromiseConstructor);
oops
> Source/JavaScriptCore/runtime/JSPromise.h:72
> + static ptrdiff_t offsetOfInternalField(unsigned index) { return
OBJECT_OFFSETOF(JSPromise, m_internalFields) + index *
sizeof(WriteBarrier<Unknown>); }
does std::array give us this guarantee?
More information about the webkit-reviews
mailing list