JSC's Type Profiler doesn't profile the type of the looping variable in ForOf/ForIn loops
https://bugs.webkit.org/show_bug.cgi?id=141241
Reviewed by Filip Pizlo.
Type information is now recorded for ForIn and ForOf statements.
It was an oversight to not have these statements profiled before.
* bytecompiler/NodesCodegen.cpp:
(JSC::ForInNode::emitLoopHeader):
(JSC::ForOfNode::emitBytecode):
* tests/typeProfiler/loop.js: Added.
(testForIn):
(testForOf):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@179865 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 898069f..fc2be4e 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,20 @@
+2015-02-09 Saam Barati <saambarati1@gmail.com>
+
+ JSC's Type Profiler doesn't profile the type of the looping variable in ForOf/ForIn loops
+ https://bugs.webkit.org/show_bug.cgi?id=141241
+
+ Reviewed by Filip Pizlo.
+
+ Type information is now recorded for ForIn and ForOf statements.
+ It was an oversight to not have these statements profiled before.
+
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::ForInNode::emitLoopHeader):
+ (JSC::ForOfNode::emitBytecode):
+ * tests/typeProfiler/loop.js: Added.
+ (testForIn):
+ (testForOf):
+
2015-02-09 Filip Pizlo <fpizlo@apple.com>
DFG::StackLayoutPhase should always set the scopeRegister to VirtualRegister() because the DFG doesn't do anything to make its value valid
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index d1b01064..44afe9c 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -2027,7 +2027,11 @@
RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident, resolveScopeInfo);
generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
generator.emitPutToScope(scope, ident, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, resolveScopeInfo);
+ if (generator.vm()->typeProfiler())
+ generator.emitProfileType(propertyName, resolveScopeInfo.isLocal() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident);
}
+ if (generator.vm()->typeProfiler())
+ generator.emitTypeProfilerExpressionInfo(m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
return;
}
if (m_lexpr->isDotAccessorNode()) {
@@ -2036,6 +2040,10 @@
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());
+ }
return;
}
if (m_lexpr->isBracketAccessorNode()) {
@@ -2044,6 +2052,10 @@
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());
+ }
return;
}
@@ -2063,6 +2075,8 @@
return;
}
generator.emitMove(local.get(), propertyName);
+ if (generator.vm()->typeProfiler())
+ generator.emitTypeProfilerExpressionInfo(m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
return;
}
@@ -2235,7 +2249,11 @@
RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident, resolveScopeInfo);
generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
generator.emitPutToScope(scope, ident, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, resolveScopeInfo);
+ if (generator.vm()->typeProfiler())
+ generator.emitProfileType(value, resolveScopeInfo.isLocal() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident);
}
+ if (generator.vm()->typeProfiler())
+ generator.emitTypeProfilerExpressionInfo(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();
@@ -2243,6 +2261,10 @@
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());
+ }
} else if (m_lexpr->isBracketAccessorNode()) {
BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
@@ -2250,6 +2272,10 @@
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());
+ }
} else {
ASSERT(m_lexpr->isDeconstructionNode());
DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr);
diff --git a/Source/JavaScriptCore/tests/typeProfiler/loop.js b/Source/JavaScriptCore/tests/typeProfiler/loop.js
new file mode 100644
index 0000000..c484024
--- /dev/null
+++ b/Source/JavaScriptCore/tests/typeProfiler/loop.js
@@ -0,0 +1,37 @@
+load("./driver/driver.js");
+
+function testForIn(x) {
+ // FIXME: add support for the following statement types: "for (var arg of expr)" and "for (var arg in expr)"
+ // https://bugs.webkit.org/show_bug.cgi?id=141241
+
+ for (arg2 in x)
+ x;
+
+ for ({x: arg3} in x)
+ x;
+}
+
+function testForOf(x) {
+ for (arg2 of x)
+ x;
+
+ for ({x: arg3} of x)
+ x;
+}
+
+testForIn([1])
+var types = findTypeForExpression(testForIn, "arg2");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.String) !== -1, "Primitive type names should contain 'String'");
+types = findTypeForExpression(testForIn, "arg3");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Undefined) !== -1, "Primitive type names should contain 'Undefined'");
+
+testForOf([1])
+types = findTypeForExpression(testForOf, "arg2");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Primitive type names should contain 'Integer'");
+types = findTypeForExpression(testForOf, "arg3");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Undefined) !== -1, "Primitive type names should contain 'Undefined'");
+testForOf([{x:29}])
+types = findTypeForExpression(testForOf, "arg2");
+assert(types.instructionTypeSet.structures[0].fields.indexOf("x") !== -1, "variable 'arg1' should have field 'x'");
+types = findTypeForExpression(testForOf, "arg3");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Primitive type names should contain 'Integer'");