Make the type profiler work with lexical scoping and add tests
authorsaambarati1@gmail.com <saambarati1@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Jul 2015 22:39:12 +0000 (22:39 +0000)
committersaambarati1@gmail.com <saambarati1@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Jul 2015 22:39:12 +0000 (22:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=145438

Reviewed by Geoffrey Garen.

op_profile_type now knows how to resolve variables allocated within
the local scope stack. This means it knows how to resolve "let"
and "const" variables. Also, some refactoring was done inside
the BytecodeGenerator to make writing code to support the type
profiler much simpler and clearer.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::symbolTable): Deleted.
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::addExceptionHandler):
(JSC::UnlinkedCodeBlock::exceptionHandler):
(JSC::UnlinkedCodeBlock::vm):
(JSC::UnlinkedCodeBlock::addArrayProfile):
(JSC::UnlinkedCodeBlock::setSymbolTableConstantIndex): Deleted.
(JSC::UnlinkedCodeBlock::symbolTableConstantIndex): Deleted.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitMove):
(JSC::BytecodeGenerator::emitTypeProfilerExpressionInfo):
(JSC::BytecodeGenerator::emitProfileType):
(JSC::BytecodeGenerator::emitProfileControlFlow):
(JSC::BytecodeGenerator::pushLexicalScopeInternal):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::emitNodeForLeftHandSide):
* bytecompiler/NodesCodegen.cpp:
(JSC::ThisNode::emitBytecode):
(JSC::ResolveNode::emitBytecode):
(JSC::BracketAccessorNode::emitBytecode):
(JSC::DotAccessorNode::emitBytecode):
(JSC::FunctionCallValueNode::emitBytecode):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::FunctionCallBracketNode::emitBytecode):
(JSC::FunctionCallDotNode::emitBytecode):
(JSC::CallFunctionCallDotNode::emitBytecode):
(JSC::ApplyFunctionCallDotNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::PostfixNode::emitBracket):
(JSC::PostfixNode::emitDot):
(JSC::PrefixNode::emitResolve):
(JSC::PrefixNode::emitBracket):
(JSC::PrefixNode::emitDot):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::AssignDotNode::emitBytecode):
(JSC::ReadModifyDotNode::emitBytecode):
(JSC::AssignBracketNode::emitBytecode):
(JSC::ReadModifyBracketNode::emitBytecode):
(JSC::EmptyVarExpression::emitBytecode):
(JSC::EmptyLetExpression::emitBytecode):
(JSC::ForInNode::emitLoopHeader):
(JSC::ForOfNode::emitBytecode):
(JSC::ReturnNode::emitBytecode):
(JSC::FunctionNode::emitBytecode):
(JSC::BindingNode::bindValue):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_profile_type):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_profile_type):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* tests/typeProfiler/es6-block-scoping.js: Added.
(noop):
(arr):
(wrapper.changeFoo):
(wrapper.scoping):
(wrapper.scoping2):
(wrapper):
* tests/typeProfiler/es6-classes.js: Added.
(noop):
(wrapper.Animal):
(wrapper.Animal.prototype.methodA):
(wrapper.Dog):
(wrapper.Dog.prototype.methodB):
(wrapper):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@187524 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/tests/typeProfiler/es6-block-scoping.js [new file with mode: 0644]
Source/JavaScriptCore/tests/typeProfiler/es6-classes.js [new file with mode: 0644]

index c1a0597..0a4dd31 100644 (file)
@@ -1,5 +1,93 @@
 2015-07-28  Saam barati  <saambarati1@gmail.com>
 
+        Make the type profiler work with lexical scoping and add tests
+        https://bugs.webkit.org/show_bug.cgi?id=145438
+
+        Reviewed by Geoffrey Garen.
+
+        op_profile_type now knows how to resolve variables allocated within
+        the local scope stack. This means it knows how to resolve "let"
+        and "const" variables. Also, some refactoring was done inside
+        the BytecodeGenerator to make writing code to support the type
+        profiler much simpler and clearer.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::CodeBlock):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::symbolTable): Deleted.
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::addExceptionHandler):
+        (JSC::UnlinkedCodeBlock::exceptionHandler):
+        (JSC::UnlinkedCodeBlock::vm):
+        (JSC::UnlinkedCodeBlock::addArrayProfile):
+        (JSC::UnlinkedCodeBlock::setSymbolTableConstantIndex): Deleted.
+        (JSC::UnlinkedCodeBlock::symbolTableConstantIndex): Deleted.
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::emitMove):
+        (JSC::BytecodeGenerator::emitTypeProfilerExpressionInfo):
+        (JSC::BytecodeGenerator::emitProfileType):
+        (JSC::BytecodeGenerator::emitProfileControlFlow):
+        (JSC::BytecodeGenerator::pushLexicalScopeInternal):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::emitNodeForLeftHandSide):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ThisNode::emitBytecode):
+        (JSC::ResolveNode::emitBytecode):
+        (JSC::BracketAccessorNode::emitBytecode):
+        (JSC::DotAccessorNode::emitBytecode):
+        (JSC::FunctionCallValueNode::emitBytecode):
+        (JSC::FunctionCallResolveNode::emitBytecode):
+        (JSC::FunctionCallBracketNode::emitBytecode):
+        (JSC::FunctionCallDotNode::emitBytecode):
+        (JSC::CallFunctionCallDotNode::emitBytecode):
+        (JSC::ApplyFunctionCallDotNode::emitBytecode):
+        (JSC::PostfixNode::emitResolve):
+        (JSC::PostfixNode::emitBracket):
+        (JSC::PostfixNode::emitDot):
+        (JSC::PrefixNode::emitResolve):
+        (JSC::PrefixNode::emitBracket):
+        (JSC::PrefixNode::emitDot):
+        (JSC::ReadModifyResolveNode::emitBytecode):
+        (JSC::AssignResolveNode::emitBytecode):
+        (JSC::AssignDotNode::emitBytecode):
+        (JSC::ReadModifyDotNode::emitBytecode):
+        (JSC::AssignBracketNode::emitBytecode):
+        (JSC::ReadModifyBracketNode::emitBytecode):
+        (JSC::EmptyVarExpression::emitBytecode):
+        (JSC::EmptyLetExpression::emitBytecode):
+        (JSC::ForInNode::emitLoopHeader):
+        (JSC::ForOfNode::emitBytecode):
+        (JSC::ReturnNode::emitBytecode):
+        (JSC::FunctionNode::emitBytecode):
+        (JSC::BindingNode::bindValue):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_profile_type):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_profile_type):
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * tests/typeProfiler/es6-block-scoping.js: Added.
+        (noop):
+        (arr):
+        (wrapper.changeFoo):
+        (wrapper.scoping):
+        (wrapper.scoping2):
+        (wrapper):
+        * tests/typeProfiler/es6-classes.js: Added.
+        (noop):
+        (wrapper.Animal):
+        (wrapper.Animal.prototype.methodA):
+        (wrapper.Dog):
+        (wrapper.Dog.prototype.methodB):
+        (wrapper):
+
+2015-07-28  Saam barati  <saambarati1@gmail.com>
+
         Implement catch scope using lexical scoping constructs introduced with "let" scoping patch
         https://bugs.webkit.org/show_bug.cgi?id=146979
 
