Bug 156378

Summary: tryGetById should be supported by the DFG/FTL
Product: WebKit Reporter: Keith Miller <keith_miller>
Component: New BugsAssignee: Keith Miller <keith_miller>
Status: RESOLVED FIXED    
Severity: Normal CC: commit-queue, ggaren, mark.lam, msaboff, saam
Priority: P2    
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch
none
Patch
none
Patch none

Description Keith Miller 2016-04-07 16:40:51 PDT
tryGetById should be supported by the DFG/FTL
Comment 1 Keith Miller 2016-04-07 16:49:00 PDT
Created attachment 275959 [details]
Patch
Comment 2 Geoffrey Garen 2016-04-08 11:16:27 PDT
/Volumes/Data/EWS/WebKit/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp:979:66: error: cannot initialize a parameter of type 'GPRReg' (aka 'RegisterID') with an rvalue of type 'unsigned int'
        cachedGetById(node->origin.semantic, baseGPR, resultGPR, node->identifierNumber(), JITCompiler::Jump(), DontSpill, AccessType::GetPure);
                                                                 ^~~~~~~~~~~~~~~~~~~~~~~~
Comment 3 Keith Miller 2016-04-08 14:28:51 PDT
Created attachment 276043 [details]
Patch
Comment 4 Mark Lam 2016-04-08 15:39:57 PDT
Comment on attachment 276043 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=276043&action=review

> Source/JavaScriptCore/ChangeLog:11
> +        we do not profile the result type. This profiling is unnessary for the current

typo: /unnessary/unnecessary/.
Comment 5 Filip Pizlo 2016-04-08 15:45:42 PDT
Comment on attachment 276043 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=276043&action=review

I think you should reduce the code duplication in ByteCodeParser.

> Source/JavaScriptCore/bytecode/GetByIdStatus.cpp:78
> -    if (instruction[0].u.opcode == LLInt::getOpcode(op_get_array_length))
> +    if (instruction[0].u.opcode == LLInt::getOpcode(op_get_array_length) || instruction[0].u.opcode == LLInt::getOpcode(op_try_get_by_id))

Can you provide clarity on why you return NoInformation when LLInt saw a try_get_by_id?

> Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h:1969
> +        forNode(node).makeBytecodeTop();

Why isn't this makeHeapTop()?  Can TryGetById return the empty value?  If not, then this should be HeapTop.

Also, it seems like you should add folding here that is like the folding we do in GetById.  If you don't add it, then please add a FIXME to that effect and link it to a bug!

> Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:2889
> +void ByteCodeParser::handleTryGetById(int destinationOperand, Node* base, unsigned identifierNumber, const GetByIdStatus& getByIdStatus)

This method looks like it duplicates a *ton* of code with handleGetById.  Please try to make them common.

> Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:2896
> +    if (!getByIdStatus.isSimple() || !getByIdStatus.numVariants() || !Options::useAccessInlining()) {
> +        set(VirtualRegister(destinationOperand),
> +            addToGraph(TryGetById, OpInfo(identifierNumber), OpInfo(SpecBytecodeTop), base));
> +        return;
> +    }

This is identical to the first case in handleGetById.

> Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:2904
> +        if (!isFTL(m_graph.m_plan.mode)
> +            || !Options::usePolymorphicAccessInlining()) {
> +            set(VirtualRegister(destinationOperand),
> +                addToGraph(TryGetById, OpInfo(identifierNumber), OpInfo(SpecBytecodeTop), base));
> +            return;
> +        }

Identical.

> Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:2932
> +        // 1) Emit prototype structure checks for all chains. This could sort of maybe not be
> +        //    optimal, if there is some rarely executed case in the chain that requires a lot
> +        //    of checks and those checks are not watchpointable.
> +        for (const GetByIdVariant& variant : getByIdStatus.variants()) {
> +            ASSERT(variant.intrinsic() == NoIntrinsic);
> +
> +            if (variant.conditionSet().isEmpty()) {
> +                cases.append(MultiGetByOffsetCase(
> +                    variant.structureSet(),
> +                    GetByOffsetMethod::load(variant.offset())));
> +                continue;
> +            }
> +
> +            GetByOffsetMethod method = planLoad(variant.conditionSet());
> +            if (!method) {
> +                set(VirtualRegister(destinationOperand),
> +                    addToGraph(TryGetById, OpInfo(identifierNumber), OpInfo(SpecBytecodeTop), base));
> +                return;
> +            }
> +
> +            cases.append(MultiGetByOffsetCase(variant.structureSet(), method));
> +        }
> +
> +        if (m_graph.compilation())
> +            m_graph.compilation()->noticeInlinedGetById();

