WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
with fixes
blah.patch (text/plain), 115.57 KB, created by
Filip Pizlo
on 2015-03-31 13:06:26 PDT
(
hide
)
Description:
with fixes
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2015-03-31 13:06:26 PDT
Size:
115.57 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 182191) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,197 @@ >+2015-03-31 Filip Pizlo <fpizlo@apple.com> >+ >+ JSC should detect singleton functions >+ https://bugs.webkit.org/show_bug.cgi?id=143232 >+ >+ Reviewed by Michael Saboff. >+ >+ This started out as an attempt to make constructors faster by detecting when a constructor is a >+ singleton. The idea is that each FunctionExecutable has a VariableWatchpointSet - a watchpoint >+ along with an inferred value - that detects if only one JSFunction has been allocated for that >+ executable, and if so, what that JSFunction is. Then, inside the code for the FunctionExecutable, >+ if the watchpoint set has an inferred value (i.e. it's been initialized and it is still valid), >+ we can constant-fold GetCallee. >+ >+ Unfortunately, constructors don't use GetCallee anymore, so that didn't pan out. But in the >+ process I realized three things: >+ >+ - This allows us to completely eliminate the GetCallee/GetScope sequence that we still sometimes >+ had even in code where our singleton-closure detection worked. That's because singleton-closure >+ inference worked at the op_resolve_scope, and that op_resolve_scope still needed to keep alive >+ the incoming scope in case we OSR exit. But by constant-folding GetCallee, that sequence >+ disappears. OSR exit can rematerialize the callee or the scope by just knowing their constant >+ values. >+ >+ - This allows us to eliminate the function reentry watchpoint. That watchpoint inferred singleton >+ closures. But we don't need to infer singleton closures, if we are inferring singleton callees. >+ So, that kills a bunch of code. >+ >+ - This allows us to use a normal WatchpointSet, instead of a VariableWatchpointSet, for inferring >+ constant values in scopes. Previously when the DFG inferred that a closure variable was >+ constant, it wouldn't know which closure that variable was in and so it couldn't just load that >+ value. But now we are first inferring that the function is a singleton, which means that we >+ know exactly what scope it points to, and we can load the value from the scope. Using a >+ WatchpointSet instead of a VariableWatchpointSet saves some memory and simplifies a bunch of >+ code. This also means that now, the only user of VariableWatchpointSet is FunctionExecutable. >+ I've tweaked the code of VariableWatchpointSet to reduce its power to just be what >+ FunctionExecutable wants. >+ >+ This also has the effect of simplifying the implementation of block scoping. Prior to this >+ change, block scoping would had had to have some story for the function reentry watchpoint on any >+ nested symbol table. That's totally weird to think about; it's not really a function reentry but >+ a scope reentry. Now we don't have to think about this. Constant inference on nested scopes will >+ "just work": if we prove that we know the constant value of the scope then the machinery kicks >+ in, otherwise it doesn't. >+ >+ * CMakeLists.txt: >+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * bytecode/BytecodeList.json: >+ * bytecode/BytecodeUseDef.h: >+ (JSC::computeUsesForBytecodeOffset): >+ (JSC::computeDefsForBytecodeOffset): >+ * bytecode/CodeBlock.cpp: >+ (JSC::CodeBlock::dumpBytecode): >+ (JSC::CodeBlock::CodeBlock): >+ (JSC::CodeBlock::finalizeUnconditionally): >+ * bytecode/CodeOrigin.cpp: >+ (JSC::InlineCallFrame::calleeConstant): >+ (JSC::InlineCallFrame::visitAggregate): >+ * bytecode/CodeOrigin.h: >+ (JSC::InlineCallFrame::calleeConstant): Deleted. >+ (JSC::InlineCallFrame::visitAggregate): Deleted. >+ * bytecode/Instruction.h: >+ * bytecode/VariableWatchpointSet.cpp: >+ (JSC::VariableWatchpointSet::notifyWrite): >+ (JSC::VariableWriteFireDetail::dump): Deleted. >+ * bytecode/VariableWatchpointSet.h: >+ (JSC::VariableWatchpointSet::VariableWatchpointSet): >+ (JSC::VariableWatchpointSet::needToFinalize): >+ (JSC::VariableWatchpointSet::finalizeUnconditionally): >+ (JSC::VariableWriteFireDetail::VariableWriteFireDetail): Deleted. >+ * bytecode/VariableWatchpointSetInlines.h: >+ (JSC::VariableWatchpointSet::notifyWrite): >+ * bytecode/VariableWriteFireDetail.cpp: Added. >+ (JSC::VariableWriteFireDetail::dump): >+ * bytecode/VariableWriteFireDetail.h: Added. >+ (JSC::VariableWriteFireDetail::VariableWriteFireDetail): >+ * bytecode/Watchpoint.h: >+ (JSC::WatchpointSet::startWatching): >+ (JSC::WatchpointSet::fireAll): >+ (JSC::WatchpointSet::touch): >+ (JSC::WatchpointSet::invalidate): >+ (JSC::InlineWatchpointSet::touch): >+ * bytecompiler/BytecodeGenerator.cpp: >+ (JSC::BytecodeGenerator::BytecodeGenerator): >+ (JSC::BytecodeGenerator::emitResolveScope): >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::get): >+ (JSC::DFG::ByteCodeParser::getScope): >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ * dfg/DFGCapabilities.cpp: >+ (JSC::DFG::capabilityLevel): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGGraph.cpp: >+ (JSC::DFG::Graph::dump): >+ (JSC::DFG::Graph::tryGetConstantClosureVar): >+ * dfg/DFGNode.h: >+ (JSC::DFG::Node::hasWatchpointSet): >+ (JSC::DFG::Node::watchpointSet): >+ (JSC::DFG::Node::hasVariableWatchpointSet): Deleted. >+ (JSC::DFG::Node::variableWatchpointSet): Deleted. >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileNewFunction): >+ (JSC::DFG::SpeculativeJIT::compileNotifyWrite): >+ * dfg/DFGSpeculativeJIT.h: >+ (JSC::DFG::SpeculativeJIT::callOperation): >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGVarargsForwardingPhase.cpp: >+ * ftl/FTLIntrinsicRepository.h: >+ * ftl/FTLLowerDFGToLLVM.cpp: >+ (JSC::FTL::LowerDFGToLLVM::compileNotifyWrite): >+ * interpreter/Interpreter.cpp: >+ (JSC::StackFrame::friendlySourceURL): >+ (JSC::StackFrame::friendlyFunctionName): >+ * interpreter/Interpreter.h: >+ (JSC::StackFrame::friendlySourceURL): Deleted. >+ (JSC::StackFrame::friendlyFunctionName): Deleted. >+ * jit/JIT.cpp: >+ (JSC::JIT::emitNotifyWrite): >+ (JSC::JIT::privateCompileMainPass): >+ * jit/JIT.h: >+ * jit/JITOpcodes.cpp: >+ (JSC::JIT::emit_op_touch_entry): Deleted. >+ * jit/JITOperations.cpp: >+ * jit/JITOperations.h: >+ * jit/JITPropertyAccess.cpp: >+ (JSC::JIT::emitPutGlobalVar): >+ (JSC::JIT::emitPutClosureVar): >+ (JSC::JIT::emitNotifyWrite): Deleted. >+ * jit/JITPropertyAccess32_64.cpp: >+ (JSC::JIT::emitPutGlobalVar): >+ (JSC::JIT::emitPutClosureVar): >+ (JSC::JIT::emitNotifyWrite): Deleted. >+ * llint/LLIntSlowPaths.cpp: >+ (JSC::LLInt::LLINT_SLOW_PATH_DECL): >+ * llint/LowLevelInterpreter.asm: >+ * llint/LowLevelInterpreter32_64.asm: >+ * llint/LowLevelInterpreter64.asm: >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::SLOW_PATH_DECL): Deleted. >+ * runtime/CommonSlowPaths.h: >+ * runtime/Executable.cpp: >+ (JSC::FunctionExecutable::visitChildren): >+ (JSC::FunctionExecutable::WatchpointCleanup::WatchpointCleanup): >+ (JSC::FunctionExecutable::WatchpointCleanup::~WatchpointCleanup): >+ (JSC::FunctionExecutable::WatchpointCleanup::finalizeUnconditionally): >+ * runtime/Executable.h: >+ (JSC::FunctionExecutable::functionReallocationWatchpointSet): >+ * runtime/JSCInlines.h: >+ * runtime/JSFunction.cpp: >+ (JSC::JSFunction::create): >+ * runtime/JSFunction.h: >+ (JSC::JSFunction::createWithInvalidatedReallocationWatchpoint): >+ (JSC::JSFunction::createImpl): >+ (JSC::JSFunction::create): Deleted. >+ * runtime/JSGlobalObject.cpp: >+ (JSC::JSGlobalObject::addGlobalVar): >+ (JSC::JSGlobalObject::addFunction): >+ * runtime/JSGlobalObject.h: >+ * runtime/JSLexicalEnvironment.cpp: >+ (JSC::JSLexicalEnvironment::symbolTablePut): >+ * runtime/JSScope.h: >+ (JSC::ResolveOp::ResolveOp): >+ * runtime/JSSymbolTableObject.h: >+ (JSC::symbolTablePut): >+ (JSC::symbolTablePutWithAttributes): >+ * runtime/PutPropertySlot.h: >+ * runtime/SymbolTable.cpp: >+ (JSC::SymbolTableEntry::prepareToWatch): >+ (JSC::SymbolTable::SymbolTable): >+ (JSC::SymbolTable::visitChildren): >+ (JSC::SymbolTableEntry::inferredValue): Deleted. >+ (JSC::SymbolTableEntry::notifyWriteSlow): Deleted. >+ (JSC::SymbolTable::WatchpointCleanup::WatchpointCleanup): Deleted. >+ (JSC::SymbolTable::WatchpointCleanup::~WatchpointCleanup): Deleted. >+ (JSC::SymbolTable::WatchpointCleanup::finalizeUnconditionally): Deleted. >+ * runtime/SymbolTable.h: >+ (JSC::SymbolTableEntry::disableWatching): >+ (JSC::SymbolTableEntry::watchpointSet): >+ (JSC::SymbolTableEntry::notifyWrite): Deleted. >+ * runtime/TypeProfiler.cpp: >+ * tests/stress/infer-uninitialized-closure-var.js: Added. >+ * tests/stress/singleton-scope-then-overwrite.js: Added. >+ * tests/stress/singleton-scope-then-realloc-and-overwrite.js: Added. >+ * tests/stress/singleton-scope-then-realloc.js: Added. >+ > 2015-03-31 Yusuke Suzuki <utatane.tea@gmail.com> > > [ES6] Object type restrictions on a first parameter of several Object.* functions are relaxed >Index: Source/JavaScriptCore/CMakeLists.txt >=================================================================== >--- Source/JavaScriptCore/CMakeLists.txt (revision 182069) >+++ Source/JavaScriptCore/CMakeLists.txt (working copy) >@@ -106,6 +106,7 @@ set(JavaScriptCore_SOURCES > bytecode/UnlinkedInstructionStream.cpp > bytecode/ValueRecovery.cpp > bytecode/VariableWatchpointSet.cpp >+ bytecode/VariableWriteFireDetail.cpp > bytecode/VirtualRegister.cpp > bytecode/Watchpoint.cpp > >Index: Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (revision 182069) >+++ Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (working copy) >@@ -353,6 +353,7 @@ > <ClCompile Include="..\bytecode\UnlinkedInstructionStream.cpp" /> > <ClCompile Include="..\bytecode\ValueRecovery.cpp" /> > <ClCompile Include="..\bytecode\VariableWatchpointSet.cpp" /> >+ <ClCompile Include="..\bytecode\VariableWriteFireDetail.cpp" /> > <ClCompile Include="..\bytecode\VirtualRegister.cpp" /> > <ClCompile Include="..\bytecode\Watchpoint.cpp" /> > <ClCompile Include="..\bytecompiler\BytecodeGenerator.cpp" /> >@@ -1005,6 +1006,7 @@ > <ClInclude Include="..\bytecode\ValueProfile.h" /> > <ClInclude Include="..\bytecode\ValueRecovery.h" /> > <ClInclude Include="..\bytecode\VariableWatchpointSet.h" /> >+ <ClInclude Include="..\bytecode\VariableWriteFireDetail.h" /> > <ClInclude Include="..\bytecode\VirtualRegister.h" /> > <ClInclude Include="..\bytecode\Watchpoint.h" /> > <ClInclude Include="..\bytecompiler\BytecodeGenerator.h" /> >Index: Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (revision 182069) >+++ Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (working copy) >@@ -383,6 +383,8 @@ > 0F6B1CC61862C47800845D97 /* FTLUnwindInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CC21862C47800845D97 /* FTLUnwindInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 0F6B1CC918641DF800845D97 /* ArityCheckFailReturnThunks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */; }; > 0F6B1CCA18641DF800845D97 /* ArityCheckFailReturnThunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CC818641DF800845D97 /* ArityCheckFailReturnThunks.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 0F6C73501AC9F99F00BE1682 /* VariableWriteFireDetail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6C734E1AC9F99F00BE1682 /* VariableWriteFireDetail.cpp */; }; >+ 0F6C73511AC9F99F00BE1682 /* VariableWriteFireDetail.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6C734F1AC9F99F00BE1682 /* VariableWriteFireDetail.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 0F6E845A19030BEF00562741 /* DFGVariableAccessData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */; }; > 0F6FC750196110A800E1D02D /* ComplexGetStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */; }; > 0F6FC751196110A800E1D02D /* ComplexGetStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; >@@ -2100,6 +2102,8 @@ > 0F6B1CC21862C47800845D97 /* FTLUnwindInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLUnwindInfo.h; path = ftl/FTLUnwindInfo.h; sourceTree = "<group>"; }; > 0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArityCheckFailReturnThunks.cpp; sourceTree = "<group>"; }; > 0F6B1CC818641DF800845D97 /* ArityCheckFailReturnThunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArityCheckFailReturnThunks.h; sourceTree = "<group>"; }; >+ 0F6C734E1AC9F99F00BE1682 /* VariableWriteFireDetail.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VariableWriteFireDetail.cpp; sourceTree = "<group>"; }; >+ 0F6C734F1AC9F99F00BE1682 /* VariableWriteFireDetail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableWriteFireDetail.h; sourceTree = "<group>"; }; > 0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessData.cpp; path = dfg/DFGVariableAccessData.cpp; sourceTree = "<group>"; }; > 0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComplexGetStatus.cpp; sourceTree = "<group>"; }; > 0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComplexGetStatus.h; sourceTree = "<group>"; }; >@@ -5280,6 +5284,8 @@ > 0FCA9112195E66A000426438 /* VariableWatchpointSet.cpp */, > 0F9181C618415CA50057B669 /* VariableWatchpointSet.h */, > FE5248F8191442D900B7FDE4 /* VariableWatchpointSetInlines.h */, >+ 0F6C734E1AC9F99F00BE1682 /* VariableWriteFireDetail.cpp */, >+ 0F6C734F1AC9F99F00BE1682 /* VariableWriteFireDetail.h */, > 0F20C2581A8013AB00DA3229 /* VirtualRegister.cpp */, > 0F426A461460CBAB00131F8F /* VirtualRegister.h */, > 0F919D2215853CDE004A4E7D /* Watchpoint.cpp */, >@@ -6354,6 +6360,7 @@ > A709F2F017A0AC0400512E98 /* SlowPathCall.h in Headers */, > 933040040E6A749400786E6A /* SmallStrings.h in Headers */, > BC18C4640E16F5CD00B34460 /* SourceCode.h in Headers */, >+ 0F6C73511AC9F99F00BE1682 /* VariableWriteFireDetail.h in Headers */, > BC18C4630E16F5CD00B34460 /* SourceProvider.h in Headers */, > 70EC0EC31AA0D7DA00B6AAFA /* JSStringIterator.h in Headers */, > E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */, >@@ -6963,6 +6970,7 @@ > A77F1821164088B200640A47 /* CodeCache.cpp in Sources */, > 0F8F9446166764F100D61971 /* CodeOrigin.cpp in Sources */, > 86B5826714D2796C00A9C306 /* CodeProfile.cpp in Sources */, >+ 0F6C73501AC9F99F00BE1682 /* VariableWriteFireDetail.cpp in Sources */, > 86B5826914D2797000A9C306 /* CodeProfiling.cpp in Sources */, > 0F8F943C1667631300D61971 /* CodeSpecializationKind.cpp in Sources */, > 0F8F94421667633500D61971 /* CodeType.cpp in Sources */, >Index: Source/JavaScriptCore/bytecode/BytecodeList.json >=================================================================== >--- Source/JavaScriptCore/bytecode/BytecodeList.json (revision 182069) >+++ Source/JavaScriptCore/bytecode/BytecodeList.json (working copy) >@@ -6,7 +6,6 @@ > { "name" : "op_enter", "length" : 1 }, > { "name" : "op_create_lexical_environment", "length" : 3 }, > { "name" : "op_get_scope", "length" : 2 }, >- { "name" : "op_touch_entry", "length" : 1 }, > { "name" : "op_create_direct_arguments", "length" : 2 }, > { "name" : "op_create_scoped_arguments", "length" : 3 }, > { "name" : "op_create_out_of_band_arguments", "length" : 2 }, >@@ -103,7 +102,7 @@ > { "name" : "op_construct_varargs", "length" : 9 }, > { "name" : "op_strcat", "length" : 4 }, > { "name" : "op_to_primitive", "length" : 3 }, >- { "name" : "op_resolve_scope", "length" : 7 }, >+ { "name" : "op_resolve_scope", "length" : 6 }, > { "name" : "op_get_from_scope", "length" : 8 }, > { "name" : "op_put_to_scope", "length" : 7 }, > { "name" : "op_get_from_arguments", "length" : 5 }, >Index: Source/JavaScriptCore/bytecode/BytecodeUseDef.h >=================================================================== >--- Source/JavaScriptCore/bytecode/BytecodeUseDef.h (revision 182069) >+++ Source/JavaScriptCore/bytecode/BytecodeUseDef.h (working copy) >@@ -50,7 +50,6 @@ void computeUsesForBytecodeOffset( > case op_new_object: > case op_enter: > case op_catch: >- case op_touch_entry: > case op_profile_control_flow: > case op_create_direct_arguments: > case op_create_out_of_band_arguments: >@@ -278,7 +277,6 @@ void computeDefsForBytecodeOffset(CodeBl > case op_put_by_index: > case op_profile_type: > case op_profile_control_flow: >- case op_touch_entry: > case op_put_to_arguments: > #define LLINT_HELPER_OPCODES(opcode, length) case opcode: > FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES); >Index: Source/JavaScriptCore/bytecode/CodeBlock.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeBlock.cpp (revision 182069) >+++ Source/JavaScriptCore/bytecode/CodeBlock.cpp (working copy) >@@ -733,10 +733,6 @@ void CodeBlock::dumpBytecode( > printLocationAndOp(out, exec, location, it, "enter"); > break; > } >- case op_touch_entry: { >- printLocationAndOp(out, exec, location, it, "touch_entry"); >- break; >- } > case op_create_lexical_environment: { > int r0 = (++it)->u.operand; > int r1 = (++it)->u.operand; >@@ -1484,7 +1480,6 @@ void CodeBlock::dumpBytecode( > out.printf("%s, %s, %s, %u<%s|%s>, %d", registerName(r0).data(), registerName(scope).data(), idName(id0, identifier(id0)).data(), > modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()), > depth); >- ++it; > break; > } > case op_get_from_scope: { >@@ -1931,8 +1926,6 @@ CodeBlock::CodeBlock(ScriptExecutable* o > ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, Get, type); > instructions[i + 4].u.operand = op.type; > instructions[i + 5].u.operand = op.depth; >- if (op.lexicalEnvironment) >- instructions[i + 6].u.lexicalEnvironment.set(*vm(), ownerExecutable, op.lexicalEnvironment); > break; > } > >@@ -1976,7 +1969,7 @@ CodeBlock::CodeBlock(ScriptExecutable* o > ConcurrentJITLocker locker(m_symbolTable->m_lock); > SymbolTable::Map::iterator iter = m_symbolTable->find(locker, uid); > ASSERT(iter != m_symbolTable->end(locker)); >- iter->value.prepareToWatch(symbolTable()); >+ iter->value.prepareToWatch(); > instructions[i + 5].u.watchpointSet = iter->value.watchpointSet(); > } else > instructions[i + 5].u.watchpointSet = nullptr; >@@ -2520,15 +2513,6 @@ void CodeBlock::finalizeUnconditionally( > curInstruction[3].u.toThisStatus = merge( > curInstruction[3].u.toThisStatus, ToThisClearedByGC); > break; >- case op_resolve_scope: { >- WriteBarrierBase<JSLexicalEnvironment>& lexicalEnvironment = curInstruction[6].u.lexicalEnvironment; >- if (!lexicalEnvironment || Heap::isMarked(lexicalEnvironment.get())) >- break; >- if (Options::verboseOSR()) >- dataLogF("Clearing dead lexicalEnvironment %p.\n", lexicalEnvironment.get()); >- lexicalEnvironment.clear(); >- break; >- } > case op_get_from_scope: > case op_put_to_scope: { > ResolveModeAndType modeAndType = >Index: Source/JavaScriptCore/bytecode/CodeOrigin.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeOrigin.cpp (revision 182069) >+++ Source/JavaScriptCore/bytecode/CodeOrigin.cpp (working copy) >@@ -141,6 +141,18 @@ void CodeOrigin::dumpInContext(PrintStre > dump(out); > } > >+JSFunction* InlineCallFrame::calleeConstant() const >+{ >+ if (calleeRecovery.isConstant()) >+ return jsCast<JSFunction*>(calleeRecovery.constant()); >+ return nullptr; >+} >+ >+void InlineCallFrame::visitAggregate(SlotVisitor& visitor) >+{ >+ visitor.append(&executable); >+} >+ > JSFunction* InlineCallFrame::calleeForCallFrame(ExecState* exec) const > { > return jsCast<JSFunction*>(calleeRecovery.recover(exec)); >Index: Source/JavaScriptCore/bytecode/CodeOrigin.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeOrigin.h (revision 182069) >+++ Source/JavaScriptCore/bytecode/CodeOrigin.h (working copy) >@@ -28,7 +28,6 @@ > > #include "CodeBlockHash.h" > #include "CodeSpecializationKind.h" >-#include "JSFunction.h" > #include "ValueRecovery.h" > #include "WriteBarrier.h" > #include <wtf/BitVector.h> >@@ -207,17 +206,8 @@ struct InlineCallFrame { > > CodeSpecializationKind specializationKind() const { return specializationKindFor(static_cast<Kind>(kind)); } > >- JSFunction* calleeConstant() const >- { >- if (calleeRecovery.isConstant()) >- return jsCast<JSFunction*>(calleeRecovery.constant()); >- return 0; >- } >- >- void visitAggregate(SlotVisitor& visitor) >- { >- visitor.append(&executable); >- } >+ JSFunction* calleeConstant() const; >+ void visitAggregate(SlotVisitor&); > > // Get the callee given a machine call frame to which this InlineCallFrame belongs. > JSFunction* calleeForCallFrame(ExecState*) const; >Index: Source/JavaScriptCore/bytecode/Instruction.h >=================================================================== >--- Source/JavaScriptCore/bytecode/Instruction.h (revision 182069) >+++ Source/JavaScriptCore/bytecode/Instruction.h (working copy) >@@ -46,7 +46,7 @@ namespace JSC { > class ArrayAllocationProfile; > class ArrayProfile; > class ObjectAllocationProfile; >-class VariableWatchpointSet; >+class WatchpointSet; > struct LLIntCallLinkInfo; > struct ValueProfile; > >@@ -117,8 +117,7 @@ struct Instruction { > ArrayProfile* arrayProfile; > ArrayAllocationProfile* arrayAllocationProfile; > ObjectAllocationProfile* objectAllocationProfile; >- VariableWatchpointSet* watchpointSet; >- WriteBarrierBase<JSLexicalEnvironment> lexicalEnvironment; >+ WatchpointSet* watchpointSet; > void* pointer; > bool* predicatePointer; > ToThisStatus toThisStatus; >Index: Source/JavaScriptCore/bytecode/VariableWatchpointSet.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/VariableWatchpointSet.cpp (revision 182069) >+++ Source/JavaScriptCore/bytecode/VariableWatchpointSet.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 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 >@@ -30,19 +30,9 @@ > > namespace JSC { > >-void VariableWriteFireDetail::dump(PrintStream& out) const >+void VariableWatchpointSet::notifyWrite(VM& vm, JSCell* owner, JSValue value, const char* reason) > { >- out.print("Write to ", m_name, " in ", JSValue(m_object)); >-} >- >-void VariableWatchpointSet::notifyWrite(VM& vm, JSValue value, JSObject* baseObject, const PropertyName& propertyName) >-{ >- notifyWrite(vm, value, VariableWriteFireDetail(baseObject, propertyName)); >-} >- >-void VariableWatchpointSet::notifyWrite(VM& vm, JSValue value, const char* reason) >-{ >- notifyWrite(vm, value, StringFireDetail(reason)); >+ notifyWrite(vm, owner, value, StringFireDetail(reason)); > } > > } // namespace JSC >Index: Source/JavaScriptCore/bytecode/VariableWatchpointSet.h >=================================================================== >--- Source/JavaScriptCore/bytecode/VariableWatchpointSet.h (revision 182069) >+++ Source/JavaScriptCore/bytecode/VariableWatchpointSet.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2012-2014 Apple Inc. All rights reserved. >+ * Copyright (C) 2012-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 >@@ -32,29 +32,12 @@ > namespace JSC { > > class JSObject; >-class SymbolTable; >- >-class VariableWriteFireDetail : public FireDetail { >-public: >- VariableWriteFireDetail(JSObject* object, const PropertyName& name) >- : m_object(object) >- , m_name(name) >- { >- } >- >- virtual void dump(PrintStream&) const override; >- >-private: >- JSObject* m_object; >- const PropertyName& m_name; >-}; > > class VariableWatchpointSet : public WatchpointSet { > friend class LLIntOffsetsExtractor; > public: >- VariableWatchpointSet(SymbolTable& symbolTable) >+ VariableWatchpointSet() > : WatchpointSet(ClearWatchpoint) >- , m_symbolTable(symbolTable) > { > } > >@@ -73,9 +56,8 @@ public: > // you will have been notified that the watchpoint was fired. > JSValue inferredValue() const { return m_inferredValue.get(); } > >- void notifyWrite(VM&, JSValue, const FireDetail&); >- JS_EXPORT_PRIVATE void notifyWrite(VM&, JSValue, JSObject* baseObject, const PropertyName&); >- void notifyWrite(VM&, JSValue, const char* reason); >+ void notifyWrite(VM&, JSCell* owner, JSValue, const FireDetail&); >+ void notifyWrite(VM&, JSCell* owner, JSValue, const char* reason); > > void invalidate(const FireDetail& detail) > { >@@ -83,15 +65,19 @@ public: > WatchpointSet::invalidate(detail); > } > >- void finalizeUnconditionally(const FireDetail& detail) >+ bool needToFinalize() > { > ASSERT(!!m_inferredValue == (state() == IsWatched)); > if (!m_inferredValue) >+ return false; >+ return m_inferredValue.get().isCell(); >+ } >+ >+ void finalizeUnconditionally(const FireDetail& detail) >+ { >+ if (!needToFinalize()) > return; >- JSValue inferredValue = m_inferredValue.get(); >- if (!inferredValue.isCell()) >- return; >- JSCell* cell = inferredValue.asCell(); >+ JSCell* cell = m_inferredValue.get().asCell(); > if (Heap::isMarked(cell)) > return; > invalidate(detail); >@@ -100,7 +86,6 @@ public: > WriteBarrier<Unknown>* addressOfInferredValue() { return &m_inferredValue; } > > private: >- SymbolTable& m_symbolTable; > WriteBarrier<Unknown> m_inferredValue; > }; > >Index: Source/JavaScriptCore/bytecode/VariableWatchpointSetInlines.h >=================================================================== >--- Source/JavaScriptCore/bytecode/VariableWatchpointSetInlines.h (revision 182069) >+++ Source/JavaScriptCore/bytecode/VariableWatchpointSetInlines.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 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 >@@ -26,17 +26,17 @@ > #ifndef VariableWatchpointSetInlines_h > #define VariableWatchpointSetInlines_h > >-#include "SymbolTable.h" > #include "VariableWatchpointSet.h" > > namespace JSC { > >-inline void VariableWatchpointSet::notifyWrite(VM& vm, JSValue value, const FireDetail& detail) >+inline void VariableWatchpointSet::notifyWrite( >+ VM& vm, JSCell* owner, JSValue value, const FireDetail& detail) > { > ASSERT(!!value); > switch (state()) { > case ClearWatchpoint: >- m_inferredValue.set(vm, &m_symbolTable, value); >+ m_inferredValue.set(vm, owner, value); > startWatching(); > return; > >Index: Source/JavaScriptCore/bytecode/VariableWriteFireDetail.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/VariableWriteFireDetail.cpp (revision 0) >+++ Source/JavaScriptCore/bytecode/VariableWriteFireDetail.cpp (working copy) >@@ -0,0 +1,44 @@ >+/* >+ * Copyright (C) 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 >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "VariableWriteFireDetail.h" >+ >+#include "JSCInlines.h" >+ >+namespace JSC { >+ >+void VariableWriteFireDetail::dump(PrintStream& out) const >+{ >+ out.print("Write to ", m_name, " in ", JSValue(m_object)); >+} >+ >+void VariableWriteFireDetail::touch(WatchpointSet* set, JSObject* object, const PropertyName& name) >+{ >+ set->touch(VariableWriteFireDetail(object, name)); >+} >+ >+} // namespace JSC >+ >Index: Source/JavaScriptCore/bytecode/VariableWriteFireDetail.h >=================================================================== >--- Source/JavaScriptCore/bytecode/VariableWriteFireDetail.h (revision 0) >+++ Source/JavaScriptCore/bytecode/VariableWriteFireDetail.h (working copy) >@@ -0,0 +1,55 @@ >+/* >+ * Copyright (C) 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 >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#ifndef VariableWriteFireDetail_h >+#define VariableWriteFireDetail_h >+ >+#include "Watchpoint.h" >+ >+namespace JSC { >+ >+class JSObject; >+class PropertyName; >+ >+class VariableWriteFireDetail : public FireDetail { >+public: >+ VariableWriteFireDetail(JSObject* object, const PropertyName& name) >+ : m_object(object) >+ , m_name(name) >+ { >+ } >+ >+ virtual void dump(PrintStream&) const override; >+ >+ JS_EXPORT_PRIVATE void touch(WatchpointSet*, JSObject*, const PropertyName&); >+ >+private: >+ JSObject* m_object; >+ const PropertyName& m_name; >+}; >+ >+} // namespace JSC >+ >+#endif // VariableWriteFireDetail_h >Index: Source/JavaScriptCore/bytecode/Watchpoint.h >=================================================================== >--- Source/JavaScriptCore/bytecode/Watchpoint.h (revision 182069) >+++ Source/JavaScriptCore/bytecode/Watchpoint.h (working copy) >@@ -125,20 +125,24 @@ public: > // set watchpoints that we believe will actually be fired. > void startWatching() > { >- ASSERT(state() != IsInvalidated); >+ ASSERT(m_state != IsInvalidated); >+ if (m_state == IsWatched) >+ return; >+ WTF::storeStoreFence(); > m_state = IsWatched; >+ WTF::storeStoreFence(); > } > > void fireAll(const FireDetail& detail) > { >- if (LIKELY(state() != IsWatched)) >+ if (LIKELY(m_state != IsWatched)) > return; > fireAllSlow(detail); > } > > void fireAll(const char* reason) > { >- if (LIKELY(state() != IsWatched)) >+ if (LIKELY(m_state != IsWatched)) > return; > fireAllSlow(reason); > } >@@ -151,13 +155,23 @@ public: > fireAll(detail); > } > >+ void touch(const char* reason) >+ { >+ touch(StringFireDetail(reason)); >+ } >+ > void invalidate(const FireDetail& detail) > { > if (state() == IsWatched) > fireAll(detail); > m_state = IsInvalidated; > } >- >+ >+ void invalidate(const char* reason) >+ { >+ invalidate(StringFireDetail(reason)); >+ } >+ > int8_t* addressOfState() { return &m_state; } > int8_t* addressOfSetIsNotEmpty() { return &m_setIsNotEmpty; } > >@@ -261,7 +275,11 @@ public: > fat()->touch(detail); > return; > } >- if (decodeState(m_data) == ClearWatchpoint) >+ uintptr_t data = m_data; >+ if (decodeState(data) == IsInvalidated) >+ return; >+ WTF::storeStoreFence(); >+ if (decodeState(data) == ClearWatchpoint) > m_data = encodeState(IsWatched); > else > m_data = encodeState(IsInvalidated); >Index: Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >=================================================================== >--- Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (revision 182069) >+++ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (working copy) >@@ -466,9 +466,6 @@ BytecodeGenerator::BytecodeGenerator(VM& > } > } > >- if (m_symbolTable->scopeSize()) >- emitOpcode(op_touch_entry); >- > if (isConstructor()) { > if (constructorKind() == ConstructorKind::Derived) { > m_newTargetRegister = addVar(); >@@ -1324,8 +1321,6 @@ RegisterID* BytecodeGenerator::emitResol > > ASSERT(!m_symbolTable || !m_symbolTable->contains(variable.ident().impl()) || resolveType() == Dynamic); > >- m_codeBlock->addPropertyAccessInstruction(instructions().size()); >- > // resolve_scope dst, id, ResolveType, depth > emitOpcode(op_resolve_scope); > dst = tempDestination(dst); >@@ -1334,7 +1329,6 @@ RegisterID* BytecodeGenerator::emitResol > instructions().append(addConstant(variable.ident())); > instructions().append(resolveType()); > instructions().append(0); >- instructions().append(0); > return dst; > } > >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -1341,6 +1341,7 @@ bool AbstractInterpreter<AbstractStateTy > } > > case CreateThis: { >+ // FIXME: We can fold this to NewObject if the incoming callee is a constant. > forNode(node).setType(SpecFinalObject); > break; > } >@@ -1403,6 +1404,15 @@ bool AbstractInterpreter<AbstractStateTy > break; > > case GetCallee: >+ if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_codeBlock->ownerExecutable())) { >+ VariableWatchpointSet& set = executable->functionReallocationWatchpointSet(); >+ if (JSValue value = set.inferredValue()) { >+ m_graph.watchpoints().addLazily(&set); >+ JSFunction* function = jsCast<JSFunction*>(value); >+ setConstant(node, *m_graph.freeze(function)); >+ break; >+ } >+ } > forNode(node).setType(SpecFunction); > break; > >Index: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (working copy) >@@ -278,8 +278,20 @@ private: > if (operand.offset() == JSStack::Callee) > return weakJSConstant(callee); > } >- } else if (operand.offset() == JSStack::Callee) >+ } else if (operand.offset() == JSStack::Callee) { >+ // We have to do some constant-folding here because this enables CreateThis folding. Note >+ // that we don't have such watchpoint-based folding for inlined uses of Callee, since in that >+ // case if the function is a singleton then we already know it. >+ if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_codeBlock->ownerExecutable())) { >+ VariableWatchpointSet& set = executable->functionReallocationWatchpointSet(); >+ if (JSValue value = set.inferredValue()) { >+ m_graph.watchpoints().addLazily(&set); >+ JSFunction* function = jsCast<JSFunction*>(value); >+ return weakJSConstant(function); >+ } >+ } > return addToGraph(GetCallee); >+ } > > return getDirect(m_inlineStackTop->remapOperand(operand)); > } >@@ -2519,6 +2531,12 @@ void ByteCodeParser::clearCaches() > Node* ByteCodeParser::getScope(VirtualRegister scopeChain, unsigned skipCount) > { > Node* localBase = get(scopeChain); >+ addToGraph(Phantom, localBase); // OSR exit cannot handle resolve_scope on a DCE'd scope. >+ if (JSScope* scope = localBase->dynamicCastConstant<JSScope*>()) { >+ for (unsigned n = skipCount; n--;) >+ scope = scope->next(); >+ return weakJSConstant(scope); >+ } > for (unsigned n = skipCount; n--;) > localBase = addToGraph(SkipScope, localBase); > return localBase; >@@ -2593,11 +2611,6 @@ bool ByteCodeParser::parseBlock(unsigned > NEXT_OPCODE(op_enter); > } > >- case op_touch_entry: >- if (m_inlineStackTop->m_codeBlock->symbolTable()->m_functionEnteredOnce.isStillValid()) >- addToGraph(ForceOSRExit); >- NEXT_OPCODE(op_touch_entry); >- > case op_to_this: { > Node* op1 = getThis(); > if (op1->op() != ToThis) { >@@ -3375,17 +3388,7 @@ bool ByteCodeParser::parseBlock(unsigned > case LocalClosureVar: > case ClosureVar: > case ClosureVarWithVarInjectionChecks: { >- JSLexicalEnvironment* lexicalEnvironment = currentInstruction[6].u.lexicalEnvironment.get(); >- if (lexicalEnvironment >- && lexicalEnvironment->symbolTable()->m_functionEnteredOnce.isStillValid()) { >- m_graph.watchpoints().addLazily(lexicalEnvironment->symbolTable()->m_functionEnteredOnce); >- addToGraph(Phantom, getDirect(m_inlineStackTop->remapOperand(VirtualRegister(currentInstruction[2].u.operand)))); >- set(VirtualRegister(dst), weakJSConstant(lexicalEnvironment)); >- break; >- } > set(VirtualRegister(dst), getScope(VirtualRegister(currentInstruction[2].u.operand), depth)); >- if (inlineCallFrame()) >- addToGraph(Phantom, getDirect(m_inlineStackTop->remapOperand(VirtualRegister(currentInstruction[2].u.operand)))); > break; > } > case Dynamic: >@@ -3437,19 +3440,58 @@ bool ByteCodeParser::parseBlock(unsigned > case GlobalVar: > case GlobalVarWithVarInjectionChecks: { > addToGraph(Phantom, get(VirtualRegister(scope))); >- ConcurrentJITLocker locker(globalObject->symbolTable()->m_lock); >- SymbolTableEntry entry = globalObject->symbolTable()->get(locker, uid); >- VariableWatchpointSet* watchpointSet = entry.watchpointSet(); >- JSValue inferredValue = >- watchpointSet ? watchpointSet->inferredValue() : JSValue(); >- if (!inferredValue) { >- SpeculatedType prediction = getPrediction(); >- set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction))); >- break; >+ WatchpointSet* watchpointSet; >+ ScopeOffset offset; >+ { >+ ConcurrentJITLocker locker(globalObject->symbolTable()->m_lock); >+ SymbolTableEntry entry = globalObject->symbolTable()->get(locker, uid); >+ watchpointSet = entry.watchpointSet(); >+ offset = entry.scopeOffset(); >+ } >+ if (watchpointSet && watchpointSet->state() == IsWatched) { >+ // This has a fun concurrency story. There is the possibility of a race in two >+ // directions: >+ // >+ // We see that the set IsWatched, but in the meantime it gets invalidated: this is >+ // fine because if we saw that it IsWatched then we add a watchpoint. If it gets >+ // invalidated, then this compilation is invalidated. Note that in the meantime we >+ // may load an absurd value from the global object. It's fine to load an absurd >+ // value if the compilation is invalidated anyway. >+ // >+ // We see that the set IsWatched, but the value isn't yet initialized: this isn't >+ // possible because of the ordering of operations. >+ // >+ // Here's how we order operations: >+ // >+ // Main thread stores to the global object: always store a value first, and only >+ // after that do we touch the watchpoint set. There is a fence in the touch, that >+ // ensures that the store to the global object always happens before the touch on the >+ // set. >+ // >+ // Compilation thread: always first load the state of the watchpoint set, and then >+ // load the value. The WatchpointSet::state() method does fences for us to ensure >+ // that the load of the state happens before our load of the value. >+ // >+ // Finalizing compilation: this happens on the main thread and synchronously checks >+ // validity of all watchpoint sets. >+ // >+ // We will only perform optimizations if the load of the state yields IsWatched. That >+ // means that at least one store would have happened to initialize the original value >+ // of the variable (that is, the value we'd like to constant fold to). There may be >+ // other stores that happen after that, but those stores will invalidate the >+ // watchpoint set and also the compilation. >+ >+ ASSERT(bitwise_cast<uintptr_t>(&globalObject->variableAt(offset)) == operand); >+ JSValue value = globalObject->variableAt(offset).get(); >+ if (value) { >+ m_graph.watchpoints().addLazily(watchpointSet); >+ set(VirtualRegister(dst), weakJSConstant(value)); >+ break; >+ } > } > >- m_graph.watchpoints().addLazily(watchpointSet); >- set(VirtualRegister(dst), weakJSConstant(inferredValue)); >+ SpeculatedType prediction = getPrediction(); >+ set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction))); > break; > } > case LocalClosureVar: >@@ -3496,7 +3538,7 @@ bool ByteCodeParser::parseBlock(unsigned > uid = nullptr; > > Structure* structure = nullptr; >- VariableWatchpointSet* watchpoints = nullptr; >+ WatchpointSet* watchpoints = nullptr; > uintptr_t operand; > { > ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); >@@ -3539,8 +3581,10 @@ bool ByteCodeParser::parseBlock(unsigned > } > Node* valueNode = get(VirtualRegister(value)); > addToGraph(PutGlobalVar, OpInfo(operand), valueNode); >- if (watchpoints && watchpoints->state() != IsInvalidated) >- addToGraph(NotifyWrite, OpInfo(watchpoints), valueNode); >+ if (watchpoints && watchpoints->state() != IsInvalidated) { >+ // Must happen after the store. See comment for GetGlobalVar. >+ addToGraph(NotifyWrite, OpInfo(watchpoints)); >+ } > // Keep scope alive until after put. > addToGraph(Phantom, get(VirtualRegister(scope))); > break; >@@ -3551,10 +3595,12 @@ bool ByteCodeParser::parseBlock(unsigned > Node* scopeNode = get(VirtualRegister(scope)); > Node* valueNode = get(VirtualRegister(value)); > >- if (watchpoints && watchpoints->state() != IsInvalidated) >- addToGraph(NotifyWrite, OpInfo(watchpoints), valueNode); >- > addToGraph(PutClosureVar, OpInfo(operand), scopeNode, valueNode); >+ >+ if (watchpoints && watchpoints->state() != IsInvalidated) { >+ // Must happen after the store. See comment for GetGlobalVar. >+ addToGraph(NotifyWrite, OpInfo(watchpoints)); >+ } > break; > } > case Dynamic: >Index: Source/JavaScriptCore/dfg/DFGCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCapabilities.cpp (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGCapabilities.cpp (working copy) >@@ -96,7 +96,6 @@ CapabilityLevel capabilityLevel(OpcodeID > > switch (opcodeID) { > case op_enter: >- case op_touch_entry: > case op_to_this: > case op_check_tdz: > case op_create_this: >Index: Source/JavaScriptCore/dfg/DFGClobberize.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobberize.h (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGClobberize.h (working copy) >@@ -860,11 +860,17 @@ void clobberize(Graph& graph, Node* node > case NewStringObject: > case PhantomNewObject: > case MaterializeNewObject: >- case NewFunction: > read(HeapObjectCount); > write(HeapObjectCount); > return; > >+ case NewFunction: >+ if (node->castOperand<FunctionExecutable*>()->functionReallocationWatchpointSet().isStillValid()) >+ write(Watchpoint_fire); >+ read(HeapObjectCount); >+ write(HeapObjectCount); >+ return; >+ > case RegExpExec: > case RegExpTest: > read(RegExpState); >Index: Source/JavaScriptCore/dfg/DFGGraph.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.cpp (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGGraph.cpp (working copy) >@@ -308,8 +308,8 @@ void Graph::dump(PrintStream& out, const > out.print(comma, "^", node->phi()->index()); > if (node->hasExecutionCounter()) > out.print(comma, RawPointer(node->executionCounter())); >- if (node->hasVariableWatchpointSet()) >- out.print(comma, RawPointer(node->variableWatchpointSet())); >+ if (node->hasWatchpointSet()) >+ out.print(comma, RawPointer(node->watchpointSet())); > if (node->hasTypedArray()) > out.print(comma, inContext(JSValue(node->typedArray()), context)); > if (node->hasStoragePointer()) >@@ -1025,6 +1025,8 @@ JSValue Graph::tryGetConstantProperty(co > > JSValue Graph::tryGetConstantClosureVar(JSValue base, ScopeOffset offset) > { >+ // This has an awesome concurrency story. See comment for GetGlobalVar in ByteCodeParser. >+ > if (!base) > return JSValue(); > >@@ -1033,24 +1035,28 @@ JSValue Graph::tryGetConstantClosureVar( > return JSValue(); > > SymbolTable* symbolTable = activation->symbolTable(); >- ConcurrentJITLocker locker(symbolTable->m_lock); >- >- if (symbolTable->m_functionEnteredOnce.hasBeenInvalidated()) >- return JSValue(); >- >- SymbolTableEntry* entry = symbolTable->entryFor(locker, offset); >- if (!entry) >- return JSValue(); >- >- VariableWatchpointSet* set = entry->watchpointSet(); >- if (!set) >- return JSValue(); >- >- JSValue value = set->inferredValue(); >- if (!value) >- return JSValue(); >+ JSValue value; >+ WatchpointSet* set; >+ { >+ ConcurrentJITLocker locker(symbolTable->m_lock); >+ >+ SymbolTableEntry* entry = symbolTable->entryFor(locker, offset); >+ if (!entry) >+ return JSValue(); >+ >+ set = entry->watchpointSet(); >+ if (!set) >+ return JSValue(); >+ >+ if (set->state() != IsWatched) >+ return JSValue(); >+ >+ ASSERT(entry->scopeOffset() == offset); >+ value = activation->variableAt(offset).get(); >+ if (!value) >+ return JSValue(); >+ } > >- watchpoints().addLazily(symbolTable->m_functionEnteredOnce); > watchpoints().addLazily(set); > > return value; >Index: Source/JavaScriptCore/dfg/DFGNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.h (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGNode.h (working copy) >@@ -1219,14 +1219,14 @@ struct Node { > m_opInfo = bitwise_cast<uintptr_t>(value); > } > >- bool hasVariableWatchpointSet() >+ bool hasWatchpointSet() > { > return op() == NotifyWrite; > } > >- VariableWatchpointSet* variableWatchpointSet() >+ WatchpointSet* watchpointSet() > { >- return reinterpret_cast<VariableWatchpointSet*>(m_opInfo); >+ return reinterpret_cast<WatchpointSet*>(m_opInfo); > } > > bool hasTypedArray() >Index: Source/JavaScriptCore/dfg/DFGOperations.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOperations.cpp (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGOperations.cpp (working copy) >@@ -1054,13 +1054,12 @@ char* JIT_OPERATION operationSwitchStrin > return static_cast<char*>(exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress()); > } > >-void JIT_OPERATION operationNotifyWrite(ExecState* exec, VariableWatchpointSet* set, EncodedJSValue encodedValue) >+void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set) > { > VM& vm = exec->vm(); > NativeCallFrameTracer tracer(&vm, exec); >- JSValue value = JSValue::decode(encodedValue); > >- set->notifyWrite(vm, value, "Executed NotifyWrite"); >+ set->touch("Executed NotifyWrite"); > } > > void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState* exec) >Index: Source/JavaScriptCore/dfg/DFGOperations.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOperations.h (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGOperations.h (working copy) >@@ -125,7 +125,7 @@ JSCell* JIT_OPERATION operationMakeRope2 > JSCell* JIT_OPERATION operationMakeRope3(ExecState*, JSString*, JSString*, JSString*); > char* JIT_OPERATION operationFindSwitchImmTargetForDouble(ExecState*, EncodedJSValue, size_t tableIndex); > char* JIT_OPERATION operationSwitchString(ExecState*, size_t tableIndex, JSString*); >-void JIT_OPERATION operationNotifyWrite(ExecState*, VariableWatchpointSet*, EncodedJSValue); >+void JIT_OPERATION operationNotifyWrite(ExecState*, WatchpointSet*); > void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState*) WTF_INTERNAL; > int32_t JIT_OPERATION operationSizeOfVarargs(ExecState*, EncodedJSValue arguments, int32_t firstVarArgOffset); > void JIT_OPERATION operationLoadVarargs(ExecState*, int32_t firstElementDest, EncodedJSValue arguments, int32_t offset, int32_t length, int32_t mandatoryMinimum); >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (working copy) >@@ -3982,32 +3982,7 @@ void SpeculativeJIT::compile(Node* node) > } > > case NotifyWrite: { >- VariableWatchpointSet* set = node->variableWatchpointSet(); >- >- JSValueOperand value(this, node->child1()); >- GPRReg valueTagGPR = value.tagGPR(); >- GPRReg valuePayloadGPR = value.payloadGPR(); >- >- GPRTemporary temp(this); >- GPRReg tempGPR = temp.gpr(); >- >- m_jit.load8(set->addressOfState(), tempGPR); >- >- JITCompiler::Jump isDone = m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated)); >- JITCompiler::JumpList notifySlow; >- notifySlow.append(m_jit.branch32( >- JITCompiler::NotEqual, >- JITCompiler::AbsoluteAddress(set->addressOfInferredValue()->payloadPointer()), >- valuePayloadGPR)); >- notifySlow.append(m_jit.branch32( >- JITCompiler::NotEqual, >- JITCompiler::AbsoluteAddress(set->addressOfInferredValue()->tagPointer()), >- valueTagGPR)); >- addSlowPathGenerator( >- slowPathCall(notifySlow, this, operationNotifyWrite, NoResult, set, valueTagGPR, valuePayloadGPR)); >- isDone.link(&m_jit); >- >- noResult(node); >+ compileNotifyWrite(node); > break; > } > >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (working copy) >@@ -4014,26 +4014,7 @@ void SpeculativeJIT::compile(Node* node) > } > > case NotifyWrite: { >- VariableWatchpointSet* set = node->variableWatchpointSet(); >- >- JSValueOperand value(this, node->child1()); >- GPRReg valueGPR = value.gpr(); >- >- GPRTemporary temp(this); >- GPRReg tempGPR = temp.gpr(); >- >- m_jit.load8(set->addressOfState(), tempGPR); >- >- JITCompiler::Jump isDone = >- m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated)); >- JITCompiler::Jump slowCase = m_jit.branch64(JITCompiler::NotEqual, >- JITCompiler::AbsoluteAddress(set->addressOfInferredValue()), valueGPR); >- isDone.link(&m_jit); >- >- addSlowPathGenerator( >- slowPathCall(slowCase, this, operationNotifyWrite, NoResult, set, valueGPR)); >- >- noResult(node); >+ compileNotifyWrite(node); > break; > } > >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (working copy) >@@ -4365,8 +4365,13 @@ void SpeculativeJIT::compileNewFunction( > SpeculateCellOperand scope(this, node->child1()); > GPRReg scopeGPR = scope.gpr(); > flushRegisters(); >- callOperation( >- operationNewFunction, resultGPR, scopeGPR, node->castOperand<FunctionExecutable*>()); >+ FunctionExecutable* executable = node->castOperand<FunctionExecutable*>(); >+ J_JITOperation_EJscC function; >+ if (executable->functionReallocationWatchpointSet().isStillValid()) >+ function = operationNewFunction; >+ else >+ function = operationNewFunctionWithInvalidatedReallocationWatchpoint; >+ callOperation(function, resultGPR, scopeGPR, executable); > cellResult(resultGPR, node); > } > >@@ -4712,6 +4717,21 @@ void SpeculativeJIT::compileCreateCloned > cellResult(resultGPR, node); > } > >+void SpeculativeJIT::compileNotifyWrite(Node* node) >+{ >+ WatchpointSet* set = node->watchpointSet(); >+ >+ JITCompiler::Jump slowCase = m_jit.branch8( >+ JITCompiler::NotEqual, >+ JITCompiler::AbsoluteAddress(set->addressOfState()), >+ TrustedImm32(IsInvalidated)); >+ >+ addSlowPathGenerator( >+ slowPathCall(slowCase, this, operationNotifyWrite, NoResult, set)); >+ >+ noResult(node); >+} >+ > bool SpeculativeJIT::compileRegExpExec(Node* node) > { > unsigned branchIndexInBlock = detectPeepHoleBranch(); >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (working copy) >@@ -1466,6 +1466,12 @@ public: > return appendCall(operation); > } > >+ JITCompiler::Call callOperation(V_JITOperation_EWs operation, WatchpointSet* watchpointSet) >+ { >+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(watchpointSet)); >+ return appendCall(operation); >+ } >+ > JITCompiler::Call callOperation(D_JITOperation_EJ operation, FPRReg result, GPRReg arg1) > { > m_jit.setupArgumentsWithExecState(arg1); >@@ -2213,6 +2219,7 @@ public: > void compilePutToArguments(Node*); > void compileCreateScopedArguments(Node*); > void compileCreateClonedArguments(Node*); >+ void compileNotifyWrite(Node*); > bool compileRegExpExec(Node*); > > JITCompiler::Jump branchIsCell(JSValueRegs); >Index: Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp (revision 182069) >+++ Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp (working copy) >@@ -32,6 +32,7 @@ > #include "DFGClobberize.h" > #include "DFGGraph.h" > #include "DFGPhase.h" >+#include "JSCInlines.h" > > namespace JSC { namespace DFG { > >Index: Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h (revision 182069) >+++ Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h (working copy) >@@ -106,6 +106,7 @@ namespace JSC { namespace FTL { > macro(V_JITOperation_EC, functionType(voidType, intPtr, intPtr)) \ > macro(V_JITOperation_ECb, functionType(voidType, intPtr, intPtr)) \ > macro(V_JITOperation_EVwsJ, functionType(voidType, intPtr, intPtr, int64)) \ >+ macro(V_JITOperation_EWs, functionType(voidType, intPtr, intPtr)) \ > macro(V_JITOperation_EZJZZZ, functionType(voidType, intPtr, int32, int64, int32, int32, int32)) \ > macro(V_JITOperation_J, functionType(voidType, int64)) \ > macro(V_JITOperation_Z, functionType(voidType, int32)) \ >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 182069) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -3783,29 +3783,19 @@ private: > > void compileNotifyWrite() > { >- VariableWatchpointSet* set = m_node->variableWatchpointSet(); >- >- LValue value = lowJSValue(m_node->child1()); >+ WatchpointSet* set = m_node->watchpointSet(); > > LBasicBlock isNotInvalidated = FTL_NEW_BLOCK(m_out, ("NotifyWrite not invalidated case")); >- LBasicBlock notifySlow = FTL_NEW_BLOCK(m_out, ("NotifyWrite notify slow case")); > LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NotifyWrite continuation")); > > LValue state = m_out.load8(m_out.absolute(set->addressOfState())); >- > m_out.branch( > m_out.equal(state, m_out.constInt8(IsInvalidated)), > usually(continuation), rarely(isNotInvalidated)); > >- LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, notifySlow); >- >- m_out.branch( >- m_out.equal(value, m_out.load64(m_out.absolute(set->addressOfInferredValue()))), >- unsure(continuation), unsure(notifySlow)); >- >- m_out.appendTo(notifySlow, continuation); >+ LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, continuation); > >- vmCall(m_out.operation(operationNotifyWrite), m_callFrame, m_out.constIntPtr(set), value); >+ vmCall(m_out.operation(operationNotifyWrite), m_callFrame, m_out.constIntPtr(set)); > m_out.jump(continuation); > > m_out.appendTo(continuation, lastNext); >Index: Source/JavaScriptCore/interpreter/Interpreter.cpp >=================================================================== >--- Source/JavaScriptCore/interpreter/Interpreter.cpp (revision 182069) >+++ Source/JavaScriptCore/interpreter/Interpreter.cpp (working copy) >@@ -89,6 +89,47 @@ using namespace std; > > namespace JSC { > >+String StackFrame::friendlySourceURL() const >+{ >+ String traceLine; >+ >+ switch (codeType) { >+ case StackFrameEvalCode: >+ case StackFrameFunctionCode: >+ case StackFrameGlobalCode: >+ if (!sourceURL.isEmpty()) >+ traceLine = sourceURL.impl(); >+ break; >+ case StackFrameNativeCode: >+ traceLine = "[native code]"; >+ break; >+ } >+ return traceLine.isNull() ? emptyString() : traceLine; >+} >+ >+String StackFrame::friendlyFunctionName(CallFrame* callFrame) const >+{ >+ String traceLine; >+ JSObject* stackFrameCallee = callee.get(); >+ >+ switch (codeType) { >+ case StackFrameEvalCode: >+ traceLine = "eval code"; >+ break; >+ case StackFrameNativeCode: >+ if (callee) >+ traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl(); >+ break; >+ case StackFrameFunctionCode: >+ traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl(); >+ break; >+ case StackFrameGlobalCode: >+ traceLine = "global code"; >+ break; >+ } >+ return traceLine.isNull() ? emptyString() : traceLine; >+} >+ > JSValue eval(CallFrame* callFrame) > { > if (!callFrame->argumentCount()) >Index: Source/JavaScriptCore/interpreter/Interpreter.h >=================================================================== >--- Source/JavaScriptCore/interpreter/Interpreter.h (revision 182069) >+++ Source/JavaScriptCore/interpreter/Interpreter.h (working copy) >@@ -90,45 +90,8 @@ namespace JSC { > unsigned bytecodeOffset; > String sourceURL; > JS_EXPORT_PRIVATE String toString(CallFrame*); >- String friendlySourceURL() const >- { >- String traceLine; >- >- switch (codeType) { >- case StackFrameEvalCode: >- case StackFrameFunctionCode: >- case StackFrameGlobalCode: >- if (!sourceURL.isEmpty()) >- traceLine = sourceURL.impl(); >- break; >- case StackFrameNativeCode: >- traceLine = "[native code]"; >- break; >- } >- return traceLine.isNull() ? emptyString() : traceLine; >- } >- String friendlyFunctionName(CallFrame* callFrame) const >- { >- String traceLine; >- JSObject* stackFrameCallee = callee.get(); >- >- switch (codeType) { >- case StackFrameEvalCode: >- traceLine = "eval code"; >- break; >- case StackFrameNativeCode: >- if (callee) >- traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl(); >- break; >- case StackFrameFunctionCode: >- traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl(); >- break; >- case StackFrameGlobalCode: >- traceLine = "global code"; >- break; >- } >- return traceLine.isNull() ? emptyString() : traceLine; >- } >+ String friendlySourceURL() const; >+ String friendlyFunctionName(CallFrame*) const; > JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column); > > private: >Index: Source/JavaScriptCore/jit/JIT.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JIT.cpp (revision 182069) >+++ Source/JavaScriptCore/jit/JIT.cpp (working copy) >@@ -105,6 +105,14 @@ void JIT::emitEnterOptimizationCheck() > } > #endif > >+void JIT::emitNotifyWrite(WatchpointSet* set) >+{ >+ if (!set || set->state() == IsInvalidated) >+ return; >+ >+ addSlowCase(branch8(NotEqual, AbsoluteAddress(set->addressOfState()), TrustedImm32(IsInvalidated))); >+} >+ > void JIT::assertStackPointerOffset() > { > if (ASSERT_DISABLED) >@@ -189,7 +197,6 @@ void JIT::privateCompileMainPass() > DEFINE_SLOW_OP(is_object_or_null) > DEFINE_SLOW_OP(typeof) > >- DEFINE_OP(op_touch_entry) > DEFINE_OP(op_add) > DEFINE_OP(op_bitand) > DEFINE_OP(op_bitor) >Index: Source/JavaScriptCore/jit/JIT.h >=================================================================== >--- Source/JavaScriptCore/jit/JIT.h (revision 182069) >+++ Source/JavaScriptCore/jit/JIT.h (working copy) >@@ -457,7 +457,6 @@ namespace JSC { > > void assertStackPointerOffset(); > >- void emit_op_touch_entry(Instruction*); > void emit_op_add(Instruction*); > void emit_op_bitand(Instruction*); > void emit_op_bitor(Instruction*); >@@ -640,13 +639,9 @@ namespace JSC { > void emitGetGlobalVar(uintptr_t operand); > void emitGetClosureVar(int scope, uintptr_t operand); > void emitPutGlobalProperty(uintptr_t* operandSlot, int value); >-#if USE(JSVALUE64) >- void emitNotifyWrite(RegisterID value, RegisterID scratch, VariableWatchpointSet*); >-#else >- void emitNotifyWrite(RegisterID tag, RegisterID payload, RegisterID scratch, VariableWatchpointSet*); >-#endif >- void emitPutGlobalVar(uintptr_t operand, int value, VariableWatchpointSet*); >- void emitPutClosureVar(int scope, uintptr_t operand, int value, VariableWatchpointSet*); >+ void emitNotifyWrite(WatchpointSet*); >+ void emitPutGlobalVar(uintptr_t operand, int value, WatchpointSet*); >+ void emitPutClosureVar(int scope, uintptr_t operand, int value, WatchpointSet*); > > void emitInitRegister(int dst); > >Index: Source/JavaScriptCore/jit/JITOpcodes.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITOpcodes.cpp (revision 182069) >+++ Source/JavaScriptCore/jit/JITOpcodes.cpp (working copy) >@@ -879,15 +879,6 @@ void JIT::emitSlow_op_to_number(Instruct > > #endif // USE(JSVALUE64) > >-void JIT::emit_op_touch_entry(Instruction* currentInstruction) >-{ >- if (m_codeBlock->symbolTable()->m_functionEnteredOnce.hasBeenInvalidated()) >- return; >- >- JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_touch_entry); >- slowPathCall.call(); >-} >- > void JIT::emit_op_loop_hint(Instruction*) > { > // Emit the JIT optimization check: >Index: Source/JavaScriptCore/jit/JITOperations.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITOperations.cpp (revision 182069) >+++ Source/JavaScriptCore/jit/JITOperations.cpp (working copy) >@@ -933,6 +933,14 @@ EncodedJSValue JIT_OPERATION operationNe > return JSValue::encode(JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), scope)); > } > >+EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState* exec, JSScope* scope, JSCell* functionExecutable) >+{ >+ ASSERT(functionExecutable->inherits(FunctionExecutable::info())); >+ VM& vm = exec->vm(); >+ NativeCallFrameTracer tracer(&vm, exec); >+ return JSValue::encode(JSFunction::createWithInvalidatedReallocationWatchpoint(vm, static_cast<FunctionExecutable*>(functionExecutable), scope)); >+} >+ > JSCell* JIT_OPERATION operationNewObject(ExecState* exec, Structure* structure) > { > VM* vm = &exec->vm(); >@@ -1703,8 +1711,8 @@ void JIT_OPERATION operationPutToScope(E > if (modeAndType.type() == LocalClosureVar) { > JSLexicalEnvironment* environment = jsCast<JSLexicalEnvironment*>(scope); > environment->variableAt(ScopeOffset(pc[6].u.operand)).set(vm, environment, value); >- if (VariableWatchpointSet* set = pc[5].u.watchpointSet) >- set->notifyWrite(vm, value, "Executed op_put_scope<LocalClosureVar>"); >+ if (WatchpointSet* set = pc[5].u.watchpointSet) >+ set->touch("Executed op_put_scope<LocalClosureVar>"); > return; > } > if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident)) { >Index: Source/JavaScriptCore/jit/JITOperations.h >=================================================================== >--- Source/JavaScriptCore/jit/JITOperations.h (revision 182069) >+++ Source/JavaScriptCore/jit/JITOperations.h (working copy) >@@ -86,6 +86,7 @@ extern "C" { > V: void > Vm: VM* > Vws: VariableWatchpointSet* >+ Ws: WatchpointSet* > Z: int32_t > */ > >@@ -192,6 +193,7 @@ typedef void JIT_OPERATION (*V_JITOperat > typedef void JIT_OPERATION (*V_JITOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue); > typedef void JIT_OPERATION (*V_JITOperation_ESsiJJI)(ExecState*, StructureStubInfo*, EncodedJSValue, EncodedJSValue, StringImpl*); > typedef void JIT_OPERATION (*V_JITOperation_EVwsJ)(ExecState*, VariableWatchpointSet*, EncodedJSValue); >+typedef void JIT_OPERATION (*V_JITOperation_EWs)(ExecState*, WatchpointSet*); > typedef void JIT_OPERATION (*V_JITOperation_EZ)(ExecState*, int32_t); > typedef void JIT_OPERATION (*V_JITOperation_EZJ)(ExecState*, int32_t, EncodedJSValue); > typedef void JIT_OPERATION (*V_JITOperation_EZJZZZ)(ExecState*, int32_t, EncodedJSValue, int32_t, int32_t, int32_t); >@@ -278,6 +280,7 @@ EncodedJSValue JIT_OPERATION operationNe > EncodedJSValue JIT_OPERATION operationNewArrayBufferWithProfile(ExecState*, ArrayAllocationProfile*, const JSValue* values, int32_t size) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(ExecState*, ArrayAllocationProfile*, EncodedJSValue size) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationNewFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL; >+EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL; > JSCell* JIT_OPERATION operationNewObject(ExecState*, Structure*) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL; > void JIT_OPERATION operationHandleWatchdogTimer(ExecState*) WTF_INTERNAL; >Index: Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp (revision 182069) >+++ Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp (working copy) >@@ -750,27 +750,10 @@ void JIT::emitPutGlobalProperty(uintptr_ > store32(regT2, BaseIndex(regT0, regT1, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); > } > >-void JIT::emitNotifyWrite(RegisterID tag, RegisterID payload, RegisterID scratch, VariableWatchpointSet* set) >-{ >- if (!set || set->state() == IsInvalidated) >- return; >- >- load8(set->addressOfState(), scratch); >- Jump isDone = branch32(Equal, scratch, TrustedImm32(IsInvalidated)); >- >- JumpList notifySlow = branch32( >- NotEqual, AbsoluteAddress(set->addressOfInferredValue()->payloadPointer()), payload); >- notifySlow.append(branch32( >- NotEqual, AbsoluteAddress(set->addressOfInferredValue()->tagPointer()), tag)); >- addSlowCase(notifySlow); >- >- isDone.link(this); >-} >- > void JIT::emitPutGlobalVar(uintptr_t operand, int value, VariableWatchpointSet* set) > { > emitLoad(value, regT1, regT0); >- emitNotifyWrite(regT1, regT0, regT2, set); >+ emitNotifyWrite(set); > store32(regT1, reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); > store32(regT0, reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); > } >@@ -779,7 +762,7 @@ void JIT::emitPutClosureVar(int scope, u > { > emitLoad(value, regT3, regT2); > emitLoad(scope, regT1, regT0); >- emitNotifyWrite(regT3, regT2, regT4, set); >+ emitNotifyWrite(set); > store32(regT3, Address(regT0, JSEnvironmentRecord::offsetOfVariables() + operand * sizeof(Register) + TagOffset)); > store32(regT2, Address(regT0, JSEnvironmentRecord::offsetOfVariables() + operand * sizeof(Register) + PayloadOffset)); > } >Index: Source/JavaScriptCore/jit/JITPropertyAccess.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITPropertyAccess.cpp (revision 182069) >+++ Source/JavaScriptCore/jit/JITPropertyAccess.cpp (working copy) >@@ -728,29 +728,18 @@ void JIT::emitPutGlobalProperty(uintptr_ > storePtr(regT2, BaseIndex(regT0, regT1, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue))); > } > >-void JIT::emitNotifyWrite(RegisterID value, RegisterID scratch, VariableWatchpointSet* set) >-{ >- if (!set || set->state() == IsInvalidated) >- return; >- >- load8(set->addressOfState(), scratch); >- Jump isDone = branch32(Equal, scratch, TrustedImm32(IsInvalidated)); >- addSlowCase(branch64(NotEqual, AbsoluteAddress(set->addressOfInferredValue()), value)); >- isDone.link(this); >-} >- >-void JIT::emitPutGlobalVar(uintptr_t operand, int value, VariableWatchpointSet* set) >+void JIT::emitPutGlobalVar(uintptr_t operand, int value, WatchpointSet* set) > { > emitGetVirtualRegister(value, regT0); >- emitNotifyWrite(regT0, regT1, set); >+ emitNotifyWrite(set); > storePtr(regT0, reinterpret_cast<void*>(operand)); > } > >-void JIT::emitPutClosureVar(int scope, uintptr_t operand, int value, VariableWatchpointSet* set) >+void JIT::emitPutClosureVar(int scope, uintptr_t operand, int value, WatchpointSet* set) > { > emitGetVirtualRegister(value, regT1); > emitGetVirtualRegister(scope, regT0); >- emitNotifyWrite(regT1, regT2, set); >+ emitNotifyWrite(set); > storePtr(regT1, Address(regT0, JSEnvironmentRecord::offsetOfVariables() + operand * sizeof(Register))); > } > >Index: Source/JavaScriptCore/llint/LLIntSlowPaths.cpp >=================================================================== >--- Source/JavaScriptCore/llint/LLIntSlowPaths.cpp (revision 182069) >+++ Source/JavaScriptCore/llint/LLIntSlowPaths.cpp (working copy) >@@ -1384,8 +1384,12 @@ LLINT_SLOW_PATH_DECL(slow_path_put_to_sc > if (modeAndType.type() == LocalClosureVar) { > JSLexicalEnvironment* environment = jsCast<JSLexicalEnvironment*>(scope); > environment->variableAt(ScopeOffset(pc[6].u.operand)).set(vm, environment, value); >- if (VariableWatchpointSet* set = pc[5].u.watchpointSet) >- set->notifyWrite(vm, value, "Executed op_put_scope<LocalClosureVar>"); >+ >+ // Have to do this *after* the write, because if this puts the set into IsWatched, then we need >+ // to have already changed the value of the variable. Otherwise we might watch and constant-fold >+ // to the Undefined value from before the assignment. >+ if (WatchpointSet* set = pc[5].u.watchpointSet) >+ set->touch("Executed op_put_scope<LocalClosureVar>"); > LLINT_END(); > } > >Index: Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm >=================================================================== >--- Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (revision 182069) >+++ Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (working copy) >@@ -805,14 +805,6 @@ _llint_op_mov: > dispatch(3) > > >-macro notifyWrite(set, valueTag, valuePayload, scratch, slow) >- loadb VariableWatchpointSet::m_state[set], scratch >- bieq scratch, IsInvalidated, .done >- bineq valuePayload, VariableWatchpointSet::m_inferredValue + PayloadOffset[set], slow >- bineq valueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set], slow >-.done: >-end >- > _llint_op_not: > traceExecution() > loadi 8[PC], t0 >@@ -2075,39 +2067,39 @@ _llint_op_resolve_scope: > #rGlobalProperty: > bineq t0, GlobalProperty, .rGlobalVar > getGlobalObject(1) >- dispatch(7) >+ dispatch(6) > > .rGlobalVar: > bineq t0, GlobalVar, .rClosureVar > getGlobalObject(1) >- dispatch(7) >+ dispatch(6) > > .rClosureVar: > bineq t0, ClosureVar, .rGlobalPropertyWithVarInjectionChecks > resolveScope() >- dispatch(7) >+ dispatch(6) > > .rGlobalPropertyWithVarInjectionChecks: > bineq t0, GlobalPropertyWithVarInjectionChecks, .rGlobalVarWithVarInjectionChecks > varInjectionCheck(.rDynamic) > getGlobalObject(1) >- dispatch(7) >+ dispatch(6) > > .rGlobalVarWithVarInjectionChecks: > bineq t0, GlobalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks > varInjectionCheck(.rDynamic) > getGlobalObject(1) >- dispatch(7) >+ dispatch(6) > > .rClosureVarWithVarInjectionChecks: > bineq t0, ClosureVarWithVarInjectionChecks, .rDynamic > varInjectionCheck(.rDynamic) > resolveScope() >- dispatch(7) >+ dispatch(6) > > .rDynamic: > callSlowPath(_llint_slow_path_resolve_scope) >- dispatch(7) >+ dispatch(6) > > > macro loadWithStructureCheck(operand, slowPath) >@@ -2204,7 +2196,7 @@ macro putGlobalVar() > loadisFromInstruction(3, t0) > loadConstantOrVariable(t0, t1, t2) > loadpFromInstruction(5, t3) >- notifyWrite(t3, t1, t2, t0, .pDynamic) >+ notifyWrite(t3, .pDynamic) > loadpFromInstruction(6, t0) > storei t1, TagOffset[t0] > storei t2, PayloadOffset[t0] >@@ -2223,7 +2215,7 @@ macro putLocalClosureVar() > loadConstantOrVariable(t1, t2, t3) > loadpFromInstruction(5, t4) > btpz t4, .noVariableWatchpointSet >- notifyWrite(t4, t2, t3, t1, .pDynamic) >+ notifyWrite(t4, .pDynamic) > .noVariableWatchpointSet: > loadisFromInstruction(6, t1) > storei t2, JSEnvironmentRecord_variables + TagOffset[t0, t1, 8] >Index: Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >=================================================================== >--- Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (revision 182069) >+++ Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (working copy) >@@ -690,13 +690,6 @@ _llint_op_mov: > dispatch(3) > > >-macro notifyWrite(set, value, scratch, slow) >- loadb VariableWatchpointSet::m_state[set], scratch >- bieq scratch, IsInvalidated, .done >- bqneq value, VariableWatchpointSet::m_inferredValue[set], slow >-.done: >-end >- > _llint_op_not: > traceExecution() > loadisFromInstruction(2, t0) >@@ -1944,39 +1937,39 @@ _llint_op_resolve_scope: > #rGlobalProperty: > bineq t0, GlobalProperty, .rGlobalVar > getGlobalObject(1) >- dispatch(7) >+ dispatch(6) > > .rGlobalVar: > bineq t0, GlobalVar, .rClosureVar > getGlobalObject(1) >- dispatch(7) >+ dispatch(6) > > .rClosureVar: > bineq t0, ClosureVar, .rGlobalPropertyWithVarInjectionChecks > resolveScope() >- dispatch(7) >+ dispatch(6) > > .rGlobalPropertyWithVarInjectionChecks: > bineq t0, GlobalPropertyWithVarInjectionChecks, .rGlobalVarWithVarInjectionChecks > varInjectionCheck(.rDynamic) > getGlobalObject(1) >- dispatch(7) >+ dispatch(6) > > .rGlobalVarWithVarInjectionChecks: > bineq t0, GlobalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks > varInjectionCheck(.rDynamic) > getGlobalObject(1) >- dispatch(7) >+ dispatch(6) > > .rClosureVarWithVarInjectionChecks: > bineq t0, ClosureVarWithVarInjectionChecks, .rDynamic > varInjectionCheck(.rDynamic) > resolveScope() >- dispatch(7) >+ dispatch(6) > > .rDynamic: > callSlowPath(_llint_slow_path_resolve_scope) >- dispatch(7) >+ dispatch(6) > > > macro loadWithStructureCheck(operand, slowPath) >@@ -2069,8 +2062,8 @@ macro putGlobalVar() > loadisFromInstruction(3, t0) > loadConstantOrVariable(t0, t1) > loadpFromInstruction(5, t2) >- notifyWrite(t2, t1, t0, .pDynamic) > loadpFromInstruction(6, t0) >+ notifyWrite(t2, .pDynamic) > storeq t1, [t0] > end > >@@ -2086,7 +2079,7 @@ macro putLocalClosureVar() > loadConstantOrVariable(t1, t2) > loadpFromInstruction(5, t3) > btpz t3, .noVariableWatchpointSet >- notifyWrite(t3, t2, t1, .pDynamic) >+ notifyWrite(t3, .pDynamic) > .noVariableWatchpointSet: > loadisFromInstruction(6, t1) > storeq t2, JSEnvironmentRecord_variables[t0, t1, 8] >Index: Source/JavaScriptCore/llint/LowLevelInterpreter.asm >=================================================================== >--- Source/JavaScriptCore/llint/LowLevelInterpreter.asm (revision 182069) >+++ Source/JavaScriptCore/llint/LowLevelInterpreter.asm (working copy) >@@ -519,6 +519,10 @@ macro skipIfIsRememberedOrInEden(cell, s > continuation(scratch1) > end > >+macro notifyWrite(set, slow) >+ bbneq WatchpointSet::m_state[set], IsInvalidated, slow >+end >+ > macro checkSwitchToJIT(increment, action) > loadp CodeBlock[cfr], t0 > baddis increment, CodeBlock::m_llintExecuteCounter + BaselineExecutionCounter::m_counter[t0], .continue >@@ -920,12 +924,6 @@ end > > > # Value-representation-agnostic code. >-_llint_op_touch_entry: >- traceExecution() >- callSlowPath(_slow_path_touch_entry) >- dispatch(1) >- >- > _llint_op_create_direct_arguments: > traceExecution() > callSlowPath(_slow_path_create_direct_arguments) >Index: Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (revision 182069) >+++ Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (working copy) >@@ -206,13 +206,6 @@ SLOW_PATH_DECL(slow_path_construct_arity > RETURN_TWO(0, setupArityCheckData(vm, slotsToAdd)); > } > >-SLOW_PATH_DECL(slow_path_touch_entry) >-{ >- BEGIN(); >- exec->codeBlock()->symbolTable()->m_functionEnteredOnce.touch("Function (re)entered"); >- END(); >-} >- > SLOW_PATH_DECL(slow_path_create_direct_arguments) > { > BEGIN(); >Index: Source/JavaScriptCore/runtime/CommonSlowPaths.h >=================================================================== >--- Source/JavaScriptCore/runtime/CommonSlowPaths.h (revision 182069) >+++ Source/JavaScriptCore/runtime/CommonSlowPaths.h (working copy) >@@ -181,7 +181,6 @@ SLOW_PATH_DECL(name) WTF_INTERNAL > > SLOW_PATH_HIDDEN_DECL(slow_path_call_arityCheck); > SLOW_PATH_HIDDEN_DECL(slow_path_construct_arityCheck); >-SLOW_PATH_HIDDEN_DECL(slow_path_touch_entry); > SLOW_PATH_HIDDEN_DECL(slow_path_create_direct_arguments); > SLOW_PATH_HIDDEN_DECL(slow_path_create_scoped_arguments); > SLOW_PATH_HIDDEN_DECL(slow_path_create_out_of_band_arguments); >Index: Source/JavaScriptCore/runtime/Executable.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/Executable.cpp (revision 182069) >+++ Source/JavaScriptCore/runtime/Executable.cpp (working copy) >@@ -567,6 +567,12 @@ void FunctionExecutable::visitChildren(J > if (thisObject->m_codeBlockForConstruct) > thisObject->m_codeBlockForConstruct->visitAggregate(visitor); > visitor.append(&thisObject->m_unlinkedExecutable); >+ >+ if (thisObject->m_functionReallocationWatchpointSet.needToFinalize()) { >+ if (!thisObject->m_watchpointCleanup) >+ thisObject->m_watchpointCleanup = std::make_unique<WatchpointCleanup>(thisObject); >+ visitor.addUnconditionalFinalizer(thisObject->m_watchpointCleanup.get()); >+ } > } > > SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind) >@@ -622,6 +628,21 @@ FunctionExecutable* FunctionExecutable:: > return unlinkedExecutable->link(exec.vm(), source, overrideLineNumber); > } > >+FunctionExecutable::WatchpointCleanup::WatchpointCleanup(FunctionExecutable* executable) >+ : m_executable(executable) >+{ >+} >+ >+FunctionExecutable::WatchpointCleanup::~WatchpointCleanup() >+{ >+} >+ >+void FunctionExecutable::WatchpointCleanup::finalizeUnconditionally() >+{ >+ m_executable->functionReallocationWatchpointSet().finalizeUnconditionally( >+ StringFireDetail("FunctionExecutable clean-up during GC")); >+} >+ > void ExecutableBase::dump(PrintStream& out) const > { > ExecutableBase* realThis = const_cast<ExecutableBase*>(this); >Index: Source/JavaScriptCore/runtime/Executable.h >=================================================================== >--- Source/JavaScriptCore/runtime/Executable.h (revision 182069) >+++ Source/JavaScriptCore/runtime/Executable.h (working copy) >@@ -33,8 +33,6 @@ > #include "CompilationResult.h" > #include "DFGPlan.h" > #include "HandlerInfo.h" >-#include "JSFunction.h" >-#include "Interpreter.h" > #include "JITCode.h" > #include "JSGlobalObject.h" > #include "RegisterPreservationMode.h" >@@ -42,6 +40,7 @@ > #include "SourceCode.h" > #include "TypeSet.h" > #include "UnlinkedCodeBlock.h" >+#include "VariableWatchpointSet.h" > > namespace JSC { > >@@ -649,6 +648,8 @@ public: > void unlinkCalls(); > > void clearCode(); >+ >+ VariableWatchpointSet& functionReallocationWatchpointSet() { return m_functionReallocationWatchpointSet; } > > private: > FunctionExecutable( >@@ -667,12 +668,26 @@ private: > } > > friend class ScriptExecutable; >+ >+ class WatchpointCleanup : public UnconditionalFinalizer { >+ public: >+ WatchpointCleanup(FunctionExecutable*); >+ virtual ~WatchpointCleanup(); >+ >+ protected: >+ void finalizeUnconditionally() override; >+ >+ private: >+ FunctionExecutable* m_executable; >+ }; > > WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable; > RefPtr<FunctionCodeBlock> m_codeBlockForCall; > RefPtr<FunctionCodeBlock> m_codeBlockForConstruct; > RefPtr<TypeSet> m_returnStatementTypeSet; > unsigned m_parametersStartOffset; >+ VariableWatchpointSet m_functionReallocationWatchpointSet; >+ std::unique_ptr<WatchpointCleanup> m_watchpointCleanup; > }; > > inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable) >Index: Source/JavaScriptCore/runtime/JSCInlines.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSCInlines.h (revision 182069) >+++ Source/JavaScriptCore/runtime/JSCInlines.h (working copy) >@@ -51,6 +51,7 @@ > #include "Operations.h" > #include "SlotVisitorInlines.h" > #include "StructureInlines.h" >+#include "VariableWatchpointSetInlines.h" > #include "WeakGCMapInlines.h" > > #endif // JSCInlines_h >Index: Source/JavaScriptCore/runtime/JSFunction.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSFunction.cpp (revision 182069) >+++ Source/JavaScriptCore/runtime/JSFunction.cpp (working copy) >@@ -59,6 +59,14 @@ bool JSFunction::isHostFunctionNonInline > return isHostFunction(); > } > >+JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope) >+{ >+ JSFunction* result = createImpl(vm, executable, scope); >+ executable->functionReallocationWatchpointSet().notifyWrite( >+ vm, executable, result, "Allocating a function"); >+ return result; >+} >+ > JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor) > { > NativeExecutable* executable; >Index: Source/JavaScriptCore/runtime/JSFunction.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSFunction.h (revision 182069) >+++ Source/JavaScriptCore/runtime/JSFunction.h (working copy) >@@ -24,6 +24,7 @@ > #ifndef JSFunction_h > #define JSFunction_h > >+#include "Executable.h" > #include "InternalFunction.h" > #include "JSCallee.h" > #include "JSScope.h" >@@ -59,15 +60,15 @@ public: > typedef JSCallee Base; > > JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor); >- >- static JSFunction* create(VM& vm, FunctionExecutable* executable, JSScope* scope) >+ >+ static JSFunction* createWithInvalidatedReallocationWatchpoint(VM& vm, FunctionExecutable* executable, JSScope* scope) > { >- JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope); >- ASSERT(function->structure()->globalObject()); >- function->finishCreation(vm); >- return function; >+ ASSERT(executable->functionReallocationWatchpointSet().hasBeenInvalidated()); >+ return createImpl(vm, executable, scope); > } > >+ static JSFunction* create(VM&, FunctionExecutable*, JSScope*); >+ > static JSFunction* createBuiltinFunction(VM&, FunctionExecutable*, JSGlobalObject*); > > static void destroy(JSCell*); >@@ -149,6 +150,14 @@ protected: > static void visitChildren(JSCell*, SlotVisitor&); > > private: >+ static JSFunction* createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope) >+ { >+ JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope); >+ ASSERT(function->structure()->globalObject()); >+ function->finishCreation(vm); >+ return function; >+ } >+ > friend class LLIntOffsetsExtractor; > > static EncodedJSValue argumentsGetter(ExecState*, JSObject*, EncodedJSValue, PropertyName); >Index: Source/JavaScriptCore/runtime/JSGlobalObject.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSGlobalObject.cpp (revision 182069) >+++ Source/JavaScriptCore/runtime/JSGlobalObject.cpp (working copy) >@@ -125,6 +125,7 @@ > #include "SymbolConstructor.h" > #include "SymbolPrototype.h" > #include "VariableWatchpointSetInlines.h" >+#include "VariableWriteFireDetail.h" > #include "WeakGCMapInlines.h" > #include "WeakMapConstructor.h" > #include "WeakMapPrototype.h" >@@ -489,7 +490,7 @@ JSGlobalObject::NewGlobalVar JSGlobalObj > ScopeOffset offset = symbolTable()->takeNextScopeOffset(locker); > SymbolTableEntry newEntry(VarOffset(offset), (constantMode == IsConstant) ? ReadOnly : 0); > if (constantMode == IsVariable) >- newEntry.prepareToWatch(symbolTable()); >+ newEntry.prepareToWatch(); > else > newEntry.disableWatching(); > symbolTable()->add(locker, ident.impl(), newEntry); >@@ -510,7 +511,7 @@ void JSGlobalObject::addFunction(ExecSta > NewGlobalVar var = addGlobalVar(propertyName, IsVariable); > variableAt(var.offset).set(exec->vm(), this, value); > if (var.set) >- var.set->notifyWrite(vm, value, VariableWriteFireDetail(this, propertyName)); >+ var.set->touch(VariableWriteFireDetail(this, propertyName)); > } > > static inline JSObject* lastInPrototypeChain(JSObject* object) >Index: Source/JavaScriptCore/runtime/JSGlobalObject.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSGlobalObject.h (revision 182069) >+++ Source/JavaScriptCore/runtime/JSGlobalObject.h (working copy) >@@ -332,7 +332,7 @@ protected: > > struct NewGlobalVar { > ScopeOffset offset; >- VariableWatchpointSet* set; >+ WatchpointSet* set; > }; > NewGlobalVar addGlobalVar(const Identifier&, ConstantMode); > >Index: Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp (revision 182069) >+++ Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp (working copy) >@@ -77,6 +77,7 @@ inline bool JSLexicalEnvironment::symbol > ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); > > WriteBarrierBase<Unknown>* reg; >+ WatchpointSet* set; > { > GCSafeConcurrentJITLocker locker(symbolTable()->m_lock, exec->vm().heap); > SymbolTable::Map::iterator iter = symbolTable()->find(locker, propertyName.uid()); >@@ -92,11 +93,12 @@ inline bool JSLexicalEnvironment::symbol > // Defend against the inspector asking for a var after it has been optimized out. > if (!isValid(offset)) > return false; >- if (VariableWatchpointSet* set = iter->value.watchpointSet()) >- set->invalidate(VariableWriteFireDetail(this, propertyName)); // Don't mess around - if we had found this statically, we would have invalidated it. >+ set = iter->value.watchpointSet(); > reg = &variableAt(offset); > } > reg->set(vm, this, value); >+ if (set) >+ set->invalidate(VariableWriteFireDetail(this, propertyName)); // Don't mess around - if we had found this statically, we would have invalidated it. > return true; > } > >Index: Source/JavaScriptCore/runtime/JSScope.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSScope.h (revision 182069) >+++ Source/JavaScriptCore/runtime/JSScope.h (working copy) >@@ -31,7 +31,7 @@ > namespace JSC { > > class ScopeChainIterator; >-class VariableWatchpointSet; >+class WatchpointSet; > > enum ResolveMode { > ThrowIfNotFound, >@@ -102,7 +102,7 @@ inline bool needsVarInjectionChecks(Reso > } > > struct ResolveOp { >- ResolveOp(ResolveType type, size_t depth, Structure* structure, JSLexicalEnvironment* lexicalEnvironment, VariableWatchpointSet* watchpointSet, uintptr_t operand) >+ ResolveOp(ResolveType type, size_t depth, Structure* structure, JSLexicalEnvironment* lexicalEnvironment, WatchpointSet* watchpointSet, uintptr_t operand) > : type(type) > , depth(depth) > , structure(structure) >@@ -116,7 +116,7 @@ struct ResolveOp { > size_t depth; > Structure* structure; > JSLexicalEnvironment* lexicalEnvironment; >- VariableWatchpointSet* watchpointSet; >+ WatchpointSet* watchpointSet; > uintptr_t operand; > }; > >Index: Source/JavaScriptCore/runtime/JSSymbolTableObject.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSSymbolTableObject.h (revision 182069) >+++ Source/JavaScriptCore/runtime/JSSymbolTableObject.h (working copy) >@@ -32,7 +32,7 @@ > #include "JSScope.h" > #include "PropertyDescriptor.h" > #include "SymbolTable.h" >-#include "VariableWatchpointSetInlines.h" >+#include "VariableWriteFireDetail.h" > > namespace JSC { > >@@ -126,6 +126,7 @@ inline bool symbolTablePut( > ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); > > WriteBarrierBase<Unknown>* reg; >+ WatchpointSet* set; > { > SymbolTable& symbolTable = *object->symbolTable(); > // FIXME: This is very suspicious. We shouldn't need a GC-safe lock here. >@@ -142,17 +143,15 @@ inline bool symbolTablePut( > throwTypeError(exec, StrictModeReadonlyPropertyWriteError); > return true; > } >- if (VariableWatchpointSet* set = iter->value.watchpointSet()) { >- // FIXME: It's strange that we're doing this while holding the symbol table's lock. >- // https://bugs.webkit.org/show_bug.cgi?id=134601 >- set->notifyWrite(vm, value, object, propertyName); >- } >+ set = iter->value.watchpointSet(); > reg = &object->variableAt(fastEntry.scopeOffset()); > } > // I'd prefer we not hold lock while executing barriers, since I prefer to reserve > // the right for barriers to be able to trigger GC. And I don't want to hold VM > // locks while GC'ing. > reg->set(vm, object, value); >+ if (set) >+ VariableWriteFireDetail::touch(set, object, propertyName); > return true; > } > >@@ -164,6 +163,7 @@ inline bool symbolTablePutWithAttributes > ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); > > WriteBarrierBase<Unknown>* reg; >+ WatchpointSet* set; > { > SymbolTable& symbolTable = *object->symbolTable(); > ConcurrentJITLocker locker(symbolTable.m_lock); >@@ -172,12 +172,13 @@ inline bool symbolTablePutWithAttributes > return false; > SymbolTableEntry& entry = iter->value; > ASSERT(!entry.isNull()); >- if (VariableWatchpointSet* set = entry.watchpointSet()) >- set->notifyWrite(vm, value, object, propertyName); >+ set = entry.watchpointSet(); > entry.setAttributes(attributes); > reg = &object->variableAt(entry.scopeOffset()); > } > reg->set(vm, object, value); >+ if (set) >+ VariableWriteFireDetail::touch(set, object, propertyName); > return true; > } > >Index: Source/JavaScriptCore/runtime/PutPropertySlot.h >=================================================================== >--- Source/JavaScriptCore/runtime/PutPropertySlot.h (revision 182069) >+++ Source/JavaScriptCore/runtime/PutPropertySlot.h (working copy) >@@ -28,6 +28,7 @@ > #define PutPropertySlot_h > > #include "JSCJSValue.h" >+#include "PropertyOffset.h" > > #include <wtf/Assertions.h> > >Index: Source/JavaScriptCore/runtime/SymbolTable.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/SymbolTable.cpp (revision 182069) >+++ Source/JavaScriptCore/runtime/SymbolTable.cpp (working copy) >@@ -33,7 +33,6 @@ > #include "JSCInlines.h" > #include "SlotVisitorInlines.h" > #include "TypeProfiler.h" >-#include "VariableWatchpointSetInlines.h" > > namespace JSC { > >@@ -60,21 +59,14 @@ void SymbolTableEntry::freeFatEntrySlow( > delete fatEntry(); > } > >-JSValue SymbolTableEntry::inferredValue() >-{ >- if (!isFat()) >- return JSValue(); >- return fatEntry()->m_watchpoints->inferredValue(); >-} >- >-void SymbolTableEntry::prepareToWatch(SymbolTable* symbolTable) >+void SymbolTableEntry::prepareToWatch() > { > if (!isWatchable()) > return; > FatEntry* entry = inflate(); > if (entry->m_watchpoints) > return; >- entry->m_watchpoints = adoptRef(new VariableWatchpointSet(*symbolTable)); >+ entry->m_watchpoints = adoptRef(new WatchpointSet(ClearWatchpoint)); > } > > void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint) >@@ -82,15 +74,6 @@ void SymbolTableEntry::addWatchpoint(Wat > fatEntry()->m_watchpoints->add(watchpoint); > } > >-void SymbolTableEntry::notifyWriteSlow(VM& vm, JSValue value, const FireDetail& detail) >-{ >- VariableWatchpointSet* watchpoints = fatEntry()->m_watchpoints.get(); >- if (!watchpoints) >- return; >- >- watchpoints->notifyWrite(vm, value, detail); >-} >- > SymbolTableEntry::FatEntry* SymbolTableEntry::inflateSlow() > { > FatEntry* entry = new FatEntry(m_bits); >@@ -101,7 +84,6 @@ SymbolTableEntry::FatEntry* SymbolTableE > SymbolTable::SymbolTable(VM& vm) > : JSCell(vm, vm.symbolTableStructure.get()) > , m_usesNonStrictEval(false) >- , m_functionEnteredOnce(ClearWatchpoint) > { > } > >@@ -113,36 +95,11 @@ void SymbolTable::visitChildren(JSCell* > > visitor.append(&thisSymbolTable->m_arguments); > >- if (!thisSymbolTable->m_watchpointCleanup) { >- thisSymbolTable->m_watchpointCleanup = >- std::make_unique<WatchpointCleanup>(thisSymbolTable); >- } >- >- visitor.addUnconditionalFinalizer(thisSymbolTable->m_watchpointCleanup.get()); >- > // Save some memory. This is O(n) to rebuild and we do so on the fly. > ConcurrentJITLocker locker(thisSymbolTable->m_lock); > thisSymbolTable->m_localToEntry = nullptr; > } > >-SymbolTable::WatchpointCleanup::WatchpointCleanup(SymbolTable* symbolTable) >- : m_symbolTable(symbolTable) >-{ >-} >- >-SymbolTable::WatchpointCleanup::~WatchpointCleanup() { } >- >-void SymbolTable::WatchpointCleanup::finalizeUnconditionally() >-{ >- StringFireDetail detail("Symbol table clean-up during GC"); >- Map::iterator iter = m_symbolTable->m_map.begin(); >- Map::iterator end = m_symbolTable->m_map.end(); >- for (; iter != end; ++iter) { >- if (VariableWatchpointSet* set = iter->value.watchpointSet()) >- set->finalizeUnconditionally(detail); >- } >-} >- > const SymbolTable::LocalToEntryVec& SymbolTable::localToEntry(const ConcurrentJITLocker&) > { > if (UNLIKELY(!m_localToEntry)) { >Index: Source/JavaScriptCore/runtime/SymbolTable.h >=================================================================== >--- Source/JavaScriptCore/runtime/SymbolTable.h (revision 182069) >+++ Source/JavaScriptCore/runtime/SymbolTable.h (working copy) >@@ -35,13 +35,15 @@ > #include "ScopedArgumentsTable.h" > #include "TypeLocation.h" > #include "VarOffset.h" >-#include "VariableWatchpointSet.h" >+#include "Watchpoint.h" > #include <memory> > #include <wtf/HashTraits.h> > #include <wtf/text/StringImpl.h> > > namespace JSC { > >+class SymbolTable; >+ > static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } > > // The bit twiddling in this class assumes that every register index is a >@@ -63,11 +65,11 @@ static ALWAYS_INLINE int missingSymbolMa > // counted pointer to a shared WatchpointSet. Thus, in-place edits of the > // WatchpointSet will manifest in all copies. Here's a picture: > // >-// SymbolTableEntry --> FatEntry --> VariableWatchpointSet >+// SymbolTableEntry --> FatEntry --> WatchpointSet > // > // If you make a copy of a SymbolTableEntry, you will have: > // >-// original: SymbolTableEntry --> FatEntry --> VariableWatchpointSet >+// original: SymbolTableEntry --> FatEntry --> WatchpointSet > // copy: SymbolTableEntry --> FatEntry -----^ > > struct SymbolTableEntry { >@@ -260,32 +262,44 @@ public: > return bits() & DontEnumFlag; > } > >- JSValue inferredValue(); >- > void disableWatching() > { >+ if (WatchpointSet* set = watchpointSet()) >+ set->invalidate("Disabling watching in symbol table"); > if (varOffset().isScope()) > pack(varOffset(), false, isReadOnly(), isDontEnum()); > } > >- void prepareToWatch(SymbolTable*); >+ void prepareToWatch(); > > void addWatchpoint(Watchpoint*); > >- VariableWatchpointSet* watchpointSet() >+ // This watchpoint set is initialized clear, and goes through the following state transitions: >+ // >+ // First write to this var, in any scope that has this symbol table: Clear->IsWatched. >+ // >+ // Second write to this var, in any scope that has this symbol table: IsWatched->IsInvalidated. >+ // >+ // We ensure that we touch the set (i.e. trigger its state transition) after we do the write. This >+ // means that if you're in the compiler thread, and you: >+ // >+ // 1) Observe that the set IsWatched and commit to adding your watchpoint. >+ // 2) Load a value from any scope that has this watchpoint set. >+ // >+ // Then you can be sure that that value is either going to be the correct value for that var forever, >+ // or the watchpoint set will invalidate and you'll get fired. >+ // >+ // It's possible to write a program that first creates multiple scopes with the same var, and then >+ // initializes that var in just one of them. This means that a compilation could constant-fold to one >+ // of the scopes that still has an undefined value for this variable. That's fine, because at that >+ // point any write to any of the instances of that variable would fire the watchpoint. >+ WatchpointSet* watchpointSet() > { > if (!isFat()) > return 0; > return fatEntry()->m_watchpoints.get(); > } > >- ALWAYS_INLINE void notifyWrite(VM& vm, JSValue value, const FireDetail& detail) >- { >- if (LIKELY(!isFat())) >- return; >- notifyWriteSlow(vm, value, detail); >- } >- > private: > static const intptr_t SlimFlag = 0x1; > static const intptr_t ReadOnlyFlag = 0x2; >@@ -308,7 +322,7 @@ private: > > intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat. > >- RefPtr<VariableWatchpointSet> m_watchpoints; >+ RefPtr<WatchpointSet> m_watchpoints; > }; > > SymbolTableEntry& copySlow(const SymbolTableEntry&); >@@ -646,18 +660,6 @@ protected: > static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags; > > private: >- class WatchpointCleanup : public UnconditionalFinalizer { >- public: >- WatchpointCleanup(SymbolTable*); >- virtual ~WatchpointCleanup(); >- >- protected: >- virtual void finalizeUnconditionally() override; >- >- private: >- SymbolTable* m_symbolTable; >- }; >- > JS_EXPORT_PRIVATE SymbolTable(VM&); > ~SymbolTable(); > >@@ -675,12 +677,9 @@ private: > > WriteBarrier<ScopedArgumentsTable> m_arguments; > >- std::unique_ptr<WatchpointCleanup> m_watchpointCleanup; > std::unique_ptr<LocalToEntryVec> m_localToEntry; > > public: >- InlineWatchpointSet m_functionEnteredOnce; >- > mutable ConcurrentJITLock m_lock; > }; > >Index: Source/JavaScriptCore/runtime/TypeProfiler.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/TypeProfiler.cpp (revision 182069) >+++ Source/JavaScriptCore/runtime/TypeProfiler.cpp (working copy) >@@ -28,6 +28,7 @@ > > #include "InspectorProtocolObjects.h" > #include "TypeLocation.h" >+#include <wtf/text/StringBuilder.h> > > namespace JSC { > >Index: Source/JavaScriptCore/tests/stress/infer-uninitialized-closure-var.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/infer-uninitialized-closure-var.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/infer-uninitialized-closure-var.js (working copy) >@@ -0,0 +1,26 @@ >+function foo(p) { >+ var x; >+ >+ noInline(f); >+ >+ if (p) { >+ var f = function() { return x; } >+ >+ foo(false); >+ >+ for (var i = 0; i < 10000; ++i) { >+ var result = f(); >+ if (result !== void 0) >+ throw "Error: bad result (1): " + result; >+ } >+ >+ x = 43; >+ >+ var result = f(); >+ if (result != 43) >+ throw "Error: bad result (2): " + result; >+ } else >+ x = 42; >+} >+ >+foo(true); >Index: Source/JavaScriptCore/tests/stress/singleton-scope-then-overwrite.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/singleton-scope-then-overwrite.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/singleton-scope-then-overwrite.js (working copy) >@@ -0,0 +1,20 @@ >+function foo(a) { >+ var x = a + 1; >+ var f = function(a) { >+ return x + a; >+ }; >+ noInline(f); >+ for (var i = 0; i < 10000; ++i) { >+ var result = f(i); >+ if (result != a + 1 + i) >+ throw "Error: bad result: " + result; >+ } >+ x = 999; >+ var result = f(1); >+ if (result != 999 + 1) >+ throw "Error: bad result: " + result; >+} >+ >+noInline(foo); >+for (var i = 0; i < 3; ++i) >+ foo(42 + i); >Index: Source/JavaScriptCore/tests/stress/singleton-scope-then-realloc-and-overwrite.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/singleton-scope-then-realloc-and-overwrite.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/singleton-scope-then-realloc-and-overwrite.js (working copy) >@@ -0,0 +1,20 @@ >+function foo(a) { >+ var x = a + 1; >+ return function(a) { >+ return x + a; >+ }; >+} >+ >+var f = foo(42); >+noInline(f); >+ >+for (var i = 0; i < 10000; ++i) { >+ var result = f(i); >+ if (result != 42 + 1 + i) >+ throw "Error: bad result: " + result; >+} >+ >+var f = foo(43); >+var result = f(1); >+if (result != 43 + 1 + 1) >+ throw "Error: bad result: " + result; >Index: Source/JavaScriptCore/tests/stress/singleton-scope-then-realloc.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/singleton-scope-then-realloc.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/singleton-scope-then-realloc.js (working copy) >@@ -0,0 +1,20 @@ >+function foo(a) { >+ var x = a + 1; >+ return function(a) { >+ return x += a; >+ }; >+} >+ >+var f = foo(42); >+noInline(f); >+ >+for (var i = 0; i < 10000; ++i) { >+ var result = f(1); >+ if (result != 42 + 1 + i + 1) >+ throw "Error: bad result: " + result; >+} >+ >+var f = foo(43); >+var result = f(1); >+if (result != 43 + 1 + 1) >+ throw "Error: bad result: " + result; >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 182191) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,20 @@ >+2015-03-31 Filip Pizlo <fpizlo@apple.com> >+ >+ JSC should detect singleton functions >+ https://bugs.webkit.org/show_bug.cgi?id=143232 >+ >+ Reviewed by Michael Saboff. >+ >+ * js/regress/create-lots-of-functions-expected.txt: Added. >+ * js/regress/create-lots-of-functions.html: Added. >+ * js/regress/no-inline-constructor-expected.txt: Added. >+ * js/regress/no-inline-constructor.html: Added. >+ * js/regress/script-tests/create-lots-of-functions.js: Added. >+ * js/regress/script-tests/no-inline-constructor.js: Added. >+ * js/regress/script-tests/singleton-scope.js: Added. >+ * js/regress/singleton-scope-expected.txt: Added. >+ * js/regress/singleton-scope.html: Added. >+ > 2015-03-31 Beth Dakin <bdakin@apple.com> > > REGRESSION (r173484): Reducing content of scrollable region does not reset scroll >Index: LayoutTests/js/regress/create-lots-of-functions-expected.txt >=================================================================== >--- LayoutTests/js/regress/create-lots-of-functions-expected.txt (revision 0) >+++ LayoutTests/js/regress/create-lots-of-functions-expected.txt (working copy) >@@ -0,0 +1,10 @@ >+JSRegress/create-lots-of-functions >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+ >+PASS no exception thrown >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >Index: LayoutTests/js/regress/create-lots-of-functions.html >=================================================================== >--- LayoutTests/js/regress/create-lots-of-functions.html (revision 0) >+++ LayoutTests/js/regress/create-lots-of-functions.html (working copy) >@@ -0,0 +1,12 @@ >+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script src="../../resources/regress-pre.js"></script> >+<script src="script-tests/create-lots-of-functions.js"></script> >+<script src="../../resources/regress-post.js"></script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >Index: LayoutTests/js/regress/no-inline-constructor-expected.txt >=================================================================== >--- LayoutTests/js/regress/no-inline-constructor-expected.txt (revision 0) >+++ LayoutTests/js/regress/no-inline-constructor-expected.txt (working copy) >@@ -0,0 +1,10 @@ >+JSRegress/no-inline-constructor >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+ >+PASS no exception thrown >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >Index: LayoutTests/js/regress/no-inline-constructor.html >=================================================================== >--- LayoutTests/js/regress/no-inline-constructor.html (revision 0) >+++ LayoutTests/js/regress/no-inline-constructor.html (working copy) >@@ -0,0 +1,12 @@ >+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script src="../../resources/regress-pre.js"></script> >+<script src="script-tests/no-inline-constructor.js"></script> >+<script src="../../resources/regress-post.js"></script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >Index: LayoutTests/js/regress/singleton-scope-expected.txt >=================================================================== >--- LayoutTests/js/regress/singleton-scope-expected.txt (revision 0) >+++ LayoutTests/js/regress/singleton-scope-expected.txt (working copy) >@@ -0,0 +1,10 @@ >+JSRegress/singleton-scope >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+ >+PASS no exception thrown >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >Index: LayoutTests/js/regress/singleton-scope.html >=================================================================== >--- LayoutTests/js/regress/singleton-scope.html (revision 0) >+++ LayoutTests/js/regress/singleton-scope.html (working copy) >@@ -0,0 +1,12 @@ >+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script src="../../resources/regress-pre.js"></script> >+<script src="script-tests/singleton-scope.js"></script> >+<script src="../../resources/regress-post.js"></script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >Index: LayoutTests/js/regress/script-tests/create-lots-of-functions.js >=================================================================== >--- LayoutTests/js/regress/script-tests/create-lots-of-functions.js (revision 0) >+++ LayoutTests/js/regress/script-tests/create-lots-of-functions.js (working copy) >@@ -0,0 +1,12 @@ >+function foo() { >+ var result = 0; >+ for (var i = 0; i < 100; ++i) >+ result += (function() { return i })(); >+ return result; >+} >+ >+for (var i = 0; i < 10000; ++i) { >+ var result = foo(); >+ if (result != 4950) >+ throw "Error: bad result: " + result; >+} >Index: LayoutTests/js/regress/script-tests/no-inline-constructor.js >=================================================================== >--- LayoutTests/js/regress/script-tests/no-inline-constructor.js (revision 0) >+++ LayoutTests/js/regress/script-tests/no-inline-constructor.js (working copy) >@@ -0,0 +1,13 @@ >+function Foo() { >+ var o = {f:{f:{f:{f:42}}}}; >+ this.f = 42; >+} >+ >+noInline(Foo); >+ >+for (var i = 0; i < 3000000; ++i) { >+ var result = new Foo(); >+ if (result.f != 42) >+ throw "Error: bad result: " + result.f; >+} >+ >Index: LayoutTests/js/regress/script-tests/singleton-scope.js >=================================================================== >--- LayoutTests/js/regress/script-tests/singleton-scope.js (revision 0) >+++ LayoutTests/js/regress/script-tests/singleton-scope.js (working copy) >@@ -0,0 +1,16 @@ >+function foo() { >+ var x = 42; >+ var y = 43; >+ return function(z) { >+ var result = x + y; >+ x += z; >+ y += z; >+ return result; >+ } >+} >+ >+var f = foo(); >+noInline(f); >+ >+for (var i = 0; i < 10000000; ++i) >+ f(1);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 143232
:
249753
|
249774
|
249840
|
249844
|
249865
|
250317
|
250327
|
250331
|
250374
|
250384
|
250392
|
250407