index 8668394..0230927 100644 (file)
@@ -1694,8 +1694,6 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
     ASSERT(m_heap->isDeferred());
     ASSERT(m_scopeRegister.isLocal());
 
-    m_symbolTableConstantIndex = other.m_symbolTableConstantIndex;
-
     setNumParameters(other.numParameters());
     optimizeAfterWarmUp();
     jitAfterWarmUp();
@@ -1767,7 +1765,6 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
     }
 
     HashSet<int, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>> clonedConstantSymbolTables;
-    m_symbolTableConstantIndex = unlinkedCodeBlock->symbolTableConstantIndex();
     {
         HashSet<SymbolTable*> clonedSymbolTables;
         for (unsigned i = 0; i < m_constantRegisters.size(); i++) {
@@ -2059,17 +2056,16 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
             VirtualRegister profileRegister(pc[1].u.operand);
             ProfileTypeBytecodeFlag flag = static_cast<ProfileTypeBytecodeFlag>(pc[3].u.operand);
             SymbolTable* symbolTable = nullptr;
-            int localScopeDepth = pc[2].u.operand;
 
             switch (flag) {
-            case ProfileTypeBytecodePutToScope:
-            case ProfileTypeBytecodeGetFromScope: {
+            case ProfileTypeBytecodeClosureVar: {
                 const Identifier& ident = identifier(pc[4].u.operand);
+                int localScopeDepth = pc[2].u.operand;
                 ResolveType type = static_cast<ResolveType>(pc[5].u.operand);
-                ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, (flag == ProfileTypeBytecodeGetFromScope ? Get : Put), type);
+                // Even though type profiling may be profiling either a Get or a Put, we can always claim a Get because
+                // we're abstractly "read"ing from a JSScope.
+                ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, Get, type);
 
-                // FIXME: handle other values for op.type here, and also consider what to do when we can't statically determine the globalID
-                // https://bugs.webkit.org/show_bug.cgi?id=135184
                 if (op.type == ClosureVar)
                     symbolTable = op.lexicalEnvironment->symbolTable();
                 else if (op.type == GlobalVar)
@@ -2086,34 +2082,18 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
 
                 break;
             }
-            case ProfileTypeBytecodePutToLocalScope:
-            case ProfileTypeBytecodeGetFromLocalScope: {
-                if (!m_symbolTableConstantIndex) {
-                    globalVariableID = TypeProfilerNoGlobalIDExists;
-                    break;
-                }
+            case ProfileTypeBytecodeLocallyResolved: {
+                int symbolTableIndex = pc[2].u.operand;
+                RELEASE_ASSERT(clonedConstantSymbolTables.contains(symbolTableIndex));
+                SymbolTable* symbolTable = jsCast<SymbolTable*>(getConstant(symbolTableIndex));
                 const Identifier& ident = identifier(pc[4].u.operand);
-                symbolTable = this->symbolTable();
                 ConcurrentJITLocker locker(symbolTable->m_lock);
                 // If our parent scope was created while profiling was disabled, it will not have prepared for profiling yet.
-                symbolTable->prepareForTypeProfiling(locker);
                 globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm());
                 globalTypeSet = symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm());
 
                 break;
             }
-
-            case ProfileTypeBytecodeHasGlobalID: {
-                if (!m_symbolTableConstantIndex) {
-                    globalVariableID = TypeProfilerNoGlobalIDExists;
-                    break;
-                }
-                symbolTable = this->symbolTable();
-                ConcurrentJITLocker locker(symbolTable->m_lock);
-                globalVariableID = symbolTable->uniqueIDForOffset(locker, VarOffset(profileRegister), *vm());
-                globalTypeSet = symbolTable->globalTypeSetForOffset(locker, VarOffset(profileRegister), *vm());
-                break;
-            }
             case ProfileTypeBytecodeDoesNotHaveGlobalID: 
             case ProfileTypeBytecodeFunctionArgument: {
                 globalVariableID = TypeProfilerNoGlobalIDExists;
index 5a13762..6c3a115 100644 (file)
@@ -916,15 +916,6 @@ protected:
 private:
     friend class CodeBlockSet;
     
-    SymbolTable* symbolTable() const 
-    { 
-        // FIXME: Get rid of this function once the type profiler has a notion of what
-        // symbol table it's reading from.
-        // https://bugs.webkit.org/show_bug.cgi?id=145438
-        RELEASE_ASSERT(m_symbolTableConstantIndex); 
-        return jsCast<SymbolTable*>(getConstant(m_symbolTableConstantIndex));
-    }
-
     CodeBlock* specialOSREntryBlockOrNull();
     
     void noticeIncomingCall(ExecState* callerFrame);
@@ -1006,7 +997,6 @@ private:
     VM* m_vm;
 
     RefCountedArray<Instruction> m_instructions;
-    int m_symbolTableConstantIndex;
     VirtualRegister m_thisRegister;
     VirtualRegister m_scopeRegister;
     VirtualRegister m_lexicalEnvironmentRegister;
index a289d24..ae8422d 100644 (file)
@@ -418,9 +418,6 @@ public:
     void addExceptionHandler(const UnlinkedHandlerInfo& handler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(handler); }
     UnlinkedHandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; }
 
-    void setSymbolTableConstantIndex(int index) { m_symbolTableConstantIndex = index; }
-    int symbolTableConstantIndex() const { return m_symbolTableConstantIndex; }
-
     VM* vm() const { return m_vm; }
 
     UnlinkedArrayProfile addArrayProfile() { return m_arrayProfileCount++; }
@@ -563,7 +560,6 @@ private:
     FunctionExpressionVector m_functionExprs;
 
     WriteBarrier<SymbolTable> m_symbolTable;
-    int m_symbolTableConstantIndex { 0 };
 
     Vector<unsigned> m_propertyAccessInstructions;
 
index 548ae44..4295ca5 100644 (file)
@@ -207,7 +207,6 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     SymbolTable* functionSymbolTable = SymbolTable::create(*m_vm);
     functionSymbolTable->setUsesNonStrictEval(m_usesNonStrictEval);
     int symbolTableConstantIndex = addConstantValue(functionSymbolTable)->index();
-    m_codeBlock->setSymbolTableConstantIndex(symbolTableConstantIndex);
 
     Vector<Identifier> boundParameterProperties;
     FunctionParameters& parameters = *functionNode->parameters(); 
@@ -1180,9 +1179,6 @@ RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
     instructions().append(dst->index());
     instructions().append(src->index());
 
-    if (!dst->isTemporary() && vm()->typeProfiler())
-        emitProfileType(dst, ProfileTypeBytecodeHasGlobalID, nullptr);
-
     return dst;
 }
 