So very identical.

> Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:2940
> +        // 2) Emit a MultiGetByOffset
> +        MultiGetByOffsetData* data = m_graph.m_multiGetByOffsetData.add();
> +        data->cases = cases;
> +        data->identifierNumber = identifierNumber;
> +        set(VirtualRegister(destinationOperand),
> +            addToGraph(MultiGetByOffset, OpInfo(data), OpInfo(SpecBytecodeTop), base));
> +        return;

Identical.

> Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:2957
> +    if (m_graph.compilation())
> +        m_graph.compilation()->noticeInlinedGetById();
> +    set(VirtualRegister(destinationOperand), loadedValue);
> +}

Looks like this is the only place where this is different from handleGetById.  Basically, you want handleGetById to have a flag or something that tells it that it's the Try variant, and then you want handleGetById to return early here.

> Source/JavaScriptCore/dfg/DFGClobberize.h:859
> +    case TryGetById: {
> +        read(JSCell_structureID);
> +        read(JSObject_butterfly);
> +        AbstractHeap heap(NamedProperties, node->identifierNumber());
> +        read(heap);
> +        def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node));
> +        return;
> +    }

Are you sure about this?  Can't TryGetById call any arbitrary GetOwnPropertySlot?

I think that the more conservative thing to do for now is remove the def() and make this read(Heap).
Comment 6 Keith Miller 2016-04-08 15:58:01 PDT
Comment on attachment 276043 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=276043&action=review

>> Source/JavaScriptCore/bytecode/GetByIdStatus.cpp:78
>> +    if (instruction[0].u.opcode == LLInt::getOpcode(op_get_array_length) || instruction[0].u.opcode == LLInt::getOpcode(op_try_get_by_id))
> 
> Can you provide clarity on why you return NoInformation when LLInt saw a try_get_by_id?

Because we don't have an LLInt cache for TryGetById. In the long run I do think that an LLInt cache should be added.

>> Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h:1969
>> +        forNode(node).makeBytecodeTop();
> 
> Why isn't this makeHeapTop()?  Can TryGetById return the empty value?  If not, then this should be HeapTop.
> 
> Also, it seems like you should add folding here that is like the folding we do in GetById.  If you don't add it, then please add a FIXME to that effect and link it to a bug!

Yeah, it should be HeapTop. I will fix.

The folding that we do here will not help any current uses of this operation since they all use values on the prototype. I'll create a bug though.

>> Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:2889
>> +void ByteCodeParser::handleTryGetById(int destinationOperand, Node* base, unsigned identifierNumber, const GetByIdStatus& getByIdStatus)
> 
> This method looks like it duplicates a *ton* of code with handleGetById.  Please try to make them common.

Yeah, you are probably right. I will change it.

>> Source/JavaScriptCore/dfg/DFGClobberize.h:859
>> +    }
> 
> Are you sure about this?  Can't TryGetById call any arbitrary GetOwnPropertySlot?
> 
> I think that the more conservative thing to do for now is remove the def() and make this read(Heap).

Changed.
Comment 7 Keith Miller 2016-04-08 16:20:49 PDT
Created attachment 276051 [details]
Patch
Comment 8 WebKit Commit Bot 2016-04-09 20:38:43 PDT
Comment on attachment 276051 [details]
Patch

Clearing flags on attachment: 276051

Committed r199279: <http://trac.webkit.org/changeset/199279>
Comment 9 WebKit Commit Bot 2016-04-09 20:38:46 PDT
All reviewed patches have been landed.  Closing bug.
Comment 10 Filip Pizlo 2016-08-16 16:59:17 PDT
Comment on attachment 276051 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=276051&action=review

> Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:3867
> +            handleGetById(currentInstruction[1].u.operand, SpecHeapTop, base, identifierNumber, getByIdStatus, AccessType::GetPure);

You should be able to produce a type prediction here.

Filed: https://bugs.webkit.org/show_bug.cgi?id=160921

> Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp:177
> +            changed |= setPrediction(SpecBytecodeTop);

It's wrong to ever use any of the Top's in prediction propagation phase.  This tells the prediction propagator that this node will *definitely* return values of all types, which causes us to assume the worst for all downstream code.

Filed: https://bugs.webkit.org/show_bug.cgi?id=160921