Dart Byte Code interpreter.

This version is Clang/GCC only and does not support Windows because it uses computed goto's.

Only unoptimized mode is supported.

Architecture is described in constants_dbc.h and stack_frame_dbc.h.

R=fschneider@google.com, zra@google.com

Review URL: https://codereview.chromium.org/1858283002 .
This commit is contained in:
Vyacheslav Egorov
2016-04-18 23:02:01 +02:00
parent 9ec591573a
commit ee0f608ce4
88 changed files with 5722 additions and 112 deletions
@@ -42,3 +42,8 @@ coverage_test: Pass, Slow
[ $compiler == dart2analyzer ]
evaluate_activation_in_method_class_test: CompileTimeError # Issue 24478
[ $arch == simdbc ]
# TODO(vegorov) re-enable when debugger, coverage and profiling is completely
# fixed for SIMDBC.
*: Skip
+14
View File
@@ -257,6 +257,15 @@ typedef simd128_value_t fpu_register_t;
#error Automatic compiler detection failed.
#endif
// DART_NOINLINE tells compiler to never inline a particular function.
#ifdef _MSC_VER
#define DART_NOINLINE __declspec(noinline)
#elif __GNUC__
#define DART_NOINLINE __attribute__((noinline))
#else
#error Automatic compiler detection failed.
#endif
// DART_UNUSED inidicates to the compiler that a variable/typedef is expected
// to be unused and disables the related warning.
#ifdef __GNUC__
@@ -282,6 +291,7 @@ typedef simd128_value_t fpu_register_t;
#if !defined(TARGET_ARCH_X64)
#if !defined(TARGET_ARCH_IA32)
#if !defined(TARGET_ARCH_ARM64)
#if !defined(TARGET_ARCH_DBC)
// No target architecture specified pick the one matching the host architecture.
#if defined(HOST_ARCH_MIPS)
#define TARGET_ARCH_MIPS 1
@@ -301,6 +311,7 @@ typedef simd128_value_t fpu_register_t;
#endif
#endif
#endif
#endif
// Verify that host and target architectures match, we cannot
// have a 64 bit Dart VM generating 32 bit code or vice-versa.
@@ -337,6 +348,9 @@ typedef simd128_value_t fpu_register_t;
#define USING_SIMULATOR 1
#endif
#elif defined(TARGET_ARCH_DBC)
#define USING_SIMULATOR 1
#else
#error Unknown architecture.
#endif
+85 -1
View File
@@ -33,7 +33,7 @@ cc/Service_Profile: Skip
cc/Dart2JSCompilerStats: Skip
cc/CorelibCompilerStats: Skip
[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simarm64 || $arch == simmips ]
[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simarm64 || $arch == simmips || $arch == simdbc ]
cc/Service_Profile: Skip
[ $compiler == dart2js ]
@@ -97,3 +97,87 @@ dart/optimized_stacktrace_test: SkipByDesign # Requires line numbers
cc/IsolateSetCheckedMode: Fail,OK # Expects exact type name.
cc/LibraryGetClassNames: Fail,OK # Expects exact type name.
cc/StackTraceFormat: Fail,OK # Expects exact type name.
[ $arch == simdbc ]
# TODO(vegorov) Profiler is completely disabled in SIMDBC builds.
cc/Profiler_AllocationSampleTest: Skip
cc/Profiler_ArrayAllocation: Skip
cc/Profiler_BasicSourcePosition: Skip
cc/Profiler_BasicSourcePositionOptimized: Skip
cc/Profiler_BinaryOperatorSourcePosition: Skip
cc/Profiler_BinaryOperatorSourcePositionOptimized: Skip
cc/Profiler_ChainedSamples: Skip
cc/Profiler_ClosureAllocation: Skip
cc/Profiler_CodeTicks: Skip
cc/Profiler_ContextAllocation: Skip
cc/Profiler_FunctionInline: Skip
cc/Profiler_FunctionTicks: Skip
cc/Profiler_InliningIntervalBoundry: Skip
cc/Profiler_IntrinsicAllocation: Skip
cc/Profiler_SampleBufferIterateTest: Skip
cc/Profiler_SampleBufferWrapTest: Skip
cc/Profiler_SourcePosition: Skip
cc/Profiler_SourcePositionOptimized: Skip
cc/Profiler_StringAllocation: Skip
cc/Profiler_StringInterpolation: Skip
cc/Profiler_ToggleRecordAllocation: Skip
cc/Profiler_TrivialRecordAllocation: Skip
cc/Profiler_TypedArrayAllocation: Skip
cc/Profiler_GetSourceReport: Skip
# TODO(vegorov) These tests are crashing because ICData objects can't be found
cc/SourceReport_CallSites_PolymorphicCall: Skip
cc/SourceReport_CallSites_SimpleCall: Skip
cc/SourceReport_Coverage_AllFunctions: Skip
cc/SourceReport_Coverage_ForceCompile: Skip
cc/SourceReport_Coverage_NestedFunctions: Skip
cc/SourceReport_Coverage_SimpleCall: Skip
cc/SourceReport_MultipleReports: Skip
cc/Coverage_Empty: Skip
cc/Coverage_FilterFunction: Skip
cc/Coverage_MainWithClass: Skip
# TODO(vegorov) DisassembleToJSONStream requires
# DecodeLoadObjectFromPoolOrThread which is unimplemented.
cc/Service_Code: Skip
cc/PrintJSON: Skip
# TODO(vegorov) These tests don't seem to work if FLAG_interpret_irregexp
# is switched on by default because they attempt to call regexp functions
# directly instead of going through JSSyntaxRegExp_ExecuteMatch.
cc/RegExp_ExternalOneByteString: Skip
cc/RegExp_ExternalTwoByteString: Skip
cc/RegExp_OneByteString: Skip
cc/RegExp_TwoByteString: Skip
# TODO(vegorov) Optimizing compiler is disabled for the SIMDBC
cc/CompileFunctionOnHelperThread: Skip
# TODO(vegorov) Field guards are disabled for SIMDBC
cc/GuardFieldConstructor2Test: Skip
cc/GuardFieldConstructorTest: Skip
cc/GuardFieldFinalListTest: Skip
cc/GuardFieldFinalVariableLengthListTest: Skip
cc/GuardFieldSimpleTest: Skip
# TODO(vegorov) Not all bytecodes have appropriate debug breaks.
cc/Debug_BreakpointStubPatching: Skip
cc/Debug_ExprClosureBreakpoint: Skip
cc/Debug_StackTraceDump1: Skip
cc/Debug_StepInto: Skip
# TODO(vegorov) These parser tests rely on debugger.
cc/Parser_AllocateVariables_CapturedVar: Skip
cc/Parser_AllocateVariables_MiddleChain: Skip
# TODO(vegorov) Test needs to generate a large enough function to go on to the
# large page. However large enough function overflows bytecode encoding.
cc/FindCodeObject: Skip
# This test is meaningless for DBC as allocation stubs are not used.
cc/RegenerateAllocStubs: Skip
# TODO(vegorov) Enable when DBC supports optimizing compiler.
cc/Debug_InspectStack_Optimized: Skip
cc/Debug_InspectStackWithClosure_Optimized: Skip
+2
View File
@@ -340,6 +340,8 @@ enum RestorePP {
#include "vm/assembler_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/assembler_mips.h"
#elif defined(TARGET_ARCH_DBC)
#include "vm/assembler_dbc.h"
#else
#error Unknown architecture.
#endif
+142
View File
@@ -0,0 +1,142 @@
// Copyright (c) 2016, 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/globals.h" // NOLINT
#if defined(TARGET_ARCH_DBC)
#include "vm/assembler.h"
#include "vm/cpu.h"
#include "vm/longjump.h"
#include "vm/runtime_entry.h"
#include "vm/simulator.h"
#include "vm/stack_frame.h"
#include "vm/stub_code.h"
namespace dart {
DECLARE_FLAG(bool, allow_absolute_addresses);
DECLARE_FLAG(bool, check_code_pointer);
DECLARE_FLAG(bool, inline_alloc);
void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) {
const uword end = data + length;
while (data < end) {
*reinterpret_cast<int32_t*>(data) = Bytecode::kTrap;
data += sizeof(int32_t);
}
}
#define DEFINE_EMIT(Name, Signature, Fmt0, Fmt1, Fmt2) \
void Assembler::Name(PARAMS_##Signature) { \
Emit(Bytecode::FENCODE_##Signature( \
Bytecode::k##Name ENCODE_##Signature)); \
} \
#define PARAMS_0
#define PARAMS_A_D uintptr_t ra, uintptr_t rd
#define PARAMS_D uintptr_t rd
#define PARAMS_A_B_C uintptr_t ra, uintptr_t rb, uintptr_t rc
#define PARAMS_A uintptr_t ra
#define PARAMS_T intptr_t x
#define PARAMS_A_X uintptr_t ra, intptr_t x
#define PARAMS_X intptr_t x
#define ENCODE_0
#define ENCODE_A_D , ra, rd
#define ENCODE_D , 0, rd
#define ENCODE_A_B_C , ra, rb, rc
#define ENCODE_A , ra, 0
#define ENCODE_T , x
#define ENCODE_A_X , ra, x
#define ENCODE_X , 0, x
#define FENCODE_0 Encode
#define FENCODE_A_D Encode
#define FENCODE_D Encode
#define FENCODE_A_B_C Encode
#define FENCODE_A Encode
#define FENCODE_T EncodeSigned
#define FENCODE_A_X EncodeSigned
#define FENCODE_X EncodeSigned
BYTECODES_LIST(DEFINE_EMIT)
#undef DEFINE_EMIT
void Assembler::Emit(int32_t value) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
buffer_.Emit<int32_t>(value);
}
const char* Assembler::RegisterName(Register reg) {
return Thread::Current()->zone()->PrintToString("R%d", reg);
}
static int32_t EncodeJump(int32_t relative_pc) {
return Bytecode::kJump | (relative_pc << 8);
}
static int32_t OffsetToPC(int32_t offset) {
return offset >> 2;
}
void Assembler::Jump(Label* label) {
if (label->IsBound()) {
Emit(EncodeJump(OffsetToPC(label->Position() - buffer_.Size())));
} else {
const intptr_t position = buffer_.Size();
Emit(label->position_);
label->LinkTo(position);
}
}
void Assembler::Bind(Label* label) {
ASSERT(!label->IsBound());
ASSERT(!label->IsBound());
intptr_t bound_pc = buffer_.Size();
while (label->IsLinked()) {
const int32_t position = label->Position();
const int32_t next_position = buffer_.Load<int32_t>(position);
buffer_.Store<int32_t>(position,
EncodeJump(OffsetToPC(bound_pc - position)));
label->position_ = next_position;
}
label->BindTo(bound_pc);
}
void Assembler::Stop(const char* message) {
// TODO(vegorov) support passing a message to the bytecode.
Emit(Bytecode::kTrap);
}
void Assembler::PushConstant(const Object& obj) {
PushConstant(AddConstant(obj));
}
void Assembler::LoadConstant(uintptr_t ra, const Object& obj) {
LoadConstant(ra, AddConstant(obj));
}
intptr_t Assembler::AddConstant(const Object& obj) {
return object_pool_wrapper().FindObject(
Object::ZoneHandle(obj.raw()));
}
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+197
View File
@@ -0,0 +1,197 @@
// Copyright (c) 2016, 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 VM_ASSEMBLER_DBC_H_
#define VM_ASSEMBLER_DBC_H_
#ifndef VM_ASSEMBLER_H_
#error Do not include assembler_dbc.h directly; use assembler.h instead.
#endif
#include "platform/assert.h"
#include "platform/utils.h"
#include "vm/constants_dbc.h"
#include "vm/cpu.h"
#include "vm/hash_map.h"
#include "vm/object.h"
#include "vm/simulator.h"
namespace dart {
// Dummy declaration to make things compile.
class Address : public ValueObject {
private:
Address();
};
class Label : public ValueObject {
public:
Label() : position_(0) { }
~Label() {
// Assert if label is being destroyed with unresolved branches pending.
ASSERT(!IsLinked());
}
// Returns the position for bound and linked labels. Cannot be used
// for unused labels.
intptr_t Position() const {
ASSERT(!IsUnused());
return IsBound() ? -position_ - kWordSize : position_ - kWordSize;
}
bool IsBound() const { return position_ < 0; }
bool IsUnused() const { return position_ == 0; }
bool IsLinked() const { return position_ > 0; }
private:
intptr_t position_;
void Reinitialize() {
position_ = 0;
}
void BindTo(intptr_t position) {
ASSERT(!IsBound());
position_ = -position - kWordSize;
ASSERT(IsBound());
}
void LinkTo(intptr_t position) {
ASSERT(!IsBound());
position_ = position + kWordSize;
ASSERT(IsLinked());
}
friend class Assembler;
DISALLOW_COPY_AND_ASSIGN(Label);
};
class Assembler : public ValueObject {
public:
explicit Assembler(bool use_far_branches = false)
: buffer_(),
comments_() {
}
~Assembler() { }
void Bind(Label* label);
void Jump(Label* label);
// Misc. functionality
intptr_t CodeSize() const { return buffer_.Size(); }
intptr_t prologue_offset() const { return 0; }
// Count the fixups that produce a pointer offset, without processing
// the fixups.
intptr_t CountPointerOffsets() const { return 0; }
const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const {
ASSERT(buffer_.pointer_offsets().length() == 0); // No pointers in code.
return buffer_.pointer_offsets();
}
ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; }
RawObjectPool* MakeObjectPool() {
return object_pool_wrapper_.MakeObjectPool();
}
void FinalizeInstructions(const MemoryRegion& region) {
buffer_.FinalizeInstructions(region);
}
// Debugging and bringup support.
void Stop(const char* message);
void Unimplemented(const char* message);
void Untested(const char* message);
void Unreachable(const char* message);
static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
static bool EmittingComments();
const Code::Comments& GetCodeComments() const;
static const char* RegisterName(Register reg);
static const char* FpuRegisterName(FpuRegister reg) {
return "?";
}
static uword GetBreakInstructionFiller() {
return Bytecode::kTrap;
}
static bool IsSafe(const Object& value) { return true; }
static bool IsSafeSmi(const Object& value) { return false; }
// Bytecodes.
#define DECLARE_EMIT(Name, Signature, Fmt0, Fmt1, Fmt2) \
void Name(PARAMS_##Signature);
#define PARAMS_0
#define PARAMS_A_D uintptr_t ra, uintptr_t rd
#define PARAMS_D uintptr_t rd
#define PARAMS_A_B_C uintptr_t ra, uintptr_t rb, uintptr_t rc
#define PARAMS_A uintptr_t ra
#define PARAMS_X intptr_t x
#define PARAMS_T intptr_t x
#define PARAMS_A_X uintptr_t ra, intptr_t x
BYTECODES_LIST(DECLARE_EMIT)
#undef PARAMS_0
#undef PARAMS_A_D
#undef PARAMS_D
#undef PARAMS_A_B_C
#undef PARAMS_A
#undef PARAMS_X
#undef PARAMS_T
#undef PARAMS_A_X
#undef DECLARE_EMIT
void Emit(int32_t value);
void PushConstant(const Object& obj);
void LoadConstant(uintptr_t ra, const Object& obj);
intptr_t AddConstant(const Object& obj);
private:
AssemblerBuffer buffer_; // Contains position independent code.
ObjectPoolWrapper object_pool_wrapper_;
class CodeComment : public ZoneAllocated {
public:
CodeComment(intptr_t pc_offset, const String& comment)
: pc_offset_(pc_offset), comment_(comment) { }
intptr_t pc_offset() const { return pc_offset_; }
const String& comment() const { return comment_; }
private:
intptr_t pc_offset_;
const String& comment_;
DISALLOW_COPY_AND_ASSIGN(CodeComment);
};
GrowableArray<CodeComment*> comments_;
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(Assembler);
};
} // namespace dart
#endif // VM_ASSEMBLER_DBC_H_
+3
View File
@@ -11,6 +11,8 @@
namespace dart {
// TODO(vegorov) assembler part of this test is not implemented.
#if !defined(TARGET_ARCH_DBC)
ASSEMBLER_TEST_EXTERN(StoreIntoObject);
ASSEMBLER_TEST_RUN(StoreIntoObject, test) {
@@ -60,5 +62,6 @@ ASSEMBLER_TEST_RUN(StoreIntoObject, test) {
EXPECT(old_array.raw() == grow_new_array.data());
EXPECT(!thread->StoreBufferContains(grow_new_array.raw()));
}
#endif
} // namespace dart
+6
View File
@@ -65,9 +65,15 @@ class AtomicOperations : public AllStatic {
} // namespace dart
#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
#define USING_SIMULATOR_ATOMICS
#endif
#if defined(USING_SIMULATOR_ATOMICS)
// We need to use the simulator to ensure that atomic operations are observed
// both in C++ and in generated code if the simulator is active.
#include "vm/atomic_simulator.h"
#endif
#if defined(TARGET_OS_ANDROID)
#include "vm/atomic_android.h"
+2 -2
View File
@@ -41,7 +41,7 @@ inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
}
#if !defined(USING_SIMULATOR)
#if !defined(USING_SIMULATOR_ATOMICS)
inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
uword old_value,
uword new_value) {
@@ -54,7 +54,7 @@ inline uint32_t AtomicOperations::CompareAndSwapUint32(uint32_t* ptr,
uint32_t new_value) {
return __sync_val_compare_and_swap(ptr, old_value, new_value);
}
#endif // !defined(USING_SIMULATOR)
#endif // !defined(USING_SIMULATOR_ATOMICS)
} // namespace dart
+2 -2
View File
@@ -46,7 +46,7 @@ inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
}
#if !defined(USING_SIMULATOR)
#if !defined(USING_SIMULATOR_ATOMICS)
inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
uword old_value,
uword new_value) {
@@ -59,7 +59,7 @@ inline uint32_t AtomicOperations::CompareAndSwapUint32(uint32_t* ptr,
uint32_t new_value) {
return __sync_val_compare_and_swap(ptr, old_value, new_value);
}
#endif // !defined(USING_SIMULATOR)
#endif // !defined(USING_SIMULATOR_ATOMICS)
} // namespace dart
+2 -2
View File
@@ -41,7 +41,7 @@ inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
}
#if !defined(USING_SIMULATOR)
#if !defined(USING_SIMULATOR_ATOMICS)
inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
uword old_value,
uword new_value) {
@@ -54,7 +54,7 @@ inline uint32_t AtomicOperations::CompareAndSwapUint32(uint32_t* ptr,
uint32_t new_value) {
return __sync_val_compare_and_swap(ptr, old_value, new_value);
}
#endif // !defined(USING_SIMULATOR)
#endif // !defined(USING_SIMULATOR_ATOMICS)
} // namespace dart
+2 -2
View File
@@ -11,7 +11,7 @@
namespace dart {
#if defined(USING_SIMULATOR)
#if defined(USING_SIMULATOR_ATOMICS)
// Forward atomic operations to the simulator if the simulator is active.
inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
uword old_value,
@@ -25,7 +25,7 @@ inline uint32_t AtomicOperations::CompareAndSwapUint32(uint32_t* ptr,
uint32_t new_value) {
return Simulator::CompareExchangeUint32(ptr, old_value, new_value);
}
#endif // defined(USING_SIMULATOR)
#endif // defined(USING_SIMULATOR_ATOMICS)
} // namespace dart
+22 -2
View File
@@ -654,6 +654,7 @@ static void CheckResultError(const Object& result) {
}
#if !defined(TARGET_ARCH_DBC)
// Gets called from debug stub when code reaches a breakpoint
// set on a runtime stub call.
DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
@@ -674,6 +675,20 @@ DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
}
arguments.SetReturn(orig_stub);
}
#else
// Gets called from the simulator when the breakpoint is reached.
DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
if (!FLAG_support_debugger) {
UNREACHABLE();
return;
}
const Error& error = Error::Handle(isolate->debugger()->SignalBpReached());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
}
}
#endif // !defined(TARGET_ARCH_DBC)
DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) {
@@ -956,6 +971,8 @@ DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerTwoArgs, 3) {
// Arg2: Arguments descriptor array.
// Returns: target function to call.
DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) {
// DBC does not use megamorphic calls right now.
#if !defined(TARGET_ARCH_DBC)
const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
const Object& ic_data_or_cache = Object::Handle(zone, arguments.ArgAt(1));
const Array& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(2));
@@ -1013,6 +1030,9 @@ DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) {
cache.Insert(class_id, target_function);
}
arguments.SetReturn(target_function);
#else
UNREACHABLE();
#endif // !defined(TARGET_ARCH_DBC)
}
@@ -1192,7 +1212,7 @@ DEFINE_RUNTIME_ENTRY(InvokeClosureNoSuchMethod, 3) {
DEFINE_RUNTIME_ENTRY(StackOverflow, 0) {
#if defined(USING_SIMULATOR)
uword stack_pos = Simulator::Current()->get_register(SPREG);
uword stack_pos = Simulator::Current()->get_sp();
#else
uword stack_pos = Thread::GetCurrentStackPointer();
#endif
@@ -1204,7 +1224,7 @@ DEFINE_RUNTIME_ENTRY(StackOverflow, 0) {
// If an interrupt happens at the same time as a stack overflow, we
// process the stack overflow now and leave the interrupt for next
// time.
if (stack_pos < thread->saved_stack_limit()) {
if (IsCalleeFrameOf(thread->saved_stack_limit(), stack_pos)) {
// Use the preallocated stack overflow exception to avoid calling
// into dart code.
const Instance& exception =
+106
View File
@@ -0,0 +1,106 @@
// Copyright (c) 2016, 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/globals.h" // Needed here to get TARGET_ARCH_DBC.
#if defined(TARGET_ARCH_DBC)
#include "vm/code_patcher.h"
#include "vm/flow_graph_compiler.h"
#include "vm/instructions.h"
#include "vm/object.h"
namespace dart {
RawCode* CodePatcher::GetStaticCallTargetAt(uword return_address,
const Code& code) {
ASSERT(code.ContainsInstructionAt(return_address));
CallPattern call(return_address, code);
return call.TargetCode();
}
void CodePatcher::PatchStaticCallAt(uword return_address,
const Code& code,
const Code& new_target) {
ASSERT(code.ContainsInstructionAt(return_address));
CallPattern call(return_address, code);
call.SetTargetCode(new_target);
}
void CodePatcher::InsertDeoptimizationCallAt(uword start, uword target) {
// The inserted call should not overlap the lazy deopt jump code.
ASSERT(start + CallPattern::DeoptCallPatternLengthInBytes() <= target);
CallPattern::InsertDeoptCallAt(start, target);
}
RawCode* CodePatcher::GetInstanceCallAt(uword return_address,
const Code& code,
ICData* ic_data) {
ASSERT(code.ContainsInstructionAt(return_address));
CallPattern call(return_address, code);
if (ic_data != NULL) {
*ic_data = call.IcData();
}
return call.TargetCode();
}
intptr_t CodePatcher::InstanceCallSizeInBytes() {
UNREACHABLE();
return 0;
}
RawFunction* CodePatcher::GetUnoptimizedStaticCallAt(
uword return_address, const Code& code, ICData* ic_data_result) {
ASSERT(code.ContainsInstructionAt(return_address));
CallPattern static_call(return_address, code);
ICData& ic_data = ICData::Handle();
ic_data ^= static_call.IcData();
if (ic_data_result != NULL) {
*ic_data_result = ic_data.raw();
}
return ic_data.GetTargetAt(0);
}
void CodePatcher::PatchSwitchableCallAt(uword return_address,
const Code& code,
const ICData& ic_data,
const MegamorphicCache& cache,
const Code& lookup_stub) {
ASSERT(code.ContainsInstructionAt(return_address));
SwitchableCallPattern call(return_address, code);
ASSERT(call.cache() == ic_data.raw());
call.SetLookupStub(lookup_stub);
call.SetCache(cache);
}
void CodePatcher::PatchNativeCallAt(uword return_address,
const Code& code,
NativeFunction target,
const Code& trampoline) {
ASSERT(code.ContainsInstructionAt(return_address));
NativeCallPattern call(return_address, code);
call.set_target(trampoline);
call.set_native_function(target);
}
RawCode* CodePatcher::GetNativeCallAt(uword return_address,
const Code& code,
NativeFunction* target) {
ASSERT(code.ContainsInstructionAt(return_address));
NativeCallPattern call(return_address, code);
*target = call.native_function();
return call.target();
}
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+490
View File
@@ -0,0 +1,490 @@
// Copyright (c) 2016, 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 VM_CONSTANTS_DBC_H_
#define VM_CONSTANTS_DBC_H_
#include "platform/globals.h"
#include "platform/assert.h"
#include "platform/utils.h"
namespace dart {
// List of Dart Bytecode instructions.
//
// INTERPRETER STATE
//
// current frame info (see stack_frame_dbc.h for layout)
// v-----^-----v
// ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~
// ~ | ~ ~ | FP[0] | FP[1] | ~ ~ | SP[-1]| SP[0] |
// ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~
// ^ ^
// FP SP
//
//
// The state of execution is captured in few interpreter registers:
//
// FP - base of the current frame
// SP - top of the stack (TOS) for the current frame
// PP - object pool for the currently execution function
//
// Frame info stored below FP additionally contains pointers to the currently
// executing function and code (see stack_frame_dbc.h for more information).
//
// In the unoptimized code most of bytecodes take operands implicitly from
// stack and store results again on the stack. Constant operands are usually
// taken from the object pool by index.
//
// ENCODING
//
// Each instruction is a 32-bit integer with opcode stored in the least
// significant byte. The following operand encodings are used:
//
// 0........8.......16.......24.......32
// +--------+--------+--------+--------+
// | opcode |~~~~~~~~~~~~~~~~~~~~~~~~~~| 0: no operands
// +--------+--------+--------+--------+
//
// +--------+--------+--------+--------+
// | opcode | A |~~~~~~~~~~~~~~~~~| A: single unsigned 8-bit operand
// +--------+--------+--------+--------+
//
// +--------+--------+--------+--------+
// | opcode | A | D | A_D: unsigned 8-bit operand and
// +--------+--------+--------+--------+ unsigned 16-bit operand
//
// +--------+--------+--------+--------+
// | opcode | A | X | A_X: unsigned 8-bit operand and
// +--------+--------+--------+--------+ signed 16-bit operand
//
// +--------+--------+--------+--------+
// | opcode |~~~~~~~~| D | D: unsigned 16-bit operand
// +--------+--------+--------+--------+
//
// +--------+--------+--------+--------+
// | opcode |~~~~~~~~| X | X: signed 16-bit operand
// +--------+--------+--------+--------+
//
// +--------+--------+--------+--------+
// | opcode | A | B | C | A_B_C: 3 unsigned 8-bit operands
// +--------+--------+--------+--------+
//
// +--------+--------+--------+--------+
// | opcode | T | T: signed 24-bit operand
// +--------+--------+--------+--------+
//
//
// INSTRUCTIONS
//
// - Trap
//
// Unreachable instruction.
//
// - Compile
//
// Compile current function and start executing newly produced code
// (used to implement LazyCompileStub);
//
// - Intrinsic id
//
// Execute intrinsic with the given id. If intrinsic returns true then
// return from the current function to the caller passing value produced
// by the intrinsic as a result;
//
// - Drop1; DropR n; Drop n
//
// Drop 1 or n values from the stack, if instruction is DropR push the first
// dropped value to the stack;
//
// - Jump target
//
// Jump to the given target. Target is specified as offset from the PC of the
// jump instruction.
//
// - Return R; ReturnTOS
//
// Return to the caller using either a value from the given register or a
// value from the top-of-stack as a result.
//
// Note: return instruction knows how many arguments to remove from the
// stack because it can look at the call instruction at caller's PC and
// take argument count from it.
//
// - Move rA, rX
//
// FP[rA] <- FP[rX]
// Note: rX is signed so it can be used to address parameters which are
// at negative indices with respect to FP.
//
// - Push rX
//
// Push FP[rX] to the stack.
//
// - LoadConstant rA, D; PushConstant D
//
// Load value at index D from constant pool into FP[rA] or push it onto the
// stack.
//
// - StoreLocal rX; PopLocal rX
//
// Store top of the stack into FP[rX] and pop it if needed.
//
// - StaticCall ArgC, D
//
// Invoke function in SP[0] with arguments SP[-(1+ArgC)], ..., SP[-1] and
// argument descriptor PP[D].
//
// - InstanceCall ArgC, D; InstanceCall2 ArgC, D; InstanceCall3 ArgC, D
//
// Lookup and invoke method using ICData in PP[D] with arguments
// SP[-(1+ArgC)], ..., SP[-1].
//
// - NativeCall, NativeBootstrapCall
//
// Invoke native function SP[-1] with argc_tag SP[0].
//
// - AddTOS; SubTOS; MulTOS; BitOrTOS; BitAndTOS; EqualTOS; LessThanTOS;
// GreaterThanTOS;
//
// Smi fast-path for a corresponding method. Checks if SP[0] and SP[-1] are
// both smis and result of SP[0] <op> SP[-1] is a smi - if this is true
// then pops operands and pushes result on the stack and skips the next
// instruction (which implements a slow path fallback).
//
// - StoreStaticTOS D
//
// Stores TOS into the static field PP[D].
//
// - PushStatic
//
// Pushes value of the static field PP[D] on to the stack.
//
// - InitStaticTOS
//
// Takes static field from TOS and ensures that it is initialized.
//
// - IfNeStrictTOS; IfEqStrictTOS; IfNeStrictNumTOS; IfEqStrictNumTOS
//
// Skips the next instruction unless the given condition holds. 'Num'
// variants perform number check while non-Num variants just compare
// RawObject pointers.
//
// Used to implement conditional jump:
//
// IfNeStrictTOS
// Jump T ;; jump if not equal
//
// - CreateArrayTOS
//
// Allocate array of length SP[0] with type arguments SP[-1].
//
// - Allocate D
//
// Allocate object of class PP[D] with no type arguments.
//
// - AllocateT
//
// Allocate object of class SP[0] with type arguments SP[-1].
//
// - StoreIndexedTOS
//
// Store SP[0] into array SP[-2] at index SP[-1]. No typechecking is done.
// SP[-2] is assumed to be a RawArray, SP[-1] to be a smi.
//
// - StoreField rA, B, rC
//
// Store value FP[rC] into object FP[rA] at offset (in words) B.
//
// - StoreFieldTOS D
//
// Store value SP[0] into object SP[-1] at offset (in words) D.
//
// - LoadField rA, rB, C
//
// Load value at offset (in words) C from object FP[rB] into FP[rA].
//
// - LoadFieldTOS D
//
// Push value at offset (in words) D from object SP[0].
//
// - BooleanNegateTOS
//
// SP[0] = !SP[0]
//
// - Throw A
//
// Throw (Rethrow if A != 0) exception. Exception object and stack object
// are taken from TOS.
//
// - Entry A, B, rC
//
// Function prologue for the function with no optional or named arguments:
// A - expected number of positional arguments;
// B - number of local slots to reserve;
// rC - specifies context register to initialize with empty context.
//
// - EntryOpt A, B, C
//
// Function prologue for the function with optional or named arguments:
// A - expected number of positional arguments;
// B - number of optional arguments;
// C - number of named arguments;
//
// Only one of B and C can be not 0.
//
// If B is not 0 then EntryOpt bytecode is followed by B LoadConstant
// bytecodes specifying default values for optional arguments.
//
// If C is not 0 then EntryOpt is followed by 2 * B LoadConstant bytecodes.
// Bytecode at 2 * i specifies name of the i-th named argument and at
// 2 * i + 1 default value. rA part of the LoadConstant bytecode specifies
// the location of the parameter on the stack. Here named arguments are
// sorted alphabetically to enable linear matching similar to how function
// prologues are implemented on other architectures.
//
// Note: Unlike Entry bytecode EntryOpt does not setup the frame for
// local variables this is done by a separate bytecode Frame.
//
// - Frame D
//
// Reserve and initialize with null space for D local variables.
//
// - SetFrame A
//
// Reinitialize SP assuming that current frame has size A.
// Used to drop temporaries from the stack in the exception handler.
//
// - AllocateContext D
//
// Allocate Context object assuming for D context variables.
//
// - CloneContext
//
// Clone context stored in TOS.
//
// - MoveSpecial rA, D
//
// Copy special values from inside interpreter to FP[rA]. Currently only
// used to pass exception object (D = 0) and stack trace object (D = 1) to
// catch handler.
//
// - InstantiateType D
//
// Instantiate type PP[D] with instantiator type arguments SP[0].
//
// - InstantiateTypeArgumentsTOS D
//
// Instantiate type arguments PP[D] with instantiator SP[0].
//
// - AssertAssignable D
//
// Assert that SP[-3] is assignable to variable named SP[0] of type
// SP[-1] with type arguments SP[-2] using SubtypeTestCache PP[D].
//
// - AssertBoolean A
//
// Assert that TOS is a boolean (A = 1) or that TOS is not null (A = 0).
//
// - CheckStack
//
// Compare SP against isolate stack limit and call StackOverflow handler if
// necessary.
//
// - DebugStep, DebugBreak A
//
// Debugger support. DebugBreak is bytecode that can be patched into the
// instruction stream to trigger in place breakpoint.
//
// When patching instance or static call with DebugBreak we set A to
// match patched call's argument count so that Return instructions continue
// to work.
//
// TODO(vegorov) the way we replace calls with DebugBreak does not work
// with our smi fast paths because DebugBreak is simply skipped.
//
// BYTECODE LIST FORMAT
//
// Bytecode list below is specified using the following format:
//
// V(BytecodeName, OperandForm, Op1, Op2, Op3)
//
// - OperandForm specifies operand encoding and should be one of 0, A, T, A_D,
// A_X, X, D (see ENCODING section above).
//
// - Op1, Op2, Op2 specify operand meaning. Possible values:
//
// ___ ignored / non-existent operand
// num immediate operand
// lit constant literal from object pool
// reg register (unsigned FP relative local)
// xeg x-register (signed FP relative local)
// tgt jump target relative to the PC of the current instruction
//
// TODO(vegorov) jump targets should be encoded relative to PC of the next
// instruction because PC is incremeted immediately after fetch
// and before decoding.
//
#define BYTECODES_LIST(V) \
V(Trap, 0, ___, ___, ___) \
V(Compile, 0, ___, ___, ___) \
V(Intrinsic, A, num, ___, ___) \
V(Drop1, 0, ___, ___, ___) \
V(DropR, A, num, ___, ___) \
V(Drop, A, num, ___, ___) \
V(Jump, T, tgt, ___, ___) \
V(Return, A, num, ___, ___) \
V(ReturnTOS, 0, ___, ___, ___) \
V(Move, A_X, reg, xeg, ___) \
V(Push, X, xeg, ___, ___) \
V(LoadConstant, A_D, reg, lit, ___) \
V(PushConstant, D, lit, ___, ___) \
V(StoreLocal, X, xeg, ___, ___) \
V(PopLocal, X, xeg, ___, ___) \
V(StaticCall, A_D, num, num, ___) \
V(InstanceCall, A_D, num, num, ___) \
V(InstanceCall2, A_D, num, num, ___) \
V(InstanceCall3, A_D, num, num, ___) \
V(NativeCall, 0, ___, ___, ___) \
V(NativeBootstrapCall, 0, ___, ___, ___) \
V(AddTOS, 0, ___, ___, ___) \
V(SubTOS, 0, ___, ___, ___) \
V(MulTOS, 0, ___, ___, ___) \
V(BitOrTOS, 0, ___, ___, ___) \
V(BitAndTOS, 0, ___, ___, ___) \
V(EqualTOS, 0, ___, ___, ___) \
V(LessThanTOS, 0, ___, ___, ___) \
V(GreaterThanTOS, 0, ___, ___, ___) \
V(StoreStaticTOS, D, lit, ___, ___) \
V(PushStatic, D, lit, ___, ___) \
V(InitStaticTOS, 0, ___, ___, ___) \
V(IfNeStrictTOS, 0, ___, ___, ___) \
V(IfEqStrictTOS, 0, ___, ___, ___) \
V(IfNeStrictNumTOS, 0, ___, ___, ___) \
V(IfEqStrictNumTOS, 0, ___, ___, ___) \
V(CreateArrayTOS, 0, ___, ___, ___) \
V(Allocate, D, lit, ___, ___) \
V(AllocateT, 0, ___, ___, ___) \
V(StoreIndexedTOS, 0, ___, ___, ___) \
V(StoreField, A_B_C, reg, reg, reg) \
V(StoreFieldTOS, D, num, ___, ___) \
V(LoadField, A_B_C, reg, reg, reg) \
V(LoadFieldTOS, D, num, ___, ___) \
V(BooleanNegateTOS, 0, ___, ___, ___) \
V(Throw, A, num, ___, ___) \
V(Entry, A_B_C, num, num, num) \
V(EntryOpt, A_B_C, num, num, num) \
V(Frame, D, num, ___, ___) \
V(SetFrame, A, num, ___, num) \
V(AllocateContext, D, num, ___, ___) \
V(CloneContext, 0, ___, ___, ___) \
V(MoveSpecial, A_D, reg, num, ___) \
V(InstantiateType, D, lit, ___, ___) \
V(InstantiateTypeArgumentsTOS, A_D, num, lit, ___) \
V(AssertAssignable, D, num, lit, ___) \
V(AssertBoolean, A, num, ___, ___) \
V(CheckStack, 0, ___, ___, ___) \
V(DebugStep, 0, ___, ___, ___) \
V(DebugBreak, A, num, ___, ___) \
typedef uint32_t Instr;
class Bytecode {
public:
enum Opcode {
#define DECLARE_BYTECODE(name, encoding, op1, op2, op3) k##name,
BYTECODES_LIST(DECLARE_BYTECODE)
#undef DECLARE_BYTECODE
};
static const intptr_t kOpShift = 0;
static const intptr_t kAShift = 8;
static const intptr_t kAMask = 0xFF;
static const intptr_t kBShift = 16;
static const intptr_t kBMask = 0xFF;
static const intptr_t kCShift = 24;
static const intptr_t kCMask = 0xFF;
static const intptr_t kDShift = 16;
static const intptr_t kDMask = 0xFFFF;
static Instr Encode(Opcode op, uintptr_t a, uintptr_t b, uintptr_t c) {
ASSERT((a & kAMask) == a);
ASSERT((b & kBMask) == b);
ASSERT((c & kCMask) == c);
return op | (a << kAShift) | (b << kBShift) | (c << kCShift);
}
static Instr Encode(Opcode op, uintptr_t a, uintptr_t d) {
ASSERT((a & kAMask) == a);
ASSERT((d & kDMask) == d);
return op | (a << kAShift) | (d << kDShift);
}
static Instr EncodeSigned(Opcode op, uintptr_t a, intptr_t x) {
ASSERT((a & kAMask) == a);
ASSERT((x << kDShift) >> kDShift == x);
return op | (a << kAShift) | (x << kDShift);
}
static Instr EncodeSigned(Opcode op, intptr_t x) {
ASSERT((x << kAShift) >> kAShift == x);
return op | (x << kAShift);
}
static Instr Encode(Opcode op) {
return op;
}
DART_FORCE_INLINE static uint8_t DecodeA(Instr bc) {
return (bc >> kAShift) & kAMask;
}
DART_FORCE_INLINE static uint16_t DecodeD(Instr bc) {
return (bc >> kDShift) & kDMask;
}
DART_FORCE_INLINE static Opcode DecodeOpcode(Instr bc) {
return static_cast<Opcode>(bc & 0xFF);
}
DART_FORCE_INLINE static uint8_t DecodeArgc(Instr call) {
#if defined(DEBUG)
const Opcode op = DecodeOpcode(call);
ASSERT((op == Bytecode::kStaticCall) ||
(op == Bytecode::kInstanceCall) ||
(op == Bytecode::kInstanceCall2) ||
(op == Bytecode::kInstanceCall3) ||
(op == Bytecode::kDebugBreak));
#endif
return (call >> 8) & 0xFF;
}
};
// Various dummy declarations to make shared code compile.
// TODO(vegorov) we need to prune away as much dead code as possible instead
// of just making it compile.
typedef int16_t Register;
const int16_t FPREG = 0;
const int16_t SPREG = 1;
const intptr_t kNumberOfCpuRegisters = 20;
const intptr_t kDartAvailableCpuRegs = 0;
const intptr_t kNoRegister = -1;
const intptr_t kReservedCpuRegisters = 0;
const intptr_t ARGS_DESC_REG = 0;
const intptr_t CODE_REG = 0;
const intptr_t kExceptionObjectReg = 0;
const intptr_t kStackTraceObjectReg = 0;
const intptr_t CTX = 0;
enum FpuRegister { kNoFpuRegister = -1, kFakeFpuRegister };
const FpuRegister FpuTMP = kFakeFpuRegister;
const intptr_t kNumberOfFpuRegisters = 1;
enum Condition { EQ, NE };
} // namespace dart
#endif // VM_CONSTANTS_DBC_H_
+2
View File
@@ -33,6 +33,8 @@ class CPU : public AllStatic {
#include "vm/cpu_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/cpu_mips.h"
#elif defined(TARGET_ARCH_DBC)
#include "vm/cpu_dbc.h"
#else
#error Unknown architecture.
#endif
+26
View File
@@ -0,0 +1,26 @@
// Copyright (c) 2016, 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/globals.h"
#if defined(TARGET_ARCH_DBC)
#include "vm/cpu.h"
namespace dart {
void CPU::FlushICache(uword start, uword size) {
// Nothing to do.
}
const char* CPU::Id() {
return "dbc";
}
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+30
View File
@@ -0,0 +1,30 @@
// Copyright (c) 2016, 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 VM_CPU_DBC_H_
#define VM_CPU_DBC_H_
#include "vm/allocation.h"
#include "vm/simulator.h"
namespace dart {
class HostCPUFeatures: public AllStatic {
public:
static const char* hardware() { return "simdbc"; }
};
class TargetCPUFeatures : public AllStatic {
public:
static void InitOnce() {}
static void Cleanup() {}
static bool double_truncate_round_supported() {
return true;
}
};
} // namespace dart
#endif // VM_CPU_DBC_H_
+2
View File
@@ -32,6 +32,8 @@ UNIT_TEST_CASE(Id) {
#else // defined(HOST_ARCH_MIPS)
EXPECT_STREQ("simmips", CPU::Id());
#endif // defined(HOST_ARCH_MIPS)
#elif defined(TARGET_ARCH_DBC)
EXPECT_STREQ("dbc", CPU::Id());
#else
#error Architecture was not detected as supported by Dart.
#endif
+2
View File
@@ -9,11 +9,13 @@
namespace dart {
#if !defined(TARGET_ARCH_DBC)
UNIT_TEST_CASE(GetCpuModelTest) {
const char* cpumodel = CpuInfo::GetCpuModel();
EXPECT_NE(strlen(cpumodel), 0UL);
// caller is responsible for deleting the returned cpumodel string.
free(const_cast<char*>(cpumodel));
}
#endif
} // namespace dart
+8 -1
View File
@@ -103,15 +103,22 @@ RawObject* DartEntry::InvokeFunction(const Function& function,
}
}
// Now Call the invoke stub which will invoke the dart function.
#if !defined(TARGET_ARCH_DBC)
invokestub entrypoint = reinterpret_cast<invokestub>(
StubCode::InvokeDartCode_entry()->EntryPoint());
#endif
const Code& code = Code::Handle(zone, function.CurrentCode());
ASSERT(!code.IsNull());
ASSERT(thread->no_callback_scope_depth() == 0);
ScopedIsolateStackLimits stack_limit(thread);
SuspendLongJumpScope suspend_long_jump_scope(thread);
TransitionToGenerated transition(thread);
#if defined(USING_SIMULATOR)
#if defined(TARGET_ARCH_DBC)
return Simulator::Current()->Call(code,
arguments_descriptor,
arguments,
thread);
#elif defined(USING_SIMULATOR)
return bit_copy<RawObject*, int64_t>(Simulator::Current()->Call(
reinterpret_cast<intptr_t>(entrypoint),
reinterpret_cast<intptr_t>(&code),
+14
View File
@@ -86,6 +86,19 @@ class ArgumentsDescriptor : public ValueObject {
static RawArray* NewNonCached(intptr_t count, bool canonicalize = true);
// Used by Simulator to parse argument descriptors.
static intptr_t name_index(intptr_t index) {
return kFirstNamedEntryIndex +
(index * kNamedEntrySize) +
kNameOffset;
}
static intptr_t position_index(intptr_t index) {
return kFirstNamedEntryIndex +
(index * kNamedEntrySize) +
kPositionOffset;
}
const Array& array_;
// A cache of VM heap allocated arguments descriptors.
@@ -93,6 +106,7 @@ class ArgumentsDescriptor : public ValueObject {
friend class SnapshotReader;
friend class SnapshotWriter;
friend class Simulator;
DISALLOW_COPY_AND_ASSIGN(ArgumentsDescriptor);
};
+20 -14
View File
@@ -231,7 +231,9 @@ void Breakpoint::PrintJSON(JSONStream* stream) {
void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_));
#if !defined(TARGET_ARCH_DBC)
visitor->VisitPointer(reinterpret_cast<RawObject**>(&saved_value_));
#endif
}
@@ -859,24 +861,25 @@ intptr_t ActivationFrame::NumLocalVariables() {
}
DART_FORCE_INLINE static RawObject* GetVariableValue(uword addr) {
return *reinterpret_cast<RawObject**>(addr);
}
RawObject* ActivationFrame::GetParameter(intptr_t index) {
intptr_t num_parameters = function().num_fixed_parameters();
ASSERT(0 <= index && index < num_parameters);
intptr_t reverse_index = num_parameters - index;
if (function().NumOptionalParameters() > 0) {
// If the function has optional parameters, the first positional parameter
// can be in a number of places in the caller's frame depending on how many
// were actually supplied at the call site, but they are copied to a fixed
// place in the callee's frame.
uword var_address = fp() + ((kFirstLocalSlotFromFp - index) * kWordSize);
return reinterpret_cast<RawObject*>(
*reinterpret_cast<uword*>(var_address));
return GetVariableValue(LocalVarAddress(fp(),
(kFirstLocalSlotFromFp - index)));
} else {
uword var_address = fp() + (kParamEndSlotFromFp * kWordSize)
+ (reverse_index * kWordSize);
return reinterpret_cast<RawObject*>(
*reinterpret_cast<uword*>(var_address));
intptr_t reverse_index = num_parameters - index;
return GetVariableValue(ParamAddress(fp(), reverse_index));
}
}
@@ -889,9 +892,7 @@ RawObject* ActivationFrame::GetClosure() {
RawObject* ActivationFrame::GetStackVar(intptr_t slot_index) {
if (deopt_frame_.IsNull()) {
uword var_address = fp() + slot_index * kWordSize;
return reinterpret_cast<RawObject*>(
*reinterpret_cast<uword*>(var_address));
return GetVariableValue(LocalVarAddress(fp(), slot_index));
} else {
return deopt_frame_.At(deopt_frame_offset_ + slot_index);
}
@@ -1171,7 +1172,12 @@ CodeBreakpoint::CodeBreakpoint(const Code& code,
bpt_location_(NULL),
next_(NULL),
breakpoint_kind_(kind),
saved_value_(Code::null()) {
#if !defined(TARGET_ARCH_DBC)
saved_value_(Code::null())
#else
saved_value_(Bytecode::kTrap)
#endif
{
ASSERT(!code.IsNull());
ASSERT(token_pos_.IsReal());
ASSERT(pc_ != 0);
@@ -2693,11 +2699,11 @@ RawError* Debugger::DebuggerStepCallback() {
if (stepping_fp_ != 0) {
// There is an "interesting frame" set. Only pause at appropriate
// locations in this frame.
if (stepping_fp_ > frame->fp()) {
if (IsCalleeFrameOf(stepping_fp_, frame->fp())) {
// We are i n a callee of the frame we're interested in.
// Ignore this stepping break.
return Error::null();
} else if (frame->fp() > stepping_fp_) {
} else if (IsCalleeFrameOf(frame->fp(), stepping_fp_)) {
// We returned from the "interesting frame", there can be no more
// stepping breaks for it. Pause at the next appropriate location
// and let the user set the "interesting" frame again.
+7
View File
@@ -227,7 +227,14 @@ class CodeBreakpoint {
CodeBreakpoint* next_;
RawPcDescriptors::Kind breakpoint_kind_;
#if !defined(TARGET_ARCH_DBC)
RawCode* saved_value_;
#else
// When running on the DBC interpreter we patch bytecode in place with
// DebugBreak. This is an instruction that was replaced. DebugBreak
// will execute it after the breakpoint.
Instr saved_value_;
#endif
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(CodeBreakpoint);
+5
View File
@@ -282,8 +282,13 @@ static void VerifyStackTrace(Dart_StackTrace trace,
res = Dart_ActivationFrameGetFramePointer(frame, &frame_pointer);
EXPECT_TRUE(res);
if (i > 0) {
#if !defined(TARGET_ARCH_DBC)
// We expect the stack to grow from high to low addresses.
EXPECT_GT(frame_pointer, last_frame_pointer);
#else
// On DBC stack grows upwards from low to high addresses.
EXPECT_LT(frame_pointer, last_frame_pointer);
#endif
}
last_frame_pointer = frame_pointer;
if (i < expected_frames) {
+86
View File
@@ -0,0 +1,86 @@
// Copyright (c) 2016, 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/globals.h"
#if defined(TARGET_ARCH_DBC)
#include "vm/code_patcher.h"
#include "vm/cpu.h"
#include "vm/debugger.h"
#include "vm/instructions.h"
#include "vm/stub_code.h"
namespace dart {
#ifndef PRODUCT
RawCode* CodeBreakpoint::OrigStubAddress() const {
return reinterpret_cast<RawCode*>(static_cast<uintptr_t>(saved_value_));
}
static Instr* CallInstructionFromReturnAddress(uword pc) {
return reinterpret_cast<Instr*>(pc) - 1;
}
void CodeBreakpoint::PatchCode() {
ASSERT(!is_enabled_);
const Code& code = Code::Handle(code_);
const Instructions& instrs = Instructions::Handle(code.instructions());
{
WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
saved_value_ = *CallInstructionFromReturnAddress(pc_);
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall: {
// DebugBreak has an A operand matching the call it replaces.
// This ensures that Return instructions continue to work - as they
// look at calls to figure out how many arguments to drop.
*CallInstructionFromReturnAddress(pc_) =
Bytecode::Encode(Bytecode::kDebugBreak,
Bytecode::DecodeArgc(saved_value_),
0,
0);
break;
}
case RawPcDescriptors::kRuntimeCall: {
*CallInstructionFromReturnAddress(pc_) = Bytecode::kDebugBreak;
break;
}
default:
UNREACHABLE();
}
}
is_enabled_ = true;
}
void CodeBreakpoint::RestoreCode() {
ASSERT(is_enabled_);
const Code& code = Code::Handle(code_);
const Instructions& instrs = Instructions::Handle(code.instructions());
{
WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
case RawPcDescriptors::kRuntimeCall: {
*CallInstructionFromReturnAddress(pc_) = saved_value_;
break;
}
default:
UNREACHABLE();
}
}
is_enabled_ = false;
}
#endif // !PRODUCT
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+5
View File
@@ -660,12 +660,16 @@ class DeoptPcMarkerInstr : public DeoptInstr {
Function& function = Function::Handle(deopt_context->zone());
function ^= deopt_context->ObjectAt(object_table_index_);
if (function.IsNull()) {
// There are no deoptimization stubs on DBC.
#if !defined(TARGET_ARCH_DBC)
*reinterpret_cast<RawObject**>(dest_addr) = deopt_context->is_lazy_deopt()
? StubCode::DeoptimizeLazy_entry()->code()
: StubCode::Deoptimize_entry()->code();
#endif
return;
}
#if !defined(TARGET_ARCH_DBC)
// We don't always have the Code object for the frame's corresponding
// unoptimized code as it may have been collected. Use a stub as the pc
// marker until we can recreate that Code object during deferred
@@ -673,6 +677,7 @@ class DeoptPcMarkerInstr : public DeoptInstr {
// a pc marker.
*reinterpret_cast<RawObject**>(dest_addr) =
StubCode::FrameAwaitingMaterialization_entry()->code();
#endif
deopt_context->DeferPcMarkerMaterialization(object_table_index_, dest_addr);
}
+233
View File
@@ -0,0 +1,233 @@
// Copyright (c) 2016, 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/disassembler.h"
#include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC.
#if defined(TARGET_ARCH_DBC)
#include "platform/assert.h"
#include "vm/constants_dbc.h"
#include "vm/cpu.h"
namespace dart {
static const char* kOpcodeNames[] = {
#define BYTECODE_NAME(name, encoding, op1, op2, op3) #name,
BYTECODES_LIST(BYTECODE_NAME)
#undef BYTECODE_NAME
};
static const size_t kOpcodeCount =
sizeof(kOpcodeNames) / sizeof(kOpcodeNames[0]);
typedef void (*BytecodeFormatter)(char* buffer,
intptr_t size,
uword pc,
uint32_t bc);
typedef void (*Fmt)(char** buf, intptr_t* size, uword pc, int32_t value);
template <typename ValueType>
void FormatOperand(char** buf,
intptr_t* size,
const char* fmt,
ValueType value) {
intptr_t written = OS::SNPrint(*buf, *size, fmt, value);
if (written < *size) {
*buf += written;
*size += written;
} else {
*size = -1;
}
}
static void Fmt___(char** buf, intptr_t* size, uword pc, int32_t value) {}
static void Fmttgt(char** buf, intptr_t* size, uword pc, int32_t value) {
FormatOperand(buf, size, "-> %" Px, pc + (value << 2));
}
static void Fmtlit(char** buf, intptr_t* size, uword pc, int32_t value) {
FormatOperand(buf, size, "k%d", value);
}
static void Fmtreg(char** buf, intptr_t* size, uword pc, int32_t value) {
FormatOperand(buf, size, "r%d", value);
}
static void Fmtxeg(char** buf, intptr_t* size, uword pc, int32_t value) {
FormatOperand(buf, size, "R(%d)", value);
}
static void Fmtnum(char** buf, intptr_t* size, uword pc, int32_t value) {
FormatOperand(buf, size, "#%d", value);
}
static void Apply(char** buf,
intptr_t* size,
uword pc,
Fmt fmt,
int32_t value,
const char* suffix) {
if (*size <= 0) {
return;
}
fmt(buf, size, pc, value);
if (*size > 0) {
FormatOperand(buf, size, "%s", suffix);
}
}
static void Format0(char* buf,
intptr_t size,
uword pc,
uint32_t op,
Fmt op1,
Fmt op2,
Fmt op3) {}
static void FormatT(char* buf,
intptr_t size,
uword pc,
uint32_t op,
Fmt op1,
Fmt op2,
Fmt op3) {
const int32_t x = static_cast<int32_t>(op) >> 8;
Apply(&buf, &size, pc, op1, x, "");
}
static void FormatA(char* buf,
intptr_t size,
uword pc,
uint32_t op,
Fmt op1,
Fmt op2,
Fmt op3) {
const int32_t a = (op & 0xFF00) >> 8;
Apply(&buf, &size, pc, op1, a, "");
}
static void FormatA_D(char* buf,
intptr_t size,
uword pc,
uint32_t op,
Fmt op1,
Fmt op2,
Fmt op3) {
const int32_t a = (op & 0xFF00) >> 8;
const int32_t bc = op >> 16;
Apply(&buf, &size, pc, op1, a, ", ");
Apply(&buf, &size, pc, op2, bc, "");
}
static void FormatA_X(char* buf,
intptr_t size,
uword pc,
uint32_t op,
Fmt op1,
Fmt op2,
Fmt op3) {
const int32_t a = (op & 0xFF00) >> 8;
const int32_t bc = static_cast<int32_t>(op) >> 16;
Apply(&buf, &size, pc, op1, a, ", ");
Apply(&buf, &size, pc, op2, bc, "");
}
static void FormatX(char* buf,
intptr_t size,
uword pc,
uint32_t op,
Fmt op1,
Fmt op2,
Fmt op3) {
const int32_t bc = static_cast<int32_t>(op) >> 16;
Apply(&buf, &size, pc, op1, bc, "");
}
static void FormatD(char* buf,
intptr_t size,
uword pc,
uint32_t op,
Fmt op1,
Fmt op2,
Fmt op3) {
const int32_t bc = op >> 16;
Apply(&buf, &size, pc, op1, bc, "");
}
static void FormatA_B_C(char* buf,
intptr_t size,
uword pc,
uint32_t op,
Fmt op1,
Fmt op2,
Fmt op3) {
const int32_t a = (op >> 8) & 0xFF;
const int32_t b = (op >> 16) & 0xFF;
const int32_t c = (op >> 24) & 0xFF;
Apply(&buf, &size, pc, op1, a, ", ");
Apply(&buf, &size, pc, op2, b, ", ");
Apply(&buf, &size, pc, op3, c, "");
}
#define BYTECODE_FORMATTER(name, encoding, op1, op2, op3) \
static void Format##name(char* buf, intptr_t size, uword pc, uint32_t op) { \
Format##encoding(buf, size, pc, op, Fmt##op1, Fmt##op2, Fmt##op3); \
}
BYTECODES_LIST(BYTECODE_FORMATTER)
#undef BYTECODE_FORMATTER
static const BytecodeFormatter kFormatters[] = {
#define BYTECODE_FORMATTER(name, encoding, op1, op2, op3) &Format##name,
BYTECODES_LIST(BYTECODE_FORMATTER)
#undef BYTECODE_FORMATTER
};
void Disassembler::DecodeInstruction(char* hex_buffer,
intptr_t hex_size,
char* human_buffer,
intptr_t human_size,
int* out_instr_size,
uword pc) {
const uint32_t instr = *reinterpret_cast<uint32_t*>(pc);
const uint8_t opcode = instr & 0xFF;
ASSERT(opcode < kOpcodeCount);
size_t name_size =
OS::SNPrint(human_buffer, human_size, "%-10s\t", kOpcodeNames[opcode]);
human_buffer += name_size;
human_size -= name_size;
kFormatters[opcode](human_buffer, human_size, pc, instr);
OS::SNPrint(hex_buffer, hex_size, "%08x", instr);
if (out_instr_size) {
*out_instr_size = sizeof(uint32_t);
}
}
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+3 -1
View File
@@ -9,7 +9,9 @@
namespace dart {
#ifndef PRODUCT
// TODO(vegorov) this test is disabled on DBC because there is no PopRegister
// method on DBC assembler.
#if !defined(PRODUCT) && !defined(TARGET_ARCH_DBC)
TEST_CASE(Disassembler) {
Assembler assembler;
+10 -4
View File
@@ -5,6 +5,12 @@
#ifndef VM_FLAG_LIST_H_
#define VM_FLAG_LIST_H_
#if defined(TARGET_ARCH_DBC)
#define USING_DBC 1
#else
#define USING_DBC 0
#endif
// List of all flags in the VM.
// Flags can be one of three categories:
// * P roduct flags: Can be set in any of the deployment modes, including in
@@ -70,9 +76,9 @@ P(getter_setter_ratio, int, 13, \
"Ratio of getter/setter usage used for double field unboxing heuristics") \
P(guess_icdata_cid, bool, true, \
"Artificially create type feedback for arithmetic etc. operations") \
P(ic_range_profiling, bool, true, \
P(ic_range_profiling, bool, !USING_DBC, \
"Generate special IC stubs collecting range information ") \
P(interpret_irregexp, bool, false, \
P(interpret_irregexp, bool, USING_DBC, \
"Use irregexp bytecode interpreter") \
P(lazy_dispatchers, bool, true, \
"Generate dispatchers lazily") \
@@ -119,7 +125,7 @@ R(print_ssa_liveranges, false, bool, false, \
"Print live ranges after allocation.") \
C(print_stop_message, false, false, bool, false, \
"Print stop message.") \
R(profiler, false, bool, true, \
R(profiler, false, bool, !USING_DBC, \
"Enable the profiler.") \
P(reorder_basic_blocks, bool, true, \
"Reorder basic blocks") \
@@ -159,7 +165,7 @@ P(truncating_left_shift, bool, true, \
"Optimize left shift to truncate if possible") \
P(use_cha_deopt, bool, true, \
"Use class hierarchy analysis even if it can cause deoptimization.") \
P(use_field_guards, bool, true, \
P(use_field_guards, bool, !USING_DBC, \
"Use field guards and track field types") \
C(use_osr, false, true, bool, true, \
"Use OSR") \
+3
View File
@@ -3499,6 +3499,8 @@ void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) {
load->set_is_immutable(kind != MethodRecognizer::kGrowableArrayLength);
return ReturnDefinition(load);
}
#if !defined(TARGET_ARCH_DBC)
// TODO(vegorov) add bytecode to support this method.
case MethodRecognizer::kClassIDgetID: {
LocalVariable* value_var =
node->scope()->LookupVariable(Symbols::Value(), true);
@@ -3506,6 +3508,7 @@ void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) {
LoadClassIdInstr* load = new(Z) LoadClassIdInstr(value);
return ReturnDefinition(load);
}
#endif
case MethodRecognizer::kGrowableArrayCapacity: {
Value* receiver = Bind(BuildLoadThisVar(node->scope(), token_pos));
LoadFieldInstr* data_load = new(Z) LoadFieldInstr(
+29 -13
View File
@@ -503,7 +503,7 @@ void FlowGraphCompiler::VisitBlocks() {
continue;
}
#if defined(DEBUG)
#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
if (!is_optimizing()) {
FrameStateClear();
}
@@ -557,14 +557,14 @@ void FlowGraphCompiler::VisitBlocks() {
EndCodeSourceRange(instr->token_pos());
}
#if defined(DEBUG)
#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
if (!is_optimizing()) {
FrameStateUpdateWith(instr);
}
#endif
}
#if defined(DEBUG)
#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
ASSERT(is_optimizing() || FrameStateIsSafeToCall());
#endif
}
@@ -1147,6 +1147,9 @@ bool FlowGraphCompiler::TryIntrinsify() {
}
// DBC is very different from other architectures in how it performs instance
// and static calls because it does not use stubs.
#if !defined(TARGET_ARCH_DBC)
void FlowGraphCompiler::GenerateInstanceCall(
intptr_t deopt_id,
TokenPosition token_pos,
@@ -1286,7 +1289,7 @@ void FlowGraphCompiler::GenerateListTypeCheck(Register kClassIdReg,
CheckClassIds(kClassIdReg, args, is_instance_lbl, &unknown);
assembler()->Bind(&unknown);
}
#endif // !defined(TARGET_ARCH_DBC)
void FlowGraphCompiler::EmitComment(Instruction* instr) {
if (!FLAG_support_il_printer || !FLAG_support_disassembler) {
@@ -1301,6 +1304,8 @@ void FlowGraphCompiler::EmitComment(Instruction* instr) {
}
#if !defined(TARGET_ARCH_DBC)
// TODO(vegorov) enable edge-counters on DBC if we consider them beneficial.
bool FlowGraphCompiler::NeedsEdgeCounter(TargetEntryInstr* block) {
// Only emit an edge counter if there is not goto at the end of the block,
// except for the entry block.
@@ -1321,18 +1326,17 @@ static Register AllocateFreeRegister(bool* blocked_registers) {
UNREACHABLE();
return kNoRegister;
}
static uword RegMaskBit(Register reg) {
return ((reg) != kNoRegister) ? (1 << (reg)) : 0;
}
#endif
void FlowGraphCompiler::AllocateRegistersLocally(Instruction* instr) {
ASSERT(!is_optimizing());
instr->InitializeLocationSummary(zone(),
false); // Not optimizing.
// No need to allocate registers based on LocationSummary on DBC as in
// unoptimized mode it's a stack based bytecode just like IR itself.
#if !defined(TARGET_ARCH_DBC)
LocationSummary* locs = instr->locs();
bool blocked_registers[kNumberOfCpuRegisters];
@@ -1422,6 +1426,12 @@ void FlowGraphCompiler::AllocateRegistersLocally(Instruction* instr) {
}
locs->set_out(0, result_location);
}
#endif // !defined(TARGET_ARCH_DBC)
}
static uword RegMaskBit(Register reg) {
return ((reg) != kNoRegister) ? (1 << (reg)) : 0;
}
@@ -1838,6 +1848,9 @@ NOT_IN_PRODUCT(
}
#if !defined(TARGET_ARCH_DBC)
// DBC emits calls very differently from other architectures due to its
// interpreted nature.
void FlowGraphCompiler::EmitPolymorphicInstanceCall(
const ICData& ic_data,
intptr_t argument_count,
@@ -1881,9 +1894,12 @@ void FlowGraphCompiler::EmitPolymorphicInstanceCall(
}
}
}
#endif
#if defined(DEBUG)
#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
// TODO(vegorov) re-enable frame state tracking on DBC. It is
// currently disabled because it relies on LocationSummaries and
// we don't use them during unoptimized compilation on DBC.
void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) {
ASSERT(!is_optimizing());
@@ -1954,7 +1970,7 @@ void FlowGraphCompiler::FrameStateClear() {
ASSERT(!is_optimizing());
frame_state_.TruncateTo(0);
}
#endif
#endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC)
} // namespace dart
+24 -13
View File
@@ -367,6 +367,15 @@ class FlowGraphCompiler : public ValueObject {
// Returns 'true' if regular code generation should be skipped.
bool TryIntrinsify();
void GenerateAssertAssignable(TokenPosition token_pos,
intptr_t deopt_id,
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs);
// DBC emits calls very differently from all other architectures due to its
// interpreted nature.
#if !defined(TARGET_ARCH_DBC)
void GenerateRuntimeCall(TokenPosition token_pos,
intptr_t deopt_id,
const RuntimeEntry& entry,
@@ -390,12 +399,6 @@ class FlowGraphCompiler : public ValueObject {
LocationSummary* locs,
const Function& target);
void GenerateAssertAssignable(TokenPosition token_pos,
intptr_t deopt_id,
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs);
void GenerateInstanceOf(TokenPosition token_pos,
intptr_t deopt_id,
const AbstractType& type,
@@ -426,12 +429,6 @@ class FlowGraphCompiler : public ValueObject {
void GenerateListTypeCheck(Register kClassIdReg,
Label* is_instance_lbl);
void EmitComment(Instruction* instr);
bool NeedsEdgeCounter(TargetEntryInstr* block);
void EmitEdgeCounter(intptr_t edge_id);
void EmitOptimizedInstanceCall(const StubEntry& stub_entry,
const ICData& ic_data,
intptr_t argument_count,
@@ -489,8 +486,15 @@ class FlowGraphCompiler : public ValueObject {
bool needs_number_check,
TokenPosition token_pos);
bool NeedsEdgeCounter(TargetEntryInstr* block);
void EmitEdgeCounter(intptr_t edge_id);
#endif // !defined(TARGET_ARCH_DBC)
void EmitTrySync(Instruction* instr, intptr_t try_index);
void EmitComment(Instruction* instr);
intptr_t StackSize() const;
// Returns assembler label associated with the given block entry.
@@ -637,6 +641,9 @@ class FlowGraphCompiler : public ValueObject {
LocationSummary* locs,
const ICData& ic_data);
// DBC handles type tests differently from all other architectures due
// to its interpreted nature.
#if !defined(TARGET_ARCH_DBC)
// Type checking helper methods.
void CheckClassIds(Register class_id_reg,
const GrowableArray<intptr_t>& class_ids,
@@ -690,6 +697,7 @@ class FlowGraphCompiler : public ValueObject {
void GenerateBoolToJump(Register bool_reg, Label* is_true, Label* is_false);
void CopyParameters();
#endif // !defined(TARGET_ARCH_DBC)
void GenerateInlinedGetter(intptr_t offset);
void GenerateInlinedSetter(intptr_t offset);
@@ -722,7 +730,10 @@ class FlowGraphCompiler : public ValueObject {
return stackmap_table_builder_;
}
#if defined(DEBUG)
// TODO(vegorov) re-enable frame state tracking on DBC. It is
// currently disabled because it relies on LocationSummaries and
// we don't use them during unoptimized compilation on DBC.
#if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
void FrameStateUpdateWith(Instruction* instr);
void FrameStatePush(Definition* defn);
void FrameStatePop(intptr_t count);
+331
View File
@@ -0,0 +1,331 @@
// Copyright (c) 2016, 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/globals.h" // Needed here to get TARGET_ARCH_DBC.
#if defined(TARGET_ARCH_DBC)
#include "vm/flow_graph_compiler.h"
#include "vm/ast_printer.h"
#include "vm/compiler.h"
#include "vm/cpu.h"
#include "vm/dart_entry.h"
#include "vm/deopt_instructions.h"
#include "vm/il_printer.h"
#include "vm/instructions.h"
#include "vm/locations.h"
#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/stack_frame.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
#include "vm/verified_memory.h"
namespace dart {
DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
DEFINE_FLAG(bool, unbox_doubles, true, "Optimize double arithmetic.");
DECLARE_FLAG(bool, enable_simd_inline);
DECLARE_FLAG(bool, use_megamorphic_stub);
DECLARE_FLAG(charp, optimization_filter);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
UNIMPLEMENTED();
}
FlowGraphCompiler::~FlowGraphCompiler() {
// BlockInfos are zone-allocated, so their destructors are not called.
// Verify the labels explicitly here.
for (int i = 0; i < block_info_.length(); ++i) {
ASSERT(!block_info_[i]->jump_label()->IsLinked());
}
}
bool FlowGraphCompiler::SupportsUnboxedDoubles() {
return false;
}
bool FlowGraphCompiler::SupportsUnboxedMints() {
return false;
}
bool FlowGraphCompiler::SupportsUnboxedSimd128() {
return false;
}
bool FlowGraphCompiler::SupportsSinCos() {
return false;
}
bool FlowGraphCompiler::SupportsHardwareDivision() {
return true;
}
bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() {
return false;
}
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
}
void FlowGraphCompiler::ExitIntrinsicMode() {
ASSERT(intrinsic_mode());
intrinsic_mode_ = false;
}
RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
UNIMPLEMENTED();
return TypedData::null();
}
void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler,
intptr_t stub_ix) {
UNIMPLEMENTED();
}
#define __ assembler()->
void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
intptr_t deopt_id,
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs) {
ASSERT(!is_optimizing());
SubtypeTestCache& test_cache = SubtypeTestCache::Handle();
if (!dst_type.IsVoidType() && dst_type.IsInstantiated()) {
test_cache = SubtypeTestCache::New();
}
__ PushConstant(dst_type);
__ PushConstant(dst_name);
__ AssertAssignable(__ AddConstant(test_cache));
AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id, token_pos);
}
void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
if (!is_optimizing()) {
Definition* defn = instr->AsDefinition();
if ((defn != NULL) &&
(defn->tag() != Instruction::kPushArgument) &&
(defn->tag() != Instruction::kStoreIndexed) &&
(defn->tag() != Instruction::kStoreStaticField) &&
(defn->tag() != Instruction::kStoreLocal) &&
(defn->tag() != Instruction::kStoreInstanceField) &&
(defn->tag() != Instruction::kDropTemps) &&
(defn->tag() != Instruction::kPushTemp) &&
!defn->HasTemp()) {
__ Drop1();
}
}
}
void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) {
__ Move(0, -(1 + kParamEndSlotFromFp));
__ LoadField(0, 0, offset / kWordSize);
__ Return(0);
}
void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) {
__ Move(0, -(2 + kParamEndSlotFromFp));
__ Move(1, -(1 + kParamEndSlotFromFp));
__ StoreField(0, offset / kWordSize, 1);
__ LoadConstant(0, Object::Handle());
__ Return(0);
}
void FlowGraphCompiler::EmitFrameEntry() {
const Function& function = parsed_function().function();
const intptr_t num_fixed_params = function.num_fixed_parameters();
const int num_opt_pos_params = function.NumOptionalPositionalParameters();
const int num_opt_named_params = function.NumOptionalNamedParameters();
const int num_params =
num_fixed_params + num_opt_pos_params + num_opt_named_params;
const bool has_optional_params = (num_opt_pos_params != 0) ||
(num_opt_named_params != 0);
const int num_locals = parsed_function().num_stack_locals();
const intptr_t context_index =
-parsed_function().current_context_var()->index() - 1;
if (has_optional_params) {
__ EntryOpt(num_fixed_params, num_opt_pos_params, num_opt_named_params);
} else {
__ Entry(num_fixed_params, num_locals, context_index);
}
if (num_opt_named_params != 0) {
LocalScope* scope = parsed_function().node_sequence()->scope();
// Start by alphabetically sorting the names of the optional parameters.
LocalVariable** opt_param =
zone()->Alloc<LocalVariable*>(num_opt_named_params);
int* opt_param_position = zone()->Alloc<int>(num_opt_named_params);
for (int pos = num_fixed_params; pos < num_params; pos++) {
LocalVariable* parameter = scope->VariableAt(pos);
const String& opt_param_name = parameter->name();
int i = pos - num_fixed_params;
while (--i >= 0) {
LocalVariable* param_i = opt_param[i];
const intptr_t result = opt_param_name.CompareTo(param_i->name());
ASSERT(result != 0);
if (result > 0) break;
opt_param[i + 1] = opt_param[i];
opt_param_position[i + 1] = opt_param_position[i];
}
opt_param[i + 1] = parameter;
opt_param_position[i + 1] = pos;
}
for (intptr_t i = 0; i < num_opt_named_params; i++) {
const int param_pos = opt_param_position[i];
const Instance& value = parsed_function().DefaultParameterValueAt(
param_pos - num_fixed_params);
__ LoadConstant(param_pos, opt_param[i]->name());
__ LoadConstant(param_pos, value);
}
} else if (num_opt_pos_params != 0) {
for (intptr_t i = 0; i < num_opt_pos_params; i++) {
const Object& value = parsed_function().DefaultParameterValueAt(i);
__ LoadConstant(num_fixed_params + i, value);
}
}
ASSERT(num_locals > 0); // There is always at least context_var.
if (has_optional_params) {
ASSERT(!is_optimizing());
__ Frame(num_locals); // Reserve space for locals.
}
if (function.IsClosureFunction()) {
Register reg = context_index;
Register closure_reg = reg;
LocalScope* scope = parsed_function().node_sequence()->scope();
LocalVariable* local = scope->VariableAt(0);
if (local->index() > 0) {
__ Move(reg, -local->index());
} else {
closure_reg = -local->index() - 1;
}
__ LoadField(reg, closure_reg, Closure::context_offset() / kWordSize);
} else if (has_optional_params) {
__ LoadConstant(context_index,
Object::Handle(isolate()->object_store()->empty_context()));
}
}
void FlowGraphCompiler::CompileGraph() {
InitCompiler();
if (TryIntrinsify()) {
// Skip regular code generation.
return;
}
EmitFrameEntry();
VisitBlocks();
}
#undef __
#define __ compiler_->assembler()->
void ParallelMoveResolver::EmitMove(int index) {
UNIMPLEMENTED();
}
void ParallelMoveResolver::EmitSwap(int index) {
UNIMPLEMENTED();
}
void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst,
const Address& src) {
UNREACHABLE();
}
void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) {
UNREACHABLE();
}
// Do not call or implement this function. Instead, use the form below that
// uses an offset from the frame pointer instead of an Address.
void ParallelMoveResolver::Exchange(Register reg, const Address& mem) {
UNREACHABLE();
}
// Do not call or implement this function. Instead, use the form below that
// uses offsets from the frame pointer instead of Addresses.
void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) {
UNREACHABLE();
}
void ParallelMoveResolver::Exchange(Register reg,
Register base_reg,
intptr_t stack_offset) {
UNIMPLEMENTED();
}
void ParallelMoveResolver::Exchange(Register base_reg1,
intptr_t stack_offset1,
Register base_reg2,
intptr_t stack_offset2) {
UNIMPLEMENTED();
}
void ParallelMoveResolver::SpillScratch(Register reg) {
UNIMPLEMENTED();
}
void ParallelMoveResolver::RestoreScratch(Register reg) {
UNIMPLEMENTED();
}
void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
UNIMPLEMENTED();
}
void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
UNIMPLEMENTED();
}
#undef __
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+2
View File
@@ -17,6 +17,8 @@
#include "vm/instructions_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/instructions_mips.h"
#elif defined(TARGET_ARCH_DBC)
#include "vm/instructions_dbc.h"
#else
#error Unknown architecture.
#endif
+177
View File
@@ -0,0 +1,177 @@
// Copyright (c) 2016, 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/globals.h" // Needed here to get TARGET_ARCH_DBC.
#if defined(TARGET_ARCH_DBC)
#include "vm/assembler.h"
#include "vm/constants_dbc.h"
#include "vm/cpu.h"
#include "vm/instructions.h"
#include "vm/object.h"
namespace dart {
CallPattern::CallPattern(uword pc, const Code& code)
: object_pool_(ObjectPool::Handle(code.GetObjectPool())),
end_(pc),
ic_data_load_end_(0),
target_code_pool_index_(-1),
ic_data_(ICData::Handle()) {
UNIMPLEMENTED();
}
int CallPattern::DeoptCallPatternLengthInInstructions() {
UNIMPLEMENTED();
return 0;
}
int CallPattern::DeoptCallPatternLengthInBytes() {
UNIMPLEMENTED();
return 0;
}
NativeCallPattern::NativeCallPattern(uword pc, const Code& code)
: object_pool_(ObjectPool::Handle(code.GetObjectPool())),
end_(pc),
native_function_pool_index_(-1),
target_code_pool_index_(-1) {
UNIMPLEMENTED();
}
RawCode* NativeCallPattern::target() const {
return reinterpret_cast<RawCode*>(
object_pool_.ObjectAt(target_code_pool_index_));
}
void NativeCallPattern::set_target(const Code& new_target) const {
object_pool_.SetObjectAt(target_code_pool_index_, new_target);
// No need to flush the instruction cache, since the code is not modified.
}
NativeFunction NativeCallPattern::native_function() const {
return reinterpret_cast<NativeFunction>(
object_pool_.RawValueAt(native_function_pool_index_));
}
void NativeCallPattern::set_native_function(NativeFunction func) const {
object_pool_.SetRawValueAt(native_function_pool_index_,
reinterpret_cast<uword>(func));
}
// Decodes a load sequence ending at 'end' (the last instruction of the load
// sequence is the instruction before the one at end). Returns a pointer to
// the first instruction in the sequence. Returns the register being loaded
// and the loaded object in the output parameters 'reg' and 'obj'
// respectively.
uword InstructionPattern::DecodeLoadObject(uword end,
const ObjectPool& object_pool,
Register* reg,
Object* obj) {
UNIMPLEMENTED();
return 0;
}
// Decodes a load sequence ending at 'end' (the last instruction of the load
// sequence is the instruction before the one at end). Returns a pointer to
// the first instruction in the sequence. Returns the register being loaded
// and the loaded immediate value in the output parameters 'reg' and 'value'
// respectively.
uword InstructionPattern::DecodeLoadWordImmediate(uword end,
Register* reg,
intptr_t* value) {
UNIMPLEMENTED();
return 0;
}
// Decodes a load sequence ending at 'end' (the last instruction of the load
// sequence is the instruction before the one at end). Returns a pointer to
// the first instruction in the sequence. Returns the register being loaded
// and the index in the pool being read from in the output parameters 'reg'
// and 'index' respectively.
uword InstructionPattern::DecodeLoadWordFromPool(uword end,
Register* reg,
intptr_t* index) {
UNIMPLEMENTED();
return 0;
}
bool DecodeLoadObjectFromPoolOrThread(uword pc,
const Code& code,
Object* obj) {
UNIMPLEMENTED();
return false;
}
RawICData* CallPattern::IcData() {
UNIMPLEMENTED();
return ICData::null();
}
RawCode* CallPattern::TargetCode() const {
return reinterpret_cast<RawCode*>(
object_pool_.ObjectAt(target_code_pool_index_));
}
void CallPattern::SetTargetCode(const Code& target_code) const {
object_pool_.SetObjectAt(target_code_pool_index_, target_code);
}
void CallPattern::InsertDeoptCallAt(uword pc, uword target_address) {
UNIMPLEMENTED();
}
SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code)
: object_pool_(ObjectPool::Handle(code.GetObjectPool())),
cache_pool_index_(-1),
stub_pool_index_(-1) {
UNIMPLEMENTED();
}
RawObject* SwitchableCallPattern::cache() const {
return reinterpret_cast<RawCode*>(
object_pool_.ObjectAt(cache_pool_index_));
}
void SwitchableCallPattern::SetCache(const MegamorphicCache& cache) const {
ASSERT(Object::Handle(object_pool_.ObjectAt(cache_pool_index_)).IsICData());
object_pool_.SetObjectAt(cache_pool_index_, cache);
}
void SwitchableCallPattern::SetLookupStub(const Code& lookup_stub) const {
ASSERT(Object::Handle(object_pool_.ObjectAt(stub_pool_index_)).IsCode());
object_pool_.SetObjectAt(stub_pool_index_, lookup_stub);
}
ReturnPattern::ReturnPattern(uword pc) : pc_(pc) {
}
bool ReturnPattern::IsValid() const {
UNIMPLEMENTED();
return false;
}
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+138
View File
@@ -0,0 +1,138 @@
// Copyright (c) 2016, 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.
// Classes that describe assembly patterns as used by inline caches.
#ifndef VM_INSTRUCTIONS_DBC_H_
#define VM_INSTRUCTIONS_DBC_H_
#ifndef VM_INSTRUCTIONS_H_
#error Do not include instructions_dbc.h directly; use instructions.h instead.
#endif
#include "vm/constants_dbc.h"
#include "vm/native_entry.h"
#include "vm/object.h"
namespace dart {
class InstructionPattern : public AllStatic {
public:
// Decodes a load sequence ending at 'end' (the last instruction of the
// load sequence is the instruction before the one at end). Returns the
// address of the first instruction in the sequence. Returns the register
// being loaded and the loaded object in the output parameters 'reg' and
// 'obj' respectively.
static uword DecodeLoadObject(uword end,
const ObjectPool& object_pool,
Register* reg,
Object* obj);
// Decodes a load sequence ending at 'end' (the last instruction of the
// load sequence is the instruction before the one at end). Returns the
// address of the first instruction in the sequence. Returns the register
// being loaded and the loaded immediate value in the output parameters
// 'reg' and 'value' respectively.
static uword DecodeLoadWordImmediate(uword end,
Register* reg,
intptr_t* value);
// Decodes a load sequence ending at 'end' (the last instruction of the
// load sequence is the instruction before the one at end). Returns the
// address of the first instruction in the sequence. Returns the register
// being loaded and the index in the pool being read from in the output
// parameters 'reg' and 'index' respectively.
static uword DecodeLoadWordFromPool(uword end,
Register* reg,
intptr_t* index);
};
class CallPattern : public ValueObject {
public:
CallPattern(uword pc, const Code& code);
RawICData* IcData();
RawCode* TargetCode() const;
void SetTargetCode(const Code& code) const;
// This constant length is only valid for inserted call patterns used for
// lazy deoptimization. Regular call pattern may vary in length.
static int DeoptCallPatternLengthInBytes();
static int DeoptCallPatternLengthInInstructions();
static void InsertDeoptCallAt(uword pc, uword target_address);
private:
const ObjectPool& object_pool_;
uword end_;
uword ic_data_load_end_;
intptr_t target_code_pool_index_;
ICData& ic_data_;
DISALLOW_COPY_AND_ASSIGN(CallPattern);
};
class NativeCallPattern : public ValueObject {
public:
NativeCallPattern(uword pc, const Code& code);
RawCode* target() const;
void set_target(const Code& target) const;
NativeFunction native_function() const;
void set_native_function(NativeFunction target) const;
private:
const ObjectPool& object_pool_;
uword end_;
intptr_t native_function_pool_index_;
intptr_t target_code_pool_index_;
DISALLOW_COPY_AND_ASSIGN(NativeCallPattern);
};
// Instance call that can switch from an IC call to a megamorphic call
class SwitchableCallPattern : public ValueObject {
public:
SwitchableCallPattern(uword pc, const Code& code);
RawObject* cache() const;
void SetCache(const MegamorphicCache& cache) const;
void SetLookupStub(const Code& stub) const;
private:
const ObjectPool& object_pool_;
intptr_t cache_pool_index_;
intptr_t stub_pool_index_;
DISALLOW_COPY_AND_ASSIGN(SwitchableCallPattern);
};
class ReturnPattern : public ValueObject {
public:
explicit ReturnPattern(uword pc);
static const int kLengthInBytes = 0;
int pattern_length_in_bytes() const {
UNIMPLEMENTED();
return kLengthInBytes;
}
bool IsValid() const;
private:
const uword pc_;
};
} // namespace dart
#endif // VM_INSTRUCTIONS_DBC_H_
+97 -6
View File
@@ -33,7 +33,7 @@ DEFINE_FLAG(bool, propagate_ic_data, true,
"Propagate IC data from unoptimized to optimized IC calls.");
DEFINE_FLAG(bool, two_args_smi_icd, true,
"Generate special IC stubs for two args Smi operations");
DEFINE_FLAG(bool, unbox_numeric_fields, true,
DEFINE_FLAG(bool, unbox_numeric_fields, !USING_DBC,
"Support unboxed double and float32x4 fields.");
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, support_externalizable_strings);
@@ -2766,9 +2766,14 @@ LocationSummary* TargetEntryInstr::MakeLocationSummary(Zone* zone,
void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ Bind(compiler->GetJumpLabel(this));
if (!compiler->is_optimizing()) {
#if !defined(TARGET_ARCH_DBC)
// TODO(vegorov) re-enable edge counters on DBC if we consider them
// beneficial for the quality of the optimized bytecode.
if (compiler->NeedsEdgeCounter(this)) {
compiler->EmitEdgeCounter(preorder_number());
}
#endif
// The deoptimization descriptor points after the edge counter code for
// uniformity with ARM and MIPS, where we can reuse pattern matching
// code that matches backwards from the end of the pattern.
@@ -2968,10 +2973,23 @@ LocationSummary* DropTempsInstr::MakeLocationSummary(Zone* zone,
void DropTempsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
#if defined(TARGET_ARCH_DBC)
// On DBC the action of poping the TOS value and then pushing it
// after all intermediates are poped is folded into a special
// bytecode (DropR). On other architectures this is handled by
// instruction prologue/epilogues.
ASSERT(!compiler->is_optimizing());
if ((InputCount() != 0) && HasTemp()) {
__ DropR(num_temps());
} else {
__ Drop(num_temps() + ((InputCount() != 0) ? 1 : 0));
}
#else
ASSERT(!compiler->is_optimizing());
// Assert that register assignment is correct.
ASSERT((InputCount() == 0) || (locs()->out(0).reg() == locs()->in(0).reg()));
__ Drop(num_temps());
#endif // defined(TARGET_ARCH_DBC)
}
@@ -2996,6 +3014,8 @@ LocationSummary* InstanceCallInstr::MakeLocationSummary(Zone* zone,
}
// DBC does not use specialized inline cache stubs for smi operations.
#if !defined(TARGET_ARCH_DBC)
static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) {
if (!FLAG_two_args_smi_icd) {
return 0;
@@ -3007,6 +3027,7 @@ static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) {
default: return NULL;
}
}
#endif
void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -3023,6 +3044,8 @@ void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
} else {
call_ic_data = &ICData::ZoneHandle(zone, ic_data()->raw());
}
#if !defined(TARGET_ARCH_DBC)
if (compiler->is_optimizing() && HasICData()) {
ASSERT(HasICData());
if (ic_data()->NumberOfUsedChecks() > 0) {
@@ -3096,6 +3119,44 @@ void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
*call_ic_data);
}
}
#else
// Emit smi fast path instruction. If fast-path succeeds it skips the next
// instruction otherwise it falls through.
if (function_name().raw() == Symbols::Plus().raw()) {
__ AddTOS();
} else if (function_name().raw() == Symbols::EqualOperator().raw()) {
__ EqualTOS();
} else if (function_name().raw() == Symbols::LAngleBracket().raw()) {
__ LessThanTOS();
} else if (function_name().raw() == Symbols::RAngleBracket().raw()) {
__ GreaterThanTOS();
} else if (function_name().raw() == Symbols::BitAnd().raw()) {
__ BitAndTOS();
} else if (function_name().raw() == Symbols::BitOr().raw()) {
__ BitOrTOS();
} else if (function_name().raw() == Symbols::Star().raw()) {
__ MulTOS();
}
const intptr_t call_ic_data_kidx = __ AddConstant(*call_ic_data);
switch (call_ic_data->NumArgsTested()) {
case 1:
__ InstanceCall(ArgumentCount(), call_ic_data_kidx);
break;
case 2:
__ InstanceCall2(ArgumentCount(), call_ic_data_kidx);
break;
case 3:
__ InstanceCall3(ArgumentCount(), call_ic_data_kidx);
break;
default:
UNIMPLEMENTED();
break;
}
compiler->AddCurrentDescriptor(RawPcDescriptors::kIcCall,
deopt_id(),
token_pos());
#endif // !defined(TARGET_ARCH_DBC)
}
@@ -3118,6 +3179,10 @@ bool PolymorphicInstanceCallInstr::HasOnlyDispatcherTargets() const {
return true;
}
// DBC does not support optimizing compiler and thus doesn't emit
// PolymorphicInstanceCallInstr.
#if !defined(TARGET_ARCH_DBC)
void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(ic_data().NumArgsTested() == 1);
if (!with_checks()) {
@@ -3141,6 +3206,7 @@ void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
locs(),
complete());
}
#endif
LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone,
@@ -3150,6 +3216,7 @@ LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone,
void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
#if !defined(TARGET_ARCH_DBC)
const ICData* call_ic_data = NULL;
if (!FLAG_propagate_ic_data || !compiler->is_optimizing() ||
(ic_data() == NULL)) {
@@ -3182,6 +3249,20 @@ void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
argument_names(),
locs(),
*call_ic_data);
#else
const Array& arguments_descriptor =
(ic_data() == NULL) ?
Array::Handle(ArgumentsDescriptor::New(ArgumentCount(),
argument_names())) :
Array::Handle(ic_data()->arguments_descriptor());
const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor);
__ PushConstant(function());
__ StaticCall(ArgumentCount(), argdesc_kidx);
compiler->AddCurrentDescriptor(RawPcDescriptors::kUnoptStaticCall,
deopt_id(),
token_pos());
#endif // !defined(TARGET_ARCH_DBC)
}
@@ -3191,7 +3272,11 @@ void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
dst_type(),
dst_name(),
locs());
// DBC does not use LocationSummaries in the same way as other architectures.
#if !defined(TARGET_ARCH_DBC)
ASSERT(locs()->in(0).reg() == locs()->out(0).reg());
#endif
}
@@ -3302,11 +3387,6 @@ void Environment::DeepCopyToOuter(Zone* zone, Instruction* instr) const {
}
static bool BindsToSmiConstant(Value* value) {
return value->BindsToConstant() && value->BoundConstant().IsSmi();
}
ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left,
Value* new_right) {
return new EqualityCompareInstr(token_pos(),
@@ -3374,9 +3454,17 @@ bool TestCidsInstr::AttributesEqual(Instruction* other) const {
}
#if !defined(TARGET_ARCH_DBC)
static bool BindsToSmiConstant(Value* value) {
return value->BindsToConstant() && value->BoundConstant().IsSmi();
}
#endif
bool IfThenElseInstr::Supports(ComparisonInstr* comparison,
Value* v1,
Value* v2) {
#if !defined(TARGET_ARCH_DBC)
bool is_smi_result = BindsToSmiConstant(v1) && BindsToSmiConstant(v2);
if (comparison->IsStrictCompare()) {
// Strict comparison with number checks calls a stub and is not supported
@@ -3389,6 +3477,9 @@ bool IfThenElseInstr::Supports(ComparisonInstr* comparison,
return false;
}
return is_smi_result;
#else
return false;
#endif // !defined(TARGET_ARCH_DBC)
}
+704
View File
@@ -0,0 +1,704 @@
// Copyright (c) 2016, 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/globals.h" // Needed here to get TARGET_ARCH_DBC.
#if defined(TARGET_ARCH_DBC)
#include "vm/intermediate_language.h"
#include "vm/cpu.h"
#include "vm/compiler.h"
#include "vm/dart_entry.h"
#include "vm/flow_graph.h"
#include "vm/flow_graph_compiler.h"
#include "vm/flow_graph_range_analysis.h"
#include "vm/locations.h"
#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/simulator.h"
#include "vm/stack_frame.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
#define __ compiler->assembler()->
namespace dart {
DECLARE_FLAG(bool, allow_absolute_addresses);
DECLARE_FLAG(bool, emit_edge_counters);
DECLARE_FLAG(int, optimization_counter_threshold);
// List of instructions that are still unimplemented by DBC backend.
#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
M(Stop) \
M(IndirectGoto) \
M(LoadCodeUnits) \
M(InstanceOf) \
M(LoadUntagged) \
M(AllocateUninitializedContext) \
M(BinaryInt32Op) \
M(UnarySmiOp) \
M(UnaryDoubleOp) \
M(SmiToDouble) \
M(Int32ToDouble) \
M(MintToDouble) \
M(DoubleToInteger) \
M(DoubleToSmi) \
M(DoubleToDouble) \
M(DoubleToFloat) \
M(FloatToDouble) \
M(UnboxedConstant) \
M(CheckEitherNonSmi) \
M(BinaryDoubleOp) \
M(MathUnary) \
M(MathMinMax) \
M(Box) \
M(Unbox) \
M(BoxInt64) \
M(CaseInsensitiveCompareUC16) \
M(BinaryMintOp) \
M(ShiftMintOp) \
M(UnaryMintOp) \
M(StringToCharCode) \
M(StringFromCharCode) \
M(InvokeMathCFunction) \
M(MergedMath) \
M(GuardFieldClass) \
M(GuardFieldLength) \
M(IfThenElse) \
M(BinaryFloat32x4Op) \
M(Simd32x4Shuffle) \
M(Simd32x4ShuffleMix) \
M(Simd32x4GetSignMask) \
M(Float32x4Constructor) \
M(Float32x4Zero) \
M(Float32x4Splat) \
M(Float32x4Comparison) \
M(Float32x4MinMax) \
M(Float32x4Scale) \
M(Float32x4Sqrt) \
M(Float32x4ZeroArg) \
M(Float32x4Clamp) \
M(Float32x4With) \
M(Float32x4ToInt32x4) \
M(Int32x4Constructor) \
M(Int32x4BoolConstructor) \
M(Int32x4GetFlag) \
M(Int32x4Select) \
M(Int32x4SetFlag) \
M(Int32x4ToFloat32x4) \
M(BinaryInt32x4Op) \
M(TestCids) \
M(BinaryFloat64x2Op) \
M(Float64x2Zero) \
M(Float64x2Constructor) \
M(Float64x2Splat) \
M(Float32x4ToFloat64x2) \
M(Float64x2ToFloat32x4) \
M(Simd64x2Shuffle) \
M(Float64x2ZeroArg) \
M(Float64x2OneArg) \
M(ExtractNthOutput) \
M(BinaryUint32Op) \
M(ShiftUint32Op) \
M(UnaryUint32Op) \
M(UnboxedIntConverter) \
M(GrowRegExpStack) \
M(BoxInteger32) \
M(UnboxInteger32) \
M(CheckedSmiOp) \
M(CheckArrayBound) \
M(CheckSmi) \
M(LoadClassId) \
M(CheckClassId) \
M(CheckClass) \
M(BinarySmiOp) \
M(TestSmi) \
M(RelationalOp) \
M(EqualityCompare) \
M(LoadIndexed) \
// Location summaries actually are not used by the unoptimizing DBC compiler
// because we don't allocate any registers.
static LocationSummary* CreateLocationSummary(Zone* zone,
intptr_t num_inputs,
bool has_result) {
const intptr_t kNumTemps = 0;
LocationSummary* locs = new(zone) LocationSummary(
zone, num_inputs, kNumTemps, LocationSummary::kNoCall);
for (intptr_t i = 0; i < num_inputs; i++) {
locs->set_in(i, Location::RequiresRegister());
}
if (has_result) {
locs->set_out(0, Location::RequiresRegister());
}
return locs;
}
#define DEFINE_MAKE_LOCATION_SUMMARY(Name, In, Out) \
LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \
const { \
return CreateLocationSummary(zone, In, Out); \
} \
#define EMIT_NATIVE_CODE(Name, In, Out) \
DEFINE_MAKE_LOCATION_SUMMARY(Name, In, Out); \
void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) \
#define DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \
LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \
const { \
UNIMPLEMENTED(); \
return NULL; \
} \
#define DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \
void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) { \
UNIMPLEMENTED(); \
}
#define DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(Name) \
void Name##Instr::EmitBranchCode(FlowGraphCompiler*, BranchInstr*) { \
UNIMPLEMENTED(); \
} \
Condition Name##Instr::EmitComparisonCode(FlowGraphCompiler*, \
BranchLabels) { \
UNIMPLEMENTED(); \
return EQ; \
}
#define DEFINE_UNIMPLEMENTED(Name) \
DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \
DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \
FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED)
#undef DEFINE_UNIMPLEMENTED
DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(TestCids)
DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(TestSmi)
DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(RelationalOp)
DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(EqualityCompare)
DEFINE_MAKE_LOCATION_SUMMARY(AssertAssignable, 2, true);
EMIT_NATIVE_CODE(AssertBoolean, 1, true) {
__ AssertBoolean(Isolate::Current()->type_checks() ? 1 : 0);
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
deopt_id(),
token_pos());
}
LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary(Zone* zone,
bool optimizing) const {
return MakeCallSummary(zone);
}
void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
UNIMPLEMENTED();
}
EMIT_NATIVE_CODE(CheckStackOverflow, 0, false) {
__ CheckStack();
compiler->AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
Thread::kNoDeoptId,
token_pos());
}
EMIT_NATIVE_CODE(PushArgument, 1, false) {
if (compiler->is_optimizing()) {
__ Push(locs()->in(0).reg());
}
}
EMIT_NATIVE_CODE(LoadLocal, 0, false) {
ASSERT(!compiler->is_optimizing());
ASSERT(local().index() != 0);
__ Push((local().index() > 0) ? (-local().index()) : (-local().index() - 1));
}
EMIT_NATIVE_CODE(StoreLocal, 0, false) {
ASSERT(!compiler->is_optimizing());
ASSERT(local().index() != 0);
if (HasTemp()) {
__ StoreLocal(
(local().index() > 0) ? (-local().index()) : (-local().index() - 1));
} else {
__ PopLocal(
(local().index() > 0) ? (-local().index()) : (-local().index() - 1));
}
}
EMIT_NATIVE_CODE(Constant, 0, true) {
const intptr_t kidx = __ AddConstant(value());
if (compiler->is_optimizing()) {
__ LoadConstant(locs()->out(0).reg(), kidx);
} else {
__ PushConstant(kidx);
}
}
EMIT_NATIVE_CODE(Return, 1, false) {
__ ReturnTOS();
}
EMIT_NATIVE_CODE(StoreStaticField, 1, false) {
const intptr_t kidx = __ AddConstant(field());
__ StoreStaticTOS(kidx);
}
EMIT_NATIVE_CODE(LoadStaticField, 1, true) {
const intptr_t kidx = __ AddConstant(StaticField());
__ PushStatic(kidx);
}
EMIT_NATIVE_CODE(InitStaticField, 0, false) {
ASSERT(!compiler->is_optimizing());
__ InitStaticTOS();
}
EMIT_NATIVE_CODE(ClosureCall, 0, false) {
intptr_t argument_count = ArgumentCount();
const Array& arguments_descriptor =
Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
argument_names()));
const intptr_t argdesc_kidx =
compiler->assembler()->AddConstant(arguments_descriptor);
__ StaticCall(argument_count, argdesc_kidx);
compiler->RecordSafepoint(locs());
// Marks either the continuation point in unoptimized code or the
// deoptimization point in optimized code, after call.
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id());
if (compiler->is_optimizing()) {
compiler->AddDeoptIndexAtCall(deopt_id_after, token_pos());
}
// Add deoptimization continuation point after the call and before the
// arguments are removed.
// In optimized code this descriptor is needed for exception handling.
compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
deopt_id_after,
token_pos());
}
static void EmitBranchOnCondition(FlowGraphCompiler* compiler,
Condition true_condition,
BranchLabels labels) {
if (labels.fall_through == labels.false_label) {
// If the next block is the false successor, fall through to it.
__ Jump(labels.true_label);
} else {
// If the next block is not the false successor, branch to it.
__ Jump(labels.false_label);
// Fall through or jump to the true successor.
if (labels.fall_through != labels.true_label) {
__ Jump(labels.true_label);
}
}
}
Condition StrictCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
BranchLabels labels) {
ASSERT((kind() == Token::kNE_STRICT) ||
(kind() == Token::kEQ_STRICT));
const Bytecode::Opcode eq_op = needs_number_check() ?
Bytecode::kIfEqStrictNumTOS : Bytecode::kIfEqStrictTOS;
const Bytecode::Opcode ne_op = needs_number_check() ?
Bytecode::kIfNeStrictNumTOS : Bytecode::kIfNeStrictTOS;
if (kind() == Token::kEQ_STRICT) {
__ Emit((labels.fall_through == labels.false_label) ? eq_op : ne_op);
} else {
__ Emit((labels.fall_through == labels.false_label) ? ne_op : eq_op);
}
if (needs_number_check() && token_pos().IsReal()) {
compiler->AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
Thread::kNoDeoptId,
token_pos());
}
return EQ;
}
void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
ASSERT((kind() == Token::kEQ_STRICT) ||
(kind() == Token::kNE_STRICT));
BranchLabels labels = compiler->CreateBranchLabels(branch);
Condition true_condition = EmitComparisonCode(compiler, labels);
EmitBranchOnCondition(compiler, true_condition, labels);
}
EMIT_NATIVE_CODE(StrictCompare, 2, true) {
ASSERT((kind() == Token::kEQ_STRICT) ||
(kind() == Token::kNE_STRICT));
Label is_true, is_false;
BranchLabels labels = { &is_true, &is_false, &is_false };
Condition true_condition = EmitComparisonCode(compiler, labels);
EmitBranchOnCondition(compiler, true_condition, labels);
Label done;
__ Bind(&is_false);
__ PushConstant(Bool::False());
__ Jump(&done);
__ Bind(&is_true);
__ PushConstant(Bool::True());
__ Bind(&done);
}
LocationSummary* BranchInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
comparison()->InitializeLocationSummary(zone, opt);
// Branches don't produce a result.
comparison()->locs()->set_out(0, Location::NoLocation());
return comparison()->locs();
}
void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
comparison()->EmitBranchCode(compiler, this);
}
EMIT_NATIVE_CODE(Goto, 0, false) {
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
// We can fall through if the successor is the next block in the list.
// Otherwise, we need a jump.
if (!compiler->CanFallThroughTo(successor())) {
__ Jump(compiler->GetJumpLabel(successor()));
}
}
EMIT_NATIVE_CODE(CreateArray, 2, true) {
__ CreateArrayTOS();
}
EMIT_NATIVE_CODE(StoreIndexed, 3, false) {
ASSERT(class_id() == kArrayCid);
__ StoreIndexedTOS();
}
EMIT_NATIVE_CODE(StringInterpolate, 0, false) {
const intptr_t kArgumentCount = 1;
const Array& arguments_descriptor = Array::Handle(
ArgumentsDescriptor::New(kArgumentCount, Object::null_array()));
__ PushConstant(CallFunction());
const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor);
__ StaticCall(kArgumentCount, argdesc_kidx);
}
EMIT_NATIVE_CODE(NativeCall, 0, false) {
SetupNative();
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
ASSERT(!link_lazily());
const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
const intptr_t target_kidx =
__ object_pool_wrapper().FindImmediate(label.address());
const intptr_t argc_tag_kidx =
__ object_pool_wrapper().FindImmediate(static_cast<uword>(argc_tag));
__ PushConstant(target_kidx);
__ PushConstant(argc_tag_kidx);
if (is_bootstrap_native()) {
__ NativeBootstrapCall();
} else {
__ NativeCall();
}
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
Thread::kNoDeoptId,
token_pos());
}
EMIT_NATIVE_CODE(AllocateObject, 0, true) {
if (ArgumentCount() == 1) {
__ PushConstant(cls());
__ AllocateT();
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
Thread::kNoDeoptId,
token_pos());
} else {
const intptr_t kidx = __ AddConstant(cls());
__ Allocate(kidx);
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
Thread::kNoDeoptId,
token_pos());
}
}
EMIT_NATIVE_CODE(StoreInstanceField, 2, false) {
ASSERT(!HasTemp());
ASSERT(offset_in_bytes() % kWordSize == 0);
if (compiler->is_optimizing()) {
const Register value = locs()->in(1).reg();
const Register instance = locs()->in(0).reg();
__ StoreField(instance, offset_in_bytes() / kWordSize, value);
} else {
__ StoreFieldTOS(offset_in_bytes() / kWordSize);
}
}
EMIT_NATIVE_CODE(LoadField, 1, true) {
ASSERT(offset_in_bytes() % kWordSize == 0);
__ LoadFieldTOS(offset_in_bytes() / kWordSize);
}
EMIT_NATIVE_CODE(BooleanNegate, 1, true) {
__ BooleanNegateTOS();
}
EMIT_NATIVE_CODE(AllocateContext, 0, false) {
__ AllocateContext(num_context_variables());
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
Thread::kNoDeoptId,
token_pos());
}
EMIT_NATIVE_CODE(CloneContext, 0, false) {
__ CloneContext();
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
Thread::kNoDeoptId,
token_pos());
}
EMIT_NATIVE_CODE(CatchBlockEntry, 0, false) {
__ Bind(compiler->GetJumpLabel(this));
compiler->AddExceptionHandler(catch_try_index(),
try_index(),
compiler->assembler()->CodeSize(),
catch_handler_types_,
needs_stacktrace());
__ MoveSpecial(-exception_var().index()-1,
Simulator::kExceptionSpecialIndex);
__ MoveSpecial(-stacktrace_var().index()-1,
Simulator::kStacktraceSpecialIndex);
__ SetFrame(compiler->StackSize());
}
EMIT_NATIVE_CODE(Throw, 0, false) {
__ Throw(0);
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
deopt_id(),
token_pos());
__ Trap();
}
EMIT_NATIVE_CODE(ReThrow, 0, false) {
compiler->SetNeedsStacktrace(catch_try_index());
__ Throw(1);
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
deopt_id(),
token_pos());
__ Trap();
}
EMIT_NATIVE_CODE(InstantiateType, 1, true) {
__ InstantiateType(__ AddConstant(type()));
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
deopt_id(),
token_pos());
}
EMIT_NATIVE_CODE(InstantiateTypeArguments, 1, true) {
__ InstantiateTypeArgumentsTOS(
type_arguments().IsRawInstantiatedRaw(type_arguments().Length()),
__ AddConstant(type_arguments()));
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
deopt_id(),
token_pos());
}
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ DebugStep();
compiler->AddCurrentDescriptor(stub_kind_, Thread::kNoDeoptId, token_pos());
}
void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (!compiler->CanFallThroughTo(normal_entry())) {
__ Jump(compiler->GetJumpLabel(normal_entry()));
}
}
LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
LocationSummary* result = new(zone) LocationSummary(
zone, 0, 0, LocationSummary::kCall);
result->set_out(0, Location::RequiresRegister());
return result;
}
CompileType BinaryUint32OpInstr::ComputeType() const {
return CompileType::Int();
}
CompileType ShiftUint32OpInstr::ComputeType() const {
return CompileType::Int();
}
CompileType UnaryUint32OpInstr::ComputeType() const {
return CompileType::Int();
}
static const intptr_t kMintShiftCountLimit = 63;
bool ShiftMintOpInstr::has_shift_count_check() const {
return !RangeUtils::IsWithin(
right()->definition()->range(), 0, kMintShiftCountLimit);
}
CompileType LoadIndexedInstr::ComputeType() const {
switch (class_id_) {
case kArrayCid:
case kImmutableArrayCid:
return CompileType::Dynamic();
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid:
return CompileType::FromCid(kDoubleCid);
case kTypedDataFloat32x4ArrayCid:
return CompileType::FromCid(kFloat32x4Cid);
case kTypedDataInt32x4ArrayCid:
return CompileType::FromCid(kInt32x4Cid);
case kTypedDataFloat64x2ArrayCid:
return CompileType::FromCid(kFloat64x2Cid);
case kTypedDataInt8ArrayCid:
case kTypedDataUint8ArrayCid:
case kTypedDataUint8ClampedArrayCid:
case kExternalTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
case kTypedDataInt16ArrayCid:
case kTypedDataUint16ArrayCid:
case kOneByteStringCid:
case kTwoByteStringCid:
return CompileType::FromCid(kSmiCid);
case kTypedDataInt32ArrayCid:
case kTypedDataUint32ArrayCid:
return CompileType::Int();
default:
UNREACHABLE();
return CompileType::Dynamic();
}
}
Representation LoadIndexedInstr::representation() const {
switch (class_id_) {
case kArrayCid:
case kImmutableArrayCid:
case kTypedDataInt8ArrayCid:
case kTypedDataUint8ArrayCid:
case kTypedDataUint8ClampedArrayCid:
case kExternalTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
case kTypedDataInt16ArrayCid:
case kTypedDataUint16ArrayCid:
case kOneByteStringCid:
case kTwoByteStringCid:
return kTagged;
case kTypedDataInt32ArrayCid:
return kUnboxedInt32;
case kTypedDataUint32ArrayCid:
return kUnboxedUint32;
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid:
return kUnboxedDouble;
case kTypedDataInt32x4ArrayCid:
return kUnboxedInt32x4;
case kTypedDataFloat32x4ArrayCid:
return kUnboxedFloat32x4;
case kTypedDataFloat64x2ArrayCid:
return kUnboxedFloat64x2;
default:
UNREACHABLE();
return kTagged;
}
}
Representation StoreIndexedInstr::RequiredInputRepresentation(
intptr_t idx) const {
// Array can be a Dart object or a pointer to external data.
if (idx == 0) return kNoRepresentation; // Flexible input representation.
if (idx == 1) return kTagged; // Index is a smi.
ASSERT(idx == 2);
switch (class_id_) {
case kArrayCid:
case kOneByteStringCid:
case kTypedDataInt8ArrayCid:
case kTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ArrayCid:
case kTypedDataUint8ClampedArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
case kTypedDataInt16ArrayCid:
case kTypedDataUint16ArrayCid:
return kTagged;
case kTypedDataInt32ArrayCid:
return kUnboxedInt32;
case kTypedDataUint32ArrayCid:
return kUnboxedUint32;
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid:
return kUnboxedDouble;
case kTypedDataFloat32x4ArrayCid:
return kUnboxedFloat32x4;
case kTypedDataInt32x4ArrayCid:
return kUnboxedInt32x4;
case kTypedDataFloat64x2ArrayCid:
return kUnboxedFloat64x2;
default:
UNREACHABLE();
return kTagged;
}
}
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+22
View File
@@ -119,6 +119,9 @@ void Intrinsifier::InitializeState() {
}
#endif // defined(DART_NO_SNAPSHOT).
// DBC does not use graph intrinsics.
#if !defined(TARGET_ARCH_DBC)
static void EmitCodeFor(FlowGraphCompiler* compiler,
FlowGraph* graph) {
// The FlowGraph here is constructed by the intrinsics builder methods, and
@@ -154,10 +157,12 @@ static void EmitCodeFor(FlowGraphCompiler* compiler,
}
compiler->assembler()->Comment("Graph intrinsic end");
}
#endif
bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function,
FlowGraphCompiler* compiler) {
#if !defined(TARGET_ARCH_DBC)
ZoneGrowableArray<const ICData*>* ic_data_array =
new ZoneGrowableArray<const ICData*>();
FlowGraphBuilder builder(parsed_function,
@@ -204,6 +209,9 @@ bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function,
}
EmitCodeFor(compiler, graph);
return true;
#else
return false;
#endif // !defined(TARGET_ARCH_DBC)
}
@@ -235,10 +243,22 @@ void Intrinsifier::Intrinsify(const ParsedFunction& parsed_function,
default:
break;
}
// On DBC all graph intrinsics are handled in the same way as non-graph
// intrinsics.
#if defined(TARGET_ARCH_DBC)
switch (function.recognized_kind()) {
GRAPH_INTRINSICS_LIST(EMIT_CASE)
default:
break;
}
#endif
#undef EMIT_INTRINSIC
}
#if !defined(TARGET_ARCH_DBC)
static intptr_t CidForRepresentation(Representation rep) {
switch (rep) {
case kUnboxedDouble:
@@ -1138,5 +1158,7 @@ bool Intrinsifier::Build_DoubleRound(FlowGraph* flow_graph) {
return BuildInvokeMathCFunction(&builder,
MethodRecognizer::kDoubleRound);
}
#endif // !defined(TARGET_ARCH_DBC)
} // namespace dart
+6
View File
@@ -42,15 +42,21 @@ class Intrinsifier : public AllStatic {
static void enum_name(Assembler* assembler);
ALL_INTRINSICS_LIST(DECLARE_FUNCTION)
#if defined(TARGET_ARCH_DBC)
// On DBC graph intrinsics are handled in the same way as non-graph ones.
GRAPH_INTRINSICS_LIST(DECLARE_FUNCTION)
#endif
#undef DECLARE_FUNCTION
#if !defined(TARGET_ARCH_DBC)
#define DECLARE_FUNCTION(test_class_name, test_function_name, enum_name, fp) \
static bool Build_##enum_name(FlowGraph* flow_graph);
GRAPH_INTRINSICS_LIST(DECLARE_FUNCTION)
#undef DECLARE_FUNCTION
#endif
};
} // namespace dart
+39
View File
@@ -0,0 +1,39 @@
// Copyright (c) 2016, 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/globals.h" // Needed here to get TARGET_ARCH_DBC.
#if defined(TARGET_ARCH_DBC)
#include "vm/intrinsifier.h"
#include "vm/assembler.h"
#include "vm/cpu.h"
#include "vm/dart_entry.h"
#include "vm/flow_graph_compiler.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/regexp_assembler.h"
#include "vm/symbols.h"
#include "vm/simulator.h"
namespace dart {
DECLARE_FLAG(bool, interpret_irregexp);
intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; }
#define DEFINE_FUNCTION(test_class_name, test_function_name, enum_name, fp) \
void Intrinsifier::enum_name(Assembler* assembler) { \
if (Simulator::IsSupportedIntrinsic(Simulator::k##enum_name##Intrinsic)) { \
assembler->Intrinsic(Simulator::k##enum_name##Intrinsic); \
} \
} \
ALL_INTRINSICS_LIST(DEFINE_FUNCTION)
GRAPH_INTRINSICS_LIST(DEFINE_FUNCTION)
#undef DEFINE_FUNCTION
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+3 -1
View File
@@ -118,6 +118,8 @@ Location Location::AnyOrConstant(Value* value) {
}
// DBC does not have an notion of 'address' in its instruction set.
#if !defined(TARGET_ARCH_DBC)
Address Location::ToStackSlotAddress() const {
const intptr_t index = stack_index();
const Register base = base_reg();
@@ -134,7 +136,7 @@ Address Location::ToStackSlotAddress() const {
return Address(base, index * kWordSize);
}
}
#endif
intptr_t Location::ToStackSlotOffset() const {
const intptr_t index = stack_index();
+7
View File
@@ -341,8 +341,11 @@ class Location : public ValueObject {
return IsStackSlot() || IsDoubleStackSlot() || IsQuadStackSlot();
}
// DBC does not have an notion of 'address' in its instruction set.
#if !defined(TARGET_ARCH_DBC)
// Return a memory operand for stack slot locations.
Address ToStackSlotAddress() const;
#endif
// Returns the offset from the frame pointer for stack slot locations.
intptr_t ToStackSlotOffset() const;
@@ -650,9 +653,13 @@ class LocationSummary : public ZoneAllocated {
void set_out(intptr_t index, Location loc) {
ASSERT(index == 0);
// DBC calls are different from call on other architectures so this
// assert doesn't make sense.
#if !defined(TARGET_ARCH_DBC)
ASSERT(!always_calls() ||
(loc.IsMachineRegister() || loc.IsInvalid() ||
loc.IsPairLocation()));
#endif
output_location_ = loc;
}
+1 -2
View File
@@ -256,7 +256,7 @@ namespace dart {
V(Int32x4List, ., TypedData_Int32x4Array_factory, 504220232) \
V(Float64x2List, ., TypedData_Float64x2Array_factory, 416019673) \
#define GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
#define GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
V(Uint8List, [], Uint8ArrayGetIndexed, 513704632) \
V(Uint8List, []=, Uint8ArraySetIndexed, 2123520783) \
V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 513704632) \
@@ -310,7 +310,6 @@ namespace dart {
MATH_LIB_INTRINSIC_LIST(V) \
TYPED_DATA_LIB_INTRINSIC_LIST(V) \
#define ALL_INTRINSICS_LIST(V) \
ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V) \
CORE_INTEGER_LIB_INTRINSIC_LIST(V)
+22 -3
View File
@@ -25,7 +25,10 @@ class Thread;
#if defined(TESTING) || defined(DEBUG)
#if defined(USING_SIMULATOR)
#if defined(TARGET_ARCH_DBC)
// C-stack is always aligned on DBC because we don't have any native code.
#define CHECK_STACK_ALIGNMENT
#elif defined(USING_SIMULATOR)
#define CHECK_STACK_ALIGNMENT { \
uword current_sp = Simulator::Current()->get_register(SPREG); \
ASSERT(Utils::IsAligned(current_sp, OS::ActivationFrameAlignment())); \
@@ -92,7 +95,13 @@ class NativeArguments {
RawObject* ArgAt(int index) const {
ASSERT((index >= 0) && (index < ArgCount()));
RawObject** arg_ptr = &((*argv_)[-index]);
#if defined(TARGET_ARCH_DBC)
// On DBC stack is growing upwards, in reverse direction from all other
// architectures.
RawObject** arg_ptr = &(argv_[index]);
#else
RawObject** arg_ptr = &(argv_[-index]);
#endif
// Tell MemorySanitizer the RawObject* was initialized (by generated code).
MSAN_UNPOISON(arg_ptr, kWordSize);
return *arg_ptr;
@@ -204,6 +213,16 @@ class NativeArguments {
friend class BootstrapNatives;
friend class Simulator;
#if defined(TARGET_ARCH_DBC)
// Allow simulator to create NativeArguments on the stack.
NativeArguments(Thread* thread,
int argc_tag,
RawObject** argv,
RawObject** retval)
: thread_(thread), argc_tag_(argc_tag), argv_(argv), retval_(retval) {
}
#endif
// Since this function is passed a RawObject directly, we need to be
// exceedingly careful when we use it. If there are any other side
// effects in the statement that may cause GC, it could lead to
@@ -235,7 +254,7 @@ class NativeArguments {
Thread* thread_; // Current thread pointer.
intptr_t argc_tag_; // Encodes argument count and invoked native call type.
RawObject*(*argv_)[]; // Pointer to an array of arguments to runtime call.
RawObject** argv_; // Pointer to an array of arguments to runtime call.
RawObject** retval_; // Pointer to the return value area.
};
+9 -4
View File
@@ -90,7 +90,8 @@ const uint8_t* NativeEntry::ResolveSymbol(uword pc) {
uword NativeEntry::NativeCallWrapperEntry() {
uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper);
#if defined(USING_SIMULATOR)
#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
// DBC does not use redirections unlike other simulators.
entry = Simulator::RedirectExternalReference(
entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments);
#endif
@@ -177,6 +178,8 @@ void NativeEntry::NativeCallWrapperNoStackCheck(Dart_NativeArguments args,
}
// DBC does not support lazy native call linking.
#if !defined(TARGET_ARCH_DBC)
static NativeFunction ResolveNativeFunction(Zone* zone,
const Function& func,
bool* is_bootstrap_native) {
@@ -260,9 +263,10 @@ void NativeEntry::LinkNativeCall(Dart_NativeArguments args) {
#endif
call_through_wrapper = !is_bootstrap_native;
const Code& trampoline = Code::Handle(call_through_wrapper ?
StubCode::CallNativeCFunction_entry()->code() :
StubCode::CallBootstrapCFunction_entry()->code());
const Code& trampoline =
Code::Handle(call_through_wrapper ?
StubCode::CallNativeCFunction_entry()->code() :
StubCode::CallBootstrapCFunction_entry()->code());
NativeFunction patch_target_function = target_function;
#if defined(USING_SIMULATOR)
@@ -295,6 +299,7 @@ void NativeEntry::LinkNativeCall(Dart_NativeArguments args) {
target_function(arguments);
}
}
#endif // !defined(TARGET_ARCH_DBC)
} // namespace dart
+3
View File
@@ -118,8 +118,11 @@ class NativeEntry : public AllStatic {
static void NativeCallWrapper(Dart_NativeArguments args,
Dart_NativeFunction func);
// DBC does not support lazy native call linking.
#if !defined(TARGET_ARCH_DBC)
static uword LinkNativeCallEntry();
static void LinkNativeCall(Dart_NativeArguments args);
#endif
private:
static void NativeCallWrapperNoStackCheck(Dart_NativeArguments args,
+15 -1
View File
@@ -13825,6 +13825,7 @@ void Code::DisableDartCode() const {
void Code::DisableStubCode() const {
#if !defined(TARGET_ARCH_DBC)
ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(IsAllocationStubCode());
ASSERT(!IsDisabled());
@@ -13832,6 +13833,10 @@ void Code::DisableStubCode() const {
Code::Handle(StubCode::FixAllocationStubTarget_entry()->code());
ASSERT(new_code.instructions()->IsVMHeapObject());
SetActiveInstructions(new_code.instructions());
#else
// DBC does not use allocation stubs.
UNIMPLEMENTED();
#endif // !defined(TARGET_ARCH_DBC)
}
@@ -14970,7 +14975,9 @@ bool Instance::IsInstanceOf(const AbstractType& other,
Zone* zone = Thread::Current()->zone();
const Class& cls = Class::Handle(zone, clazz());
if (cls.IsClosureClass()) {
if (other.IsObjectType() || other.IsDartFunctionType()) {
if (other.IsObjectType() ||
other.IsDartFunctionType() ||
other.IsDartClosureType()) {
return true;
}
Function& other_signature = Function::Handle(zone);
@@ -15757,6 +15764,13 @@ bool AbstractType::IsDartFunctionType() const {
}
bool AbstractType::IsDartClosureType() const {
return !IsFunctionType() &&
HasResolvedTypeClass() &&
(type_class() == Isolate::Current()->object_store()->closure_class());
}
bool AbstractType::TypeTest(TypeTestKind test_kind,
const AbstractType& other,
Error* bound_error,
+3
View File
@@ -5485,6 +5485,9 @@ class AbstractType : public Instance {
// Check if this type represents the Dart 'Function' type.
bool IsDartFunctionType() const;
// Check if this type represents the Dart '_Closure' type.
bool IsDartClosureType() const;
// Check the subtype relationship.
bool IsSubtypeOf(const AbstractType& other,
Error* bound_error,
+7 -4
View File
@@ -21,10 +21,6 @@ namespace dart {
DECLARE_FLAG(bool, write_protect_code);
static RawLibrary* CreateDummyLibrary(const String& library_name) {
return Library::New(library_name);
}
static RawClass* CreateDummyClass(const String& class_name,
const Script& script) {
@@ -2690,6 +2686,12 @@ VM_TEST_CASE(CheckedHandle) {
}
#if !defined(TARGET_ARCH_DBC)
static RawLibrary* CreateDummyLibrary(const String& library_name) {
return Library::New(library_name);
}
static RawFunction* CreateFunction(const char* name) {
Thread* thread = Thread::Current();
const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
@@ -2966,6 +2968,7 @@ VM_TEST_CASE(PcDescriptorsLargeDeltas) {
EXPECT_EQ(false, iter.MoveNext());
}
#endif // !defined(TARGET_ARCH_DBC)
static RawClass* CreateTestClass(const char* name) {
+3 -1
View File
@@ -191,7 +191,7 @@ intptr_t OS::ActivationFrameAlignment() {
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM64)
const int kMinimumAlignment = 16;
#elif defined(TARGET_ARCH_ARM)
#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_DBC)
const int kMinimumAlignment = 8;
#else
#error Unsupported architecture.
@@ -212,6 +212,8 @@ intptr_t OS::PreferredCodeAlignment() {
const int kMinimumAlignment = 16;
#elif defined(TARGET_ARCH_ARM)
const int kMinimumAlignment = 16;
#elif defined(TARGET_ARCH_DBC)
const int kMinimumAlignment = 16;
#else
#error Unsupported architecture.
#endif
+4 -2
View File
@@ -197,7 +197,8 @@ void OS::AlignedFree(void* ptr) {
intptr_t OS::ActivationFrameAlignment() {
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM64)
defined(TARGET_ARCH_ARM64) || \
defined(TARGET_ARCH_DBC)
const int kMinimumAlignment = 16;
#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
const int kMinimumAlignment = 8;
@@ -217,7 +218,8 @@ intptr_t OS::ActivationFrameAlignment() {
intptr_t OS::PreferredCodeAlignment() {
#if defined(TARGET_ARCH_IA32) || \
defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM64)
defined(TARGET_ARCH_ARM64) || \
defined(TARGET_ARCH_DBC)
const int kMinimumAlignment = 32;
#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
const int kMinimumAlignment = 16;
+2
View File
@@ -1721,6 +1721,7 @@ void Precompiler::BindStaticCalls() {
void Precompiler::SwitchICCalls() {
#if !defined(TARGET_ARCH_DBC)
// Now that all functions have been compiled, we can switch to an instance
// call sequence that loads the Code object and entry point directly from
// the ic data array instead indirectly through a Function in the ic data
@@ -1794,6 +1795,7 @@ void Precompiler::SwitchICCalls() {
ASSERT(!I->compilation_allowed());
SwitchICCallsVisitor visitor(Z);
VisitFunctions(&visitor);
#endif
}
+15 -3
View File
@@ -290,6 +290,11 @@ bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) {
ASSERT(return_address != NULL);
return false;
}
#elif defined(TARGET_ARCH_DBC)
bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) {
ASSERT(return_address != NULL);
return false;
}
#else
#error ReturnAddressLocator implementation missing for this architecture.
#endif
@@ -839,7 +844,7 @@ static Sample* SetupSample(Thread* thread,
Sample* sample = sample_buffer->ReserveSample();
sample->Init(isolate, OS::GetCurrentMonotonicMicros(), tid);
uword vm_tag = thread->vm_tag();
#if defined(USING_SIMULATOR)
#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
// When running in the simulator, the runtime entry function address
// (stored as the vm tag) is the address of a redirect function.
// Attempt to find the real runtime entry function address and use that.
@@ -973,6 +978,11 @@ void Profiler::SampleThreadSingleFrame(Thread* thread, uintptr_t pc) {
void Profiler::SampleThread(Thread* thread,
const InterruptedThreadState& state) {
#if defined(TARGET_ARCH_DBC)
// TODO(vegorov) implement simulator stack sampling.
return;
#endif
ASSERT(thread != NULL);
OSThread* os_thread = thread->os_thread();
ASSERT(os_thread != NULL);
@@ -996,13 +1006,15 @@ void Profiler::SampleThread(Thread* thread,
uintptr_t sp = 0;
uintptr_t fp = state.fp;
uintptr_t pc = state.pc;
#if defined(USING_SIMULATOR)
#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
Simulator* simulator = NULL;
#endif
if (in_dart_code) {
// If we're in Dart code, use the Dart stack pointer.
#if defined(USING_SIMULATOR)
#if defined(TARGET_ARCH_DBC)
UNIMPLEMENTED();
#elif defined(USING_SIMULATOR)
simulator = isolate->simulator();
sp = simulator->get_register(SPREG);
fp = simulator->get_register(FPREG);
+4
View File
@@ -231,6 +231,8 @@ CLASS_LIST_TYPED_DATA(V)
friend class object; \
friend class RawObject; \
friend class Heap; \
friend class Simulator; \
friend class SimulatorHelpers; \
DISALLOW_ALLOCATION(); \
DISALLOW_IMPLICIT_CONSTRUCTORS(Raw##object)
@@ -665,6 +667,8 @@ class RawObject {
friend class StackFrame; // GetCodeObject assertion.
friend class CodeLookupTableBuilder; // profiler
friend class NativeEntry; // GetClassId
friend class Simulator;
friend class SimulatorHelpers;
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(RawObject);
+11 -2
View File
@@ -1540,9 +1540,13 @@ RawObjectPool* ObjectPool::ReadFrom(SnapshotReader* reader,
break;
}
case ObjectPool::kNativeEntry: {
#if !defined(TARGET_ARCH_DBC)
// Read nothing. Initialize with the lazy link entry.
uword new_entry = NativeEntry::LinkNativeCallEntry();
result->SetRawValueAt(i, static_cast<intptr_t>(new_entry));
#else
UNREACHABLE(); // DBC does not support lazy native call linking.
#endif
break;
}
default:
@@ -1592,14 +1596,16 @@ void RawObjectPool::WriteTo(SnapshotWriter* writer,
Entry& entry = ptr()->data()[i];
switch (entry_type) {
case ObjectPool::kTaggedObject: {
#if !defined(TARGET_ARCH_DBC)
if (entry.raw_obj_ == StubCode::CallNativeCFunction_entry()->code()) {
// Natives can run while precompiling, becoming linked and switching
// their stub. Reset to the initial stub used for lazy-linking.
writer->WriteObjectImpl(
StubCode::CallBootstrapCFunction_entry()->code(), kAsReference);
} else {
writer->WriteObjectImpl(entry.raw_obj_, kAsReference);
break;
}
#endif
writer->WriteObjectImpl(entry.raw_obj_, kAsReference);
break;
}
case ObjectPool::kImmediate: {
@@ -1608,6 +1614,9 @@ void RawObjectPool::WriteTo(SnapshotWriter* writer,
}
case ObjectPool::kNativeEntry: {
// Write nothing. Will initialize with the lazy link entry.
#if defined(TARGET_ARCH_DBC)
UNREACHABLE(); // DBC does not support lazy native call linking.
#endif
break;
}
default:
+29
View File
@@ -0,0 +1,29 @@
// Copyright (c) 2016, 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/globals.h"
#if defined(TARGET_ARCH_DBC)
#include "vm/runtime_entry.h"
#include "vm/assembler.h"
#include "vm/simulator.h"
#include "vm/stub_code.h"
namespace dart {
uword RuntimeEntry::GetEntryPoint() const {
return reinterpret_cast<uword>(function());
}
void RuntimeEntry::Call(Assembler* assembler, intptr_t argument_count) const {
UNIMPLEMENTED();
}
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+2
View File
@@ -17,6 +17,8 @@
#include "vm/simulator_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/simulator_mips.h"
#elif defined(TARGET_ARCH_DBC)
#include "vm/simulator_dbc.h"
#else
#error Unknown architecture.
#endif // defined(TARGET_ARCH_...)
+1 -2
View File
@@ -44,7 +44,6 @@ DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX,
// The runtime then does a Longjmp on that buffer to return to the simulator.
class SimulatorSetjmpBuffer {
public:
int Setjmp() { return setjmp(buffer_); }
void Longjmp() {
// "This" is now the last setjmp buffer.
simulator_->set_last_setjmp_buffer(this);
@@ -1546,7 +1545,7 @@ void Simulator::SupervisorCall(Instr* instr) {
ASSERT(sizeof(NativeArguments) == 4*kWordSize);
arguments.thread_ = reinterpret_cast<Thread*>(get_register(R0));
arguments.argc_tag_ = get_register(R1);
arguments.argv_ = reinterpret_cast<RawObject*(*)[]>(get_register(R2));
arguments.argv_ = reinterpret_cast<RawObject**>(get_register(R2));
arguments.retval_ = reinterpret_cast<RawObject**>(get_register(R3));
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
+4
View File
@@ -52,6 +52,10 @@ class Simulator {
void set_register(Register reg, int32_t value);
int32_t get_register(Register reg) const;
int32_t get_sp() const {
return get_register(SPREG);
}
// Special case of set_register and get_register to access the raw PC value.
void set_pc(int32_t value);
int32_t get_pc() const;
-1
View File
@@ -43,7 +43,6 @@ DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX,
// The runtime then does a Longjmp on that buffer to return to the simulator.
class SimulatorSetjmpBuffer {
public:
int Setjmp() { return setjmp(buffer_); }
void Longjmp() {
// "This" is now the last setjmp buffer.
simulator_->set_last_setjmp_buffer(this);
+4
View File
@@ -65,6 +65,10 @@ class Simulator {
void get_vregister(VRegister reg, simd_value_t* value) const;
void set_vregister(VRegister reg, const simd_value_t& value);
int64_t get_sp() const {
return get_register(SPREG);
}
int64_t get_pc() const;
int64_t get_last_pc() const;
void set_pc(int64_t pc);
File diff suppressed because it is too large Load Diff
+182
View File
@@ -0,0 +1,182 @@
// Copyright (c) 2016, 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 VM_SIMULATOR_DBC_H_
#define VM_SIMULATOR_DBC_H_
#ifndef VM_SIMULATOR_H_
#error Do not include simulator_dbc.h directly; use simulator.h.
#endif
#include "vm/constants_dbc.h"
#include "vm/method_recognizer.h"
namespace dart {
class Isolate;
class RawObject;
class SimulatorSetjmpBuffer;
class Thread;
class Code;
class Array;
class RawICData;
class RawArray;
class RawObjectPool;
class RawFunction;
// Simulator intrinsic handler. It is invoked on entry to the intrinsified
// function via Intrinsic bytecode before the frame is setup.
// If the handler returns true then Intrinsic bytecode works as a return
// instruction returning the value in result. Otherwise interpreter proceeds to
// execute the body of the function.
typedef bool (*IntrinsicHandler)(Thread* thread,
RawObject** FP,
RawObject** result);
class Simulator {
public:
static const uword kSimulatorStackUnderflowSize = 64;
Simulator();
~Simulator();
// The currently executing Simulator instance, which is associated to the
// current isolate
static Simulator* Current();
// Accessors to the internal simulator stack base and top.
uword StackBase() const { return reinterpret_cast<uword>(stack_); }
uword StackTop() const;
// The isolate's top_exit_frame_info refers to a Dart frame in the simulator
// stack. The simulator's top_exit_frame_info refers to a C++ frame in the
// native stack.
uword top_exit_frame_info() const { return top_exit_frame_info_; }
void set_top_exit_frame_info(uword value) { top_exit_frame_info_ = value; }
// Call on program start.
static void InitOnce();
RawObject* Call(const Code& code,
const Array& arguments_descriptor,
const Array& arguments,
Thread* thread);
void Longjmp(uword pc,
uword sp,
uword fp,
RawObject* raw_exception,
RawObject* raw_stacktrace,
Thread* thread);
uword get_sp() const {
return reinterpret_cast<uword>(sp_);
}
enum IntrinsicId {
#define V(test_class_name, test_function_name, enum_name, fp) \
k##enum_name##Intrinsic,
ALL_INTRINSICS_LIST(V)
GRAPH_INTRINSICS_LIST(V)
#undef V
kIntrinsicCount,
};
static bool IsSupportedIntrinsic(IntrinsicId id) {
return intrinsics_[id] != NULL;
}
enum SpecialIndex {
kExceptionSpecialIndex,
kStacktraceSpecialIndex,
kSpecialIndexCount
};
private:
uintptr_t* stack_;
RawObject** fp_;
RawObject** sp_;
uword pc_;
SimulatorSetjmpBuffer* last_setjmp_buffer_;
uword top_exit_frame_info_;
RawObject* special_[kSpecialIndexCount];
static IntrinsicHandler intrinsics_[kIntrinsicCount];
void Exit(Thread* thread,
RawObject** base,
RawObject** exit_frame,
uint32_t* pc);
void CallRuntime(Thread* thread,
RawObject** base,
RawObject** exit_frame,
uint32_t* pc,
intptr_t argc_tag,
RawObject** args,
RawObject** result,
uword target);
void Invoke(Thread* thread,
RawObject** call_base,
RawObject** call_top,
RawObjectPool** pp,
uint32_t** pc,
RawObject*** B,
RawObject*** SP);
void InlineCacheMiss(int checked_args,
Thread* thread,
RawICData* icdata,
RawObject** call_base,
RawObject** top,
uint32_t* pc,
RawObject** B, RawObject** SP);
void InstanceCall1(Thread* thread,
RawICData* icdata,
RawObject** call_base,
RawObject** call_top,
RawArray** argdesc,
RawObjectPool** pp,
uint32_t** pc,
RawObject*** B, RawObject*** SP);
void InstanceCall2(Thread* thread,
RawICData* icdata,
RawObject** call_base,
RawObject** call_top,
RawArray** argdesc,
RawObjectPool** pp,
uint32_t** pc,
RawObject*** B, RawObject*** SP);
void InstanceCall3(Thread* thread,
RawICData* icdata,
RawObject** call_base,
RawObject** call_top,
RawArray** argdesc,
RawObjectPool** pp,
uint32_t** pc,
RawObject*** B, RawObject*** SP);
// Longjmp support for exceptions.
SimulatorSetjmpBuffer* last_setjmp_buffer() {
return last_setjmp_buffer_;
}
void set_last_setjmp_buffer(SimulatorSetjmpBuffer* buffer) {
last_setjmp_buffer_ = buffer;
}
friend class SimulatorSetjmpBuffer;
DISALLOW_COPY_AND_ASSIGN(Simulator);
};
} // namespace dart
#endif // VM_SIMULATOR_DBC_H_
+1 -2
View File
@@ -43,7 +43,6 @@ DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX,
// The runtime then does a Longjmp on that buffer to return to the simulator.
class SimulatorSetjmpBuffer {
public:
int Setjmp() { return setjmp(buffer_); }
void Longjmp() {
// "This" is now the last setjmp buffer.
simulator_->set_last_setjmp_buffer(this);
@@ -1257,7 +1256,7 @@ void Simulator::DoBreak(Instr *instr) {
ASSERT(sizeof(NativeArguments) == 4*kWordSize);
arguments.thread_ = reinterpret_cast<Thread*>(get_register(A0));
arguments.argc_tag_ = get_register(A1);
arguments.argv_ = reinterpret_cast<RawObject*(*)[]>(get_register(A2));
arguments.argv_ = reinterpret_cast<RawObject**>(get_register(A2));
arguments.retval_ = reinterpret_cast<RawObject**>(get_register(A3));
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
+4
View File
@@ -58,6 +58,10 @@ class Simulator {
int64_t get_dregister_bits(DRegister freg) const;
double get_dregister(DRegister freg) const;
int32_t get_sp() const {
return get_register(SPREG);
}
// Accessor for the pc.
void set_pc(int32_t value) { pc_ = value; }
int32_t get_pc() const { return pc_; }
+24
View File
@@ -69,6 +69,7 @@ void ExitFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
void EntryFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
#if !defined(TARGET_ARCH_DBC)
ASSERT(thread() == Thread::Current());
// Visit objects between SP and (FP - callee_save_area).
ASSERT(visitor != NULL);
@@ -76,10 +77,17 @@ void EntryFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
RawObject** last = reinterpret_cast<RawObject**>(
fp() + (kExitLinkSlotFromEntryFp - 1) * kWordSize);
visitor->VisitPointers(first, last);
#else
// On DBC stack is growing upwards which implies fp() <= sp().
RawObject** first = reinterpret_cast<RawObject**>(fp());
RawObject** last = reinterpret_cast<RawObject**>(sp());
visitor->VisitPointers(first, last);
#endif
}
void StackFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
#if !defined(TARGET_ARCH_DBC)
// NOTE: This code runs while GC is in progress and runs within
// a NoHandleScope block. Hence it is not ok to use regular Zone or
// Scope handles. We use direct stack handles, the raw pointers in
@@ -159,6 +167,13 @@ void StackFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
RawObject** last = reinterpret_cast<RawObject**>(
fp() + (kFirstObjectSlotFromFp * kWordSize));
visitor->VisitPointers(first, last);
#else
// On DBC stack grows upwards: fp() <= sp().
RawObject** first = reinterpret_cast<RawObject**>(
fp() + (kFirstObjectSlotFromFp * kWordSize));
RawObject** last = reinterpret_cast<RawObject**>(sp());
visitor->VisitPointers(first, last);
#endif // !defined(TARGET_ARCH_DBC)
}
@@ -319,6 +334,7 @@ StackFrameIterator::StackFrameIterator(uword last_fp, bool validate,
}
#if !defined(TARGET_ARCH_DBC)
StackFrameIterator::StackFrameIterator(uword fp, uword sp, uword pc,
bool validate, Thread* thread)
: validate_(validate),
@@ -333,6 +349,7 @@ StackFrameIterator::StackFrameIterator(uword fp, uword sp, uword pc,
frames_.sp_ = sp;
frames_.pc_ = pc;
}
#endif
StackFrame* StackFrameIterator::NextFrame() {
@@ -353,6 +370,7 @@ StackFrame* StackFrameIterator::NextFrame() {
return NULL;
}
UnpoisonStack(frames_.fp_);
#if !defined(TARGET_ARCH_DBC)
if (frames_.pc_ == 0) {
// Iteration starts from an exit frame given by its fp.
current_frame_ = NextExitFrame();
@@ -364,6 +382,12 @@ StackFrame* StackFrameIterator::NextFrame() {
// Iteration starts from a Dart or stub frame given by its fp, sp, and pc.
current_frame_ = frames_.NextFrame(validate_);
}
#else
// Iteration starts from an exit frame given by its fp. This is the only
// mode supported on DBC.
ASSERT(frames_.pc_ == 0);
current_frame_ = NextExitFrame();
#endif // !defined(TARGET_ARCH_DBC)
return current_frame_;
}
ASSERT((validate_ == kDontValidateFrames) || current_frame_->IsValid());
+32 -1
View File
@@ -19,6 +19,8 @@
#include "vm/stack_frame_arm64.h"
#elif defined(TARGET_ARCH_MIPS)
#include "vm/stack_frame_mips.h"
#elif defined(TARGET_ARCH_DBC)
#include "vm/stack_frame_dbc.h"
#else
#error Unknown architecture.
#endif
@@ -101,10 +103,12 @@ class StackFrame : public ValueObject {
uword GetCallerSp() const {
return fp() + (kCallerSpSlotFromFp * kWordSize);
}
uword GetCallerFp() const {
return *(reinterpret_cast<uword*>(
fp() + (kSavedCallerFpSlotFromFp * kWordSize)));
fp() + (kSavedCallerFpSlotFromFp * kWordSize)));
}
uword GetCallerPc() const {
return *(reinterpret_cast<uword*>(
fp() + (kSavedCallerPcSlotFromFp * kWordSize)));
@@ -188,10 +192,12 @@ class StackFrameIterator : public ValueObject {
StackFrameIterator(uword last_fp, bool validate,
Thread* thread = Thread::Current());
#if !defined(TARGET_ARCH_DBC)
// Iterator for iterating over all frames from the current frame (given by its
// fp, sp, and pc) to the first EntryFrame.
StackFrameIterator(uword fp, uword sp, uword pc, bool validate,
Thread* thread = Thread::Current());
#endif
// Checks if a next frame exists.
bool HasNextFrame() const { return frames_.fp_ != 0; }
@@ -272,6 +278,8 @@ class DartFrameIterator : public ValueObject {
DartFrameIterator(uword last_fp,
Thread* thread = Thread::Current())
: frames_(last_fp, StackFrameIterator::kDontValidateFrames, thread) { }
#if !defined(TARGET_ARCH_DBC)
DartFrameIterator(uword fp,
uword sp,
uword pc,
@@ -279,6 +287,8 @@ class DartFrameIterator : public ValueObject {
: frames_(fp, sp, pc,
StackFrameIterator::kDontValidateFrames, thread) {
}
#endif
// Get next dart frame.
StackFrame* NextFrame() {
StackFrame* frame = frames_.NextFrame();
@@ -336,6 +346,27 @@ class InlinedFunctionsIterator : public ValueObject {
DISALLOW_COPY_AND_ASSIGN(InlinedFunctionsIterator);
};
#if !defined(TARGET_ARCH_DBC)
DART_FORCE_INLINE static uword LocalVarAddress(uword fp, intptr_t index) {
return fp + (index * kWordSize);
}
DART_FORCE_INLINE static uword ParamAddress(uword fp, intptr_t reverse_index) {
return fp + (kParamEndSlotFromFp * kWordSize) + (reverse_index * kWordSize);
}
DART_FORCE_INLINE static bool IsCalleeFrameOf(uword fp, uword other_fp) {
return other_fp < fp;
}
// Value for stack limit that is used to cause an interrupt.
// Note that on DBC stack is growing upwards so interrupt limit is 0 unlike
// on all other architectures.
static const uword kInterruptStackLimit = ~static_cast<uword>(0);
#endif
} // namespace dart
#endif // VM_STACK_FRAME_H_
+85
View File
@@ -0,0 +1,85 @@
// Copyright (c) 2016, 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 VM_STACK_FRAME_DBC_H_
#define VM_STACK_FRAME_DBC_H_
namespace dart {
/* DBC Frame Layout
IMPORTANT: On DBC stack is growing upwards which is different from all other
architectures. This enables effecient addressing for locals via unsigned index.
| | <- TOS
Callee frame | ... |
| saved FP | (FP of current frame)
| saved PC | (PC of current frame)
| code object |
| function object |
+--------------------+
Current frame | ... T| <- SP of current frame
| ... T|
| first local T| <- FP of current frame
| caller's FP *|
| caller's PC *|
| code object T| (current frame's code object)
| function object T| (current frame's function object)
+--------------------+
Caller frame | last parameter | <- SP of caller frame
| ... |
T against a slot indicates it needs to be traversed during GC.
* against a slot indicates that it can be traversed during GC
because it will look like a smi to the visitor.
*/
static const int kDartFrameFixedSize = 4; // Function, Code, PC, FP
static const int kSavedPcSlotFromSp = 3;
static const int kFirstObjectSlotFromFp = -4; // Used by GC to traverse stack.
static const int kSavedCallerFpSlotFromFp = -1;
static const int kSavedCallerPpSlotFromFp = kSavedCallerFpSlotFromFp;
static const int kSavedCallerPcSlotFromFp = -2;
static const int kCallerSpSlotFromFp = -kDartFrameFixedSize-1;
static const int kPcMarkerSlotFromFp = -3;
static const int kFunctionSlotFromFp = -4;
// Note: These constants don't match actual DBC behavior. This is done because
// setting kFirstLocalSlotFromFp to 0 breaks assumptions spread across the code.
// Instead for the purposes of local variable allocation we pretend that DBC
// behaves as other architectures (stack growing downwards) and later fix
// these indices during code generation in the backend.
static const int kParamEndSlotFromFp = 4; // One slot past last parameter.
static const int kFirstLocalSlotFromFp = -1;
DART_FORCE_INLINE static uword LocalVarAddress(uword fp, intptr_t index) {
ASSERT(index != 0);
if (index > 0) {
return fp - index * kWordSize;
} else {
return fp - (index + 1) * kWordSize;
}
}
DART_FORCE_INLINE static uword ParamAddress(uword fp, intptr_t reverse_index) {
return fp - (kDartFrameFixedSize + reverse_index) * kWordSize;
}
DART_FORCE_INLINE static bool IsCalleeFrameOf(uword fp, uword other_fp) {
return other_fp > fp;
}
static const int kExitLinkSlotFromEntryFp = 0;
// Value for stack limit that is used to cause an interrupt.
// Note that on DBC stack is growing upwards so interrupt limit is 0 unlike
// on all other architectures.
static const uword kInterruptStackLimit = 0;
} // namespace dart
#endif // VM_STACK_FRAME_DBC_H_
+25
View File
@@ -85,30 +85,47 @@ void StubCode::VisitObjectPointers(ObjectPointerVisitor* visitor) {
bool StubCode::HasBeenInitialized() {
#if !defined(TARGET_ARCH_DBC)
// Use JumpToExceptionHandler and InvokeDart as canaries.
const StubEntry* entry_1 = StubCode::JumpToExceptionHandler_entry();
const StubEntry* entry_2 = StubCode::InvokeDartCode_entry();
return (entry_1 != NULL) && (entry_2 != NULL);
#else
return true;
#endif
}
bool StubCode::InInvocationStub(uword pc) {
#if !defined(TARGET_ARCH_DBC)
ASSERT(HasBeenInitialized());
uword entry = StubCode::InvokeDartCode_entry()->EntryPoint();
uword size = StubCode::InvokeDartCodeSize();
return (pc >= entry) && (pc < (entry + size));
#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::InJumpToExceptionHandlerStub(uword pc) {
#if !defined(TARGET_ARCH_DBC)
ASSERT(HasBeenInitialized());
uword entry = StubCode::JumpToExceptionHandler_entry()->EntryPoint();
uword size = StubCode::JumpToExceptionHandlerSize();
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));
@@ -169,11 +186,16 @@ RawCode* StubCode::GetAllocationStubForClass(const Class& cls) {
}
}
return stub.raw();
#endif
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();
@@ -185,6 +207,9 @@ const StubEntry* StubCode::UnoptimizedStaticCallEntry(
UNIMPLEMENTED();
return NULL;
}
#else
return NULL;
#endif
}
+8 -1
View File
@@ -18,9 +18,9 @@ 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(GetStackPointer) \
V(JumpToExceptionHandler) \
@@ -65,6 +65,13 @@ class SnapshotWriter;
V(CallClosureNoSuchMethod) \
V(FrameAwaitingMaterialization) \
#else
#define VM_STUB_CODE_LIST(V) \
V(LazyCompile) \
V(FixCallersTarget) \
#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,
+66
View File
@@ -0,0 +1,66 @@
// Copyright (c) 2016, 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/globals.h"
#if defined(TARGET_ARCH_DBC)
#include "vm/assembler.h"
#include "vm/code_generator.h"
#include "vm/cpu.h"
#include "vm/compiler.h"
#include "vm/dart_entry.h"
#include "vm/flow_graph_compiler.h"
#include "vm/heap.h"
#include "vm/instructions.h"
#include "vm/object_store.h"
#include "vm/stack_frame.h"
#include "vm/stub_code.h"
#include "vm/tags.h"
#define __ assembler->
namespace dart {
DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects.");
DEFINE_FLAG(bool, use_slow_path, false,
"Set to true for debugging & verifying the slow paths.");
DECLARE_FLAG(bool, trace_optimized_ic_calls);
DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, support_debugger);
DECLARE_FLAG(bool, lazy_dispatchers);
void StubCode::GenerateLazyCompileStub(Assembler* assembler) {
__ Compile();
}
// TODO(vegorov) Don't generate this stub.
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
__ Trap();
}
// TODO(vegorov) Don't generate these stubs.
void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
const Class& cls) {
__ Trap();
}
// TODO(vegorov) Don't generate this stub.
void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
__ Trap();
}
// Print the stop message.
DEFINE_LEAF_RUNTIME_ENTRY(void, PrintStopMessage, 1, const char* message) {
OS::Print("Stop message: %s\n", message);
}
END_LEAF_RUNTIME_ENTRY
} // namespace dart
#endif // defined TARGET_ARCH_DBC
+10 -2
View File
@@ -318,6 +318,7 @@ void Thread::PrepareForGC() {
void Thread::SetStackLimitFromStackBase(uword stack_base) {
// Set stack limit.
#if !defined(TARGET_ARCH_DBC)
#if defined(USING_SIMULATOR)
// Ignore passed-in native stack top and use Simulator stack top.
Simulator* sim = Simulator::Current(); // May allocate a simulator.
@@ -326,6 +327,9 @@ void Thread::SetStackLimitFromStackBase(uword stack_base) {
// The overflow area is accounted for by the simulator.
#endif
SetStackLimit(stack_base - OSThread::GetSpecifiedStackSize());
#else
SetStackLimit(Simulator::Current()->StackTop());
#endif // !defined(TARGET_ARCH_DBC)
}
@@ -348,11 +352,15 @@ void Thread::ClearStackLimit() {
/* static */
uword Thread::GetCurrentStackPointer() {
#if !defined(TARGET_ARCH_DBC)
// Since AddressSanitizer's detect_stack_use_after_return instruments the
// C++ code to give out fake stack addresses, we call a stub in that case.
ASSERT(StubCode::GetStackPointer_entry() != NULL);
uword (*func)() = reinterpret_cast<uword (*)()>(
StubCode::GetStackPointer_entry()->EntryPoint());
#else
uword (*func)() = NULL;
#endif
// But for performance (and to support simulators), we normally use a local.
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
@@ -390,7 +398,7 @@ void Thread::ScheduleInterruptsLocked(uword interrupt_bits) {
}
if (stack_limit_ == saved_stack_limit_) {
stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
stack_limit_ = kInterruptStackLimit & ~kInterruptsMask;
}
stack_limit_ |= interrupt_bits;
}
@@ -437,7 +445,7 @@ void Thread::RestoreOOBMessageInterrupts() {
deferred_interrupts_mask_ = 0;
if (deferred_interrupts_ != 0) {
if (stack_limit_ == saved_stack_limit_) {
stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
stack_limit_ = kInterruptStackLimit & ~kInterruptsMask;
}
stack_limit_ |= deferred_interrupts_;
deferred_interrupts_ = 0;
+29 -6
View File
@@ -70,11 +70,10 @@ class Zone;
V(TypeParameter) \
// List of VM-global objects/addresses cached in each Thread object.
#define CACHED_VM_OBJECTS_LIST(V) \
V(RawObject*, object_null_, Object::null(), NULL) \
V(RawBool*, bool_true_, Object::bool_true().raw(), NULL) \
V(RawBool*, bool_false_, Object::bool_false().raw(), NULL) \
#if defined(TARGET_ARCH_DBC)
#define CACHED_VM_STUBS_LIST(V)
#else
#define CACHED_VM_STUBS_LIST(V) \
V(RawCode*, update_store_buffer_code_, \
StubCode::UpdateStoreBuffer_entry()->code(), NULL) \
V(RawCode*, fix_callers_target_code_, \
@@ -86,11 +85,28 @@ class Zone;
V(RawCode*, call_to_runtime_stub_, \
StubCode::CallToRuntime_entry()->code(), NULL) \
#define CACHED_ADDRESSES_LIST(V) \
#endif
// List of VM-global objects/addresses cached in each Thread object.
#define CACHED_VM_OBJECTS_LIST(V) \
V(RawObject*, object_null_, Object::null(), NULL) \
V(RawBool*, bool_true_, Object::bool_true().raw(), NULL) \
V(RawBool*, bool_false_, Object::bool_false().raw(), NULL) \
CACHED_VM_STUBS_LIST(V) \
#if defined(TARGET_ARCH_DBC)
#define CACHED_VM_STUBS_ADDRESSES_LIST(V)
#else
#define CACHED_VM_STUBS_ADDRESSES_LIST(V) \
V(uword, update_store_buffer_entry_point_, \
StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0) \
V(uword, call_to_runtime_entry_point_, \
StubCode::CallToRuntime_entry()->EntryPoint(), 0) \
#endif
#define CACHED_ADDRESSES_LIST(V) \
CACHED_VM_STUBS_ADDRESSES_LIST(V) \
V(uword, native_call_wrapper_entry_point_, \
NativeEntry::NativeCallWrapperEntry(), 0) \
V(RawString**, predefined_symbols_address_, \
@@ -175,6 +191,13 @@ class Thread : public BaseThread {
// The true stack limit for this isolate.
uword saved_stack_limit() const { return saved_stack_limit_; }
#if defined(TARGET_ARCH_DBC)
// Access to the current stack limit for DBC interpreter.
uword stack_limit() const {
return stack_limit_;
}
#endif
// Stack overflow flags
enum {
kOsrRequest = 0x1, // Current stack overflow caused by OSR request.
+6 -4
View File
@@ -157,10 +157,12 @@
#if defined(TARGET_ARCH_ARM) || \
defined(TARGET_ARCH_MIPS) || \
defined(TARGET_ARCH_ARM64)
defined(TARGET_ARCH_ARM64) || \
defined(TARGET_ARCH_DBC)
#if defined(HOST_ARCH_ARM) || \
defined(HOST_ARCH_MIPS) || \
defined(HOST_ARCH_ARM64)
defined(HOST_ARCH_ARM64) || \
!defined(TARGET_ARCH_DBC)
// Running on actual ARM or MIPS hardware, execute code natively.
#define EXECUTE_TEST_CODE_INT32(name, entry) reinterpret_cast<name>(entry)()
#define EXECUTE_TEST_CODE_INT64(name, entry) reinterpret_cast<name>(entry)()
@@ -374,7 +376,7 @@ class AssemblerTest {
// using the ABI calling convention.
// ResultType is the return type of the assembler test function.
// ArgNType is the type of the Nth argument.
#if defined(USING_SIMULATOR)
#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
#if defined(ARCH_IS_64_BIT)
// TODO(fschneider): Make InvokeWithCodeAndThread<> more general and work on
@@ -454,7 +456,7 @@ class AssemblerTest {
typedef ResultType (*FunctionType) (Arg1Type, Arg2Type, Arg3Type);
return reinterpret_cast<FunctionType>(entry())(arg1, arg2, arg3);
}
#endif // USING_SIMULATOR
#endif // defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
// Assemble test and set code_.
void Assemble();
+15
View File
@@ -19,6 +19,8 @@
'assembler_arm64.cc',
'assembler_arm64.h',
'assembler_arm64_test.cc',
'assembler_dbc.cc',
'assembler_dbc.h',
'assembler_ia32.cc',
'assembler_ia32.h',
'assembler_ia32_test.cc',
@@ -89,6 +91,7 @@
'code_patcher_arm_test.cc',
'code_patcher_arm64.cc',
'code_patcher_arm64_test.cc',
'code_patcher_dbc.cc',
'code_patcher_ia32.cc',
'code_patcher_ia32_test.cc',
'code_patcher_mips.cc',
@@ -110,6 +113,7 @@
'cpu.h',
'cpu_arm.cc',
'cpu_arm64.cc',
'cpu_dbc.cc',
'cpu_ia32.cc',
'cpu_mips.cc',
'cpu_test.cc',
@@ -140,6 +144,7 @@
'debugger_api_impl_test.cc',
'debugger_arm.cc',
'debugger_arm64.cc',
'debugger_dbc.cc',
'debugger_ia32.cc',
'debugger_mips.cc',
'debugger_x64.cc',
@@ -151,6 +156,7 @@
'disassembler.h',
'disassembler_arm.cc',
'disassembler_arm64.cc',
'disassembler_dbc.cc',
'disassembler_ia32.cc',
'disassembler_mips.cc',
'disassembler_test.cc',
@@ -177,6 +183,7 @@
'flow_graph_compiler.h',
'flow_graph_compiler_arm.cc',
'flow_graph_compiler_arm64.cc',
'flow_graph_compiler_dbc.cc',
'flow_graph_compiler_ia32.cc',
'flow_graph_compiler_mips.cc',
'flow_graph_compiler_x64.cc',
@@ -218,6 +225,8 @@
'instructions_arm64.cc',
'instructions_arm64.h',
'instructions_arm64_test.cc',
'instructions_dbc.cc',
'instructions_dbc.h',
'instructions_ia32.cc',
'instructions_ia32.h',
'instructions_ia32_test.cc',
@@ -231,6 +240,7 @@
'intermediate_language.h',
'intermediate_language_arm.cc',
'intermediate_language_arm64.cc',
'intermediate_language_dbc.cc',
'intermediate_language_ia32.cc',
'intermediate_language_mips.cc',
'intermediate_language_test.cc',
@@ -239,6 +249,7 @@
'intrinsifier.h',
'intrinsifier_arm.cc',
'intrinsifier_arm64.cc',
'intrinsifier_dbc.cc',
'intrinsifier_ia32.cc',
'intrinsifier_mips.cc',
'intrinsifier_x64.cc',
@@ -377,6 +388,7 @@
'runtime_entry_list.h',
'runtime_entry_arm.cc',
'runtime_entry_arm64.cc',
'runtime_entry_dbc.cc',
'runtime_entry_ia32.cc',
'runtime_entry_mips.cc',
'runtime_entry.cc',
@@ -410,6 +422,8 @@
'simulator_arm.h',
'simulator_arm64.cc',
'simulator_arm64.h',
'simulator_dbc.cc',
'simulator_dbc.h',
'simulator_mips.cc',
'simulator_mips.h',
'snapshot.cc',
@@ -436,6 +450,7 @@
'stub_code_arm_test.cc',
'stub_code_arm64.cc',
'stub_code_arm64_test.cc',
'stub_code_dbc.cc',
'stub_code_ia32.cc',
'stub_code_ia32_test.cc',
'stub_code_mips.cc',
+5
View File
@@ -163,3 +163,8 @@ LibTest/typed_data/Uint32List/runtimeType_A01_t01: Fail,OK # Expects exact type
LibTest/typed_data/Uint64List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
LibTest/typed_data/Uint8ClampedList/runtimeType_A01_t01: Fail,OK # Expects exact type name.
LibTest/typed_data/Uint8List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
[ $arch == simdbc && $mode == debug ]
# TODO(vegorov) These tests are very slow on unoptimized SIMDBC
LibTest/collection/ListMixin/ListMixin_class_A01_t02: Timeout
LibTest/collection/ListBase/ListBase_class_A01_t02: Timeout
+4 -1
View File
@@ -207,4 +207,7 @@ int_parse_radix_test: Pass, Timeout # --no_intrinsify
data_resource_test: Skip # Resolve URI not supported yet in product mode.
package_resource_test: Skip # Resolve URI not supported yet in product mode.
file_resource_test: Skip # Resolve URI not supported yet in product mode.
http_resource_test: Skip # Resolve URI not supported yet in product mode.
http_resource_test: Skip # Resolve URI not supported yet in product mode.
[ $arch == simdbc ]
regexp/stack-overflow_test: RuntimeError, OK # Smaller limit with irregex interpreter
+8
View File
@@ -211,3 +211,11 @@ library_env_test/has_no_mirror_support: RuntimeError, OK
[ $noopt || $compiler == precompiler || $mode == product ]
# The following tests are supposed to fail.
library_env_test/has_mirror_support: RuntimeError, OK
[ $arch == simdbc ]
# TODO(vegorov) StopInstr is unimplemented.
vm/debug_break_enabled_vm_test/none: Skip
# TODO(vegorov) Encoding limitation: StoreField bytecode only supports 256
# fields in an object.
large_class_declaration_test: Skip
+5
View File
@@ -362,3 +362,8 @@ mirrors/*: SkipByDesign
[ $noopt || $compiler == precompiler ]
convert/chunked_conversion_utf88_test: Pass, Timeout
convert/utf85_test: Pass, Timeout
[ $arch == simdbc ]
# TODO(vegorov) LoadField bytecode supports only up to 256 fields. Need a long
# version.
mirrors/accessor_cache_overflow_test: Skip
+10
View File
@@ -285,3 +285,13 @@ package/scenarios/invalid/non_existent_packages_file_test: Skip
package/scenarios/empty_packages_file/empty_packages_file_noimports_test: Skip
package/scenarios/packages_option_only/packages_option_only_noimports_test: Skip
package/scenarios/packages_option_only/packages_option_only_test: Skip
[ $arch == simdbc ]
# TODO(vegorov) SIMDBC interpreter doesn't support coverage yet.
full_coverage_test: Skip
# SIMDBC interpreter doesn't support lazy linking of natives.
link_natives_lazily_test: SkipByDesign
# SIMDBC interpreter doesn't support --no_lazy_dispatchers
no_lazy_dispatchers_test: SkipByDesign
+7 -5
View File
@@ -56,7 +56,7 @@ def BuildOptions():
result.add_option("-a", "--arch",
help='Target architectures (comma-separated).',
metavar='[all,ia32,x64,simarm,arm,simarmv6,armv6,simarmv5te,armv5te,'
'simmips,mips,simarm64,arm64,]',
'simmips,mips,simarm64,arm64,simdbc,]',
default=utils.GuessArchitecture())
result.add_option("--os",
help='Target OSs (comma-separated).',
@@ -102,7 +102,8 @@ def ProcessOptions(options, args):
return False
for arch in options.arch:
archs = ['ia32', 'x64', 'simarm', 'arm', 'simarmv6', 'armv6',
'simarmv5te', 'armv5te', 'simmips', 'mips', 'simarm64', 'arm64',]
'simarmv5te', 'armv5te', 'simmips', 'mips', 'simarm64', 'arm64',
'simdbc',]
if not arch in archs:
print "Unknown arch %s" % arch
return False
@@ -119,7 +120,8 @@ def ProcessOptions(options, args):
print ("Cross-compilation to %s is not supported on host os %s."
% (os_name, HOST_OS))
return False
if not arch in ['ia32', 'x64', 'arm', 'armv6', 'armv5te', 'arm64', 'mips']:
if not arch in ['ia32', 'x64', 'arm', 'armv6', 'armv5te', 'arm64', 'mips',
'simdbc',]:
print ("Cross-compilation to %s is not supported for architecture %s."
% (os_name, arch))
return False
@@ -137,7 +139,7 @@ def GetToolchainPrefix(target_os, arch, options):
if target_os == 'android':
android_toolchain = GetAndroidToolchainDir(HOST_OS, arch)
if arch == 'arm':
if arch == 'arm' or arch == 'simdbc':
return os.path.join(android_toolchain, 'arm-linux-androideabi')
if arch == 'arm64':
return os.path.join(android_toolchain, 'aarch64-linux-android')
@@ -197,7 +199,7 @@ def GetAndroidToolchainDir(host_os, target_arch):
global THIRD_PARTY_ROOT
if host_os not in ['linux']:
raise Exception('Unsupported host os %s' % host_os)
if target_arch not in ['ia32', 'x64', 'arm', 'arm64']:
if target_arch not in ['ia32', 'x64', 'arm', 'arm64', 'simdbc']:
raise Exception('Unsupported target architecture %s' % target_arch)
# Set up path to the Android NDK.
+29
View File
@@ -26,6 +26,7 @@
['"<(target_arch)"=="simarm64"', { 'dart_target_arch': 'SIMARM64', }],
['"<(target_arch)"=="mips"', { 'dart_target_arch': 'MIPS', }],
['"<(target_arch)"=="simmips"', { 'dart_target_arch': 'SIMMIPS', }],
['"<(target_arch)"=="simdbc"', { 'dart_target_arch': 'SIMDBC', }],
[ 'OS=="linux"', { 'dart_target_os': 'Linux', } ],
[ 'OS=="mac"', { 'dart_target_os': 'Macos', } ],
[ 'OS=="win"', { 'dart_target_os': 'Win', } ],
@@ -132,6 +133,14 @@
],
},
'Dart_simdbc_Base': {
'abstract': 1,
'defines': [
'TARGET_ARCH_DBC',
'USING_SIMULATOR',
]
},
'Dart_Debug': {
'abstract': 1,
},
@@ -356,6 +365,26 @@
],
},
'DebugSIMDBC': {
'inherit_from': [
'Dart_Base', 'Dart_simdbc_Base', 'Dart_Debug',
'Dart_<(dart_target_os)_Base',
'Dart_<(dart_target_os)_simdbc_Base',
'Dart_<(dart_target_os)_Debug',
],
'defines': [
'DEBUG',
],
},
'ReleaseSIMDBC': {
'inherit_from': [
'Dart_Base', 'Dart_simdbc_Base', 'Dart_Release',
'Dart_<(dart_target_os)_Base',
'Dart_<(dart_target_os)_simdbc_Base',
'Dart_<(dart_target_os)_Release',
],
},
# ARM and MIPS hardware configurations are only for Linux and Android.
'DebugXARM': {
+6
View File
@@ -113,6 +113,12 @@
],
},
'Dart_Linux_simdbc_Base': {
'abstract': 1,
'cflags': [ '-O3', '-m32', '-msse2', '-mfpmath=sse' ],
'ldflags': [ '-m32', ],
},
# ARM cross-build
'Dart_Linux_xarm_Base': {
'abstract': 1,
@@ -171,6 +171,7 @@ class DartVmRuntimeConfiguration extends RuntimeConfiguration {
case 'simmips':
case 'mips':
case 'simarm64':
case 'simdbc':
multiplier *= 4;
break;
}
+2 -1
View File
@@ -148,7 +148,8 @@ class TestOptionsParser {
'simarmv6',
'simarmv5te',
'simarm64',
'simmips'
'simmips',
'simdbc'
],
'x64'),
new _TestOptionSpecification(
+1
View File
@@ -240,6 +240,7 @@ ARCH_FAMILY = {
'simarmv5te': 'ia32',
'simmips': 'ia32',
'simarm64': 'ia32',
'simdbc': 'ia32',
}
ARCH_GUESS = GuessArchitecture()