@@ -1289,24 +1285,85 @@ RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst
 
 void BytecodeGenerator::emitTypeProfilerExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot)
 {
+    ASSERT(vm()->typeProfiler());
+
     unsigned start = startDivot.offset; // Ranges are inclusive of their endpoints, AND 0 indexed.
     unsigned end = endDivot.offset - 1; // End Ranges already go one past the inclusive range, so subtract 1.
     unsigned instructionOffset = instructions().size() - 1;
     m_codeBlock->addTypeProfilerExpressionInfo(instructionOffset, start, end);
 }
 
-void BytecodeGenerator::emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag flag, const Identifier* identifier)
+void BytecodeGenerator::emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag flag)
 {
-    if (flag == ProfileTypeBytecodeGetFromScope || flag == ProfileTypeBytecodePutToScope)
-        RELEASE_ASSERT(identifier);
+    if (!vm()->typeProfiler())
+        return;
+
+    if (!registerToProfile)
+        return;
+
+    emitOpcode(op_profile_type);
+    instructions().append(registerToProfile->index());
+    instructions().append(0);
+    instructions().append(flag);
+    instructions().append(0);
+    instructions().append(resolveType());
+
+    // Don't emit expression info for this version of profile type. This generally means
+    // we're profiling information for something that isn't in the actual text of a JavaScript
+    // program. For example, implicit return undefined from a function call.
+}
+
+void BytecodeGenerator::emitProfileType(RegisterID* registerToProfile, const JSTextPosition& startDivot, const JSTextPosition& endDivot)
+{
+    emitProfileType(registerToProfile, ProfileTypeBytecodeDoesNotHaveGlobalID, startDivot, endDivot);
+}
+
+void BytecodeGenerator::emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag flag, const JSTextPosition& startDivot, const JSTextPosition& endDivot)
+{
+    if (!vm()->typeProfiler())
+        return;
+
+    if (!registerToProfile)
+        return;
 
     // The format of this instruction is: op_profile_type regToProfile, TypeLocation*, flag, identifier?, resolveType?
     emitOpcode(op_profile_type);
     instructions().append(registerToProfile->index());
-    instructions().append(localScopeDepth());
+    instructions().append(0);
     instructions().append(flag);
-    instructions().append(identifier ? addConstant(*identifier) : 0);
+    instructions().append(0);
+    instructions().append(resolveType());
+
+    emitTypeProfilerExpressionInfo(startDivot, endDivot);
+}
+
+void BytecodeGenerator::emitProfileType(RegisterID* registerToProfile, const Variable& var, const JSTextPosition& startDivot, const JSTextPosition& endDivot)
+{
+    if (!vm()->typeProfiler())
+        return;
+
+    if (!registerToProfile)
+        return;
+
+    ProfileTypeBytecodeFlag flag;
+    int symbolTableOrScopeDepth;
+    if (var.local() || var.offset().isScope()) {
+        flag = ProfileTypeBytecodeLocallyResolved;
+        symbolTableOrScopeDepth = var.symbolTableConstantIndex();
+    } else {
+        flag = ProfileTypeBytecodeClosureVar;
+        symbolTableOrScopeDepth = localScopeDepth();
+    }
+
+    // The format of this instruction is: op_profile_type regToProfile, TypeLocation*, flag, identifier?, resolveType?
+    emitOpcode(op_profile_type);
+    instructions().append(registerToProfile->index());
+    instructions().append(symbolTableOrScopeDepth);
+    instructions().append(flag);
+    instructions().append(addConstant(var.ident()));
     instructions().append(resolveType());
+
+    emitTypeProfilerExpressionInfo(startDivot, endDivot);
 }
 
 void BytecodeGenerator::emitProfileControlFlow(int textOffset)
