Changeset 200606 in webkit


Ignore:
Timestamp:
May 9, 2016 7:01:28 PM (8 years ago)
Author:
fpizlo@apple.com
Message:

Polymorphic operands in operators coerces downstream values to double.
https://bugs.webkit.org/show_bug.cgi?id=151793

Reviewed by Mark Lam.
Source/JavaScriptCore:


Previously if an object flowed into arithmetic, the prediction propagation phase would either
assume that the output of the arithmetic had to be double or sometimes it would assume that it
couldn't be double. We want it to only assume that the output is double if it actually had been.

The first part of this patch is to roll out http://trac.webkit.org/changeset/200502. That removed
some of the machinery that we had in place to detect whether the output of an operation is int or
double. That changeset claimed that the machinery was "fundamentally broken". It actually wasn't.
The reason why it didn't work was that ByteCodeParser was ignoring it if likelyToTakeSlowCase was
false. I think this was a complete goof-up: the code in ByteCodeParser::makeSafe was structured
in a way that made it non-obvious that the method is a no-op if !likelyToTakeSlowCase. So, this
change rolls out r200502 and makes ResultProfile do its job by reshaping how makeSafe processes
it.

This also makes two other changes to shore up ResultProfile:

  • OSR exit can now refine a ResultProfile the same way that it refines ValueProfile.
  • Baseline JIT slow paths now set bits in ResultProfile.


Based on this stuff, the DFG now predicts int/double/string in op_add/op_sub/op_mul based on
ResultProfiles. To be conservative, we still only use the ResultProfiles if the incoming
prediction is not number-or-boolean. This ensures that we exactly retain our old behavior in
those cases for which it was tuned. But I hope to remove this soon. I believe that ResultProfile
is already strictly better than what prediction propagation was doing before.

This can be an enormous win. This patch adds some simple microbenchmarks that demonstrate the
problem of assuming that arithmetic on objects returns double. The most extreme of these speeds
up 8x with this change (object-int-add-array).

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/CodeBlock.h:

(JSC::CodeBlock::addFrequentExitSite):
(JSC::CodeBlock::hasExitSite):

  • bytecode/DFGExitProfile.cpp:

(JSC::DFG::FrequentExitSite::dump):
(JSC::DFG::ExitProfile::ExitProfile):
(JSC::DFG::ExitProfile::~ExitProfile):
(JSC::DFG::ExitProfile::add):

  • bytecode/DFGExitProfile.h:

(JSC::DFG::FrequentExitSite::isHashTableDeletedValue):

  • bytecode/MethodOfGettingAValueProfile.cpp:

(JSC::MethodOfGettingAValueProfile::fromLazyOperand):
(JSC::MethodOfGettingAValueProfile::emitReportValue):
(JSC::MethodOfGettingAValueProfile::getSpecFailBucket): Deleted.

  • bytecode/MethodOfGettingAValueProfile.h:

(JSC::MethodOfGettingAValueProfile::MethodOfGettingAValueProfile):
(JSC::MethodOfGettingAValueProfile::operator bool):
(JSC::MethodOfGettingAValueProfile::operator!): Deleted.

  • bytecode/PolymorphicAccess.cpp:

(JSC::AccessCase::generateImpl):

  • bytecode/ValueProfile.cpp:

(JSC::ResultProfile::emitDetectBitsLight):
(JSC::ResultProfile::emitSetDouble):
(JSC::ResultProfile::emitSetNonNumber):
(WTF::printInternal):

  • bytecode/ValueProfile.h:

(JSC::ResultProfile::ResultProfile):
(JSC::ResultProfile::bytecodeOffset):
(JSC::ResultProfile::specialFastPathCount):
(JSC::ResultProfile::didObserveNonInt32):
(JSC::ResultProfile::didObserveDouble):
(JSC::ResultProfile::didObserveNonNegZeroDouble):
(JSC::ResultProfile::didObserveNegZeroDouble):
(JSC::ResultProfile::didObserveNonNumber):
(JSC::ResultProfile::didObserveInt32Overflow):
(JSC::ResultProfile::didObserveInt52Overflow):
(JSC::ResultProfile::setObservedNonNegZeroDouble):
(JSC::ResultProfile::setObservedNegZeroDouble):
(JSC::ResultProfile::setObservedNonNumber):
(JSC::ResultProfile::setObservedInt32Overflow):
(JSC::ResultProfile::addressOfFlags):
(JSC::ResultProfile::addressOfSpecialFastPathCount):
(JSC::ResultProfile::detectBitsLight):
(JSC::ResultProfile::hasBits):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::makeSafe):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::ensureNaturalLoops):
(JSC::DFG::Graph::methodOfGettingAValueProfileFor):
(JSC::DFG::Graph::valueProfileFor): Deleted.

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::hasExitSite):
(JSC::DFG::Graph::numBlocks):

  • dfg/DFGNode.h:

(JSC::DFG::Node::arithNodeFlags):
(JSC::DFG::Node::mayHaveNonIntResult):
(JSC::DFG::Node::mayHaveDoubleResult):
(JSC::DFG::Node::mayHaveNonNumberResult):
(JSC::DFG::Node::hasConstantBuffer):

  • dfg/DFGNodeFlags.cpp:

(JSC::DFG::dumpNodeFlags):

  • dfg/DFGNodeFlags.h:
  • dfg/DFGOSRExitCompiler32_64.cpp:

(JSC::DFG::OSRExitCompiler::compileExit):

  • dfg/DFGOSRExitCompiler64.cpp:

(JSC::DFG::OSRExitCompiler::compileExit):

  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • ftl/FTLOSRExitCompiler.cpp:

(JSC::FTL::compileStub):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::branchIfEqual):
(JSC::AssemblyHelpers::branchIfNotCell):
(JSC::AssemblyHelpers::branchIfNotNumber):
(JSC::AssemblyHelpers::branchIfNotDoubleKnownNotInt32):
(JSC::AssemblyHelpers::branchIfBoolean):
(JSC::AssemblyHelpers::branchIfEmpty):
(JSC::AssemblyHelpers::branchStructure):

  • jit/CCallHelpers.h:

(JSC::CCallHelpers::CCallHelpers):
(JSC::CCallHelpers::setupArguments):
(JSC::CCallHelpers::setupArgumentsWithExecState):

  • jit/IntrinsicEmitter.cpp:

(JSC::AccessCase::emitIntrinsicGetter):

  • jit/JIT.h:
  • jit/JITAddGenerator.cpp:

(JSC::JITAddGenerator::generateFastPath):

  • jit/JITAddGenerator.h:

(JSC::JITAddGenerator::JITAddGenerator):

  • jit/JITArithmetic.cpp:

(JSC::JIT::emit_op_add):
(JSC::JIT::emitSlow_op_add):
(JSC::JIT::emit_op_div):
(JSC::JIT::emit_op_mul):
(JSC::JIT::emitSlow_op_mul):
(JSC::JIT::emit_op_sub):
(JSC::JIT::emitSlow_op_sub):

  • jit/JITInlines.h:

(JSC::JIT::callOperation):
(JSC::JIT::callOperationNoExceptionCheck):

  • jit/JITMulGenerator.cpp:

(JSC::JITMulGenerator::generateFastPath):

  • jit/JITOperations.cpp:
  • jit/JITOperations.h:
  • jit/JITSubGenerator.cpp:

(JSC::JITSubGenerator::generateFastPath):

  • jit/JITSubGenerator.h:

(JSC::JITSubGenerator::JITSubGenerator):

  • jit/TagRegistersMode.cpp: Added.

(WTF::printInternal):

  • jit/TagRegistersMode.h: Added.
  • runtime/CommonSlowPaths.cpp:

(JSC::updateResultProfileForBinaryArithOp):

LayoutTests:

  • js/regress/object-int-add-array-expected.txt: Added.
  • js/regress/object-int-add-array.html: Added.
  • js/regress/object-int-add-expected.txt: Added.
  • js/regress/object-int-add.html: Added.
  • js/regress/object-int-mul-array-expected.txt: Added.
  • js/regress/object-int-mul-array.html: Added.
  • js/regress/object-int-sub-array-expected.txt: Added.
  • js/regress/object-int-sub-array.html: Added.
  • js/regress/object-int-sub-expected.txt: Added.
  • js/regress/object-int-sub.html: Added.
  • js/regress/script-tests/object-int-add-array.js: Added.

(i.o.valueOf):

  • js/regress/script-tests/object-int-add.js: Added.

(i.o.valueOf):

  • js/regress/script-tests/object-int-mul-array.js: Added.

(i.o.valueOf):

  • js/regress/script-tests/object-int-sub-array.js: Added.

(i.o.valueOf):

  • js/regress/script-tests/object-int-sub.js: Added.

(i.o.valueOf):

