2008-09-02 Geoffrey Garen <ggaren@apple.com>
Reviewed by Sam Weinig.
Implemented the rest of Darin's review comments for the 09-01 inline
caching patch.
SunSpider says 0.5% faster, but that seems like noise.
* JavaScriptCore.xcodeproj/project.pbxproj: Put PutPropertySlot into
its own file, and added BatchedTransitionOptimizer.
* VM/CodeBlock.cpp:
(KJS::CodeBlock::~CodeBlock): Use array indexing instead of a pointer
iterator.
* VM/CodeGenerator.cpp:
(KJS::CodeGenerator::CodeGenerator): Used BatchedTransitionOptimizer to
make batched put and remove for declared variables fast, without forever
pessimizing the global object. Removed the old getDirect/removeDirect hack
that tried to do the same in a more limited way.
* VM/CodeGenerator.h: Moved IdentifierRepHash to the KJS namespace since
it doesn't specialize anything in WTF.
* VM/Machine.cpp:
(KJS::Machine::Machine): Nixed the DummyConstruct tag because it was
confusingly named.
(KJS::Machine::execute): Used BatchedTransitionOptimizer, as above. Fixed
up some comments.
(KJS::cachePrototypeChain): Cast to JSObject*, since it's more specific.
(KJS::Machine::tryCachePutByID): Use isNull() instead of comparing to
jsNull(), since isNull() leaves more options open for the future.
(KJS::Machine::tryCacheGetByID): ditto
(KJS::Machine::privateExecute): ditto
* VM/SamplingTool.cpp:
(KJS::SamplingTool::dump): Use C++-style cast, to match our style
guidelines.
* kjs/BatchedTransitionOptimizer.h: Added. New class that allows host
code to add a batch of properties to an object in an efficient way.
* kjs/JSActivation.cpp: Use isNull(), as above.
* kjs/JSArray.cpp: Get rid of DummyConstruct tag, as above.
* kjs/JSArray.h:
* kjs/JSGlobalData.cpp: Nixed two unused StructureIDs.
* kjs/JSGlobalData.h:
* kjs/JSImmediate.cpp: Use isNull(), as above.
* kjs/JSObject.cpp:
(KJS::JSObject::mark): Moved mark tracing code elsewhere, to make this
function more readable.
(KJS::JSObject::put): Use isNull(), as above.
(KJS::JSObject::createInheritorID): Return a raw pointer, since the
object is owned by a data member, not necessarily the caller.
* kjs/JSObject.h:
* kjs/JSString.cpp: Use isNull(), as above.
* kjs/PropertyMap.h: Updated to use PropertySlot::invalidOffset.
* kjs/PropertySlot.h: Changed KJS_INVALID_OFFSET to WTF::notFound
because C macros are so 80's.
* kjs/PutPropertySlot.h: Added. Split out of PropertySlot.h. Also renamed
PutPropertySlot::SlotType to PutPropertySlot::Type, and slotBase to base,
since "slot" was redundant.
* kjs/StructureID.cpp: Added a new transition *away* from dictionary
status, to support BatchedTransitionOptimizer.
(KJS::StructureIDChain::StructureIDChain): No need to store m_size as
a data member, so keep it in a local, which might be faster.
* kjs/StructureID.h:
* kjs/SymbolTable.h: Moved IdentifierRepHash to KJS namespace, as above.
* kjs/ustring.h:
JavaScriptGlue:
2008-09-02 Geoffrey Garen <ggaren@apple.com>
Reviewed by Sam Weinig.
Implemented the rest of Darin's review comments for the 09-01 inline
caching patch.
* ForwardingHeaders/kjs/PutPropertySlot.h: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@36032
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2008-09-02 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Implemented the rest of Darin's review comments for the 09-01 inline
+ caching patch.
+
+ SunSpider says 0.5% faster, but that seems like noise.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj: Put PutPropertySlot into
+ its own file, and added BatchedTransitionOptimizer.
+
+ * VM/CodeBlock.cpp:
+ (KJS::CodeBlock::~CodeBlock): Use array indexing instead of a pointer
+ iterator.
+
+ * VM/CodeGenerator.cpp:
+ (KJS::CodeGenerator::CodeGenerator): Used BatchedTransitionOptimizer to
+ make batched put and remove for declared variables fast, without forever
+ pessimizing the global object. Removed the old getDirect/removeDirect hack
+ that tried to do the same in a more limited way.
+
+ * VM/CodeGenerator.h: Moved IdentifierRepHash to the KJS namespace since
+ it doesn't specialize anything in WTF.
+
+ * VM/Machine.cpp:
+ (KJS::Machine::Machine): Nixed the DummyConstruct tag because it was
+ confusingly named.
+
+ (KJS::Machine::execute): Used BatchedTransitionOptimizer, as above. Fixed
+ up some comments.
+
+ (KJS::cachePrototypeChain): Cast to JSObject*, since it's more specific.
+
+ (KJS::Machine::tryCachePutByID): Use isNull() instead of comparing to
+ jsNull(), since isNull() leaves more options open for the future.
+ (KJS::Machine::tryCacheGetByID): ditto
+ (KJS::Machine::privateExecute): ditto
+
+ * VM/SamplingTool.cpp:
+ (KJS::SamplingTool::dump): Use C++-style cast, to match our style
+ guidelines.
+
+ * kjs/BatchedTransitionOptimizer.h: Added. New class that allows host
+ code to add a batch of properties to an object in an efficient way.
+
+ * kjs/JSActivation.cpp: Use isNull(), as above.
+
+ * kjs/JSArray.cpp: Get rid of DummyConstruct tag, as above.
+ * kjs/JSArray.h:
+
+ * kjs/JSGlobalData.cpp: Nixed two unused StructureIDs.
+ * kjs/JSGlobalData.h:
+
+ * kjs/JSImmediate.cpp: Use isNull(), as above.
+
+ * kjs/JSObject.cpp:
+ (KJS::JSObject::mark): Moved mark tracing code elsewhere, to make this
+ function more readable.
+
+ (KJS::JSObject::put): Use isNull(), as above.
+
+ (KJS::JSObject::createInheritorID): Return a raw pointer, since the
+ object is owned by a data member, not necessarily the caller.
+ * kjs/JSObject.h:
+
+ * kjs/JSString.cpp: Use isNull(), as above.
+
+ * kjs/PropertyMap.h: Updated to use PropertySlot::invalidOffset.
+
+ * kjs/PropertySlot.h: Changed KJS_INVALID_OFFSET to WTF::notFound
+ because C macros are so 80's.
+
+ * kjs/PutPropertySlot.h: Added. Split out of PropertySlot.h. Also renamed
+ PutPropertySlot::SlotType to PutPropertySlot::Type, and slotBase to base,
+ since "slot" was redundant.
+
+ * kjs/StructureID.cpp: Added a new transition *away* from dictionary
+ status, to support BatchedTransitionOptimizer.
+
+ (KJS::StructureIDChain::StructureIDChain): No need to store m_size as
+ a data member, so keep it in a local, which might be faster.
+ * kjs/StructureID.h:
+
+ * kjs/SymbolTable.h: Moved IdentifierRepHash to KJS namespace, as above.
+ * kjs/ustring.h:
+
2008-09-02 Adam Roben <aroben@apple.com>
Windows build fixes
__ZN3KJS11PropertyMap3putERKNS_10IdentifierEPNS_7JSValueEjbPNS_8JSObjectERNS_15PutPropertySlotE
__ZN3KJS11PropertyMapD1Ev
__ZN3KJS11StructureID21addPropertyTransitionEPS0_RKNS_10IdentifierE
+__ZN3KJS11StructureID24fromDictionaryTransitionEPS0_
__ZN3KJS11StructureID25changePrototypeTransitionEPS0_PNS_7JSValueE
__ZN3KJS11StructureIDD1Ev
__ZN3KJS12DateInstance4infoE
1440F8AF0A508D200005F061 /* JSCallbackConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1440F8AD0A508D200005F061 /* JSCallbackConstructor.cpp */; };
1440FCE40A51E46B0005F061 /* JSClassRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1440FCE20A51E46B0005F061 /* JSClassRef.cpp */; };
146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 146AAB370B66A94400E55F16 /* JSStringRefCF.cpp */; };
+ 147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */; };
+ 147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B84620E6DE6B1004775A4 /* PutPropertySlot.h */; settings = {ATTRIBUTES = (Private, ); }; };
1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B74C0A43032800517CFC /* JSStringRef.cpp */; };
1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B7E20A43076000517CFC /* JSObjectRef.cpp */; };
14909A2D0DCAF6CD00B29EB3 /* ExecState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD53F40A3E12D800BAF59C /* ExecState.cpp */; };
146AAB2A0B66A84900E55F16 /* JSStringRefCF.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSStringRefCF.h; sourceTree = "<group>"; };
146AAB370B66A94400E55F16 /* JSStringRefCF.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringRefCF.cpp; sourceTree = "<group>"; };
14760863099C633800437128 /* JSImmediate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSImmediate.cpp; sourceTree = "<group>"; };
+ 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BatchedTransitionOptimizer.h; sourceTree = "<group>"; };
+ 147B84620E6DE6B1004775A4 /* PutPropertySlot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutPropertySlot.h; sourceTree = "<group>"; };
1480DB9B0DDC227F003CFDF2 /* DebuggerCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DebuggerCallFrame.h; path = kjs/DebuggerCallFrame.h; sourceTree = "<group>"; };
1482B6EA0A4300B300517CFC /* JSValueRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueRef.h; sourceTree = "<group>"; };
1482B74B0A43032800517CFC /* JSStringRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringRef.h; sourceTree = "<group>"; };
5D53726E0E1C54880021E549 /* Tracing.h */,
F692A8850255597D01FF60F7 /* ustring.cpp */,
F692A8860255597D01FF60F7 /* ustring.h */,
+ 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */,
+ 147B84620E6DE6B1004775A4 /* PutPropertySlot.h */,
);
path = kjs;
sourceTree = "<group>";
9534AAFB0E5B7A9600B8A45B /* JSProfilerPrivate.h in Headers */,
933040040E6A749400786E6A /* SmallStrings.h in Headers */,
BCDE3AB80E6C82F5001453A7 /* StructureID.h in Headers */,
+ 147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */,
+ 147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
CodeBlock::~CodeBlock()
{
- Vector<size_t>::const_iterator end = structureIDInstructions.end();
- for (Vector<size_t>::const_iterator it = structureIDInstructions.begin(); it != end; ++it)
- derefStructureIDs(&instructions[*it]);
+ size_t size = structureIDInstructions.size();
+ for (size_t i = 0; i < size; ++i)
+ derefStructureIDs(&instructions[structureIDInstructions[i]]);
}
void CodeBlock::derefStructureIDs(Instruction* vPC) const
#include "config.h"
#include "CodeGenerator.h"
+#include "BatchedTransitionOptimizer.h"
#include "JSFunction.h"
#include "Machine.h"
#include "ustring.h"
SymbolTable::iterator end = symbolTable->end();
for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex() + m_globalVarStorageOffset);
+
+ BatchedTransitionOptimizer optimizer(globalObject);
bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();
if (canOptimizeNewGlobals) {
for (size_t i = 0; i < functionStack.size(); ++i) {
FuncDeclNode* funcDecl = functionStack[i].get();
- if (globalObject->getDirect(funcDecl->m_ident))
- globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
+ globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);
}
static const bool needsRef = false;
};
- typedef HashMap<RefPtr<UString::Rep>, int, WTF::IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, IdentifierMapIndexHashTraits> IdentifierMap;
+ typedef HashMap<RefPtr<UString::Rep>, int, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, IdentifierMapIndexHashTraits> IdentifierMap;
RegisterID* emitCall(OpcodeID, RegisterID*, RegisterID*, RegisterID*, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
ScopeNode* m_scopeNode;
CodeBlock* m_codeBlock;
- HashSet<RefPtr<UString::Rep>, WTF::IdentifierRepHash> m_functions;
+ HashSet<RefPtr<UString::Rep>, IdentifierRepHash> m_functions;
RegisterID m_thisRegister;
SegmentedVector<RegisterID, 512> m_locals;
SegmentedVector<RegisterID, 512> m_constants;
#include "config.h"
#include "Machine.h"
+#include "BatchedTransitionOptimizer.h"
#include "CodeBlock.h"
#include "DebuggerCallFrame.h"
#include "ExceptionHelpers.h"
// Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
void* storage = fastMalloc(sizeof(CollectorBlock));
- JSArray* jsArray = new (storage) JSArray(JSArray::DummyConstruct);
+ JSArray* jsArray = new (storage) JSArray(StructureID::create(jsNull()));
m_jsArrayVptr = jsArray->vptr();
static_cast<JSCell*>(jsArray)->~JSCell();
}
}
- const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
- Node::VarStack::const_iterator varStackEnd = varStack.end();
- for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
- const Identifier& ident = (*it).first;
- if (!variableObject->hasProperty(exec, ident)) {
+ { // Scope for BatchedTransitionOptimizer
+
+ BatchedTransitionOptimizer optimizer(variableObject);
+
+ const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
+ Node::VarStack::const_iterator varStackEnd = varStack.end();
+ for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
+ const Identifier& ident = (*it).first;
+ if (!variableObject->hasProperty(exec, ident)) {
+ PutPropertySlot slot;
+ variableObject->put(exec, ident, jsUndefined(), slot);
+ }
+ }
+
+ const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
+ Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
+ for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
PutPropertySlot slot;
- variableObject->put(exec, ident, jsUndefined(), slot);
+ variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
}
- }
- const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
- Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
- for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
- PutPropertySlot slot;
- variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
}
size_t oldSize = m_registerFile.size();
StructureIDChain* cachePrototypeChain(StructureID* structureID)
{
- RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSCell*>(structureID->prototype())->structureID());
+ RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(structureID->prototype())->structureID());
structureID->setCachedPrototypeChain(chain.release());
return structureID->cachedPrototypeChain();
}
// Cache hit: Specialize instruction and ref StructureIDs.
- // If baseCell != slotBase, then baseCell must be a proxy for another object.
- if (baseCell != slot.slotBase()) {
+ // If baseCell != slot.base(), then baseCell must be a proxy for another object.
+ if (baseCell != slot.base()) {
vPC[0] = getOpcode(op_put_by_id_generic);
return;
}
baseCell = static_cast<JSCell*>(baseCell->structureID()->prototype());
// If we didn't find slotBase in baseCell's prototype chain, then baseCell
// must be a proxy for another object.
- if (baseCell == jsNull()) {
+ if (baseCell->isNull()) {
vPC[0] = getOpcode(op_get_by_id_generic);
return;
}
/* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
Cached property access: Attempts to get a cached property from the
- value base's prototype chain. If the cache misses, op_get_by_id_proto
+ value base's prototype chain. If the cache misses, op_get_by_id_chain
reverts to op_get_by_id.
*/
int base = vPC[2].u.operand;
RefPtr<StructureID>* end = it + count;
while (1) {
- baseCell = static_cast<JSCell*>(baseCell->structureID()->prototype());
- if (UNLIKELY(baseCell->structureID() != (*it).get()))
+ ASSERT(baseCell->isObject());
+ JSObject* baseObject = static_cast<JSObject*>(baseCell->structureID()->prototype());
+ if (UNLIKELY(baseObject->structureID() != (*it).get()))
break;
if (++it == end) {
- ASSERT(baseCell->isObject());
- JSObject* baseObject = static_cast<JSObject*>(baseCell);
int dst = vPC[1].u.operand;
int offset = vPC[7].u.operand;
BEGIN_OPCODE(op_put_by_id) {
/* put_by_id base(r) property(id) value(r) nop(n) nop(n)
- Sets register value on register base as the property named
- by identifier property. Base is converted to object first.
+ Generic property access: Sets the property named by identifier
+ property, belonging to register base, to register value.
Unlike many opcodes, this one does not write any output to
the register file.
BEGIN_OPCODE(op_put_by_id_replace) {
/* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n)
- Sets register value on register base as the property named
- by identifier property. Base is converted to object first.
+ Cached property access: Attempts to set a pre-existing, cached
+ property named by identifier property, belonging to register base,
+ to register value. If the cache misses, op_put_by_id_replace
+ reverts to op_put_by_id.
Unlike many opcodes, this one does not write any output to
the register file.
BEGIN_OPCODE(op_put_by_id_generic) {
/* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n)
- Sets register value on register base as the property named
- by identifier property. Base is converted to object first.
+ Generic property access: Sets the property named by identifier
+ property, belonging to register base, to register value.
Unlike many opcodes, this one does not write any output to
the register file.
printf("Opcodes in order:\n\n");
for (int i = 0; i < numOpcodeIDs; ++i) {
long long count = opcodeSampleCounts[i];
- printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[i], padOpcodeName((OpcodeID)i, 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);
+ printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[i], padOpcodeName(static_cast<OpcodeID>(i), 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);
}
printf("\n");
printf("Opcodes by sample count:\n\n");
--- /dev/null
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2008 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 COMPUTER, 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 COMPUTER, 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 BatchedTransitionOptimizer_h
+#define BatchedTransitionOptimizer_h
+
+#include <wtf/Noncopyable.h>
+#include "JSObject.h"
+
+namespace KJS {
+
+ class BatchedTransitionOptimizer : Noncopyable {
+ public:
+ BatchedTransitionOptimizer(JSObject* object)
+ : m_object(object)
+ {
+ if (!m_object->structureID()->isDictionary())
+ m_object->setStructureID(StructureID::toDictionaryTransition(m_object->structureID()));
+ }
+
+ ~BatchedTransitionOptimizer()
+ {
+ m_object->setStructureID(StructureID::fromDictionaryTransition(m_object->structureID()));
+ }
+
+ private:
+ JSObject* m_object;
+ };
+
+} // namespace KJS
+
+#endif // BatchedTransitionOptimizer_h
// We don't call through to JSObject because there's no way to give an
// activation object getter properties or a prototype.
ASSERT(!hasGetterSetterProperties());
- ASSERT(prototype() == jsNull());
+ ASSERT(prototype()->isNull());
return false;
}
#endif
-JSArray::JSArray(DummyConstructTag)
- : JSObject(StructureID::create(jsNull()))
+JSArray::JSArray(PassRefPtr<StructureID> structureID)
+ : JSObject(structureID)
{
unsigned initialCapacity = 0;
class JSArray : public JSObject {
public:
- enum DummyConstructTag { DummyConstruct };
- JSArray(DummyConstructTag);
+ JSArray(PassRefPtr<StructureID>);
JSArray(JSObject* prototype, unsigned initialLength);
JSArray(ExecState* exec, JSObject* prototype, const ArgList& initialValues);
virtual ~JSArray();
, regExpConstructorTable(&KJS::regExpConstructorTable)
, stringTable(&KJS::stringTable)
#endif
- , stringStructureID(StructureID::create(jsNull()))
- , numberStructureID(StructureID::create(jsNull()))
, nullProtoStructureID(StructureID::create(jsNull()))
, identifierTable(createIdentifierTable())
, propertyNames(new CommonIdentifiers(this))
const HashTable* regExpConstructorTable;
const HashTable* stringTable;
- RefPtr<StructureID> stringStructureID;
- RefPtr<StructureID> numberStructureID;
RefPtr<StructureID> nullProtoStructureID;
IdentifierTable* identifierTable;
if (isBoolean(v))
return constructBooleanFromImmediateBoolean(exec, const_cast<JSValue*>(v));
- JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v == jsNull());
+ JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v->isNull());
exec->setException(exception);
return new (exec) JSNotAnObject(exec, exception);
}
if (isBoolean(v))
return exec->lexicalGlobalObject()->booleanPrototype();
- JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v == jsNull());
+ JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v->isNull());
exec->setException(exception);
return new (exec) JSNotAnObject(exec, exception);
}
return "false";
if (v == jsBoolean(true))
return "true";
- if (v == jsNull())
+ if (v->isNull())
return "null";
ASSERT(v == jsUndefined());
return "undefined";
#include <profiler/Profiler.h>
#include <wtf/Assertions.h>
-#define JAVASCRIPT_MARK_TRACING 0
+#define JSOBJECT_MARK_TRACING 0
+
+#if JSOBJECT_MARK_TRACING
+
+#define JSOBJECT_MARK_BEGIN() \
+ static int markStackDepth = 0; \
+ for (int i = 0; i < markStackDepth; i++) \
+ putchar('-'); \
+ printf("%s (%p)\n", className().UTF8String().c_str(), this); \
+ markStackDepth++; \
+
+#define JSOBJECT_MARK_END() \
+ markStackDepth--;
+
+#else // JSOBJECT_MARK_TRACING
+
+#define JSOBJECT_MARK_BEGIN()
+#define JSOBJECT_MARK_END()
+
+#endif // JSOBJECT_MARK_TRACING
namespace KJS {
void JSObject::mark()
{
- JSCell::mark();
-
-#if JAVASCRIPT_MARK_TRACING
- static int markStackDepth = 0;
- markStackDepth++;
- for (int i = 0; i < markStackDepth; i++)
- putchar('-');
- printf("%s (%p)\n", className().UTF8String().c_str(), this);
-#endif
+ JSOBJECT_MARK_BEGIN();
+ JSCell::mark();
m_structureID->mark();
m_propertyMap.mark();
-#if JAVASCRIPT_MARK_TRACING
- markStackDepth--;
-#endif
+ JSOBJECT_MARK_END();
}
UString JSObject::className() const
JSObject* proto = value->getObject();
// Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
- if (!proto && value != jsNull())
+ if (!proto && !value->isNull())
return;
while (proto) {
JSValue* prototype;
for (JSObject* obj = this; !obj->m_propertyMap.hasGetterSetterProperties(); obj = static_cast<JSObject*>(prototype)) {
prototype = obj->prototype();
- if (prototype == jsNull()) {
+ if (prototype->isNull()) {
putDirect(propertyName, value, 0, true, slot);
return;
}
}
prototype = obj->prototype();
- if (prototype == jsNull())
+ if (prototype->isNull())
break;
}
{
m_propertyMap.remove(propertyName);
if (!m_structureID->isDictionary()) {
- RefPtr<StructureID> structureID = StructureID::dictionaryTransition(m_structureID);
+ RefPtr<StructureID> structureID = StructureID::toDictionaryTransition(m_structureID);
setStructureID(structureID.release());
}
}
slot.setUndefined();
}
-PassRefPtr<StructureID> JSObject::createInheritorID()
+StructureID* JSObject::createInheritorID()
{
m_inheritorID = StructureID::create(this);
- return m_inheritorID;
+ return m_inheritorID.get();
}
bool JSObject::isObject() const
#include "JSNumberCell.h"
#include "PropertyMap.h"
#include "PropertySlot.h"
+#include "PutPropertySlot.h"
#include "ScopeChain.h"
#include "StructureID.h"
};
class JSObject : public JSCell {
+ friend class BatchedTransitionOptimizer;
+
public:
JSObject(PassRefPtr<StructureID>);
JSObject(JSObject* prototype);
JSValue* prototype() const;
void setPrototype(JSValue* prototype);
- PassRefPtr<StructureID> inheritorID();
+ StructureID* inheritorID();
virtual UString className() const;
const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
void setStructureID(PassRefPtr<StructureID>);
- PassRefPtr<StructureID> createInheritorID();
+ StructureID* createInheritorID();
PropertyMap m_propertyMap;
RefPtr<StructureID> m_inheritorID;
JSObject* constructEmptyObject(ExecState*);
inline JSObject::JSObject(JSObject* prototype)
- : JSCell(prototype->inheritorID().releaseRef()) // ~JSObject balances this ref()
+ : JSCell(prototype->inheritorID())
{
ASSERT(m_structureID);
ASSERT(this->prototype());
- ASSERT(this->prototype() == jsNull() || Heap::heap(this) == Heap::heap(this->prototype()));
+ ASSERT(this->prototype()->isNull() || Heap::heap(this) == Heap::heap(this->prototype()));
+ m_structureID->ref(); // ~JSObject balances this ref()
}
inline JSObject::JSObject(PassRefPtr<StructureID> structureID)
m_structureID = structureID.releaseRef(); // ~JSObject balances this ref()
}
-inline PassRefPtr<StructureID> JSObject::inheritorID()
+inline StructureID* JSObject::inheritorID()
{
if (m_inheritorID)
return m_inheritorID.get();
return true;
slot.setBase(this);
JSObject* object;
- for (JSValue* prototype = exec->lexicalGlobalObject()->stringPrototype(); prototype != jsNull(); prototype = object->prototype()) {
+ for (JSValue* prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype->isNull(); prototype = object->prototype()) {
ASSERT(prototype->isObject());
object = static_cast<JSObject*>(prototype);
if (object->getOwnPropertySlot(exec, propertyName, slot))
m_u.singleEntryValue = value;
m_singleEntryAttributes = static_cast<short>(attributes);
checkConsistency();
- slot.setNewProperty(slotBase, KJS_INVALID_OFFSET);
+ slot.setNewProperty(slotBase, WTF::notFound);
return;
}
if (rep == m_singleEntryKey && !(checkReadOnly && (m_singleEntryAttributes & ReadOnly))) {
#include "PropertySlot.h"
#include "identifier.h"
+#include <wtf/NotFound.h>
namespace KJS {
reinterpret_cast<JSValue**>(m_u.table->entryIndicies)[offset] = v;
}
- size_t offsetForLocation(JSValue** location) { return m_usingTable ? offsetForTableLocation(location) : KJS_INVALID_OFFSET; }
+ size_t offsetForLocation(JSValue** location) { return m_usingTable ? offsetForTableLocation(location) : WTF::notFound; }
void mark() const;
void getEnumerablePropertyNames(PropertyNameArray&) const;
#include "JSValue.h"
#include "identifier.h"
#include <wtf/Assertions.h>
+#include <wtf/NotFound.h>
namespace KJS {
#define KJS_VALUE_SLOT_MARKER 0
#define KJS_REGISTER_SLOT_MARKER reinterpret_cast<GetValueFunc>(1)
-#define KJS_INVALID_OFFSET static_cast<size_t>(-1)
class PropertySlot {
public:
PropertySlot()
- : m_offset(KJS_INVALID_OFFSET)
+ : m_offset(WTF::notFound)
{
clearBase();
clearValue();
explicit PropertySlot(JSValue* base)
: m_slotBase(base)
- , m_offset(KJS_INVALID_OFFSET)
+ , m_offset(WTF::notFound)
{
clearValue();
}
return m_getValue(exec, Identifier::from(exec, propertyName), *this);
}
- bool isCacheable() const { return m_offset != KJS_INVALID_OFFSET; }
+ bool isCacheable() const { return m_offset != WTF::notFound; }
size_t cachedOffset() const
{
ASSERT(isCacheable());
size_t m_offset;
};
-
- class PutPropertySlot {
- public:
- enum SlotType {
- Invalid,
- ExistingProperty,
- NewProperty,
- };
-
- PutPropertySlot()
- : m_type(Invalid)
- , m_base(0)
- {
- }
-
- void setExistingProperty(JSObject* base, size_t offset)
- {
- m_type = ExistingProperty;
- m_base = base;
- m_offset = offset;
- }
-
- void setNewProperty(JSObject* base, size_t offset)
- {
- m_type = NewProperty;
- m_base = base;
- m_offset = offset;
- }
-
- SlotType type() const { return m_type; }
- JSObject* slotBase() const { return m_base; }
-
- bool isCacheable() const { return m_type != Invalid; }
- size_t cachedOffset() const {
- ASSERT(isCacheable());
- return m_offset;
- }
-
- private:
- SlotType m_type;
- JSObject* m_base;
- size_t m_offset;
- };
} // namespace KJS
--- /dev/null
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2008 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 COMPUTER, 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 COMPUTER, 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 PutPropertySlot_h
+#define PutPropertySlot_h
+
+#include <wtf/Assertions.h>
+
+namespace KJS {
+
+ class JSObject;
+
+ class PutPropertySlot {
+ public:
+ enum Type { Invalid, ExistingProperty, NewProperty };
+
+ PutPropertySlot()
+ : m_type(Invalid)
+ , m_base(0)
+ {
+ }
+
+ void setExistingProperty(JSObject* base, size_t offset)
+ {
+ m_type = ExistingProperty;
+ m_base = base;
+ m_offset = offset;
+ }
+
+ void setNewProperty(JSObject* base, size_t offset)
+ {
+ m_type = NewProperty;
+ m_base = base;
+ m_offset = offset;
+ }
+
+ Type type() const { return m_type; }
+ JSObject* base() const { return m_base; }
+
+ bool isCacheable() const { return m_type != Invalid; }
+ size_t cachedOffset() const {
+ ASSERT(isCacheable());
+ return m_offset;
+ }
+
+ private:
+ Type m_type;
+ JSObject* m_base;
+ size_t m_offset;
+ };
+
+} // namespace KJS
+
+#endif // PutPropertySlot_h
#include "StructureID.h"
#include "identifier.h"
-#include "JSCell.h"
+#include "JSObject.h"
#include <wtf/RefPtr.h>
namespace KJS {
return existingTransition;
if (structureID->m_transitionCount > s_maxTransitionLength)
- return dictionaryTransition(structureID);
+ return toDictionaryTransition(structureID);
RefPtr<StructureID> transition = create(structureID->m_prototype);
transition->m_cachedPrototypeChain = structureID->m_cachedPrototypeChain;
return transition.release();
}
-PassRefPtr<StructureID> StructureID::dictionaryTransition(StructureID* structureID)
+PassRefPtr<StructureID> StructureID::toDictionaryTransition(StructureID* structureID)
{
ASSERT(!structureID->m_isDictionary);
RefPtr<StructureID> transition = create(structureID->m_prototype);
transition->m_isDictionary = true;
- transition->m_transitionCount = structureID->m_transitionCount + 1;
return transition.release();
}
+PassRefPtr<StructureID> StructureID::fromDictionaryTransition(StructureID* structureID)
+{
+ ASSERT(structureID->m_isDictionary);
+
+ // Since dictionary StructureIDs are not shared, and no opcodes specialize
+ // for them, we don't need to allocate a new StructureID when transitioning
+ // to non-dictionary status.
+ structureID->m_isDictionary = false;
+ return structureID;
+}
+
PassRefPtr<StructureID> StructureID::changePrototypeTransition(StructureID* structureID, JSValue* prototype)
{
RefPtr<StructureID> transition = create(prototype);
}
StructureIDChain::StructureIDChain(StructureID* structureID)
- : m_size(0)
{
+ size_t size = 0;
+
StructureID* tmp = structureID;
- while (tmp->prototype() != jsNull()) {
- ++m_size;
+ while (!tmp->prototype()->isNull()) {
+ ++size;
tmp = static_cast<JSCell*>(tmp->prototype())->structureID();
}
- m_vector.set(new RefPtr<StructureID>[m_size]);
+ m_vector.set(new RefPtr<StructureID>[size]);
- for (size_t i = 0; i < m_size; ++i) {
+ for (size_t i = 0; i < size; ++i) {
m_vector[i] = structureID;
- structureID = static_cast<JSCell*>(structureID->prototype())->structureID();
+ structureID = static_cast<JSObject*>(structureID->prototype())->structureID();
}
}
static PassRefPtr<StructureID> changePrototypeTransition(StructureID*, JSValue* prototype);
static PassRefPtr<StructureID> addPropertyTransition(StructureID*, const Identifier& name);
static PassRefPtr<StructureID> getterSetterTransition(StructureID*);
- static PassRefPtr<StructureID> dictionaryTransition(StructureID*);
+ static PassRefPtr<StructureID> toDictionaryTransition(StructureID*);
+ static PassRefPtr<StructureID> fromDictionaryTransition(StructureID*);
~StructureID();
StructureIDChain* cachedPrototypeChain() const { return m_cachedPrototypeChain.get(); }
private:
- typedef HashMap<RefPtr<UString::Rep>, StructureID*, WTF::IdentifierRepHash, HashTraits<RefPtr<UString::Rep> > > TransitionTable;
+ typedef HashMap<RefPtr<UString::Rep>, StructureID*, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> > > TransitionTable;
StructureID(JSValue* prototype);
private:
StructureIDChain(StructureID* structureID);
- size_t m_size;
OwnArrayPtr<RefPtr<StructureID> > m_vector;
};
static const bool needsDestruction = false;
};
- typedef HashMap<RefPtr<UString::Rep>, SymbolTableEntry, WTF::IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, SymbolTableIndexHashTraits> SymbolTable;
+ typedef HashMap<RefPtr<UString::Rep>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, SymbolTableIndexHashTraits> SymbolTable;
} // namespace KJS
return capacityDelta;
}
+ struct IdentifierRepHash : PtrHash<RefPtr<KJS::UString::Rep> > {
+ static unsigned hash(const RefPtr<KJS::UString::Rep>& key) { return key->computedHash(); }
+ static unsigned hash(KJS::UString::Rep* key) { return key->computedHash(); }
+ };
+
} // namespace KJS
namespace WTF {
};
- struct IdentifierRepHash : PtrHash<RefPtr<KJS::UString::Rep> > {
- static unsigned hash(const RefPtr<KJS::UString::Rep>& key) { return key->computedHash(); }
- static unsigned hash(KJS::UString::Rep* key) { return key->computedHash(); }
- };
-
} // namespace WTF
#endif
+2008-09-02 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Implemented the rest of Darin's review comments for the 09-01 inline
+ caching patch.
+
+ * ForwardingHeaders/kjs/PutPropertySlot.h: Added.
+
2008-09-01 Geoffrey Garen <ggaren@apple.com>
Reviewed by Darin Adler.
--- /dev/null
+#include <JavaScriptCore/PutPropertySlot.h>
--- /dev/null
+#include <JavaScriptCore/NotFound.h>