@@ -1408,13 +1465,20 @@ void BytecodeGenerator::pushLexicalScopeInternal(VariableEnvironment& environmen
     }
 
     RegisterID* newScope = nullptr;
+    RegisterID* constantSymbolTable = nullptr;
     int symbolTableConstantIndex = 0;
+    if (vm()->typeProfiler()) {
+        constantSymbolTable = addConstantValue(symbolTable.get());
+        symbolTableConstantIndex = constantSymbolTable->index();
+    }
     if (hasCapturedVariables) {
         newScope = newBlockScopeVariable();
         newScope->ref();
-
-        RegisterID* constantSymbolTable = addConstantValue(!m_codeBlock->vm()->typeProfiler() ? symbolTable->cloneScopePart(*m_vm) : symbolTable.get());
-        symbolTableConstantIndex = constantSymbolTable->index();
+        if (!constantSymbolTable) {
+            ASSERT(!vm()->typeProfiler());
+            constantSymbolTable = addConstantValue(symbolTable->cloneScopePart(*m_vm));
+            symbolTableConstantIndex = constantSymbolTable->index();
+        }
         if (constantSymbolTableResult)
             *constantSymbolTableResult = constantSymbolTable;
 
index 347f0fe..723fcda 100644 (file)
@@ -252,11 +252,8 @@ namespace JSC {
     };
 
     enum ProfileTypeBytecodeFlag {
-        ProfileTypeBytecodePutToScope,
-        ProfileTypeBytecodeGetFromScope,
-        ProfileTypeBytecodePutToLocalScope,
-        ProfileTypeBytecodeGetFromLocalScope,
-        ProfileTypeBytecodeHasGlobalID,
+        ProfileTypeBytecodeClosureVar,
+        ProfileTypeBytecodeLocallyResolved,
         ProfileTypeBytecodeDoesNotHaveGlobalID,
         ProfileTypeBytecodeFunctionArgument,
         ProfileTypeBytecodeFunctionReturnStatement
@@ -447,8 +444,18 @@ namespace JSC {
             return emitNode(n);
         }
 
+    private:
         void emitTypeProfilerExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot);
-        void emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag, const Identifier*);
+    public:
+
+        // This doesn't emit expression info. If using this, make sure you shouldn't be emitting text offset.
+        void emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag); 
+        // These variables are associated with variables in a program. They could be Locals, LocalClosureVar, or ClosureVar.
+        void emitProfileType(RegisterID* registerToProfile, const Variable&, const JSTextPosition& startDivot, const JSTextPosition& endDivot);
+
+        void emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag, const JSTextPosition& startDivot, const JSTextPosition& endDivot);
+        // These are not associated with variables and don't have a global id.
+        void emitProfileType(RegisterID* registerToProfile, const JSTextPosition& startDivot, const JSTextPosition& endDivot);
 
         void emitProfileControlFlow(int);
 
index 7c4ea62..9d51fe9 100644 (file)
@@ -153,11 +153,8 @@ RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst
         return 0;
 
     RegisterID* result = generator.moveToDestinationIfNeeded(dst, generator.thisRegister());
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(generator.thisRegister(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        static const unsigned thisLength = 4;
-        generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + thisLength, -1));
-    }
+    static const unsigned thisLength = 4;
+    generator.emitProfileType(generator.thisRegister(), position(), JSTextPosition(-1, position().offset + thisLength, -1));
     return result;
 }
 
@@ -209,10 +206,8 @@ RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
         generator.emitTDZCheckIfNecessary(var, local, nullptr);
         if (dst == generator.ignoredResult())
             return nullptr;
-        if (generator.vm()->typeProfiler()) {
-            generator.emitProfileType(local, ProfileTypeBytecodeHasGlobalID, nullptr);
-            generator.emitTypeProfilerExpressionInfo(m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1));
-        }
+
+        generator.emitProfileType(local, var, m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1));
         return generator.moveToDestinationIfNeeded(dst, local);
     }
     
@@ -222,10 +217,7 @@ RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
     RegisterID* finalDest = generator.finalDestination(dst);
     RegisterID* result = generator.emitGetFromScope(finalDest, scope.get(), var, ThrowIfNotFound);
     generator.emitTDZCheckIfNecessary(var, finalDest, nullptr);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(finalDest, var.isResolved() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident);
-        generator.emitTypeProfilerExpressionInfo(m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1));
-    }
+    generator.emitProfileType(finalDest, var, m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1));
     return result;
 }
 
@@ -623,10 +615,7 @@ RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, Regi
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
 
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(finalDest, divotStart(), divotEnd());
     return ret;
 }
 
@@ -638,10 +627,7 @@ RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, Register
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     RegisterID* finalDest = generator.finalDestination(dst);
     RegisterID* ret = generator.emitGetById(finalDest, base.get(), m_ident);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(finalDest, divotStart(), divotEnd());
     return ret;
 }
 
@@ -734,10 +720,7 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re
     }
     generator.emitLoad(callArguments.thisRegister(), jsUndefined());
     RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
     return ret;
 }
 
@@ -757,10 +740,7 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
         // This passes NoExpectedFunction because we expect that if the function is in a
         // local variable, then it's not one of our built-in constructors.
         RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
-        if (generator.vm()->typeProfiler()) {
-            generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-            generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-        }
+        generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
         return ret;
     }
 
@@ -776,10 +756,7 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
     generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound);
     generator.emitTDZCheckIfNecessary(var, func.get(), nullptr);
     RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd());
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
     return ret;
 }
 
@@ -847,10 +824,7 @@ RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator,
     else
         generator.emitMove(callArguments.thisRegister(), base.get());
     RegisterID* ret = generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
     return ret;
 }
 