Location:
trunk
Files:
17 added
42 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r200604 r200606  
     12016-05-09  Filip Pizlo  <fpizlo@apple.com>
     2
     3        Polymorphic operands in operators coerces downstream values to double.
     4        https://bugs.webkit.org/show_bug.cgi?id=151793
     5
     6        Reviewed by Mark Lam.
     7
     8        * js/regress/object-int-add-array-expected.txt: Added.
     9        * js/regress/object-int-add-array.html: Added.
     10        * js/regress/object-int-add-expected.txt: Added.
     11        * js/regress/object-int-add.html: Added.
     12        * js/regress/object-int-mul-array-expected.txt: Added.
     13        * js/regress/object-int-mul-array.html: Added.
     14        * js/regress/object-int-sub-array-expected.txt: Added.
     15        * js/regress/object-int-sub-array.html: Added.
     16        * js/regress/object-int-sub-expected.txt: Added.
     17        * js/regress/object-int-sub.html: Added.
     18        * js/regress/script-tests/object-int-add-array.js: Added.
     19        (i.o.valueOf):
     20        * js/regress/script-tests/object-int-add.js: Added.
     21        (i.o.valueOf):
     22        * js/regress/script-tests/object-int-mul-array.js: Added.
     23        (i.o.valueOf):
     24        * js/regress/script-tests/object-int-sub-array.js: Added.
     25        (i.o.valueOf):
     26        * js/regress/script-tests/object-int-sub.js: Added.
     27        (i.o.valueOf):
     28
    1292016-05-09  Simon Fraser  <simon.fraser@apple.com>
    230
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r200543 r200606  
    564564    jit/ScratchRegisterAllocator.cpp
    565565    jit/SetupVarargsFrame.cpp
     566    jit/TagRegistersMode.cpp
    566567    jit/TempRegisterSet.cpp
    567568    jit/ThunkGenerators.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r200597 r200606  
     12016-05-09  Filip Pizlo  <fpizlo@apple.com>
     2
     3        Polymorphic operands in operators coerces downstream values to double.
     4        https://bugs.webkit.org/show_bug.cgi?id=151793
     5
     6        Reviewed by Mark Lam.
     7       
     8        Previously if an object flowed into arithmetic, the prediction propagation phase would either
     9        assume that the output of the arithmetic had to be double or sometimes it would assume that it
     10        couldn't be double. We want it to only assume that the output is double if it actually had been.
     11       
     12        The first part of this patch is to roll out http://trac.webkit.org/changeset/200502. That removed
     13        some of the machinery that we had in place to detect whether the output of an operation is int or
     14        double. That changeset claimed that the machinery was "fundamentally broken". It actually wasn't.
     15        The reason why it didn't work was that ByteCodeParser was ignoring it if likelyToTakeSlowCase was
     16        false. I think this was a complete goof-up: the code in ByteCodeParser::makeSafe was structured
     17        in a way that made it non-obvious that the method is a no-op if !likelyToTakeSlowCase. So, this
     18        change rolls out r200502 and makes ResultProfile do its job by reshaping how makeSafe processes
     19        it.
     20       
     21        This also makes two other changes to shore up ResultProfile:
     22        - OSR exit can now refine a ResultProfile the same way that it refines ValueProfile.
     23        - Baseline JIT slow paths now set bits in ResultProfile.
     24       
     25        Based on this stuff, the DFG now predicts int/double/string in op_add/op_sub/op_mul based on
     26        ResultProfiles. To be conservative, we still only use the ResultProfiles if the incoming
     27        prediction is not number-or-boolean. This ensures that we exactly retain our old behavior in
     28        those cases for which it was tuned. But I hope to remove this soon. I believe that ResultProfile
     29        is already strictly better than what prediction propagation was doing before.
     30       
     31        This can be an enormous win. This patch adds some simple microbenchmarks that demonstrate the
     32        problem of assuming that arithmetic on objects returns double. The most extreme of these speeds
     33        up 8x with this change (object-int-add-array).
     34       
     35        * CMakeLists.txt:
     36        * JavaScriptCore.xcodeproj/project.pbxproj:
     37        * bytecode/CodeBlock.h:
     38        (JSC::CodeBlock::addFrequentExitSite):
     39        (JSC::CodeBlock::hasExitSite):
     40        * bytecode/DFGExitProfile.cpp:
     41        (JSC::DFG::FrequentExitSite::dump):
     42        (JSC::DFG::ExitProfile::ExitProfile):
     43        (JSC::DFG::ExitProfile::~ExitProfile):
     44        (JSC::DFG::ExitProfile::add):
     45        * bytecode/DFGExitProfile.h:
     46        (JSC::DFG::FrequentExitSite::isHashTableDeletedValue):
     47        * bytecode/MethodOfGettingAValueProfile.cpp:
     48        (JSC::MethodOfGettingAValueProfile::fromLazyOperand):
     49        (JSC::MethodOfGettingAValueProfile::emitReportValue):
     50        (JSC::MethodOfGettingAValueProfile::getSpecFailBucket): Deleted.
     51        * bytecode/MethodOfGettingAValueProfile.h:
     52        (JSC::MethodOfGettingAValueProfile::MethodOfGettingAValueProfile):
     53        (JSC::MethodOfGettingAValueProfile::operator bool):
     54        (JSC::MethodOfGettingAValueProfile::operator!): Deleted.
     55        * bytecode/PolymorphicAccess.cpp:
     56        (JSC::AccessCase::generateImpl):
     57        * bytecode/ValueProfile.cpp:
     58        (JSC::ResultProfile::emitDetectBitsLight):
     59        (JSC::ResultProfile::emitSetDouble):
     60        (JSC::ResultProfile::emitSetNonNumber):
     61        (WTF::printInternal):
     62        * bytecode/ValueProfile.h:
     63        (JSC::ResultProfile::ResultProfile):
     64        (JSC::ResultProfile::bytecodeOffset):
     65        (JSC::ResultProfile::specialFastPathCount):
     66        (JSC::ResultProfile::didObserveNonInt32):
     67        (JSC::ResultProfile::didObserveDouble):
     68        (JSC::ResultProfile::didObserveNonNegZeroDouble):
     69        (JSC::ResultProfile::didObserveNegZeroDouble):
     70        (JSC::ResultProfile::didObserveNonNumber):
     71        (JSC::ResultProfile::didObserveInt32Overflow):
     72        (JSC::ResultProfile::didObserveInt52Overflow):
     73        (JSC::ResultProfile::setObservedNonNegZeroDouble):
     74        (JSC::ResultProfile::setObservedNegZeroDouble):
     75        (JSC::ResultProfile::setObservedNonNumber):
     76        (JSC::ResultProfile::setObservedInt32Overflow):
     77        (JSC::ResultProfile::addressOfFlags):
     78        (JSC::ResultProfile::addressOfSpecialFastPathCount):
     79        (JSC::ResultProfile::detectBitsLight):
     80        (JSC::ResultProfile::hasBits):
     81        * dfg/DFGByteCodeParser.cpp:
     82        (JSC::DFG::ByteCodeParser::makeSafe):
     83        * dfg/DFGFixupPhase.cpp:
     84        (JSC::DFG::FixupPhase::fixupNode):
     85        * dfg/DFGGraph.cpp:
     86        (JSC::DFG::Graph::ensureNaturalLoops):
     87        (JSC::DFG::Graph::methodOfGettingAValueProfileFor):
     88        (JSC::DFG::Graph::valueProfileFor): Deleted.
     89        * dfg/DFGGraph.h:
     90        (JSC::DFG::Graph::hasExitSite):
     91        (JSC::DFG::Graph::numBlocks):
     92        * dfg/DFGNode.h:
     93        (JSC::DFG::Node::arithNodeFlags):
     94        (JSC::DFG::Node::mayHaveNonIntResult):
     95        (JSC::DFG::Node::mayHaveDoubleResult):
     96        (JSC::DFG::Node::mayHaveNonNumberResult):
     97        (JSC::DFG::Node::hasConstantBuffer):
     98        * dfg/DFGNodeFlags.cpp:
     99        (JSC::DFG::dumpNodeFlags):
     100        * dfg/DFGNodeFlags.h:
     101        * dfg/DFGOSRExitCompiler32_64.cpp:
     102        (JSC::DFG::OSRExitCompiler::compileExit):
     103        * dfg/DFGOSRExitCompiler64.cpp:
     104        (JSC::DFG::OSRExitCompiler::compileExit):
     105        * dfg/DFGOperations.cpp:
     106        * dfg/DFGOperations.h:
     107        * dfg/DFGPredictionPropagationPhase.cpp:
     108        * dfg/DFGSpeculativeJIT.h:
     109        (JSC::DFG::SpeculativeJIT::callOperation):
     110        * ftl/FTLOSRExitCompiler.cpp:
     111        (JSC::FTL::compileStub):
     112        * jit/AssemblyHelpers.h:
     113        (JSC::AssemblyHelpers::branchIfEqual):
     114        (JSC::AssemblyHelpers::branchIfNotCell):
     115        (JSC::AssemblyHelpers::branchIfNotNumber):
     116        (JSC::AssemblyHelpers::branchIfNotDoubleKnownNotInt32):
     117        (JSC::AssemblyHelpers::branchIfBoolean):
     118        (JSC::AssemblyHelpers::branchIfEmpty):
     119        (JSC::AssemblyHelpers::branchStructure):
     120        * jit/CCallHelpers.h:
     121        (JSC::CCallHelpers::CCallHelpers):
     122        (JSC::CCallHelpers::setupArguments):
     123        (JSC::CCallHelpers::setupArgumentsWithExecState):
     124        * jit/IntrinsicEmitter.cpp:
     125        (JSC::AccessCase::emitIntrinsicGetter):
     126        * jit/JIT.h:
     127        * jit/JITAddGenerator.cpp:
     128        (JSC::JITAddGenerator::generateFastPath):
     129        * jit/JITAddGenerator.h:
     130        (JSC::JITAddGenerator::JITAddGenerator):
     131        * jit/JITArithmetic.cpp:
     132        (JSC::JIT::emit_op_add):
     133        (JSC::JIT::emitSlow_op_add):
     134        (JSC::JIT::emit_op_div):
     135        (JSC::JIT::emit_op_mul):
     136        (JSC::JIT::emitSlow_op_mul):
     137        (JSC::JIT::emit_op_sub):
     138        (JSC::JIT::emitSlow_op_sub):
     139        * jit/JITInlines.h:
     140        (JSC::JIT::callOperation):
     141        (JSC::JIT::callOperationNoExceptionCheck):
     142        * jit/JITMulGenerator.cpp:
     143        (JSC::JITMulGenerator::generateFastPath):
     144        * jit/JITOperations.cpp:
     145        * jit/JITOperations.h:
     146        * jit/JITSubGenerator.cpp:
     147        (JSC::JITSubGenerator::generateFastPath):
     148        * jit/JITSubGenerator.h:
     149        (JSC::JITSubGenerator::JITSubGenerator):
     150        * jit/TagRegistersMode.cpp: Added.
     151        (WTF::printInternal):
     152        * jit/TagRegistersMode.h: Added.
     153        * runtime/CommonSlowPaths.cpp:
     154        (JSC::updateResultProfileForBinaryArithOp):
     155
    11562016-05-09  Keith Miller  <keith_miller@apple.com>
    2157
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r200568 r200606  
    19931993                DC2143071CA32E55000A8869 /* ICStats.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2143061CA32E52000A8869 /* ICStats.h */; };
    19941994                DC2143081CA32E58000A8869 /* ICStats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC2143051CA32E52000A8869 /* ICStats.cpp */; };
     1995                DC7997831CDE9FA0004D4A09 /* TagRegistersMode.h in Headers */ = {isa = PBXBuildFile; fileRef = DC7997821CDE9F9E004D4A09 /* TagRegistersMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1996                DC7997841CDE9FA2004D4A09 /* TagRegistersMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC7997811CDE9F9E004D4A09 /* TagRegistersMode.cpp */; };
    19951997                DCF3D5691CD2946D003D5C65 /* LazyClassStructure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCF3D5641CD29468003D5C65 /* LazyClassStructure.cpp */; };
    19961998                DCF3D56A1CD29470003D5C65 /* LazyClassStructure.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF3D5651CD29468003D5C65 /* LazyClassStructure.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    42054207                DC2143051CA32E52000A8869 /* ICStats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ICStats.cpp; sourceTree = "<group>"; };
    42064208                DC2143061CA32E52000A8869 /* ICStats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICStats.h; sourceTree = "<group>"; };
     4209                DC7997811CDE9F9E004D4A09 /* TagRegistersMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TagRegistersMode.cpp; sourceTree = "<group>"; };
     4210                DC7997821CDE9F9E004D4A09 /* TagRegistersMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TagRegistersMode.h; sourceTree = "<group>"; };
    42074211                DCF3D5641CD29468003D5C65 /* LazyClassStructure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LazyClassStructure.cpp; sourceTree = "<group>"; };
    42084212                DCF3D5651CD29468003D5C65 /* LazyClassStructure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyClassStructure.h; sourceTree = "<group>"; };
     
    50855089                                A7386551118697B400540279 /* SpecializedThunkJIT.h */,
    50865090                                A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */,
     5091                                DC7997811CDE9F9E004D4A09 /* TagRegistersMode.cpp */,
     5092                                DC7997821CDE9F9E004D4A09 /* TagRegistersMode.h */,
    50875093                                0FC314111814559100033232 /* TempRegisterSet.cpp */,
    50885094                                0F24E54817EE274900ABB217 /* TempRegisterSet.h */,
     
    78627868                                14CA958D16AB50FA00938A06 /* ObjectAllocationProfile.h in Headers */,
    78637869                                DCF3D56C1CD29475003D5C65 /* LazyProperty.h in Headers */,
     7870                                DC7997831CDE9FA0004D4A09 /* TagRegistersMode.h in Headers */,
    78647871                                BC18C4450E16F5CD00B34460 /* ObjectConstructor.h in Headers */,
    78657872                                996B73221BDA08EF00331B84 /* ObjectConstructor.lut.h in Headers */,
     
    90179024                                A57D23E51890CEBF0031C7FA /* InspectorDebuggerAgent.cpp in Sources */,
    90189025                                A532438918568335002ED692 /* InspectorFrontendDispatchers.cpp in Sources */,
     9026                                DC7997841CDE9FA2004D4A09 /* TagRegistersMode.cpp in Sources */,
    90199027                                99F1A6FE1B8E6D9400463B26 /* InspectorFrontendRouter.cpp in Sources */,
    90209028                                A5339EC71BB399A90054F005 /* InspectorHeapAgent.cpp in Sources */,
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r199394 r200606  
    501501        ASSERT(JITCode::isBaselineCode(jitType()));
    502502        ConcurrentJITLocker locker(m_lock);
    503         return m_exitProfile.add(locker, site);
     503        return m_exitProfile.add(locker, this, site);
    504504    }
    505505
  • trunk/Source/JavaScriptCore/bytecode/DFGExitProfile.cpp

    r185618 r200606  
    11/*
    2  * Copyright (C) 2011 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011, 2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2929#if ENABLE(DFG_JIT)
    3030
     31#include "CodeBlock.h"
     32
    3133namespace JSC { namespace DFG {
     34
     35void FrequentExitSite::dump(PrintStream& out) const
     36{
     37    out.print("bc#", m_bytecodeOffset, ": ", m_kind, "/", m_jitType);
     38}
    3239
    3340ExitProfile::ExitProfile() { }
    3441ExitProfile::~ExitProfile() { }
    3542
    36 bool ExitProfile::add(const ConcurrentJITLocker&, const FrequentExitSite& site)
     43bool ExitProfile::add(const ConcurrentJITLocker&, CodeBlock* owner, const FrequentExitSite& site)
    3744{
    3845    ASSERT(site.jitType() != ExitFromAnything);
     46
     47    if (Options::verboseExitProfile())
     48        dataLog(pointerDump(owner), ": Adding exit site: ", site, "\n");
    3949   
    4050    // If we've never seen any frequent exits then create the list and put this site
  • trunk/Source/JavaScriptCore/bytecode/DFGExitProfile.h

    r185618 r200606  
    11/*
    2  * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011-2014, 2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    117117        return m_kind == ExitKindUnset && m_bytecodeOffset;
    118118    }
     119   
     120    void dump(PrintStream& out) const;
    119121
    120122private:
     
    160162    // rare to begin with, and implies doing O(n) operations on the CodeBlock
    161163    // anyway.
    162     bool add(const ConcurrentJITLocker&, const FrequentExitSite&);
     164    bool add(const ConcurrentJITLocker&, CodeBlock* owner, const FrequentExitSite&);
    163165   
    164166    // Get the frequent exit sites for a bytecode index. This is O(n), and is
  • trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp

    r163844 r200606  
    11/*
    2  * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012, 2013, 2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2929#if ENABLE(DFG_JIT)
    3030
     31#include "CCallHelpers.h"
    3132#include "CodeBlock.h"
    3233#include "JSCInlines.h"
     
    4546}
    4647
    47 EncodedJSValue* MethodOfGettingAValueProfile::getSpecFailBucket(unsigned index) const
     48void MethodOfGettingAValueProfile::emitReportValue(CCallHelpers& jit, JSValueRegs regs) const
    4849{
    4950    switch (m_kind) {
    5051    case None:
    51         return 0;
     52        return;
    5253       
    5354    case Ready:
    54         return u.profile->specFailBucket(index);
     55        jit.storeValue(regs, u.profile->specFailBucket(0));
     56        return;
    5557       
    5658    case LazyOperand: {
     
    6062        LazyOperandValueProfile* profile =
    6163            u.lazyOperand.codeBlock->lazyOperandValueProfiles().add(locker, key);
    62         return profile->specFailBucket(index);
     64        jit.storeValue(regs, profile->specFailBucket(0));
     65        return;
    6366    }
    6467       
    65     default:
    66         RELEASE_ASSERT_NOT_REACHED();
    67         return 0;
    68     }
     68    case ResultProfileReady: {
     69        u.resultProfile->emitDetectNumericness(jit, regs, DoNotHaveTagRegisters);
     70        return;
     71    } }
     72   
     73    RELEASE_ASSERT_NOT_REACHED();
    6974}
    7075
  • trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h

    r164424 r200606  
    11/*
    2  * Copyright (C) 2012 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012, 2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3333#if ENABLE(DFG_JIT)
    3434
     35#include "GPRInfo.h"
    3536#include "JSCJSValue.h"
    3637
    3738namespace JSC {
    3839
     40class CCallHelpers;
    3941class CodeBlock;
    4042class LazyOperandValueProfileKey;
     43struct ResultProfile;
    4144struct ValueProfile;
    4245
     
    4851    }
    4952   
    50     explicit MethodOfGettingAValueProfile(ValueProfile* profile)
     53    MethodOfGettingAValueProfile(ValueProfile* profile)
    5154    {
    5255        if (profile) {
     
    5760    }
    5861   
     62    MethodOfGettingAValueProfile(ResultProfile* profile)
     63    {
     64        if (profile) {
     65            m_kind = ResultProfileReady;
     66            u.resultProfile = profile;
     67        } else
     68            m_kind = None;
     69    }
     70   
    5971    static MethodOfGettingAValueProfile fromLazyOperand(
    6072        CodeBlock*, const LazyOperandValueProfileKey&);
    6173   
    62     bool operator!() const { return m_kind == None; }
     74    explicit operator bool() const { return m_kind != None; }
    6375   
    64     // This logically has a pointer to a "There exists X such that
    65     // ValueProfileBase<X>". But since C++ does not have existential
    66     // templates, I cannot return it. So instead, for any methods that
    67     // users of this class would like to call, we'll just have to provide
    68     // a method here that does it through an indirection. Or we could
    69     // possibly just make ValueProfile less template-based. But last I
    70     // tried that, it felt more yucky than this class.
    71    
    72     EncodedJSValue* getSpecFailBucket(unsigned index) const;
     76    void emitReportValue(CCallHelpers&, JSValueRegs) const;
    7377   
    7478private:
     
    7680        None,
    7781        Ready,
     82        ResultProfileReady,
    7883        LazyOperand
    7984    };
     
    8287    union {
    8388        ValueProfile* profile;
     89        ResultProfile* resultProfile;
    8490        struct {
    8591            CodeBlock* codeBlock;
  • trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp

    r200405 r200606  
    11471147                dataLog("Have type: ", type->descriptor(), "\n");
    11481148            state.failAndRepatch.append(
    1149                 jit.branchIfNotType(
    1150                     valueRegs, scratchGPR, type->descriptor(), CCallHelpers::HaveTagRegisters));
     1149                jit.branchIfNotType(valueRegs, scratchGPR, type->descriptor()));
    11511150        } else if (verbose)
    11521151            dataLog("Don't have type.\n");
     
    11781177                dataLog("Have type: ", type->descriptor(), "\n");
    11791178            state.failAndRepatch.append(
    1180                 jit.branchIfNotType(
    1181                     valueRegs, scratchGPR, type->descriptor(), CCallHelpers::HaveTagRegisters));
     1179                jit.branchIfNotType(valueRegs, scratchGPR, type->descriptor()));
    11821180        } else if (verbose)
    11831181            dataLog("Don't have type.\n");
  • trunk/Source/JavaScriptCore/bytecode/ValueProfile.cpp

    r200502 r200606  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2727#include "ValueProfile.h"
    2828
     29#include "CCallHelpers.h"
     30#include "JSCInlines.h"
     31
     32namespace JSC {
     33
     34void ResultProfile::emitDetectNumericness(CCallHelpers& jit, JSValueRegs regs, TagRegistersMode mode)
     35{
     36    CCallHelpers::Jump isInt32 = jit.branchIfInt32(regs, mode);
     37    CCallHelpers::Jump notDouble = jit.branchIfNotDoubleKnownNotInt32(regs, mode);
     38    // FIXME: We could be more precise here.
     39    emitSetDouble(jit);
     40    CCallHelpers::Jump done = jit.jump();
     41    notDouble.link(&jit);
     42    emitSetNonNumber(jit);
     43    done.link(&jit);
     44    isInt32.link(&jit);
     45}
     46
     47void ResultProfile::emitSetDouble(CCallHelpers& jit)
     48{
     49    jit.or32(CCallHelpers::TrustedImm32(ResultProfile::Int32Overflow | ResultProfile::Int52Overflow | ResultProfile::NegZeroDouble | ResultProfile::NonNegZeroDouble), CCallHelpers::AbsoluteAddress(addressOfFlags()));
     50}
     51
     52void ResultProfile::emitSetNonNumber(CCallHelpers& jit)
     53{
     54    jit.or32(CCallHelpers::TrustedImm32(ResultProfile::NonNumber), CCallHelpers::AbsoluteAddress(addressOfFlags()));
     55}
     56
     57} // namespace JSC
     58
    2959namespace WTF {
    3060   
     
    3565    const char* separator = "";
    3666
    37     if (profile.didObserveNegZeroDouble()) {
    38         out.print(separator, "NegZeroDouble");
     67    if (!profile.didObserveNonInt32()) {
     68        out.print("Int32");
    3969        separator = "|";
     70    } else {
     71        if (profile.didObserveNegZeroDouble()) {
     72            out.print(separator, "NegZeroDouble");
     73            separator = "|";
     74        }
     75        if (profile.didObserveNonNegZeroDouble()) {
     76            out.print("NonNegZeroDouble");
     77            separator = "|";
     78        }
     79        if (profile.didObserveNonNumber()) {
     80            out.print("NonNumber");
     81            separator = "|";
     82        }
     83        if (profile.didObserveInt32Overflow()) {
     84            out.print("Int32Overflow");
     85            separator = "|";
     86        }
     87        if (profile.didObserveInt52Overflow()) {
     88            out.print("Int52Overflow");
     89            separator = "|";
     90        }
    4091    }
    41     if (profile.didObserveNonNumber()) {
    42         out.print("NonNumber");
    43         separator = "|";
    44     }
    45     if (profile.didObserveInt32Overflow()) {
    46         out.print("Int32Overflow");
    47         separator = "|";
    48     }
    49     if (profile.didObserveInt52Overflow()) {
    50         out.print("Int52Overflow");
    51         separator = "|";
    52     }
    53 
    5492    if (profile.specialFastPathCount()) {
    5593        out.print(" special fast path: ");
  • trunk/Source/JavaScriptCore/bytecode/ValueProfile.h

    r200502 r200606  
    11/*
    2  * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011-2013, 2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3535#include "SpeculatedType.h"
    3636#include "Structure.h"
     37#include "TagRegistersMode.h"
    3738#include "WriteBarrier.h"
    3839#include <wtf/PrintStream.h>
     
    4041
    4142namespace JSC {
     43
     44class CCallHelpers;
    4245
    4346template<unsigned numberOfBucketsArgument>
     
    219222
    220223    enum ObservedResults {
    221         NegZeroDouble    = 1 << 0,
    222         NonNumber        = 1 << 1,
    223         Int32Overflow    = 1 << 2,
    224         Int52Overflow    = 1 << 3,
     224        NonNegZeroDouble = 1 << 0,
     225        NegZeroDouble    = 1 << 1,
     226        NonNumber        = 1 << 2,
     227        Int32Overflow    = 1 << 3,
     228        Int52Overflow    = 1 << 4,
    225229    };
    226230
     
    228232    unsigned specialFastPathCount() const { return m_specialFastPathCount; }
    229233
     234    bool didObserveNonInt32() const { return hasBits(NonNegZeroDouble | NegZeroDouble | NonNumber); }
     235    bool didObserveDouble() const { return hasBits(NonNegZeroDouble | NegZeroDouble); }
     236    bool didObserveNonNegZeroDouble() const { return hasBits(NonNegZeroDouble); }
    230237    bool didObserveNegZeroDouble() const { return hasBits(NegZeroDouble); }
    231238    bool didObserveNonNumber() const { return hasBits(NonNumber); }
     
    233240    bool didObserveInt52Overflow() const { return hasBits(Int52Overflow); }
    234241
     242    void setObservedNonNegZeroDouble() { setBit(NonNegZeroDouble); }
    235243    void setObservedNegZeroDouble() { setBit(NegZeroDouble); }
    236244    void setObservedNonNumber() { setBit(NonNumber); }
     
    240248    void* addressOfFlags() { return &m_bytecodeOffsetAndFlags; }
    241249    void* addressOfSpecialFastPathCount() { return &m_specialFastPathCount; }
     250   
     251    // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble) if it sees a
     252    // double. Sets NonNumber if it sees a non-number.
     253    void emitDetectNumericness(CCallHelpers&, JSValueRegs, TagRegistersMode = HaveTagRegisters);
     254   
     255    void detectNumericness(JSValue value)
     256    {
     257        if (value.isInt32())
     258            return;
     259        if (value.isNumber()) {
     260            m_bytecodeOffsetAndFlags |= Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble;
     261            return;
     262        }
     263        m_bytecodeOffsetAndFlags |= NonNumber;
     264    }
     265   
     266    // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble).
     267    void emitSetDouble(CCallHelpers&);
     268   
     269    // Sets NonNumber.
     270    void emitSetNonNumber(CCallHelpers&);
    242271
    243272private:
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r200586 r200606  
    907907            return node;
    908908
    909         if (!m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex))
    910             return node;
    911        
    912         switch (node->op()) {
    913         case UInt32ToNumber:
    914         case ArithAdd:
    915         case ArithSub:
    916         case ValueAdd:
    917         case ArithMod: // for ArithMod "MayOverflow" means we tried to divide by zero, or we saw double.
    918             node->mergeFlags(NodeMayOverflowInt32InBaseline);
    919             break;
    920            
    921         case ArithNegate:
    922             // Currently we can't tell the difference between a negation overflowing
    923             // (i.e. -(1 << 31)) or generating negative zero (i.e. -0). If it took slow
    924             // path then we assume that it did both of those things.
    925             node->mergeFlags(NodeMayOverflowInt32InBaseline);
    926             node->mergeFlags(NodeMayNegZeroInBaseline);
    927             break;
    928 
    929         case ArithMul: {
    930             ResultProfile& resultProfile = *m_inlineStackTop->m_profiledBlock->resultProfileForBytecodeOffset(m_currentIndex);
    931             if (resultProfile.didObserveInt52Overflow())
    932                 node->mergeFlags(NodeMayOverflowInt52);
    933             if (resultProfile.didObserveInt32Overflow() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
     909        ResultProfile* resultProfile = m_inlineStackTop->m_profiledBlock->resultProfileForBytecodeOffset(m_currentIndex);
     910        if (resultProfile) {
     911            switch (node->op()) {
     912            case ArithAdd:
     913            case ArithSub:
     914            case ValueAdd:
     915                if (resultProfile->didObserveDouble())
     916                    node->mergeFlags(NodeMayHaveDoubleResult);
     917                if (resultProfile->didObserveNonNumber())
     918                    node->mergeFlags(NodeMayHaveNonNumberResult);
     919                break;
     920               
     921            case ArithMul: {
     922                if (resultProfile->didObserveInt52Overflow())
     923                    node->mergeFlags(NodeMayOverflowInt52);
     924                if (resultProfile->didObserveInt32Overflow() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
     925                    node->mergeFlags(NodeMayOverflowInt32InBaseline);
     926                if (resultProfile->didObserveNegZeroDouble() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
     927                    node->mergeFlags(NodeMayNegZeroInBaseline);
     928                if (resultProfile->didObserveDouble())
     929                    node->mergeFlags(NodeMayHaveDoubleResult);
     930                if (resultProfile->didObserveNonNumber())
     931                    node->mergeFlags(NodeMayHaveNonNumberResult);
     932                break;
     933            }
     934               
     935            default:
     936                break;
     937            }
     938        }
     939       
     940        if (m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)) {
     941            switch (node->op()) {
     942            case UInt32ToNumber:
     943            case ArithAdd:
     944            case ArithSub:
     945            case ValueAdd:
     946            case ArithMod: // for ArithMod "MayOverflow" means we tried to divide by zero, or we saw double.
    934947                node->mergeFlags(NodeMayOverflowInt32InBaseline);
    935             if (resultProfile.didObserveNegZeroDouble() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
     948                break;
     949               
     950            case ArithNegate:
     951                // Currently we can't tell the difference between a negation overflowing
     952                // (i.e. -(1 << 31)) or generating negative zero (i.e. -0). If it took slow
     953                // path then we assume that it did both of those things.
     954                node->mergeFlags(NodeMayOverflowInt32InBaseline);
    936955                node->mergeFlags(NodeMayNegZeroInBaseline);
    937             break;
    938         }
    939 
    940         default:
    941             RELEASE_ASSERT_NOT_REACHED();
    942             break;
     956                break;
     957               
     958            default:
     959                break;
     960            }
    943961        }
    944962       
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r200586 r200606  
    193193        case ArithSub: {
    194194            if (op == ArithSub
    195                 && Node::shouldSpeculateUntypedForArithmetic(node->child1().node(), node->child2().node())
    196                 && m_graph.hasExitSite(node->origin.semantic, BadType)) {
    197 
     195                && Node::shouldSpeculateUntypedForArithmetic(node->child1().node(), node->child2().node())) {
    198196                fixEdge<UntypedUse>(node->child1());
    199197                fixEdge<UntypedUse>(node->child2());
     
    237235            Edge& leftChild = node->child1();
    238236            Edge& rightChild = node->child2();
    239             if (Node::shouldSpeculateUntypedForArithmetic(leftChild.node(), rightChild.node())
    240                 && m_graph.hasExitSite(node->origin.semantic, BadType)) {
     237            if (Node::shouldSpeculateUntypedForArithmetic(leftChild.node(), rightChild.node())) {
    241238                fixEdge<UntypedUse>(leftChild);
    242239                fixEdge<UntypedUse>(rightChild);
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r200117 r200606  
    14471447}
    14481448
    1449 ValueProfile* Graph::valueProfileFor(Node* node)
    1450 {
    1451     if (!node)
    1452         return nullptr;
    1453        
    1454     CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic);
    1455        
    1456     if (node->hasLocal(*this)) {
    1457         if (!node->local().isArgument())
    1458             return nullptr;
    1459         int argument = node->local().toArgument();
    1460         Node* argumentNode = m_arguments[argument];
    1461         if (!argumentNode)
    1462             return nullptr;
    1463         if (node->variableAccessData() != argumentNode->variableAccessData())
    1464             return nullptr;
    1465         return profiledBlock->valueProfileForArgument(argument);
    1466     }
    1467        
    1468     if (node->hasHeapPrediction())
    1469         return profiledBlock->valueProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex);
    1470        
    1471     return nullptr;
    1472 }
    1473 
    14741449MethodOfGettingAValueProfile Graph::methodOfGettingAValueProfileFor(Node* node)
    14751450{
    1476     if (!node)
    1477         return MethodOfGettingAValueProfile();
    1478    
    1479     if (ValueProfile* valueProfile = valueProfileFor(node))
    1480         return MethodOfGettingAValueProfile(valueProfile);
    1481    
    1482     if (node->op() == GetLocal) {
     1451    while (node) {
    14831452        CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic);
    14841453       
    1485         return MethodOfGettingAValueProfile::fromLazyOperand(
    1486             profiledBlock,
    1487             LazyOperandValueProfileKey(
    1488                 node->origin.semantic.bytecodeIndex, node->local()));
     1454        if (node->hasLocal(*this)) {
     1455            ValueProfile* result = [&] () -> ValueProfile* {
     1456                if (!node->local().isArgument())
     1457                    return nullptr;
     1458                int argument = node->local().toArgument();
     1459                Node* argumentNode = m_arguments[argument];
     1460                if (!argumentNode)
     1461                    return nullptr;
     1462                if (node->variableAccessData() != argumentNode->variableAccessData())
     1463                    return nullptr;
     1464                return profiledBlock->valueProfileForArgument(argument);
     1465            }();
     1466            if (result)
     1467                return result;
     1468           
     1469            if (node->op() == GetLocal) {
     1470                return MethodOfGettingAValueProfile::fromLazyOperand(
     1471                    profiledBlock,
     1472                    LazyOperandValueProfileKey(
     1473                        node->origin.semantic.bytecodeIndex, node->local()));
     1474            }
     1475        }
     1476       
     1477        if (node->hasHeapPrediction())
     1478            return profiledBlock->valueProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex);
     1479       
     1480        if (ResultProfile* result = profiledBlock->resultProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex))
     1481            return result;
     1482       
     1483        switch (node->op()) {
     1484        case Identity:
     1485        case ValueRep:
     1486        case DoubleRep:
     1487        case Int52Rep:
     1488            node = node->child1().node();
     1489            break;
     1490        default:
     1491            node = nullptr;
     1492        }
    14891493    }
    14901494   
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r200117 r200606  
    401401    }
    402402   
    403     ValueProfile* valueProfileFor(Node*);
    404403    MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node*);
    405404   
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r200586 r200606  
    951951            return result;
    952952        return result & ~NodeBytecodeNeedsNegZero;
     953    }
     954
     955    bool mayHaveNonIntResult()
     956    {
     957        return m_flags & NodeMayHaveNonIntResult;
     958    }
     959   
     960    bool mayHaveDoubleResult()
     961    {
     962        return m_flags & NodeMayHaveDoubleResult;
     963    }
     964   
     965    bool mayHaveNonNumberResult()
     966    {
     967        return m_flags & NodeMayHaveNonNumberResult;
    953968    }
    954969
  • trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp

    r200502 r200606  
    8686    }
    8787
     88    if (flags & NodeMayHaveDoubleResult)
     89        out.print(comma, "MayHaveDoubleResult");
     90
     91    if (flags & NodeMayHaveNonNumberResult)
     92        out.print(comma, "MayHaveNonNumberResult");
     93
    8894    if (flags & NodeMayOverflowInt52)
    8995        out.print(comma, "MayOverflowInt52");
  • trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h

    r200502 r200606  
    4949   
    5050#define NodeBehaviorMask                 0x07e0
     51#define NodeMayHaveDoubleResult          0x0020
    5152#define NodeMayOverflowInt52             0x0040
    5253#define NodeMayOverflowInt32InBaseline   0x0080
     
    5455#define NodeMayNegZeroInBaseline         0x0200
    5556#define NodeMayNegZeroInDFG              0x0400
     57#define NodeMayHaveNonNumberResult       0x0800
     58#define NodeMayHaveNonIntResult          (NodeMayHaveDoubleResult | NodeMayHaveNonNumberResult)
    5659                               
    57 #define NodeBytecodeBackPropMask         0xf800
    58 #define NodeBytecodeUseBottom            0x0000
    59 #define NodeBytecodeUsesAsNumber         0x0800 // The result of this computation may be used in a context that observes fractional, or bigger-than-int32, results.
    60 #define NodeBytecodeNeedsNegZero         0x1000 // The result of this computation may be used in a context that observes -0.
    61 #define NodeBytecodeUsesAsOther          0x2000 // The result of this computation may be used in a context that distinguishes between NaN and other things (like undefined).
    62 #define NodeBytecodeUsesAsValue          (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther)
    63 #define NodeBytecodeUsesAsInt            0x4000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
    64 #define NodeBytecodeUsesAsArrayIndex     0x8000 // The result of this computation is known to be used in a context that strongly prefers integer values, to the point that we should avoid using doubles if at all possible.
     60#define NodeBytecodeBackPropMask        0x1f000
     61#define NodeBytecodeUseBottom           0x00000
     62#define NodeBytecodeUsesAsNumber        0x01000 // The result of this computation may be used in a context that observes fractional, or bigger-than-int32, results.
     63#define NodeBytecodeNeedsNegZero        0x02000 // The result of this computation may be used in a context that observes -0.
     64#define NodeBytecodeUsesAsOther         0x04000 // The result of this computation may be used in a context that distinguishes between NaN and other things (like undefined).
     65#define NodeBytecodeUsesAsValue         (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther)
     66#define NodeBytecodeUsesAsInt           0x08000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
     67#define NodeBytecodeUsesAsArrayIndex    0x10000 // The result of this computation is known to be used in a context that strongly prefers integer values, to the point that we should avoid using doubles if at all possible.
    6568
    6669#define NodeArithFlagsMask               (NodeBehaviorMask | NodeBytecodeBackPropMask)
    6770
    68 #define NodeIsFlushed                   0x10000 // Computed by CPSRethreadingPhase, will tell you which local nodes are backwards-reachable from a Flush.
     71#define NodeIsFlushed                   0x20000 // Computed by CPSRethreadingPhase, will tell you which local nodes are backwards-reachable from a Flush.
    6972
    70 #define NodeMiscFlag1                   0x20000
    71 #define NodeMiscFlag2                   0x40000
    72 #define NodeMiscFlag3                   0x80000
     73#define NodeMiscFlag1                   0x40000
     74#define NodeMiscFlag2                   0x80000
    7375
    7476typedef uint32_t NodeFlags;
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp

    r199792 r200606  
    11/*
    2  * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011, 2013-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    129129        }
    130130       
    131         if (!!exit.m_valueProfile) {
    132             EncodedJSValue* bucket = exit.m_valueProfile.getSpecFailBucket(0);
    133        
     131        if (MethodOfGettingAValueProfile profile = exit.m_valueProfile) {
    134132            if (exit.m_jsValueSource.isAddress()) {
    135133                // Save a register so we can use it.
    136                 GPRReg scratch = AssemblyHelpers::selectScratchGPR(exit.m_jsValueSource.base());
    137                
    138                 m_jit.push(scratch);
    139 
    140                 m_jit.load32(exit.m_jsValueSource.asAddress(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), scratch);
    141                 m_jit.store32(scratch, &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.tag);
    142                 m_jit.load32(exit.m_jsValueSource.asAddress(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), scratch);
    143                 m_jit.store32(scratch, &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.payload);
    144                
    145                 m_jit.pop(scratch);
     134                GPRReg scratchPayload = AssemblyHelpers::selectScratchGPR(exit.m_jsValueSource.base());
     135                GPRReg scratchTag = AssemblyHelpers::selectScratchGPR(exit.m_jsValueSource.base(), scratchPayload);
     136                m_jit.pushToSave(scratchPayload);
     137                m_jit.pushToSave(scratchTag);
     138
     139                JSValueRegs scratch(scratchTag, scratchPayload);
     140               
     141                m_jit.loadValue(exit.m_jsValueSource.asAddress(), scratch);
     142                profile.emitReportValue(m_jit, scratch);
     143               
     144                m_jit.popToRestore(scratchTag);
     145                m_jit.popToRestore(scratchPayload);
    146146            } else if (exit.m_jsValueSource.hasKnownTag()) {
    147                 m_jit.store32(AssemblyHelpers::TrustedImm32(exit.m_jsValueSource.tag()), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.tag);
    148                 m_jit.store32(exit.m_jsValueSource.payloadGPR(), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.payload);
    149             } else {
    150                 m_jit.store32(exit.m_jsValueSource.tagGPR(), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.tag);
    151                 m_jit.store32(exit.m_jsValueSource.payloadGPR(), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.payload);
    152             }
     147                GPRReg scratchTag = AssemblyHelpers::selectScratchGPR(exit.m_jsValueSource.payloadGPR());
     148                m_jit.pushToSave(scratchTag);
     149                m_jit.move(AssemblyHelpers::TrustedImm32(exit.m_jsValueSource.tag()), scratchTag);
     150                JSValueRegs value(scratchTag, exit.m_jsValueSource.payloadGPR());
     151                profile.emitReportValue(m_jit, value);
     152                m_jit.popToRestore(scratchTag);
     153            } else
     154                profile.emitReportValue(m_jit, exit.m_jsValueSource.regs());
    153155        }
    154156    }
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp

    r199792 r200606  
    11/*
    2  * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011, 2013-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    135135        }
    136136       
    137         if (!!exit.m_valueProfile) {
    138             EncodedJSValue* bucket = exit.m_valueProfile.getSpecFailBucket(0);
    139            
     137        if (MethodOfGettingAValueProfile profile = exit.m_valueProfile) {
    140138            if (exit.m_jsValueSource.isAddress()) {
    141139                // We can't be sure that we have a spare register. So use the tagTypeNumberRegister,
    142140                // since we know how to restore it.
    143141                m_jit.load64(AssemblyHelpers::Address(exit.m_jsValueSource.asAddress()), GPRInfo::tagTypeNumberRegister);
    144                 m_jit.store64(GPRInfo::tagTypeNumberRegister, bucket);
     142                profile.emitReportValue(m_jit, JSValueRegs(GPRInfo::tagTypeNumberRegister));
    145143                m_jit.move(AssemblyHelpers::TrustedImm64(TagTypeNumber), GPRInfo::tagTypeNumberRegister);
    146144            } else
    147                 m_jit.store64(exit.m_jsValueSource.gpr(), bucket);
     145                profile.emitReportValue(m_jit, JSValueRegs(exit.m_jsValueSource.gpr()));
    148146        }
    149147    }
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r200586 r200606  
    279279}
    280280
    281 EncodedJSValue JIT_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    282 {
    283     VM* vm = &exec->vm();
    284     NativeCallFrameTracer tracer(vm, exec);
    285    
    286     JSValue op1 = JSValue::decode(encodedOp1);
    287     JSValue op2 = JSValue::decode(encodedOp2);
    288    
    289     return JSValue::encode(jsAdd(exec, op1, op2));
    290 }
    291 
    292281EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    293282{
     
    317306    double b = op2.toNumber(exec);
    318307    return JSValue::encode(jsNumber(a / b));
    319 }
    320 
    321 EncodedJSValue JIT_OPERATION operationValueMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    322 {
    323     VM* vm = &exec->vm();
    324     NativeCallFrameTracer tracer(vm, exec);
    325 
    326     JSValue op1 = JSValue::decode(encodedOp1);
    327     JSValue op2 = JSValue::decode(encodedOp2);
    328 
    329     double a = op1.toNumber(exec);
    330     double b = op2.toNumber(exec);
    331     return JSValue::encode(jsNumber(a * b));
    332 }
    333 
    334 EncodedJSValue JIT_OPERATION operationValueSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    335 {
    336     VM* vm = &exec->vm();
    337     NativeCallFrameTracer tracer(vm, exec);
    338    
    339     JSValue op1 = JSValue::decode(encodedOp1);
    340     JSValue op2 = JSValue::decode(encodedOp2);
    341 
    342     double a = op1.toNumber(exec);
    343     double b = op2.toNumber(exec);
    344     return JSValue::encode(jsNumber(a - b));
    345308}
    346309
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r200586 r200606  
    5252EncodedJSValue JIT_OPERATION operationValueBitRShift(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
    5353EncodedJSValue JIT_OPERATION operationValueBitURShift(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
    54 EncodedJSValue JIT_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
    5554EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
    5655EncodedJSValue JIT_OPERATION operationValueDiv(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
    57 EncodedJSValue JIT_OPERATION operationValueMul(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
    58 EncodedJSValue JIT_OPERATION operationValueSub(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
    5956EncodedJSValue JIT_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL;
    6057EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r200586 r200606  
    192192                    else
    193193                        changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
    194                 } else if (
    195                     !(left & (SpecFullNumber | SpecBoolean))
    196                     || !(right & (SpecFullNumber | SpecBoolean))) {
     194                } else if (isStringOrStringObjectSpeculation(left) && isStringOrStringObjectSpeculation(right)) {
    197195                    // left or right is definitely something other than a number.
    198196                    changed |= mergePrediction(SpecString);
    199                 } else
    200                     changed |= mergePrediction(SpecString | SpecInt32Only | SpecBytecodeDouble);
     197                } else {
     198                    changed |= mergePrediction(SpecInt32Only);
     199                    if (node->mayHaveDoubleResult())
     200                        changed |= mergePrediction(SpecBytecodeDouble);
     201                    if (node->mayHaveNonNumberResult())
     202                        changed |= mergePrediction(SpecString);
     203                }
    201204            }
    202205            break;
     
    212215                else if (m_graph.addShouldSpeculateAnyInt(node))
    213216                    changed |= mergePrediction(SpecInt52Only);
     217                else if (isFullNumberOrBooleanSpeculation(left) && isFullNumberOrBooleanSpeculation(right))
     218                    changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
     219                else if (node->mayHaveNonIntResult() || (left & SpecBytecodeDouble) || (right & SpecBytecodeDouble))
     220                    changed |= mergePrediction(SpecInt32Only | SpecBytecodeDouble);
    214221                else
    215                     changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
     222                    changed |= mergePrediction(SpecInt32Only);
    216223            }
    217224            break;
     
    231238                    else
    232239                        changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
    233                 } else
     240                } else if (node->mayHaveNonIntResult() || (left & SpecBytecodeDouble) || (right & SpecBytecodeDouble))
    234241                    changed |= mergePrediction(SpecInt32Only | SpecBytecodeDouble);
     242                else
     243                    changed |= mergePrediction(SpecInt32Only);
    235244            }
    236245            break;
     
    268277           
    269278            if (left && right) {
     279                // FIXME: We're currently relying on prediction propagation and backwards propagation
     280                // whenever we can, and only falling back on result flags if that fails. And the result
     281                // flags logic doesn't know how to use backwards propagation. We should get rid of the
     282                // prediction propagation logic and rely solely on the result type.
    270283                if (isFullNumberOrBooleanSpeculationExpectingDefined(left)
    271284                    && isFullNumberOrBooleanSpeculationExpectingDefined(right)) {
     
    276289                    else
    277290                        changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
    278                 } else
    279                     changed |= mergePrediction(SpecInt32Only | SpecBytecodeDouble);
     291                } else {
     292                    if (node->mayHaveNonIntResult()
     293                        || (left & SpecBytecodeDouble)
     294                        || (right & SpecBytecodeDouble))
     295                        changed |= mergePrediction(SpecInt32Only | SpecBytecodeDouble);
     296                    else
     297                        changed |= mergePrediction(SpecInt32Only);
     298                }
    280299            }
    281300            break;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r200586 r200606  
    16881688#else // USE(JSVALUE32_64)
    16891689
    1690 // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned on an even-numbered register (r0, r2 or [sp]).
    1691 // To prevent the assembler from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary.
    1692 #if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS)
    1693 #define EABI_32BIT_DUMMY_ARG      TrustedImm32(0),
    1694 #else
    1695 #define EABI_32BIT_DUMMY_ARG
    1696 #endif
    1697 
    1698 // JSVALUE32_64 is a 64-bit integer that cannot be put half in an argument register and half on stack when using SH4 architecture.
    1699 // To avoid this, let's occupy the 4th argument register (r7) with a dummy argument when necessary. This must only be done when there
    1700 // is no other 32-bit value argument behind this 64-bit JSValue.
    1701 #if CPU(SH4)
    1702 #define SH4_32BIT_DUMMY_ARG      TrustedImm32(0),
    1703 #else
    1704 #define SH4_32BIT_DUMMY_ARG
    1705 #endif
    1706 
    17071690    JITCompiler::Call callOperation(J_JITOperation_EJJI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, UniquedStringImpl* uid)
    17081691    {
     
    21452128        return appendCall(operation);
    21462129    }
    2147 #undef EABI_32BIT_DUMMY_ARG
    2148 #undef SH4_32BIT_DUMMY_ARG
    21492130   
    21502131    template<typename FunctionType>
  • trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp

    r198364 r200606  
    11/*
    2  * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    285285        }
    286286
    287         if (!!exit.m_descriptor->m_valueProfile)
    288             jit.store64(GPRInfo::regT0, exit.m_descriptor->m_valueProfile.getSpecFailBucket(0));
     287        if (exit.m_descriptor->m_valueProfile)
     288            exit.m_descriptor->m_valueProfile.emitReportValue(jit, JSValueRegs(GPRInfo::regT0));
    289289    }
    290290
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h

    r199946 r200606  
    654654    }
    655655
    656     enum TagRegistersMode {
    657         DoNotHaveTagRegisters,
    658         HaveTagRegisters
    659     };
    660 
    661656    Jump branchIfNotCell(GPRReg reg, TagRegistersMode mode = HaveTagRegisters)
    662657    {
     
    781776        add32(TrustedImm32(1), regs.tagGPR(), tempGPR);
    782777        return branch32(AboveOrEqual, tempGPR, TrustedImm32(JSValue::LowestTag + 1));
     778#endif
     779    }
     780
     781    Jump branchIfNotDoubleKnownNotInt32(JSValueRegs regs, TagRegistersMode mode = HaveTagRegisters)
     782    {
     783#if USE(JSVALUE64)
     784        if (mode == HaveTagRegisters)
     785            return branchTest64(Zero, regs.gpr(), GPRInfo::tagTypeNumberRegister);
     786        return branchTest64(Zero, regs.gpr(), TrustedImm64(TagTypeNumber));
     787#else
     788        UNUSED_PARAM(mode);
     789        return branch32(AboveOrEqual, regs.tagGPR(), TrustedImm32(JSValue::LowestTag));
    783790#endif
    784791    }
     
    849856
    850857    JumpList branchIfNotType(
    851         JSValueRegs, GPRReg tempGPR, const InferredType::Descriptor&, TagRegistersMode);
     858        JSValueRegs, GPRReg tempGPR, const InferredType::Descriptor&,
     859        TagRegistersMode = HaveTagRegisters);
    852860
    853861    template<typename T>
  • trunk/Source/JavaScriptCore/jit/CCallHelpers.h

    r200586 r200606  
    4040#else
    4141#define POKE_ARGUMENT_OFFSET 0
     42#endif
     43
     44// EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]).
     45// To avoid assemblies from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary.
     46#if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS)
     47#define EABI_32BIT_DUMMY_ARG      TrustedImm32(0),
     48#else
     49#define EABI_32BIT_DUMMY_ARG
     50#endif
     51
     52// JSVALUE32_64 is a 64-bit integer that cannot be put half in an argument register and half on stack when using SH4 architecture.
     53// To avoid this, let's occupy the 4th argument register (r7) with a dummy argument when necessary. This must only be done when there
     54// is no other 32-bit value argument behind this 64-bit JSValue.
     55#if CPU(SH4)
     56#define SH4_32BIT_DUMMY_ARG      TrustedImm32(0),
     57#else
     58#define SH4_32BIT_DUMMY_ARG
    4259#endif
    4360
     
    21682185#endif
    21692186   
     2187    void setupArgumentsWithExecState(JSValueRegs arg1, JSValueRegs arg2, TrustedImmPtr arg3)
     2188    {
     2189#if USE(JSVALUE64)
     2190        setupArgumentsWithExecState(arg1.gpr(), arg2.gpr(), arg3);
     2191#else
     2192        setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1.payloadGPR(), arg1.tagGPR(), arg2.payloadGPR(), arg2.tagGPR(), arg3);
     2193#endif
     2194    }
     2195   
    21702196    void setupArguments(JSValueRegs arg1)
    21712197    {
  • trunk/Source/JavaScriptCore/jit/GPRInfo.h

    r200586 r200606  
    11/*
    2  * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011, 2013-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    140140    }
    141141   
     142    JSValueRegs regs() const
     143    {
     144        return JSValueRegs(gpr());
     145    }
     146   
    142147    MacroAssembler::Address asAddress() const { return MacroAssembler::Address(base(), offset()); }
    143148   
     
    305310    {
    306311        return static_cast<int32_t>(m_tagType);
     312    }
     313   
     314    JSValueRegs regs() const
     315    {
     316        return JSValueRegs(tagGPR(), payloadGPR());
    307317    }
    308318   
  • trunk/Source/JavaScriptCore/jit/IntrinsicEmitter.cpp

    r199303 r200606  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    7979    case TypedArrayLengthIntrinsic: {
    8080        jit.load32(MacroAssembler::Address(state.baseGPR, JSArrayBufferView::offsetOfLength()), valueGPR);
    81         jit.boxInt32(valueGPR, valueRegs, CCallHelpers::DoNotHaveTagRegisters);
     81        jit.boxInt32(valueGPR, valueRegs);
    8282        state.succeed();
    8383        return;
     
    9494        }
    9595
    96         jit.boxInt32(valueGPR, valueRegs, CCallHelpers::DoNotHaveTagRegisters);
     96        jit.boxInt32(valueGPR, valueRegs);
    9797        state.succeed();
    9898        return;
     
    120120        done.link(&jit);
    121121       
    122         jit.boxInt32(valueGPR, valueRegs, CCallHelpers::DoNotHaveTagRegisters);
     122        jit.boxInt32(valueGPR, valueRegs);
    123123        state.succeed();
    124124        return;
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r200586 r200606  
    757757        MacroAssembler::Call callOperation(J_JITOperation_EJI, int, GPRReg, UniquedStringImpl*);
    758758        MacroAssembler::Call callOperation(J_JITOperation_EJJ, int, GPRReg, GPRReg);
     759        MacroAssembler::Call callOperation(J_JITOperation_EJJRp, JSValueRegs, JSValueRegs, JSValueRegs, ResultProfile*);
    759760        MacroAssembler::Call callOperation(J_JITOperation_EJJAp, int, GPRReg, GPRReg, ArrayProfile*);
    760761        MacroAssembler::Call callOperation(J_JITOperation_EJJBy, int, GPRReg, GPRReg, ByValInfo*);
  • trunk/Source/JavaScriptCore/jit/JITAddGenerator.cpp

    r192842 r200606  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    129129    // Do doubleVar + doubleVar.
    130130    jit.addDouble(m_rightFPR, m_leftFPR);
     131    if (m_resultProfile)
     132        m_resultProfile->emitSetDouble(jit);
     133       
    131134    jit.boxDouble(m_leftFPR, m_result);
    132135}
  • trunk/Source/JavaScriptCore/jit/JITAddGenerator.h

    r192842 r200606  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3838    JITAddGenerator(SnippetOperand leftOperand, SnippetOperand rightOperand,
    3939        JSValueRegs result, JSValueRegs left, JSValueRegs right,
    40         FPRReg leftFPR, FPRReg rightFPR, GPRReg scratchGPR, FPRReg scratchFPR)
     40        FPRReg leftFPR, FPRReg rightFPR, GPRReg scratchGPR, FPRReg scratchFPR,
     41        ResultProfile* resultProfile = nullptr)
    4142        : m_leftOperand(leftOperand)
    4243        , m_rightOperand(rightOperand)
     
    4849        , m_scratchGPR(scratchGPR)
    4950        , m_scratchFPR(scratchFPR)
     51        , m_resultProfile(resultProfile)
    5052    {
    5153        ASSERT(!m_leftOperand.isConstInt32() || !m_rightOperand.isConstInt32());
     
    6870    GPRReg m_scratchGPR;
    6971    FPRReg m_scratchFPR;
     72    ResultProfile* m_resultProfile;
    7073    bool m_didEmitFastPath { false };
    7174
  • trunk/Source/JavaScriptCore/jit/JITArithmetic.cpp

    r198364 r200606  
    11/*
    2  * Copyright (C) 2008, 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    697697#endif
    698698
     699    ResultProfile* resultProfile = nullptr;
     700    if (shouldEmitProfiling())
     701        resultProfile = m_codeBlock->ensureResultProfile(m_bytecodeOffset);
     702
    699703    SnippetOperand leftOperand(types.first());
    700704    SnippetOperand rightOperand(types.second());
     
    713717
    714718    JITAddGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
    715         fpRegT0, fpRegT1, scratchGPR, scratchFPR);
     719        fpRegT0, fpRegT1, scratchGPR, scratchFPR, resultProfile);
    716720
    717721    gen.generateFastPath(*this);
     
    725729        ASSERT(gen.endJumpList().empty());
    726730        ASSERT(gen.slowPathJumpList().empty());
     731        if (resultProfile) {
     732            if (leftOperand.isConst())
     733                emitGetVirtualRegister(op1, leftRegs);
     734            if (rightOperand.isConst())
     735                emitGetVirtualRegister(op2, rightRegs);
     736            callOperation(operationValueAddProfiled, resultRegs, leftRegs, rightRegs, resultProfile);
     737            emitPutVirtualRegister(result, resultRegs);
     738        } else {
     739            JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_add);
     740            slowPathCall.call();
     741        }
     742    }
     743}
     744
     745void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     746{
     747    linkAllSlowCasesForBytecodeOffset(m_slowCases, iter, m_bytecodeOffset);
     748
     749    int result = currentInstruction[1].u.operand;
     750    int op1 = currentInstruction[2].u.operand;
     751    int op2 = currentInstruction[3].u.operand;
     752    OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
     753
     754#if USE(JSVALUE64)
     755    JSValueRegs leftRegs = JSValueRegs(regT0);
     756    JSValueRegs rightRegs = JSValueRegs(regT1);
     757    JSValueRegs resultRegs = leftRegs;
     758#else
     759    JSValueRegs leftRegs = JSValueRegs(regT1, regT0);
     760    JSValueRegs rightRegs = JSValueRegs(regT3, regT2);
     761    JSValueRegs resultRegs = leftRegs;
     762#endif
     763   
     764    SnippetOperand leftOperand(types.first());
     765    SnippetOperand rightOperand(types.second());
     766
     767    if (isOperandConstantInt(op1))
     768        leftOperand.setConstInt32(getOperandConstantInt(op1));
     769    else if (isOperandConstantInt(op2))
     770        rightOperand.setConstInt32(getOperandConstantInt(op2));
     771
     772    if (shouldEmitProfiling()) {
     773        if (leftOperand.isConst())
     774            emitGetVirtualRegister(op1, leftRegs);
     775        if (rightOperand.isConst())
     776            emitGetVirtualRegister(op2, rightRegs);
     777        ResultProfile* resultProfile = m_codeBlock->ensureResultProfile(m_bytecodeOffset);
     778        callOperation(operationValueAddProfiled, resultRegs, leftRegs, rightRegs, resultProfile);
     779        emitPutVirtualRegister(result, resultRegs);
     780    } else {
    727781        JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_add);
    728782        slowPathCall.call();
    729783    }
    730 }
    731 
    732 void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    733 {
    734     linkAllSlowCasesForBytecodeOffset(m_slowCases, iter, m_bytecodeOffset);
    735 
    736     JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_add);
    737     slowPathCall.call();
    738784}
    739785
     
    865911        ASSERT(gen.endJumpList().empty());
    866912        ASSERT(gen.slowPathJumpList().empty());
     913        if (resultProfile) {
     914            if (leftOperand.isPositiveConstInt32())
     915                emitGetVirtualRegister(op1, leftRegs);
     916            if (rightOperand.isPositiveConstInt32())
     917                emitGetVirtualRegister(op2, rightRegs);
     918            callOperation(operationValueMulProfiled, resultRegs, leftRegs, rightRegs, resultProfile);
     919            emitPutVirtualRegister(result, resultRegs);
     920        } else {
     921            JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_mul);
     922            slowPathCall.call();
     923        }
     924    }
     925}
     926
     927void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     928{
     929    linkAllSlowCasesForBytecodeOffset(m_slowCases, iter, m_bytecodeOffset);
     930   
     931    int result = currentInstruction[1].u.operand;
     932    int op1 = currentInstruction[2].u.operand;
     933    int op2 = currentInstruction[3].u.operand;
     934    OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
     935
     936#if USE(JSVALUE64)
     937    JSValueRegs leftRegs = JSValueRegs(regT0);
     938    JSValueRegs rightRegs = JSValueRegs(regT1);
     939    JSValueRegs resultRegs = leftRegs;
     940#else
     941    JSValueRegs leftRegs = JSValueRegs(regT1, regT0);
     942    JSValueRegs rightRegs = JSValueRegs(regT3, regT2);
     943    JSValueRegs resultRegs = leftRegs;
     944#endif
     945
     946    SnippetOperand leftOperand(types.first());
     947    SnippetOperand rightOperand(types.second());
     948
     949    if (isOperandConstantInt(op1))
     950        leftOperand.setConstInt32(getOperandConstantInt(op1));
     951    else if (isOperandConstantInt(op2))
     952        rightOperand.setConstInt32(getOperandConstantInt(op2));
     953
     954    if (shouldEmitProfiling()) {
     955        if (leftOperand.isPositiveConstInt32())
     956            emitGetVirtualRegister(op1, leftRegs);
     957        if (rightOperand.isPositiveConstInt32())
     958            emitGetVirtualRegister(op2, rightRegs);
     959        ResultProfile* resultProfile = m_codeBlock->ensureResultProfile(m_bytecodeOffset);
     960        callOperation(operationValueMulProfiled, resultRegs, leftRegs, rightRegs, resultProfile);
     961        emitPutVirtualRegister(result, resultRegs);
     962    } else {
    867963        JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_mul);
    868964        slowPathCall.call();
    869965    }
    870 }
    871 
    872 void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    873 {
    874     linkAllSlowCasesForBytecodeOffset(m_slowCases, iter, m_bytecodeOffset);
    875    
    876     JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_mul);
    877     slowPathCall.call();
    878966}
    879967
     
    899987#endif
    900988
     989    ResultProfile* resultProfile = nullptr;
     990    if (shouldEmitProfiling())
     991        resultProfile = m_codeBlock->ensureResultProfile(m_bytecodeOffset);
     992
    901993    SnippetOperand leftOperand(types.first());
    902994    SnippetOperand rightOperand(types.second());
     
    906998
    907999    JITSubGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
    908         fpRegT0, fpRegT1, scratchGPR, scratchFPR);
     1000        fpRegT0, fpRegT1, scratchGPR, scratchFPR, resultProfile);
    9091001
    9101002    gen.generateFastPath(*this);
     
    9211013    linkAllSlowCasesForBytecodeOffset(m_slowCases, iter, m_bytecodeOffset);
    9221014
    923     JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_sub);
    924     slowPathCall.call();
     1015    int result = currentInstruction[1].u.operand;
     1016#if USE(JSVALUE64)
     1017    JSValueRegs leftRegs = JSValueRegs(regT0);
     1018    JSValueRegs rightRegs = JSValueRegs(regT1);
     1019    JSValueRegs resultRegs = leftRegs;
     1020#else
     1021    JSValueRegs leftRegs = JSValueRegs(regT1, regT0);
     1022    JSValueRegs rightRegs = JSValueRegs(regT3, regT2);
     1023    JSValueRegs resultRegs = leftRegs;
     1024#endif
     1025
     1026    if (shouldEmitProfiling()) {
     1027        ResultProfile* resultProfile = m_codeBlock->ensureResultProfile(m_bytecodeOffset);
     1028        callOperation(operationValueSubProfiled, resultRegs, leftRegs, rightRegs, resultProfile);
     1029        emitPutVirtualRegister(result, resultRegs);
     1030    } else {
     1031        JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_sub);
     1032        slowPathCall.call();
     1033    }
    9251034}
    9261035
  • trunk/Source/JavaScriptCore/jit/JITInlines.h

    r199710 r200606  
    417417}
    418418
     419inline MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJRp operation, JSValueRegs result, JSValueRegs arg1, JSValueRegs arg2, ResultProfile* resultProfile)
     420{
     421    setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(resultProfile));
     422    Call call = appendCallWithExceptionCheck(operation);
     423    setupResults(result);
     424    return call;
     425}
     426
    419427#if USE(JSVALUE64)
    420428ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(Z_JITOperation_EJZZ operation, GPRReg arg1, int32_t arg2, int32_t arg3)
     
    603611#else // USE(JSVALUE32_64)
    604612
    605 // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]).
    606 // To avoid assemblies from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary.
    607 #if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS)
    608 #define EABI_32BIT_DUMMY_ARG      TrustedImm32(0),
    609 #else
    610 #define EABI_32BIT_DUMMY_ARG
    611 #endif
    612 
    613 // JSVALUE32_64 is a 64-bit integer that cannot be put half in an argument register and half on stack when using SH4 architecture.
    614 // To avoid this, let's occupy the 4th argument register (r7) with a dummy argument when necessary. This must only be done when there
    615 // is no other 32-bit value argument behind this 64-bit JSValue.
    616 #if CPU(SH4)
    617 #define SH4_32BIT_DUMMY_ARG      TrustedImm32(0),
    618 #else
    619 #define SH4_32BIT_DUMMY_ARG
    620 #endif
    621 
    622613ALWAYS_INLINE MacroAssembler::Call JIT::callOperationNoExceptionCheck(V_JITOperation_EJ operation, GPRReg arg1Tag, GPRReg arg1Payload)
    623614{
     
    800791    return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
    801792}
    802 
    803 #undef EABI_32BIT_DUMMY_ARG
    804 #undef SH4_32BIT_DUMMY_ARG
    805793
    806794#endif // USE(JSVALUE32_64)
  • trunk/Source/JavaScriptCore/jit/JITMulGenerator.cpp

    r200502 r200606  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    154154
    155155        notNegativeZero.link(&jit);
     156        jit.or32(CCallHelpers::TrustedImm32(ResultProfile::NonNegZeroDouble), CCallHelpers::AbsoluteAddress(m_resultProfile->addressOfFlags()));
    156157
    157158        jit.move(m_result.payloadGPR(), m_scratchGPR);
     
    175176
    176177        notNegativeZero.link(&jit);
     178        jit.or32(CCallHelpers::TrustedImm32(ResultProfile::NonNegZeroDouble), CCallHelpers::AbsoluteAddress(m_resultProfile->addressOfFlags()));
    177179
    178180        jit.move(m_result.tagGPR(), m_scratchGPR);
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r200459 r200606  
    22442244}
    22452245
     2246EncodedJSValue JIT_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
     2247{
     2248    VM* vm = &exec->vm();
     2249    NativeCallFrameTracer tracer(vm, exec);
     2250   
     2251    JSValue op1 = JSValue::decode(encodedOp1);
     2252    JSValue op2 = JSValue::decode(encodedOp2);
     2253   
     2254    return JSValue::encode(jsAdd(exec, op1, op2));
     2255}
     2256
     2257EncodedJSValue JIT_OPERATION operationValueAddProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ResultProfile* resultProfile)
     2258{
     2259    VM* vm = &exec->vm();
     2260    NativeCallFrameTracer tracer(vm, exec);
     2261   
     2262    JSValue op1 = JSValue::decode(encodedOp1);
     2263    JSValue op2 = JSValue::decode(encodedOp2);
     2264   
     2265    JSValue result = jsAdd(exec, op1, op2);
     2266    resultProfile->detectNumericness(result);
     2267    return JSValue::encode(result);
     2268}
     2269
     2270EncodedJSValue JIT_OPERATION operationValueMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
     2271{
     2272    VM* vm = &exec->vm();
     2273    NativeCallFrameTracer tracer(vm, exec);
     2274
     2275    JSValue op1 = JSValue::decode(encodedOp1);
     2276    JSValue op2 = JSValue::decode(encodedOp2);
     2277
     2278    double a = op1.toNumber(exec);
     2279    double b = op2.toNumber(exec);
     2280    return JSValue::encode(jsNumber(a * b));
     2281}
     2282
     2283EncodedJSValue JIT_OPERATION operationValueMulProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ResultProfile* resultProfile)
     2284{
     2285    VM* vm = &exec->vm();
     2286    NativeCallFrameTracer tracer(vm, exec);
     2287
     2288    JSValue op1 = JSValue::decode(encodedOp1);
     2289    JSValue op2 = JSValue::decode(encodedOp2);
     2290
     2291    double a = op1.toNumber(exec);
     2292    double b = op2.toNumber(exec);
     2293   
     2294    JSValue result = jsNumber(a * b);
     2295    resultProfile->detectNumericness(result);
     2296    return JSValue::encode(result);
     2297}
     2298
     2299EncodedJSValue JIT_OPERATION operationValueSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
     2300{
     2301    VM* vm = &exec->vm();
     2302    NativeCallFrameTracer tracer(vm, exec);
     2303   
     2304    JSValue op1 = JSValue::decode(encodedOp1);
     2305    JSValue op2 = JSValue::decode(encodedOp2);
     2306
     2307    double a = op1.toNumber(exec);
     2308    double b = op2.toNumber(exec);
     2309    return JSValue::encode(jsNumber(a - b));
     2310}
     2311
     2312EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ResultProfile* resultProfile)
     2313{
     2314    VM* vm = &exec->vm();
     2315    NativeCallFrameTracer tracer(vm, exec);
     2316   
     2317    JSValue op1 = JSValue::decode(encodedOp1);
     2318    JSValue op2 = JSValue::decode(encodedOp2);
     2319
     2320    double a = op1.toNumber(exec);
     2321    double b = op2.toNumber(exec);
     2322   
     2323    JSValue result = jsNumber(a - b);
     2324    resultProfile->detectNumericness(result);
     2325    return JSValue::encode(result);
     2326}
     2327
    22462328void JIT_OPERATION operationProcessTypeProfilerLog(ExecState* exec)
    22472329{
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r200586 r200606  
    5454struct ByValInfo;
    5555struct InlineCallFrame;
     56struct ResultProfile;
    5657
    5758typedef ExecState CallFrame;
     
    9798    R: Register
    9899    Reo: RegExpObject*
     100    Rp: ResultProfile*
    99101    S: size_t
    100102    Sprt: SlowPathReturnType
     
    137139typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJBy)(ExecState*, EncodedJSValue, EncodedJSValue, ByValInfo*);
    138140typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
     141typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJRp)(ExecState*, EncodedJSValue, EncodedJSValue, ResultProfile*);
    139142typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJssZ)(ExecState*, JSString*, int32_t);
    140143typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJssReo)(ExecState*, JSString*, RegExpObject*);
     
    410413JSCell* JIT_OPERATION operationToIndexString(ExecState*, int32_t);
    411414
     415EncodedJSValue JIT_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
     416EncodedJSValue JIT_OPERATION operationValueAddProfiled(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ResultProfile*) WTF_INTERNAL;
     417EncodedJSValue JIT_OPERATION operationValueMul(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
     418EncodedJSValue JIT_OPERATION operationValueMulProfiled(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ResultProfile*) WTF_INTERNAL;
     419EncodedJSValue JIT_OPERATION operationValueSub(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
     420EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ResultProfile*) WTF_INTERNAL;
     421
    412422void JIT_OPERATION operationProcessTypeProfilerLog(ExecState*) WTF_INTERNAL;
    413423void JIT_OPERATION operationProcessShadowChickenLog(ExecState*) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/jit/JITSubGenerator.cpp

    r192842 r200606  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    8484
    8585    jit.subDouble(m_rightFPR, m_leftFPR);
     86    if (m_resultProfile)
     87        m_resultProfile->emitSetDouble(jit);
     88
    8689    jit.boxDouble(m_leftFPR, m_result);
    8790}
  • trunk/Source/JavaScriptCore/jit/JITSubGenerator.h

    r192842 r200606  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3838    JITSubGenerator(SnippetOperand leftOperand, SnippetOperand rightOperand,
    3939        JSValueRegs result, JSValueRegs left, JSValueRegs right,
    40         FPRReg leftFPR, FPRReg rightFPR, GPRReg scratchGPR, FPRReg scratchFPR)
     40        FPRReg leftFPR, FPRReg rightFPR, GPRReg scratchGPR, FPRReg scratchFPR,
     41        ResultProfile* resultProfile = nullptr)
    4142        : m_leftOperand(leftOperand)
    4243        , m_rightOperand(rightOperand)
     
    4849        , m_scratchGPR(scratchGPR)
    4950        , m_scratchFPR(scratchFPR)
     51        , m_resultProfile(resultProfile)
    5052    { }
    5153
     
    6668    GPRReg m_scratchGPR;
    6769    FPRReg m_scratchFPR;
     70    ResultProfile* m_resultProfile;
    6871    bool m_didEmitFastPath { false };
    6972
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r200586 r200606  
    379379                profile->setObservedNegZeroDouble();
    380380            else {
     381                profile->setObservedNonNegZeroDouble();
     382
    381383                // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value.
    382384                // Therefore, we will get a false positive if the result is that value. This is intentionally
  • trunk/Source/JavaScriptCore/runtime/Options.h

    r200543 r200606  
    176176    v(bool, reportFTLCompileTimes, false, Normal, "dumps JS function signature and the time it took to FTL compile") \
    177177    v(bool, reportTotalCompileTimes, false, Normal, nullptr) \
     178    v(bool, verboseExitProfile, false, Normal, nullptr) \
    178179    v(bool, verboseCFA, false, Normal, nullptr) \
    179180    v(bool, verboseFTLToJSThunk, false, Normal, nullptr) \
Note: See TracChangeset for help on using the changeset viewer.