mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:41:41 +00:00
Begins work on ARM64, first assembler test.
Most new code is in constants_arm64.h and {assembler,disassembler,simulator}_arm64.{h,cc} The rest of the CL just #def's out tests, modifies status files, and adds UNIMPLEMENTED functions, etc. R=regis@google.com Review URL: https://codereview.chromium.org//221133002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@34654 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
7a0660513f
commit
2fe51715e5
|
@ -264,6 +264,9 @@ matcher/test/*_minified_test: Skip # DO NOT COPY THIS UNLESS YOU WORK ON DART2JS
|
|||
[ $arch == simarm && $checked ]
|
||||
watcher/test/directory_watcher/linux_test: Skip # Issue 16118
|
||||
|
||||
[ $arch == simarm64 ]
|
||||
*: Skip
|
||||
|
||||
# Skip serialization test that explicitly has no library declaration in the
|
||||
# test on Dartium, which requires all tests to have a library.
|
||||
[ $compiler == none && ( $runtime == dartium || $runtime == drt ) ]
|
||||
|
|
|
@ -67,6 +67,14 @@
|
|||
]}],
|
||||
],
|
||||
},
|
||||
# Added by Dart.
|
||||
'Dart_simarm64_Base': {
|
||||
'defines': [
|
||||
'NSS_X86_OR_X64',
|
||||
'NSS_X64',
|
||||
'NSS_USE_64',
|
||||
],
|
||||
},
|
||||
},
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
|
|
|
@ -196,6 +196,7 @@ typedef double fpu_register_t;
|
|||
#if !defined(TARGET_ARCH_ARM)
|
||||
#if !defined(TARGET_ARCH_X64)
|
||||
#if !defined(TARGET_ARCH_IA32)
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
// No target architecture specified pick the one matching the host architecture.
|
||||
#if defined(HOST_ARCH_MIPS)
|
||||
#define TARGET_ARCH_MIPS 1
|
||||
|
@ -205,6 +206,8 @@ typedef double fpu_register_t;
|
|||
#define TARGET_ARCH_X64 1
|
||||
#elif defined(HOST_ARCH_IA32)
|
||||
#define TARGET_ARCH_IA32 1
|
||||
#elif defined(HOST_ARCH_ARM64)
|
||||
#define TARGET_ARCH_ARM64 1
|
||||
#else
|
||||
#error Automatic target architecture detection failed.
|
||||
#endif
|
||||
|
@ -212,10 +215,12 @@ typedef double 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.
|
||||
#if defined(TARGET_ARCH_X64)
|
||||
#if defined(TARGET_ARCH_X64) || \
|
||||
defined(TARGET_ARCH_ARM64)
|
||||
#if !defined(ARCH_IS_64_BIT)
|
||||
#error Mismatched Host/Target architectures.
|
||||
#endif
|
||||
|
|
|
@ -75,6 +75,9 @@ cc/StaticNonNullSumCallCodegen: Crash, Pass # dartbug.com/17440
|
|||
[ $arch == mips && $mode == debug ]
|
||||
cc/FindCodeObject: Skip # Takes more than 8 minutes. dartbug.com/17440.
|
||||
|
||||
[ $arch == simarm64 ]
|
||||
dart/*: Skip
|
||||
|
||||
[ $compiler == none && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
|
||||
dart/mirrored_compilation_error_test: Skip # Can't pass needed VM flag
|
||||
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
|
||||
namespace dart {
|
||||
|
||||
#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
|
||||
#if defined(TARGET_ARCH_ARM) || \
|
||||
defined(TARGET_ARCH_ARM64) || \
|
||||
defined(TARGET_ARCH_MIPS)
|
||||
DECLARE_FLAG(bool, use_far_branches);
|
||||
#endif
|
||||
|
||||
|
@ -217,6 +219,8 @@ class AssemblerBuffer : public ValueObject {
|
|||
#include "vm/assembler_x64.h"
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
#include "vm/assembler_arm.h"
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
#include "vm/assembler_arm64.h"
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
#include "vm/assembler_mips.h"
|
||||
#else
|
||||
|
|
78
runtime/vm/assembler_arm64.cc
Normal file
78
runtime/vm/assembler_arm64.cc
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) 2014, 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_ARM64)
|
||||
|
||||
#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"
|
||||
|
||||
// An extra check since we are assuming the existence of /proc/cpuinfo below.
|
||||
#if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID)
|
||||
#error ARM64 cross-compile only supported on Linux
|
||||
#endif
|
||||
|
||||
namespace dart {
|
||||
|
||||
DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
|
||||
DECLARE_FLAG(bool, inline_alloc);
|
||||
|
||||
|
||||
void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) {
|
||||
ASSERT(Utils::IsAligned(data, 4));
|
||||
ASSERT(Utils::IsAligned(length, 4));
|
||||
const uword end = data + length;
|
||||
while (data < end) {
|
||||
*reinterpret_cast<int32_t*>(data) = Instr::kBreakPointInstruction;
|
||||
data += 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Assembler::Stop(const char* message) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Assembler::Emit(int32_t value) {
|
||||
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
|
||||
buffer_.Emit<int32_t>(value);
|
||||
}
|
||||
|
||||
|
||||
static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "ip0", "ip1", "pp", "ctx", "fp", "lr", "r31",
|
||||
};
|
||||
|
||||
|
||||
const char* Assembler::RegisterName(Register reg) {
|
||||
ASSERT((0 <= reg) && (reg < kNumberOfCpuRegisters));
|
||||
return cpu_reg_names[reg];
|
||||
}
|
||||
|
||||
|
||||
static const char* fpu_reg_names[kNumberOfFpuRegisters] = {
|
||||
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
|
||||
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
|
||||
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
|
||||
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
|
||||
};
|
||||
|
||||
|
||||
const char* Assembler::FpuRegisterName(FpuRegister reg) {
|
||||
ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters));
|
||||
return fpu_reg_names[reg];
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
357
runtime/vm/assembler_arm64.h
Normal file
357
runtime/vm/assembler_arm64.h
Normal file
|
@ -0,0 +1,357 @@
|
|||
// Copyright (c) 2014, 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_ARM64_H_
|
||||
#define VM_ASSEMBLER_ARM64_H_
|
||||
|
||||
#ifndef VM_ASSEMBLER_H_
|
||||
#error Do not include assembler_arm64.h directly; use assembler.h instead.
|
||||
#endif
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/utils.h"
|
||||
#include "vm/constants_arm64.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/simulator.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
// Forward declarations.
|
||||
class RuntimeEntry;
|
||||
|
||||
// TODO(zra): Label, Address, and FieldAddress are copied from ARM,
|
||||
// they must be adapted to ARM64.
|
||||
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 Address : public ValueObject {
|
||||
public:
|
||||
Address(const Address& other)
|
||||
: ValueObject(), encoding_(other.encoding_) {
|
||||
}
|
||||
|
||||
Address& operator=(const Address& other) {
|
||||
encoding_ = other.encoding_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Address(Register rn, int32_t offset = 0) {
|
||||
ASSERT(Utils::IsAbsoluteUint(12, offset));
|
||||
encoding_ = -1;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t encoding() const { return encoding_; }
|
||||
|
||||
uint32_t encoding_;
|
||||
|
||||
friend class Assembler;
|
||||
};
|
||||
|
||||
|
||||
class FieldAddress : public Address {
|
||||
public:
|
||||
FieldAddress(Register base, int32_t disp)
|
||||
: Address(base, disp - kHeapObjectTag) { }
|
||||
|
||||
FieldAddress(const FieldAddress& other) : Address(other) { }
|
||||
|
||||
FieldAddress& operator=(const FieldAddress& other) {
|
||||
Address::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Operand : public ValueObject {
|
||||
public:
|
||||
// Data-processing operand - Uninitialized.
|
||||
Operand() : encoding_(-1), type_(Unknown) { }
|
||||
|
||||
// Data-processing operands - Copy constructor.
|
||||
Operand(const Operand& other)
|
||||
: ValueObject(), encoding_(other.encoding_), type_(other.type_) { }
|
||||
|
||||
explicit Operand(Register rm) {
|
||||
ASSERT((rm != R31) && (rm != SP));
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
encoding_ = (static_cast<int32_t>(crm) << kRmShift);
|
||||
}
|
||||
|
||||
Operand(Register rm, Shift shift, int32_t imm) {
|
||||
ASSERT(Utils::IsUint(6, imm));
|
||||
ASSERT((rm != R31) && (rm != SP));
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
encoding_ =
|
||||
(imm << kImm6Shift) |
|
||||
(static_cast<int32_t>(crm) << kRmShift) |
|
||||
(static_cast<int32_t>(shift) << kShiftTypeShift);
|
||||
type_ = Shifted;
|
||||
}
|
||||
|
||||
Operand(Register rm, Extend extend, int32_t imm) {
|
||||
ASSERT(Utils::IsUint(3, imm));
|
||||
ASSERT((rm != R31) && (rm != SP));
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
encoding_ =
|
||||
B21 |
|
||||
(static_cast<int32_t>(crm) << kRmShift) |
|
||||
(static_cast<int32_t>(extend) << kExtendTypeShift) |
|
||||
((imm & 0x7) << kImm3Shift);
|
||||
type_ = Extended;
|
||||
}
|
||||
|
||||
explicit Operand(int32_t imm) {
|
||||
if (Utils::IsUint(12, imm)) {
|
||||
encoding_ = imm << kImm12Shift;
|
||||
} else {
|
||||
// imm only has bits in [12, 24) set.
|
||||
ASSERT(((imm & 0xfff) == 0) && (Utils::IsUint(12, imm >> 12)));
|
||||
encoding_ = B22 | ((imm >> 12) << kImm12Shift);
|
||||
}
|
||||
type_ = Immediate;
|
||||
}
|
||||
|
||||
// TODO(zra): Add bitfield immediate operand
|
||||
// Operand(int32_t n, int32_t imms, int32_t immr);
|
||||
|
||||
enum OperandType {
|
||||
Shifted,
|
||||
Extended,
|
||||
Immediate,
|
||||
BitfieldImm,
|
||||
Unknown,
|
||||
};
|
||||
|
||||
private:
|
||||
uint32_t encoding() const {
|
||||
return encoding_;
|
||||
}
|
||||
OperandType type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
uint32_t encoding_;
|
||||
OperandType type_;
|
||||
|
||||
friend class Assembler;
|
||||
};
|
||||
|
||||
|
||||
class Assembler : public ValueObject {
|
||||
public:
|
||||
explicit Assembler(bool use_far_branches = false)
|
||||
: buffer_(),
|
||||
object_pool_(GrowableObjectArray::Handle()),
|
||||
prologue_offset_(-1),
|
||||
use_far_branches_(use_far_branches),
|
||||
comments_() { }
|
||||
~Assembler() { }
|
||||
|
||||
void PopRegister(Register r) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void Drop(intptr_t stack_elements) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void Bind(Label* label) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
// Misc. functionality
|
||||
intptr_t CodeSize() const { return buffer_.Size(); }
|
||||
intptr_t prologue_offset() const { return prologue_offset_; }
|
||||
|
||||
// Count the fixups that produce a pointer offset, without processing
|
||||
// the fixups. On ARM64 there are no pointers in code.
|
||||
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();
|
||||
}
|
||||
const GrowableObjectArray& object_pool() const { return object_pool_; }
|
||||
|
||||
bool use_far_branches() const {
|
||||
return FLAG_use_far_branches || use_far_branches_;
|
||||
}
|
||||
|
||||
void set_use_far_branches(bool b) {
|
||||
ASSERT(buffer_.Size() == 0);
|
||||
use_far_branches_ = b;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
const Code::Comments& GetCodeComments() const;
|
||||
|
||||
static const char* RegisterName(Register reg);
|
||||
|
||||
static const char* FpuRegisterName(FpuRegister reg);
|
||||
|
||||
// TODO(zra): Make sure this is right.
|
||||
// Instruction pattern from entrypoint is used in Dart frame prologs
|
||||
// to set up the frame and save a PC which can be used to figure out the
|
||||
// RawInstruction object corresponding to the code running in the frame.
|
||||
static const intptr_t kEntryPointToPcMarkerOffset = 0;
|
||||
|
||||
// Emit data (e.g encoded instruction or immediate) in instruction stream.
|
||||
void Emit(int32_t value);
|
||||
|
||||
// On some other platforms, we draw a distinction between safe and unsafe
|
||||
// smis.
|
||||
static bool IsSafe(const Object& object) { return true; }
|
||||
static bool IsSafeSmi(const Object& object) { return object.IsSmi(); }
|
||||
|
||||
void add(Register rd, Register rn, Operand o) {
|
||||
AddSubHelper(kDoubleWord, false, false, rd, rn, o);
|
||||
}
|
||||
void addw(Register rd, Register rn, Operand o) {
|
||||
AddSubHelper(kWord, false, false, rd, rn, o);
|
||||
}
|
||||
|
||||
// Function return.
|
||||
void ret(Register rn = R30) {
|
||||
EmitUnconditionalBranchRegOp(RET, rn);
|
||||
}
|
||||
|
||||
private:
|
||||
AssemblerBuffer buffer_; // Contains position independent code.
|
||||
GrowableObjectArray& object_pool_; // Objects and patchable jump targets.
|
||||
int32_t prologue_offset_;
|
||||
|
||||
bool use_far_branches_;
|
||||
|
||||
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_;
|
||||
|
||||
void AddSubHelper(OperandSize os, bool set_flags, bool subtract,
|
||||
Register rd, Register rn, Operand o) {
|
||||
ASSERT((rd != R31) && (rn != R31));
|
||||
const Register crd = ConcreteRegister(rd);
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
if (o.type() == Operand::Immediate) {
|
||||
ASSERT((rd != ZR) && (rn != ZR));
|
||||
EmitAddSubImmOp(subtract ? SUBI : ADDI, crd, crn, o, os, set_flags);
|
||||
} else {
|
||||
if (o.type() == Operand::Shifted) {
|
||||
ASSERT((rd != SP) && (rn != SP));
|
||||
EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags);
|
||||
} else {
|
||||
ASSERT(o.type() == Operand::Extended);
|
||||
ASSERT((rd != SP) && (rn != ZR));
|
||||
EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmitAddSubImmOp(AddSubImmOp op, Register rd, Register rn,
|
||||
Operand o, OperandSize os, bool set_flags) {
|
||||
ASSERT((os == kDoubleWord) || (os == kWord));
|
||||
const int32_t size = (os == kDoubleWord) ? B31 : 0;
|
||||
const int32_t s = set_flags ? B29 : 0;
|
||||
const int32_t encoding =
|
||||
op | size | s |
|
||||
(static_cast<int32_t>(rd) << kRdShift) |
|
||||
(static_cast<int32_t>(rn) << kRnShift) |
|
||||
o.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
void EmitAddSubShiftExtOp(AddSubShiftExtOp op,
|
||||
Register rd, Register rn, Operand o,
|
||||
OperandSize os, bool set_flags) {
|
||||
ASSERT((os == kDoubleWord) || (os == kWord));
|
||||
const int32_t size = (os == kDoubleWord) ? B31 : 0;
|
||||
const int32_t s = set_flags ? B29 : 0;
|
||||
const int32_t encoding =
|
||||
op | size | s |
|
||||
(static_cast<int32_t>(rd) << kRdShift) |
|
||||
(static_cast<int32_t>(rn) << kRnShift) |
|
||||
o.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) {
|
||||
const int32_t encoding =
|
||||
op | (static_cast<int32_t>(rn) << kRnShift);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(Assembler);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_ASSEMBLER_ARM64_H_
|
32
runtime/vm/assembler_arm64_test.cc
Normal file
32
runtime/vm/assembler_arm64_test.cc
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 2013, 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_ARM64)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/unit_test.h"
|
||||
#include "vm/virtual_memory.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
#define __ assembler->
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Simple, assembler) {
|
||||
__ add(R0, ZR, Operand(ZR));
|
||||
__ add(R0, R0, Operand(42));
|
||||
__ ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Simple, test) {
|
||||
typedef int (*SimpleCode)();
|
||||
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(TARGET_ARCH_ARM64)
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when test is ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/os.h"
|
||||
|
@ -73,3 +77,5 @@ ASSEMBLER_TEST_RUN(StoreIntoObject, test) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "bin/file.h"
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
|
||||
#include "vm/dart_api_impl.h"
|
||||
#include "vm/stack_frame.h"
|
||||
|
@ -30,6 +31,8 @@ void Benchmark::RunAll(const char* executable) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
//
|
||||
// Measure compile of all functions in dart core lib classes.
|
||||
|
@ -578,4 +581,6 @@ BENCHMARK(SimpleMessage) {
|
|||
benchmark->set_score(elapsed_time);
|
||||
}
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/cha.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
|
@ -127,3 +131,5 @@ TEST_CASE(ClassHierarchyAnalysis) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/globals.h"
|
||||
|
||||
|
@ -280,3 +284,5 @@ TEST_CASE(StackmapGC) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/ast.h"
|
||||
|
@ -566,3 +570,5 @@ CODEGEN_TEST_RAW_RUN(AllocateNewObjectCodegen, function) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
88
runtime/vm/code_patcher_arm64.cc
Normal file
88
runtime/vm/code_patcher_arm64.cc
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Copyright (c) 2014, 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_ARM64.
|
||||
#if defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "vm/code_patcher.h"
|
||||
|
||||
#include "vm/instructions.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
RawArray* CodePatcher::GetClosureArgDescAt(uword return_address,
|
||||
const Code& code) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uword CodePatcher::GetStaticCallTargetAt(uword return_address,
|
||||
const Code& code) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CodePatcher::PatchStaticCallAt(uword return_address,
|
||||
const Code& code,
|
||||
uword new_target) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void CodePatcher::PatchInstanceCallAt(uword return_address,
|
||||
const Code& code,
|
||||
uword new_target) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
int32_t CodePatcher::GetPoolOffsetAt(uword return_address) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CodePatcher::SetPoolOffsetAt(uword return_address, int32_t offset) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void CodePatcher::InsertCallAt(uword start, uword target) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
uword CodePatcher::GetInstanceCallAt(uword return_address,
|
||||
const Code& code,
|
||||
ICData* ic_data) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
intptr_t CodePatcher::InstanceCallSizeInBytes() {
|
||||
// The instance call instruction sequence has a variable size on ARM.
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
RawFunction* CodePatcher::GetUnoptimizedStaticCallAt(
|
||||
uword return_address, const Code& code, ICData* ic_data_result) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
RawObject* CodePatcher::GetEdgeCounterAt(uword pc, const Code& code) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
10
runtime/vm/code_patcher_arm64_test.cc
Normal file
10
runtime/vm/code_patcher_arm64_test.cc
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) 2014, 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_ARM64)
|
||||
|
||||
// TODO(zra): Port these tests.
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
#include "vm/compiler.h"
|
||||
|
@ -98,3 +102,5 @@ TEST_CASE(EvalExpression) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
519
runtime/vm/constants_arm64.h
Normal file
519
runtime/vm/constants_arm64.h
Normal file
|
@ -0,0 +1,519 @@
|
|||
// Copyright (c) 2014, 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_ARM64_H_
|
||||
#define VM_CONSTANTS_ARM64_H_
|
||||
|
||||
#include "platform/assert.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
enum Register {
|
||||
kFirstFreeCpuRegister = 0,
|
||||
R0 = 0,
|
||||
R1 = 1,
|
||||
R2 = 2,
|
||||
R3 = 3,
|
||||
R4 = 4,
|
||||
R5 = 5,
|
||||
R6 = 6,
|
||||
R7 = 7,
|
||||
R8 = 8,
|
||||
R9 = 9,
|
||||
R10 = 10,
|
||||
R11 = 11,
|
||||
R12 = 12,
|
||||
R13 = 13,
|
||||
R14 = 14,
|
||||
R15 = 15,
|
||||
R16 = 16,
|
||||
R17 = 17,
|
||||
R18 = 18,
|
||||
R19 = 19,
|
||||
R20 = 20,
|
||||
R21 = 21,
|
||||
R22 = 22,
|
||||
R23 = 23,
|
||||
R24 = 24,
|
||||
kLastFreeCpuRegister = 24,
|
||||
R25 = 25, // IP0
|
||||
R26 = 26, // IP1
|
||||
R27 = 27, // PP
|
||||
R28 = 28, // CTX
|
||||
R29 = 29, // FP
|
||||
R30 = 30, // LR
|
||||
R31 = 31, // ZR, SP
|
||||
kNumberOfCpuRegisters = 32,
|
||||
kNoRegister = -1,
|
||||
|
||||
// Aliases.
|
||||
IP0 = R25,
|
||||
IP1 = R26,
|
||||
FP = R29,
|
||||
LR = R30,
|
||||
|
||||
// Left abstract so we can avoid misuse.
|
||||
SP,
|
||||
ZR,
|
||||
};
|
||||
|
||||
enum VRegister {
|
||||
V0 = 0,
|
||||
V1 = 1,
|
||||
V2 = 2,
|
||||
V3 = 3,
|
||||
V4 = 4,
|
||||
V5 = 5,
|
||||
V6 = 6,
|
||||
V7 = 7,
|
||||
V8 = 8,
|
||||
V9 = 9,
|
||||
V10 = 10,
|
||||
V11 = 11,
|
||||
V12 = 12,
|
||||
V13 = 13,
|
||||
V14 = 14,
|
||||
V15 = 15,
|
||||
V16 = 16,
|
||||
V17 = 17,
|
||||
V18 = 18,
|
||||
V19 = 19,
|
||||
V20 = 20,
|
||||
V21 = 21,
|
||||
V22 = 22,
|
||||
V23 = 24,
|
||||
V24 = 24,
|
||||
V25 = 25,
|
||||
V26 = 26,
|
||||
V27 = 27,
|
||||
V28 = 28,
|
||||
V29 = 29,
|
||||
V30 = 30,
|
||||
V31 = 31,
|
||||
kNumberOfVRegisters = 32,
|
||||
kNoVRegister = -1,
|
||||
};
|
||||
|
||||
// Register alias for floating point scratch register.
|
||||
const VRegister VTMP0 = V30;
|
||||
const VRegister VTMP1 = V31;
|
||||
|
||||
// Architecture independent aliases.
|
||||
typedef VRegister FpuRegister;
|
||||
const FpuRegister FpuTMP = VTMP0;
|
||||
const int kNumberOfFpuRegisters = kNumberOfVRegisters;
|
||||
const FpuRegister kNoFpuRegister = kNoVRegister;
|
||||
|
||||
// Register aliases.
|
||||
const Register TMP = R25; // Used as scratch register by assembler.
|
||||
const Register TMP0 = R25;
|
||||
const Register TMP1 = R26;
|
||||
const Register CTX = R27; // Caches current context in generated code.
|
||||
const Register PP = R26; // Caches object pool pointer in generated code.
|
||||
const Register SPREG = R31; // Stack pointer register.
|
||||
const Register FPREG = FP; // Frame pointer register.
|
||||
const Register ICREG = R5; // IC data register.
|
||||
|
||||
// Exception object is passed in this register to the catch handlers when an
|
||||
// exception is thrown.
|
||||
const Register kExceptionObjectReg = R0;
|
||||
|
||||
// Stack trace object is passed in this register to the catch handlers when
|
||||
// an exception is thrown.
|
||||
const Register kStackTraceObjectReg = R1;
|
||||
|
||||
// Masks, sizes, etc.
|
||||
const int kXRegSizeInBits = 64;
|
||||
const int kWRegSizeInBits = 32;
|
||||
const int64_t kXRegMask = 0xffffffffffffffffL;
|
||||
const int64_t kWRegMask = 0x00000000ffffffffL;
|
||||
|
||||
// List of registers used in load/store multiple.
|
||||
typedef uint32_t RegList;
|
||||
const RegList kAllCpuRegistersList = 0xFFFF;
|
||||
|
||||
|
||||
// C++ ABI call registers.
|
||||
const RegList kAbiArgumentCpuRegs =
|
||||
(1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) |
|
||||
(1 << R4) | (1 << R5) | (1 << R6) | (1 << R7);
|
||||
const RegList kAbiPreservedCpuRegs =
|
||||
(1 << R19) | (1 << R20) | (1 << R21) | (1 << R22) |
|
||||
(1 << R23) | (1 << R24) | (1 << R25) | (1 << R26) |
|
||||
(1 << R27) | (1 << R28) | (1 << R29);
|
||||
const int kAbiPreservedCpuRegCount = 11;
|
||||
const VRegister kAbiFirstPreservedFpuReg = V8;
|
||||
const VRegister kAbiLastPreservedFpuReg = V15;
|
||||
const int kAbiPreservedFpuRegCount = 8;
|
||||
|
||||
// CPU registers available to Dart allocator.
|
||||
const RegList kDartAvailableCpuRegs =
|
||||
(1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) |
|
||||
(1 << R4) | (1 << R5) | (1 << R6) | (1 << R7) |
|
||||
(1 << R8) | (1 << R9) | (1 << R10) | (1 << R11) |
|
||||
(1 << R12) | (1 << R13) | (1 << R14) | (1 << R15) |
|
||||
(1 << R16) | (1 << R17) | (1 << R18) | (1 << R19) |
|
||||
(1 << R20) | (1 << R21) | (1 << R22) | (1 << R23) |
|
||||
(1 << R24);
|
||||
|
||||
// Registers available to Dart that are not preserved by runtime calls.
|
||||
const RegList kDartVolatileCpuRegs =
|
||||
kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs;
|
||||
const int kDartVolatileCpuRegCount = 19;
|
||||
const VRegister kDartFirstVolatileFpuReg = V0;
|
||||
const VRegister kDartLastVolatileFpuReg = V7;
|
||||
const int kDartVolatileFpuRegCount = 8;
|
||||
|
||||
static inline Register ConcreteRegister(Register r) {
|
||||
return ((r == ZR) || (r == SP)) ? R31 : r;
|
||||
}
|
||||
|
||||
// Values for the condition field as defined in section A3.2.
|
||||
enum Condition {
|
||||
kNoCondition = -1,
|
||||
EQ = 0, // equal
|
||||
NE = 1, // not equal
|
||||
CS = 2, // carry set/unsigned higher or same
|
||||
CC = 3, // carry clear/unsigned lower
|
||||
MI = 4, // minus/negative
|
||||
PL = 5, // plus/positive or zero
|
||||
VS = 6, // overflow
|
||||
VC = 7, // no overflow
|
||||
HI = 8, // unsigned higher
|
||||
LS = 9, // unsigned lower or same
|
||||
GE = 10, // signed greater than or equal
|
||||
LT = 11, // signed less than
|
||||
GT = 12, // signed greater than
|
||||
LE = 13, // signed less than or equal
|
||||
AL = 14, // always (unconditional)
|
||||
NV = 15, // special condition (refer to section C1.2.3)
|
||||
kMaxCondition = 16,
|
||||
};
|
||||
|
||||
enum Bits {
|
||||
B0 = (1 << 0), B1 = (1 << 1), B2 = (1 << 2), B3 = (1 << 3),
|
||||
B4 = (1 << 4), B5 = (1 << 5), B6 = (1 << 6), B7 = (1 << 7),
|
||||
B8 = (1 << 8), B9 = (1 << 9), B10 = (1 << 10), B11 = (1 << 11),
|
||||
B12 = (1 << 12), B13 = (1 << 13), B14 = (1 << 14), B15 = (1 << 15),
|
||||
B16 = (1 << 16), B17 = (1 << 17), B18 = (1 << 18), B19 = (1 << 19),
|
||||
B20 = (1 << 20), B21 = (1 << 21), B22 = (1 << 22), B23 = (1 << 23),
|
||||
B24 = (1 << 24), B25 = (1 << 25), B26 = (1 << 26), B27 = (1 << 27),
|
||||
B28 = (1 << 28), B29 = (1 << 29), B30 = (1 << 30), B31 = (1 << 31),
|
||||
};
|
||||
|
||||
enum OperandSize {
|
||||
kByte,
|
||||
kUnsignedByte,
|
||||
kHalfword,
|
||||
kUnsignedHalfword,
|
||||
kWord,
|
||||
kUnsignedWord,
|
||||
kDoubleWord,
|
||||
kSWord,
|
||||
kDWord,
|
||||
};
|
||||
|
||||
// Opcodes from C3
|
||||
// C3.1.
|
||||
enum MainOp {
|
||||
DPImmediateMask = 0x1c000000,
|
||||
DPImmediateFixed = B28,
|
||||
|
||||
CompareBranchMask = 0x1c000000,
|
||||
CompareBranchFixed = B28 | B26,
|
||||
|
||||
LoadStoreMask = B27 | B25,
|
||||
LoadStoreFixed = B27,
|
||||
|
||||
DPRegisterMask = 0x0e000000,
|
||||
DPRegisterFixed = B27 | B25,
|
||||
|
||||
DPSimd1Mask = 0x1e000000,
|
||||
DPSimd1Fixed = B27 | B26 | B25,
|
||||
|
||||
DPSimd2Mask = 0x1e000000,
|
||||
DPSimd2Fixed = B28 | DPSimd1Fixed,
|
||||
};
|
||||
|
||||
// C3.2.3
|
||||
enum ExceptionGenOp {
|
||||
ExceptionGenMask = 0xff000000,
|
||||
ExceptionGenFixed = CompareBranchFixed | B31 | B30,
|
||||
SVC = ExceptionGenFixed | B0,
|
||||
BRK = ExceptionGenFixed | B21,
|
||||
HLT = ExceptionGenFixed | B22,
|
||||
};
|
||||
|
||||
// C3.2.4
|
||||
enum SystemOp {
|
||||
SystemMask = 0xffc00000,
|
||||
SystemFixed = CompareBranchFixed | B31 | B30 | B24,
|
||||
HINT = SystemFixed | B17 | B16 | B13 | B4 | B3 | B2 | B1 | B0,
|
||||
};
|
||||
|
||||
// C3.2.7
|
||||
enum UnconditionalBranchRegOp {
|
||||
UnconditionalBranchRegMask = 0xfe000000,
|
||||
UnconditionalBranchRegFixed = CompareBranchFixed | B31 | B30 | B25,
|
||||
BR = UnconditionalBranchRegFixed | B20 | B19 | B18 | B17 | B16,
|
||||
BLR = BR | B21,
|
||||
RET = BR | B22,
|
||||
};
|
||||
|
||||
// C3.4.1
|
||||
enum AddSubImmOp {
|
||||
AddSubImmMask = 0x1f000000,
|
||||
AddSubImmFixed = DPImmediateFixed | B24,
|
||||
ADDI = AddSubImmFixed,
|
||||
SUBI = AddSubImmFixed | B30,
|
||||
};
|
||||
|
||||
// C3.4.5
|
||||
enum MoveWideOp {
|
||||
MoveWideMask = 0x1f800000,
|
||||
MoveWideFixed = DPImmediateFixed | B25 | B23,
|
||||
MOVN = MoveWideFixed,
|
||||
MOVZ = MoveWideFixed | B30,
|
||||
MOVK = MoveWideFixed | B30 | B29,
|
||||
};
|
||||
|
||||
|
||||
// C3.5.1
|
||||
enum AddSubShiftExtOp {
|
||||
AddSubShiftExtMask = 0x1f200000,
|
||||
AddSubShiftExtFixed = DPRegisterFixed | B24,
|
||||
ADD = AddSubShiftExtFixed,
|
||||
SUB = AddSubShiftExtFixed | B30,
|
||||
};
|
||||
|
||||
#define APPLY_OP_LIST(_V) \
|
||||
_V(DPImmediate) \
|
||||
_V(CompareBranch) \
|
||||
_V(LoadStore) \
|
||||
_V(DPRegister) \
|
||||
_V(DPSimd1) \
|
||||
_V(DPSimd2) \
|
||||
_V(ExceptionGen) \
|
||||
_V(System) \
|
||||
_V(UnconditionalBranchReg) \
|
||||
_V(AddSubImm) \
|
||||
_V(MoveWide) \
|
||||
_V(AddSubShiftExt) \
|
||||
|
||||
|
||||
enum Shift {
|
||||
kNoShift = -1,
|
||||
LSL = 0, // Logical shift left
|
||||
LSR = 1, // Logical shift right
|
||||
ASR = 2, // Arithmetic shift right
|
||||
ROR = 3, // Rotate right
|
||||
kMaxShift = 4,
|
||||
};
|
||||
|
||||
enum Extend {
|
||||
kNoExtend = -1,
|
||||
UXTB = 0,
|
||||
UXTH = 1,
|
||||
UXTW = 2,
|
||||
UXTX = 3,
|
||||
SXTB = 4,
|
||||
SXTH = 5,
|
||||
SXTW = 6,
|
||||
SXTX = 7,
|
||||
kMaxExtend = 8,
|
||||
};
|
||||
|
||||
enum R31Type {
|
||||
R31IsSP,
|
||||
R31IsZR,
|
||||
R31IsUndef,
|
||||
};
|
||||
|
||||
// Constants used for the decoding or encoding of the individual fields of
|
||||
// instructions. Based on the "Figure 3-1 ARM instruction set summary".
|
||||
enum InstructionFields {
|
||||
// S-bit (modify condition register)
|
||||
kSShift = 29,
|
||||
kSBits = 1,
|
||||
|
||||
// sf field.
|
||||
kSFShift = 31,
|
||||
kSFBits = 1,
|
||||
|
||||
// Registers.
|
||||
kRdShift = 0,
|
||||
kRdBits = 5,
|
||||
kRnShift = 5,
|
||||
kRnBits = 5,
|
||||
kRaShift = 10,
|
||||
kRaBits = 5,
|
||||
kRmShift = 16,
|
||||
kRmBits = 5,
|
||||
|
||||
// Immediates.
|
||||
kImm3Shift = 10,
|
||||
kImm3Bits = 3,
|
||||
kImm6Shift = 10,
|
||||
kImm6Bits = 6,
|
||||
kImm12Shift = 10,
|
||||
kImm12Bits = 12,
|
||||
kImm12ShiftShift = 22,
|
||||
kImm12ShiftBits = 2,
|
||||
kImm16Shift = 5,
|
||||
kImm16Bits = 16,
|
||||
|
||||
// Shift and Extend.
|
||||
kShiftExtendShift = 21,
|
||||
kShiftExtendBits = 1,
|
||||
kShiftTypeShift = 22,
|
||||
kShiftTypeBits = 2,
|
||||
kExtendTypeShift = 13,
|
||||
kExtendTypeBits = 3,
|
||||
|
||||
// Hint Fields.
|
||||
kHintCRmShift = 8,
|
||||
kHintCRmBits = 4,
|
||||
kHintOp2Shift = 5,
|
||||
kHintOp2Bits = 3,
|
||||
};
|
||||
|
||||
|
||||
const uint32_t kImmExceptionIsRedirectedCall = 0xca11;
|
||||
const uint32_t kImmExceptionIsUnreachable = 0xdebf;
|
||||
const uint32_t kImmExceptionIsPrintf = 0xdeb1;
|
||||
const uint32_t kImmExceptionIsDebug = 0xdeb0;
|
||||
|
||||
// The class Instr enables access to individual fields defined in the ARM
|
||||
// architecture instruction set encoding as described in figure A3-1.
|
||||
//
|
||||
// Example: Test whether the instruction at ptr sets the condition code bits.
|
||||
//
|
||||
// bool InstructionSetsConditionCodes(byte* ptr) {
|
||||
// Instr* instr = Instr::At(ptr);
|
||||
// int type = instr->TypeField();
|
||||
// return ((type == 0) || (type == 1)) && instr->HasS();
|
||||
// }
|
||||
//
|
||||
class Instr {
|
||||
public:
|
||||
enum {
|
||||
kInstrSize = 4,
|
||||
kInstrSizeLog2 = 2,
|
||||
kPCReadOffset = 8
|
||||
};
|
||||
|
||||
static const int32_t kNopInstruction = HINT; // hint #0 === nop.
|
||||
static const int32_t kBreakPointInstruction = // hlt #kImmExceptionIsDebug.
|
||||
HLT | (kImmExceptionIsDebug << kImm16Shift);
|
||||
static const int kBreakPointInstructionSize = kInstrSize;
|
||||
|
||||
// Get the raw instruction bits.
|
||||
inline int32_t InstructionBits() const {
|
||||
return *reinterpret_cast<const int32_t*>(this);
|
||||
}
|
||||
|
||||
// Set the raw instruction bits to value.
|
||||
inline void SetInstructionBits(int32_t value) {
|
||||
*reinterpret_cast<int32_t*>(this) = value;
|
||||
}
|
||||
|
||||
// Read one particular bit out of the instruction bits.
|
||||
inline int Bit(int nr) const {
|
||||
return (InstructionBits() >> nr) & 1;
|
||||
}
|
||||
|
||||
// Read a bit field out of the instruction bits.
|
||||
inline int Bits(int shift, int count) const {
|
||||
return (InstructionBits() >> shift) & ((1 << count) - 1);
|
||||
}
|
||||
|
||||
|
||||
inline int SField() const { return Bit(kSShift); }
|
||||
inline int SFField() const { return Bit(kSFShift); }
|
||||
inline Register RdField() const { return static_cast<Register>(
|
||||
Bits(kRdShift, kRdBits)); }
|
||||
inline Register RnField() const { return static_cast<Register>(
|
||||
Bits(kRnShift, kRnBits)); }
|
||||
inline Register RaField() const { return static_cast<Register>(
|
||||
Bits(kRaShift, kRaBits)); }
|
||||
inline Register RmField() const { return static_cast<Register>(
|
||||
Bits(kRmShift, kRmBits)); }
|
||||
|
||||
// Immediates
|
||||
inline int Imm3Field() const { return Bits(kImm3Shift, kImm3Bits); }
|
||||
inline int Imm6Field() const { return Bits(kImm6Shift, kImm6Bits); }
|
||||
inline int Imm12Field() const { return Bits(kImm12Shift, kImm12Bits); }
|
||||
inline int Imm16Field() const { return Bits(kImm16Shift, kImm16Bits); }
|
||||
|
||||
inline int Imm12ShiftField() const {
|
||||
return Bits(kImm12ShiftShift, kImm12ShiftBits); }
|
||||
|
||||
// Shift and Extend.
|
||||
inline bool IsShift() const { return (Bit(kShiftExtendShift) == 0); }
|
||||
inline bool IsExtend() const { return (Bit(kShiftExtendShift) == 1); }
|
||||
inline Shift ShiftTypeField() const {
|
||||
return static_cast<Shift>(Bits(kShiftTypeShift, kShiftTypeBits)); }
|
||||
inline Extend ExtendTypeField() const {
|
||||
return static_cast<Extend>(Bits(kExtendTypeShift, kExtendTypeBits)); }
|
||||
inline int ShiftAmountField() const { return Imm6Field(); }
|
||||
inline int ExtShiftAmountField() const { return Imm3Field(); }
|
||||
|
||||
// Instruction identification.
|
||||
#define IS_OP(op) \
|
||||
inline bool Is##op##Op() const { \
|
||||
return ((InstructionBits() & op##Mask) == (op##Fixed & op##Mask)); }
|
||||
APPLY_OP_LIST(IS_OP)
|
||||
#undef IS_OP
|
||||
|
||||
inline bool HasS() const { return (SField() == 1); }
|
||||
|
||||
// Indicate whether Rd can be the SP or ZR. This does not check that the
|
||||
// instruction actually has an Rd field.
|
||||
R31Type RdMode() const {
|
||||
// The following instructions use SP as Rd:
|
||||
// Add/sub (immediate) when not setting the flags.
|
||||
// Add/sub (extended) when not setting the flags.
|
||||
// Logical (immediate) when not setting the flags.
|
||||
// Otherwise, R31 is the ZR.
|
||||
if (IsAddSubImmOp() || (IsAddSubShiftExtOp() && IsExtend())) {
|
||||
if (HasS()) {
|
||||
return R31IsZR;
|
||||
} else {
|
||||
return R31IsSP;
|
||||
}
|
||||
}
|
||||
// TODO(zra): Handle for logical immediate operations.
|
||||
return R31IsZR;
|
||||
}
|
||||
|
||||
// Indicate whether Rn can be SP or ZR. This does not check that the
|
||||
// instruction actually has an Rn field.
|
||||
R31Type RnMode() const {
|
||||
// The following instructions use SP as Rn:
|
||||
// All loads and stores.
|
||||
// Add/sub (immediate).
|
||||
// Add/sub (extended).
|
||||
// Otherwise, r31 is ZR.
|
||||
if (IsLoadStoreOp() ||
|
||||
IsAddSubImmOp() ||
|
||||
(IsAddSubShiftExtOp() && IsExtend())) {
|
||||
return R31IsSP;
|
||||
}
|
||||
return R31IsZR;
|
||||
}
|
||||
|
||||
// Instructions are read out of a code stream. The only way to get a
|
||||
// reference to an instruction is to convert a pointer. There is no way
|
||||
// to allocate or create instances of class Instr.
|
||||
// Use the At(pc) function to create references to Instr.
|
||||
static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
|
||||
|
||||
private:
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_CONSTANTS_ARM64_H_
|
|
@ -29,6 +29,8 @@ class CPU : public AllStatic {
|
|||
#include "vm/cpu_x64.h"
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
#include "vm/cpu_arm.h"
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
#include "vm/cpu_arm64.h"
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
#include "vm/cpu_mips.h"
|
||||
#else
|
||||
|
|
90
runtime/vm/cpu_arm64.cc
Normal file
90
runtime/vm/cpu_arm64.cc
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2014, 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_ARM64)
|
||||
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/cpuinfo.h"
|
||||
#include "vm/simulator.h"
|
||||
|
||||
#if defined(HOST_ARCH_ARM64)
|
||||
#include <sys/syscall.h> /* NOLINT */
|
||||
#include <unistd.h> /* NOLINT */
|
||||
#endif
|
||||
|
||||
namespace dart {
|
||||
|
||||
void CPU::FlushICache(uword start, uword size) {
|
||||
#if defined(USING_SIMULATOR)
|
||||
// Nothing to do.
|
||||
#else
|
||||
UNIMPLEMENTED();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const char* CPU::Id() {
|
||||
return
|
||||
#if !defined(HOST_ARCH_ARM64)
|
||||
"sim"
|
||||
#endif // !defined(HOST_ARCH_ARM64)
|
||||
"arm64";
|
||||
}
|
||||
|
||||
|
||||
const char* HostCPUFeatures::hardware_ = NULL;
|
||||
#if defined(DEBUG)
|
||||
bool HostCPUFeatures::initialized_ = false;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HOST_ARCH_ARM64)
|
||||
void HostCPUFeatures::InitOnce() {
|
||||
CpuInfo::InitOnce();
|
||||
hardware_ = CpuInfo::GetCpuModel();
|
||||
#if defined(DEBUG)
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HostCPUFeatures::Cleanup() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
#if defined(DEBUG)
|
||||
initialized_ = false;
|
||||
#endif
|
||||
ASSERT(hardware_ != NULL);
|
||||
free(const_cast<char*>(hardware_));
|
||||
hardware_ = NULL;
|
||||
CpuInfo::Cleanup();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void HostCPUFeatures::InitOnce() {
|
||||
CpuInfo::InitOnce();
|
||||
hardware_ = CpuInfo::GetCpuModel();
|
||||
#if defined(DEBUG)
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HostCPUFeatures::Cleanup() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
#if defined(DEBUG)
|
||||
initialized_ = false;
|
||||
#endif
|
||||
ASSERT(hardware_ != NULL);
|
||||
free(const_cast<char*>(hardware_));
|
||||
hardware_ = NULL;
|
||||
CpuInfo::Cleanup();
|
||||
}
|
||||
#endif // defined(HOST_ARCH_ARM64)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
55
runtime/vm/cpu_arm64.h
Normal file
55
runtime/vm/cpu_arm64.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) 2014, 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_ARM64_H_
|
||||
#define VM_CPU_ARM64_H_
|
||||
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/simulator.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
// TargetCPUFeatures gives CPU features for the architecture that we are
|
||||
// generating code for. HostCPUFeatures gives the CPU features for the
|
||||
// architecture that we are actually running on. When the architectures
|
||||
// are the same, TargetCPUFeatures will query HostCPUFeatures. When they are
|
||||
// different (i.e. we are running in a simulator), HostCPUFeatures will
|
||||
// additionally mock the options needed for the target architecture so that
|
||||
// they may be altered for testing.
|
||||
|
||||
class HostCPUFeatures: public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static void Cleanup();
|
||||
static const char* hardware() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return hardware_;
|
||||
}
|
||||
|
||||
private:
|
||||
static const char* hardware_;
|
||||
#if defined(DEBUG)
|
||||
static bool initialized_;
|
||||
#endif
|
||||
};
|
||||
|
||||
class TargetCPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce() {
|
||||
HostCPUFeatures::InitOnce();
|
||||
}
|
||||
static void Cleanup() {
|
||||
HostCPUFeatures::Cleanup();
|
||||
}
|
||||
static const char* hardware() {
|
||||
return HostCPUFeatures::hardware();
|
||||
}
|
||||
static bool double_truncate_round_supported() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_CPU_ARM64_H_
|
|
@ -20,6 +20,12 @@ UNIT_TEST_CASE(Id) {
|
|||
#else // defined(HOST_ARCH_ARM)
|
||||
EXPECT_STREQ("simarm", CPU::Id());
|
||||
#endif // defined(HOST_ARCH_ARM)
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
#if defined(HOST_ARCH_ARM64)
|
||||
EXPECT_STREQ("arm64", CPU::Id());
|
||||
#else // defined(HOST_ARCH_ARM64)
|
||||
EXPECT_STREQ("simarm64", CPU::Id());
|
||||
#endif // defined(HOST_ARCH_ARM64)
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
#if defined(HOST_ARCH_MIPS)
|
||||
EXPECT_STREQ("mips", CPU::Id());
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "include/dart_api.h"
|
||||
#include "include/dart_native_api.h"
|
||||
|
||||
|
@ -350,3 +354,5 @@ UNIT_TEST_CASE(CustomIsolates) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -233,12 +233,15 @@ RawError* Dart::InitializeIsolate(const uint8_t* snapshot_buffer, void* data) {
|
|||
Object::VerifyBuiltinVtables();
|
||||
|
||||
StubCode::Init(isolate);
|
||||
// TODO(zra): ifndef to be removed when ARM64 port is ready.
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
if (snapshot_buffer == NULL) {
|
||||
if (!isolate->object_store()->PreallocateObjects()) {
|
||||
return isolate->object_store()->sticky_error();
|
||||
}
|
||||
}
|
||||
isolate->megamorphic_cache_table()->InitMissHandler();
|
||||
#endif
|
||||
|
||||
isolate->heap()->EnableGrowthControl();
|
||||
isolate->set_init_callback_data(data);
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "bin/builtin.h"
|
||||
#include "include/dart_api.h"
|
||||
#include "include/dart_debugger_api.h"
|
||||
|
@ -8094,3 +8098,5 @@ TEST_CASE(ExternalStringIndexOf) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -58,12 +58,22 @@ RawObject* DartEntry::InvokeFunction(const Function& function,
|
|||
ASSERT(!code.IsNull());
|
||||
ASSERT(Isolate::Current()->no_callback_scope_depth() == 0);
|
||||
#if defined(USING_SIMULATOR)
|
||||
#if defined(ARCH_IS_64_BIT)
|
||||
// TODO(zra): Change to intptr_t so we have only one case.
|
||||
return bit_copy<RawObject*, int64_t>(Simulator::Current()->Call(
|
||||
reinterpret_cast<int64_t>(entrypoint),
|
||||
static_cast<int64_t>(code.EntryPoint()),
|
||||
reinterpret_cast<int64_t>(&arguments_descriptor),
|
||||
reinterpret_cast<int64_t>(&arguments),
|
||||
reinterpret_cast<int64_t>(&context)));
|
||||
#else
|
||||
return bit_copy<RawObject*, int64_t>(Simulator::Current()->Call(
|
||||
reinterpret_cast<int32_t>(entrypoint),
|
||||
static_cast<int32_t>(code.EntryPoint()),
|
||||
reinterpret_cast<int32_t>(&arguments_descriptor),
|
||||
reinterpret_cast<int32_t>(&arguments),
|
||||
reinterpret_cast<int32_t>(&context)));
|
||||
#endif
|
||||
#else
|
||||
return entrypoint(code.EntryPoint(),
|
||||
arguments_descriptor,
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
|
@ -111,3 +115,5 @@ TEST_CASE(InvokeDynamic_CompileError) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "include/dart_debugger_api.h"
|
||||
#include "include/dart_mirrors_api.h"
|
||||
#include "platform/assert.h"
|
||||
|
@ -2139,3 +2143,5 @@ TEST_CASE(Debug_ScriptGetTokenInfo_MultiLineInterpolation) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
46
runtime/vm/debugger_arm64.cc
Normal file
46
runtime/vm/debugger_arm64.cc
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2014, 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_ARM64)
|
||||
|
||||
#include "vm/code_patcher.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/debugger.h"
|
||||
#include "vm/instructions.h"
|
||||
#include "vm/stub_code.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
RawInstance* ActivationFrame::GetInstanceCallReceiver(
|
||||
intptr_t num_actual_args) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
RawObject* ActivationFrame::GetClosureObject(intptr_t num_actual_args) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uword CodeBreakpoint::OrigStubAddress() const {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CodeBreakpoint::PatchCode() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void CodeBreakpoint::RestoreCode() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "vm/debugger.h"
|
||||
#include "vm/unit_test.h"
|
||||
|
||||
|
@ -104,6 +108,6 @@ TEST_CASE(Debugger_PauseEvent) {
|
|||
EXPECT(saw_paused_event);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
486
runtime/vm/disassembler_arm64.cc
Normal file
486
runtime/vm/disassembler_arm64.cc
Normal file
|
@ -0,0 +1,486 @@
|
|||
// Copyright (c) 2014, 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_ARM64.
|
||||
#if defined(TARGET_ARCH_ARM64)
|
||||
#include "platform/assert.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class ARM64Decoder : public ValueObject {
|
||||
public:
|
||||
ARM64Decoder(char* buffer, size_t buffer_size)
|
||||
: buffer_(buffer),
|
||||
buffer_size_(buffer_size),
|
||||
buffer_pos_(0) {
|
||||
buffer_[buffer_pos_] = '\0';
|
||||
}
|
||||
|
||||
~ARM64Decoder() {}
|
||||
|
||||
// Writes one disassembled instruction into 'buffer' (0-terminated).
|
||||
// Returns true if the instruction was successfully decoded, false otherwise.
|
||||
void InstructionDecode(uword pc);
|
||||
|
||||
private:
|
||||
// Bottleneck functions to print into the out_buffer.
|
||||
void Print(const char* str);
|
||||
|
||||
// Printing of common values.
|
||||
void PrintRegister(int reg);
|
||||
void PrintShiftExtendRm(Instr* instr);
|
||||
void PrintS(Instr* instr);
|
||||
|
||||
// Handle formatting of instructions and their options.
|
||||
int FormatRegister(Instr* instr, const char* option);
|
||||
int FormatOption(Instr* instr, const char* format);
|
||||
void Format(Instr* instr, const char* format);
|
||||
void Unknown(Instr* instr);
|
||||
|
||||
// Decode instructions.
|
||||
#define DECODE_OP(op) \
|
||||
void Decode##op(Instr* instr);
|
||||
APPLY_OP_LIST(DECODE_OP)
|
||||
#undef DECODE_OP
|
||||
|
||||
|
||||
// Convenience functions.
|
||||
char* get_buffer() const { return buffer_; }
|
||||
char* current_position_in_buffer() { return buffer_ + buffer_pos_; }
|
||||
size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; }
|
||||
|
||||
char* buffer_; // Decode instructions into this buffer.
|
||||
size_t buffer_size_; // The size of the character buffer.
|
||||
size_t buffer_pos_; // Current character position in buffer.
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ARM64Decoder);
|
||||
};
|
||||
|
||||
|
||||
// Support for assertions in the ARM64Decoder formatting functions.
|
||||
#define STRING_STARTS_WITH(string, compare_string) \
|
||||
(strncmp(string, compare_string, strlen(compare_string)) == 0)
|
||||
|
||||
|
||||
// Append the str to the output buffer.
|
||||
void ARM64Decoder::Print(const char* str) {
|
||||
char cur = *str++;
|
||||
while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) {
|
||||
buffer_[buffer_pos_++] = cur;
|
||||
cur = *str++;
|
||||
}
|
||||
buffer_[buffer_pos_] = '\0';
|
||||
}
|
||||
|
||||
|
||||
// These register names are defined in a way to match the native disassembler
|
||||
// formatting, except for register aliases ctx (r9) and pp (r10).
|
||||
// See for example the command "objdump -d <binary file>".
|
||||
static const char* reg_names[kNumberOfCpuRegisters] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "ip0", "ip1", "pp", "ctx", "fp", "lr", "r31",
|
||||
};
|
||||
|
||||
|
||||
// Print the register name according to the active name converter.
|
||||
void ARM64Decoder::PrintRegister(int reg) {
|
||||
ASSERT(0 <= reg);
|
||||
ASSERT(reg < kNumberOfCpuRegisters);
|
||||
Print(reg_names[reg]);
|
||||
}
|
||||
|
||||
|
||||
// These shift names are defined in a way to match the native disassembler
|
||||
// formatting. See for example the command "objdump -d <binary file>".
|
||||
static const char* shift_names[kMaxShift] = {
|
||||
"lsl", "lsr", "asr", "ror"
|
||||
};
|
||||
|
||||
|
||||
static const char* extend_names[kMaxExtend] = {
|
||||
"uxtb", "uxth", "uxtw", "uxtx",
|
||||
"sxtb", "sxth", "sxtw", "sxtx",
|
||||
};
|
||||
|
||||
|
||||
// Print the register shift operands for the instruction. Generally used for
|
||||
// data processing instructions.
|
||||
void ARM64Decoder::PrintShiftExtendRm(Instr* instr) {
|
||||
int rm = instr->RmField();
|
||||
Shift shift = instr->ShiftTypeField();
|
||||
int shift_amount = instr->ShiftAmountField();
|
||||
Extend extend = instr->ExtendTypeField();
|
||||
int extend_shift_amount = instr->ExtShiftAmountField();
|
||||
|
||||
PrintRegister(rm);
|
||||
|
||||
if (instr->IsShift() && (shift == LSL) && (shift_amount == 0)) {
|
||||
// Special case for using rm only.
|
||||
return;
|
||||
}
|
||||
if (instr->IsShift()) {
|
||||
// by immediate
|
||||
if ((shift == ROR) && (shift_amount == 0)) {
|
||||
Print(", RRX");
|
||||
return;
|
||||
} else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
|
||||
shift_amount = 32;
|
||||
}
|
||||
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
||||
remaining_size_in_buffer(),
|
||||
", %s #%d",
|
||||
shift_names[shift],
|
||||
shift_amount);
|
||||
} else {
|
||||
ASSERT(instr->IsExtend());
|
||||
// by register
|
||||
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
||||
remaining_size_in_buffer(),
|
||||
", %s",
|
||||
extend_names[extend]);
|
||||
if (((instr->SFField() == 1) && (extend == UXTX)) ||
|
||||
((instr->SFField() == 0) && (extend == UXTW))) {
|
||||
// Shift amount.
|
||||
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
||||
remaining_size_in_buffer(),
|
||||
" %d",
|
||||
extend_shift_amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Handle all register based formatting in these functions to reduce the
|
||||
// complexity of FormatOption.
|
||||
int ARM64Decoder::FormatRegister(Instr* instr, const char* format) {
|
||||
ASSERT(format[0] == 'r');
|
||||
if (format[1] == 'n') { // 'rn: Rn register
|
||||
int reg = instr->RnField();
|
||||
PrintRegister(reg);
|
||||
return 2;
|
||||
} else if (format[1] == 'd') { // 'rd: Rd register
|
||||
int reg = instr->RdField();
|
||||
PrintRegister(reg);
|
||||
return 2;
|
||||
} else if (format[1] == 'm') { // 'rm: Rm register
|
||||
int reg = instr->RmField();
|
||||
PrintRegister(reg);
|
||||
return 2;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// FormatOption takes a formatting string and interprets it based on
|
||||
// the current instructions. The format string points to the first
|
||||
// character of the option string (the option escape has already been
|
||||
// consumed by the caller.) FormatOption returns the number of
|
||||
// characters that were consumed from the formatting string.
|
||||
int ARM64Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
switch (format[0]) {
|
||||
case 'i': { // 'imm12, imm16
|
||||
uint64_t imm;
|
||||
int ret = 5;
|
||||
if (format[4] == '2') {
|
||||
ASSERT(STRING_STARTS_WITH(format, "imm12"));
|
||||
imm = instr->Imm12Field();
|
||||
if (format[5] == 's') {
|
||||
// shifted immediate.
|
||||
if (instr->Imm12ShiftField() == 1) {
|
||||
imm = imm << 12;
|
||||
} else if ((instr->Imm12ShiftField() & 0x2) != 0) {
|
||||
Print("Unknown Shift");
|
||||
}
|
||||
ret = 6;
|
||||
}
|
||||
} else {
|
||||
ASSERT(STRING_STARTS_WITH(format, "imm16"));
|
||||
imm = instr->Imm16Field();
|
||||
}
|
||||
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
||||
remaining_size_in_buffer(),
|
||||
"0x%"Px64,
|
||||
imm);
|
||||
return ret;
|
||||
}
|
||||
case 's': { // 's: S flag.
|
||||
if (format[1] == 'h') {
|
||||
ASSERT(STRING_STARTS_WITH(format, "shift_op"));
|
||||
PrintShiftExtendRm(instr);
|
||||
return 8;
|
||||
} else if (format[1] == 'f') {
|
||||
ASSERT(STRING_STARTS_WITH(format, "sf"));
|
||||
if (instr->SFField() == 1) {
|
||||
// TODO(zra): If we don't use the w form much, we can omit printing
|
||||
// this x.
|
||||
Print("x");
|
||||
} else {
|
||||
Print("w");
|
||||
}
|
||||
return 2;
|
||||
} else if (format[1] == ' ') {
|
||||
if (instr->HasS()) {
|
||||
Print("s");
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
case 'r': {
|
||||
return FormatRegister(instr, format);
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Format takes a formatting string for a whole instruction and prints it into
|
||||
// the output buffer. All escaped options are handed to FormatOption to be
|
||||
// parsed further.
|
||||
void ARM64Decoder::Format(Instr* instr, const char* format) {
|
||||
char cur = *format++;
|
||||
while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) {
|
||||
if (cur == '\'') { // Single quote is used as the formatting escape.
|
||||
format += FormatOption(instr, format);
|
||||
} else {
|
||||
buffer_[buffer_pos_++] = cur;
|
||||
}
|
||||
cur = *format++;
|
||||
}
|
||||
buffer_[buffer_pos_] = '\0';
|
||||
}
|
||||
|
||||
|
||||
// For currently unimplemented decodings the disassembler calls Unknown(instr)
|
||||
// which will just print "unknown" of the instruction bits.
|
||||
void ARM64Decoder::Unknown(Instr* instr) {
|
||||
Format(instr, "unknown");
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeMoveWide(Instr* instr) {
|
||||
switch (instr->Bits(29, 2)) {
|
||||
case 0:
|
||||
Format(instr, "movn'sf 'rd, 'imm16");
|
||||
break;
|
||||
case 2:
|
||||
Format(instr, "movz'sf 'rd, 'imm16");
|
||||
break;
|
||||
case 3:
|
||||
Format(instr, "movk'sf 'rd, 'imm16");
|
||||
break;
|
||||
default:
|
||||
Unknown(instr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeAddSubImm(Instr* instr) {
|
||||
switch (instr->Bit(30)) {
|
||||
case 0:
|
||||
Format(instr, "addi'sf's 'rd, 'rn, 'imm12s");
|
||||
break;
|
||||
case 1:
|
||||
Format(instr, "subi'sf's 'rd, 'rn, 'imm12s");
|
||||
break;
|
||||
default:
|
||||
Unknown(instr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ARM64Decoder::DecodeDPImmediate(Instr* instr) {
|
||||
if (instr->IsMoveWideOp()) {
|
||||
DecodeMoveWide(instr);
|
||||
} else if (instr->IsAddSubImmOp()) {
|
||||
DecodeAddSubImm(instr);
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeExceptionGen(Instr* instr) {
|
||||
if ((instr->Bits(0, 2) == 1) && (instr->Bits(2, 3) == 0) &&
|
||||
(instr->Bits(21, 3) == 0)) {
|
||||
Format(instr, "svc 'imm16");
|
||||
} else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) &&
|
||||
(instr->Bits(21, 3) == 1)) {
|
||||
Format(instr, "brk 'imm16");
|
||||
} else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) &&
|
||||
(instr->Bits(21, 3) == 2)) {
|
||||
Format(instr, "hlt 'imm16");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeSystem(Instr* instr) {
|
||||
if ((instr->Bits(0, 8) == 0x5f) && (instr->Bits(12, 4) == 2) &&
|
||||
(instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) &&
|
||||
(instr->Bit(21) == 0)) {
|
||||
if (instr->Bits(8, 4) == 0) {
|
||||
Format(instr, "nop");
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeUnconditionalBranchReg(Instr* instr) {
|
||||
if ((instr->Bits(0, 5) == 0) && (instr->Bits(10, 5) == 0) &&
|
||||
(instr->Bits(16, 5) == 0x1f)) {
|
||||
switch (instr->Bits(21, 4)) {
|
||||
case 0:
|
||||
Format(instr, "br 'rn");
|
||||
break;
|
||||
case 1:
|
||||
Format(instr, "blr 'rn");
|
||||
break;
|
||||
case 2:
|
||||
Format(instr, "ret 'rn");
|
||||
break;
|
||||
default:
|
||||
Unknown(instr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeCompareBranch(Instr* instr) {
|
||||
if (instr->IsExceptionGenOp()) {
|
||||
DecodeExceptionGen(instr);
|
||||
} else if (instr->IsSystemOp()) {
|
||||
DecodeSystem(instr);
|
||||
} else if (instr->IsUnconditionalBranchRegOp()) {
|
||||
DecodeUnconditionalBranchReg(instr);
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeLoadStore(Instr* instr) {
|
||||
Unknown(instr);
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeAddSubShiftExt(Instr* instr) {
|
||||
switch (instr->Bit(30)) {
|
||||
case 0:
|
||||
Format(instr, "add'sf's 'rd, 'rn, 'shift_op");
|
||||
break;
|
||||
case 1:
|
||||
Format(instr, "sub'sf's 'rd, 'rn, 'shift_op");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeDPRegister(Instr* instr) {
|
||||
if (instr->IsAddSubShiftExtOp()) {
|
||||
DecodeAddSubShiftExt(instr);
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeDPSimd1(Instr* instr) {
|
||||
Unknown(instr);
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::DecodeDPSimd2(Instr* instr) {
|
||||
Unknown(instr);
|
||||
}
|
||||
|
||||
|
||||
void ARM64Decoder::InstructionDecode(uword pc) {
|
||||
Instr* instr = Instr::At(pc);
|
||||
|
||||
if (instr->IsDPImmediateOp()) {
|
||||
DecodeDPImmediate(instr);
|
||||
} else if (instr->IsCompareBranchOp()) {
|
||||
DecodeCompareBranch(instr);
|
||||
} else if (instr->IsLoadStoreOp()) {
|
||||
DecodeLoadStore(instr);
|
||||
} else if (instr->IsDPRegisterOp()) {
|
||||
DecodeDPRegister(instr);
|
||||
} else if (instr->IsDPSimd1Op()) {
|
||||
DecodeDPSimd1(instr);
|
||||
} else {
|
||||
ASSERT(instr->IsDPSimd2Op());
|
||||
DecodeDPSimd2(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
|
||||
char* human_buffer, intptr_t human_size,
|
||||
int* out_instr_size, uword pc) {
|
||||
ARM64Decoder decoder(human_buffer, human_size);
|
||||
decoder.InstructionDecode(pc);
|
||||
int32_t instruction_bits = Instr::At(pc)->InstructionBits();
|
||||
OS::SNPrint(hex_buffer, hex_size, "%08x", instruction_bits);
|
||||
if (out_instr_size) {
|
||||
*out_instr_size = Instr::kInstrSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::Disassemble(uword start,
|
||||
uword end,
|
||||
DisassemblyFormatter* formatter,
|
||||
const Code::Comments& comments) {
|
||||
ASSERT(formatter != NULL);
|
||||
char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form.
|
||||
char human_buffer[kUserReadableBufferSize]; // Human-readable instruction.
|
||||
uword pc = start;
|
||||
intptr_t comment_finger = 0;
|
||||
while (pc < end) {
|
||||
const intptr_t offset = pc - start;
|
||||
while (comment_finger < comments.Length() &&
|
||||
comments.PCOffsetAt(comment_finger) <= offset) {
|
||||
formatter->Print(
|
||||
" ;; %s\n",
|
||||
String::Handle(comments.CommentAt(comment_finger)).ToCString());
|
||||
comment_finger++;
|
||||
}
|
||||
int instruction_length;
|
||||
DecodeInstruction(hex_buffer, sizeof(hex_buffer),
|
||||
human_buffer, sizeof(human_buffer),
|
||||
&instruction_length, pc);
|
||||
|
||||
formatter->ConsumeInstruction(hex_buffer,
|
||||
sizeof(hex_buffer),
|
||||
human_buffer,
|
||||
sizeof(human_buffer),
|
||||
pc);
|
||||
pc += instruction_length;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/disassembler.h"
|
||||
#include "vm/unit_test.h"
|
||||
|
@ -23,3 +27,5 @@ TEST_CASE(Disassembler) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -403,6 +403,9 @@ void ElfGen::AddELFHeader(int shoff) {
|
|||
WriteShort(&header_, kEM_X86_64); // e_machine
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
WriteShort(&header_, kEM_ARM); // e_machine
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
// TODO(zra): Find the right ARM64 constant.
|
||||
WriteShort(&header_, kEM_ARM); // e_machine
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
WriteShort(&header_, kEM_MIPS); // e_machine
|
||||
#else
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "include/dart_api.h"
|
||||
#include "platform/assert.h"
|
||||
#include "vm/dart_api_impl.h"
|
||||
|
@ -133,3 +137,5 @@ TEST_CASE(UnhandledExceptions) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
#include "vm/compiler.h"
|
||||
|
@ -156,3 +160,5 @@ TEST_CASE(FindCodeObject) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
429
runtime/vm/flow_graph_compiler_arm64.cc
Normal file
429
runtime/vm/flow_graph_compiler_arm64.cc
Normal file
|
@ -0,0 +1,429 @@
|
|||
// Copyright (c) 2014, 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_ARM64.
|
||||
#if defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#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/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"
|
||||
|
||||
namespace dart {
|
||||
|
||||
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::SupportsUnboxedMints() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FlowGraphCompiler::SupportsUnboxedSimd128() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FlowGraphCompiler::SupportsSinCos() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
|
||||
DeoptInfoBuilder* builder,
|
||||
const Array& deopt_table) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler,
|
||||
intptr_t stub_ix) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
#define __ assembler()->
|
||||
|
||||
|
||||
// Fall through if bool_register contains null.
|
||||
void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
|
||||
Label* is_true,
|
||||
Label* is_false) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
|
||||
TypeTestStubKind test_kind,
|
||||
Register instance_reg,
|
||||
Register type_arguments_reg,
|
||||
Register temp_reg,
|
||||
Label* is_instance_lbl,
|
||||
Label* is_not_instance_lbl) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
RawSubtypeTestCache*
|
||||
FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
|
||||
intptr_t token_pos,
|
||||
const AbstractType& type,
|
||||
Label* is_instance_lbl,
|
||||
Label* is_not_instance_lbl) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
|
||||
const GrowableArray<intptr_t>& class_ids,
|
||||
Label* is_equal_lbl,
|
||||
Label* is_not_equal_lbl) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
|
||||
intptr_t token_pos,
|
||||
const AbstractType& type,
|
||||
Label* is_instance_lbl,
|
||||
Label* is_not_instance_lbl) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
|
||||
intptr_t token_pos,
|
||||
const Class& type_class,
|
||||
Label* is_instance_lbl,
|
||||
Label* is_not_instance_lbl) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
|
||||
intptr_t token_pos,
|
||||
const AbstractType& type,
|
||||
Label* is_instance_lbl,
|
||||
Label* is_not_instance_lbl) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
|
||||
intptr_t token_pos,
|
||||
const AbstractType& type,
|
||||
Label* is_instance_lbl,
|
||||
Label* is_not_instance_lbl) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
|
||||
intptr_t deopt_id,
|
||||
const AbstractType& type,
|
||||
bool negate_result,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
|
||||
intptr_t deopt_id,
|
||||
const AbstractType& dst_type,
|
||||
const String& dst_name,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::CopyParameters() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitFrameEntry() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::CompileGraph() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
|
||||
const ExternalLabel* label,
|
||||
PcDescriptors::Kind kind,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
|
||||
intptr_t token_pos,
|
||||
const ExternalLabel* label,
|
||||
PcDescriptors::Kind kind,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos,
|
||||
intptr_t deopt_id,
|
||||
const RuntimeEntry& entry,
|
||||
intptr_t argument_count,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitEdgeCounter() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitOptimizedInstanceCall(
|
||||
ExternalLabel* target_label,
|
||||
const ICData& ic_data,
|
||||
intptr_t argument_count,
|
||||
intptr_t deopt_id,
|
||||
intptr_t token_pos,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
|
||||
const ICData& ic_data,
|
||||
intptr_t argument_count,
|
||||
intptr_t deopt_id,
|
||||
intptr_t token_pos,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitMegamorphicInstanceCall(
|
||||
const ICData& ic_data,
|
||||
intptr_t argument_count,
|
||||
intptr_t deopt_id,
|
||||
intptr_t token_pos,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitUnoptimizedStaticCall(
|
||||
const Function& target_function,
|
||||
const Array& arguments_descriptor,
|
||||
intptr_t argument_count,
|
||||
intptr_t deopt_id,
|
||||
intptr_t token_pos,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitOptimizedStaticCall(
|
||||
const Function& function,
|
||||
const Array& arguments_descriptor,
|
||||
intptr_t argument_count,
|
||||
intptr_t deopt_id,
|
||||
intptr_t token_pos,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg,
|
||||
const Object& obj,
|
||||
bool needs_number_check,
|
||||
intptr_t token_pos) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
|
||||
Register right,
|
||||
bool needs_number_check,
|
||||
intptr_t token_pos) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// This function must be in sync with FlowGraphCompiler::RecordSafepoint and
|
||||
// FlowGraphCompiler::SlowPathEnvironmentFor.
|
||||
void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data,
|
||||
Register class_id_reg,
|
||||
intptr_t argument_count,
|
||||
const Array& argument_names,
|
||||
Label* deopt,
|
||||
intptr_t deopt_id,
|
||||
intptr_t token_index,
|
||||
LocationSummary* locs) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Do not implement or use this function.
|
||||
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
|
||||
intptr_t index_scale,
|
||||
Register array,
|
||||
intptr_t index) {
|
||||
UNREACHABLE();
|
||||
return FieldAddress(array, index);
|
||||
}
|
||||
|
||||
|
||||
// Do not implement or use this function.
|
||||
FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
|
||||
intptr_t index_scale,
|
||||
Register array,
|
||||
Register index) {
|
||||
UNREACHABLE(); // No register indexed with offset addressing mode on ARM.
|
||||
return FieldAddress(array, index);
|
||||
}
|
||||
|
||||
|
||||
Address FlowGraphCompiler::ExternalElementAddressForIntIndex(
|
||||
intptr_t index_scale,
|
||||
Register array,
|
||||
intptr_t index) {
|
||||
UNREACHABLE();
|
||||
return FieldAddress(array, index);
|
||||
}
|
||||
|
||||
|
||||
Address FlowGraphCompiler::ExternalElementAddressForRegIndex(
|
||||
intptr_t index_scale,
|
||||
Register array,
|
||||
Register index) {
|
||||
UNREACHABLE();
|
||||
return FieldAddress(array, index);
|
||||
}
|
||||
|
||||
|
||||
#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) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// 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, intptr_t stack_offset) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void ParallelMoveResolver::Exchange(intptr_t stack_offset1,
|
||||
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_ARM64
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "vm/dart_api_impl.h"
|
||||
#include "vm/dart_api_state.h"
|
||||
#include "vm/intermediate_language.h"
|
||||
|
@ -270,3 +274,5 @@ TEST_CASE(GuardFieldConstructor2Test) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
// 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 "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/dart_api_impl.h"
|
||||
#include "vm/globals.h"
|
||||
|
@ -206,3 +209,5 @@ TEST_CASE(FindObject) {
|
|||
}
|
||||
|
||||
} // namespace dart.
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "vm/instructions_x64.h"
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
#include "vm/instructions_arm.h"
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
#include "vm/instructions_arm64.h"
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
#include "vm/instructions_mips.h"
|
||||
#else
|
||||
|
|
129
runtime/vm/instructions_arm64.cc
Normal file
129
runtime/vm/instructions_arm64.cc
Normal file
|
@ -0,0 +1,129 @@
|
|||
// Copyright (c) 2014, 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_ARM64.
|
||||
#if defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/constants_arm64.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/instructions.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
CallPattern::CallPattern(uword pc, const Code& code)
|
||||
: object_pool_(Array::Handle(code.ObjectPool())),
|
||||
end_(pc),
|
||||
args_desc_load_end_(0),
|
||||
ic_data_load_end_(0),
|
||||
target_address_pool_index_(-1),
|
||||
args_desc_(Array::Handle()),
|
||||
ic_data_(ICData::Handle()) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
int CallPattern::LengthInBytes() {
|
||||
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 object in the output parameters 'reg' and 'obj'
|
||||
// respectively.
|
||||
uword InstructionPattern::DecodeLoadObject(uword end,
|
||||
const Array& 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;
|
||||
}
|
||||
|
||||
|
||||
RawICData* CallPattern::IcData() {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
RawArray* CallPattern::ClosureArgumentsDescriptor() {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uword CallPattern::TargetAddress() const {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CallPattern::SetTargetAddress(uword target_address) const {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void CallPattern::InsertAt(uword pc, uword target_address) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { }
|
||||
|
||||
|
||||
int JumpPattern::pattern_length_in_bytes() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool JumpPattern::IsValid() const {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uword JumpPattern::TargetAddress() const {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void JumpPattern::SetTargetAddress(uword target_address) const {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
101
runtime/vm/instructions_arm64.h
Normal file
101
runtime/vm/instructions_arm64.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
// Copyright (c) 2014, 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_ARM64_H_
|
||||
#define VM_INSTRUCTIONS_ARM64_H_
|
||||
|
||||
#ifndef VM_INSTRUCTIONS_H_
|
||||
#error Do not include instructions_arm64.h directly; use instructions.h instead.
|
||||
#endif
|
||||
|
||||
#include "vm/constants_arm64.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 Array& 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();
|
||||
RawArray* ClosureArgumentsDescriptor();
|
||||
|
||||
uword TargetAddress() const;
|
||||
void SetTargetAddress(uword target_address) const;
|
||||
|
||||
// This constant length is only valid for inserted call patterns used for
|
||||
// lazy deoptimization. Regular call pattern may vary in length.
|
||||
static int LengthInBytes();
|
||||
|
||||
static void InsertAt(uword pc, uword target_address);
|
||||
|
||||
private:
|
||||
const Array& object_pool_;
|
||||
|
||||
uword end_;
|
||||
uword args_desc_load_end_;
|
||||
uword ic_data_load_end_;
|
||||
|
||||
intptr_t target_address_pool_index_;
|
||||
Array& args_desc_;
|
||||
ICData& ic_data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CallPattern);
|
||||
};
|
||||
|
||||
|
||||
class JumpPattern : public ValueObject {
|
||||
public:
|
||||
JumpPattern(uword pc, const Code& code);
|
||||
|
||||
static const int kLengthInBytes = 3 * Instr::kInstrSize;
|
||||
|
||||
static int pattern_length_in_bytes();
|
||||
|
||||
bool IsValid() const;
|
||||
uword TargetAddress() const;
|
||||
void SetTargetAddress(uword target_address) const;
|
||||
|
||||
private:
|
||||
const uword pc_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(JumpPattern);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_INSTRUCTIONS_ARM64_H_
|
10
runtime/vm/instructions_arm64_test.cc
Normal file
10
runtime/vm/instructions_arm64_test.cc
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) 2014, 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_ARM64)
|
||||
|
||||
// TODO(zra): Port these tests.
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
1247
runtime/vm/intermediate_language_arm64.cc
Normal file
1247
runtime/vm/intermediate_language_arm64.cc
Normal file
File diff suppressed because it is too large
Load diff
408
runtime/vm/intrinsifier_arm64.cc
Normal file
408
runtime/vm/intrinsifier_arm64.cc
Normal file
|
@ -0,0 +1,408 @@
|
|||
// Copyright (c) 2014, 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_ARM64.
|
||||
#if defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "vm/intrinsifier.h"
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/flow_graph_compiler.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/symbols.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
#define __ assembler->
|
||||
|
||||
void Intrinsifier::List_Allocate(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Array_getLength(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::ImmutableList_getLength(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Array_getIndexed(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::ImmutableList_getIndexed(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Array_setIndexed(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Allocate a GrowableObjectArray using the backing array specified.
|
||||
// On stack: type argument (+1), data (+0).
|
||||
void Intrinsifier::GrowableList_Allocate(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::GrowableList_getLength(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::GrowableList_getCapacity(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Set value into growable object array at specified index.
|
||||
// On stack: growable array (+2), index (+1), value (+0).
|
||||
void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Set length of growable object array. The length cannot
|
||||
// be greater than the length of the data container.
|
||||
// On stack: growable array (+1), length (+0).
|
||||
void Intrinsifier::GrowableList_setLength(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Set data of growable object array.
|
||||
// On stack: growable array (+1), data (+0).
|
||||
void Intrinsifier::GrowableList_setData(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::GrowableList_add(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Gets the length of a TypedData.
|
||||
void Intrinsifier::TypedData_getLength(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
#define TYPED_DATA_ALLOCATOR(clazz) \
|
||||
void Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \
|
||||
UNIMPLEMENTED(); \
|
||||
} \
|
||||
void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \
|
||||
UNIMPLEMENTED(); \
|
||||
}
|
||||
CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR)
|
||||
#undef TYPED_DATA_ALLOCATOR
|
||||
|
||||
|
||||
void Intrinsifier::Integer_addFromInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_add(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_subFromInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_sub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_mul(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Implementation:
|
||||
// res = left % right;
|
||||
// if (res < 0) {
|
||||
// if (right < 0) {
|
||||
// res = res - right;
|
||||
// } else {
|
||||
// res = res + right;
|
||||
// }
|
||||
// }
|
||||
void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_truncDivide(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_negate(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_bitAnd(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_bitOr(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_bitXor(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_shl(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_lessThan(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_greaterThan(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// This is called for Smi, Mint and Bigint receivers. The right argument
|
||||
// can be Smi, Mint, Bigint or double.
|
||||
void Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_equal(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Integer_sar(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Smi_bitNegate(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Smi_bitLength(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_greaterThan(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_lessThan(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_equal(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_lessEqualThan(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_add(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_mul(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_sub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_div(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Left is double right is integer (Bigint, Mint or Smi)
|
||||
void Intrinsifier::Double_mulFromInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_fromInteger(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_getIsNaN(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_getIsNegative(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Double_toInt(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Math_sqrt(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
|
||||
// _state[kSTATE_LO] = state & _MASK_32;
|
||||
// _state[kSTATE_HI] = state >> 32;
|
||||
void Intrinsifier::Random_nextState(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::Object_equal(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::String_getHashCode(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::String_getLength(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::String_codeUnitAt(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::String_getIsEmpty(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Arg0: OneByteString (receiver).
|
||||
// Arg1: Start index as Smi.
|
||||
// Arg2: End index as Smi.
|
||||
// The indexes must be valid.
|
||||
void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::OneByteString_setAt(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::OneByteString_allocate(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// TODO(srdjan): Add combinations (one-byte/two-byte/external strings).
|
||||
void StringEquality(Assembler* assembler, intptr_t string_cid) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::OneByteString_equality(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::TwoByteString_equality(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/isolate.h"
|
||||
|
@ -80,3 +84,5 @@ TEST_CASE(IsolateSpawn) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/json.h"
|
||||
#include "vm/json_stream.h"
|
||||
|
@ -334,3 +338,5 @@ TEST_CASE(JSON_JSONStream_Options) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -5863,7 +5863,13 @@ RawFunction* Function::New(const String& name,
|
|||
const ClosureData& data = ClosureData::Handle(ClosureData::New());
|
||||
result.set_data(data);
|
||||
}
|
||||
|
||||
// TODO(zra): Remove when arm64 is ready.
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
result.set_code(Code::Handle(StubCode::LazyCompile_entry()->code()));
|
||||
#else
|
||||
result.set_code(Code::Handle());
|
||||
#endif
|
||||
return result.raw();
|
||||
}
|
||||
|
||||
|
|
11
runtime/vm/object_arm64_test.cc
Normal file
11
runtime/vm/object_arm64_test.cc
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2014, 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 "platform/assert.h"
|
||||
#include "vm/globals.h"
|
||||
#if defined(TARGET_ARCH_ARM64)
|
||||
|
||||
// TODO(zra): Port these tests.
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/object_id_ring.h"
|
||||
|
@ -190,3 +194,5 @@ TEST_CASE(ObjectIdRingOldGCTest) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/bigint_operations.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
|
@ -4009,3 +4013,5 @@ TEST_CASE(PrintToJSONStream) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -59,6 +59,8 @@ class LowLevelProfileCodeObserver : public CodeObserver {
|
|||
const char arch[] = "x64";
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
const char arch[] = "arm";
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
const char arch[] = "arm64";
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
const char arch[] = "mips";
|
||||
#else
|
||||
|
@ -355,6 +357,8 @@ class JitdumpCodeObserver : public CodeObserver {
|
|||
static const uint32_t kElfMachIA32 = 3;
|
||||
static const uint32_t kElfMachX64 = 62;
|
||||
static const uint32_t kElfMachARM = 40;
|
||||
// TODO(zra): Find the right ARM64 constant.
|
||||
static const uint32_t kElfMachARM64 = 40;
|
||||
static const uint32_t kElfMachMIPS = 10;
|
||||
static const int kInvalidClockId = -1;
|
||||
|
||||
|
@ -405,6 +409,8 @@ class JitdumpCodeObserver : public CodeObserver {
|
|||
return kElfMachX64;
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
return kElfMachARM;
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
return kElfMachARM64;
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
return kElfMachMIPS;
|
||||
#else
|
||||
|
@ -570,7 +576,9 @@ void OS::AlignedFree(void* ptr) {
|
|||
// TODO(5411554): May need to hoist these architecture dependent code
|
||||
// into a architecture specific file e.g: os_ia32_linux.cc
|
||||
word OS::ActivationFrameAlignment() {
|
||||
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
|
||||
#if defined(TARGET_ARCH_IA32) || \
|
||||
defined(TARGET_ARCH_X64) || \
|
||||
defined(TARGET_ARCH_ARM64)
|
||||
const int kMinimumAlignment = 16;
|
||||
#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
|
||||
const int kMinimumAlignment = 8;
|
||||
|
@ -588,7 +596,9 @@ word OS::ActivationFrameAlignment() {
|
|||
|
||||
|
||||
word OS::PreferredCodeAlignment() {
|
||||
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
|
||||
#if defined(TARGET_ARCH_IA32) || \
|
||||
defined(TARGET_ARCH_X64) || \
|
||||
defined(TARGET_ARCH_ARM64)
|
||||
const int kMinimumAlignment = 32;
|
||||
#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
|
||||
const int kMinimumAlignment = 16;
|
||||
|
|
|
@ -710,8 +710,13 @@ RawFunction* Function::ReadFrom(SnapshotReader* reader,
|
|||
*(func.raw()->from() + i) = reader->ReadObjectRef();
|
||||
}
|
||||
|
||||
// TODO(zra): Remove when arm64 is ready.
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
// Set up code pointer with the lazy-compile-stub.
|
||||
func.set_code(Code::Handle(StubCode::LazyCompile_entry()->code()));
|
||||
#else
|
||||
func.set_code(Code::Handle());
|
||||
#endif
|
||||
|
||||
return func.raw();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
|
@ -213,3 +217,5 @@ TEST_CASE(DartDynamicResolve) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
24
runtime/vm/runtime_entry_arm64.cc
Normal file
24
runtime/vm/runtime_entry_arm64.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2014, 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_ARM64)
|
||||
|
||||
#include "vm/runtime_entry.h"
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/simulator.h"
|
||||
#include "vm/stub_code.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
#define __ assembler->
|
||||
|
||||
void RuntimeEntry::Call(Assembler* assembler, intptr_t argument_count) const {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "vm/runtime_entry.h"
|
||||
|
||||
#include "vm/object.h"
|
||||
|
@ -59,3 +63,5 @@ DEFINE_LEAF_RUNTIME_ENTRY(RawObject*, TestLeafSmiAdd, 2,
|
|||
END_LEAF_RUNTIME_ENTRY
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "include/dart_debugger_api.h"
|
||||
#include "vm/dart_api_impl.h"
|
||||
#include "vm/dart_entry.h"
|
||||
|
@ -1376,3 +1380,5 @@ TEST_CASE(Service_Profile) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -21,6 +21,14 @@
|
|||
#include "vm/simulator_arm.h"
|
||||
#endif
|
||||
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
#if defined(HOST_ARCH_ARM64)
|
||||
// No simulator used.
|
||||
#else
|
||||
#define USING_SIMULATOR 1
|
||||
#include "vm/simulator_arm64.h"
|
||||
#endif
|
||||
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
#if defined(HOST_ARCH_MIPS)
|
||||
// No simulator used.
|
||||
|
|
714
runtime/vm/simulator_arm64.cc
Normal file
714
runtime/vm/simulator_arm64.cc
Normal file
|
@ -0,0 +1,714 @@
|
|||
// Copyright (c) 2014, 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 <math.h> // for isnan.
|
||||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(TARGET_ARCH_ARM64)
|
||||
|
||||
// Only build the simulator if not compiling for real ARM hardware.
|
||||
#if !defined(HOST_ARCH_ARM64)
|
||||
|
||||
#include "vm/simulator.h"
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/constants_arm64.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/disassembler.h"
|
||||
#include "vm/native_arguments.h"
|
||||
#include "vm/stack_frame.h"
|
||||
#include "vm/thread.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
DEFINE_FLAG(bool, trace_sim, false, "Trace simulator execution.");
|
||||
DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at.");
|
||||
|
||||
|
||||
// This macro provides a platform independent use of sscanf. The reason for
|
||||
// SScanF not being implemented in a platform independent way through
|
||||
// OS in the same way as SNPrint is that the Windows C Run-Time
|
||||
// Library does not provide vsscanf.
|
||||
#define SScanF sscanf // NOLINT
|
||||
|
||||
|
||||
Simulator::Simulator() {
|
||||
// Setup simulator support first. Some of this information is needed to
|
||||
// setup the architecture state.
|
||||
// We allocate the stack here, the size is computed as the sum of
|
||||
// the size specified by the user and the buffer space needed for
|
||||
// handling stack overflow exceptions. To be safe in potential
|
||||
// stack underflows we also add some underflow buffer space.
|
||||
stack_ = new char[(Isolate::GetSpecifiedStackSize() +
|
||||
Isolate::kStackSizeBuffer +
|
||||
kSimulatorStackUnderflowSize)];
|
||||
pc_modified_ = false;
|
||||
icount_ = 0;
|
||||
break_pc_ = NULL;
|
||||
break_instr_ = 0;
|
||||
top_exit_frame_info_ = 0;
|
||||
|
||||
// Setup architecture state.
|
||||
// All registers are initialized to zero to start with.
|
||||
for (int i = 0; i < kNumberOfCpuRegisters; i++) {
|
||||
registers_[i] = 0;
|
||||
}
|
||||
n_flag_ = false;
|
||||
z_flag_ = false;
|
||||
c_flag_ = false;
|
||||
v_flag_ = false;
|
||||
|
||||
// The sp is initialized to point to the bottom (high address) of the
|
||||
// allocated stack area.
|
||||
registers_[SP] = StackTop();
|
||||
// The lr and pc are initialized to a known bad value that will cause an
|
||||
// access violation if the simulator ever tries to execute it.
|
||||
registers_[LR] = kBadLR;
|
||||
pc_ = kBadLR;
|
||||
}
|
||||
|
||||
|
||||
Simulator::~Simulator() {
|
||||
delete[] stack_;
|
||||
Isolate* isolate = Isolate::Current();
|
||||
if (isolate != NULL) {
|
||||
isolate->set_simulator(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the active Simulator for the current isolate.
|
||||
Simulator* Simulator::Current() {
|
||||
Simulator* simulator = Isolate::Current()->simulator();
|
||||
if (simulator == NULL) {
|
||||
simulator = new Simulator();
|
||||
Isolate::Current()->set_simulator(simulator);
|
||||
}
|
||||
return simulator;
|
||||
}
|
||||
|
||||
|
||||
// Sets the register in the architecture state.
|
||||
void Simulator::set_register(Register reg, int64_t value, R31Type r31t) {
|
||||
// register is in range, and if it is R31, a mode is specified.
|
||||
ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
|
||||
ASSERT((reg != R31) || (r31t != R31IsUndef));
|
||||
if ((reg != R31) || (r31t != R31IsZR)) {
|
||||
registers_[reg] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the register from the architecture state.
|
||||
int64_t Simulator::get_register(Register reg, R31Type r31t) const {
|
||||
ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
|
||||
ASSERT((reg != R31) || (r31t != R31IsUndef));
|
||||
if ((reg == R31) && (r31t == R31IsZR)) {
|
||||
return 0;
|
||||
} else {
|
||||
return registers_[reg];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::set_wregister(Register reg, int32_t value, R31Type r31t) {
|
||||
ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
|
||||
ASSERT((reg != R31) || (r31t != R31IsUndef));
|
||||
// When setting in W mode, clear the high bits.
|
||||
if ((reg != R31) || (r31t != R31IsZR)) {
|
||||
registers_[reg] = Utils::LowHighTo64Bits(static_cast<uint32_t>(value), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the register from the architecture state.
|
||||
int32_t Simulator::get_wregister(Register reg, R31Type r31t) const {
|
||||
ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
|
||||
ASSERT((reg != R31) || (r31t != R31IsUndef));
|
||||
if ((reg == R31) && (r31t == R31IsZR)) {
|
||||
return 0;
|
||||
} else {
|
||||
return registers_[reg];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Raw access to the PC register.
|
||||
void Simulator::set_pc(int64_t value) {
|
||||
pc_modified_ = true;
|
||||
pc_ = value;
|
||||
}
|
||||
|
||||
|
||||
// Raw access to the PC register without the special adjustment when reading.
|
||||
int64_t Simulator::get_pc() const {
|
||||
return pc_;
|
||||
}
|
||||
|
||||
|
||||
void Simulator::HandleIllegalAccess(uword addr, Instr* instr) {
|
||||
uword fault_pc = get_pc();
|
||||
// TODO(zra): drop into debugger.
|
||||
char buffer[128];
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"illegal memory access at 0x%" Px ", pc=0x%" Px "\n",
|
||||
addr, fault_pc);
|
||||
// The debugger will return control in non-interactive mode.
|
||||
FATAL("Cannot continue execution after illegal memory access.");
|
||||
}
|
||||
|
||||
|
||||
void Simulator::UnimplementedInstruction(Instr* instr) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr);
|
||||
// TODO(zra): drop into debugger.
|
||||
FATAL("Cannot continue execution after unimplemented instruction.");
|
||||
}
|
||||
|
||||
|
||||
// Returns the top of the stack area to enable checking for stack pointer
|
||||
// validity.
|
||||
uword Simulator::StackTop() const {
|
||||
// To be safe in potential stack underflows we leave some buffer above and
|
||||
// set the stack top.
|
||||
return reinterpret_cast<uword>(stack_) +
|
||||
(Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer);
|
||||
}
|
||||
|
||||
|
||||
// Unsupported instructions use Format to print an error and stop execution.
|
||||
void Simulator::Format(Instr* instr, const char* format) {
|
||||
OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n",
|
||||
instr,
|
||||
format);
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Calculate and set the Negative and Zero flags.
|
||||
void Simulator::SetNZFlagsW(int32_t val) {
|
||||
n_flag_ = (val < 0);
|
||||
z_flag_ = (val == 0);
|
||||
}
|
||||
|
||||
|
||||
// Calculate C flag value for additions.
|
||||
bool Simulator::CarryFromW(int32_t left, int32_t right) {
|
||||
uint32_t uleft = static_cast<uint32_t>(left);
|
||||
uint32_t uright = static_cast<uint32_t>(right);
|
||||
uint32_t urest = 0xffffffffU - uleft;
|
||||
|
||||
return (uright > urest);
|
||||
}
|
||||
|
||||
|
||||
// Calculate C flag value for subtractions.
|
||||
bool Simulator::BorrowFromW(int32_t left, int32_t right) {
|
||||
uint32_t uleft = static_cast<uint32_t>(left);
|
||||
uint32_t uright = static_cast<uint32_t>(right);
|
||||
|
||||
return (uright > uleft);
|
||||
}
|
||||
|
||||
|
||||
// Calculate V flag value for additions and subtractions.
|
||||
bool Simulator::OverflowFromW(int32_t alu_out,
|
||||
int32_t left, int32_t right, bool addition) {
|
||||
bool overflow;
|
||||
if (addition) {
|
||||
// operands have the same sign
|
||||
overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
|
||||
// and operands and result have different sign
|
||||
&& ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
|
||||
} else {
|
||||
// operands have different signs
|
||||
overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
|
||||
// and first operand and result have different signs
|
||||
&& ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
|
||||
}
|
||||
return overflow;
|
||||
}
|
||||
|
||||
|
||||
// Calculate and set the Negative and Zero flags.
|
||||
void Simulator::SetNZFlagsX(int64_t val) {
|
||||
n_flag_ = (val < 0);
|
||||
z_flag_ = (val == 0);
|
||||
}
|
||||
|
||||
|
||||
// Calculate C flag value for additions.
|
||||
bool Simulator::CarryFromX(int64_t left, int64_t right) {
|
||||
uint64_t uleft = static_cast<uint64_t>(left);
|
||||
uint64_t uright = static_cast<uint64_t>(right);
|
||||
uint64_t urest = 0xffffffffffffffffULL - uleft;
|
||||
|
||||
return (uright > urest);
|
||||
}
|
||||
|
||||
|
||||
// Calculate C flag value for subtractions.
|
||||
bool Simulator::BorrowFromX(int64_t left, int64_t right) {
|
||||
uint64_t uleft = static_cast<uint64_t>(left);
|
||||
uint64_t uright = static_cast<uint64_t>(right);
|
||||
|
||||
return (uright > uleft);
|
||||
}
|
||||
|
||||
|
||||
// Calculate V flag value for additions and subtractions.
|
||||
bool Simulator::OverflowFromX(int64_t alu_out,
|
||||
int64_t left, int64_t right, bool addition) {
|
||||
bool overflow;
|
||||
if (addition) {
|
||||
// operands have the same sign
|
||||
overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
|
||||
// and operands and result have different sign
|
||||
&& ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
|
||||
} else {
|
||||
// operands have different signs
|
||||
overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
|
||||
// and first operand and result have different signs
|
||||
&& ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
|
||||
}
|
||||
return overflow;
|
||||
}
|
||||
|
||||
|
||||
// Set the Carry flag.
|
||||
void Simulator::SetCFlag(bool val) {
|
||||
c_flag_ = val;
|
||||
}
|
||||
|
||||
|
||||
// Set the oVerflow flag.
|
||||
void Simulator::SetVFlag(bool val) {
|
||||
v_flag_ = val;
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeMoveWide(Instr* instr) {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeAddSubImm(Instr* instr) {
|
||||
switch (instr->Bit(30)) {
|
||||
case 0: {
|
||||
// Format(instr, "addi'sf's 'rd, 'rn, 'imm12s");
|
||||
const Register rd = instr->RdField();
|
||||
const Register rn = instr->RnField();
|
||||
const uint32_t imm = (instr->Bit(22) == 1) ? (instr->Imm12Field() << 12)
|
||||
: (instr->Imm12Field());
|
||||
if (instr->SFField()) {
|
||||
// 64-bit add.
|
||||
const int64_t rn_val = get_register(rn, instr->RnMode());
|
||||
const int64_t alu_out = rn_val + imm;
|
||||
set_register(rd, alu_out, instr->RdMode());
|
||||
if (instr->HasS()) {
|
||||
SetNZFlagsX(alu_out);
|
||||
SetCFlag(CarryFromX(rn_val, imm));
|
||||
SetVFlag(OverflowFromX(alu_out, rn_val, imm, true));
|
||||
}
|
||||
} else {
|
||||
// 32-bit add.
|
||||
const int32_t rn_val = get_wregister(rn, instr->RnMode());
|
||||
const int32_t alu_out = rn_val + imm;
|
||||
set_wregister(rd, alu_out, instr->RdMode());
|
||||
if (instr->HasS()) {
|
||||
SetNZFlagsW(alu_out);
|
||||
SetCFlag(CarryFromW(rn_val, imm));
|
||||
SetVFlag(OverflowFromW(alu_out, rn_val, imm, true));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UnimplementedInstruction(instr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Simulator::DecodeDPImmediate(Instr* instr) {
|
||||
if (instr->IsMoveWideOp()) {
|
||||
DecodeMoveWide(instr);
|
||||
} else if (instr->IsAddSubImmOp()) {
|
||||
DecodeAddSubImm(instr);
|
||||
} else {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeExceptionGen(Instr* instr) {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeSystem(Instr* instr) {
|
||||
if ((instr->Bits(0, 8) == 0x5f) && (instr->Bits(12, 4) == 2) &&
|
||||
(instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) &&
|
||||
(instr->Bit(21) == 0)) {
|
||||
if (instr->Bits(8, 4) == 0) {
|
||||
// Format(instr, "nop");
|
||||
} else {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
} else {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeUnconditionalBranchReg(Instr* instr) {
|
||||
if ((instr->Bits(0, 5) == 0) && (instr->Bits(10, 6) == 0) &&
|
||||
(instr->Bits(16, 5) == 0x1f)) {
|
||||
switch (instr->Bits(21, 4)) {
|
||||
case 2: {
|
||||
// Format(instr, "ret 'rn");
|
||||
const Register rn = instr->RnField();
|
||||
const int64_t rn_val = get_register(rn, instr->RnMode());
|
||||
set_pc(rn_val);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UnimplementedInstruction(instr);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeCompareBranch(Instr* instr) {
|
||||
if (instr->IsExceptionGenOp()) {
|
||||
DecodeExceptionGen(instr);
|
||||
} else if (instr->IsSystemOp()) {
|
||||
DecodeSystem(instr);
|
||||
} else if (instr->IsUnconditionalBranchRegOp()) {
|
||||
DecodeUnconditionalBranchReg(instr);
|
||||
} else {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeLoadStore(Instr* instr) {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
|
||||
|
||||
int64_t Simulator::ShiftOperand(uint8_t reg_size,
|
||||
int64_t value,
|
||||
Shift shift_type,
|
||||
uint8_t amount) {
|
||||
if (amount == 0) {
|
||||
return value;
|
||||
}
|
||||
int64_t mask = reg_size == kXRegSizeInBits ? kXRegMask : kWRegMask;
|
||||
switch (shift_type) {
|
||||
case LSL:
|
||||
return (value << amount) & mask;
|
||||
case LSR:
|
||||
return static_cast<uint64_t>(value) >> amount;
|
||||
case ASR: {
|
||||
// Shift used to restore the sign.
|
||||
uint8_t s_shift = kXRegSizeInBits - reg_size;
|
||||
// Value with its sign restored.
|
||||
int64_t s_value = (value << s_shift) >> s_shift;
|
||||
return (s_value >> amount) & mask;
|
||||
}
|
||||
case ROR: {
|
||||
if (reg_size == kWRegSizeInBits) {
|
||||
value &= kWRegMask;
|
||||
}
|
||||
return (static_cast<uint64_t>(value) >> amount) |
|
||||
((value & ((1L << amount) - 1L)) << (reg_size - amount));
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int64_t Simulator::ExtendOperand(uint8_t reg_size,
|
||||
int64_t value,
|
||||
Extend extend_type,
|
||||
uint8_t amount) {
|
||||
switch (extend_type) {
|
||||
case UXTB:
|
||||
value &= 0xff;
|
||||
break;
|
||||
case UXTH:
|
||||
value &= 0xffff;
|
||||
break;
|
||||
case UXTW:
|
||||
value &= 0xffffffff;
|
||||
break;
|
||||
case SXTB:
|
||||
value = (value << 56) >> 56;
|
||||
break;
|
||||
case SXTH:
|
||||
value = (value << 48) >> 48;
|
||||
break;
|
||||
case SXTW:
|
||||
value = (value << 32) >> 32;
|
||||
break;
|
||||
case UXTX:
|
||||
case SXTX:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
int64_t mask = (reg_size == kXRegSizeInBits) ? kXRegMask : kWRegMask;
|
||||
return (value << amount) & mask;
|
||||
}
|
||||
|
||||
|
||||
int64_t Simulator::DecodeShiftExtendOperand(Instr* instr) {
|
||||
const Register rm = instr->RmField();
|
||||
const int64_t rm_val = get_register(rm, R31IsZR);
|
||||
const uint8_t size = instr->SFField() ? kXRegSizeInBits : kWRegSizeInBits;
|
||||
if (instr->IsShift()) {
|
||||
const Shift shift_type = instr->ShiftTypeField();
|
||||
const uint8_t shift_amount = instr->Imm6Field();
|
||||
return ShiftOperand(size, rm_val, shift_type, shift_amount);
|
||||
} else {
|
||||
ASSERT(instr->IsExtend());
|
||||
const Extend extend_type = instr->ExtendTypeField();
|
||||
const uint8_t shift_amount = instr->Imm3Field();
|
||||
return ExtendOperand(size, rm_val, extend_type, shift_amount);
|
||||
}
|
||||
UNREACHABLE();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeAddSubShiftExt(Instr* instr) {
|
||||
switch (instr->Bit(30)) {
|
||||
case 0: {
|
||||
// Format(instr, "add'sf's 'rd, 'rn, 'shift_op");
|
||||
const Register rd = instr->RdField();
|
||||
const Register rn = instr->RnField();
|
||||
const int64_t rm_val = DecodeShiftExtendOperand(instr);
|
||||
if (instr->SFField()) {
|
||||
// 64-bit add.
|
||||
const int64_t rn_val = get_register(rn, instr->RnMode());
|
||||
const int64_t alu_out = rn_val + rm_val;
|
||||
set_register(rd, alu_out, instr->RdMode());
|
||||
if (instr->HasS()) {
|
||||
SetNZFlagsX(alu_out);
|
||||
SetCFlag(CarryFromX(rn_val, rm_val));
|
||||
SetVFlag(OverflowFromX(alu_out, rn_val, rm_val, true));
|
||||
}
|
||||
} else {
|
||||
// 32-bit add.
|
||||
const int32_t rn_val = get_wregister(rn, instr->RnMode());
|
||||
const int32_t rm_val32 = static_cast<int32_t>(rm_val & kWRegMask);
|
||||
const int32_t alu_out = rn_val + rm_val32;
|
||||
set_wregister(rd, alu_out, instr->RdMode());
|
||||
if (instr->HasS()) {
|
||||
SetNZFlagsW(alu_out);
|
||||
SetCFlag(CarryFromW(rn_val, rm_val32));
|
||||
SetVFlag(OverflowFromW(alu_out, rn_val, rm_val32, true));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UnimplementedInstruction(instr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeDPRegister(Instr* instr) {
|
||||
if (instr->IsAddSubShiftExtOp()) {
|
||||
DecodeAddSubShiftExt(instr);
|
||||
} else {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeDPSimd1(Instr* instr) {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeDPSimd2(Instr* instr) {
|
||||
UnimplementedInstruction(instr);
|
||||
}
|
||||
|
||||
|
||||
// Executes the current instruction.
|
||||
void Simulator::InstructionDecode(Instr* instr) {
|
||||
pc_modified_ = false;
|
||||
if (FLAG_trace_sim) {
|
||||
const uword start = reinterpret_cast<uword>(instr);
|
||||
const uword end = start + Instr::kInstrSize;
|
||||
Disassembler::Disassemble(start, end);
|
||||
}
|
||||
|
||||
if (instr->IsDPImmediateOp()) {
|
||||
DecodeDPImmediate(instr);
|
||||
} else if (instr->IsCompareBranchOp()) {
|
||||
DecodeCompareBranch(instr);
|
||||
} else if (instr->IsLoadStoreOp()) {
|
||||
DecodeLoadStore(instr);
|
||||
} else if (instr->IsDPRegisterOp()) {
|
||||
DecodeDPRegister(instr);
|
||||
} else if (instr->IsDPSimd1Op()) {
|
||||
DecodeDPSimd1(instr);
|
||||
} else {
|
||||
ASSERT(instr->IsDPSimd2Op());
|
||||
DecodeDPSimd2(instr);
|
||||
}
|
||||
|
||||
if (!pc_modified_) {
|
||||
set_pc(reinterpret_cast<int64_t>(instr) + Instr::kInstrSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::Execute() {
|
||||
// Get the PC to simulate. Cannot use the accessor here as we need the
|
||||
// raw PC value and not the one used as input to arithmetic instructions.
|
||||
uword program_counter = get_pc();
|
||||
|
||||
if (FLAG_stop_sim_at == 0) {
|
||||
// Fast version of the dispatch loop without checking whether the simulator
|
||||
// should be stopping at a particular executed instruction.
|
||||
while (program_counter != kEndSimulatingPC) {
|
||||
Instr* instr = reinterpret_cast<Instr*>(program_counter);
|
||||
icount_++;
|
||||
if (IsIllegalAddress(program_counter)) {
|
||||
HandleIllegalAccess(program_counter, instr);
|
||||
} else {
|
||||
InstructionDecode(instr);
|
||||
}
|
||||
program_counter = get_pc();
|
||||
}
|
||||
} else {
|
||||
// FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
|
||||
// we reach the particular instruction count.
|
||||
while (program_counter != kEndSimulatingPC) {
|
||||
Instr* instr = reinterpret_cast<Instr*>(program_counter);
|
||||
icount_++;
|
||||
if (icount_ == FLAG_stop_sim_at) {
|
||||
// TODO(zra): Add a debugger.
|
||||
UNIMPLEMENTED();
|
||||
} else if (IsIllegalAddress(program_counter)) {
|
||||
HandleIllegalAccess(program_counter, instr);
|
||||
} else {
|
||||
InstructionDecode(instr);
|
||||
}
|
||||
program_counter = get_pc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int64_t Simulator::Call(int64_t entry,
|
||||
int64_t parameter0,
|
||||
int64_t parameter1,
|
||||
int64_t parameter2,
|
||||
int64_t parameter3) {
|
||||
// Save the SP register before the call so we can restore it.
|
||||
int32_t sp_before_call = get_register(SP, R31IsSP);
|
||||
|
||||
// Setup parameters.
|
||||
set_register(R0, parameter0);
|
||||
set_register(R1, parameter1);
|
||||
set_register(R2, parameter2);
|
||||
set_register(R3, parameter3);
|
||||
|
||||
// Make sure the activation frames are properly aligned.
|
||||
int32_t stack_pointer = sp_before_call;
|
||||
if (OS::ActivationFrameAlignment() > 1) {
|
||||
stack_pointer =
|
||||
Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment());
|
||||
}
|
||||
set_register(SP, stack_pointer, R31IsSP);
|
||||
|
||||
// Prepare to execute the code at entry.
|
||||
set_pc(entry);
|
||||
// Put down marker for end of simulation. The simulator will stop simulation
|
||||
// when the PC reaches this value. By saving the "end simulation" value into
|
||||
// the LR the simulation stops when returning to this call point.
|
||||
set_register(LR, kEndSimulatingPC);
|
||||
|
||||
// Remember the values of callee-saved registers.
|
||||
int64_t r19_val = get_register(R19);
|
||||
int64_t r20_val = get_register(R20);
|
||||
int64_t r21_val = get_register(R21);
|
||||
int64_t r22_val = get_register(R22);
|
||||
int64_t r23_val = get_register(R23);
|
||||
int64_t r24_val = get_register(R24);
|
||||
int64_t r25_val = get_register(R25);
|
||||
int64_t r26_val = get_register(R26);
|
||||
int64_t r27_val = get_register(R27);
|
||||
int64_t r28_val = get_register(R28);
|
||||
int64_t r29_val = get_register(R29);
|
||||
|
||||
// Setup the callee-saved registers with a known value. To be able to check
|
||||
// that they are preserved properly across dart execution.
|
||||
int64_t callee_saved_value = icount_;
|
||||
set_register(R19, callee_saved_value);
|
||||
set_register(R20, callee_saved_value);
|
||||
set_register(R21, callee_saved_value);
|
||||
set_register(R22, callee_saved_value);
|
||||
set_register(R23, callee_saved_value);
|
||||
set_register(R24, callee_saved_value);
|
||||
set_register(R25, callee_saved_value);
|
||||
set_register(R26, callee_saved_value);
|
||||
set_register(R27, callee_saved_value);
|
||||
set_register(R28, callee_saved_value);
|
||||
set_register(R29, callee_saved_value);
|
||||
|
||||
// Start the simulation
|
||||
Execute();
|
||||
|
||||
// Check that the callee-saved registers have been preserved.
|
||||
ASSERT(callee_saved_value == get_register(R19));
|
||||
ASSERT(callee_saved_value == get_register(R20));
|
||||
ASSERT(callee_saved_value == get_register(R21));
|
||||
ASSERT(callee_saved_value == get_register(R22));
|
||||
ASSERT(callee_saved_value == get_register(R23));
|
||||
ASSERT(callee_saved_value == get_register(R24));
|
||||
ASSERT(callee_saved_value == get_register(R25));
|
||||
ASSERT(callee_saved_value == get_register(R26));
|
||||
ASSERT(callee_saved_value == get_register(R27));
|
||||
ASSERT(callee_saved_value == get_register(R28));
|
||||
ASSERT(callee_saved_value == get_register(R29));
|
||||
|
||||
// Restore callee-saved registers with the original value.
|
||||
set_register(R19, r19_val);
|
||||
set_register(R20, r20_val);
|
||||
set_register(R21, r21_val);
|
||||
set_register(R22, r22_val);
|
||||
set_register(R23, r23_val);
|
||||
set_register(R24, r24_val);
|
||||
set_register(R25, r25_val);
|
||||
set_register(R26, r26_val);
|
||||
set_register(R27, r27_val);
|
||||
set_register(R28, r28_val);
|
||||
set_register(R29, r29_val);
|
||||
|
||||
// Restore the SP register and return R1:R0.
|
||||
set_register(SP, sp_before_call, R31IsSP);
|
||||
int64_t return_value;
|
||||
return_value = get_register(R0);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(HOST_ARCH_ARM64)
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
160
runtime/vm/simulator_arm64.h
Normal file
160
runtime/vm/simulator_arm64.h
Normal file
|
@ -0,0 +1,160 @@
|
|||
// Copyright (c) 2014, 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.
|
||||
|
||||
// Declares a Simulator for ARM64 instructions if we are not generating a native
|
||||
// ARM64 binary. This Simulator allows us to run and debug ARM64 code generation
|
||||
// on regular desktop machines.
|
||||
// Dart calls into generated code by "calling" the InvokeDartCode stub,
|
||||
// which will start execution in the Simulator or forwards to the real entry
|
||||
// on a ARM64 HW platform.
|
||||
|
||||
#ifndef VM_SIMULATOR_ARM64_H_
|
||||
#define VM_SIMULATOR_ARM64_H_
|
||||
|
||||
#ifndef VM_SIMULATOR_H_
|
||||
#error Do not include simulator_arm64.h directly; use simulator.h.
|
||||
#endif
|
||||
|
||||
#include "vm/constants_arm64.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class Isolate;
|
||||
|
||||
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 for register state.
|
||||
void set_register(Register reg, int64_t value, R31Type r31t = R31IsUndef);
|
||||
int64_t get_register(Register reg, R31Type r31t = R31IsUndef) const;
|
||||
void set_wregister(Register reg, int32_t value, R31Type r31t = R31IsUndef);
|
||||
int32_t get_wregister(Register reg, R31Type r31t = R31IsUndef) const;
|
||||
|
||||
int64_t get_pc() const;
|
||||
void set_pc(int64_t pc);
|
||||
|
||||
// Accessor to the internal simulator stack top.
|
||||
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() {}
|
||||
|
||||
// Dart generally calls into generated code with 5 parameters. This is a
|
||||
// convenience function, which sets up the simulator state and grabs the
|
||||
// result on return. The return value is R0. The parameters are placed in
|
||||
// R0-3.
|
||||
int64_t Call(int64_t entry,
|
||||
int64_t parameter0,
|
||||
int64_t parameter1,
|
||||
int64_t parameter2,
|
||||
int64_t parameter3);
|
||||
|
||||
void Longjmp(uword pc,
|
||||
uword sp,
|
||||
uword fp,
|
||||
RawObject* raw_exception,
|
||||
RawObject* raw_stacktrace) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
private:
|
||||
// Known bad pc value to ensure that the simulator does not execute
|
||||
// without being properly setup.
|
||||
static const uword kBadLR = -1;
|
||||
// A pc value used to signal the simulator to stop execution. Generally
|
||||
// the lr is set to this value on transition from native C code to
|
||||
// simulated execution, so that the simulator can "return" to the native
|
||||
// C code.
|
||||
static const uword kEndSimulatingPC = -2;
|
||||
|
||||
// CPU state.
|
||||
int64_t registers_[kNumberOfCpuRegisters];
|
||||
bool n_flag_;
|
||||
bool z_flag_;
|
||||
bool c_flag_;
|
||||
bool v_flag_;
|
||||
|
||||
// Simulator support.
|
||||
int64_t pc_;
|
||||
char* stack_;
|
||||
bool pc_modified_;
|
||||
intptr_t icount_;
|
||||
static int64_t flag_stop_sim_at_;
|
||||
uword top_exit_frame_info_;
|
||||
|
||||
// Registered breakpoints.
|
||||
Instr* break_pc_;
|
||||
int64_t break_instr_;
|
||||
|
||||
// Illegal memory access support.
|
||||
static bool IsIllegalAddress(uword addr) {
|
||||
return addr < 64*1024;
|
||||
}
|
||||
void HandleIllegalAccess(uword addr, Instr* instr);
|
||||
|
||||
// Handles a legal instruction that the simulator does not implement.
|
||||
void UnimplementedInstruction(Instr* instr);
|
||||
|
||||
// Unsupported instructions use Format to print an error and stop execution.
|
||||
void Format(Instr* instr, const char* format);
|
||||
|
||||
// Helper functions to set the conditional flags in the architecture state.
|
||||
void SetNZFlagsW(int32_t val);
|
||||
bool CarryFromW(int32_t left, int32_t right);
|
||||
bool BorrowFromW(int32_t left, int32_t right);
|
||||
bool OverflowFromW(
|
||||
int32_t alu_out, int32_t left, int32_t right, bool addition);
|
||||
|
||||
void SetNZFlagsX(int64_t val);
|
||||
bool CarryFromX(int64_t left, int64_t right);
|
||||
bool BorrowFromX(int64_t left, int64_t right);
|
||||
bool OverflowFromX(
|
||||
int64_t alu_out, int64_t left, int64_t right, bool addition);
|
||||
|
||||
void SetCFlag(bool val);
|
||||
void SetVFlag(bool val);
|
||||
|
||||
int64_t ShiftOperand(uint8_t reg_size,
|
||||
int64_t value,
|
||||
Shift shift_type,
|
||||
uint8_t amount);
|
||||
|
||||
int64_t ExtendOperand(uint8_t reg_size,
|
||||
int64_t value,
|
||||
Extend extend_type,
|
||||
uint8_t amount);
|
||||
|
||||
int64_t DecodeShiftExtendOperand(Instr* instr);
|
||||
|
||||
// Decode instructions.
|
||||
void InstructionDecode(Instr* instr);
|
||||
#define DECODE_OP(op) \
|
||||
void Decode##op(Instr* instr);
|
||||
APPLY_OP_LIST(DECODE_OP)
|
||||
#undef DECODE_OP
|
||||
|
||||
// Executes ARM64 instructions until the PC reaches kEndSimulatingPC.
|
||||
void Execute();
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Simulator);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_SIMULATOR_ARM64_H_
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "include/dart_debugger_api.h"
|
||||
#include "platform/assert.h"
|
||||
#include "vm/bigint_operations.h"
|
||||
|
@ -2692,3 +2696,5 @@ UNIT_TEST_CASE(PostCObject) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "vm/stack_frame_x64.h"
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
#include "vm/stack_frame_arm.h"
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
#include "vm/stack_frame_arm64.h"
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
#include "vm/stack_frame_mips.h"
|
||||
#else
|
||||
|
|
34
runtime/vm/stack_frame_arm64.h
Normal file
34
runtime/vm/stack_frame_arm64.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2014, 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_ARM64_H_
|
||||
#define VM_STACK_FRAME_ARM64_H_
|
||||
|
||||
namespace dart {
|
||||
|
||||
// TODO(zra):
|
||||
// These are the values for ARM. Fill in the values for ARM64 as they are
|
||||
// needed.
|
||||
|
||||
static const int kDartFrameFixedSize = 4; // PP, FP, LR, PC marker.
|
||||
static const int kSavedPcSlotFromSp = -2;
|
||||
|
||||
static const int kFirstObjectSlotFromFp = -1; // Used by GC to traverse stack.
|
||||
|
||||
static const int kFirstLocalSlotFromFp = -2;
|
||||
static const int kSavedCallerPpSlotFromFp = -1;
|
||||
static const int kSavedCallerFpSlotFromFp = 0;
|
||||
static const int kSavedCallerPcSlotFromFp = 1;
|
||||
static const int kPcMarkerSlotFromFp = 2;
|
||||
static const int kParamEndSlotFromFp = 2; // One slot past last parameter.
|
||||
static const int kCallerSpSlotFromFp = 3;
|
||||
|
||||
// Entry and exit frame layout.
|
||||
static const int kSavedContextSlotFromEntryFp = -27;
|
||||
static const int kExitLinkSlotFromEntryFp = -26;
|
||||
static const int kSavedVMTagSlotFromEntryFp = -25;
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_STACK_FRAME_ARM64_H_
|
|
@ -2,6 +2,10 @@
|
|||
// 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.
|
||||
|
||||
// TODO(zra): Remove when tests are ready to enable.
|
||||
#include "platform/globals.h"
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
#include "include/dart_api.h"
|
||||
#include "platform/assert.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
|
@ -288,3 +292,5 @@ TEST_CASE(ValidateNoSuchMethodStackFrameIteration) {
|
|||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "vm/stub_code.h"
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/disassembler.h"
|
||||
#include "vm/flags.h"
|
||||
|
@ -50,9 +51,12 @@ StubCode::~StubCode() {
|
|||
|
||||
|
||||
void StubCode::InitOnce() {
|
||||
// TODO(zra): ifndef to be removed when ARM64 port is ready.
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
// Generate all the stubs.
|
||||
Code& code = Code::Handle();
|
||||
VM_STUB_CODE_LIST(STUB_CODE_GENERATE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -66,9 +70,12 @@ void StubCode::GenerateFor(Isolate* init) {
|
|||
|
||||
|
||||
void StubCode::Init(Isolate* isolate) {
|
||||
// TODO(zra): ifndef to be removed when ARM64 port is ready.
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
StubCode* stubs = new StubCode();
|
||||
isolate->set_stub_code(stubs);
|
||||
stubs->GenerateFor(isolate);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
249
runtime/vm/stub_code_arm64.cc
Normal file
249
runtime/vm/stub_code_arm64.cc
Normal file
|
@ -0,0 +1,249 @@
|
|||
// Copyright (c) 2014, 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_ARM64)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/code_generator.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 {
|
||||
|
||||
void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GeneratePrintStopMessageStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateDeoptimizeStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
|
||||
const Class& cls) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateUsageCounterIncrement(Assembler* assembler,
|
||||
Register temp_reg) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateNArgsCheckInlineCacheStub(
|
||||
Assembler* assembler,
|
||||
intptr_t num_args,
|
||||
const RuntimeEntry& handle_ic_miss) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub(
|
||||
Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub(
|
||||
Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub(
|
||||
Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateLazyCompileStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateDebugStepCheckStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateSubtype1TestCacheStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateSubtype2TestCacheStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateSubtype3TestCacheStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateGetStackPointerStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
|
||||
const Register left,
|
||||
const Register right,
|
||||
const Register temp,
|
||||
const Register unused) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateUnoptimizedIdenticalWithNumberCheckStub(
|
||||
Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub(
|
||||
Assembler* assembler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
10
runtime/vm/stub_code_arm64_test.cc
Normal file
10
runtime/vm/stub_code_arm64_test.cc
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) 2014, 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_ARM64)
|
||||
|
||||
// TODO(zra): Port these tests.
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM64
|
|
@ -2,13 +2,14 @@
|
|||
// 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 <stdio.h>
|
||||
|
||||
#include "vm/unit_test.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bin/builtin.h"
|
||||
#include "bin/dartutils.h"
|
||||
|
||||
#include "platform/globals.h"
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/ast_printer.h"
|
||||
#include "vm/compiler.h"
|
||||
|
@ -25,7 +26,6 @@ namespace dart {
|
|||
|
||||
DECLARE_FLAG(bool, disassemble);
|
||||
|
||||
|
||||
TestCaseBase* TestCaseBase::first_ = NULL;
|
||||
TestCaseBase* TestCaseBase::tail_ = NULL;
|
||||
|
||||
|
@ -48,6 +48,8 @@ void TestCaseBase::RunAll() {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(zra): Remove when tests that need these functions are ready to enable.
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
|
||||
Dart_Handle library,
|
||||
|
@ -142,6 +144,7 @@ Dart_Handle TestCase::library_handler(Dart_LibraryTag tag,
|
|||
return Api::Success();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void AssemblerTest::Assemble() {
|
||||
const String& function_name = String::ZoneHandle(Symbols::New(name_));
|
||||
|
@ -166,6 +169,9 @@ void AssemblerTest::Assemble() {
|
|||
}
|
||||
|
||||
|
||||
// TODO(zra): Remove once supported.
|
||||
#if !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
CodeGenTest::CodeGenTest(const char* name)
|
||||
: function_(Function::ZoneHandle()),
|
||||
node_sequence_(new SequenceNode(Scanner::kNoSourcePos,
|
||||
|
@ -233,4 +239,6 @@ bool CompilerTest::TestCompileFunction(const Function& function) {
|
|||
return error.IsNull();
|
||||
}
|
||||
|
||||
#endif // !defined(TARGET_ARCH_ARM64)
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "include/dart_api.h"
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
#include "vm/ast.h"
|
||||
#include "vm/dart.h"
|
||||
#include "vm/globals.h"
|
||||
|
@ -130,8 +132,12 @@
|
|||
}
|
||||
|
||||
|
||||
#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
|
||||
#if defined(HOST_ARCH_ARM) || defined(HOST_ARCH_MIPS)
|
||||
#if defined(TARGET_ARCH_ARM) || \
|
||||
defined(TARGET_ARCH_MIPS) || \
|
||||
defined(TARGET_ARCH_ARM64)
|
||||
#if defined(HOST_ARCH_ARM) || \
|
||||
defined(HOST_ARCH_MIPS) || \
|
||||
defined(HOST_ARCH_ARM64)
|
||||
// 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_LL(name, entry, long_arg0, long_arg1) \
|
||||
|
@ -144,9 +150,16 @@
|
|||
reinterpret_cast<name>(entry)(double_arg)
|
||||
#else
|
||||
// Not running on ARM or MIPS hardware, call simulator to execute code.
|
||||
#if defined(ARCH_IS_64_BIT)
|
||||
// TODO(zra): Supply more macros for 64-bit as tests are added for ARM64.
|
||||
#define EXECUTE_TEST_CODE_INT32(name, entry) \
|
||||
static_cast<int32_t>(Simulator::Current()->Call( \
|
||||
bit_cast<int64_t, uword>(entry), 0, 0, 0, 0))
|
||||
#else
|
||||
#define EXECUTE_TEST_CODE_INT32(name, entry) \
|
||||
static_cast<int32_t>(Simulator::Current()->Call( \
|
||||
bit_cast<int32_t, uword>(entry), 0, 0, 0, 0))
|
||||
#endif
|
||||
#define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1) \
|
||||
static_cast<int64_t>(Simulator::Current()->Call( \
|
||||
bit_cast<int32_t, uword>(entry), \
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
'assembler_arm.cc',
|
||||
'assembler_arm.h',
|
||||
'assembler_arm_test.cc',
|
||||
'assembler_arm64.cc',
|
||||
'assembler_arm64.h',
|
||||
'assembler_arm64_test.cc',
|
||||
'assembler_ia32.cc',
|
||||
'assembler_ia32.h',
|
||||
'assembler_ia32_test.cc',
|
||||
|
@ -77,6 +80,8 @@
|
|||
'code_patcher.h',
|
||||
'code_patcher_arm.cc',
|
||||
'code_patcher_arm_test.cc',
|
||||
'code_patcher_arm64.cc',
|
||||
'code_patcher_arm64_test.cc',
|
||||
'code_patcher_ia32.cc',
|
||||
'code_patcher_ia32_test.cc',
|
||||
'code_patcher_mips.cc',
|
||||
|
@ -89,6 +94,7 @@
|
|||
'compiler_stats.h',
|
||||
'compiler_test.cc',
|
||||
'constants_arm.h',
|
||||
'constants_arm64.h',
|
||||
'constants_ia32.h',
|
||||
'constants_mips.h',
|
||||
'constants_x64.h',
|
||||
|
@ -96,6 +102,7 @@
|
|||
'coverage.h',
|
||||
'cpu.h',
|
||||
'cpu_arm.cc',
|
||||
'cpu_arm64.cc',
|
||||
'cpu_ia32.cc',
|
||||
'cpu_mips.cc',
|
||||
'cpu_test.cc',
|
||||
|
@ -124,6 +131,7 @@
|
|||
'debugger.h',
|
||||
'debugger_api_impl_test.cc',
|
||||
'debugger_arm.cc',
|
||||
'debugger_arm64.cc',
|
||||
'debugger_ia32.cc',
|
||||
'debugger_mips.cc',
|
||||
'debugger_x64.cc',
|
||||
|
@ -137,6 +145,7 @@
|
|||
'disassembler.cc',
|
||||
'disassembler.h',
|
||||
'disassembler_arm.cc',
|
||||
'disassembler_arm64.cc',
|
||||
'disassembler_ia32.cc',
|
||||
'disassembler_mips.cc',
|
||||
'disassembler_test.cc',
|
||||
|
@ -160,6 +169,7 @@
|
|||
'flow_graph_compiler.cc',
|
||||
'flow_graph_compiler.h',
|
||||
'flow_graph_compiler_arm.cc',
|
||||
'flow_graph_compiler_arm64.cc',
|
||||
'flow_graph_compiler_ia32.cc',
|
||||
'flow_graph_compiler_mips.cc',
|
||||
'flow_graph_compiler_x64.cc',
|
||||
|
@ -199,6 +209,9 @@
|
|||
'instructions_arm.cc',
|
||||
'instructions_arm.h',
|
||||
'instructions_arm_test.cc',
|
||||
'instructions_arm64.cc',
|
||||
'instructions_arm64.h',
|
||||
'instructions_arm64_test.cc',
|
||||
'instructions_ia32.cc',
|
||||
'instructions_ia32.h',
|
||||
'instructions_ia32_test.cc',
|
||||
|
@ -211,6 +224,7 @@
|
|||
'intermediate_language.cc',
|
||||
'intermediate_language.h',
|
||||
'intermediate_language_arm.cc',
|
||||
'intermediate_language_arm64.cc',
|
||||
'intermediate_language_ia32.cc',
|
||||
'intermediate_language_mips.cc',
|
||||
'intermediate_language_test.cc',
|
||||
|
@ -218,6 +232,7 @@
|
|||
'intrinsifier.cc',
|
||||
'intrinsifier.h',
|
||||
'intrinsifier_arm.cc',
|
||||
'intrinsifier_arm64.cc',
|
||||
'intrinsifier_ia32.cc',
|
||||
'intrinsifier_mips.cc',
|
||||
'intrinsifier_x64.cc',
|
||||
|
@ -258,6 +273,7 @@
|
|||
'object.cc',
|
||||
'object.h',
|
||||
'object_arm_test.cc',
|
||||
'object_arm64_test.cc',
|
||||
'object_ia32_test.cc',
|
||||
'object_id_ring.cc',
|
||||
'object_id_ring.h',
|
||||
|
@ -300,6 +316,7 @@
|
|||
'reusable_handles.h',
|
||||
'runtime_entry.h',
|
||||
'runtime_entry_arm.cc',
|
||||
'runtime_entry_arm64.cc',
|
||||
'runtime_entry_ia32.cc',
|
||||
'runtime_entry_mips.cc',
|
||||
'runtime_entry_test.cc',
|
||||
|
@ -323,6 +340,8 @@
|
|||
'simulator.h',
|
||||
'simulator_arm.cc',
|
||||
'simulator_arm.h',
|
||||
'simulator_arm64.cc',
|
||||
'simulator_arm64.h',
|
||||
'simulator_mips.cc',
|
||||
'simulator_mips.h',
|
||||
'snapshot.cc',
|
||||
|
@ -332,6 +351,7 @@
|
|||
'stack_frame.cc',
|
||||
'stack_frame.h',
|
||||
'stack_frame_arm.h',
|
||||
'stack_frame_arm64.h',
|
||||
'stack_frame_ia32.h',
|
||||
'stack_frame_mips.h',
|
||||
'stack_frame_test.cc',
|
||||
|
@ -342,6 +362,8 @@
|
|||
'stub_code.h',
|
||||
'stub_code_arm.cc',
|
||||
'stub_code_arm_test.cc',
|
||||
'stub_code_arm64.cc',
|
||||
'stub_code_arm64_test.cc',
|
||||
'stub_code_ia32.cc',
|
||||
'stub_code_ia32_test.cc',
|
||||
'stub_code_mips.cc',
|
||||
|
|
|
@ -79,3 +79,6 @@ LibTest/collection/ListBase/ListBase_class_A01_t01: Skip # Timeouts
|
|||
|
||||
[ $runtime == vm ]
|
||||
LibTest/isolate/Isolate/spawn_A02_t01: Skip # co19 issue 667
|
||||
|
||||
[ $compiler == none && $runtime == vm && $arch == simarm64 ]
|
||||
*: Skip
|
||||
|
|
|
@ -143,6 +143,9 @@ int_parse_radix_test: Skip # Timeout
|
|||
[ $arch == simarm && $checked ]
|
||||
num_parse_test: Pass, Timeout
|
||||
|
||||
[ $arch == simarm64 ]
|
||||
*: Skip
|
||||
|
||||
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
|
||||
error_stack_trace_test: StaticWarning, OK # Test generates errors on purpose.
|
||||
iterable_element_at_test: StaticWarning, OK # Test generates errors on purpose.
|
||||
|
|
|
@ -9,6 +9,9 @@ isolate_stress_test: Fail # Issue 12588: This should be able to pass when we hav
|
|||
[ $runtime == vm && $arch == mips && $mode == debug ]
|
||||
mandel_isolate_test: Skip # Uses 600 MB Ram on our 1 GB test device.
|
||||
|
||||
[ $runtime == vm && $arch == simarm64 ]
|
||||
*: Skip
|
||||
|
||||
[ $compiler == none || $compiler == dart2dart ]
|
||||
serialization_test: SkipByDesign # Tests dart2js-specific serialization code
|
||||
isolate_throws_test/01: Skip # Issue 12587
|
||||
|
|
|
@ -134,3 +134,6 @@ generic_instanceof3_test: Pass, Crash # Issue 17440.
|
|||
[ $compiler == none && $runtime == vm && $arch == mips && $mode == debug ]
|
||||
stack_overflow_test: Skip # Crashes. Issue 17440.
|
||||
stack_overflow_stacktrace_test: Skip # Crashes. Issue 17440.
|
||||
|
||||
[ $compiler == none && $runtime == vm && $arch == simarm64 ]
|
||||
*: Skip
|
||||
|
|
|
@ -283,6 +283,9 @@ convert/streamed_conversion_json_utf8_decode_test: Pass, Slow
|
|||
convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12644.
|
||||
convert/utf85_test: Pass, Slow # Issue 12644.
|
||||
|
||||
[ $arch == simarm64 ]
|
||||
*: Skip
|
||||
|
||||
[ $compiler == none && $runtime == dartium ]
|
||||
async/schedule_microtask5_test: Pass, Timeout # Issue 13719: Please triage this failure.
|
||||
async/timer_cancel2_test: Pass, Timeout # Issue 13719: Please triage this failure.
|
||||
|
|
|
@ -119,6 +119,9 @@ io/signals_test: Skip # Starts 10 dart subprocesses, uses too much memory
|
|||
[ $arch == mips && $mode == debug ]
|
||||
io/file_read_special_device_test: Fail # dartbug.com/17440
|
||||
|
||||
[ $arch == simarm64 ]
|
||||
*: Skip
|
||||
|
||||
[ $compiler == none && ($runtime == dartium || $runtime == ContentShellOnAndroid) && $unchecked ]
|
||||
assert_test: Fail # Issue 13719: Please triage this failure.
|
||||
|
||||
|
|
|
@ -18,3 +18,6 @@ dart2js_test: Skip # Uses dart:io.
|
|||
|
||||
[ $compiler == dart2js && $mode == debug ]
|
||||
source_mirrors_test: Slow, Pass
|
||||
|
||||
[ $compiler == none && $runtime == vm && $arch == simarm64 ]
|
||||
*: Skip
|
||||
|
|
|
@ -44,7 +44,7 @@ def BuildOptions():
|
|||
default=False, action="store_true")
|
||||
result.add_option("-a", "--arch",
|
||||
help='Target architectures (comma-separated).',
|
||||
metavar='[all,ia32,x64,simarm,arm,simmips,mips]',
|
||||
metavar='[all,ia32,x64,simarm,arm,simmips,mips,simarm64]',
|
||||
default=utils.GuessArchitecture())
|
||||
result.add_option("--os",
|
||||
help='Target OSs (comma-separated).',
|
||||
|
@ -76,7 +76,7 @@ def ProcessOsOption(os):
|
|||
|
||||
def ProcessOptions(options, args):
|
||||
if options.arch == 'all':
|
||||
options.arch = 'ia32,x64,simarm,simmips'
|
||||
options.arch = 'ia32,x64,simarm,simmips,simarm64'
|
||||
if options.mode == 'all':
|
||||
options.mode = 'release,debug'
|
||||
if options.os == 'all':
|
||||
|
@ -89,7 +89,8 @@ def ProcessOptions(options, args):
|
|||
print "Unknown mode %s" % mode
|
||||
return False
|
||||
for arch in options.arch:
|
||||
if not arch in ['ia32', 'x64', 'simarm', 'arm', 'simmips', 'mips']:
|
||||
archs = ['ia32', 'x64', 'simarm', 'arm', 'simmips', 'mips', 'simarm64']
|
||||
if not arch in archs:
|
||||
print "Unknown arch %s" % arch
|
||||
return False
|
||||
options.os = [ProcessOsOption(os) for os in options.os]
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
['"<(target_arch)"=="x64"', { 'dart_target_arch': 'X64', }],
|
||||
['"<(target_arch)"=="arm"', { 'dart_target_arch': 'ARM', }],
|
||||
['"<(target_arch)"=="simarm"', { 'dart_target_arch': 'SIMARM', }],
|
||||
['"<(target_arch)"=="simarm64"', { 'dart_target_arch': 'SIMARM64', }],
|
||||
['"<(target_arch)"=="mips"', { 'dart_target_arch': 'MIPS', }],
|
||||
['"<(target_arch)"=="simmips"', { 'dart_target_arch': 'SIMMIPS', }],
|
||||
[ 'OS=="linux"', { 'dart_target_os': 'Linux', } ],
|
||||
|
@ -59,6 +60,13 @@
|
|||
]
|
||||
},
|
||||
|
||||
'Dart_simarm64_Base': {
|
||||
'abstract': 1,
|
||||
'defines': [
|
||||
'TARGET_ARCH_ARM64',
|
||||
]
|
||||
},
|
||||
|
||||
'Dart_arm_Base': {
|
||||
'abstract': 1,
|
||||
'defines': [
|
||||
|
@ -150,6 +158,27 @@
|
|||
],
|
||||
},
|
||||
|
||||
'DebugSIMARM64': {
|
||||
'inherit_from': [
|
||||
'Dart_Base', 'Dart_simarm64_Base', 'Dart_Debug',
|
||||
'Dart_<(dart_target_os)_Base',
|
||||
'Dart_<(dart_target_os)_simarm64_Base',
|
||||
'Dart_<(dart_target_os)_Debug',
|
||||
],
|
||||
'defines': [
|
||||
'DEBUG',
|
||||
],
|
||||
},
|
||||
|
||||
'ReleaseSIMARM64': {
|
||||
'inherit_from': [
|
||||
'Dart_Base', 'Dart_simarm64_Base', 'Dart_Release',
|
||||
'Dart_<(dart_target_os)_Base',
|
||||
'Dart_<(dart_target_os)_simarm64_Base',
|
||||
'Dart_<(dart_target_os)_Release',
|
||||
],
|
||||
},
|
||||
|
||||
'DebugSIMMIPS': {
|
||||
'inherit_from': [
|
||||
'Dart_Base', 'Dart_simmips_Base', 'Dart_Debug',
|
||||
|
|
|
@ -49,6 +49,15 @@
|
|||
],
|
||||
},
|
||||
|
||||
'Dart_Linux_simarm64_Base': {
|
||||
'abstract': 1,
|
||||
'cflags': [ '-O3', '-m64', '-msse2' ],
|
||||
'ldflags': [ '-m64', ],
|
||||
'defines': [
|
||||
'ARM64_FLOAT_ABI_HARD',
|
||||
],
|
||||
},
|
||||
|
||||
# ARM cross-build
|
||||
'Dart_Linux_xarm_Base': {
|
||||
'abstract': 1,
|
||||
|
|
|
@ -107,7 +107,8 @@ class TestOptionsParser {
|
|||
'arch',
|
||||
'The architecture to run tests for',
|
||||
['-a', '--arch'],
|
||||
['all', 'ia32', 'x64', 'simarm', 'simmips', 'arm', 'mips'],
|
||||
['all', 'ia32', 'x64', 'arm', 'mips',
|
||||
'simarm', 'simarm64', 'simmips'],
|
||||
'ia32'),
|
||||
new _TestOptionSpecification(
|
||||
'system',
|
||||
|
@ -634,7 +635,7 @@ Note: currently only implemented for dart2js.''',
|
|||
List<Map> _expandConfigurations(Map configuration) {
|
||||
// Expand the pseudo-values such as 'all'.
|
||||
if (configuration['arch'] == 'all') {
|
||||
configuration['arch'] = 'ia32,x64,simarm,simmips';
|
||||
configuration['arch'] = 'ia32,x64,simarm,simarm64,simmips';
|
||||
}
|
||||
if (configuration['mode'] == 'all') {
|
||||
configuration['mode'] = 'debug,release';
|
||||
|
|
|
@ -220,6 +220,7 @@ ARCH_FAMILY = {
|
|||
'mips': 'mips',
|
||||
'simarm': 'ia32',
|
||||
'simmips': 'ia32',
|
||||
'simarm64': 'ia32',
|
||||
}
|
||||
|
||||
ARCH_GUESS = GuessArchitecture()
|
||||
|
|
|
@ -14,6 +14,9 @@ peg_test: Skip
|
|||
[ $arch == simarm ]
|
||||
*: Skip
|
||||
|
||||
[ $arch == simarm64 ]
|
||||
*: Skip
|
||||
|
||||
[ $arch == mips ]
|
||||
*: Skip
|
||||
|
||||
|
|
Loading…
Reference in a new issue