diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
commit | 49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch) | |
tree | 5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/JavaScriptCore/bytecompiler | |
parent | b211c645d8ab690f713515dfdc84d80b11c27d2c (diff) | |
download | qtwebkit-49233e234e5c787396cadb2cea33b31ae0cd65c1.tar.gz |
Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813)
New snapshot with Windows build fixes
Diffstat (limited to 'Source/JavaScriptCore/bytecompiler')
3 files changed, 102 insertions, 41 deletions
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index fb05e48ff..8969a7f25 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -148,6 +148,7 @@ void ResolveResult::checkValidity() return; case IndexedGlobal: case ReadOnlyIndexedGlobal: + case WatchedIndexedGlobal: case DynamicIndexedGlobal: case DynamicReadOnlyIndexedGlobal: ASSERT(m_index != missingSymbolMarker()); @@ -161,6 +162,11 @@ void ResolveResult::checkValidity() } #endif +WriteBarrier<Unknown>* ResolveResult::registerPointer() const +{ + return &jsCast<JSGlobalObject*>(globalObject())->registerAt(index()); +} + static bool s_dumpsGeneratedCode = false; void BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode) @@ -211,13 +217,19 @@ bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, Registe return true; } -int BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant) +int BytecodeGenerator::addGlobalVar( + const Identifier& ident, ConstantMode constantMode, FunctionMode functionMode) { + UNUSED_PARAM(functionMode); int index = symbolTable().size(); - SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); + SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0); + if (functionMode == IsFunctionToSpecialize) + newEntry.attemptToWatch(); SymbolTable::AddResult result = symbolTable().add(ident.impl(), newEntry); - if (!result.isNewEntry) + if (!result.isNewEntry) { + result.iterator->second.notifyWrite(); index = result.iterator->second.getIndex(); + } return index; } @@ -280,21 +292,27 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* s size_t newGlobals = varStack.size() + functionStack.size(); if (!newGlobals) return; - globalObject->resizeRegisters(symbolTable->size() + newGlobals); + globalObject->addRegisters(newGlobals); for (size_t i = 0; i < functionStack.size(); ++i) { FunctionBodyNode* function = functionStack[i]; - globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties. - + bool propertyDidExist = + globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties. + JSValue value = JSFunction::create(exec, makeFunction(exec, function), scopeChain); - int index = addGlobalVar(function->ident(), false); + int index = addGlobalVar( + function->ident(), IsVariable, + !propertyDidExist ? IsFunctionToSpecialize : NotFunctionOrNotSpecializable); globalObject->registerAt(index).set(*m_globalData, globalObject, value); } for (size_t i = 0; i < varStack.size(); ++i) { if (globalObject->hasProperty(exec, *varStack[i].first)) continue; - addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant); + addGlobalVar( + *varStack[i].first, + (varStack[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable, + NotFunctionOrNotSpecializable); } } @@ -679,6 +697,14 @@ void BytecodeGenerator::retrieveLastUnaryOp(int& dstIndex, int& srcIndex) srcIndex = instructions().at(size - 1).u.operand; } +void BytecodeGenerator::retrieveLastUnaryOp(WriteBarrier<Unknown>*& dstPointer, int& srcIndex) +{ + ASSERT(instructions().size() >= 3); + size_t size = instructions().size(); + dstPointer = instructions().at(size - 2).u.registerPointer; + srcIndex = instructions().at(size - 1).u.operand; +} + void ALWAYS_INLINE BytecodeGenerator::rewindBinaryOp() { ASSERT(instructions().size() >= 4); @@ -1170,6 +1196,7 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property) ScopeChainIterator iter = m_scopeChain->begin(); ScopeChainIterator end = m_scopeChain->end(); size_t depth = 0; + size_t depthOfFirstScopeWithDynamicChecks = 0; unsigned flags = 0; for (; iter != end; ++iter, ++depth) { JSObject* currentScope = iter->get(); @@ -1177,7 +1204,7 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property) flags |= ResolveResult::DynamicFlag; break; } - JSVariableObject* currentVariableObject = jsCast<JSVariableObject*>(currentScope); + JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope); SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); // Found the property @@ -1188,7 +1215,9 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property) if (++iter == end) { if (flags & ResolveResult::DynamicFlag) return ResolveResult::dynamicIndexedGlobalResolve(entry.getIndex(), depth, currentScope, flags); - return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentScope, flags); + return ResolveResult::indexedGlobalResolve( + entry.getIndex(), currentScope, + flags | (entry.couldBeWatched() ? ResolveResult::WatchedFlag : 0)); } #if !ASSERT_DISABLED if (JSActivation* activation = jsDynamicCast<JSActivation*>(currentVariableObject)) @@ -1199,19 +1228,27 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property) bool scopeRequiresDynamicChecks = false; if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks)) break; - if (scopeRequiresDynamicChecks) - flags |= ResolveResult::DynamicFlag; + if (!(flags & ResolveResult::DynamicFlag)) { + if (scopeRequiresDynamicChecks) + flags |= ResolveResult::DynamicFlag; + else + ++depthOfFirstScopeWithDynamicChecks; + } } // Can't locate the property but we're able to avoid a few lookups. JSObject* scope = iter->get(); + // Step over the function's activation, if it needs one. At this point we + // know there is no dynamic scope in the function itself, so this is safe to + // do. depth += m_codeBlock->needsFullScopeChain(); + depthOfFirstScopeWithDynamicChecks += m_codeBlock->needsFullScopeChain(); if (++iter == end) { if ((flags & ResolveResult::DynamicFlag) && depth) return ResolveResult::dynamicGlobalResolve(depth, scope); return ResolveResult::globalResolve(scope); } - return ResolveResult::dynamicResolve(depth); + return ResolveResult::dynamicResolve(depthOfFirstScopeWithDynamicChecks); } ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property) @@ -1234,7 +1271,7 @@ ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property) JSObject* currentScope = iter->get(); if (!currentScope->isVariableObject()) continue; - JSVariableObject* currentVariableObject = jsCast<JSVariableObject*>(currentScope); + JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope); SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); if (entry.isNull()) continue; @@ -1274,7 +1311,7 @@ bool BytecodeGenerator::shouldAvoidResolveGlobal() RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) { if (resolveResult.isStatic()) - return emitGetStaticVar(dst, resolveResult); + return emitGetStaticVar(dst, resolveResult, property); if (resolveResult.isGlobal() && !shouldAvoidResolveGlobal()) { #if ENABLE(JIT) @@ -1357,7 +1394,7 @@ RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, Register if (resolveResult.isStatic()) { // Directly index the property lookup across multiple scopes. - emitGetStaticVar(propDst, resolveResult); + emitGetStaticVar(propDst, resolveResult, property); return baseDst; } @@ -1396,7 +1433,7 @@ RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, Register { if (resolveResult.isStatic()) { emitLoad(baseDst, jsUndefined()); - emitGetStaticVar(propDst, resolveResult); + emitGetStaticVar(propDst, resolveResult, property); return baseDst; } @@ -1414,7 +1451,7 @@ RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, Register return emitResolve(propDst, resolveResult, property); } -RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult) +RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& identifier) { ValueProfile* profile = 0; @@ -1437,16 +1474,27 @@ RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveRe case ResolveResult::IndexedGlobal: case ResolveResult::ReadOnlyIndexedGlobal: if (m_lastOpcodeID == op_put_global_var) { - int dstIndex; + WriteBarrier<Unknown>* dstPointer; int srcIndex; - retrieveLastUnaryOp(dstIndex, srcIndex); - if (dstIndex == resolveResult.index() && srcIndex == dst->index()) + retrieveLastUnaryOp(dstPointer, srcIndex); + if (dstPointer == resolveResult.registerPointer() && srcIndex == dst->index()) return dst; } profile = emitProfiledOpcode(op_get_global_var); instructions().append(dst->index()); - instructions().append(resolveResult.index()); + instructions().append(resolveResult.registerPointer()); + instructions().append(profile); + return dst; + + case ResolveResult::WatchedIndexedGlobal: + // Skip the peephole for now. It's not clear that it's profitable given + // the DFG's capabilities, and the fact that if it's watchable then we + // don't expect to see any put_global_var's anyway. + profile = emitProfiledOpcode(op_get_global_var_watchable); + instructions().append(dst->index()); + instructions().append(resolveResult.registerPointer()); + instructions().append(addConstant(identifier)); // For the benefit of the DFG. instructions().append(profile); return dst; @@ -1456,7 +1504,7 @@ RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveRe } } -RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, RegisterID* value) +RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, const Identifier& identifier, RegisterID* value) { switch (resolveResult.type()) { case ResolveResult::Register: @@ -1474,8 +1522,16 @@ RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResu case ResolveResult::IndexedGlobal: case ResolveResult::ReadOnlyIndexedGlobal: emitOpcode(op_put_global_var); - instructions().append(resolveResult.index()); + instructions().append(resolveResult.registerPointer()); + instructions().append(value->index()); + return value; + + case ResolveResult::WatchedIndexedGlobal: + emitOpcode(op_put_global_var_check); + instructions().append(resolveResult.registerPointer()); instructions().append(value->index()); + instructions().append(jsCast<JSGlobalObject*>(resolveResult.globalObject())->symbolTable().get(identifier.impl()).addressOfIsWatched()); + instructions().append(addConstant(identifier)); return value; default: diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index a71bbb785..8b1d1d744 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -111,7 +111,9 @@ namespace JSC { // The resolved binding is immutable. ReadOnlyFlag = 0x20, // The base object is the global object. - GlobalFlag = 0x40 + GlobalFlag = 0x40, + // The property is being watched, so writes should be special. + WatchedFlag = 0x80 }; enum Type { // The property is local, and stored in a register. @@ -131,6 +133,8 @@ namespace JSC { // binding created with "var" at the top level. At runtime we'll // just index into the global object. IndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag, + // Like IndexedGlobal, but the property is being watched. + WatchedIndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag | WatchedFlag, // Like IndexedGlobal, but the property is also read-only, like NaN, // Infinity, or undefined. ReadOnlyIndexedGlobal = IndexedFlag | ReadOnlyFlag | GlobalFlag | StaticFlag, @@ -197,6 +201,7 @@ namespace JSC { int index() const { ASSERT (isIndexed() || isRegister()); return m_index; } size_t depth() const { ASSERT(isScoped()); return m_depth; } JSObject* globalObject() const { ASSERT(isGlobal()); ASSERT(m_globalObject); return m_globalObject; } + WriteBarrier<Unknown>* registerPointer() const; bool isRegister() const { return m_type & RegisterFlag; } bool isDynamic() const { return m_type & DynamicFlag; } @@ -440,8 +445,8 @@ namespace JSC { RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } - RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&); - RegisterID* emitPutStaticVar(const ResolveResult&, RegisterID* value); + RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&, const Identifier&); + RegisterID* emitPutStaticVar(const ResolveResult&, const Identifier&, RegisterID* value); RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property); RegisterID* emitResolveBase(RegisterID* dst, const ResolveResult&, const Identifier& property); @@ -541,6 +546,7 @@ namespace JSC { ValueProfile* emitProfiledOpcode(OpcodeID); void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); + void retrieveLastUnaryOp(WriteBarrier<Unknown>*& dstPointer, int& srcIndex); ALWAYS_INLINE void rewindBinaryOp(); ALWAYS_INLINE void rewindUnaryOp(); @@ -572,7 +578,9 @@ namespace JSC { } // Returns the index of the added var. - int addGlobalVar(const Identifier&, bool isConstant); + enum ConstantMode { IsConstant, IsVariable }; + enum FunctionMode { IsFunctionToSpecialize, NotFunctionOrNotSpecializable }; + int addGlobalVar(const Identifier&, ConstantMode, FunctionMode); void addParameter(const Identifier&, int parameterIndex); @@ -608,10 +616,7 @@ namespace JSC { void addLineInfo(unsigned lineNo) { -#if !ENABLE(OPCODE_SAMPLING) - if (m_shouldEmitRichSourceInfo) -#endif - m_codeBlock->addLineInfo(instructions().size(), lineNo); + m_codeBlock->addLineInfo(instructions().size(), lineNo); } RegisterID* emitInitLazyRegister(RegisterID*); diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp index 4f113f776..d243e8ce0 100644 --- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -430,7 +430,7 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, if (resolveResult.isStatic()) { RefPtr<RegisterID> func = generator.newTemporary(); CallArguments callArguments(generator, m_args); - generator.emitGetStaticVar(func.get(), resolveResult); + generator.emitGetStaticVar(func.get(), resolveResult, m_ident); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } @@ -618,7 +618,7 @@ RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, Regis } if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { - RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult); + RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, m_ident); RegisterID* oldValue; if (dst == generator.ignoredResult()) { oldValue = 0; @@ -626,7 +626,7 @@ RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, Regis } else { oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); } - generator.emitPutStaticVar(resolveResult, value.get()); + generator.emitPutStaticVar(resolveResult, m_ident, value.get()); return oldValue; } @@ -803,9 +803,9 @@ RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, Regist } if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { - RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult); + RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident); emitPreIncOrDec(generator, propDst.get(), m_operator); - generator.emitPutStaticVar(resolveResult, propDst.get()); + generator.emitPutStaticVar(resolveResult, m_ident, propDst.get()); return generator.moveToDestinationIfNeeded(dst, propDst.get()); } @@ -1226,9 +1226,9 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re } if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { - RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult); + RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident); RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitPutStaticVar(resolveResult, result); + generator.emitPutStaticVar(resolveResult, m_ident, result); return result; } @@ -1256,7 +1256,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist if (dst == generator.ignoredResult()) dst = 0; RegisterID* value = generator.emitNode(dst, m_right); - generator.emitPutStaticVar(resolveResult, value); + generator.emitPutStaticVar(resolveResult, m_ident, value); return value; } @@ -1361,7 +1361,7 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); if (resolveResult.isStatic()) - return generator.emitPutStaticVar(resolveResult, value.get()); + return generator.emitPutStaticVar(resolveResult, m_ident, value.get()); if (generator.codeType() != EvalCode) return value.get(); |