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
diff --git a/Source/JavaScriptCore/API/JSObjectRef.cpp b/Source/JavaScriptCore/API/JSObjectRef.cpp
index d27f867..1fdddad 100644
--- a/Source/JavaScriptCore/API/JSObjectRef.cpp
+++ b/Source/JavaScriptCore/API/JSObjectRef.cpp
@@ -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"
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 7f147e7..6973c6f 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,312 @@
+2013-01-28 Geoffrey Garen <ggaren@apple.com>
+
+ Static size inference for JavaScript objects
+ https://bugs.webkit.org/show_bug.cgi?id=108093
+
+ Reviewed by Phil Pizlo.
+
+ * 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 :(.
+
2013-01-28 Oliver Hunt <oliver@apple.com>
Add more assertions to the property storage use in arrays
diff --git a/Source/JavaScriptCore/JavaScriptCore.order b/Source/JavaScriptCore/JavaScriptCore.order
index 6a19466..e6f5fff 100644
--- a/Source/JavaScriptCore/JavaScriptCore.order
+++ b/Source/JavaScriptCore/JavaScriptCore.order
@@ -233,7 +233,6 @@
__ZN3JSC8JSObject34putDirectFunctionWithoutTransitionEPNS_9ExecStateEPNS_10JSFunctionEj
__ZN3JSC10JSFunction4nameEPNS_9ExecStateE
__ZN3JSC15ObjectPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
-__ZN3JSC8JSObject17createInheritorIDERNS_12JSGlobalDataE
__ZN3JSC14ArrayPrototypeC1EPNS_14JSGlobalObjectEPNS_9StructureE
__ZN3JSC7JSArrayC2ERNS_12JSGlobalDataEPNS_9StructureE
__ZN3JSC15StringPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreExports.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreExports.def
index f58acd2..1b4a363 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreExports.def
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreExports.def
@@ -27,7 +27,7 @@
??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 @@
?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
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 3baffdc..bb5379d 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -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 */,
+ 0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */,
- 0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
- 0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
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 */,
+ 0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
+ 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */,
- 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
- 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
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;
};
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index dda578d..084594a 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -755,7 +755,8 @@
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 @@
}
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 @@
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 @@
}
#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 @@
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);
}
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index ad4f338..bee492e 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -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 @@
}
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 @@
SegmentedVector<ArrayAllocationProfile, 8> m_arrayAllocationProfiles;
ArrayProfileVector m_arrayProfiles;
#endif
+ SegmentedVector<ObjectAllocationProfile, 8> m_objectAllocationProfiles;
// Constant Pool
Vector<Identifier> m_identifiers;
diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h
index 50b80e0..d108f14 100644
--- a/Source/JavaScriptCore/bytecode/Instruction.h
+++ b/Source/JavaScriptCore/bytecode/Instruction.h
@@ -50,6 +50,7 @@
class ArrayAllocationProfile;
class ArrayProfile;
class JSCell;
+ class ObjectAllocationProfile;
class Structure;
class StructureChain;
struct LLIntCallLinkInfo;
@@ -195,6 +196,7 @@
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 @@
ValueProfile* profile;
ArrayProfile* arrayProfile;
ArrayAllocationProfile* arrayAllocationProfile;
+ ObjectAllocationProfile* objectAllocationProfile;
void* pointer;
bool* predicatePointer;
} u;
diff --git a/Source/JavaScriptCore/bytecode/ObjectAllocationProfile.h b/Source/JavaScriptCore/bytecode/ObjectAllocationProfile.h
new file mode 100644
index 0000000..c42e7cd
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/ObjectAllocationProfile.h
@@ -0,0 +1,142 @@
+/*
+ * 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
diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h
index 548f95c..ab96c0c 100644
--- a/Source/JavaScriptCore/bytecode/Opcode.h
+++ b/Source/JavaScriptCore/bytecode/Opcode.h
@@ -44,11 +44,11 @@
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) \
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
index 1fea8d1..8462b9a 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
@@ -176,6 +176,7 @@
, m_putToBaseOperationCount(1)
, m_arrayProfileCount(0)
, m_arrayAllocationProfileCount(0)
+ , m_objectAllocationProfileCount(0)
, m_valueProfileCount(0)
, m_llintCallLinkInfoCount(0)
#if ENABLE(BYTECODE_COMMENTS)
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
index 67e686e..3ca27ae 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
@@ -58,6 +58,7 @@
typedef unsigned UnlinkedValueProfile;
typedef unsigned UnlinkedArrayProfile;
typedef unsigned UnlinkedArrayAllocationProfile;
+typedef unsigned UnlinkedObjectAllocationProfile;
typedef unsigned UnlinkedLLIntCallLinkInfo;
struct ExecutableInfo {
@@ -398,6 +399,8 @@
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 @@
unsigned m_putToBaseOperationCount;
unsigned m_arrayProfileCount;
unsigned m_arrayAllocationProfileCount;
+ unsigned m_objectAllocationProfileCount;
unsigned m_valueProfileCount;
unsigned m_llintCallLinkInfoCount;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index f57e1bc..86d8e69 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -155,7 +155,9 @@
m_codeBlock->setThisRegister(m_thisRegister.index());
m_scopeNode->emitBytecode(*this);
-
+
+ m_staticPropertyAnalyzer.kill();
+
for (unsigned i = 0; i < m_tryRanges.size(); ++i) {
TryRange& range = m_tryRanges[i];
int start = range.start->bind();
@@ -244,6 +246,7 @@
, m_hasCreatedActivation(true)
, m_firstLazyFunction(0)
, m_lastLazyFunction(0)
+ , m_staticPropertyAnalyzer(&m_instructions)
, m_globalData(&globalData)
, m_lastOpcodeID(op_end)
#ifndef NDEBUG
@@ -294,6 +297,7 @@
, m_hasCreatedActivation(false)
, m_firstLazyFunction(0)
, m_lastLazyFunction(0)
+ , m_staticPropertyAnalyzer(&m_instructions)
, m_globalData(&globalData)
, m_lastOpcodeID(op_end)
#ifndef NDEBUG
@@ -475,19 +479,10 @@
if (isConstructor()) {
prependComment("'this' because we are a Constructor function");
-
- RefPtr<RegisterID> func = newTemporary();
-
- UnlinkedValueProfile profile = emitProfiledOpcode(op_get_callee);
- instructions().append(func->index());
- instructions().append(profile);
-
- emitOpcode(op_create_this);
- instructions().append(m_thisRegister.index());
- instructions().append(func->index());
+ emitCreateThis(&m_thisRegister);
} else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) {
UnlinkedValueProfile profile = emitProfiledOpcode(op_convert_this);
- instructions().append(m_thisRegister.index());
+ instructions().append(kill(&m_thisRegister));
instructions().append(profile);
}
}
@@ -511,6 +506,7 @@
, m_hasCreatedActivation(true)
, m_firstLazyFunction(0)
, m_lastLazyFunction(0)
+ , m_staticPropertyAnalyzer(&m_instructions)
, m_globalData(&globalData)
, m_lastOpcodeID(op_end)
#ifndef NDEBUG
@@ -751,6 +747,11 @@
#endif
}
+UnlinkedObjectAllocationProfile BytecodeGenerator::newObjectAllocationProfile()
+{
+ return m_codeBlock->addObjectAllocationProfile();
+}
+
UnlinkedValueProfile BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID)
{
#if ENABLE(VALUE_PROFILER)
@@ -1111,6 +1112,8 @@
RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
{
+ m_staticPropertyAnalyzer.mov(dst->index(), src->index());
+
emitOpcode(op_mov);
instructions().append(dst->index());
instructions().append(src->index());
@@ -1333,7 +1336,7 @@
return emitGetLocalVar(dst, resolveResult, property);
UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve);
- instructions().append(dst->index());
+ instructions().append(kill(dst));
instructions().append(addConstant(property));
instructions().append(getResolveOperations(property));
instructions().append(profile);
@@ -1345,7 +1348,7 @@
ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
// We can't optimise at all :-(
UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_base);
- instructions().append(dst->index());
+ instructions().append(kill(dst));
instructions().append(addConstant(property));
instructions().append(false);
instructions().append(getResolveBaseOperations(property));
@@ -1359,7 +1362,7 @@
ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
// We can't optimise at all :-(
UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_base);
- instructions().append(dst->index());
+ instructions().append(kill(dst));
instructions().append(addConstant(property));
instructions().append(m_codeBlock->isStrictMode());
uint32_t putToBaseIndex = 0;
@@ -1374,7 +1377,7 @@
{
ASSERT_UNUSED(resolveResult, !resolveResult.isRegister());
UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_with_base);
- instructions().append(baseDst->index());
+ instructions().append(kill(baseDst));
instructions().append(propDst->index());
instructions().append(addConstant(property));
uint32_t putToBaseIndex = 0;
@@ -1394,7 +1397,7 @@
}
UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_with_this);
- instructions().append(baseDst->index());
+ instructions().append(kill(baseDst));
instructions().append(propDst->index());
instructions().append(addConstant(property));
instructions().append(getResolveWithThisOperations(property));
@@ -1433,7 +1436,7 @@
m_codeBlock->addPropertyAccessInstruction(instructions().size());
UnlinkedValueProfile profile = emitProfiledOpcode(op_get_by_id);
- instructions().append(dst->index());
+ instructions().append(kill(dst));
instructions().append(base->index());
instructions().append(addConstant(property));
instructions().append(0);
@@ -1456,11 +1459,15 @@
RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
{
+ unsigned propertyIndex = addConstant(property);
+
+ m_staticPropertyAnalyzer.putById(base->index(), propertyIndex);
+
m_codeBlock->addPropertyAccessInstruction(instructions().size());
emitOpcode(op_put_by_id);
instructions().append(base->index());
- instructions().append(addConstant(property));
+ instructions().append(propertyIndex);
instructions().append(value->index());
instructions().append(0);
instructions().append(0);
@@ -1482,11 +1489,15 @@
RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value)
{
+ unsigned propertyIndex = addConstant(property);
+
+ m_staticPropertyAnalyzer.putById(base->index(), propertyIndex);
+
m_codeBlock->addPropertyAccessInstruction(instructions().size());
emitOpcode(op_put_by_id);
instructions().append(base->index());
- instructions().append(addConstant(property));
+ instructions().append(propertyIndex);
instructions().append(value->index());
instructions().append(0);
instructions().append(0);
@@ -1500,9 +1511,13 @@
void BytecodeGenerator::emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter)
{
+ unsigned propertyIndex = addConstant(property);
+
+ m_staticPropertyAnalyzer.putById(base->index(), propertyIndex);
+
emitOpcode(op_put_getter_setter);
instructions().append(base->index());
- instructions().append(addConstant(property));
+ instructions().append(propertyIndex);
instructions().append(getter->index());
instructions().append(setter->index());
}
@@ -1520,7 +1535,7 @@
{
UnlinkedArrayProfile arrayProfile = newArrayProfile();
UnlinkedValueProfile profile = emitProfiledOpcode(op_get_argument_by_val);
- instructions().append(dst->index());
+ instructions().append(kill(dst));
ASSERT(base->index() == m_codeBlock->argumentsRegister());
instructions().append(base->index());
instructions().append(property->index());
@@ -1546,7 +1561,7 @@
}
UnlinkedArrayProfile arrayProfile = newArrayProfile();
UnlinkedValueProfile profile = emitProfiledOpcode(op_get_by_val);
- instructions().append(dst->index());
+ instructions().append(kill(dst));
instructions().append(base->index());
instructions().append(property->index());
instructions().append(arrayProfile);
@@ -1583,10 +1598,33 @@
return value;
}
+RegisterID* BytecodeGenerator::emitCreateThis(RegisterID* dst)
+{
+ RefPtr<RegisterID> func = newTemporary();
+
+ UnlinkedValueProfile profile = emitProfiledOpcode(op_get_callee);
+ instructions().append(func->index());
+ instructions().append(profile);
+
+ size_t begin = instructions().size();
+ m_staticPropertyAnalyzer.createThis(m_thisRegister.index(), begin + 3);
+
+ emitOpcode(op_create_this);
+ instructions().append(m_thisRegister.index());
+ instructions().append(func->index());
+ instructions().append(0);
+ return dst;
+}
+
RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst)
{
+ size_t begin = instructions().size();
+ m_staticPropertyAnalyzer.newObject(dst->index(), begin + 2);
+
emitOpcode(op_new_object);
instructions().append(dst->index());
+ instructions().append(0);
+ instructions().append(newObjectAllocationProfile());
return dst;
}
@@ -1767,10 +1805,8 @@
instructions().append(Special::ObjectConstructor);
instructions().append(realCall->bind(begin, instructions().size()));
- if (dst != ignoredResult()) {
- emitOpcode(op_new_object);
- instructions().append(dst->index());
- }
+ if (dst != ignoredResult())
+ emitNewObject(dst);
break;
}
@@ -1862,7 +1898,7 @@
instructions().append(arrayProfile);
if (dst != ignoredResult()) {
UnlinkedValueProfile profile = emitProfiledOpcode(op_call_put_result);
- instructions().append(dst->index()); // dst
+ instructions().append(kill(dst));
instructions().append(profile);
}
@@ -1895,7 +1931,7 @@
instructions().append(firstFreeRegister->index());
if (dst != ignoredResult()) {
UnlinkedValueProfile profile = emitProfiledOpcode(op_call_put_result);
- instructions().append(dst->index());
+ instructions().append(kill(dst));
instructions().append(profile);
}
if (m_shouldEmitProfileHooks) {
@@ -1978,7 +2014,7 @@
instructions().append(0);
if (dst != ignoredResult()) {
UnlinkedValueProfile profile = emitProfiledOpcode(op_call_put_result);
- instructions().append(dst->index()); // dst
+ instructions().append(kill(dst));
instructions().append(profile);
}
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index a5bb95b..74a26cc 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -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 @@
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 @@
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 @@
IdentifierResolvePutMap m_resolveBaseForPutMap;
IdentifierResolvePutMap m_resolveWithBaseForPutMap;
+ StaticPropertyAnalyzer m_staticPropertyAnalyzer;
+
JSGlobalData* m_globalData;
OpcodeID m_lastOpcodeID;
diff --git a/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalysis.h b/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalysis.h
new file mode 100644
index 0000000..607c0ff
--- /dev/null
+++ b/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalysis.h
@@ -0,0 +1,67 @@
+/*
+ * 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
diff --git a/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalyzer.h b/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalyzer.h
new file mode 100644
index 0000000..5afe035
--- /dev/null
+++ b/Source/JavaScriptCore/bytecompiler/StaticPropertyAnalyzer.h
@@ -0,0 +1,170 @@
+/*
+ * 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 StaticPropertyAnalyzer_h
+#define StaticPropertyAnalyzer_h
+
+#include "StaticPropertyAnalysis.h"
+#include <wtf/HashMap.h>
+
+namespace JSC {
+
+// Used for flow-insensitive static analysis of the number of properties assigned to an object.
+// We use this analysis with other runtime data to produce an optimization guess. This analysis
+// is understood to be lossy, and it's OK if it turns out to be wrong sometimes.
+class StaticPropertyAnalyzer {
+public:
+ StaticPropertyAnalyzer(Vector<UnlinkedInstruction>*);
+
+ void createThis(int dst, unsigned offsetOfInlineCapacityOperand);
+ void newObject(int dst, unsigned offsetOfInlineCapacityOperand);
+ void putById(int dst, unsigned propertyIndex); // propertyIndex is an index into a uniqued set of strings.
+ void mov(int dst, int src);
+
+ void kill();
+ void kill(int dst);
+
+private:
+ void kill(StaticPropertyAnalysis*);
+
+ Vector<UnlinkedInstruction>* m_instructions;
+ typedef HashMap<int, RefPtr<StaticPropertyAnalysis>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int> > AnalysisMap;
+ AnalysisMap m_analyses;
+};
+
+inline StaticPropertyAnalyzer::StaticPropertyAnalyzer(Vector<UnlinkedInstruction>* instructions)
+ : m_instructions(instructions)
+{
+}
+
+inline void StaticPropertyAnalyzer::createThis(int dst, unsigned offsetOfInlineCapacityOperand)
+{
+ AnalysisMap::AddResult addResult = m_analyses.add(
+ dst, StaticPropertyAnalysis::create(m_instructions, offsetOfInlineCapacityOperand));
+ ASSERT_UNUSED(addResult, addResult.isNewEntry); // Can't have two 'this' in the same constructor.
+}
+
+inline void StaticPropertyAnalyzer::newObject(int dst, unsigned offsetOfInlineCapacityOperand)
+{
+ RefPtr<StaticPropertyAnalysis> analysis = StaticPropertyAnalysis::create(m_instructions, offsetOfInlineCapacityOperand);
+ AnalysisMap::AddResult addResult = m_analyses.add(dst, analysis);
+ if (!addResult.isNewEntry) {
+ kill(addResult.iterator->value.get());
+ addResult.iterator->value = analysis.release();
+ }
+}
+
+inline void StaticPropertyAnalyzer::putById(int dst, unsigned propertyIndex)
+{
+ StaticPropertyAnalysis* analysis = m_analyses.get(dst).get();
+ if (!analysis)
+ return;
+ analysis->addPropertyIndex(propertyIndex);
+}
+
+inline void StaticPropertyAnalyzer::mov(int dst, int src)
+{
+ RefPtr<StaticPropertyAnalysis> analysis = m_analyses.get(src);
+ if (!analysis) {
+ kill(dst);
+ return;
+ }
+
+ AnalysisMap::AddResult addResult = m_analyses.add(dst, analysis);
+ if (!addResult.isNewEntry) {
+ kill(addResult.iterator->value.get());
+ addResult.iterator->value = analysis.release();
+ }
+}
+
+inline void StaticPropertyAnalyzer::kill(StaticPropertyAnalysis* analysis)
+{
+ if (!analysis)
+ return;
+ if (!analysis->hasOneRef()) // Aliases for this object still exist, so it might acquire more properties.
+ return;
+ analysis->record();
+}
+
+inline void StaticPropertyAnalyzer::kill(int dst)
+{
+ // We observe kills in order to avoid piling on properties to an object after
+ // its bytecode register has been recycled.
+
+ // Consider these cases:
+
+ // (1) Aliased temporary
+ // var o1 = { name: name };
+ // var o2 = { name: name };
+
+ // (2) Aliased local -- no control flow
+ // var local;
+ // local = new Object;
+ // local.name = name;
+ // ...
+
+ // local = lookup();
+ // local.didLookup = true;
+ // ...
+
+ // (3) Aliased local -- control flow
+ // var local;
+ // if (condition)
+ // local = { };
+ // else {
+ // local = new Object;
+ // }
+ // local.name = name;
+
+ // (Note: our default codegen for "new Object" looks like case (3).)
+
+ // Case (1) is easy because temporaries almost never survive across control flow.
+
+ // Cases (2) and (3) are hard. Case (2) should kill "local", while case (3) should
+ // not. There is no great way to solve these cases with simple static analysis.
+
+ // Since this is a simple static analysis, we just try to catch the simplest cases,
+ // so we accept kills to any registers except for registers that have no inferred
+ // properties yet.
+
+ AnalysisMap::iterator it = m_analyses.find(dst);
+ if (it == m_analyses.end())
+ return;
+ if (!it->value->propertyIndexCount())
+ return;
+
+ kill(it->value.get());
+ m_analyses.remove(it);
+}
+
+inline void StaticPropertyAnalyzer::kill()
+{
+ while (m_analyses.size())
+ kill(m_analyses.take(m_analyses.begin()->key).get());
+}
+
+} // namespace JSC
+
+#endif // StaticPropertyAnalyzer_h
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 4083376..110e6d1 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -1344,7 +1344,7 @@
break;
}
- case InheritorIDWatchpoint:
+ case AllocationProfileWatchpoint:
node.setCanExit(true);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index d0c49aa..9fed8fb 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -2135,20 +2135,24 @@
ASSERT(cell->inherits(&JSFunction::s_info));
JSFunction* function = jsCast<JSFunction*>(cell);
- Structure* inheritorID = function->tryGetKnownInheritorID();
- if (inheritorID) {
- addToGraph(InheritorIDWatchpoint, OpInfo(function));
- set(currentInstruction[1].u.operand, addToGraph(NewObject, OpInfo(inheritorID)));
+ ObjectAllocationProfile* allocationProfile = function->tryGetAllocationProfile();
+ if (allocationProfile) {
+ addToGraph(AllocationProfileWatchpoint, OpInfo(function));
+ set(currentInstruction[1].u.operand,
+ addToGraph(NewObject, OpInfo(allocationProfile->structure())));
alreadyEmitted = true;
}
}
if (!alreadyEmitted)
- set(currentInstruction[1].u.operand, addToGraph(CreateThis, callee));
+ set(currentInstruction[1].u.operand,
+ addToGraph(CreateThis, OpInfo(currentInstruction[3].u.operand), callee));
NEXT_OPCODE(op_create_this);
}
-
+
case op_new_object: {
- set(currentInstruction[1].u.operand, addToGraph(NewObject, OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->emptyObjectStructure())));
+ set(currentInstruction[1].u.operand,
+ addToGraph(NewObject,
+ OpInfo(currentInstruction[3].u.objectAllocationProfile->structure())));
NEXT_OPCODE(op_new_object);
}
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 2aa7216..4e31696 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -486,6 +486,17 @@
return m_opInfo;
}
+ bool hasInlineCapacity()
+ {
+ return op() == CreateThis;
+ }
+
+ unsigned inlineCapacity()
+ {
+ ASSERT(hasInlineCapacity());
+ return m_opInfo;
+ }
+
void setIndexingType(IndexingType indexingType)
{
ASSERT(hasIndexingType());
@@ -700,7 +711,7 @@
{
switch (op()) {
case CheckFunction:
- case InheritorIDWatchpoint:
+ case AllocationProfileWatchpoint:
return true;
default:
return false;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index c320a57..344f6b5 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -165,7 +165,7 @@
macro(GlobalVarWatchpoint, NodeMustGenerate) \
macro(PutGlobalVarCheck, NodeMustGenerate) \
macro(CheckFunction, NodeMustGenerate) \
- macro(InheritorIDWatchpoint, NodeMustGenerate) \
+ macro(AllocationProfileWatchpoint, NodeMustGenerate) \
\
/* Optimizations for array mutation. */\
macro(ArrayPush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 4c5427e..1c06c0b 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -42,6 +42,7 @@
#include "JSGlobalData.h"
#include "JSNameScope.h"
#include "NameInstance.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
#include <wtf/InlineASM.h>
@@ -347,7 +348,7 @@
return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec));
}
-JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* constructor)
+JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor, int32_t inlineCapacity)
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
@@ -357,7 +358,7 @@
ASSERT(jsCast<JSFunction*>(constructor)->methodTable()->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS);
#endif
- return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->cachedInheritorID(exec));
+ return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->allocationProfile(exec, inlineCapacity)->structure());
}
JSCell* DFG_OPERATION operationNewObject(ExecState* exec, Structure* structure)
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index cc8de6d..5c9e829 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -85,6 +85,7 @@
typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_EIcf)(ExecState*, InlineCallFrame*);
+typedef JSCell* DFG_OPERATION (*C_DFGOperation_EOZ)(ExecState*, JSObject*, int32_t);
typedef JSCell* DFG_OPERATION (*C_DFGOperation_ESt)(ExecState*, Structure*);
typedef double DFG_OPERATION (*D_DFGOperation_DD)(double, double);
typedef double DFG_OPERATION (*D_DFGOperation_ZZ)(int32_t, int32_t);
@@ -122,7 +123,7 @@
// These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
JSCell* DFG_OPERATION operationNewObject(ExecState*, Structure*) WTF_INTERNAL;
-JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* constructor) WTF_INTERNAL;
+JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSObject* constructor, int32_t inlineCapacity) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationConvertThis(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index ae0992e..c879bbf 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -806,7 +806,7 @@
case CheckArgumentsNotCreated:
case GlobalVarWatchpoint:
case GarbageValue:
- case InheritorIDWatchpoint:
+ case AllocationProfileWatchpoint:
case Phantom:
changed |= mergeDefaultFlags(node);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
index e40c35b..dd77a2a 100644
--- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp
+++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
@@ -323,7 +323,7 @@
// Optimize self access.
if (slot.slotBase() == baseValue) {
if ((slot.cachedPropertyType() != PropertySlot::Value)
- || !MacroAssembler::isCompactPtrAlignedAddressOffset(offsetRelativeToPatchedStorage(slot.cachedOffset()))) {
+ || !MacroAssembler::isCompactPtrAlignedAddressOffset(maxOffsetRelativeToPatchedStorage(slot.cachedOffset()))) {
dfgRepatchCall(codeBlock, stubInfo.callReturnLocation, operationGetByIdBuildList);
return true;
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index efd46a8..57769a5 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -59,12 +59,14 @@
WTF::deleteAllValues(m_slowPathGenerators);
}
-void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR, GPRReg storageGPR, unsigned numElements)
+void SpeculativeJIT::emitAllocateJSArray(GPRReg resultGPR, Structure* structure, GPRReg storageGPR, unsigned numElements)
{
ASSERT(hasUndecided(structure->indexingType()) || hasInt32(structure->indexingType()) || hasDouble(structure->indexingType()) || hasContiguous(structure->indexingType()));
GPRTemporary scratch(this);
+ GPRTemporary scratch2(this);
GPRReg scratchGPR = scratch.gpr();
+ GPRReg scratch2GPR = scratch2.gpr();
unsigned vectorLength = std::max(BASE_VECTOR_LEN, numElements);
@@ -73,12 +75,8 @@
slowCases.append(
emitAllocateBasicStorage(TrustedImm32(vectorLength * sizeof(JSValue) + sizeof(IndexingHeader)), storageGPR));
m_jit.subPtr(TrustedImm32(vectorLength * sizeof(JSValue)), storageGPR);
- emitAllocateBasicJSObject<JSArray, MarkedBlock::None>(
- TrustedImmPtr(structure), resultGPR, scratchGPR,
- storageGPR, sizeof(JSArray), slowCases);
+ emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
- // I'm assuming that two 32-bit stores are better than a 64-bit store.
- // I have no idea if that's true. And it probably doesn't matter anyway.
m_jit.store32(TrustedImm32(numElements), MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
m_jit.store32(TrustedImm32(vectorLength), MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index e4fdc50a..7ef4541 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -938,6 +938,11 @@
m_jit.setupArgumentsWithExecState(object, TrustedImmPtr(size));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_EOZ operation, GPRReg result, GPRReg object, int32_t size)
+ {
+ m_jit.setupArgumentsWithExecState(object, TrustedImmPtr(static_cast<size_t>(size)));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(P_DFGOperation_EPS operation, GPRReg result, GPRReg old, size_t size)
{
m_jit.setupArgumentsWithExecState(old, TrustedImmPtr(size));
@@ -1305,6 +1310,11 @@
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(arg2));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_EOZ operation, GPRReg result, GPRReg object, int32_t size)
+ {
+ m_jit.setupArgumentsWithExecState(object, TrustedImmPtr(size));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(P_DFGOperation_EPS operation, GPRReg result, GPRReg old, size_t size)
{
m_jit.setupArgumentsWithExecState(old, TrustedImmPtr(size));
@@ -2135,27 +2145,19 @@
return slowPath;
}
-
- // It is NOT okay for the structure and the scratch register to be the same thing because if they are then the Structure will
- // get clobbered.
- template <typename ClassType, MarkedBlock::DestructorType destructorType, typename StructureType, typename StorageType>
- void emitAllocateBasicJSObject(StructureType structure, GPRReg resultGPR, GPRReg scratchGPR, StorageType storage, size_t size, MacroAssembler::JumpList& slowPath)
- {
- MarkedAllocator* allocator = 0;
- if (destructorType == MarkedBlock::Normal)
- allocator = &m_jit.globalData()->heap.allocatorForObjectWithNormalDestructor(size);
- else if (destructorType == MarkedBlock::ImmortalStructure)
- allocator = &m_jit.globalData()->heap.allocatorForObjectWithImmortalStructureDestructor(size);
- else
- allocator = &m_jit.globalData()->heap.allocatorForObjectWithoutDestructor(size);
- m_jit.loadPtr(&allocator->m_freeList.head, resultGPR);
+ // Allocator for an object of a specific size.
+ template <typename StructureType, typename StorageType> // StructureType and StorageType can be GPR or ImmPtr.
+ void emitAllocateJSObject(GPRReg resultGPR, GPRReg allocatorGPR, StructureType structure,
+ StorageType storage, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
+ {
+ m_jit.loadPtr(MacroAssembler::Address(allocatorGPR, MarkedAllocator::offsetOfFreeListHead()), resultGPR);
slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
// The object is half-allocated: we have what we know is a fresh object, but
// it's still on the GC's free list.
m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
- m_jit.storePtr(scratchGPR, &allocator->m_freeList.head);
+ m_jit.storePtr(scratchGPR, MacroAssembler::Address(allocatorGPR, MarkedAllocator::offsetOfFreeListHead()));
// Initialize the object's Structure.
m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSCell::structureOffset()));
@@ -2164,13 +2166,24 @@
m_jit.storePtr(storage, MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()));
}
- template<typename T>
- void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
+ // Convenience allocator for a buit-in object.
+ template <typename ClassType, typename StructureType, typename StorageType> // StructureType and StorageType can be GPR or ImmPtr.
+ void emitAllocateJSObject(GPRReg resultGPR, StructureType structure, StorageType storage,
+ GPRReg scratchGPR1, GPRReg scratchGPR2, MacroAssembler::JumpList& slowPath)
{
- return emitAllocateBasicJSObject<JSFinalObject, MarkedBlock::None>(structure, resultGPR, scratchGPR, TrustedImmPtr(0), JSFinalObject::allocationSize(INLINE_STORAGE_CAPACITY), slowPath);
+ MarkedAllocator* allocator = 0;
+ size_t size = ClassType::allocationSize(0);
+ if (ClassType::needsDestruction && ClassType::hasImmortalStructure)
+ allocator = &m_jit.globalData()->heap.allocatorForObjectWithImmortalStructureDestructor(size);
+ else if (ClassType::needsDestruction)
+ allocator = &m_jit.globalData()->heap.allocatorForObjectWithNormalDestructor(size);
+ else
+ allocator = &m_jit.globalData()->heap.allocatorForObjectWithoutDestructor(size);
+ m_jit.move(TrustedImmPtr(allocator), scratchGPR1);
+ emitAllocateJSObject(resultGPR, scratchGPR1, structure, storage, scratchGPR2, slowPath);
}
-
- void emitAllocateJSArray(Structure*, GPRReg resultGPR, GPRReg storageGPR, unsigned numElements);
+
+ void emitAllocateJSArray(GPRReg resultGPR, Structure*, GPRReg storageGPR, unsigned numElements);
#if USE(JSVALUE64)
JITCompiler::Jump convertToDouble(GPRReg value, FPRReg result, GPRReg tmp);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 17978f0..79bc932 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -3563,7 +3563,7 @@
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
- emitAllocateJSArray(structure, resultGPR, storageGPR, numElements);
+ emitAllocateJSArray(resultGPR, structure, storageGPR, numElements);
// At this point, one way or another, resultGPR and storageGPR have pointers to
// the JSArray and the Butterfly, respectively.
@@ -3729,11 +3729,13 @@
GPRTemporary result(this);
GPRTemporary storage(this);
GPRTemporary scratch(this);
+ GPRTemporary scratch2(this);
GPRReg sizeGPR = size.gpr();
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
GPRReg scratchGPR = scratch.gpr();
+ GPRReg scratch2GPR = scratch2.gpr();
MacroAssembler::JumpList slowCases;
slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
@@ -3745,9 +3747,8 @@
slowCases.append(
emitAllocateBasicStorage(resultGPR, storageGPR));
m_jit.subPtr(scratchGPR, storageGPR);
- emitAllocateBasicJSObject<JSArray, MarkedBlock::None>(
- TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR,
- storageGPR, sizeof(JSArray), slowCases);
+ Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType());
+ emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
@@ -3808,7 +3809,7 @@
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
- emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements);
+ emitAllocateJSArray(resultGPR, globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), storageGPR, numElements);
if (node.indexingType() == ArrayWithDouble) {
JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant());
@@ -3919,45 +3920,54 @@
SpeculateCellOperand callee(this, node.child1());
GPRTemporary result(this);
+ GPRTemporary allocator(this);
GPRTemporary structure(this);
GPRTemporary scratch(this);
GPRReg calleeGPR = callee.gpr();
GPRReg resultGPR = result.gpr();
+ GPRReg allocatorGPR = allocator.gpr();
GPRReg structureGPR = structure.gpr();
GPRReg scratchGPR = scratch.gpr();
- // Load the inheritorID. If the inheritorID is not set, go to slow path.
- m_jit.loadPtr(MacroAssembler::Address(calleeGPR, JSFunction::offsetOfCachedInheritorID()), structureGPR);
MacroAssembler::JumpList slowPath;
- slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, structureGPR));
-
- emitAllocateJSFinalObject(structureGPR, resultGPR, scratchGPR, slowPath);
-
- addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, calleeGPR));
+
+ m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR);
+ m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR);
+ slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, allocatorGPR));
+ emitAllocateJSObject(resultGPR, allocatorGPR, structureGPR, TrustedImmPtr(0), scratchGPR, slowPath);
+
+ addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, calleeGPR, node.inlineCapacity()));
cellResult(resultGPR, m_compileIndex);
break;
}
- case InheritorIDWatchpoint: {
- jsCast<JSFunction*>(node.function())->addInheritorIDWatchpoint(speculationWatchpoint());
+ case AllocationProfileWatchpoint: {
+ jsCast<JSFunction*>(node.function())->addAllocationProfileWatchpoint(speculationWatchpoint());
noResult(m_compileIndex);
break;
}
case NewObject: {
GPRTemporary result(this);
+ GPRTemporary allocator(this);
GPRTemporary scratch(this);
GPRReg resultGPR = result.gpr();
+ GPRReg allocatorGPR = allocator.gpr();
GPRReg scratchGPR = scratch.gpr();
MacroAssembler::JumpList slowPath;
- emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(node.structure()), resultGPR, scratchGPR, slowPath);
-
- addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, node.structure()));
+ Structure* structure = node.structure();
+ size_t allocationSize = JSObject::allocationSize(structure->inlineCapacity());
+ MarkedAllocator* allocatorPtr = &m_jit.globalData()->heap.allocatorForObjectWithoutDestructor(allocationSize);
+
+ m_jit.move(TrustedImmPtr(allocatorPtr), allocatorGPR);
+ emitAllocateJSObject(resultGPR, allocatorGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR, slowPath);
+
+ addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, structure));
cellResult(resultGPR, m_compileIndex);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index a79896e..e916da6 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3478,7 +3478,7 @@
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
- emitAllocateJSArray(structure, resultGPR, storageGPR, numElements);
+ emitAllocateJSArray(resultGPR, structure, storageGPR, numElements);
// At this point, one way or another, resultGPR and storageGPR have pointers to
// the JSArray and the Butterfly, respectively.
@@ -3645,19 +3645,13 @@
GPRTemporary result(this);
GPRTemporary storage(this);
GPRTemporary scratch(this);
- GPRTemporary scratch2;
+ GPRTemporary scratch2(this);
GPRReg sizeGPR = size.gpr();
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
GPRReg scratchGPR = scratch.gpr();
- GPRReg scratch2GPR = InvalidGPRReg;
-
- if (hasDouble(node.indexingType())) {
- GPRTemporary realScratch2(this, size);
- scratch2.adopt(realScratch2);
- scratch2GPR = scratch2.gpr();
- }
+ GPRReg scratch2GPR = scratch2.gpr();
MacroAssembler::JumpList slowCases;
slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
@@ -3669,9 +3663,8 @@
slowCases.append(
emitAllocateBasicStorage(resultGPR, storageGPR));
m_jit.subPtr(scratchGPR, storageGPR);
- emitAllocateBasicJSObject<JSArray, MarkedBlock::None>(
- TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR,
- storageGPR, sizeof(JSArray), slowCases);
+ Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType());
+ emitAllocateJSObject<JSArray>(resultGPR, ImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
@@ -3767,7 +3760,7 @@
GPRReg resultGPR = result.gpr();
GPRReg storageGPR = storage.gpr();
- emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements);
+ emitAllocateJSArray(resultGPR, globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), storageGPR, numElements);
RELEASE_ASSERT(indexingType & IsArray);
JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant());
@@ -3871,45 +3864,54 @@
SpeculateCellOperand callee(this, node.child1());
GPRTemporary result(this);
+ GPRTemporary allocator(this);
GPRTemporary structure(this);
GPRTemporary scratch(this);
GPRReg calleeGPR = callee.gpr();
GPRReg resultGPR = result.gpr();
+ GPRReg allocatorGPR = allocator.gpr();
GPRReg structureGPR = structure.gpr();
GPRReg scratchGPR = scratch.gpr();
-
- // Load the inheritorID. If the inheritorID is not set, go to slow path.
- m_jit.loadPtr(MacroAssembler::Address(calleeGPR, JSFunction::offsetOfCachedInheritorID()), structureGPR);
+
MacroAssembler::JumpList slowPath;
- slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, structureGPR));
-
- emitAllocateJSFinalObject(structureGPR, resultGPR, scratchGPR, slowPath);
-
- addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, calleeGPR));
+
+ m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR);
+ m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR);
+ slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, allocatorGPR));
+ emitAllocateJSObject(resultGPR, allocatorGPR, structureGPR, TrustedImmPtr(0), scratchGPR, slowPath);
+
+ addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, calleeGPR, node.inlineCapacity()));
cellResult(resultGPR, m_compileIndex);
break;
}
- case InheritorIDWatchpoint: {
- jsCast<JSFunction*>(node.function())->addInheritorIDWatchpoint(speculationWatchpoint());
+ case AllocationProfileWatchpoint: {
+ jsCast<JSFunction*>(node.function())->addAllocationProfileWatchpoint(speculationWatchpoint());
noResult(m_compileIndex);
break;
}
case NewObject: {
GPRTemporary result(this);
+ GPRTemporary allocator(this);
GPRTemporary scratch(this);
GPRReg resultGPR = result.gpr();
+ GPRReg allocatorGPR = allocator.gpr();
GPRReg scratchGPR = scratch.gpr();
MacroAssembler::JumpList slowPath;
-
- emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(node.structure()), resultGPR, scratchGPR, slowPath);
-
- addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, node.structure()));
+
+ Structure* structure = node.structure();
+ size_t allocationSize = JSObject::allocationSize(structure->inlineCapacity());
+ MarkedAllocator* allocatorPtr = &m_jit.globalData()->heap.allocatorForObjectWithoutDestructor(allocationSize);
+
+ m_jit.move(TrustedImmPtr(allocatorPtr), allocatorGPR);
+ emitAllocateJSObject(resultGPR, allocatorGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR, slowPath);
+
+ addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, structure));
cellResult(resultGPR, m_compileIndex);
break;
diff --git a/Source/JavaScriptCore/heap/MarkedAllocator.h b/Source/JavaScriptCore/heap/MarkedAllocator.h
index 867481f..6866914 100644
--- a/Source/JavaScriptCore/heap/MarkedAllocator.h
+++ b/Source/JavaScriptCore/heap/MarkedAllocator.h
@@ -15,10 +15,11 @@
}
class MarkedAllocator {
- friend class JIT;
- friend class DFG::SpeculativeJIT;
+ friend class LLIntOffsetsExtractor;
public:
+ static ptrdiff_t offsetOfFreeListHead();
+
MarkedAllocator();
void reset();
void canonicalizeCellLivenessData();
@@ -36,8 +37,6 @@
bool isPagedOut(double deadline);
private:
- friend class LLIntOffsetsExtractor;
-
JS_EXPORT_PRIVATE void* allocateSlowCase(size_t);
void* tryAllocate(size_t);
void* tryAllocateHelper(size_t);
@@ -53,6 +52,11 @@
MarkedSpace* m_markedSpace;
};
+inline ptrdiff_t MarkedAllocator::offsetOfFreeListHead()
+{
+ return OBJECT_OFFSETOF(MarkedAllocator, m_freeList) + OBJECT_OFFSETOF(MarkedBlock::FreeList, head);
+}
+
inline MarkedAllocator::MarkedAllocator()
: m_currentBlock(0)
, m_blocksToSweep(0)
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index f6edd3f..2cb3f89 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -62,6 +62,7 @@
class Interpreter;
class JSScope;
class JSStack;
+ class MarkedAllocator;
class Register;
class StructureChain;
@@ -453,8 +454,8 @@
void emitWriteBarrier(RegisterID owner, RegisterID valueTag, RegisterID scratch, RegisterID scratch2, WriteBarrierMode, WriteBarrierUseKind);
void emitWriteBarrier(JSCell* owner, RegisterID value, RegisterID scratch, WriteBarrierMode, WriteBarrierUseKind);
- template<typename ClassType, MarkedBlock::DestructorType, typename StructureType> void emitAllocateBasicJSObject(StructureType, RegisterID result, RegisterID storagePtr);
- template<typename T> void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID storagePtr);
+ template<typename StructureType> // StructureType can be RegisterID or ImmPtr.
+ void emitAllocateJSObject(RegisterID allocator, StructureType, RegisterID result, RegisterID scratch);
#if ENABLE(VALUE_PROFILER)
// This assumes that the value to profile is in regT0 and that regT3 is available for
diff --git a/Source/JavaScriptCore/jit/JITInlines.h b/Source/JavaScriptCore/jit/JITInlines.h
index 6ea0321..14b5b1e 100644
--- a/Source/JavaScriptCore/jit/JITInlines.h
+++ b/Source/JavaScriptCore/jit/JITInlines.h
@@ -310,22 +310,15 @@
return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1;
}
-template <typename ClassType, MarkedBlock::DestructorType destructorType, typename StructureType> inline void JIT::emitAllocateBasicJSObject(StructureType structure, RegisterID result, RegisterID storagePtr)
+template<typename StructureType>
+inline void JIT::emitAllocateJSObject(RegisterID allocator, StructureType structure, RegisterID result, RegisterID scratch)
{
- size_t size = ClassType::allocationSize(INLINE_STORAGE_CAPACITY);
- MarkedAllocator* allocator = 0;
- if (destructorType == MarkedBlock::Normal)
- allocator = &m_globalData->heap.allocatorForObjectWithNormalDestructor(size);
- else if (destructorType == MarkedBlock::ImmortalStructure)
- allocator = &m_globalData->heap.allocatorForObjectWithImmortalStructureDestructor(size);
- else
- allocator = &m_globalData->heap.allocatorForObjectWithoutDestructor(size);
- loadPtr(&allocator->m_freeList.head, result);
+ loadPtr(Address(allocator, MarkedAllocator::offsetOfFreeListHead()), result);
addSlowCase(branchTestPtr(Zero, result));
// remove the object from the free list
- loadPtr(Address(result), storagePtr);
- storePtr(storagePtr, &allocator->m_freeList.head);
+ loadPtr(Address(result), scratch);
+ storePtr(scratch, Address(allocator, MarkedAllocator::offsetOfFreeListHead()));
// initialize the object's structure
storePtr(structure, Address(result, JSCell::structureOffset()));
@@ -334,11 +327,6 @@
storePtr(TrustedImmPtr(0), Address(result, JSObject::butterflyOffset()));
}
-template <typename T> inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch)
-{
- emitAllocateBasicJSObject<JSFinalObject, MarkedBlock::None, T>(structure, result, scratch);
-}
-
#if ENABLE(VALUE_PROFILER)
inline void JIT::emitValueProfilingSite(ValueProfile* valueProfile)
{
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index 404d537..4ac8037 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -95,15 +95,25 @@
void JIT::emit_op_new_object(Instruction* currentInstruction)
{
- emitAllocateJSFinalObject(TrustedImmPtr(m_codeBlock->globalObject()->emptyObjectStructure()), regT0, regT1);
-
+ Structure* structure = currentInstruction[3].u.objectAllocationProfile->structure();
+ size_t allocationSize = JSObject::allocationSize(structure->inlineCapacity());
+ MarkedAllocator* allocator = &m_globalData->heap.allocatorForObjectWithoutDestructor(allocationSize);
+
+ RegisterID resultReg = regT0;
+ RegisterID allocatorReg = regT1;
+ RegisterID scratchReg = regT2;
+
+ move(TrustedImmPtr(allocator), allocatorReg);
+ emitAllocateJSObject(allocatorReg, TrustedImmPtr(structure), resultReg, scratchReg);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
void JIT::emitSlow_op_new_object(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
- JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand);
+ JITStubCall stubCall(this, cti_op_new_object);
+ stubCall.addArgument(TrustedImmPtr(currentInstruction[3].u.objectAllocationProfile->structure()));
+ stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_check_has_instance(Instruction* currentInstruction)
@@ -922,22 +932,28 @@
void JIT::emit_op_create_this(Instruction* currentInstruction)
{
int callee = currentInstruction[2].u.operand;
- emitGetVirtualRegister(callee, regT0);
- loadPtr(Address(regT0, JSFunction::offsetOfCachedInheritorID()), regT2);
- addSlowCase(branchTestPtr(Zero, regT2));
-
- // now regT2 contains the inheritorID, which is the structure that the newly
- // allocated object will have.
-
- emitAllocateJSFinalObject(regT2, regT0, regT1);
+ RegisterID calleeReg = regT0;
+ RegisterID resultReg = regT0;
+ RegisterID allocatorReg = regT1;
+ RegisterID structureReg = regT2;
+ RegisterID scratchReg = regT3;
+
+ emitGetVirtualRegister(callee, calleeReg);
+ loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorReg);
+ loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg);
+ addSlowCase(branchTestPtr(Zero, allocatorReg));
+
+ emitAllocateJSObject(allocatorReg, structureReg, resultReg, scratchReg);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
- linkSlowCase(iter); // doesn't have an inheritor ID
+ linkSlowCase(iter); // doesn't have an allocation profile
linkSlowCase(iter); // allocation failed
+
JITStubCall stubCall(this, cti_op_create_this);
+ stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
stubCall.call(currentInstruction[1].u.operand);
}
diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
index fe3818e..389b4cb 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -213,15 +213,25 @@
void JIT::emit_op_new_object(Instruction* currentInstruction)
{
- emitAllocateJSFinalObject(TrustedImmPtr(m_codeBlock->globalObject()->emptyObjectStructure()), regT0, regT1);
-
- emitStoreCell(currentInstruction[1].u.operand, regT0);
+ Structure* structure = currentInstruction[3].u.objectAllocationProfile->structure();
+ size_t allocationSize = JSObject::allocationSize(structure->inlineCapacity());
+ MarkedAllocator* allocator = &m_globalData->heap.allocatorForObjectWithoutDestructor(allocationSize);
+
+ RegisterID resultReg = regT0;
+ RegisterID allocatorReg = regT1;
+ RegisterID scratchReg = regT2;
+
+ move(TrustedImmPtr(allocator), allocatorReg);
+ emitAllocateJSObject(allocatorReg, TrustedImmPtr(structure), resultReg, scratchReg);
+ emitStoreCell(currentInstruction[1].u.operand, resultReg);
}
void JIT::emitSlow_op_new_object(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
- JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand);
+ JITStubCall stubCall(this, cti_op_new_object);
+ stubCall.addArgument(TrustedImmPtr(currentInstruction[3].u.objectAllocationProfile->structure()));
+ stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_check_has_instance(Instruction* currentInstruction)
@@ -1161,22 +1171,28 @@
void JIT::emit_op_create_this(Instruction* currentInstruction)
{
int callee = currentInstruction[2].u.operand;
- emitLoadPayload(callee, regT0);
- loadPtr(Address(regT0, JSFunction::offsetOfCachedInheritorID()), regT2);
- addSlowCase(branchTestPtr(Zero, regT2));
-
- // now regT2 contains the inheritorID, which is the structure that the newly
- // allocated object will have.
-
- emitAllocateJSFinalObject(regT2, regT0, regT1);
- emitStoreCell(currentInstruction[1].u.operand, regT0);
+ RegisterID calleeReg = regT0;
+ RegisterID resultReg = regT0;
+ RegisterID allocatorReg = regT1;
+ RegisterID structureReg = regT2;
+ RegisterID scratchReg = regT3;
+
+ emitLoadPayload(callee, calleeReg);
+ loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorReg);
+ loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg);
+ addSlowCase(branchTestPtr(Zero, allocatorReg));
+
+ emitAllocateJSObject(allocatorReg, structureReg, resultReg, scratchReg);
+ emitStoreCell(currentInstruction[1].u.operand, resultReg);
}
void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
- linkSlowCase(iter); // doesn't have an inheritor ID
+ linkSlowCase(iter); // doesn't have an allocation profile
linkSlowCase(iter); // allocation failed
+
JITStubCall stubCall(this, cti_op_create_this);
+ stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
stubCall.call(currentInstruction[1].u.operand);
}
diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp
index 3b085bf..047795b 100644
--- a/Source/JavaScriptCore/jit/JITStubs.cpp
+++ b/Source/JavaScriptCore/jit/JITStubs.cpp
@@ -58,6 +58,7 @@
#include "JSWithScope.h"
#include "LegacyProfiler.h"
#include "NameInstance.h"
+#include "ObjectConstructor.h"
#include "ObjectPrototype.h"
#include "Operations.h"
#include "Parser.h"
@@ -931,10 +932,9 @@
// Cache hit: Specialize instruction and ref Structures.
if (slot.slotBase() == baseValue) {
- // set this up, so derefStructures can do it's job.
stubInfo->initGetByIdSelf(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
if ((slot.cachedPropertyType() != PropertySlot::Value)
- || !MacroAssembler::isCompactPtrAlignedAddressOffset(offsetRelativeToPatchedStorage(slot.cachedOffset())))
+ || !MacroAssembler::isCompactPtrAlignedAddressOffset(maxOffsetRelativeToPatchedStorage(slot.cachedOffset())))
ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail));
else
JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress);
@@ -1300,6 +1300,7 @@
{
STUB_INIT_STACK_FRAME(stackFrame);
CallFrame* callFrame = stackFrame.callFrame;
+ size_t inlineCapacity = stackFrame.args[0].int32();
JSFunction* constructor = jsCast<JSFunction*>(callFrame->callee());
#if !ASSERT_DISABLED
@@ -1307,7 +1308,7 @@
ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
#endif
- Structure* structure = constructor->cachedInheritorID(callFrame);
+ Structure* structure = constructor->allocationProfile(callFrame, inlineCapacity)->structure();
JSValue result = constructEmptyObject(callFrame, structure);
return JSValue::encode(result);
@@ -1395,7 +1396,7 @@
{
STUB_INIT_STACK_FRAME(stackFrame);
- return constructEmptyObject(stackFrame.callFrame);
+ return constructEmptyObject(stackFrame.callFrame, stackFrame.args[0].structure());
}
DEFINE_STUB_FUNCTION(void, op_put_by_id_generic)
diff --git a/Source/JavaScriptCore/llint/LLIntData.cpp b/Source/JavaScriptCore/llint/LLIntData.cpp
index 90faff2..d105290 100644
--- a/Source/JavaScriptCore/llint/LLIntData.cpp
+++ b/Source/JavaScriptCore/llint/LLIntData.cpp
@@ -108,9 +108,9 @@
ASSERT(ImplementsHasInstance == 2);
ASSERT(ImplementsDefaultHasInstance == 8);
#if USE(JSVALUE64)
- ASSERT(&globalData.heap.allocatorForObjectWithoutDestructor(JSObject::allocationSize(INLINE_STORAGE_CAPACITY)) - &globalData.heap.firstAllocatorWithoutDestructors() == 1);
+ ASSERT(&globalData.heap.allocatorForObjectWithoutDestructor(JSFinalObject::allocationSize(JSFinalObject::defaultInlineCapacity())) - &globalData.heap.firstAllocatorWithoutDestructors() == 1);
#else
- ASSERT(&globalData.heap.allocatorForObjectWithoutDestructor(JSObject::allocationSize(INLINE_STORAGE_CAPACITY)) - &globalData.heap.firstAllocatorWithoutDestructors() == 3);
+ ASSERT(&globalData.heap.allocatorForObjectWithoutDestructor(JSFinalObject::allocationSize(JSFinalObject::defaultInlineCapacity())) - &globalData.heap.firstAllocatorWithoutDestructors() == 3);
#endif
ASSERT(FirstConstantRegisterIndex == 0x40000000);
ASSERT(GlobalCode == 0);
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index a69fec6..71f5aee 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -47,6 +47,7 @@
#include "LLIntCommon.h"
#include "LLIntExceptions.h"
#include "LowLevelInterpreter.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
#include <wtf/StringPrintStream.h>
@@ -483,8 +484,9 @@
ConstructData constructData;
ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
#endif
-
- Structure* structure = constructor->cachedInheritorID(exec);
+
+ size_t inlineCapacity = pc[3].u.operand;
+ Structure* structure = constructor->allocationProfile(exec, inlineCapacity)->structure();
LLINT_RETURN(constructEmptyObject(exec, structure));
}
@@ -503,7 +505,7 @@
LLINT_SLOW_PATH_DECL(slow_path_new_object)
{
LLINT_BEGIN();
- LLINT_RETURN(constructEmptyObject(exec));
+ LLINT_RETURN(constructEmptyObject(exec, pc[3].u.objectAllocationProfile->structure()));
}
LLINT_SLOW_PATH_DECL(slow_path_new_array)
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index 9de48f1..64d2296 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -369,32 +369,21 @@
.stackHeightOK:
end
-macro allocateBasicJSObject(sizeClassIndex, structure, result, scratch1, scratch2, slowCase)
+macro allocateJSObject(allocator, structure, result, scratch1, slowCase)
if ALWAYS_ALLOCATE_SLOW
jmp slowCase
else
- const offsetOfMySizeClass =
- JSGlobalData::heap +
- Heap::m_objectSpace +
- MarkedSpace::m_normalSpace +
- MarkedSpace::Subspace::preciseAllocators +
- sizeClassIndex * sizeof MarkedAllocator
-
const offsetOfFirstFreeCell =
MarkedAllocator::m_freeList +
MarkedBlock::FreeList::head
- # FIXME: we can get the global data in one load from the stack.
- loadp CodeBlock[cfr], scratch1
- loadp CodeBlock::m_globalData[scratch1], scratch1
-
# Get the object from the free list.
- loadp offsetOfMySizeClass + offsetOfFirstFreeCell[scratch1], result
+ loadp offsetOfFirstFreeCell[allocator], result
btpz result, slowCase
# Remove the object from the free list.
- loadp [result], scratch2
- storep scratch2, offsetOfMySizeClass + offsetOfFirstFreeCell[scratch1]
+ loadp [result], scratch1
+ storep scratch1, offsetOfFirstFreeCell[allocator]
# Initialize the object.
storep structure, JSCell::m_structure[result]
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index 98097bb..54d1f7b 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -361,17 +361,18 @@
traceExecution()
loadi 8[PC], t0
loadp PayloadOffset[cfr, t0, 8], t0
- loadp JSFunction::m_cachedInheritorID[t0], t2
- btpz t2, .opCreateThisSlow
- allocateBasicJSObject(JSFinalObjectSizeClassIndex, t2, t0, t1, t3, .opCreateThisSlow)
+ loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_allocator[t0], t1
+ loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_structure[t0], t2
+ btpz t1, .opCreateThisSlow
+ allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
loadi 4[PC], t1
storei CellTag, TagOffset[cfr, t1, 8]
storei t0, PayloadOffset[cfr, t1, 8]
- dispatch(3)
+ dispatch(4)
.opCreateThisSlow:
callSlowPath(_llint_slow_path_create_this)
- dispatch(3)
+ dispatch(4)
_llint_op_get_callee:
@@ -403,18 +404,18 @@
_llint_op_new_object:
traceExecution()
- loadp CodeBlock[cfr], t0
- loadp CodeBlock::m_globalObject[t0], t0
- loadp JSGlobalObject::m_emptyObjectStructure[t0], t1
- allocateBasicJSObject(JSFinalObjectSizeClassIndex, t1, t0, t2, t3, .opNewObjectSlow)
+ loadpFromInstruction(3, t0)
+ loadp ObjectAllocationProfile::m_allocator[t0], t1
+ loadp ObjectAllocationProfile::m_structure[t0], t2
+ allocateJSObject(t1, t2, t0, t3, .opNewObjectSlow)
loadi 4[PC], t1
storei CellTag, TagOffset[cfr, t1, 8]
storei t0, PayloadOffset[cfr, t1, 8]
- dispatch(2)
+ dispatch(4)
.opNewObjectSlow:
callSlowPath(_llint_slow_path_new_object)
- dispatch(2)
+ dispatch(4)
_llint_op_mov:
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index a9f427b..8352971 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -243,16 +243,17 @@
traceExecution()
loadisFromInstruction(2, t0)
loadp [cfr, t0, 8], t0
- loadp JSFunction::m_cachedInheritorID[t0], t2
- btpz t2, .opCreateThisSlow
- allocateBasicJSObject(JSFinalObjectSizeClassIndex, t2, t0, t1, t3, .opCreateThisSlow)
+ loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_allocator[t0], t1
+ loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_structure[t0], t2
+ btpz t1, .opCreateThisSlow
+ allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
loadisFromInstruction(1, t1)
storeq t0, [cfr, t1, 8]
- dispatch(3)
+ dispatch(4)
.opCreateThisSlow:
callSlowPath(_llint_slow_path_create_this)
- dispatch(3)
+ dispatch(4)
_llint_op_get_callee:
@@ -283,17 +284,17 @@
_llint_op_new_object:
traceExecution()
- loadp CodeBlock[cfr], t0
- loadp CodeBlock::m_globalObject[t0], t0
- loadp JSGlobalObject::m_emptyObjectStructure[t0], t1
- allocateBasicJSObject(JSFinalObjectSizeClassIndex, t1, t0, t2, t3, .opNewObjectSlow)
+ loadpFromInstruction(3, t0)
+ loadp ObjectAllocationProfile::m_allocator[t0], t1
+ loadp ObjectAllocationProfile::m_structure[t0], t2
+ allocateJSObject(t1, t2, t0, t3, .opNewObjectSlow)
loadisFromInstruction(1, t1)
storeq t0, [cfr, t1, 8]
- dispatch(2)
+ dispatch(4)
.opNewObjectSlow:
callSlowPath(_llint_slow_path_new_object)
- dispatch(2)
+ dispatch(4)
_llint_op_mov:
diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp
index 3755a27..c68ff7d3 100644
--- a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp
@@ -27,6 +27,7 @@
#include "ProfilerBytecode.h"
#include "JSGlobalObject.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
index 481f4de..d017582 100644
--- a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
@@ -28,6 +28,7 @@
#include "CodeBlock.h"
#include "JSGlobalObject.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
#include <wtf/StringPrintStream.h>
diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
index c70152c..5ff49d4 100644
--- a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
@@ -27,6 +27,7 @@
#include "ProfilerCompilation.h"
#include "JSGlobalObject.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
#include "ProfilerDatabase.h"
#include <wtf/StringPrintStream.h>
diff --git a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp
index b8f5a85..d53dd2a 100644
--- a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp
@@ -27,6 +27,7 @@
#include "ProfilerCompiledBytecode.h"
#include "JSGlobalObject.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
index c4a334d..3a0a752 100644
--- a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
@@ -28,6 +28,7 @@
#include "CodeBlock.h"
#include "JSONObject.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp
index 5fe13f7..e114ddf 100644
--- a/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp
@@ -27,6 +27,7 @@
#include "ProfilerOSRExit.h"
#include "JSGlobalObject.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp
index ffbcf28..ca9782a 100644
--- a/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp
@@ -27,6 +27,7 @@
#include "ProfilerOrigin.h"
#include "JSGlobalObject.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
#include "ProfilerBytecodes.h"
#include "ProfilerDatabase.h"
diff --git a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp
index d072e4f..30915e5 100644
--- a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp
@@ -27,6 +27,7 @@
#include "ProfilerProfiledBytecodes.h"
#include "JSGlobalObject.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
index d3dd929..1b42b7f 100644
--- a/Source/JavaScriptCore/runtime/Executable.h
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -778,7 +778,7 @@
: Base(globalData, scope->globalObject()->functionStructure())
, m_executable(globalData, this, executable)
, m_scope(globalData, this, scope)
- , m_inheritorIDWatchpoint(InitializedBlind) // See comment in JSFunction.cpp concerning the reason for using InitializedBlind as opposed to InitializedWatching.
+ , m_allocationProfileWatchpoint(InitializedBlind) // See comment in JSFunction.cpp concerning the reason for using InitializedBlind as opposed to InitializedWatching.
{
}
diff --git a/Source/JavaScriptCore/runtime/JSCellInlines.h b/Source/JavaScriptCore/runtime/JSCellInlines.h
index 2614e55a..85c9663 100644
--- a/Source/JavaScriptCore/runtime/JSCellInlines.h
+++ b/Source/JavaScriptCore/runtime/JSCellInlines.h
@@ -83,7 +83,7 @@
JSCell* result = 0;
if (T::needsDestruction && T::hasImmortalStructure)
result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size));
- else if (T::needsDestruction && !T::hasImmortalStructure)
+ else if (T::needsDestruction)
result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size));
else
result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size));
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 34e675c..ded8e88 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -35,6 +35,7 @@
#include "JSGlobalObject.h"
#include "JSNotAnObject.h"
#include "Interpreter.h"
+#include "ObjectConstructor.h"
#include "ObjectPrototype.h"
#include "Operations.h"
#include "Parser.h"
@@ -88,12 +89,12 @@
// the optimizer kicks in don't disable optimizations. Once the optimizer kicks in, the
// watchpoint will start watching and any changes will both force deoptimization and disable
// future attempts to optimize. This is necessary because we are guaranteed that the
- // inheritorID is changed exactly once prior to optimizations kicking in. We could be
+ // allocation profile is changed exactly once prior to optimizations kicking in. We could be
// smarter and count the number of times the prototype is clobbered and only optimize if it
// was clobbered exactly once, but that seems like overkill. In almost all cases it will be
// clobbered once, and if it's clobbered more than once, that will probably only occur
// before we started optimizing, anyway.
- , m_inheritorIDWatchpoint(InitializedBlind)
+ , m_allocationProfileWatchpoint(InitializedBlind)
{
}
@@ -106,15 +107,14 @@
putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum);
}
-Structure* JSFunction::cacheInheritorID(ExecState* exec)
+ObjectAllocationProfile* JSFunction::createAllocationProfile(ExecState* exec, size_t inlineCapacity)
{
JSGlobalData& globalData = exec->globalData();
- JSValue prototype = get(exec, globalData.propertyNames->prototype);
- if (prototype.isObject())
- m_cachedInheritorID.set(globalData, this, globalData.prototypeMap.emptyObjectStructureForPrototype(asObject(prototype)));
- else
- m_cachedInheritorID.set(globalData, this, globalData.prototypeMap.emptyObjectStructureForPrototype(globalObject()->objectPrototype()));
- return m_cachedInheritorID.get();
+ JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, globalData.propertyNames->prototype));
+ if (!prototype)
+ prototype = globalObject()->objectPrototype();
+ m_allocationProfile.initialize(globalObject()->globalData(), this, prototype, inlineCapacity);
+ return &m_allocationProfile;
}
String JSFunction::name(ExecState* exec)
@@ -163,7 +163,7 @@
visitor.append(&thisObject->m_scope);
visitor.append(&thisObject->m_executable);
- visitor.append(&thisObject->m_cachedInheritorID);
+ thisObject->m_allocationProfile.visitAggregate(visitor);
}
CallType JSFunction::getCallData(JSCell* cell, CallData& callData)
@@ -221,12 +221,13 @@
return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
if (propertyName == exec->propertyNames().prototype) {
- PropertyOffset offset = thisObject->getDirectOffset(exec->globalData(), propertyName);
+ JSGlobalData& globalData = exec->globalData();
+ PropertyOffset offset = thisObject->getDirectOffset(globalData, propertyName);
if (!isValidOffset(offset)) {
- JSObject* prototype = constructEmptyObject(exec, thisObject->globalObject()->emptyObjectStructure());
- prototype->putDirect(exec->globalData(), exec->propertyNames().constructor, thisObject, DontEnum);
- thisObject->putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
- offset = thisObject->getDirectOffset(exec->globalData(), exec->propertyNames().prototype);
+ JSObject* prototype = constructEmptyObject(exec);
+ prototype->putDirect(globalData, exec->propertyNames().constructor, thisObject, DontEnum);
+ thisObject->putDirect(globalData, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
+ offset = thisObject->getDirectOffset(globalData, exec->propertyNames().prototype);
ASSERT(isValidOffset(offset));
}
@@ -355,9 +356,9 @@
// following the rules set out in ECMA-262 8.12.9.
PropertySlot slot;
thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
- thisObject->m_cachedInheritorID.clear();
- thisObject->m_inheritorIDWatchpoint.notifyWrite();
- // Don't allow this to be cached, since a [[Put]] must clear m_cachedInheritorID.
+ thisObject->m_allocationProfile.clear();
+ thisObject->m_allocationProfileWatchpoint.notifyWrite();
+ // Don't allow this to be cached, since a [[Put]] must clear m_allocationProfile.
PutPropertySlot dontCache;
Base::put(thisObject, exec, propertyName, value, dontCache);
return;
@@ -402,8 +403,8 @@
// following the rules set out in ECMA-262 8.12.9.
PropertySlot slot;
thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
- thisObject->m_cachedInheritorID.clear();
- thisObject->m_inheritorIDWatchpoint.notifyWrite();
+ thisObject->m_allocationProfile.clear();
+ thisObject->m_allocationProfileWatchpoint.notifyWrite();
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
@@ -469,7 +470,6 @@
constructData.js.scope = thisObject->scope();
return ConstructTypeJS;
}
-
String getCalculatedDisplayName(CallFrame* callFrame, JSObject* object)
{
diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h
index b36e0b7..f4918b0 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.h
+++ b/Source/JavaScriptCore/runtime/JSFunction.h
@@ -27,6 +27,7 @@
#include "InternalFunction.h"
#include "JSDestructibleObject.h"
#include "JSScope.h"
+#include "ObjectAllocationProfile.h"
#include "Watchpoint.h"
namespace JSC {
@@ -116,41 +117,42 @@
static ConstructType getConstructData(JSCell*, ConstructData&);
static CallType getCallData(JSCell*, CallData&);
- static inline size_t offsetOfScopeChain()
+ static inline ptrdiff_t offsetOfScopeChain()
{
return OBJECT_OFFSETOF(JSFunction, m_scope);
}
- static inline size_t offsetOfExecutable()
+ static inline ptrdiff_t offsetOfExecutable()
{
return OBJECT_OFFSETOF(JSFunction, m_executable);
}
- Structure* cachedInheritorID(ExecState* exec)
+ static inline ptrdiff_t offsetOfAllocationProfile()
{
- if (UNLIKELY(!m_cachedInheritorID))
- return cacheInheritorID(exec);
- return m_cachedInheritorID.get();
+ return OBJECT_OFFSETOF(JSFunction, m_allocationProfile);
}
- Structure* tryGetKnownInheritorID()
+ ObjectAllocationProfile* allocationProfile(ExecState* exec, unsigned inlineCapacity)
{
- if (!m_cachedInheritorID)
+ if (UNLIKELY(m_allocationProfile.isNull()))
+ return createAllocationProfile(exec, inlineCapacity);
+ ASSERT(inlineCapacity <= m_allocationProfile.structure()->inlineCapacity());
+ return &m_allocationProfile;
+ }
+
+ ObjectAllocationProfile* tryGetAllocationProfile()
+ {
+ if (m_allocationProfile.isNull())
return 0;
- if (m_inheritorIDWatchpoint.hasBeenInvalidated())
+ if (m_allocationProfileWatchpoint.hasBeenInvalidated())
return 0;
- return m_cachedInheritorID.get();
+ return &m_allocationProfile;
}
- void addInheritorIDWatchpoint(Watchpoint* watchpoint)
+ void addAllocationProfileWatchpoint(Watchpoint* watchpoint)
{
- ASSERT(tryGetKnownInheritorID());
- m_inheritorIDWatchpoint.add(watchpoint);
- }
-
- static size_t offsetOfCachedInheritorID()
- {
- return OBJECT_OFFSETOF(JSFunction, m_cachedInheritorID);
+ ASSERT(tryGetAllocationProfile());
+ m_allocationProfileWatchpoint.add(watchpoint);
}
protected:
@@ -162,7 +164,7 @@
void finishCreation(ExecState*, NativeExecutable*, int length, const String& name);
using Base::finishCreation;
- Structure* cacheInheritorID(ExecState*);
+ ObjectAllocationProfile* createAllocationProfile(ExecState*, size_t inlineCapacity);
static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
@@ -187,8 +189,8 @@
WriteBarrier<ExecutableBase> m_executable;
WriteBarrier<JSScope> m_scope;
- WriteBarrier<Structure> m_cachedInheritorID;
- InlineWatchpointSet m_inheritorIDWatchpoint;
+ ObjectAllocationProfile m_allocationProfile;
+ InlineWatchpointSet m_allocationProfileWatchpoint;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index a509ecb..fcd0a9b 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -223,8 +223,7 @@
m_strictEvalActivationStructure.set(exec->globalData(), this, StrictEvalActivation::createStructure(exec->globalData(), this, jsNull()));
m_withScopeStructure.set(exec->globalData(), this, JSWithScope::createStructure(exec->globalData(), this, jsNull()));
- m_emptyObjectStructure.set(exec->globalData(), this, globalData().prototypeMap.emptyObjectStructureForPrototype(m_objectPrototype.get()));
- m_nullPrototypeObjectStructure.set(exec->globalData(), this, JSFinalObject::createStructure(globalData(), this, jsNull()));
+ m_nullPrototypeObjectStructure.set(exec->globalData(), this, JSFinalObject::createStructure(globalData(), this, jsNull(), JSFinalObject::defaultInlineCapacity()));
m_callbackFunctionStructure.set(exec->globalData(), this, JSCallbackFunction::createStructure(exec->globalData(), this, m_functionPrototype.get()));
m_argumentsStructure.set(exec->globalData(), this, Arguments::createStructure(exec->globalData(), this, m_objectPrototype.get()));
@@ -513,7 +512,6 @@
visitor.append(&thisObject->m_callbackFunctionStructure);
visitor.append(&thisObject->m_callbackObjectStructure);
visitor.append(&thisObject->m_dateStructure);
- visitor.append(&thisObject->m_emptyObjectStructure);
visitor.append(&thisObject->m_nullPrototypeObjectStructure);
visitor.append(&thisObject->m_errorStructure);
visitor.append(&thisObject->m_functionStructure);
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index d1cef90..2073696 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -141,7 +141,6 @@
WriteBarrier<Structure> m_callbackFunctionStructure;
WriteBarrier<Structure> m_callbackObjectStructure;
WriteBarrier<Structure> m_dateStructure;
- WriteBarrier<Structure> m_emptyObjectStructure;
WriteBarrier<Structure> m_nullPrototypeObjectStructure;
WriteBarrier<Structure> m_errorStructure;
WriteBarrier<Structure> m_functionStructure;
@@ -303,7 +302,6 @@
Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
Structure* dateStructure() const { return m_dateStructure.get(); }
- Structure* emptyObjectStructure() const { return m_emptyObjectStructure.get(); }
Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); }
Structure* errorStructure() const { return m_errorStructure.get(); }
Structure* functionStructure() const { return m_functionStructure.get(); }
@@ -514,16 +512,6 @@
return globalData().dynamicGlobalObject;
}
- inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
- {
- return constructEmptyObject(exec, globalObject->emptyObjectStructure());
- }
-
- inline JSObject* constructEmptyObject(ExecState* exec)
- {
- return constructEmptyObject(exec, exec->lexicalGlobalObject());
- }
-
inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0)
{
return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength));
diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp
index 0b501334..9fd19f6 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSONObject.cpp
@@ -35,6 +35,7 @@
#include "Local.h"
#include "LocalScope.h"
#include "Lookup.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
#include "PropertyNameArray.h"
#include <wtf/MathExtras.h>
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index d77aaf7..1cb7e85 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -960,7 +960,6 @@
Butterfly* m_butterfly;
};
-
// JSNonFinalObject is a type of JSObject that has some internal storage,
// but also preserves some space in the collector cell for additional
// data members in derived types.
@@ -999,10 +998,22 @@
public:
typedef JSObject Base;
- static JSFinalObject* create(ExecState*, Structure*);
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ static const unsigned defaultSize = 64;
+ static inline unsigned defaultInlineCapacity()
{
- return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info, NonArray, INLINE_STORAGE_CAPACITY);
+ return (defaultSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
+ }
+
+ static const unsigned maxSize = 512;
+ static inline unsigned maxInlineCapacity()
+ {
+ return (maxSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
+ }
+
+ static JSFinalObject* create(ExecState*, Structure*);
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, unsigned inlineCapacity)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info, NonArray, inlineCapacity);
}
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
@@ -1096,11 +1107,6 @@
m_butterfly = butterfly;
}
-inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
-{
- return JSFinalObject::create(exec, structure);
-}
-
inline CallType getCallData(JSValue value, CallData& callData)
{
CallType result = value.isCell() ? value.asCell()->methodTable()->getCallData(value.asCell(), callData) : CallTypeNone;
@@ -1404,7 +1410,7 @@
return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
}
-// This is a helper for patching code where you want to emit a load or store and
+// Helpers for patching code where you want to emit a load or store and
// the base is:
// For inline offsets: a pointer to the out-of-line storage pointer.
// For out-of-line offsets: the base of the out-of-line storage.
@@ -1415,6 +1421,17 @@
return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
}
+// Returns the maximum offset a load instruction will encode.
+inline size_t maxOffsetRelativeToPatchedStorage(PropertyOffset offset)
+{
+#if USE(JSVALUE32_64)
+ return offsetRelativeToPatchedStorage(offset)
+ + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag);
+#else
+ return offsetRelativeToPatchedStorage(offset);
+#endif
+}
+
inline int indexRelativeToBase(PropertyOffset offset)
{
if (isOutOfLineOffset(offset))
diff --git a/Source/JavaScriptCore/runtime/JSProxy.cpp b/Source/JavaScriptCore/runtime/JSProxy.cpp
index 4ff9443..ea15353 100644
--- a/Source/JavaScriptCore/runtime/JSProxy.cpp
+++ b/Source/JavaScriptCore/runtime/JSProxy.cpp
@@ -52,7 +52,16 @@
ASSERT_ARG(globalObject, globalObject);
m_target.set(globalData, this, globalObject);
setPrototype(globalData, globalObject->prototype());
- globalData.prototypeMap.clearEmptyObjectStructureForPrototype(this);
+
+ PrototypeMap& prototypeMap = globalData.prototypeMap;
+ if (!prototypeMap.isPrototype(this))
+ return;
+
+ // This is slow but constant time. We think it's very rare for a proxy
+ // to be a prototype, and reasonably rare to retarget a proxy,
+ // so slow constant time is OK.
+ for (size_t i = 0; i <= JSFinalObject::maxInlineCapacity(); ++i)
+ prototypeMap.clearEmptyObjectStructureForPrototype(this, i);
}
String JSProxy::className(const JSObject* object)
diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp
index 3435fa1..3d18ba3 100644
--- a/Source/JavaScriptCore/runtime/LiteralParser.cpp
+++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp
@@ -32,6 +32,7 @@
#include "JSArray.h"
#include "JSString.h"
#include "Lexer.h"
+#include "ObjectConstructor.h"
#include "Operations.h"
#include "StrongInlines.h"
#include <wtf/ASCIICType.h>
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
index bafc95f..8bd1e50 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -102,19 +102,19 @@
return getStaticFunctionDescriptor<JSObject>(exec, ExecState::objectConstructorTable(exec), jsCast<ObjectConstructor*>(object), propertyName, descriptor);
}
-// ECMA 15.2.2
-static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
+static ALWAYS_INLINE JSObject* constructObject(ExecState* exec)
{
+ JSGlobalObject* globalObject = exec->callee()->globalObject();
+ ArgList args(exec);
JSValue arg = args.at(0);
if (arg.isUndefinedOrNull())
- return constructEmptyObject(exec, globalObject);
+ return constructEmptyObject(exec, globalObject->objectPrototype());
return arg.toObject(exec, globalObject);
}
static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec)
{
- ArgList args(exec);
- return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args));
+ return JSValue::encode(constructObject(exec));
}
ConstructType ObjectConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -125,8 +125,7 @@
static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec)
{
- ArgList args(exec);
- return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args));
+ return JSValue::encode(constructObject(exec));
}
CallType ObjectConstructor::getCallData(JSCell*, CallData& callData)
@@ -351,7 +350,7 @@
return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object prototype may only be an Object or null.")));
JSValue proto = exec->argument(0);
JSObject* newObject = proto.isObject()
- ? constructEmptyObject(exec, exec->globalData().prototypeMap.emptyObjectStructureForPrototype(asObject(proto)))
+ ? constructEmptyObject(exec, asObject(proto))
: constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
if (exec->argument(1).isUndefined())
return JSValue::encode(newObject);
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.h b/Source/JavaScriptCore/runtime/ObjectConstructor.h
index c891345..e8a6d14 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.h
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.h
@@ -22,6 +22,8 @@
#define ObjectConstructor_h
#include "InternalFunction.h"
+#include "JSGlobalObject.h"
+#include "ObjectPrototype.h"
namespace JSC {
@@ -58,6 +60,30 @@
static CallType getCallData(JSCell*, CallData&);
};
+ inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
+ {
+ return JSFinalObject::create(exec, structure);
+ }
+
+ inline JSObject* constructEmptyObject(ExecState* exec, JSObject* prototype, unsigned inlineCapacity)
+ {
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ PrototypeMap& prototypeMap = globalObject->globalData().prototypeMap;
+ Structure* structure = prototypeMap.emptyObjectStructureForPrototype(
+ prototype, inlineCapacity);
+ return constructEmptyObject(exec, structure);
+ }
+
+ inline JSObject* constructEmptyObject(ExecState* exec, JSObject* prototype)
+ {
+ return constructEmptyObject(exec, prototype, JSFinalObject::defaultInlineCapacity());
+ }
+
+ inline JSObject* constructEmptyObject(ExecState* exec)
+ {
+ return constructEmptyObject(exec, exec->lexicalGlobalObject()->objectPrototype());
+ }
+
} // namespace JSC
#endif // ObjectConstructor_h
diff --git a/Source/JavaScriptCore/runtime/PropertyOffset.h b/Source/JavaScriptCore/runtime/PropertyOffset.h
index e5486ed..c622004 100644
--- a/Source/JavaScriptCore/runtime/PropertyOffset.h
+++ b/Source/JavaScriptCore/runtime/PropertyOffset.h
@@ -32,12 +32,6 @@
namespace JSC {
-#if USE(JSVALUE32_64)
-#define INLINE_STORAGE_CAPACITY 7
-#else
-#define INLINE_STORAGE_CAPACITY 6
-#endif
-
typedef int PropertyOffset;
static const PropertyOffset invalidOffset = -1;
diff --git a/Source/JavaScriptCore/runtime/PrototypeMap.cpp b/Source/JavaScriptCore/runtime/PrototypeMap.cpp
index 734636c..ecb3f76 100644
--- a/Source/JavaScriptCore/runtime/PrototypeMap.cpp
+++ b/Source/JavaScriptCore/runtime/PrototypeMap.cpp
@@ -52,18 +52,24 @@
// used as a prototype.
}
-Structure* PrototypeMap::emptyObjectStructureForPrototype(JSObject* object)
+Structure* PrototypeMap::emptyObjectStructureForPrototype(JSObject* prototype, unsigned inlineCapacity)
{
- WeakGCMap<JSObject*, Structure>::AddResult addResult = m_structures.add(object, nullptr);
+ StructureMap::AddResult addResult = m_structures.add(std::make_pair(prototype, inlineCapacity), nullptr);
if (!addResult.isNewEntry) {
- ASSERT(isPrototype(object));
+ ASSERT(isPrototype(prototype));
return addResult.iterator->value.get();
}
- addPrototype(object);
- Structure* structure = JSFinalObject::createStructure(object->globalObject()->globalData(), object->globalObject(), object);
+ addPrototype(prototype);
+ Structure* structure = JSFinalObject::createStructure(
+ prototype->globalObject()->globalData(), prototype->globalObject(), prototype, inlineCapacity);
addResult.iterator->value = structure;
return structure;
}
+void PrototypeMap::clearEmptyObjectStructureForPrototype(JSObject* object, unsigned inlineCapacity)
+{
+ m_structures.remove(std::make_pair(object, inlineCapacity));
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/PrototypeMap.h b/Source/JavaScriptCore/runtime/PrototypeMap.h
index 3c7fbeb..6bfcced 100644
--- a/Source/JavaScriptCore/runtime/PrototypeMap.h
+++ b/Source/JavaScriptCore/runtime/PrototypeMap.h
@@ -33,16 +33,18 @@
class JSObject;
class Structure;
+// Tracks the canonical structure an object should be allocated with when inheriting from a given prototype.
class PrototypeMap {
public:
- JS_EXPORT_PRIVATE Structure* emptyObjectStructureForPrototype(JSObject*);
- void clearEmptyObjectStructureForPrototype(JSObject*);
+ JS_EXPORT_PRIVATE Structure* emptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity);
+ void clearEmptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity);
void addPrototype(JSObject*);
bool isPrototype(JSObject*); // Returns a conservative estimate.
private:
WeakGCMap<JSObject*, JSObject> m_prototypes;
- WeakGCMap<JSObject*, Structure> m_structures;
+ typedef WeakGCMap<std::pair<JSObject*, unsigned>, Structure> StructureMap;
+ StructureMap m_structures;
};
inline bool PrototypeMap::isPrototype(JSObject* object)
@@ -50,11 +52,6 @@
return m_prototypes.contains(object);
}
-inline void PrototypeMap::clearEmptyObjectStructureForPrototype(JSObject* object)
-{
- m_structures.remove(object);
-}
-
} // namespace JSC
#endif // PrototypeMap_h
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index e3a8c7d..47c2ed1 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -149,7 +149,7 @@
#endif
}
-Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity)
+Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
: JSCell(globalData, globalData.structureStructure.get())
, m_typeInfo(typeInfo)
, m_indexingType(indexingType)
@@ -171,6 +171,8 @@
, m_didTransition(false)
, m_staticFunctionReified(false)
{
+ ASSERT(inlineCapacity <= JSFinalObject::maxInlineCapacity());
+ ASSERT(inlineCapacity < firstOutOfLineOffset);
}
const ClassInfo Structure::s_info = { "Structure", 0, 0, 0, CREATE_METHOD_TABLE(Structure) };
@@ -245,7 +247,7 @@
ASSERT(structure->m_propertyTable);
ASSERT(!structure->m_previous);
- m_propertyTable = structure->m_propertyTable->copy(globalData, 0, numberOfSlotsForLastOffset(m_offset, m_typeInfo.type()));
+ m_propertyTable = structure->m_propertyTable->copy(globalData, 0, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
break;
}
@@ -253,7 +255,7 @@
}
if (!m_propertyTable)
- createPropertyMap(numberOfSlotsForLastOffset(m_offset, m_typeInfo.type()));
+ createPropertyMap(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
structure = structures[i];
@@ -393,6 +395,7 @@
transition->growOutOfLineCapacity();
transition->m_offset = offset;
+ checkOffset(transition->m_offset, transition->inlineCapacity());
structure->m_transitionTable.add(globalData, transition);
return transition;
}
@@ -564,6 +567,7 @@
transition->m_attributesInPrevious = attributes;
transition->m_indexingType = indexingType;
transition->m_offset = structure->m_offset;
+ checkOffset(transition->m_offset, transition->inlineCapacity());
if (structure->m_propertyTable) {
if (structure->m_isPinnedPropertyTable)
@@ -719,7 +723,7 @@
PassOwnPtr<PropertyTable> Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
{
- return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(numberOfSlotsForLastOffset(m_offset, m_typeInfo.type())));
+ return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)));
}
PropertyOffset Structure::get(JSGlobalData& globalData, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue)
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 8b2fb7b..e173087 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -69,7 +69,7 @@
typedef JSCell Base;
- static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, PropertyOffset inlineCapacity = 0);
+ static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
protected:
void finishCreation(JSGlobalData& globalData)
@@ -221,7 +221,7 @@
{
if (m_propertyTable)
return m_propertyTable->propertyStorageSize();
- return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type());
+ return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
}
unsigned totalStorageCapacity() const
{
@@ -359,7 +359,7 @@
private:
friend class LLIntOffsetsExtractor;
- JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, PropertyOffset inlineCapacity);
+ JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
Structure(JSGlobalData&);
Structure(JSGlobalData&, const Structure*);
@@ -400,7 +400,7 @@
int transitionCount() const
{
// Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
- return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type());
+ return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
}
bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
@@ -454,7 +454,7 @@
unsigned m_staticFunctionReified;
};
- inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity)
+ inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
{
ASSERT(globalData.structureStructure);
ASSERT(classInfo);
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index d99be4f..3f5d3c3 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,19 @@
+2013-01-28 Geoffrey Garen <ggaren@apple.com>
+
+ Static size inference for JavaScript objects
+ https://bugs.webkit.org/show_bug.cgi?id=108093
+
+ Reviewed by Phil Pizlo.
+
+ * 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.
+
2013-01-28 Alec Flett <alecflett@chromium.org>
IndexedDB: Pass metadata in to IDBOpenDBRequest.onUpgradeNeeded/onSuccess
diff --git a/Source/WebCore/ForwardingHeaders/runtime/ObjectConstructor.h b/Source/WebCore/ForwardingHeaders/runtime/ObjectConstructor.h
new file mode 100644
index 0000000..8fcb717
--- /dev/null
+++ b/Source/WebCore/ForwardingHeaders/runtime/ObjectConstructor.h
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_ObjectConstructor_h
+#define WebCore_FWD_ObjectConstructor_h
+#include <JavaScriptCore/ObjectConstructor.h>
+#endif
diff --git a/Source/WebCore/bindings/js/IDBBindingUtilities.cpp b/Source/WebCore/bindings/js/IDBBindingUtilities.cpp
index 232b8b2..af13a5a 100644
--- a/Source/WebCore/bindings/js/IDBBindingUtilities.cpp
+++ b/Source/WebCore/bindings/js/IDBBindingUtilities.cpp
@@ -35,6 +35,7 @@
#include "IDBTracing.h"
#include <runtime/DateInstance.h>
+#include <runtime/ObjectConstructor.h>
using namespace JSC;
diff --git a/Source/WebCore/bindings/js/JSDeviceMotionEventCustom.cpp b/Source/WebCore/bindings/js/JSDeviceMotionEventCustom.cpp
index 193a6c4..6112767 100644
--- a/Source/WebCore/bindings/js/JSDeviceMotionEventCustom.cpp
+++ b/Source/WebCore/bindings/js/JSDeviceMotionEventCustom.cpp
@@ -31,6 +31,7 @@
#include "DeviceMotionData.h"
#include "DeviceMotionEvent.h"
+#include <runtime/ObjectConstructor.h>
using namespace JSC;
diff --git a/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp b/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp
index 9aef576..089a82f 100644
--- a/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp
+++ b/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp
@@ -67,6 +67,7 @@
#include <runtime/JSArray.h>
#include <runtime/JSFunction.h>
#include <runtime/JSLock.h>
+#include <runtime/ObjectConstructor.h>
#include <runtime/RegExpObject.h>
using namespace JSC;
diff --git a/Source/WebCore/bindings/js/JSSQLResultSetRowListCustom.cpp b/Source/WebCore/bindings/js/JSSQLResultSetRowListCustom.cpp
index 0d09375..f154521 100644
--- a/Source/WebCore/bindings/js/JSSQLResultSetRowListCustom.cpp
+++ b/Source/WebCore/bindings/js/JSSQLResultSetRowListCustom.cpp
@@ -35,6 +35,7 @@
#include "ExceptionCode.h"
#include "SQLValue.h"
#include "SQLResultSetRowList.h"
+#include <runtime/ObjectConstructor.h>
using namespace JSC;
diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.cpp b/Source/WebCore/bindings/js/SerializedScriptValue.cpp
index 02ba199..079da58 100644
--- a/Source/WebCore/bindings/js/SerializedScriptValue.cpp
+++ b/Source/WebCore/bindings/js/SerializedScriptValue.cpp
@@ -60,6 +60,7 @@
#include <runtime/DateInstance.h>
#include <runtime/Error.h>
#include <runtime/ExceptionHelpers.h>
+#include <runtime/ObjectConstructor.h>
#include <runtime/Operations.h>
#include <runtime/PropertyNameArray.h>
#include <runtime/RegExp.h>
@@ -1674,7 +1675,7 @@
case ObjectStartState: {
if (outputObjectStack.size() > maximumFilterRecursion)
return make_pair(JSValue(), StackOverflowError);
- JSObject* outObject = constructEmptyObject(m_exec, m_globalObject);
+ JSObject* outObject = constructEmptyObject(m_exec, m_globalObject->objectPrototype());
m_gcBuffer.append(outObject);
outputObjectStack.append(outObject);
// fallthrough