#include "config.h"
#include "PutByIdStatus.h"
#include "CodeBlock.h"
#include "LLIntData.h"
#include "LowLevelInterpreter.h"
#include "Operations.h"
#include "Structure.h"
#include "StructureChain.h"
namespace JSC {
PutByIdStatus PutByIdStatus::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;
Structure* structure = instruction[4].u.structure.get();
if (!structure)
return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
if (instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id)
|| instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id_out_of_line)) {
PropertyOffset offset = structure->get(*profiledBlock->vm(), ident);
if (!isValidOffset(offset))
return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
return PutByIdStatus(SimpleReplace, structure, 0, 0, offset);
}
ASSERT(structure->transitionWatchpointSetHasBeenInvalidated());
ASSERT(instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id_transition_direct)
|| instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id_transition_normal)
|| instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id_transition_direct_out_of_line)
|| instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id_transition_normal_out_of_line));
Structure* newStructure = instruction[6].u.structure.get();
StructureChain* chain = instruction[7].u.structureChain.get();
ASSERT(newStructure);
ASSERT(chain);
PropertyOffset offset = newStructure->get(*profiledBlock->vm(), ident);
if (!isValidOffset(offset))
return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
return PutByIdStatus(SimpleTransition, structure, newStructure, chain, offset);
#else
return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
#endif
}
PutByIdStatus PutByIdStatus::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);
if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex))
return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
StructureStubInfo& stubInfo = profiledBlock->getStubInfo(bytecodeIndex);
if (!stubInfo.seen)
return computeFromLLInt(profiledBlock, bytecodeIndex, ident);
if (stubInfo.resetByGC)
return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
switch (stubInfo.accessType) {
case access_unset:
return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
case access_put_by_id_replace: {
PropertyOffset offset = stubInfo.u.putByIdReplace.baseObjectStructure->get(
*profiledBlock->vm(), ident);
if (isValidOffset(offset)) {
return PutByIdStatus(
SimpleReplace,
stubInfo.u.putByIdReplace.baseObjectStructure.get(),
0, 0,
offset);
}
return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
}
case access_put_by_id_transition_normal:
case access_put_by_id_transition_direct: {
ASSERT(stubInfo.u.putByIdTransition.previousStructure->transitionWatchpointSetHasBeenInvalidated());
PropertyOffset offset = stubInfo.u.putByIdTransition.structure->get(
*profiledBlock->vm(), ident);
if (isValidOffset(offset)) {
return PutByIdStatus(
SimpleTransition,
stubInfo.u.putByIdTransition.previousStructure.get(),
stubInfo.u.putByIdTransition.structure.get(),
stubInfo.u.putByIdTransition.chain.get(),
offset);
}
return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
}
default:
return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
}
#else // ENABLE(JIT)
return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
#endif // ENABLE(JIT)
}
PutByIdStatus PutByIdStatus::computeFor(VM& vm, JSGlobalObject* globalObject, Structure* structure, Identifier& ident, bool isDirect)
{
if (PropertyName(ident).asIndex() != PropertyName::NotAnIndex)
return PutByIdStatus(TakesSlowPath);
if (structure->typeInfo().overridesGetOwnPropertySlot())
return PutByIdStatus(TakesSlowPath);
if (!structure->propertyAccessesAreCacheable())
return PutByIdStatus(TakesSlowPath);
unsigned attributes;
JSCell* specificValue;
PropertyOffset offset = structure->get(vm, ident, attributes, specificValue);
if (isValidOffset(offset)) {
if (attributes & (Accessor | ReadOnly))
return PutByIdStatus(TakesSlowPath);
if (specificValue) {
return PutByIdStatus(TakesSlowPath);
}
return PutByIdStatus(SimpleReplace, structure, 0, 0, offset);
}
if (structure->isDictionary())
return PutByIdStatus(TakesSlowPath);
if (structure->typeInfo().type() == StringType)
return PutByIdStatus(TakesSlowPath);
if (!isDirect) {
if (structure->prototypeChainMayInterceptStoreTo(vm, ident))
return PutByIdStatus(TakesSlowPath);
if (!isPrototypeChainNormalized(globalObject, structure))
return PutByIdStatus(TakesSlowPath);
}
Structure* transition = Structure::addPropertyTransitionToExistingStructure(structure, ident, 0, 0, offset);
if (!transition)
return PutByIdStatus(TakesSlowPath); ASSERT(!transition->transitionDidInvolveSpecificValue());
ASSERT(isValidOffset(offset));
return PutByIdStatus(
SimpleTransition, structure, transition,
structure->prototypeChain(vm, globalObject), offset);
}
}