Support op_typeof in the DFG
https://bugs.webkit.org/show_bug.cgi?id=98898
Reviewed by Filip Pizlo.
Adds a TypeOf node to the DFG to support op_typeof.
To avoid adding too much GC horror, this also makes the
common strings portion of the SmallString cache strongly
referenced.
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
We try to determine the result early here, and substitute in a constant.
Otherwise we leave the node intact, and set the result type to SpecString.
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
Parse op_typeof
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::performNodeCSE):
TypeOf nodes can be subjected to pure CSE
* dfg/DFGCapabilities.h:
(JSC::DFG::canCompileOpcode):
We can handle typeof.
* dfg/DFGNodeType.h:
(DFG):
Define the node.
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
Add operationTypeOf to support the non-trivial cases.
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
Actual codegen
* runtime/Operations.cpp:
(JSC::jsTypeStringForValue):
(JSC):
* runtime/Operations.h:
(JSC):
Some refactoring to allow us to get the type string for an
object without needing a callframe.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@139145 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 1731f89..934961b 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,51 @@
+2013-01-08 Oliver Hunt <oliver@apple.com>
+
+ Support op_typeof in the DFG
+ https://bugs.webkit.org/show_bug.cgi?id=98898
+
+ Reviewed by Filip Pizlo.
+
+ Adds a TypeOf node to the DFG to support op_typeof.
+
+ To avoid adding too much GC horror, this also makes the
+ common strings portion of the SmallString cache strongly
+ referenced.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ We try to determine the result early here, and substitute in a constant.
+ Otherwise we leave the node intact, and set the result type to SpecString.
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ Parse op_typeof
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ TypeOf nodes can be subjected to pure CSE
+ * dfg/DFGCapabilities.h:
+ (JSC::DFG::canCompileOpcode):
+ We can handle typeof.
+ * dfg/DFGNodeType.h:
+ (DFG):
+ Define the node.
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ Add operationTypeOf to support the non-trivial cases.
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ Actual codegen
+ * runtime/Operations.cpp:
+ (JSC::jsTypeStringForValue):
+ (JSC):
+ * runtime/Operations.h:
+ (JSC):
+ Some refactoring to allow us to get the type string for an
+ object without needing a callframe.
+
+
2013-01-08 Filip Pizlo <fpizlo@apple.com>
DFG shouldn't treat the 'this' argument as being captured if a code block uses arguments
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 9585ae4..f42c105 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -31,6 +31,7 @@
#include "CodeBlock.h"
#include "DFGBasicBlock.h"
#include "GetByIdStatus.h"
+#include "Operations.h"
#include "PutByIdStatus.h"
namespace JSC { namespace DFG {
@@ -707,6 +708,11 @@
case IsString:
constantWasSet = trySetConstant(nodeIndex, jsBoolean(isJSString(child)));
break;
+ case IsObject:
+ if (child.isNull() || !child.isObject()) {
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(child.isNull()));
+ break;
+ }
default:
constantWasSet = false;
break;
@@ -716,9 +722,64 @@
break;
}
}
+
forNode(nodeIndex).set(SpecBoolean);
break;
}
+
+ case TypeOf: {
+ JSGlobalData* globalData = m_codeBlock->globalData();
+ JSValue child = forNode(node.child1()).value();
+ AbstractValue& abstractChild = forNode(node.child1());
+ if (child) {
+ JSValue typeString = jsTypeStringForValue(*globalData, m_codeBlock->globalObjectFor(node.codeOrigin), child);
+ if (trySetConstant(nodeIndex, typeString)) {
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isNumberSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.numberString())) {
+ forNode(node.child1()).filter(SpecNumber);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isStringSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.stringString())) {
+ forNode(node.child1()).filter(SpecString);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isFinalObjectSpeculation(abstractChild.m_type) || isArraySpeculation(abstractChild.m_type) || isArgumentsSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.objectString())) {
+ forNode(node.child1()).filter(SpecFinalObject | SpecArray | SpecArguments);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isFunctionSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.functionString())) {
+ forNode(node.child1()).filter(SpecFunction);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isBooleanSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.booleanString())) {
+ forNode(node.child1()).filter(SpecBoolean);
+ m_foundConstants = true;
+ break;
+ }
+ } else {
+ Node& childNode = m_graph[node.child1()];
+ if (isCellSpeculation(childNode.prediction())) {
+ if (isStringSpeculation(childNode.prediction()))
+ forNode(node.child1()).filter(SpecString);
+ else
+ forNode(node.child1()).filter(SpecCell);
+ node.setCanExit(true);
+ }
+ }
+ forNode(nodeIndex).set(SpecString);
+ break;
+ }
case CompareLess:
case CompareLessEq:
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index c0e028d..6cc05f6 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -3223,6 +3223,12 @@
NEXT_OPCODE(op_new_func_exp);
}
+ case op_typeof: {
+ set(currentInstruction[1].u.operand,
+ addToGraph(TypeOf, get(currentInstruction[2].u.operand)));
+ NEXT_OPCODE(op_typeof);
+ }
+
default:
// Parse failed! This should not happen because the capabilities checker
// should have caught it.
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index b7efb93..af52e89 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -597,6 +597,7 @@
case CreateThis:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
+ case TypeOf:
return NoNode;
case GetIndexedPropertyStorage:
@@ -1166,6 +1167,7 @@
case SkipScope:
case GetScopeRegisters:
case GetScope:
+ case TypeOf:
setReplacement(pureCSE(node));
break;
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.h b/Source/JavaScriptCore/dfg/DFGCapabilities.h
index 7d46102..0a39d66 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.h
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.h
@@ -198,6 +198,7 @@
case op_jneq_ptr:
case op_put_to_base_variable:
case op_put_to_base:
+ case op_typeof:
return CanCompile;
case op_call_varargs:
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 1d8e780..4afe163 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -214,6 +214,7 @@
macro(IsString, NodeResultBoolean) \
macro(IsObject, NodeResultBoolean) \
macro(IsFunction, NodeResultBoolean) \
+ macro(TypeOf, NodeResultJS) \
macro(LogicalNot, NodeResultBoolean) \
macro(ToPrimitive, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(StrCat, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 0bea7b5..884eb78 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1428,6 +1428,11 @@
return jsIsFunctionType(JSValue::decode(value));
}
+JSCell* DFG_OPERATION operationTypeOf(ExecState* exec, JSCell* value)
+{
+ return jsTypeStringForValue(exec, JSValue(value)).asCell();
+}
+
void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObject* base, Structure* structure, PropertyOffset offset, EncodedJSValue value)
{
JSGlobalData& globalData = exec->globalData();
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index fa6f65b..556041f 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -199,6 +199,7 @@
double DFG_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL;
size_t DFG_OPERATION operationIsObject(ExecState*, EncodedJSValue) WTF_INTERNAL;
size_t DFG_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL;
+JSCell* DFG_OPERATION operationTypeOf(ExecState*, JSCell*) WTF_INTERNAL;
void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL;
char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState*) WTF_INTERNAL;
char* DFG_OPERATION operationAllocatePropertyStorage(ExecState*, size_t newSize) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 1dcc6ae..64f788c 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -518,7 +518,13 @@
changed |= mergeDefaultFlags(node);
break;
}
-
+
+ case TypeOf: {
+ changed |= setPrediction(SpecString);
+ changed |= mergeDefaultFlags(node);
+ break;
+ }
+
case GetById: {
changed |= mergePrediction(node.getHeapPrediction());
changed |= mergeDefaultFlags(node);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index b350321..05ca69a 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4584,6 +4584,66 @@
booleanResult(result.gpr(), m_compileIndex);
break;
}
+ case TypeOf: {
+ JSValueOperand value(this, node.child1());
+ GPRReg tagGPR = value.tagGPR();
+ GPRReg payloadGPR = value.payloadGPR();
+ GPRTemporary temp(this);
+ GPRReg tempGPR = temp.gpr();
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+ JITCompiler::JumpList doneJumps;
+
+ flushRegisters();
+
+ JITCompiler::Jump isNotCell = m_jit.branch32(JITCompiler::NotEqual, tagGPR, JITCompiler::TrustedImm32(JSValue::CellTag));
+ Node& child = m_jit.graph()[node.child1()];
+ if (child.shouldSpeculateCell())
+ speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node.child1(), isNotCell);
+
+ if (!child.shouldSpeculateNonStringCell()) {
+ m_jit.loadPtr(JITCompiler::Address(payloadGPR, JSCell::structureOffset()), tempGPR);
+ JITCompiler::Jump notString = m_jit.branch8(JITCompiler::NotEqual, JITCompiler::Address(tempGPR, Structure::typeInfoTypeOffset()), TrustedImm32(StringType));
+ if (child.shouldSpeculateString())
+ speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node.child1(), notString);
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.stringString()), resultGPR);
+ doneJumps.append(m_jit.jump());
+ if (!child.shouldSpeculateString()) {
+ notString.link(&m_jit);
+ callOperation(operationTypeOf, resultGPR, payloadGPR);
+ doneJumps.append(m_jit.jump());
+ }
+ } else {
+ callOperation(operationTypeOf, resultGPR, payloadGPR);
+ doneJumps.append(m_jit.jump());
+ }
+
+ if (!child.shouldSpeculateCell()) {
+ isNotCell.link(&m_jit);
+
+ m_jit.add32(TrustedImm32(1), tagGPR, tempGPR);
+ JITCompiler::Jump notNumber = m_jit.branch32(JITCompiler::AboveOrEqual, tempGPR, JITCompiler::TrustedImm32(JSValue::LowestTag + 1));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.numberString()), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notNumber.link(&m_jit);
+
+ JITCompiler::Jump notUndefined = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::UndefinedTag));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.undefinedString()), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notUndefined.link(&m_jit);
+
+ JITCompiler::Jump notNull = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::NullTag));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.objectString()), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notNull.link(&m_jit);
+
+ // Only boolean left
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.booleanString()), resultGPR);
+ }
+ doneJumps.link(&m_jit);
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
case Phi:
case Flush:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 39c6331..dffbd08 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -4088,7 +4088,7 @@
cachedGetById(node.codeOrigin, baseGPR, resultGPR, node.identifierNumber(), notCell, DontSpill);
jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
-
+
break;
}
@@ -4511,6 +4511,64 @@
break;
}
+ case TypeOf: {
+ JSValueOperand value(this, node.child1());
+ GPRReg valueGPR = value.gpr();
+ GPRTemporary temp(this);
+ GPRReg tempGPR = temp.gpr();
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+ JITCompiler::JumpList doneJumps;
+
+ flushRegisters();
+
+ JITCompiler::Jump isNotCell = m_jit.branchTest64(JITCompiler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
+ Node& child = m_jit.graph()[node.child1()];
+ if (child.shouldSpeculateCell())
+ speculationCheck(BadType, JSValueSource(valueGPR), node.child1(), isNotCell);
+
+ if (!child.shouldSpeculateNonStringCell()) {
+ m_jit.loadPtr(JITCompiler::Address(valueGPR, JSCell::structureOffset()), tempGPR);
+ JITCompiler::Jump notString = m_jit.branch8(JITCompiler::NotEqual, JITCompiler::Address(tempGPR, Structure::typeInfoTypeOffset()), TrustedImm32(StringType));
+ if (child.shouldSpeculateString())
+ speculationCheck(BadType, JSValueSource(valueGPR), node.child1(), notString);
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.stringString()), resultGPR);
+ doneJumps.append(m_jit.jump());
+ if (!child.shouldSpeculateString()) {
+ notString.link(&m_jit);
+ callOperation(operationTypeOf, resultGPR, valueGPR);
+ doneJumps.append(m_jit.jump());
+ }
+ } else {
+ callOperation(operationTypeOf, resultGPR, valueGPR);
+ doneJumps.append(m_jit.jump());
+ }
+
+ if (!child.shouldSpeculateCell()) {
+ isNotCell.link(&m_jit);
+ JITCompiler::Jump notNumber = m_jit.branchTest64(JITCompiler::Zero, valueGPR, GPRInfo::tagTypeNumberRegister);
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.numberString()), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notNumber.link(&m_jit);
+
+ JITCompiler::Jump notUndefined = m_jit.branch64(JITCompiler::NotEqual, valueGPR, JITCompiler::TrustedImm64(ValueUndefined));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.undefinedString()), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notUndefined.link(&m_jit);
+
+ JITCompiler::Jump notNull = m_jit.branch64(JITCompiler::NotEqual, valueGPR, JITCompiler::TrustedImm64(ValueNull));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.objectString()), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notNull.link(&m_jit);
+
+ // Only boolean left
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.booleanString()), resultGPR);
+ }
+ doneJumps.link(&m_jit);
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
+
case Flush:
case Phi:
break;
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index 9ff318b..6cf7050 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -492,6 +492,8 @@
m_globalData->codeBlocksBeingCompiled[i]->visitAggregate(visitor);
}
+ m_globalData->smallStrings.visitStrongReferences(visitor);
+
{
GCPHASE(VisitMachineRoots);
MARK_LOG_ROOT(visitor, "C++ Stack");
diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
index a331c6c..94507f9 100644
--- a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
@@ -79,19 +79,19 @@
JSGlobalData* globalData = &exec->globalData();
JSValue thisValue = exec->hostThisValue();
if (thisValue == jsBoolean(false))
- return JSValue::encode(globalData->smallStrings.falseString(globalData));
+ return JSValue::encode(globalData->smallStrings.falseString());
if (thisValue == jsBoolean(true))
- return JSValue::encode(globalData->smallStrings.trueString(globalData));
+ return JSValue::encode(globalData->smallStrings.trueString());
if (!thisValue.inherits(&BooleanObject::s_info))
return throwVMTypeError(exec);
if (asBooleanObject(thisValue)->internalValue() == jsBoolean(false))
- return JSValue::encode(globalData->smallStrings.falseString(globalData));
+ return JSValue::encode(globalData->smallStrings.falseString());
ASSERT(asBooleanObject(thisValue)->internalValue() == jsBoolean(true));
- return JSValue::encode(globalData->smallStrings.trueString(globalData));
+ return JSValue::encode(globalData->smallStrings.trueString());
}
EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index 2dd8df8..8f0c895 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -230,6 +230,7 @@
unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull()));
unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull()));
unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull()));
+ smallStrings.initializeCommonStrings(*this);
wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
@@ -245,7 +246,7 @@
#endif
heap.notifyIsSafeToCollect();
-
+
LLInt::Data::performAssertions(*this);
if (Options::enableProfiler())
diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h
index 245c48a..c4ea552 100644
--- a/Source/JavaScriptCore/runtime/JSString.h
+++ b/Source/JavaScriptCore/runtime/JSString.h
@@ -333,7 +333,7 @@
inline JSString* jsEmptyString(JSGlobalData* globalData)
{
- return globalData->smallStrings.emptyString(globalData);
+ return globalData->smallStrings.emptyString();
}
ALWAYS_INLINE JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
@@ -386,7 +386,7 @@
{
int size = s.length();
if (!size)
- return globalData->smallStrings.emptyString(globalData);
+ return globalData->smallStrings.emptyString();
if (size == 1) {
UChar c = s.characterAt(0);
if (c <= maxSingleCharacterString)
@@ -402,7 +402,7 @@
ASSERT(offset + length <= static_cast<unsigned>(s->length()));
JSGlobalData* globalData = &exec->globalData();
if (!length)
- return globalData->smallStrings.emptyString(globalData);
+ return globalData->smallStrings.emptyString();
return jsSubstring(globalData, s->value(exec), offset, length);
}
@@ -412,7 +412,7 @@
ASSERT(length <= static_cast<unsigned>(s.length()));
ASSERT(offset + length <= static_cast<unsigned>(s.length()));
if (!length)
- return globalData->smallStrings.emptyString(globalData);
+ return globalData->smallStrings.emptyString();
if (length == 1) {
UChar c = s.characterAt(offset);
if (c <= maxSingleCharacterString)
@@ -427,7 +427,7 @@
ASSERT(length <= static_cast<unsigned>(s.length()));
ASSERT(offset + length <= static_cast<unsigned>(s.length()));
if (!length)
- return globalData->smallStrings.emptyString(globalData);
+ return globalData->smallStrings.emptyString();
if (length == 1) {
UChar c = s.characterAt(offset);
if (c <= maxSingleCharacterString)
@@ -440,7 +440,7 @@
{
int size = s.length();
if (!size)
- return globalData->smallStrings.emptyString(globalData);
+ return globalData->smallStrings.emptyString();
if (size == 1) {
UChar c = s.characterAt(0);
if (c <= maxSingleCharacterString)
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
index 6b4ff0f..457eb0a 100644
--- a/Source/JavaScriptCore/runtime/JSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -295,13 +295,13 @@
if (isDouble())
return jsString(&globalData, globalData.numericStrings.add(asDouble()));
if (isTrue())
- return globalData.smallStrings.trueString(&globalData);
+ return globalData.smallStrings.trueString();
if (isFalse())
- return globalData.smallStrings.falseString(&globalData);
+ return globalData.smallStrings.falseString();
if (isNull())
- return globalData.smallStrings.nullString(&globalData);
+ return globalData.smallStrings.nullString();
if (isUndefined())
- return globalData.smallStrings.undefinedString(&globalData);
+ return globalData.smallStrings.undefinedString();
ASSERT(isCell());
JSValue value = asCell()->toPrimitive(exec, PreferString);
diff --git a/Source/JavaScriptCore/runtime/Operations.cpp b/Source/JavaScriptCore/runtime/Operations.cpp
index d96bae5..3dccb2a 100644
--- a/Source/JavaScriptCore/runtime/Operations.cpp
+++ b/Source/JavaScriptCore/runtime/Operations.cpp
@@ -56,28 +56,32 @@
return jsNumber(p1.toNumber(callFrame) + p2.toNumber(callFrame));
}
-JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
+JSValue jsTypeStringForValue(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue v)
{
- JSGlobalData& globalData = callFrame->globalData();
if (v.isUndefined())
- return globalData.smallStrings.undefinedString(&globalData);
+ return globalData.smallStrings.undefinedString();
if (v.isBoolean())
- return globalData.smallStrings.booleanString(&globalData);
+ return globalData.smallStrings.booleanString();
if (v.isNumber())
- return globalData.smallStrings.numberString(&globalData);
+ return globalData.smallStrings.numberString();
if (v.isString())
- return globalData.smallStrings.stringString(&globalData);
+ return globalData.smallStrings.stringString();
if (v.isObject()) {
// Return "undefined" for objects that should be treated
// as null when doing comparisons.
- if (asObject(v)->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject()))
- return globalData.smallStrings.undefinedString(&globalData);
+ if (asObject(v)->structure()->masqueradesAsUndefined(globalObject))
+ return globalData.smallStrings.undefinedString();
CallData callData;
JSObject* object = asObject(v);
if (object->methodTable()->getCallData(object, callData) != CallTypeNone)
- return globalData.smallStrings.functionString(&globalData);
+ return globalData.smallStrings.functionString();
}
- return globalData.smallStrings.objectString(&globalData);
+ return globalData.smallStrings.objectString();
+}
+
+JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
+{
+ return jsTypeStringForValue(callFrame->globalData(), callFrame->lexicalGlobalObject(), v);
}
bool jsIsObjectType(CallFrame* callFrame, JSValue v)
diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h
index 8e0a0a3..4ff0741 100644
--- a/Source/JavaScriptCore/runtime/Operations.h
+++ b/Source/JavaScriptCore/runtime/Operations.h
@@ -32,6 +32,7 @@
NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
JSValue jsTypeStringForValue(CallFrame*, JSValue);
+ JSValue jsTypeStringForValue(JSGlobalData&, JSGlobalObject*, JSValue);
bool jsIsObjectType(CallFrame*, JSValue);
bool jsIsFunctionType(JSValue);
diff --git a/Source/JavaScriptCore/runtime/SmallStrings.cpp b/Source/JavaScriptCore/runtime/SmallStrings.cpp
index 56a3592..6552d7c 100644
--- a/Source/JavaScriptCore/runtime/SmallStrings.cpp
+++ b/Source/JavaScriptCore/runtime/SmallStrings.cpp
@@ -80,6 +80,22 @@
m_singleCharacterStrings[i] = 0;
}
+void SmallStrings::initializeCommonStrings(JSGlobalData& globalData)
+{
+ createEmptyString(&globalData);
+#define JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE(name) initialize(&globalData, m_##name, #name);
+ JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE)
+#undef JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE
+}
+
+void SmallStrings::visitStrongReferences(SlotVisitor& visitor)
+{
+ visitor.appendUnbarrieredPointer(&m_emptyString);
+#define JSC_COMMON_STRINGS_ATTRIBUTE_VISIT(name) visitor.appendUnbarrieredPointer(&m_##name);
+ JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_VISIT)
+#undef JSC_COMMON_STRINGS_ATTRIBUTE_VISIT
+}
+
SmallStrings::~SmallStrings()
{
}
@@ -89,9 +105,6 @@
finalize(m_emptyString);
for (unsigned i = 0; i < singleCharacterStringCount; ++i)
finalize(m_singleCharacterStrings[i]);
-#define JSC_COMMON_STRINGS_ATTRIBUTE_FINALIZE(name) finalize(m_##name);
- JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_FINALIZE)
-#undef JSC_COMMON_STRINGS_ATTRIBUTE_FINALIZE
}
void SmallStrings::createEmptyString(JSGlobalData* globalData)
diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h
index 5bc9d22..3fc9b3c 100644
--- a/Source/JavaScriptCore/runtime/SmallStrings.h
+++ b/Source/JavaScriptCore/runtime/SmallStrings.h
@@ -26,6 +26,8 @@
#ifndef SmallStrings_h
#define SmallStrings_h
+#include "WriteBarrier.h"
+
#include <wtf/FixedArray.h>
#include <wtf/Noncopyable.h>
#include <wtf/OwnPtr.h>
@@ -61,10 +63,8 @@
SmallStrings();
~SmallStrings();
- JSString* emptyString(JSGlobalData* globalData)
+ JSString* emptyString()
{
- if (!m_emptyString)
- createEmptyString(globalData);
return m_emptyString;
}
@@ -81,11 +81,12 @@
JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; }
+ void initializeCommonStrings(JSGlobalData&);
+ void visitStrongReferences(SlotVisitor&);
+
#define JSC_COMMON_STRINGS_ACCESSOR_DEFINITION(name) \
- JSString* name##String(JSGlobalData* globalData) const \
+ JSString* name##String() const \
{ \
- if (!m_##name) \
- initialize(globalData, m_##name, #name); \
return m_##name; \
}
JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ACCESSOR_DEFINITION)
@@ -100,7 +101,7 @@
void initialize(JSGlobalData* globalData, JSString*& string, const char* value) const;
JSString* m_emptyString;
-#define JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION(name) mutable JSString* m_##name;
+#define JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION(name) JSString* m_##name;
JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION)
#undef JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION
JSString* m_singleCharacterStrings[singleCharacterStringCount];