f496e538f4
This is the next step towards preventing compiler from directly peeking into runtime and instead interact with runtime through a well defined surface. The goal of the refactoring to locate all places where compiler accesses some runtime information and partion those accesses into two categories: - creating objects in the host runtime (e.g. allocating strings, numbers, etc) during compilation; - accessing properties of the target runtime (e.g. offsets of fields) to embed those into the generated code; This change introduces dart::compiler and dart::compiler::target namespaces. All code in the compiler will gradually be moved into dart::compiler namespace. One of the motivations for this change is to be able to prevent access to globally defined host constants like kWordSize by shadowing them in the dart::compiler namespace. The nested namespace dart::compiler::target hosts all information about target runtime that compiler could access, e.g. compiler::target::kWordSize defines word size of the target which will eventually be made different from the host kWordSize (defined by dart::kWordSize). The API for compiler to runtime interaction is placed into compiler_api.h. Note that we still permit runtime to access compiler internals directly - this is not going to be decoupled as part of this work. Issue https://github.com/dart-lang/sdk/issues/31709 Change-Id: If4396d295879391becfa6c38d4802bbff81f5b20 Reviewed-on: https://dart-review.googlesource.com/c/90242 Commit-Queue: Vyacheslav Egorov <vegorov@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
258 lines
13 KiB
C++
258 lines
13 KiB
C++
// Copyright (c) 2011, 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.
|
|
|
|
#ifndef RUNTIME_VM_STUB_CODE_H_
|
|
#define RUNTIME_VM_STUB_CODE_H_
|
|
|
|
#include "vm/allocation.h"
|
|
#include "vm/compiler/assembler/assembler.h"
|
|
#include "vm/object.h"
|
|
|
|
namespace dart {
|
|
|
|
// Forward declarations.
|
|
class Code;
|
|
class Isolate;
|
|
class ObjectPointerVisitor;
|
|
class RawCode;
|
|
class SnapshotReader;
|
|
class SnapshotWriter;
|
|
|
|
// List of stubs created in the VM isolate, these stubs are shared by different
|
|
// isolates running in this dart process.
|
|
#if !defined(TARGET_ARCH_DBC)
|
|
#define VM_STUB_CODE_LIST(V) \
|
|
V(GetCStackPointer) \
|
|
V(JumpToFrame) \
|
|
V(RunExceptionHandler) \
|
|
V(DeoptForRewind) \
|
|
V(WriteBarrier) \
|
|
V(WriteBarrierWrappers) \
|
|
V(ArrayWriteBarrier) \
|
|
V(PrintStopMessage) \
|
|
V(AllocateArray) \
|
|
V(AllocateContext) \
|
|
V(CallToRuntime) \
|
|
V(LazyCompile) \
|
|
V(InterpretCall) \
|
|
V(CallBootstrapNative) \
|
|
V(CallNoScopeNative) \
|
|
V(CallAutoScopeNative) \
|
|
V(FixCallersTarget) \
|
|
V(CallStaticFunction) \
|
|
V(OptimizeFunction) \
|
|
V(InvokeDartCode) \
|
|
V(InvokeDartCodeFromBytecode) \
|
|
V(DebugStepCheck) \
|
|
V(UnlinkedCall) \
|
|
V(MonomorphicMiss) \
|
|
V(SingleTargetCall) \
|
|
V(ICCallThroughFunction) \
|
|
V(ICCallThroughCode) \
|
|
V(MegamorphicCall) \
|
|
V(FixAllocationStubTarget) \
|
|
V(Deoptimize) \
|
|
V(DeoptimizeLazyFromReturn) \
|
|
V(DeoptimizeLazyFromThrow) \
|
|
V(UnoptimizedIdenticalWithNumberCheck) \
|
|
V(OptimizedIdenticalWithNumberCheck) \
|
|
V(ICCallBreakpoint) \
|
|
V(RuntimeCallBreakpoint) \
|
|
V(OneArgCheckInlineCache) \
|
|
V(TwoArgsCheckInlineCache) \
|
|
V(SmiAddInlineCache) \
|
|
V(SmiSubInlineCache) \
|
|
V(SmiEqualInlineCache) \
|
|
V(OneArgOptimizedCheckInlineCache) \
|
|
V(TwoArgsOptimizedCheckInlineCache) \
|
|
V(ZeroArgsUnoptimizedStaticCall) \
|
|
V(OneArgUnoptimizedStaticCall) \
|
|
V(TwoArgsUnoptimizedStaticCall) \
|
|
V(Subtype1TestCache) \
|
|
V(Subtype2TestCache) \
|
|
V(Subtype4TestCache) \
|
|
V(Subtype6TestCache) \
|
|
V(DefaultTypeTest) \
|
|
V(TopTypeTypeTest) \
|
|
V(TypeRefTypeTest) \
|
|
V(UnreachableTypeTest) \
|
|
V(SlowTypeTest) \
|
|
V(LazySpecializeTypeTest) \
|
|
V(CallClosureNoSuchMethod) \
|
|
V(FrameAwaitingMaterialization) \
|
|
V(AsynchronousGapMarker) \
|
|
V(NullErrorSharedWithFPURegs) \
|
|
V(NullErrorSharedWithoutFPURegs) \
|
|
V(StackOverflowSharedWithFPURegs) \
|
|
V(StackOverflowSharedWithoutFPURegs) \
|
|
V(OneArgCheckInlineCacheWithExactnessCheck) \
|
|
V(OneArgOptimizedCheckInlineCacheWithExactnessCheck)
|
|
|
|
#else
|
|
#define VM_STUB_CODE_LIST(V) \
|
|
V(LazyCompile) \
|
|
V(OptimizeFunction) \
|
|
V(CallClosureNoSuchMethod) \
|
|
V(RunExceptionHandler) \
|
|
V(DeoptForRewind) \
|
|
V(FixCallersTarget) \
|
|
V(Deoptimize) \
|
|
V(DeoptimizeLazyFromReturn) \
|
|
V(DeoptimizeLazyFromThrow) \
|
|
V(DefaultTypeTest) \
|
|
V(TopTypeTypeTest) \
|
|
V(TypeRefTypeTest) \
|
|
V(UnreachableTypeTest) \
|
|
V(SlowTypeTest) \
|
|
V(LazySpecializeTypeTest) \
|
|
V(FrameAwaitingMaterialization) \
|
|
V(AsynchronousGapMarker) \
|
|
V(InvokeDartCodeFromBytecode) \
|
|
V(InterpretCall)
|
|
|
|
#endif // !defined(TARGET_ARCH_DBC)
|
|
|
|
// Is it permitted for the stubs above to refer to Object::null(), which is
|
|
// allocated in the VM isolate and shared across all isolates.
|
|
// However, in cases where a simple GC-safe placeholder is needed on the stack,
|
|
// using Smi 0 instead of Object::null() is slightly more efficient, since a Smi
|
|
// does not require relocation.
|
|
|
|
// class StubCode is used to maintain the lifecycle of stubs.
|
|
class StubCode : public AllStatic {
|
|
public:
|
|
// Generate all stubs which are shared across all isolates, this is done
|
|
// only once and the stub code resides in the vm_isolate heap.
|
|
static void Init();
|
|
|
|
static void Cleanup();
|
|
static void VisitObjectPointers(ObjectPointerVisitor* visitor);
|
|
|
|
// Returns true if stub code has been initialized.
|
|
static bool HasBeenInitialized();
|
|
|
|
// Check if specified pc is in the dart invocation stub used for
|
|
// transitioning into dart code.
|
|
static bool InInvocationStub(uword pc, bool is_interpreted_frame);
|
|
|
|
// Check if the specified pc is in the jump to frame stub.
|
|
static bool InJumpToFrameStub(uword pc);
|
|
|
|
// Returns NULL if no stub found.
|
|
static const char* NameOfStub(uword entry_point);
|
|
|
|
// Define the shared stub code accessors.
|
|
#define STUB_CODE_ACCESSOR(name) \
|
|
static const Code& name() { return *entries_[k##name##Index]; } \
|
|
static intptr_t name##Size() { return name().Size(); }
|
|
VM_STUB_CODE_LIST(STUB_CODE_ACCESSOR);
|
|
#undef STUB_CODE_ACCESSOR
|
|
|
|
static RawCode* GetAllocationStubForClass(const Class& cls);
|
|
|
|
#if !defined(TARGET_ARCH_DBC) && !defined(TARGET_ARCH_IA32)
|
|
static RawCode* GetBuildMethodExtractorStub(ObjectPoolBuilder* pool);
|
|
static void GenerateBuildMethodExtractorStub(compiler::Assembler* assembler);
|
|
#endif
|
|
|
|
static const Code& UnoptimizedStaticCallEntry(intptr_t num_args_tested);
|
|
|
|
static const intptr_t kNoInstantiator = 0;
|
|
static const intptr_t kInstantiationSizeInWords = 3;
|
|
|
|
static const Code& EntryAt(intptr_t index) { return *entries_[index]; }
|
|
static void EntryAtPut(intptr_t index, Code* entry) {
|
|
ASSERT(entry->IsReadOnlyHandle());
|
|
ASSERT(entries_[index] == nullptr);
|
|
entries_[index] = entry;
|
|
}
|
|
static intptr_t NumEntries() { return kNumStubEntries; }
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
#define GENERATE_STUB(name) \
|
|
static RawCode* BuildIsolateSpecific##name##Stub(ObjectPoolBuilder* opw) { \
|
|
return StubCode::Generate("_iso_stub_" #name, opw, \
|
|
StubCode::Generate##name##Stub); \
|
|
}
|
|
VM_STUB_CODE_LIST(GENERATE_STUB);
|
|
#undef GENERATE_STUB
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
private:
|
|
friend class MegamorphicCacheTable;
|
|
|
|
enum {
|
|
#define STUB_CODE_ENTRY(name) k##name##Index,
|
|
VM_STUB_CODE_LIST(STUB_CODE_ENTRY)
|
|
#undef STUB_CODE_ENTRY
|
|
kNumStubEntries
|
|
};
|
|
|
|
static Code* entries_[kNumStubEntries];
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
#define STUB_CODE_GENERATE(name) \
|
|
static void Generate##name##Stub(compiler::Assembler* assembler);
|
|
VM_STUB_CODE_LIST(STUB_CODE_GENERATE)
|
|
#undef STUB_CODE_GENERATE
|
|
|
|
// Generate the stub and finalize the generated code into the stub
|
|
// code executable area.
|
|
static RawCode* Generate(
|
|
const char* name,
|
|
ObjectPoolBuilder* object_pool_builder,
|
|
void (*GenerateStub)(compiler::Assembler* assembler));
|
|
|
|
static void GenerateSharedStub(compiler::Assembler* assembler,
|
|
bool save_fpu_registers,
|
|
const RuntimeEntry* target,
|
|
intptr_t self_code_stub_offset_from_thread,
|
|
bool allow_return);
|
|
|
|
static void GenerateMegamorphicMissStub(compiler::Assembler* assembler);
|
|
static void GenerateAllocationStubForClass(compiler::Assembler* assembler,
|
|
const Class& cls);
|
|
static void GenerateNArgsCheckInlineCacheStub(
|
|
compiler::Assembler* assembler,
|
|
intptr_t num_args,
|
|
const RuntimeEntry& handle_ic_miss,
|
|
Token::Kind kind,
|
|
bool optimized = false,
|
|
bool exactness_check = false);
|
|
static void GenerateUsageCounterIncrement(compiler::Assembler* assembler,
|
|
Register temp_reg);
|
|
static void GenerateOptimizedUsageCounterIncrement(
|
|
compiler::Assembler* assembler);
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
|
};
|
|
|
|
enum DeoptStubKind { kLazyDeoptFromReturn, kLazyDeoptFromThrow, kEagerDeopt };
|
|
|
|
// Invocation mode for TypeCheck runtime entry that describes
|
|
// where we are calling it from.
|
|
enum TypeCheckMode {
|
|
// TypeCheck is invoked from LazySpecializeTypeTest stub.
|
|
// It should replace stub on the type with a specialized version.
|
|
kTypeCheckFromLazySpecializeStub,
|
|
|
|
// TypeCheck is invoked from the SlowTypeTest stub.
|
|
// This means that cache can be lazily created (if needed)
|
|
// and dst_name can be fetched from the pool.
|
|
kTypeCheckFromSlowStub,
|
|
|
|
// TypeCheck is invoked from normal inline AssertAssignable.
|
|
// Both cache and dst_name must be already populated.
|
|
kTypeCheckFromInline
|
|
};
|
|
|
|
// Zap value used to indicate unused CODE_REG in deopt.
|
|
static const uword kZapCodeReg = 0xf1f1f1f1;
|
|
|
|
// Zap value used to indicate unused return address in deopt.
|
|
static const uword kZapReturnAddress = 0xe1e1e1e1;
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_STUB_CODE_H_
|