@@ -869,10 +843,7 @@ RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, Regi
     generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
     generator.emitGetById(function.get(), baseIsSuper ? emitSuperBaseForCallee(generator) : callArguments.thisRegister(), m_ident);
     RegisterID* ret = generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
     return ret;
 }
 
@@ -927,10 +898,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
         }
         generator.emitLabel(end.get());
     }
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
     return returnValue.get();
 }
 
@@ -1038,10 +1006,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
         generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
         generator.emitLabel(end.get());
     }
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
     return returnValue.get();
 }
 
@@ -1077,19 +1042,10 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
         if (var.isReadOnly()) {
             generator.emitReadOnlyExceptionIfNeeded(var);
             localReg = generator.emitMove(generator.tempDestination(dst), local);
-        } else if (generator.vm()->typeProfiler()) {
-            RefPtr<RegisterID> tempDst = generator.finalDestination(dst);
-            ASSERT(dst != localReg);
-            RefPtr<RegisterID> tempDstSrc = generator.newTemporary();
-            generator.emitToNumber(tempDst.get(), localReg.get());
-            generator.emitMove(tempDstSrc.get(), localReg.get());
-            emitIncOrDec(generator, tempDstSrc.get(), m_operator);
-            generator.emitMove(localReg.get(), tempDstSrc.get());
-            if (generator.vm()->typeProfiler())
-                generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-            return tempDst.get();
         }
-        return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator);
+        RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator);
+        generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd());
+        return oldValue.get();
     }
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
@@ -1103,10 +1059,7 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
     }
     RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
     generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(value.get(), var, divotStart(), divotEnd());
 
     return oldValue.get();
 }
@@ -1129,10 +1082,7 @@ RegisterID* PostfixNode::emitBracket(BytecodeGenerator& generator, RegisterID* d
     RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     generator.emitPutByVal(base.get(), property.get(), value.get());
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(value.get(), divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, oldValue);
 }
 
@@ -1153,10 +1103,7 @@ RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst)
     RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     generator.emitPutById(base.get(), ident, value.get());
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(value.get(), divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, oldValue);
 }
 
@@ -1291,8 +1238,7 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
             generator.emitMove(tempDst.get(), localReg.get());
             emitIncOrDec(generator, tempDst.get(), m_operator);
             generator.emitMove(localReg.get(), tempDst.get());
-            if (generator.vm()->typeProfiler())
-                generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
+            generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd());
             return generator.moveToDestinationIfNeeded(dst, tempDst.get());
         }
         emitIncOrDec(generator, localReg.get(), m_operator);
@@ -1311,10 +1257,7 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
 
     emitIncOrDec(generator, value.get(), m_operator);
     generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(value.get(), var, divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, value.get());
 }
 
@@ -1334,10 +1277,7 @@ RegisterID* PrefixNode::emitBracket(BytecodeGenerator& generator, RegisterID* ds
     emitIncOrDec(generator, value, m_operator);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     generator.emitPutByVal(base.get(), property.get(), value);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(value, divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, propDst.get());
 }
 
@@ -1356,10 +1296,7 @@ RegisterID* PrefixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst)
     emitIncOrDec(generator, value, m_operator);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     generator.emitPutById(base.get(), ident, value);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(value, divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, propDst.get());
 }
 
@@ -1809,23 +1746,24 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
         generator.emitTDZCheckIfNecessary(var, local, nullptr);
         if (var.isReadOnly()) {
             generator.emitReadOnlyExceptionIfNeeded(var);
-            return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
+            RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
+            generator.emitProfileType(result, divotStart(), divotEnd());
+            return result;
         }
         
-        if (generator.vm()->typeProfiler()
-            || generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
+        if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
             RefPtr<RegisterID> result = generator.newTemporary();
             generator.emitMove(result.get(), local);
             emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
             generator.emitMove(local, result.get());
             generator.invalidateForInContextForLocal(local);
-            if (generator.vm()->typeProfiler())
-                generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
+            generator.emitProfileType(local, divotStart(), divotEnd());
             return generator.moveToDestinationIfNeeded(dst, result.get());
         }
         
         RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
         generator.invalidateForInContextForLocal(local);
+        generator.emitProfileType(result, divotStart(), divotEnd());
         return generator.moveToDestinationIfNeeded(dst, result);
     }
 
@@ -1840,10 +1778,7 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
     }
     RefPtr<RegisterID> result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this);
     RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(result.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
     return returnResult;
 }
 
@@ -1860,16 +1795,17 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
         if (var.isReadOnly() && m_assignmentContext != AssignmentContext::ConstDeclarationStatement) {
             result = generator.emitNode(dst, m_right); // Execute side effects first.
             generator.emitReadOnlyExceptionIfNeeded(var);
-        } else if (var.isSpecial() || generator.vm()->typeProfiler()) {
+            generator.emitProfileType(result, var, divotStart(), divotEnd());
+        } else if (var.isSpecial()) {
             RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
             generator.emitNode(tempDst.get(), m_right);
             generator.emitMove(local, tempDst.get());
+            generator.emitProfileType(local, var, divotStart(), divotEnd());
             generator.invalidateForInContextForLocal(local);
-            if (generator.vm()->typeProfiler())
-                generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
             result = generator.moveToDestinationIfNeeded(dst, tempDst.get());
         } else {
             RegisterID* right = generator.emitNode(local, m_right);
+            generator.emitProfileType(right, var, divotStart(), divotEnd());
             generator.invalidateForInContextForLocal(local);
             result = generator.moveToDestinationIfNeeded(dst, right);
         }
