#include "config.h"
#include "GetByIdStatus.h"
#include "CodeBlock.h"
#include "JSScope.h"
#include "LLIntData.h"
#include "LowLevelInterpreter.h"
#include "Operations.h"
namespace JSC {
GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident)
{
UNUSED_PARAM(profiledBlock);
UNUSED_PARAM(bytecodeIndex);
UNUSED_PARAM(ident);
#if ENABLE(LLINT)
Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex;
if (instruction[0].u.opcode == LLInt::getOpcode(llint_op_get_array_length))
return GetByIdStatus(NoInformation, false);
Structure* structure = instruction[4].u.structure.get();
if (!structure)
return GetByIdStatus(NoInformation, false);
unsigned attributesIgnored;
JSCell* specificValue;
PropertyOffset offset = structure->get(
*profiledBlock->vm(), ident, attributesIgnored, specificValue);
if (structure->isDictionary())
specificValue = 0;
if (!isValidOffset(offset))
return GetByIdStatus(NoInformation, false);
return GetByIdStatus(Simple, false, StructureSet(structure), offset, specificValue);
#else
return GetByIdStatus(NoInformation, false);
#endif
}
void GetByIdStatus::computeForChain(GetByIdStatus& result, CodeBlock* profiledBlock, Identifier& ident, Structure* structure)
{
#if ENABLE(JIT) && ENABLE(VALUE_PROFILER)
Structure* currentStructure = structure;
JSObject* currentObject = 0;
for (unsigned i = 0; i < result.m_chain.size(); ++i) {
ASSERT(!currentStructure->isDictionary());
currentObject = asObject(currentStructure->prototypeForLookup(profiledBlock));
currentStructure = result.m_chain[i];
if (currentObject->structure() != currentStructure)
return;
}
ASSERT(currentObject);
unsigned attributesIgnored;
JSCell* specificValue;
result.m_offset = currentStructure->get(
*profiledBlock->vm(), ident, attributesIgnored, specificValue);
if (currentStructure->isDictionary())
specificValue = 0;
if (!isValidOffset(result.m_offset))
return;
result.m_structureSet.add(structure);
result.m_specificValue = JSValue(specificValue);
#else
UNUSED_PARAM(result);
UNUSED_PARAM(profiledBlock);
UNUSED_PARAM(ident);
UNUSED_PARAM(structure);
UNREACHABLE_FOR_PLATFORM();
#endif
}
GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident)
{
UNUSED_PARAM(profiledBlock);
UNUSED_PARAM(bytecodeIndex);
UNUSED_PARAM(ident);
#if ENABLE(JIT) && ENABLE(VALUE_PROFILER)
if (!profiledBlock->numberOfStructureStubInfos())
return computeFromLLInt(profiledBlock, bytecodeIndex, ident);
StructureStubInfo& stubInfo = profiledBlock->getStubInfo(bytecodeIndex);
if (!stubInfo.seen)
return computeFromLLInt(profiledBlock, bytecodeIndex, ident);
if (stubInfo.resetByGC)
return GetByIdStatus(TakesSlowPath, true);
PolymorphicAccessStructureList* list;
int listSize;
switch (stubInfo.accessType) {
case access_get_by_id_self_list:
list = stubInfo.u.getByIdSelfList.structureList;
listSize = stubInfo.u.getByIdSelfList.listSize;
break;
case access_get_by_id_proto_list:
list = stubInfo.u.getByIdProtoList.structureList;
listSize = stubInfo.u.getByIdProtoList.listSize;
break;
default:
list = 0;
listSize = 0;
break;
}
for (int i = 0; i < listSize; ++i) {
if (!list->list[i].isDirect)
return GetByIdStatus(MakesCalls, true);
}
if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex))
return GetByIdStatus(TakesSlowPath, true);
GetByIdStatus result;
result.m_wasSeenInJIT = true; switch (stubInfo.accessType) {
case access_unset:
return computeFromLLInt(profiledBlock, bytecodeIndex, ident);
case access_get_by_id_self: {
Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
unsigned attributesIgnored;
JSCell* specificValue;
result.m_offset = structure->get(
*profiledBlock->vm(), ident, attributesIgnored, specificValue);
if (structure->isDictionary())
specificValue = 0;
if (isValidOffset(result.m_offset)) {
result.m_structureSet.add(structure);
result.m_specificValue = JSValue(specificValue);
}
if (isValidOffset(result.m_offset))
ASSERT(result.m_structureSet.size());
break;
}
case access_get_by_id_self_list: {
for (int i = 0; i < listSize; ++i) {
ASSERT(list->list[i].isDirect);
Structure* structure = list->list[i].base.get();
if (result.m_structureSet.contains(structure))
continue;
unsigned attributesIgnored;
JSCell* specificValue;
PropertyOffset myOffset = structure->get(
*profiledBlock->vm(), ident, attributesIgnored, specificValue);
if (structure->isDictionary())
specificValue = 0;
if (!isValidOffset(myOffset)) {
result.m_offset = invalidOffset;
break;
}
if (!i) {
result.m_offset = myOffset;
result.m_specificValue = JSValue(specificValue);
} else if (result.m_offset != myOffset) {
result.m_offset = invalidOffset;
break;
} else if (result.m_specificValue != JSValue(specificValue))
result.m_specificValue = JSValue();
result.m_structureSet.add(structure);
}
if (isValidOffset(result.m_offset))
ASSERT(result.m_structureSet.size());
break;
}
case access_get_by_id_proto: {
if (!stubInfo.u.getByIdProto.isDirect)
return GetByIdStatus(MakesCalls, true);
result.m_chain.append(stubInfo.u.getByIdProto.prototypeStructure.get());
computeForChain(
result, profiledBlock, ident,
stubInfo.u.getByIdProto.baseObjectStructure.get());
break;
}
case access_get_by_id_chain: {
if (!stubInfo.u.getByIdChain.isDirect)
return GetByIdStatus(MakesCalls, true);
for (unsigned i = 0; i < stubInfo.u.getByIdChain.count; ++i)
result.m_chain.append(stubInfo.u.getByIdChain.chain->head()[i].get());
computeForChain(
result, profiledBlock, ident,
stubInfo.u.getByIdChain.baseObjectStructure.get());
break;
}
default:
ASSERT(!isValidOffset(result.m_offset));
break;
}
if (!isValidOffset(result.m_offset)) {
result.m_state = TakesSlowPath;
result.m_structureSet.clear();
result.m_chain.clear();
result.m_specificValue = JSValue();
} else
result.m_state = Simple;
return result;
#else // ENABLE(JIT)
return GetByIdStatus(NoInformation, false);
#endif // ENABLE(JIT)
}
GetByIdStatus GetByIdStatus::computeFor(VM& vm, Structure* structure, Identifier& ident)
{
if (PropertyName(ident).asIndex() != PropertyName::NotAnIndex)
return GetByIdStatus(TakesSlowPath);
if (structure->typeInfo().overridesGetOwnPropertySlot())
return GetByIdStatus(TakesSlowPath);
if (!structure->propertyAccessesAreCacheable())
return GetByIdStatus(TakesSlowPath);
GetByIdStatus result;
result.m_wasSeenInJIT = false; unsigned attributes;
JSCell* specificValue;
result.m_offset = structure->get(vm, ident, attributes, specificValue);
if (!isValidOffset(result.m_offset))
return GetByIdStatus(TakesSlowPath); if (attributes & Accessor)
return GetByIdStatus(MakesCalls);
if (structure->isDictionary())
specificValue = 0;
result.m_structureSet.add(structure);
result.m_specificValue = JSValue(specificValue);
return result;
}
}