diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/bytecode/StructureStubInfo.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/bytecode/StructureStubInfo.cpp')
-rw-r--r-- | Source/JavaScriptCore/bytecode/StructureStubInfo.cpp | 308 |
1 files changed, 232 insertions, 76 deletions
diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp b/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp index 91413dfbf..70b767c57 100644 --- a/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp +++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2014-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,108 +27,264 @@ #include "StructureStubInfo.h" #include "JSObject.h" -#include "PolymorphicPutByIdList.h" - +#include "JSCInlines.h" +#include "PolymorphicAccess.h" +#include "Repatch.h" namespace JSC { #if ENABLE(JIT) + +static const bool verbose = false; + +StructureStubInfo::StructureStubInfo(AccessType accessType) + : callSiteIndex(UINT_MAX) + , accessType(accessType) + , cacheType(CacheType::Unset) + , countdown(1) // For a totally clear stub, we'll patch it after the first execution. + , repatchCount(0) + , numberOfCoolDowns(0) + , bufferingCountdown(Options::repatchBufferingCountdown()) + , resetByGC(false) + , tookSlowPath(false) + , everConsidered(false) +{ +} + +StructureStubInfo::~StructureStubInfo() +{ +} + +void StructureStubInfo::initGetByIdSelf(CodeBlock* codeBlock, Structure* baseObjectStructure, PropertyOffset offset) +{ + cacheType = CacheType::GetByIdSelf; + + u.byIdSelf.baseObjectStructure.set( + *codeBlock->vm(), codeBlock, baseObjectStructure); + u.byIdSelf.offset = offset; +} + +void StructureStubInfo::initArrayLength() +{ + cacheType = CacheType::ArrayLength; +} + +void StructureStubInfo::initPutByIdReplace(CodeBlock* codeBlock, Structure* baseObjectStructure, PropertyOffset offset) +{ + cacheType = CacheType::PutByIdReplace; + + u.byIdSelf.baseObjectStructure.set( + *codeBlock->vm(), codeBlock, baseObjectStructure); + u.byIdSelf.offset = offset; +} + +void StructureStubInfo::initStub(CodeBlock*, std::unique_ptr<PolymorphicAccess> stub) +{ + cacheType = CacheType::Stub; + u.stub = stub.release(); +} + void StructureStubInfo::deref() { - switch (accessType) { - case access_get_by_id_self_list: { - PolymorphicAccessStructureList* polymorphicStructures = u.getByIdSelfList.structureList; - delete polymorphicStructures; + switch (cacheType) { + case CacheType::Stub: + delete u.stub; return; - } - case access_get_by_id_proto_list: { - PolymorphicAccessStructureList* polymorphicStructures = u.getByIdProtoList.structureList; - delete polymorphicStructures; + case CacheType::Unset: + case CacheType::GetByIdSelf: + case CacheType::PutByIdReplace: + case CacheType::ArrayLength: return; } - case access_put_by_id_list: - delete u.putByIdList.list; + + RELEASE_ASSERT_NOT_REACHED(); +} + +void StructureStubInfo::aboutToDie() +{ + switch (cacheType) { + case CacheType::Stub: + u.stub->aboutToDie(); return; - case access_in_list: { - PolymorphicAccessStructureList* polymorphicStructures = u.inList.structureList; - delete polymorphicStructures; + case CacheType::Unset: + case CacheType::GetByIdSelf: + case CacheType::PutByIdReplace: + case CacheType::ArrayLength: return; } - case access_get_by_id_self: - case access_get_by_id_proto: - case access_get_by_id_chain: - case access_put_by_id_transition_normal: - case access_put_by_id_transition_direct: - case access_put_by_id_replace: - case access_unset: - case access_get_by_id_generic: - case access_put_by_id_generic: - case access_get_array_length: - case access_get_string_length: - // These instructions don't have to release any allocated memory - return; - default: - RELEASE_ASSERT_NOT_REACHED(); + + RELEASE_ASSERT_NOT_REACHED(); +} + +AccessGenerationResult StructureStubInfo::addAccessCase( + CodeBlock* codeBlock, const Identifier& ident, std::unique_ptr<AccessCase> accessCase) +{ + VM& vm = *codeBlock->vm(); + + if (verbose) + dataLog("Adding access case: ", accessCase, "\n"); + + if (!accessCase) + return AccessGenerationResult::GaveUp; + + AccessGenerationResult result; + + if (cacheType == CacheType::Stub) { + result = u.stub->addCase(vm, codeBlock, *this, ident, WTFMove(accessCase)); + + if (verbose) + dataLog("Had stub, result: ", result, "\n"); + + if (!result.buffered()) { + bufferedStructures.clear(); + return result; + } + } else { + std::unique_ptr<PolymorphicAccess> access = std::make_unique<PolymorphicAccess>(); + + Vector<std::unique_ptr<AccessCase>, 2> accessCases; + + std::unique_ptr<AccessCase> previousCase = + AccessCase::fromStructureStubInfo(vm, codeBlock, *this); + if (previousCase) + accessCases.append(WTFMove(previousCase)); + + accessCases.append(WTFMove(accessCase)); + + result = access->addCases(vm, codeBlock, *this, ident, WTFMove(accessCases)); + + if (verbose) + dataLog("Created stub, result: ", result, "\n"); + + if (!result.buffered()) { + bufferedStructures.clear(); + return result; + } + + initStub(codeBlock, WTFMove(access)); + } + + RELEASE_ASSERT(!result.generatedSomeCode()); + + // If we didn't buffer any cases then bail. If this made no changes then we'll just try again + // subject to cool-down. + if (!result.buffered()) { + if (verbose) + dataLog("Didn't buffer anything, bailing.\n"); + bufferedStructures.clear(); + return result; } + + // The buffering countdown tells us if we should be repatching now. + if (bufferingCountdown) { + if (verbose) + dataLog("Countdown is too high: ", bufferingCountdown, ".\n"); + return result; + } + + // Forget the buffered structures so that all future attempts to cache get fully handled by the + // PolymorphicAccess. + bufferedStructures.clear(); + + result = u.stub->regenerate(vm, codeBlock, *this, ident); + + if (verbose) + dataLog("Regeneration result: ", result, "\n"); + + RELEASE_ASSERT(!result.buffered()); + + if (!result.generatedSomeCode()) + return result; + + // If we generated some code then we don't want to attempt to repatch in the future until we + // gather enough cases. + bufferingCountdown = Options::repatchBufferingCountdown(); + return result; } -bool StructureStubInfo::visitWeakReferences() +void StructureStubInfo::reset(CodeBlock* codeBlock) { + bufferedStructures.clear(); + + if (cacheType == CacheType::Unset) + return; + + if (Options::verboseOSR()) { + // This can be called from GC destructor calls, so we don't try to do a full dump + // of the CodeBlock. + dataLog("Clearing structure cache (kind ", static_cast<int>(accessType), ") in ", RawPointer(codeBlock), ".\n"); + } + switch (accessType) { - case access_get_by_id_self: - if (!Heap::isMarked(u.getByIdSelf.baseObjectStructure.get())) - return false; + case AccessType::TryGet: + resetGetByID(codeBlock, *this, GetByIDKind::Try); break; - case access_get_by_id_proto: - if (!Heap::isMarked(u.getByIdProto.baseObjectStructure.get()) - || !Heap::isMarked(u.getByIdProto.prototypeStructure.get())) - return false; + case AccessType::Get: + resetGetByID(codeBlock, *this, GetByIDKind::Normal); break; - case access_get_by_id_chain: - if (!Heap::isMarked(u.getByIdChain.baseObjectStructure.get()) - || !Heap::isMarked(u.getByIdChain.chain.get())) - return false; + case AccessType::Put: + resetPutByID(codeBlock, *this); break; - case access_get_by_id_self_list: { - PolymorphicAccessStructureList* polymorphicStructures = u.getByIdSelfList.structureList; - if (!polymorphicStructures->visitWeak(u.getByIdSelfList.listSize)) - return false; - break; - } - case access_get_by_id_proto_list: { - PolymorphicAccessStructureList* polymorphicStructures = u.getByIdProtoList.structureList; - if (!polymorphicStructures->visitWeak(u.getByIdProtoList.listSize)) - return false; + case AccessType::In: + resetIn(codeBlock, *this); break; } - case access_put_by_id_transition_normal: - case access_put_by_id_transition_direct: - if (!Heap::isMarked(u.putByIdTransition.previousStructure.get()) - || !Heap::isMarked(u.putByIdTransition.structure.get()) - || !Heap::isMarked(u.putByIdTransition.chain.get())) - return false; - break; - case access_put_by_id_replace: - if (!Heap::isMarked(u.putByIdReplace.baseObjectStructure.get())) - return false; - break; - case access_put_by_id_list: - if (!u.putByIdList.list->visitWeak()) - return false; + + deref(); + cacheType = CacheType::Unset; +} + +void StructureStubInfo::visitWeakReferences(CodeBlock* codeBlock) +{ + VM& vm = *codeBlock->vm(); + + bufferedStructures.genericFilter( + [&] (Structure* structure) -> bool { + return Heap::isMarked(structure); + }); + + switch (cacheType) { + case CacheType::GetByIdSelf: + case CacheType::PutByIdReplace: + if (Heap::isMarked(u.byIdSelf.baseObjectStructure.get())) + return; break; - case access_in_list: { - PolymorphicAccessStructureList* polymorphicStructures = u.inList.structureList; - if (!polymorphicStructures->visitWeak(u.inList.listSize)) - return false; + case CacheType::Stub: + if (u.stub->visitWeak(vm)) + return; break; - } default: - // The rest of the instructions don't require references, so there is no need to - // do anything. - break; + return; } + + reset(codeBlock); + resetByGC = true; +} + +bool StructureStubInfo::propagateTransitions(SlotVisitor& visitor) +{ + switch (cacheType) { + case CacheType::Unset: + case CacheType::ArrayLength: + return true; + case CacheType::GetByIdSelf: + case CacheType::PutByIdReplace: + return u.byIdSelf.baseObjectStructure->markIfCheap(visitor); + case CacheType::Stub: + return u.stub->propagateTransitions(visitor); + } + + RELEASE_ASSERT_NOT_REACHED(); return true; } -#endif + +bool StructureStubInfo::containsPC(void* pc) const +{ + if (cacheType != CacheType::Stub) + return false; + return u.stub->containsPC(pc); +} + +#endif // ENABLE(JIT) } // namespace JSC |