@@ -1895,10 +1831,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
     }
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(result.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
 
     if (m_assignmentContext == AssignmentContext::DeclarationStatement || m_assignmentContext == AssignmentContext::ConstDeclarationStatement)
         generator.liftTDZCheckIfPossible(var);
@@ -1915,10 +1848,7 @@ RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
     generator.emitPutById(base.get(), m_ident, forwardResult);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(forwardResult, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(forwardResult, divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, forwardResult);
 }
 
@@ -1934,10 +1864,7 @@ RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, Regist
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     RegisterID* ret = generator.emitPutById(base.get(), m_ident, updatedValue);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(updatedValue, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(updatedValue, divotStart(), divotEnd());
     return ret;
 }
 
@@ -1965,10 +1892,7 @@ RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, Regist
     else
         generator.emitPutByVal(base.get(), property.get(), forwardResult);
 
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(forwardResult, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(forwardResult, divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, forwardResult);
 }
 
@@ -1985,10 +1909,7 @@ RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, Re
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     generator.emitPutByVal(base.get(), property.get(), updatedValue);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(updatedValue, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(updatedValue, divotStart(), divotEnd());
 
     return updatedValue;
 }
@@ -2080,15 +2001,13 @@ RegisterID* EmptyVarExpression::emitBytecode(BytecodeGenerator& generator, Regis
 
     Variable var = generator.variable(m_ident);
     if (RegisterID* local = var.local())
-        generator.emitProfileType(local, ProfileTypeBytecodeHasGlobalID, nullptr);
+        generator.emitProfileType(local, var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
     else {
         RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
         RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound);
-        generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident);
+        generator.emitProfileType(value.get(), var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
     }
 
-    generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
-
     return nullptr;
 }
 
@@ -2101,17 +2020,13 @@ RegisterID* EmptyLetExpression::emitBytecode(BytecodeGenerator& generator, Regis
     Variable var = generator.variable(m_ident);
     if (RegisterID* local = var.local()) {
         generator.emitLoad(local, jsUndefined());
-        if (generator.vm()->typeProfiler())
-            generator.emitProfileType(local, ProfileTypeBytecodeHasGlobalID, nullptr);
+        generator.emitProfileType(local, var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
     } else {
         RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
         RefPtr<RegisterID> value = generator.emitLoad(nullptr, jsUndefined());
         generator.emitPutToScope(scope.get(), var, value.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
-        if (generator.vm()->typeProfiler())
-            generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident);
+        generator.emitProfileType(value.get(), var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); 
     }
-    if (generator.vm()->typeProfiler())
-        generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
 
     // It's safe to return null here because this node will always be a child node of DeclarationStatement which ignores our return value.
     return nullptr;
@@ -2316,11 +2231,8 @@ void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propert
             RegisterID* scope = generator.emitResolveScope(nullptr, var);
             generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
             generator.emitPutToScope(scope, var, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
-            if (generator.vm()->typeProfiler())
-                generator.emitProfileType(propertyName, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident);
         }
-        if (generator.vm()->typeProfiler())
-            generator.emitTypeProfilerExpressionInfo(m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
+        generator.emitProfileType(propertyName, var, m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
         return;
     }
     if (m_lexpr->isDotAccessorNode()) {
@@ -2329,10 +2241,7 @@ void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propert
         RegisterID* base = generator.emitNode(assignNode->base());
         generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
         generator.emitPutById(base, ident, propertyName);
-        if (generator.vm()->typeProfiler()) {
-            generator.emitProfileType(propertyName, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-            generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd());
-        }
+        generator.emitProfileType(propertyName, assignNode->divotStart(), assignNode->divotEnd());
         return;
     }
     if (m_lexpr->isBracketAccessorNode()) {
@@ -2341,10 +2250,7 @@ void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propert
         RegisterID* subscript = generator.emitNode(assignNode->subscript());
         generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
         generator.emitPutByVal(base.get(), subscript, propertyName);
-        if (generator.vm()->typeProfiler()) {
-            generator.emitProfileType(propertyName, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-            generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd());
-        }
+        generator.emitProfileType(propertyName, assignNode->divotStart(), assignNode->divotEnd());
         return;
     }
 
@@ -2364,8 +2270,7 @@ void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propert
             return;
         }
         generator.emitMove(var.local(), propertyName);
-        if (generator.vm()->typeProfiler())
-            generator.emitTypeProfilerExpressionInfo(simpleBinding->divotStart(), simpleBinding->divotEnd());
+        generator.emitProfileType(propertyName, var, simpleBinding->divotStart(), simpleBinding->divotEnd());
         return;
     }
 
@@ -2547,11 +2452,8 @@ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
                 RegisterID* scope = generator.emitResolveScope(nullptr, var);
                 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
                 generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
-                if (generator.vm()->typeProfiler())
-                    generator.emitProfileType(value, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident);
             }
-            if (generator.vm()->typeProfiler())
-                generator.emitTypeProfilerExpressionInfo(m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
+            generator.emitProfileType(value, var, m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
         } else if (m_lexpr->isDotAccessorNode()) {
             DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr);
             const Identifier& ident = assignNode->identifier();
@@ -2559,10 +2461,7 @@ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
             
             generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
             generator.emitPutById(base.get(), ident, value);
-            if (generator.vm()->typeProfiler()) {
-                generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-                generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd());
-            }
+            generator.emitProfileType(value, assignNode->divotStart(), assignNode->divotEnd());
         } else if (m_lexpr->isBracketAccessorNode()) {
             BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
             RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
@@ -2570,10 +2469,7 @@ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
             
             generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
             generator.emitPutByVal(base.get(), subscript, value);
-            if (generator.vm()->typeProfiler()) {
-                generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
-                generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd());
-            }
+            generator.emitProfileType(value, assignNode->divotStart(), assignNode->divotEnd());
         } else {
             ASSERT(m_lexpr->isDestructuringNode());
             DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr);
