summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/bytecode/StructureStubInfo.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/bytecode/StructureStubInfo.cpp')
-rw-r--r--Source/JavaScriptCore/bytecode/StructureStubInfo.cpp308
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