Files
sdk/runtime/vm/stub_code.cc
T
Ryan Macnak 1d4c316d55 [vm, gc] Don't eagerly evacuate new space on old allocation failure, take 2.
Large allocations and direct old space allocations are not signals that the current new space objects will be long lived.

Still perform a scavenge to handle (dead new -> dead old) references even when new space allocation is low, but a non-evacuating scavenge.

Change-Id: I4008fb163c4536abfc7ba42410ec57917a69786a
Reviewed-on: https://dart-review.googlesource.com/72340
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
2018-09-04 22:51:07 +00:00

235 lines
7.5 KiB
C++

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/stub_code.h"
#include "platform/assert.h"
#include "platform/globals.h"
#include "vm/clustered_snapshot.h"
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/assembler/disassembler.h"
#include "vm/flags.h"
#include "vm/heap/safepoint.h"
#include "vm/object_store.h"
#include "vm/snapshot.h"
#include "vm/virtual_memory.h"
#include "vm/visitor.h"
namespace dart {
DEFINE_FLAG(bool, disassemble_stubs, false, "Disassemble generated stubs.");
StubEntry* StubCode::entries_[kNumStubEntries] = {
#define STUB_CODE_DECLARE(name) NULL,
VM_STUB_CODE_LIST(STUB_CODE_DECLARE)
#undef STUB_CODE_DECLARE
};
StubEntry::StubEntry(const Code& code)
: code_(code.raw()),
entry_point_(code.EntryPoint()),
monomorphic_entry_point_(code.MonomorphicEntryPoint()),
size_(code.Size()),
label_(code.EntryPoint()) {}
// Visit all object pointers.
void StubEntry::VisitObjectPointers(ObjectPointerVisitor* visitor) {
ASSERT(visitor != NULL);
visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_));
}
#if defined(DART_PRECOMPILED_RUNTIME)
void StubCode::InitOnce() {
// Stubs will be loaded from the snapshot.
UNREACHABLE();
}
#else
#define STUB_CODE_GENERATE(name) \
code ^= Generate("_stub_" #name, StubCode::Generate##name##Stub); \
entries_[k##name##Index] = new StubEntry(code);
void StubCode::InitOnce() {
// Generate all the stubs.
Code& code = Code::Handle();
VM_STUB_CODE_LIST(STUB_CODE_GENERATE);
}
#undef STUB_CODE_GENERATE
RawCode* StubCode::Generate(const char* name,
void (*GenerateStub)(Assembler* assembler)) {
ObjectPoolWrapper object_pool_wrapper;
Assembler assembler(&object_pool_wrapper);
GenerateStub(&assembler);
const Code& code = Code::Handle(
Code::FinalizeCode(name, nullptr, &assembler, false /* optimized */));
#ifndef PRODUCT
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
LogBlock lb;
THR_Print("Code for stub '%s': {\n", name);
DisassembleToStdout formatter;
code.Disassemble(&formatter);
THR_Print("}\n");
const ObjectPool& object_pool = ObjectPool::Handle(code.object_pool());
object_pool.DebugPrint();
}
#endif // !PRODUCT
return code.raw();
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
void StubCode::VisitObjectPointers(ObjectPointerVisitor* visitor) {}
bool StubCode::HasBeenInitialized() {
// Use AsynchronousGapMarker as canary.
return StubCode::AsynchronousGapMarker_entry() != NULL;
}
bool StubCode::InInvocationStub(uword pc, bool is_interpreted_frame) {
#if !defined(TARGET_ARCH_DBC)
ASSERT(HasBeenInitialized());
#if defined(DART_USE_INTERPRETER)
if (is_interpreted_frame) {
// Recognize special marker set up by interpreter in entry frame.
return (pc & 2) != 0;
}
{
uword entry = StubCode::InvokeDartCodeFromBytecode_entry()->EntryPoint();
uword size = StubCode::InvokeDartCodeFromBytecodeSize();
if ((pc >= entry) && (pc < (entry + size))) {
return true;
}
}
#endif
uword entry = StubCode::InvokeDartCode_entry()->EntryPoint();
uword size = StubCode::InvokeDartCodeSize();
return (pc >= entry) && (pc < (entry + size));
#elif defined(DART_USE_INTERPRETER)
#error "Simultaneous usage of DBC simulator and interpreter not yet supported."
#else
// On DBC we use a special marker PC to signify entry frame because there is
// no such thing as invocation stub.
return (pc & 2) != 0;
#endif
}
bool StubCode::InJumpToFrameStub(uword pc) {
#if !defined(TARGET_ARCH_DBC)
ASSERT(HasBeenInitialized());
uword entry = StubCode::JumpToFrame_entry()->EntryPoint();
uword size = StubCode::JumpToFrameSize();
return (pc >= entry) && (pc < (entry + size));
#else
// This stub does not exist on DBC.
return false;
#endif
}
RawCode* StubCode::GetAllocationStubForClass(const Class& cls) {
// These stubs are not used by DBC.
#if !defined(TARGET_ARCH_DBC)
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
ASSERT(error.IsNull());
if (cls.id() == kArrayCid) {
return AllocateArray_entry()->code();
}
Code& stub = Code::Handle(zone, cls.allocation_stub());
#if !defined(DART_PRECOMPILED_RUNTIME)
if (stub.IsNull()) {
ObjectPoolWrapper object_pool_wrapper;
Assembler assembler(&object_pool_wrapper);
const char* name = cls.ToCString();
StubCode::GenerateAllocationStubForClass(&assembler, cls);
if (thread->IsMutatorThread()) {
stub ^=
Code::FinalizeCode(name, nullptr, &assembler, false /* optimized */);
// Check if background compilation thread has not already added the stub.
if (cls.allocation_stub() == Code::null()) {
stub.set_owner(cls);
cls.set_allocation_stub(stub);
}
} else {
// This part of stub code generation must be at a safepoint.
// Stop mutator thread before creating the instruction object and
// installing code.
// Mutator thread may not run code while we are creating the
// instruction object, since the creation of instruction object
// changes code page access permissions (makes them temporary not
// executable).
{
SafepointOperationScope safepoint_scope(thread);
stub = cls.allocation_stub();
// Check if stub was already generated.
if (!stub.IsNull()) {
return stub.raw();
}
// Do not Garbage collect during this stage and instead allow the
// heap to grow.
NoHeapGrowthControlScope no_growth_control;
stub ^= Code::FinalizeCode(name, nullptr, &assembler,
false /* optimized */);
stub.set_owner(cls);
cls.set_allocation_stub(stub);
}
Isolate* isolate = thread->isolate();
if (isolate->heap()->NeedsGarbageCollection()) {
isolate->heap()->CollectMostGarbage();
}
}
#ifndef PRODUCT
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
LogBlock lb;
THR_Print("Code for allocation stub '%s': {\n", name);
DisassembleToStdout formatter;
stub.Disassemble(&formatter);
THR_Print("}\n");
const ObjectPool& object_pool = ObjectPool::Handle(stub.object_pool());
object_pool.DebugPrint();
}
#endif // !PRODUCT
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
return stub.raw();
#endif // !DBC
UNIMPLEMENTED();
return Code::null();
}
const StubEntry* StubCode::UnoptimizedStaticCallEntry(
intptr_t num_args_tested) {
// These stubs are not used by DBC.
#if !defined(TARGET_ARCH_DBC)
switch (num_args_tested) {
case 0:
return ZeroArgsUnoptimizedStaticCall_entry();
case 1:
return OneArgUnoptimizedStaticCall_entry();
case 2:
return TwoArgsUnoptimizedStaticCall_entry();
default:
UNIMPLEMENTED();
return NULL;
}
#else
return NULL;
#endif
}
const char* StubCode::NameOfStub(uword entry_point) {
#define VM_STUB_CODE_TESTER(name) \
if ((name##_entry() != NULL) && \
(entry_point == name##_entry()->EntryPoint())) { \
return "" #name; \
}
VM_STUB_CODE_LIST(VM_STUB_CODE_TESTER);
#undef VM_STUB_CODE_TESTER
return NULL;
}
} // namespace dart