Commit c862eacf authored by ggaren@apple.com's avatar ggaren@apple.com

Static size inference for JavaScript objects

https://bugs.webkit.org/show_bug.cgi?id=108093

Reviewed by Phil Pizlo.

../JavaScriptCore: 

* API/JSObjectRef.cpp:
* JavaScriptCore.order:
* JavaScriptCore.xcodeproj/project.pbxproj: Pay the tax man.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode): op_new_object and op_create_this now
have an extra inferredInlineCapacity argument. This is the statically
inferred inline capacity, just from analyzing source text. op_new_object
also gets a pointer to an allocation profile. (For op_create_this, the
profile is in the construtor function.)

(JSC::CodeBlock::CodeBlock): Link op_new_object.

(JSC::CodeBlock::stronglyVisitStrongReferences): Mark our profiles.

* bytecode/CodeBlock.h:
(CodeBlock): Removed some dead code. Added object allocation profiles.

* bytecode/Instruction.h:
(JSC): New union type, since an instruction operand may point to an
object allocation profile now.

* bytecode/ObjectAllocationProfile.h: Added.
(JSC):
(ObjectAllocationProfile):
(JSC::ObjectAllocationProfile::offsetOfAllocator):
(JSC::ObjectAllocationProfile::offsetOfStructure):
(JSC::ObjectAllocationProfile::ObjectAllocationProfile):
(JSC::ObjectAllocationProfile::isNull):
(JSC::ObjectAllocationProfile::initialize):
(JSC::ObjectAllocationProfile::structure):
(JSC::ObjectAllocationProfile::inlineCapacity):
(JSC::ObjectAllocationProfile::clear):
(JSC::ObjectAllocationProfile::visitAggregate):
(JSC::ObjectAllocationProfile::possibleDefaultPropertyCount): New class
for tracking a prediction about object allocation: structure, inline
capacity, allocator to use.

* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName): Updated instruction sizes.

* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC):
(JSC::UnlinkedCodeBlock::addObjectAllocationProfile):
(JSC::UnlinkedCodeBlock::numberOfObjectAllocationProfiles):
(UnlinkedCodeBlock): Unlinked support for allocation profiles.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate): Kill all remaining analyses at the
end of codegen, since this is our last opportunity.

(JSC::BytecodeGenerator::BytecodeGenerator): Added a static property
analyzer to bytecode generation. It tracks initializing assignments and
makes a guess about how many will happen.

(JSC::BytecodeGenerator::newObjectAllocationProfile):
(JSC):
(JSC::BytecodeGenerator::emitProfiledOpcode):
(JSC::BytecodeGenerator::emitMove):
(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveBase):
(JSC::BytecodeGenerator::emitResolveBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithThis):
(JSC::BytecodeGenerator::emitGetById):
(JSC::BytecodeGenerator::emitPutById):
(JSC::BytecodeGenerator::emitDirectPutById):
(JSC::BytecodeGenerator::emitPutGetterSetter):
(JSC::BytecodeGenerator::emitGetArgumentByVal):
(JSC::BytecodeGenerator::emitGetByVal): Added hooks to the static property
analyzer, so it can observe allocations and stores.

(JSC::BytecodeGenerator::emitCreateThis): Factored this into a helper
function because it was a significant amount of logic, and I wanted to
add to it.

(JSC::BytecodeGenerator::emitNewObject):
(JSC::BytecodeGenerator::emitExpectedFunctionSnippet):
(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::emitCallVarargs):
(JSC::BytecodeGenerator::emitConstruct): Added a hook to profiled opcodes
to track their stores, in case a store kills a profiled allocation. Since
profiled opcodes are basically the only interesting stores we do, this
is a convenient place to notice any store that might kill an allocation.

* bytecompiler/BytecodeGenerator.h:
(BytecodeGenerator): As above.

* bytecompiler/StaticPropertyAnalysis.h: Added.
(JSC):
(StaticPropertyAnalysis):
(JSC::StaticPropertyAnalysis::create):
(JSC::StaticPropertyAnalysis::addPropertyIndex):
(JSC::StaticPropertyAnalysis::record):
(JSC::StaticPropertyAnalysis::propertyIndexCount):
(JSC::StaticPropertyAnalysis::StaticPropertyAnalysis): Simple helper
class for tracking allocations and stores.