@@ -2656,10 +2552,7 @@ void ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
         dst = 0;
 
     RefPtr<RegisterID> returnRegister = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined());
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(returnRegister.get(), ProfileTypeBytecodeFunctionReturnStatement, nullptr);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(returnRegister.get(), ProfileTypeBytecodeFunctionReturnStatement, divotStart(), divotEnd());
     if (generator.labelScopeDepth()) {
         returnRegister = generator.emitMove(generator.newTemporary(), returnRegister.get());
         generator.emitPopScopes(generator.scopeRegister(), 0);
@@ -3019,13 +2912,12 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 {
     if (generator.vm()->typeProfiler()) {
         for (size_t i = 0; i < m_parameters->size(); i++) {
-            // FIXME: Handle Destructuring assignments into arguments.
+            // Destructuring parameters are handled in destructuring nodes.
             if (!m_parameters->at(i).first->isBindingNode())
                 continue;
             BindingNode* parameter = static_cast<BindingNode*>(m_parameters->at(i).first);
             RegisterID reg(CallFrame::argumentOffset(i));
-            generator.emitProfileType(&reg, ProfileTypeBytecodeFunctionArgument, nullptr);
-            generator.emitTypeProfilerExpressionInfo(parameter->divotStart(), parameter->divotEnd());
+            generator.emitProfileType(&reg, ProfileTypeBytecodeFunctionArgument, parameter->divotStart(), parameter->divotEnd());
         }
     }
 
@@ -3046,8 +2938,7 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
     // If there is no return we must automatically insert one.
     if (!returnNode) {
         RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
-        if (generator.vm()->typeProfiler())
-            generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement, nullptr); // Do not emit expression info for this profile because it's not in the user's source code.
+        generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement); // Do not emit expression info for this profile because it's not in the user's source code.
         ASSERT(startOffset() >= lineStartOffset());
         generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset());
         generator.emitReturn(r0);
@@ -3367,8 +3258,7 @@ void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) con
                 return;
         }
         generator.emitMove(local, value);
-        if (generator.vm()->typeProfiler())
-            generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
+        generator.emitProfileType(local, var, divotStart(), divotEnd());
         if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement)
             generator.liftTDZCheckIfPossible(var);
         return;
@@ -3385,10 +3275,7 @@ void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) con
             return;
     }
     generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
-    if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_boundProperty);
-        generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-    }
+    generator.emitProfileType(value, var, divotStart(), divotEnd());
     if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement)
         generator.liftTDZCheckIfPossible(var);
     return;
index 7e08d9b..972d408 100644 (file)
@@ -4580,6 +4580,8 @@ void SpeculativeJIT::compile(Node* node)
         GPRReg scratch2GPR = scratch2.gpr();
         GPRReg scratch3GPR = scratch3.gpr();
 
+        JITCompiler::Jump isTDZValue = m_jit.branch32(JITCompiler::Equal, value.tagGPR(), TrustedImm32(JSValue::EmptyValueTag));
+
         // Load the TypeProfilerLog into Scratch2.
         TypeProfilerLog* cachedTypeProfilerLog = m_jit.vm()->typeProfilerLog();
         m_jit.move(TrustedImmPtr(cachedTypeProfilerLog), scratch2GPR);
@@ -4612,6 +4614,8 @@ void SpeculativeJIT::compile(Node* node)
         addSlowPathGenerator(
             slowPathCall(clearLog, this, operationProcessTypeProfilerLogDFG, NoResult));
 
+        isTDZValue.link(&m_jit);
+
         noResult(node);
         break;
     }
index 2c78f9a..c3db363 100644 (file)
@@ -4609,6 +4609,8 @@ void SpeculativeJIT::compile(Node* node)
 
         MacroAssembler::JumpList jumpToEnd;
 
+        jumpToEnd.append(m_jit.branchTest64(JITCompiler::Zero, valueGPR));
+
         TypeLocation* cachedTypeLocation = node->typeLocation();
         // Compile in a predictive type check, if possible, to see if we can skip writing to the log.
         // These typechecks are inlined to match those of the 64-bit JSValue type checks.
index 54db327..90b5321 100644 (file)
@@ -1239,6 +1239,8 @@ void JIT::emit_op_profile_type(Instruction* currentInstruction)
 
     JumpList jumpToEnd;
 
+    jumpToEnd.append(branchTest64(Zero, regT0));
+
     // Compile in a predictive type check, if possible, to see if we can skip writing to the log.
     // These typechecks are inlined to match those of the 64-bit JSValue type checks.
     if (cachedTypeLocation->m_lastSeenType == TypeUndefined)
index 2863508..d0e75ce 100644 (file)
@@ -1244,6 +1244,8 @@ void JIT::emit_op_profile_type(Instruction* currentInstruction)
 
     JumpList jumpToEnd;
 
+    jumpToEnd.append(branch32(Equal, regT3, TrustedImm32(JSValue::EmptyValueTag)));
+
     // Compile in a predictive type check, if possible, to see if we can skip writing to the log.
     // These typechecks are inlined to match those of the 32-bit JSValue type checks.
     if (cachedTypeLocation->m_lastSeenType == TypeUndefined)
index b66a99d..e90eced 100644 (file)
@@ -2342,6 +2342,8 @@ _llint_op_profile_type:
     loadisFromInstruction(1, t2)
     loadConstantOrVariable(t2, t4, t0)
 
+    bieq t4, EmptyValueTag, .opProfileTypeDone
+
     # t2 is holding the pointer to the current log entry.
     loadp TypeProfilerLog::m_currentLogEntryPtr[t1], t2
 
index f5af818..d9455f7 100644 (file)
@@ -2200,6 +2200,7 @@ _llint_op_profile_type:
     loadisFromInstruction(1, t3)
     loadConstantOrVariable(t3, t0)
 
+    bqeq t0, ValueEmpty, .opProfileTypeDone
     # Store the JSValue onto the log entry.
     storeq t0, TypeProfilerLog::LogEntry::value[t2]
     
