Web Inspector: ES6: Better support for Symbol types in Type Profiler
https://bugs.webkit.org/show_bug.cgi?id=141257
Reviewed by Joseph Pecoraro.
Source/JavaScriptCore:
ES6 introduces the new primitive type Symbol. This patch makes JSC's
type profiler support this new primitive type.
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* inspector/protocol/Runtime.json:
* runtime/RuntimeType.cpp:
(JSC::runtimeTypeForValue):
* runtime/RuntimeType.h:
(JSC::runtimeTypeIsPrimitive):
* runtime/TypeSet.cpp:
(JSC::TypeSet::addTypeInformation):
(JSC::TypeSet::dumpTypes):
(JSC::TypeSet::doesTypeConformTo):
(JSC::TypeSet::displayName):
(JSC::TypeSet::inspectorTypeSet):
(JSC::TypeSet::toJSONString):
* runtime/TypeSet.h:
(JSC::TypeSet::seenTypes):
* tests/typeProfiler/driver/driver.js:
* tests/typeProfiler/symbol.js: Added.
(wrapper.foo):
(wrapper.bar):
(wrapper.bar.bar.baz):
(wrapper):
Source/WebInspectorUI:
The Web Inspector's visualization of JSC's type profiler
should have support for the Symbol type.
* UserInterface/Models/TypeSet.js:
(WebInspector.TypeSet):
(WebInspector.TypeSet.prototype.get primitiveTypeNames):
* UserInterface/Views/TypeTokenView.css:
TypeTokenView will display Symbol type tokens using the same color that
Symbol values are displayed as formatted values.
(.type-token-symbol):
* UserInterface/Views/TypeTokenView.js:
(WebInspector.TypeTokenView.prototype._displayTypeName):
(WebInspector.TypeTokenView):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@182114 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index c03b067..25af2cb 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,36 @@
+2015-03-28 Saam Barati <saambarati1@gmail.com>
+
+ Web Inspector: ES6: Better support for Symbol types in Type Profiler
+ https://bugs.webkit.org/show_bug.cgi?id=141257
+
+ Reviewed by Joseph Pecoraro.
+
+ ES6 introduces the new primitive type Symbol. This patch makes JSC's
+ type profiler support this new primitive type.
+
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * inspector/protocol/Runtime.json:
+ * runtime/RuntimeType.cpp:
+ (JSC::runtimeTypeForValue):
+ * runtime/RuntimeType.h:
+ (JSC::runtimeTypeIsPrimitive):
+ * runtime/TypeSet.cpp:
+ (JSC::TypeSet::addTypeInformation):
+ (JSC::TypeSet::dumpTypes):
+ (JSC::TypeSet::doesTypeConformTo):
+ (JSC::TypeSet::displayName):
+ (JSC::TypeSet::inspectorTypeSet):
+ (JSC::TypeSet::toJSONString):
+ * runtime/TypeSet.h:
+ (JSC::TypeSet::seenTypes):
+ * tests/typeProfiler/driver/driver.js:
+ * tests/typeProfiler/symbol.js: Added.
+ (wrapper.foo):
+ (wrapper.bar):
+ (wrapper.bar.bar.baz):
+ (wrapper):
+
2015-03-27 Saam Barati <saambarati1@gmail.com>
Deconstruction parameters are bound too late
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 146ee5c..537faac 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -1148,7 +1148,7 @@
// (The other direction does not hold in general).
RefPtr<TypeSet> typeSet = node->typeLocation()->m_instructionTypeSet;
- uint8_t seenTypes = typeSet->seenTypes();
+ RuntimeTypeMask seenTypes = typeSet->seenTypes();
if (typeSet->doesTypeConformTo(TypeMachineInt)) {
node->convertToCheck();
if (node->child1()->shouldSpeculateInt32())
diff --git a/Source/JavaScriptCore/inspector/protocol/Runtime.json b/Source/JavaScriptCore/inspector/protocol/Runtime.json
index e3bb91a..a7dfb7e 100644
--- a/Source/JavaScriptCore/inspector/protocol/Runtime.json
+++ b/Source/JavaScriptCore/inspector/protocol/Runtime.json
@@ -154,7 +154,8 @@
{ "name": "isInteger", "type": "boolean", "description": "Indicates if this type description has been type Integer." },
{ "name": "isNumber", "type": "boolean", "description": "Indicates if this type description has been type Number." },
{ "name": "isString", "type": "boolean", "description": "Indicates if this type description has been type String." },
- { "name": "isObject", "type": "boolean", "description": "Indicates if this type description has been type Object." }
+ { "name": "isObject", "type": "boolean", "description": "Indicates if this type description has been type Object." },
+ { "name": "isSymbol", "type": "boolean", "description": "Indicates if this type description has been type Symbol." }
]
},
{
diff --git a/Source/JavaScriptCore/runtime/RuntimeType.cpp b/Source/JavaScriptCore/runtime/RuntimeType.cpp
index 1d55d9b..4e7b3a7 100644
--- a/Source/JavaScriptCore/runtime/RuntimeType.cpp
+++ b/Source/JavaScriptCore/runtime/RuntimeType.cpp
@@ -51,6 +51,8 @@
return TypeObject;
if (value.isFunction())
return TypeFunction;
+ if (value.isSymbol())
+ return TypeSymbol;
return TypeNothing;
}
diff --git a/Source/JavaScriptCore/runtime/RuntimeType.h b/Source/JavaScriptCore/runtime/RuntimeType.h
index 5f81e62..d57b8fb 100644
--- a/Source/JavaScriptCore/runtime/RuntimeType.h
+++ b/Source/JavaScriptCore/runtime/RuntimeType.h
@@ -31,7 +31,7 @@
namespace JSC {
-enum RuntimeType : uint8_t {
+enum RuntimeType : uint16_t {
TypeNothing = 0x0,
TypeFunction = 0x1,
TypeUndefined = 0x2,
@@ -40,13 +40,21 @@
TypeMachineInt = 0x10,
TypeNumber = 0x20,
TypeString = 0x40,
- TypeObject = 0x80
+ TypeObject = 0x80,
+ TypeSymbol = 0x100
};
+typedef uint16_t RuntimeTypeMask;
+
class JSValue;
RuntimeType runtimeTypeForValue(JSValue);
String runtimeTypeAsString(RuntimeType);
+ALWAYS_INLINE bool runtimeTypeIsPrimitive(RuntimeTypeMask type)
+{
+ return type & ~(TypeFunction | TypeObject);
+}
+
} // namespace JSC
#endif // RuntimeType_h
diff --git a/Source/JavaScriptCore/runtime/TypeSet.cpp b/Source/JavaScriptCore/runtime/TypeSet.cpp
index 3161581..8107388 100644
--- a/Source/JavaScriptCore/runtime/TypeSet.cpp
+++ b/Source/JavaScriptCore/runtime/TypeSet.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2014, 2015 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -47,7 +47,7 @@
RefPtr<StructureShape> newShape = prpNewShape;
m_seenTypes = m_seenTypes | type;
- if (structure && newShape && type != TypeString) {
+ if (structure && newShape && !runtimeTypeIsPrimitive(type)) {
if (!m_structureSet.contains(structure)) {
m_structureSet.add(structure);
// Make one more pass making sure that:
@@ -93,21 +93,23 @@
StringBuilder seen;
if (m_seenTypes & TypeFunction)
- seen.append("Function ");
+ seen.appendLiteral("Function ");
if (m_seenTypes & TypeUndefined)
- seen.append("Undefined ");
+ seen.appendLiteral("Undefined ");
if (m_seenTypes & TypeNull)
- seen.append("Null ");
+ seen.appendLiteral("Null ");
if (m_seenTypes & TypeBoolean)
- seen.append("Boolean ");
+ seen.appendLiteral("Boolean ");
if (m_seenTypes & TypeMachineInt)
- seen.append("MachineInt ");
+ seen.appendLiteral("MachineInt ");
if (m_seenTypes & TypeNumber)
- seen.append("Number ");
+ seen.appendLiteral("Number ");
if (m_seenTypes & TypeString)
- seen.append("String ");
+ seen.appendLiteral("String ");
if (m_seenTypes & TypeObject)
- seen.append("Object ");
+ seen.appendLiteral("Object ");
+ if (m_seenTypes & TypeSymbol)
+ seen.appendLiteral("Symbol ");
for (size_t i = 0; i < m_structureHistory.size(); i++) {
RefPtr<StructureShape> shape = m_structureHistory.at(i);
@@ -116,7 +118,7 @@
}
if (m_structureHistory.size())
- seen.append("\nStructures:[ ");
+ seen.appendLiteral("\nStructures:[ ");
for (size_t i = 0; i < m_structureHistory.size(); i++) {
seen.append(m_structureHistory.at(i)->stringRepresentation());
seen.append(' ');
@@ -125,14 +127,14 @@
seen.append(']');
if (m_structureHistory.size()) {
- seen.append("\nLeast Common Ancestor: ");
+ seen.appendLiteral("\nLeast Common Ancestor: ");
seen.append(leastCommonAncestor());
}
return seen.toString();
}
-bool TypeSet::doesTypeConformTo(uint8_t test) const
+bool TypeSet::doesTypeConformTo(RuntimeTypeMask test) const
{
// This function checks if our seen types conform to the types described by the test bitstring. (i.e we haven't seen more types than test).
// We are <= to those types if ANDing with the bitstring doesn't zero out any of our bits.
@@ -183,6 +185,8 @@
return ASCIILiteral("Number");
if (doesTypeConformTo(TypeString))
return ASCIILiteral("String");
+ if (doesTypeConformTo(TypeSymbol))
+ return ASCIILiteral("Symbol");
if (doesTypeConformTo(TypeNull | TypeUndefined))
return ASCIILiteral("(?)");
@@ -197,6 +201,8 @@
return ASCIILiteral("Number?");
if (doesTypeConformTo(TypeString | TypeNull | TypeUndefined))
return ASCIILiteral("String?");
+ if (doesTypeConformTo(TypeSymbol | TypeNull | TypeUndefined))
+ return ASCIILiteral("Symbol?");
if (doesTypeConformTo(TypeObject | TypeFunction | TypeString))
return ASCIILiteral("Object");
@@ -232,6 +238,7 @@
.setIsNumber((m_seenTypes & TypeNumber) != TypeNothing)
.setIsString((m_seenTypes & TypeString) != TypeNothing)
.setIsObject((m_seenTypes & TypeObject) != TypeNothing)
+ .setIsSymbol((m_seenTypes & TypeSymbol) != TypeNothing)
.release();
}
@@ -288,6 +295,12 @@
hasAnItem = true;
json.append("\"String\"");
}
+ if (m_seenTypes & TypeSymbol) {
+ if (hasAnItem)
+ json.append(",");
+ hasAnItem = true;
+ json.append("\"Symbol\"");
+ }
json.append("]");
json.append(",");
diff --git a/Source/JavaScriptCore/runtime/TypeSet.h b/Source/JavaScriptCore/runtime/TypeSet.h
index 9737602..2297f1d 100644
--- a/Source/JavaScriptCore/runtime/TypeSet.h
+++ b/Source/JavaScriptCore/runtime/TypeSet.h
@@ -94,12 +94,12 @@
String leastCommonAncestor() const;
Ref<Inspector::Protocol::Runtime::TypeSet> inspectorTypeSet() const;
bool isEmpty() const { return m_seenTypes == TypeNothing; }
- bool doesTypeConformTo(uint8_t test) const;
- uint8_t seenTypes() const { return m_seenTypes; }
+ bool doesTypeConformTo(RuntimeTypeMask test) const;
+ RuntimeTypeMask seenTypes() const { return m_seenTypes; }
StructureSet structureSet() const { return m_structureSet; };
private:
- uint8_t m_seenTypes;
+ RuntimeTypeMask m_seenTypes;
bool m_isOverflown;
Vector<RefPtr<StructureShape>> m_structureHistory;
StructureSet m_structureSet;
diff --git a/Source/JavaScriptCore/tests/typeProfiler/driver/driver.js b/Source/JavaScriptCore/tests/typeProfiler/driver/driver.js
index a48ee10..4ea44ad 100644
--- a/Source/JavaScriptCore/tests/typeProfiler/driver/driver.js
+++ b/Source/JavaScriptCore/tests/typeProfiler/driver/driver.js
@@ -7,6 +7,7 @@
Many: "(many)",
String: "String",
Undefined: "Undefined",
+ Symbol: "Symbol",
UndefinedOrNull: "(?)"
};
@@ -14,7 +15,8 @@
Boolean:"Boolean?",
Integer: "Integer?",
Number: "Number?",
- String: "String?"
+ String: "String?",
+ Symbol: "Symbol?"
};
function assert(condition, reason) {
diff --git a/Source/JavaScriptCore/tests/typeProfiler/symbol.js b/Source/JavaScriptCore/tests/typeProfiler/symbol.js
new file mode 100644
index 0000000..0686faa
--- /dev/null
+++ b/Source/JavaScriptCore/tests/typeProfiler/symbol.js
@@ -0,0 +1,44 @@
+load("./driver/driver.js");
+
+function wrapper() {
+ var s1 = Symbol();
+
+ var sCaptured = Symbol();
+ function foo() {
+ sCaptured = null;
+ }
+ foo();
+
+ function bar(s3) { return s3; }
+ for (var i = 0; i < 1000; i++)
+ bar(i)
+ bar(Symbol())
+
+ function baz(s4) { return s4; }
+ for (var i = 0; i < 1000; i++)
+ baz(Symbol())
+ baz("hello")
+}
+
+wrapper();
+
+// ====== End test cases ======
+
+var types = findTypeForExpression(wrapper, "s1");
+assert(types.instructionTypeSet.primitiveTypeNames.length === 1, "Primitive type names should contain one type");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Symbol) !== -1, "Primitive type names should contain 'Symbol'");
+
+types = findTypeForExpression(wrapper, "sCaptured");
+assert(types.globalTypeSet.primitiveTypeNames.length === 2, "Primitive type names should contain two items.");
+assert(types.globalTypeSet.primitiveTypeNames.indexOf(T.Symbol) !== -1, "Primitive type names should contain 'Symbol'");
+assert(types.globalTypeSet.primitiveTypeNames.indexOf(T.Null) !== -1, "Primitive type names should contain 'Null'");
+
+types = findTypeForExpression(wrapper, "s3");
+assert(types.instructionTypeSet.primitiveTypeNames.length === 2, "Primitive type names should contain 2 items");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Integer) !== -1, "Primitive type names should contain 'Integer'");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Symbol) !== -1, "Primitive type names should contain 'Symbol'");
+
+types = findTypeForExpression(wrapper, "s4");
+assert(types.instructionTypeSet.primitiveTypeNames.length === 2, "Primitive type names should contain 2 items");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.String) !== -1, "Primitive type names should contain 'String'");
+assert(types.instructionTypeSet.primitiveTypeNames.indexOf(T.Symbol) !== -1, "Primitive type names should contain 'Symbol'");