* bytecompiler/StaticPropertyAnalyzer.h: Added.
(StaticPropertyAnalyzer):
(JSC::StaticPropertyAnalyzer::StaticPropertyAnalyzer):
(JSC::StaticPropertyAnalyzer::createThis):
(JSC::StaticPropertyAnalyzer::newObject):
(JSC::StaticPropertyAnalyzer::putById):
(JSC::StaticPropertyAnalyzer::mov):
(JSC::StaticPropertyAnalyzer::kill): Helper class for observing allocations
and stores and making an inline capacity guess. The heuristics here are
intentionally minimal because we don't want this one class to try to
re-create something like a DFG or a runtime analysis. If we discover that
we need those kinds of analyses, we should just replace this class with
something else.

This class tracks multiple registers that alias the same object -- that
happens a lot, when moving locals into temporary registers -- but it
doesn't track control flow or multiple objects that alias the same register.

* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute): Updated for rename.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock): Updated for inline capacity and
allocation profile.

* dfg/DFGNode.h:
(JSC::DFG::Node::hasInlineCapacity):
(Node):
(JSC::DFG::Node::inlineCapacity):
(JSC::DFG::Node::hasFunction): Give the graph a good way to represent
inline capacity for an allocation.

* dfg/DFGNodeType.h:
(DFG): Updated for rename.

* dfg/DFGOperations.cpp: Updated for interface change.

* dfg/DFGOperations.h: We pass the inline capacity to the slow case as
an argument. This is the simplest way, since it's stored as a bytecode operand.

* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate): Updated for rename.

* dfg/DFGRepatch.cpp:
(JSC::DFG::tryCacheGetByID): Fixed a horrible off-by-one-half bug that only
appears when doing an inline cached load for property number 64 on a 32-bit
system. In JSVALUE32_64 land, "offsetRelativeToPatchedStorage" is the
offset of the 64bit JSValue -- but we'll actually issue two loads, one for
the payload at that offset, and one for the tag at that offset + 4. We need
to ensure that both loads have a compact representation, or we'll corrupt
the instruction stream.

* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::emitAllocateJSArray):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculativeJIT::emitAllocateBasicStorage):
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::emitAllocateJSObject):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile): Lots of refactoring to support
passing an allocator to our allocation function, and/or passing a Structure
as a register instead of an immediate.

* heap/MarkedAllocator.h:
(DFG):
(MarkedAllocator):
(JSC::MarkedAllocator::offsetOfFreeListHead): Added an accessor to simplify
JIT code generation of allocation from an arbitrary allocator.

* jit/JIT.h:
(JSC):
* jit/JITInlines.h:
(JSC):
(JSC::JIT::emitAllocateJSObject):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_new_object):
(JSC::JIT::emitSlow_op_new_object):
(JSC::JIT::emit_op_create_this):
(JSC::JIT::emitSlow_op_create_this):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_new_object):
(JSC::JIT::emitSlow_op_new_object):
(JSC::JIT::emit_op_create_this):
(JSC::JIT::emitSlow_op_create_this): Same refactoring as done for the DFG.

* jit/JITStubs.cpp:
(JSC::tryCacheGetByID): Fixed the same bug mentioned above.

(JSC::DEFINE_STUB_FUNCTION): Updated for interface changes.

* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions): Updated for interface changes.

* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm: Same refactoring as for the JITs.

* profiler/ProfilerBytecode.cpp:
* profiler/ProfilerBytecodes.cpp:
* profiler/ProfilerCompilation.cpp:
* profiler/ProfilerCompiledBytecode.cpp:
* profiler/ProfilerDatabase.cpp:
* profiler/ProfilerOSRExit.cpp:
* profiler/ProfilerOrigin.cpp:
* profiler/ProfilerProfiledBytecodes.cpp: Include ObjectConstructor.h
because that's where createEmptyObject() lives now.

* runtime/Executable.h:
(JSC::JSFunction::JSFunction): Updated for rename.

* runtime/JSCellInlines.h:
(JSC::allocateCell): Updated to match the allocator selection code in
the JIT, so it's clearer that both are correct.

* runtime/JSFunction.cpp:
(JSC::JSFunction::JSFunction):
(JSC::JSFunction::createAllocationProfile):
(JSC::JSFunction::visitChildren):
(JSC::JSFunction::getOwnPropertySlot):
(JSC::JSFunction::put):
(JSC::JSFunction::defineOwnProperty):
(JSC::JSFunction::getConstructData):
* runtime/JSFunction.h:
(JSC::JSFunction::offsetOfScopeChain):
(JSC::JSFunction::offsetOfExecutable):
(JSC::JSFunction::offsetOfAllocationProfile):
(JSC::JSFunction::allocationProfile):
(JSFunction):
(JSC::JSFunction::tryGetAllocationProfile):
(JSC::JSFunction::addAllocationProfileWatchpoint): Changed inheritorID
data member to be an ObjectAllocationProfile, which includes a pointer
to the desired allocator. This simplifies JIT code, since we don't have
to compute the allocator on the fly. I verified by code inspection that
JSFunction is still only 64 bytes.

* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
(JSC::JSGlobalObject::dateStructure): No direct pointer to the empty
object structure anymore, because now clients need to specify how much
inline capacity they want.

* runtime/JSONObject.cpp:
* runtime/JSObject.h:
(JSC):
(JSFinalObject):
(JSC::JSFinalObject::defaultInlineCapacity):
(JSC::JSFinalObject::maxInlineCapacity):
(JSC::JSFinalObject::createStructure): A little refactoring to try to 
clarify where some of these constants derive from.

(JSC::maxOffsetRelativeToPatchedStorage): Used for bug fix, above.

* runtime/JSProxy.cpp:
(JSC::JSProxy::setTarget): Ugly, but effective.

* runtime/LiteralParser.cpp:
* runtime/ObjectConstructor.cpp:
(JSC::constructObject):
(JSC::constructWithObjectConstructor):
(JSC::callObjectConstructor):
(JSC::objectConstructorCreate): Updated for interface changes.

* runtime/ObjectConstructor.h:
(JSC::constructEmptyObject): Clarified your options for how to allocate
an empty object, to emphasize what things can actually vary.

* runtime/PropertyOffset.h: These constants have moved because they're
really higher level concepts to do with the layout of objects and the
collector. PropertyOffset is just an abstract number line, independent
of those things.

* runtime/PrototypeMap.cpp:
(JSC::PrototypeMap::emptyObjectStructureForPrototype):
(JSC::PrototypeMap::clearEmptyObjectStructureForPrototype):
* runtime/PrototypeMap.h:
(PrototypeMap): The map key is now a pair of prototype and inline capacity,
since Structure encodes inline capacity.

* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::nonPropertyTransition):
(JSC::Structure::copyPropertyTableForPinning):
* runtime/Structure.h:
(Structure):
(JSC::Structure::totalStorageSize):
(JSC::Structure::transitionCount):
(JSC::Structure::create): Fixed a nasty refactoring bug that only shows
up after enabling variable-sized inline capacities: we were passing our
type info where our inline capacity was expected. The compiler didn't
notice because both have type int :(.

../WebCore: 

* ForwardingHeaders/runtime/ObjectConstructor.h: Added.

* bindings/js/JSInjectedScriptHostCustom.cpp:
* bindings/js/JSSQLResultSetRowListCustom.cpp: Include ObjectConstructor.h because
that's where createEmptyObject() is located now.

* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneDeserializer::deserialize): Updated for interface change.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@141050 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a5b12aca
......@@ -48,6 +48,7 @@
#include "JSRetainPtr.h"
#include "JSString.h"
#include "JSValueRef.h"
#include "ObjectConstructor.h"
#include "ObjectPrototype.h"
#include "Operations.h"
#include "PropertyNameArray.h"
......
This diff is collapsed.
......@@ -233,7 +233,6 @@ __ZN3JSC16NativeExecutable6createERNS_12JSGlobalDataENS_21MacroAssemblerCodePtrE
__ZN3JSC8JSObject34putDirectFunctionWithoutTransitionEPNS_9ExecStateEPNS_10JSFunctionEj
__ZN3JSC10JSFunction4nameEPNS_9ExecStateE
__ZN3JSC15ObjectPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
__ZN3JSC8JSObject17createInheritorIDERNS_12JSGlobalDataE
__ZN3JSC14ArrayPrototypeC1EPNS_14JSGlobalObjectEPNS_9StructureE
__ZN3JSC7JSArrayC2ERNS_12JSGlobalDataEPNS_9StructureE
__ZN3JSC15StringPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
......
......@@ -27,7 +27,7 @@ EXPORTS
??0SHA1@WTF@@QAE@XZ
??0StringObject@JSC@@IAE@AAVJSGlobalData@1@PAVStructure@1@@Z
??0StringPrintStream@WTF@@QAE@XZ
??0Structure@JSC@@AAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@VJSValue@1@ABVTypeInfo@1@PBUClassInfo@1@EH@Z
??0Structure@JSC@@AAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@VJSValue@1@ABVTypeInfo@1@PBUClassInfo@1@EI@Z
??0ThreadCondition@WTF@@QAE@XZ
??0WTFThreadData@WTF@@QAE@XZ
??0WrapperBase@MemoryInstrumentation@WTF@@QAE@PBDPBX@Z
......@@ -195,6 +195,7 @@ EXPORTS
?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z
?EcmaScriptConverter@DoubleToStringConverter@double_conversion@WTF@@SAABV123@XZ
?empty@StringImpl@WTF@@SAPAV12@XZ
?emptyObjectStructureForPrototype@PrototypeMap@JSC@@QAEPAVStructure@2@PAVJSObject@2@I@Z
?enumerable@PropertyDescriptor@JSC@@QBE_NXZ
?equalUTF16WithUTF8@Unicode@WTF@@YA_NPB_W0PBD1@Z
?evaluate@DebuggerCallFrame@JSC@@QBE?AVJSValue@2@ABVString@WTF@@AAV32@@Z
......
......@@ -459,8 +459,11 @@
14BD5A320A3E91F600BAF59C /* JSValueRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A2B0A3E91F600BAF59C /* JSValueRef.cpp */; };
14BFCE6910CDB1FC00364CCE /* WeakGCMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
14C5242B0F5355E900BA3D04 /* JITStubs.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A6581A0F4E36F4000150FD /* JITStubs.h */; settings = {ATTRIBUTES = (Private, ); }; };
14CA958B16AB50DE00938A06 /* StaticPropertyAnalyzer.h in Headers */ = {isa = PBXBuildFile; fileRef = 14CA958A16AB50DE00938A06 /* StaticPropertyAnalyzer.h */; settings = {ATTRIBUTES = (Private, ); }; };
14CA958D16AB50FA00938A06 /* ObjectAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 14CA958C16AB50FA00938A06 /* ObjectAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
14D2F3DA139F4BE200491031 /* MarkedSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14D2F3D8139F4BE200491031 /* MarkedSpace.cpp */; };
14D2F3DB139F4BE200491031 /* MarkedSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D2F3D9139F4BE200491031 /* MarkedSpace.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DF04DA16B3996D0016A513 /* StaticPropertyAnalysis.h in Headers */ = {isa = PBXBuildFile; fileRef = 14DF04D916B3996D0016A513 /* StaticPropertyAnalysis.h */; settings = {ATTRIBUTES = (Private, ); }; };
14E84F9E14EE1ACC00D6D5D4 /* WeakBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14E84F9914EE1ACC00D6D5D4 /* WeakBlock.cpp */; };
14E84F9F14EE1ACC00D6D5D4 /* WeakBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9A14EE1ACC00D6D5D4 /* WeakBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
14E84FA014EE1ACC00D6D5D4 /* WeakSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14E84F9B14EE1ACC00D6D5D4 /* WeakSet.cpp */; };
......@@ -731,7 +734,7 @@
BC18C4420E16F5CD00B34460 /* NumberConstructor.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */; };
BC18C4430E16F5CD00B34460 /* NumberObject.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8710255597D01FF60F7 /* NumberObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC18C4440E16F5CD00B34460 /* NumberPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C50E16D4E900A06E92 /* NumberPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC18C4450E16F5CD00B34460 /* ObjectConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C70E16D4E900A06E92 /* ObjectConstructor.h */; };
BC18C4450E16F5CD00B34460 /* ObjectConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C70E16D4E900A06E92 /* ObjectConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC18C4480E16F5CD00B34460 /* Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8780255597D01FF60F7 /* Operations.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F0B3AA09BB4DC00068FCE3 /* Parser.h */; settings = {ATTRIBUTES = (); }; };
......@@ -1279,6 +1282,8 @@
14BD5A2B0A3E91F600BAF59C /* JSValueRef.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSValueRef.cpp; sourceTree = "<group>"; };
14BD5A2D0A3E91F600BAF59C /* testapi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testapi.c; path = API/tests/testapi.c; sourceTree = "<group>"; };
14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakGCMap.h; sourceTree = "<group>"; };
14CA958A16AB50DE00938A06 /* StaticPropertyAnalyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticPropertyAnalyzer.h; sourceTree = "<group>"; };
14CA958C16AB50FA00938A06 /* ObjectAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectAllocationProfile.h; sourceTree = "<group>"; };
14D2F3D8139F4BE200491031 /* MarkedSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MarkedSpace.cpp; sourceTree = "<group>"; };
14D2F3D9139F4BE200491031 /* MarkedSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedSpace.h; sourceTree = "<group>"; };
14D792640DAA03FB001A9F05 /* JSStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStack.h; sourceTree = "<group>"; };
......@@ -1288,6 +1293,7 @@
14DA818E0D99FD2000B0A4FB /* JSActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSActivation.h; sourceTree = "<group>"; };
14DA818F0D99FD2000B0A4FB /* JSActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSActivation.cpp; sourceTree = "<group>"; };
14DE0D680D02431400AACCA2 /* JSGlobalObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalObject.cpp; sourceTree = "<group>"; };
14DF04D916B3996D0016A513 /* StaticPropertyAnalysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticPropertyAnalysis.h; sourceTree = "<group>"; };
14E84F9914EE1ACC00D6D5D4 /* WeakBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakBlock.cpp; sourceTree = "<group>"; };
14E84F9A14EE1ACC00D6D5D4 /* WeakBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakBlock.h; sourceTree = "<group>"; };
14E84F9B14EE1ACC00D6D5D4 /* WeakSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakSet.cpp; sourceTree = "<group>"; };
......@@ -2231,6 +2237,8 @@
960097A50EBABB58007A7297 /* LabelScope.h */,
655EB29A10CE2581001A990E /* NodesCodegen.cpp */,
969A07280ED1CE6900F1F681 /* RegisterID.h */,
14DF04D916B3996D0016A513 /* StaticPropertyAnalysis.h */,
14CA958A16AB50DE00938A06 /* StaticPropertyAnalyzer.h */,
);
path = bytecompiler;
sourceTree = "<group>";
......@@ -2767,9 +2775,8 @@
0FB105831675480C00F8AB6E /* ExitKind.h */,
0F0B83AA14BCF5B900885B4F /* ExpressionRangeInfo.h */,
0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */,
0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */,
0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */,
0F0B83A814BCF55E00885B4F /* HandlerInfo.h */,
969A07930ED1D3AE00F1F681 /* Instruction.h */,
BCFD8C900EEB2EE700283848 /* JumpTable.cpp */,
......@@ -2780,15 +2787,16 @@
0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */,
0FB5467C14F5CFD3002C2989 /* MethodOfGettingAValueProfile.cpp */,
0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */,
14CA958C16AB50FA00938A06 /* ObjectAllocationProfile.h */,
969A07940ED1D3AE00F1F681 /* Opcode.cpp */,
969A07950ED1D3AE00F1F681 /* Opcode.h */,
0F2BDC2B151FDE8B00CD8910 /* Operands.h */,
0F9FC8BF14E1B5FB00D52AE0 /* PolymorphicPutByIdList.cpp */,
0F9FC8C014E1B5FB00D52AE0 /* PolymorphicPutByIdList.h */,
0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */,
0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */,
0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */,
0F9FC8C114E1B5FB00D52AE0 /* PutKind.h */,
0FF60ABF16740F8100029779 /* ReduceWhitespace.cpp */,
0FF60AC016740F8100029779 /* ReduceWhitespace.h */,
......@@ -2802,7 +2810,7 @@
0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */,
0FD82E4F141DAEA100179C94 /* SpeculatedType.h */,
0F93329B14CA7DC10085F3C6 /* StructureSet.h */,
0F93329B14CA7DC10085F3C6 /* StructureSet.h */,
0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */,
0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */,
BCCF0D0B0EF0B8A500413C8F /* StructureStubInfo.cpp */,
......@@ -2814,6 +2822,7 @@
0F426A461460CBAB00131F8F /* VirtualRegister.h */,
0F919D2215853CDE004A4E7D /* Watchpoint.cpp */,
0F919D2315853CDE004A4E7D /* Watchpoint.h */,
0F93329B14CA7DC10085F3C6 /* StructureSet.h */,
);
path = bytecode;
sourceTree = "<group>";
......@@ -3283,6 +3292,9 @@
86704B4312DB8A8100A9FE7B /* YarrSyntaxChecker.h in Headers */,
0F9749711687ADE400A4FF6A /* JSCellInlines.h in Headers */,
1474C33B16AA2D950062F01D /* PrototypeMap.h in Headers */,
14CA958B16AB50DE00938A06 /* StaticPropertyAnalyzer.h in Headers */,
14CA958D16AB50FA00938A06 /* ObjectAllocationProfile.h in Headers */,
14DF04DA16B3996D0016A513 /* StaticPropertyAnalysis.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -755,7 +755,8 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
case op_create_this: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
out.printf("[%4d] create_this %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data());
unsigned inferredInlineCapacity = (++it)->u.operand;
out.printf("[%4d] create_this %s, %s, %u", location, registerName(exec, r0).data(), registerName(exec, r1).data(), inferredInlineCapacity);
break;
}
case op_convert_this: {
......@@ -766,7 +767,9 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
}
case op_new_object: {
int r0 = (++it)->u.operand;
out.printf("[%4d] new_object\t %s", location, registerName(exec, r0).data());
unsigned inferredInlineCapacity = (++it)->u.operand;
out.printf("[%4d] new_object\t %s, %u", location, registerName(exec, r0).data(), inferredInlineCapacity);
++it; // Skip object allocation profile.
break;
}
case op_new_array: {
......@@ -1812,6 +1815,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
if (size_t size = unlinkedCodeBlock->numberOfValueProfiles())
m_valueProfiles.grow(size);
#endif
if (size_t size = unlinkedCodeBlock->numberOfObjectAllocationProfiles())
m_objectAllocationProfiles.grow(size);
if (size_t size = unlinkedCodeBlock->numberOfResolveOperations())
m_resolveOperations.grow(size);
size_t putToBaseCount = unlinkedCodeBlock->numberOfPutToBaseOperations();
......@@ -1873,6 +1878,17 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
}
#endif
case op_new_object: {
int objectAllocationProfileIndex = pc[i + opLength - 1].u.operand;
ObjectAllocationProfile* objectAllocationProfile = &m_objectAllocationProfiles[objectAllocationProfileIndex];
int inferredInlineCapacity = pc[i + opLength - 2].u.operand;
instructions[i + opLength - 1] = objectAllocationProfile;
objectAllocationProfile->initialize(*globalData(),
m_ownerExecutable.get(), m_globalObject->objectPrototype(), inferredInlineCapacity);
break;
}
case op_call:
case op_call_eval: {
#if ENABLE(DFG_JIT)
......@@ -2390,6 +2406,8 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor)
visitor.append(&m_functionExprs[i]);
for (size_t i = 0; i < m_functionDecls.size(); ++i)
visitor.append(&m_functionDecls[i]);
for (unsigned i = 0; i < m_objectAllocationProfiles.size(); ++i)
m_objectAllocationProfiles[i].visitAggregate(visitor);
updateAllPredictions(Collection);
}
......
......@@ -51,6 +51,7 @@
#include "ExecutionCounter.h"
#include "ExpressionRangeInfo.h"
#include "HandlerInfo.h"
#include "ObjectAllocationProfile.h"
#include "Options.h"
#include "Instruction.h"
#include "JITCode.h"
......@@ -787,13 +788,6 @@ namespace JSC {
}
ArrayProfile* getArrayProfile(unsigned bytecodeOffset);
ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset);
unsigned numberOfArrayAllocationProfiles() const { return m_arrayAllocationProfiles.size(); }
ArrayAllocationProfile* addArrayAllocationProfile()
{
m_arrayAllocationProfiles.append(ArrayAllocationProfile());
return &m_arrayAllocationProfiles.last();
}
#endif
// Exception handling support
......@@ -1314,6 +1308,7 @@ namespace JSC {
SegmentedVector<ArrayAllocationProfile, 8> m_arrayAllocationProfiles;
ArrayProfileVector m_arrayProfiles;
#endif
SegmentedVector<ObjectAllocationProfile, 8> m_objectAllocationProfiles;
// Constant Pool
Vector<Identifier> m_identifiers;
......
......@@ -50,6 +50,7 @@ namespace JSC {
class ArrayAllocationProfile;
class ArrayProfile;
class JSCell;
class ObjectAllocationProfile;
class Structure;
class StructureChain;
struct LLIntCallLinkInfo;
......@@ -195,6 +196,7 @@ namespace JSC {
Instruction(ValueProfile* profile) { u.profile = profile; }
Instruction(ArrayProfile* profile) { u.arrayProfile = profile; }
Instruction(ArrayAllocationProfile* profile) { u.arrayAllocationProfile = profile; }
Instruction(ObjectAllocationProfile* profile) { u.objectAllocationProfile = profile; }
Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; }
......@@ -215,6 +217,7 @@ namespace JSC {
ValueProfile* profile;
ArrayProfile* arrayProfile;
ArrayAllocationProfile* arrayAllocationProfile;
ObjectAllocationProfile* objectAllocationProfile;
void* pointer;
bool* predicatePointer;
} u;
......
/*
* Copyright (C) 2013 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 ObjectAllocationProfile_h
#define ObjectAllocationProfile_h
#include "JSGlobalData.h"
#include "JSGlobalObject.h"
#include "ObjectPrototype.h"
#include "SlotVisitor.h"
#include "WriteBarrier.h"
namespace JSC {
class ObjectAllocationProfile {
friend class LLIntOffsetsExtractor;
public:
static ptrdiff_t offsetOfAllocator() { return OBJECT_OFFSETOF(ObjectAllocationProfile, m_allocator); }
static ptrdiff_t offsetOfStructure() { return OBJECT_OFFSETOF(ObjectAllocationProfile, m_structure); }
ObjectAllocationProfile()
: m_allocator(0)
{
}
bool isNull() { return !m_allocator; }
void initialize(JSGlobalData& globalData, JSCell* owner, JSObject* prototype, unsigned inferredInlineCapacity)
{
ASSERT(!m_allocator);
ASSERT(!m_structure);
unsigned inlineCapacity = 0;
if (inferredInlineCapacity < JSFinalObject::defaultInlineCapacity()) {
// Try to shrink the object based on static analysis.
inferredInlineCapacity += possibleDefaultPropertyCount(globalData, prototype);
if (!inferredInlineCapacity) {
// Empty objects are rare, so most likely the static analyzer just didn't
// see the real initializer function. This can happen with helper functions.
inferredInlineCapacity = JSFinalObject::defaultInlineCapacity();
} else if (inferredInlineCapacity > JSFinalObject::defaultInlineCapacity()) {
// Default properties are weak guesses, so don't allow them to turn a small
// object into a large object.
inferredInlineCapacity = JSFinalObject::defaultInlineCapacity();
}
inlineCapacity = inferredInlineCapacity;
ASSERT(inlineCapacity < JSFinalObject::maxInlineCapacity());
} else {
// Normal or large object.
inlineCapacity = inferredInlineCapacity;
if (inlineCapacity > JSFinalObject::maxInlineCapacity())
inlineCapacity = JSFinalObject::maxInlineCapacity();
}
ASSERT(inlineCapacity > 0);
ASSERT(inlineCapacity <= JSFinalObject::maxInlineCapacity());
size_t allocationSize = JSFinalObject::allocationSize(inlineCapacity);
MarkedAllocator* allocator = &globalData.heap.allocatorForObjectWithoutDestructor(allocationSize);
ASSERT(allocator->cellSize());
// Take advantage of extra inline capacity available in the size class.
size_t slop = (allocator->cellSize() - allocationSize) / sizeof(WriteBarrier<Unknown>);
inlineCapacity += slop;
if (inlineCapacity > JSFinalObject::maxInlineCapacity())
inlineCapacity = JSFinalObject::maxInlineCapacity();
m_allocator = allocator;
m_structure.set(globalData, owner,
globalData.prototypeMap.emptyObjectStructureForPrototype(prototype, inlineCapacity));
}
Structure* structure() { return m_structure.get(); }
unsigned inlineCapacity() { return m_structure->inlineCapacity(); }
void clear()
{
m_allocator = 0;
m_structure.clear();
ASSERT(isNull());
}
void visitAggregate(SlotVisitor& visitor)
{
visitor.append(&m_structure);
}
private:
unsigned possibleDefaultPropertyCount(JSGlobalData& globalData, JSObject* prototype)
{
if (prototype == prototype->globalObject()->objectPrototype())
return 0;
size_t count = 0;
PropertyNameArray propertyNameArray(&globalData);
prototype->structure()->getPropertyNamesFromStructure(globalData, propertyNameArray, ExcludeDontEnumProperties);
PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArray.data()->propertyNameVector();
for (size_t i = 0; i < propertyNameVector.size(); ++i) {
JSValue value = prototype->getDirect(globalData, propertyNameVector[i]);
// Functions are common, and are usually class-level objects that are not overridden.
if (jsDynamicCast<JSFunction*>(value))
continue;
++count;
}
return count;
}
MarkedAllocator* m_allocator; // Precomputed to make things easier for generated code.
WriteBarrier<Structure> m_structure;
};
} // namespace JSC
#endif // ObjectAllocationProfile_h
......@@ -44,11 +44,11 @@ namespace JSC {
macro(op_create_activation, 2) \
macro(op_init_lazy_reg, 2) \
macro(op_create_arguments, 2) \
macro(op_create_this, 3) \
macro(op_create_this, 4) \
macro(op_get_callee, 3) \
macro(op_convert_this, 3) \
\
macro(op_new_object, 2) \
macro(op_new_object, 4) \
macro(op_new_array, 5) \
macro(op_new_array_with_size, 4) \
macro(op_new_array_buffer, 5) \
......
......@@ -176,6 +176,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(JSGlobalData* globalData, Structure* struct
, m_putToBaseOperationCount(1)
, m_arrayProfileCount(0)
, m_arrayAllocationProfileCount(0)
, m_objectAllocationProfileCount(0)
, m_valueProfileCount(0)
, m_llintCallLinkInfoCount(0)
#if ENABLE(BYTECODE_COMMENTS)
......
......@@ -58,6 +58,7 @@ class UnlinkedFunctionCodeBlock;
typedef unsigned UnlinkedValueProfile;
typedef unsigned UnlinkedArrayProfile;
typedef unsigned UnlinkedArrayAllocationProfile;
typedef unsigned UnlinkedObjectAllocationProfile;
typedef unsigned UnlinkedLLIntCallLinkInfo;
struct ExecutableInfo {
......@@ -398,6 +399,8 @@ public:
unsigned numberOfArrayProfiles() { return m_arrayProfileCount; }
UnlinkedArrayAllocationProfile addArrayAllocationProfile() { return m_arrayAllocationProfileCount++; }
unsigned numberOfArrayAllocationProfiles() { return m_arrayAllocationProfileCount; }
UnlinkedObjectAllocationProfile addObjectAllocationProfile() { return m_objectAllocationProfileCount++; }
unsigned numberOfObjectAllocationProfiles() { return m_objectAllocationProfileCount; }
UnlinkedValueProfile addValueProfile() { return m_valueProfileCount++; }
unsigned numberOfValueProfiles() { return m_valueProfileCount; }
......@@ -525,6 +528,7 @@ private:
unsigned m_putToBaseOperationCount;
unsigned m_arrayProfileCount;
unsigned m_arrayAllocationProfileCount;
unsigned m_objectAllocationProfileCount;
unsigned m_valueProfileCount;
unsigned m_llintCallLinkInfoCount;
......
......@@ -41,6 +41,7 @@
#include "SymbolTable.h"
#include "Debugger.h"
#include "Nodes.h"
#include "StaticPropertyAnalyzer.h"
#include "UnlinkedCodeBlock.h"
#include <wtf/PassRefPtr.h>
#include <wtf/SegmentedVector.h>
......@@ -383,6 +384,7 @@ namespace JSC {
RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2);
RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src);
RegisterID* emitCreateThis(RegisterID* dst);
RegisterID* emitNewObject(RegisterID* dst);
RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision
......@@ -521,8 +523,16 @@ namespace JSC {
void emitOpcode(OpcodeID);
UnlinkedArrayAllocationProfile newArrayAllocationProfile();
UnlinkedObjectAllocationProfile newObjectAllocationProfile();
UnlinkedArrayProfile newArrayProfile();
UnlinkedValueProfile emitProfiledOpcode(OpcodeID);
int kill(RegisterID* dst)
{
int index = dst->index();
m_staticPropertyAnalyzer.kill(index);
return index;
}
void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
void retrieveLastUnaryOp(int& dstIndex, int& srcIndex);
ALWAYS_INLINE void rewindBinaryOp();
......@@ -775,6 +785,8 @@ namespace JSC {
IdentifierResolvePutMap m_resolveBaseForPutMap;
IdentifierResolvePutMap m_resolveWithBaseForPutMap;
StaticPropertyAnalyzer m_staticPropertyAnalyzer;
JSGlobalData* m_globalData;
OpcodeID m_lastOpcodeID;
......
/*
* Copyright (C) 2013 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 StaticPropertyAnalysis_h
#define StaticPropertyAnalysis_h
#include "Executable.h"
#include "JSGlobalObject.h"
#include <wtf/HashSet.h>
namespace JSC {
// Reference count indicates number of live registers that alias this object.
class StaticPropertyAnalysis : public RefCounted<StaticPropertyAnalysis> {
public:
static PassRefPtr<StaticPropertyAnalysis> create(Vector<UnlinkedInstruction>* instructions, unsigned target)
{
return adoptRef(new StaticPropertyAnalysis(instructions, target));
}
void addPropertyIndex(unsigned propertyIndex) { m_propertyIndexes.add(propertyIndex); }
void record()
{
(*m_instructions)[m_target] = m_propertyIndexes.size();
}
int propertyIndexCount() { return m_propertyIndexes.size(); }
private:
StaticPropertyAnalysis(Vector<UnlinkedInstruction>* instructions, unsigned target)
: m_instructions(instructions)
, m_target(target)
{
}
Vector<UnlinkedInstruction>* m_instructions;
unsigned m_target;
typedef HashSet<unsigned, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > PropertyIndexSet;
PropertyIndexSet m_propertyIndexes;
};
} // namespace JSC
#endif // StaticPropertyAnalysis_h
/*
* Copyright (C) 2013 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