Commit 8d8ff6a5 authored by ggaren@apple.com's avatar ggaren@apple.com

JavaScriptCore:

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
parent 7e49a7a8
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
......
......@@ -108,6 +108,7 @@ __ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierERb
__ZN3KJS11PropertyMap3putERKNS_10IdentifierEPNS_7JSValueEjbPNS_8JSObjectERNS_15PutPropertySlotE
__ZN3KJS11PropertyMapD1Ev
__ZN3KJS11StructureID21addPropertyTransitionEPS0_RKNS_10IdentifierE
__ZN3KJS11StructureID24fromDictionaryTransitionEPS0_
__ZN3KJS11StructureID25changePrototypeTransitionEPS0_PNS_7JSValueE
__ZN3KJS11StructureIDD1Ev
__ZN3KJS12DateInstance4infoE
......
......@@ -54,6 +54,8 @@
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 */; };
......@@ -458,6 +460,8 @@
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>"; };
......@@ -1268,6 +1272,8 @@
5D53726E0E1C54880021E549 /* Tracing.h */,
F692A8850255597D01FF60F7 /* ustring.cpp */,
F692A8860255597D01FF60F7 /* ustring.h */,
147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */,
147B84620E6DE6B1004775A4 /* PutPropertySlot.h */,
);
path = kjs;
sourceTree = "<group>";
......@@ -1545,6 +1551,8 @@
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;
};
......
......@@ -799,9 +799,9 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
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
......
......@@ -30,6 +30,7 @@
#include "config.h"
#include "CodeGenerator.h"
#include "BatchedTransitionOptimizer.h"
#include "JSFunction.h"
#include "Machine.h"
#include "ustring.h"
......@@ -219,6 +220,8 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
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) {
......@@ -227,8 +230,7 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
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);
}
......
......@@ -345,7 +345,7 @@ namespace KJS {
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);
......@@ -397,7 +397,7 @@ namespace KJS {
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;
......
......@@ -30,6 +30,7 @@
#include "config.h"
#include "Machine.h"
#include "BatchedTransitionOptimizer.h"
#include "CodeBlock.h"
#include "DebuggerCallFrame.h"
#include "ExceptionHelpers.h"
......@@ -539,7 +540,7 @@ Machine::Machine()
// 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();
......@@ -884,21 +885,27 @@ JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj
}
}
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();
......@@ -1096,7 +1103,7 @@ static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBl
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();
}
......@@ -1152,8 +1159,8 @@ NEVER_INLINE void Machine::tryCachePutByID(CodeBlock* codeBlock, Instruction* vP
// 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;
}
......@@ -1242,7 +1249,7 @@ NEVER_INLINE void Machine::tryCacheGetByID(CodeBlock* codeBlock, Instruction* vP
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;
}
......@@ -2203,7 +2210,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
/* 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;
......@@ -2219,13 +2226,12 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
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;
......@@ -2265,8 +2271,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
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.
......@@ -2291,8 +2297,10 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
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.
......@@ -2324,8 +2332,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
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.
......
......@@ -266,7 +266,7 @@ void SamplingTool::dump(ExecState* exec)
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");
......
// -*- 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
......@@ -79,7 +79,7 @@ bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propert
// 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;
}
......
......@@ -125,8 +125,8 @@ inline void JSArray::checkConsistency(ConsistencyCheckType)
#endif
JSArray::JSArray(DummyConstructTag)
: JSObject(StructureID::create(jsNull()))
JSArray::JSArray(PassRefPtr<StructureID> structureID)
: JSObject(structureID)
{
unsigned initialCapacity = 0;
......
......@@ -38,8 +38,7 @@ namespace KJS {
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();
......
......@@ -76,8 +76,6 @@ JSGlobalData::JSGlobalData(bool isShared)
, 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))
......
......@@ -73,8 +73,6 @@ namespace KJS {
const HashTable* regExpConstructorTable;
const HashTable* stringTable;
RefPtr<StructureID> stringStructureID;
RefPtr<StructureID> numberStructureID;
RefPtr<StructureID> nullProtoStructureID;
IdentifierTable* identifierTable;
......
......@@ -40,7 +40,7 @@ JSObject* JSImmediate::toObject(const JSValue* v, ExecState* exec)
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);
}
......@@ -53,7 +53,7 @@ JSObject* JSImmediate::prototype(const JSValue* v, ExecState* exec)
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);
}
......@@ -67,7 +67,7 @@ UString JSImmediate::toString(const JSValue* v)
return "false";
if (v == jsBoolean(true))
return "true";
if (v == jsNull())
if (v->isNull())
return "null";
ASSERT(v == jsUndefined());
return "undefined";
......
......@@ -38,7 +38,26 @@
#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 {
......@@ -46,22 +65,13 @@ ASSERT_CLASS_FITS_IN_CELL(JSObject);
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
......@@ -92,7 +102,7 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* val
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) {
......@@ -111,7 +121,7 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* val
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;
}
......@@ -144,7 +154,7 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* val
}
prototype = obj->prototype();
if (prototype == jsNull())
if (prototype->isNull())
break;
}
......@@ -477,7 +487,7 @@ void JSObject::removeDirect(const Identifier& propertyName)
{
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());
}
}
......@@ -495,10 +505,10 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue**
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
......
......@@ -30,6 +30,7 @@
#include "JSNumberCell.h"
#include "PropertyMap.h"
#include "PropertySlot.h"
#include "PutPropertySlot.h"
#include "ScopeChain.h"
#include "StructureID.h"
......@@ -52,6 +53,8 @@ namespace KJS {
};
class JSObject : public JSCell {
friend class BatchedTransitionOptimizer;
public:
JSObject(PassRefPtr<StructureID>);
JSObject(JSObject* prototype);
......@@ -64,7 +67,7 @@ namespace KJS {
JSValue* prototype() const;
void setPrototype(JSValue* prototype);
PassRefPtr<StructureID> inheritorID();
StructureID* inheritorID();
virtual UString className() const;
......@@ -152,7 +155,7 @@ namespace KJS {
const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
void setStructureID(PassRefPtr<StructureID>);
PassRefPtr<StructureID> createInheritorID();
StructureID* createInheritorID();
PropertyMap m_propertyMap;
RefPtr<StructureID> m_inheritorID;
......@@ -161,11 +164,12 @@ namespace KJS {
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)
......@@ -198,7 +202,7 @@ inline void JSObject::setStructureID(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();
......
......@@ -90,7 +90,7 @@ bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNam
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))
......
......@@ -331,7 +331,7 @@ void PropertyMap::put(const Identifier& propertyName, JSValue* value, unsigned a
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))) {
...