diff --git a/Source/JavaScriptCore/tests/typeProfiler/es6-block-scoping.js b/Source/JavaScriptCore/tests/typeProfiler/es6-block-scoping.js
new file mode 100644 (file)
index 0000000..81a7ef2
--- /dev/null
@@ -0,0 +1,83 @@
+load("./driver/driver.js");
+
+let changeFoo;
+let tdzError;
+let scoping;
+let scoping2;
+function noop(){}
+function arr() {
+    return [1, 1.5, "hello", {}];
+}
+
+function wrapper() {
+
+let foo=20;
+changeFoo = function(arg) { foo = arg; }
+
+scoping = function ()
+{
+    let x = "hello";
+    if (true) {
+        let x = 20;
+        const y = true;
+        x = "h"
+    }
+    noop(x);
+}
+
+scoping2 = function() 
+{
+    for (const item of arr()) {
+        noop(item);
+    }
+}
+
+}
+wrapper();
+
+// ====== End test cases ======
+
+var types = findTypeForExpression(wrapper, "foo=20;"); 
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Primitive type names should contain 'Integer'");
+assert(types.globalTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Primitive type names should contain 'Integer'");
+assert(types.globalTypeSet.primitiveTypeNames.length === 1, "Primitive type names should contain exactly only one item globally");
+assert(types.instructionTypeSet.primitiveTypeNames.length === 1, "Primitive type names should contain exactly only one item on the instruction");
+assert(types.globalTypeSet.displayTypeName === T.Integer, "global display name should be Integer");
+assert(types.instructionTypeSet.displayTypeName === T.Integer, "instruction display name should be Integer");
+
+changeFoo(20.5);
+types = findTypeForExpression(wrapper, "foo=20;");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Primitive type names should contain 'Integer'");
+assert(types.instructionTypeSet.primitiveTypeNames.length === 1, "Primitive type names should contain STILL only contain exactly one item on the instruction");
+assert(types.globalTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Global primitive type names should now still contain 'Integer'");
+assert(types.globalTypeSet.primitiveTypeNames.indexOf(T.Number) !== -1, "Global primitive type names should now contain 'Number'");
+assert(types.globalTypeSet.primitiveTypeNames.length === 2, "Global primitive type names should contain exactly two items globally");
+assert(types.globalTypeSet.displayTypeName === T.Number, "global display name should be Number");
+
+
+scoping();
+types = findTypeForExpression(scoping, "x = 20");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Primitive type names should contain 'Integer'");
+assert(types.instructionTypeSet.primitiveTypeNames.length === 1, "Primitive type names should contain only one item on the instruction");
+assert(types.globalTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Primitive type names should contain 'Integer'");
+assert(types.globalTypeSet.primitiveTypeNames.length === 2, "Primitive type names should contain two items: [String, Integer]");
+
+types = findTypeForExpression(scoping, "x)");
+assert(types.globalTypeSet.primitiveTypeNames.indexOf(T.String) !== -1, "Global primitive type names should have string.");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.String) !== -1, "Global primitive type names should have string.");
+
+types = findTypeForExpression(scoping, "y = true");
+assert(types.globalTypeSet.primitiveTypeNames.indexOf(T.Boolean) !== -1, "Global primitive type names should have boolean.");
+assert(types.globalTypeSet.primitiveTypeNames.length === 1, "type only have one item.");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Boolean) !== -1, "Global primitive type names should have boolean.");
+assert(types.instructionTypeSet.primitiveTypeNames.length === 1, "type only have one item.");
+
+
+scoping2();
+types = findTypeForExpression(scoping2, "item)");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Primitive type names should contain 'Integer'");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Number) !== -1, "Primitive type names should contain 'Number'");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.String) !== -1, "Primitive type names should contain 'String'");
+assert(types.instructionTypeSet.structures.length === 1, "should have one structure");
+assert(types.instructionTypeSet.structures[0].constructorName === "Object", "Should be object");
+assert(types.instructionTypeSet.structures[0].fields.length === 0, "Should have no fields");
diff --git a/Source/JavaScriptCore/tests/typeProfiler/es6-classes.js b/Source/JavaScriptCore/tests/typeProfiler/es6-classes.js
new file mode 100644 (file)
index 0000000..c53aaa2
--- /dev/null
@@ -0,0 +1,39 @@
+load("./driver/driver.js");
+
+let changeFoo;
+let tdzError;
+let scoping;
+let scoping2;
+function noop(){}
+
+function wrapper() {
+    class Animal {
+        constructor() { }
+        methodA() {}
+    }
+    class Dog extends Animal {
+        constructor() { super() }
+        methodB() {}
+    }
+
+    let dogInstance = new Dog;
+    const animalInstance = new Animal;
+}
+wrapper();
+
+// ====== End test cases ======
+
+var types = findTypeForExpression(wrapper, "dogInstance =");
+assert(types.globalTypeSet.displayTypeName === "Dog", "Should show constructor name");
+assert(types.globalTypeSet.structures[0].constructorName === "Dog", "Should be Dog");
+assert(types.globalTypeSet.structures[0].proto.fields.length === 2, "should have two fields");
+assert(types.globalTypeSet.structures[0].proto.fields.indexOf("constructor") !== -1, "should have constructor");
+assert(types.globalTypeSet.structures[0].proto.fields.indexOf("methodB") !== -1, "should have methodB");
+
+types = findTypeForExpression(wrapper, "animalInstance =");
+assert(types.globalTypeSet.displayTypeName === "Animal", "Should show constructor name");
+assert(types.globalTypeSet.structures.length === 1, "should have one structure");
+assert(types.globalTypeSet.structures[0].constructorName === "Animal", "Should be Animal");
+assert(types.globalTypeSet.structures[0].proto.fields.length === 2, "should have two fields");
+assert(types.globalTypeSet.structures[0].proto.fields.indexOf("constructor") !== -1, "should have constructor");
+assert(types.globalTypeSet.structures[0].proto.fields.indexOf("methodA") !== -1, "should have methodA");