Commit 4d189594 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Avoid a call to the runtime system when doing binary fp ops on ARM

(at the moment only if we do not need to allocate a heap number).
Find a few more oportunities to avoid heap number allocation on IA32.
Add some infrastructure to test coverage of generated ARM code in our
tests.
Review URL: http://codereview.chromium.org/67163

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1720 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b92740bf
...@@ -582,4 +582,40 @@ ExternalReference ExternalReference::debug_step_in_fp_address() { ...@@ -582,4 +582,40 @@ ExternalReference ExternalReference::debug_step_in_fp_address() {
return ExternalReference(Debug::step_in_fp_addr()); return ExternalReference(Debug::step_in_fp_addr());
} }
static double add_two_doubles(double x, double y) {
return x + y;
}
static double sub_two_doubles(double x, double y) {
return x - y;
}
static double mul_two_doubles(double x, double y) {
return x * y;
}
ExternalReference ExternalReference::double_fp_operation(
Token::Value operation) {
typedef double BinaryFPOperation(double x, double y);
BinaryFPOperation* function = NULL;
switch (operation) {
case Token::ADD:
function = &add_two_doubles;
break;
case Token::SUB:
function = &sub_two_doubles;
break;
case Token::MUL:
function = &mul_two_doubles;
break;
default:
UNREACHABLE();
}
return ExternalReference(FUNCTION_ADDR(function));
}
} } // namespace v8::internal } } // namespace v8::internal
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "runtime.h" #include "runtime.h"
#include "top.h" #include "top.h"
#include "zone-inl.h" #include "zone-inl.h"
#include "token.h"
namespace v8 { namespace internal { namespace v8 { namespace internal {
...@@ -417,6 +418,8 @@ class ExternalReference BASE_EMBEDDED { ...@@ -417,6 +418,8 @@ class ExternalReference BASE_EMBEDDED {
// Used to check if single stepping is enabled in generated code. // Used to check if single stepping is enabled in generated code.
static ExternalReference debug_step_in_fp_address(); static ExternalReference debug_step_in_fp_address();
static ExternalReference double_fp_operation(Token::Value operation);
Address address() const {return address_;} Address address() const {return address_;}
private: private:
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
namespace v8 { namespace internal { namespace v8 { namespace internal {
#define __ masm-> #define __ DEFINE_MASM(masm)
void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) { void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
...@@ -218,8 +218,9 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, ...@@ -218,8 +218,9 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ mov(r5, Operand(r4)); __ mov(r5, Operand(r4));
__ mov(r6, Operand(r4)); __ mov(r6, Operand(r4));
__ mov(r7, Operand(r4)); __ mov(r7, Operand(r4));
if (kR9Available == 1) if (kR9Available == 1) {
__ mov(r9, Operand(r4)); __ mov(r9, Operand(r4));
}
// Invoke the code and pass argc as r0. // Invoke the code and pass argc as r0.
__ mov(r0, Operand(r3)); __ mov(r0, Operand(r3));
......
This diff is collapsed.
...@@ -35,9 +35,6 @@ class DeferredCode; ...@@ -35,9 +35,6 @@ class DeferredCode;
class RegisterAllocator; class RegisterAllocator;
class RegisterFile; class RegisterFile;
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
enum InitState { CONST_INIT, NOT_CONST_INIT }; enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
...@@ -292,10 +289,13 @@ class CodeGenerator: public AstVisitor { ...@@ -292,10 +289,13 @@ class CodeGenerator: public AstVisitor {
void ToBoolean(JumpTarget* true_target, JumpTarget* false_target); void ToBoolean(JumpTarget* true_target, JumpTarget* false_target);
void GenericBinaryOperation(Token::Value op); void GenericBinaryOperation(Token::Value op, OverwriteMode overwrite_mode);
void Comparison(Condition cc, bool strict = false); void Comparison(Condition cc, bool strict = false);
void SmiOperation(Token::Value op, Handle<Object> value, bool reversed); void SmiOperation(Token::Value op,
Handle<Object> value,
bool reversed,
OverwriteMode mode);
void CallWithArguments(ZoneList<Expression*>* arguments, int position); void CallWithArguments(ZoneList<Expression*>* arguments, int position);
......
...@@ -3933,6 +3933,9 @@ void CodeGenerator::VisitAssignment(Assignment* node) { ...@@ -3933,6 +3933,9 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
} else { } else {
Literal* literal = node->value()->AsLiteral(); Literal* literal = node->value()->AsLiteral();
bool overwrite_value =
(node->value()->AsBinaryOperation() != NULL &&
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); Variable* right_var = node->value()->AsVariableProxy()->AsVariable();
// There are two cases where the target is not read in the right hand // There are two cases where the target is not read in the right hand
// side, that are easy to test for: the right hand side is a literal, // side, that are easy to test for: the right hand side is a literal,
...@@ -3945,7 +3948,9 @@ void CodeGenerator::VisitAssignment(Assignment* node) { ...@@ -3945,7 +3948,9 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
target.GetValue(NOT_INSIDE_TYPEOF); target.GetValue(NOT_INSIDE_TYPEOF);
} }
Load(node->value()); Load(node->value());
GenericBinaryOperation(node->binary_op(), node->type()); GenericBinaryOperation(node->binary_op(),
node->type(),
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
} }
if (var != NULL && if (var != NULL &&
......
...@@ -35,9 +35,6 @@ class DeferredCode; ...@@ -35,9 +35,6 @@ class DeferredCode;
class RegisterAllocator; class RegisterAllocator;
class RegisterFile; class RegisterFile;
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
enum InitState { CONST_INIT, NOT_CONST_INIT }; enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
...@@ -435,7 +432,7 @@ class CodeGenerator: public AstVisitor { ...@@ -435,7 +432,7 @@ class CodeGenerator: public AstVisitor {
void GenericBinaryOperation( void GenericBinaryOperation(
Token::Value op, Token::Value op,
SmiAnalysis* type, SmiAnalysis* type,
const OverwriteMode overwrite_mode = NO_OVERWRITE); OverwriteMode overwrite_mode);
// If possible, combine two constant smi values using op to produce // If possible, combine two constant smi values using op to produce
// a smi result, and push it on the virtual frame, all at compile time. // a smi result, and push it on the virtual frame, all at compile time.
......
...@@ -71,6 +71,11 @@ ...@@ -71,6 +71,11 @@
// CodeForStatementPosition // CodeForStatementPosition
// CodeForSourcePosition // CodeForSourcePosition
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
#ifdef ARM #ifdef ARM
#include "codegen-arm.h" #include "codegen-arm.h"
#else #else
......
...@@ -106,7 +106,12 @@ enum SoftwareInterruptCodes { ...@@ -106,7 +106,12 @@ enum SoftwareInterruptCodes {
call_rt_r5 = 0x10, call_rt_r5 = 0x10,
call_rt_r2 = 0x11, call_rt_r2 = 0x11,
// break point // break point
break_point = 0x20 break_point = 0x20,
// FP operations. These simulate calling into C for a moment to do fp ops.
// They should trash all caller-save registers.
simulator_fp_add = 0x21,
simulator_fp_sub = 0x22,
simulator_fp_mul = 0x23
}; };
......
...@@ -58,7 +58,7 @@ bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) { ...@@ -58,7 +58,7 @@ bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
} }
#define __ masm-> #define __ DEFINE_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm, static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
......
...@@ -261,6 +261,15 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) { ...@@ -261,6 +261,15 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) {
case break_point: case break_point:
Print("break_point"); Print("break_point");
return; return;
case simulator_fp_add:
Print("simulator_fp_add");
return;
case simulator_fp_mul:
Print("simulator_fp_mul");
return;
case simulator_fp_sub:
Print("simulator_fp_sub");
return;
default: default:
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"%d", "%d",
......
...@@ -514,6 +514,16 @@ inline Dest bit_cast(const Source& source) { ...@@ -514,6 +514,16 @@ inline Dest bit_cast(const Source& source) {
} }
#ifdef ARM_GENERATED_CODE_COVERAGE
#define CODE_COVERAGE_STRINGIFY(x) #x
#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
#define DEFINE_MASM(masm) masm->stop(__FILE_LINE__); masm->
#else
#define DEFINE_MASM(masm) masm->
#endif
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_GLOBALS_H_ #endif // V8_GLOBALS_H_
...@@ -39,7 +39,7 @@ namespace v8 { namespace internal { ...@@ -39,7 +39,7 @@ namespace v8 { namespace internal {
// Static IC stub generators. // Static IC stub generators.
// //
#define __ masm-> #define __ DEFINE_MASM(masm)
// Helper function used from LoadIC/CallIC GenerateNormal. // Helper function used from LoadIC/CallIC GenerateNormal.
...@@ -96,7 +96,9 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, ...@@ -96,7 +96,9 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
// Compute the masked index: (hash + i + i * i) & mask. // Compute the masked index: (hash + i + i * i) & mask.
__ ldr(t1, FieldMemOperand(r2, String::kLengthOffset)); __ ldr(t1, FieldMemOperand(r2, String::kLengthOffset));
__ mov(t1, Operand(t1, LSR, String::kHashShift)); __ mov(t1, Operand(t1, LSR, String::kHashShift));
if (i > 0) __ add(t1, t1, Operand(Dictionary::GetProbeOffset(i))); if (i > 0) {
__ add(t1, t1, Operand(Dictionary::GetProbeOffset(i)));
}
__ and_(t1, t1, Operand(r3)); __ and_(t1, t1, Operand(r3));
// Scale the index by multiplying by the element size. // Scale the index by multiplying by the element size.
......
...@@ -168,11 +168,11 @@ void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode, ...@@ -168,11 +168,11 @@ void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
} }
void MacroAssembler::Ret() { void MacroAssembler::Ret(Condition cond) {
#if USE_BX #if USE_BX
bx(lr); bx(lr, cond);
#else #else
mov(pc, Operand(lr)); mov(pc, Operand(lr), LeaveCC, cond);
#endif #endif
} }
......
...@@ -86,7 +86,7 @@ class MacroAssembler: public Assembler { ...@@ -86,7 +86,7 @@ class MacroAssembler: public Assembler {
void Call(Register target, Condition cond = al); void Call(Register target, Condition cond = al);
void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al); void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al); void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
void Ret(); void Ret(Condition cond = al);
// Jumps to the label at the index given by the Smi in "index". // Jumps to the label at the index given by the Smi in "index".
void SmiJumpTable(Register index, Vector<Label*> targets); void SmiJumpTable(Register index, Vector<Label*> targets);
......
...@@ -3482,6 +3482,7 @@ static Object* Runtime_NumberToSmi(Arguments args) { ...@@ -3482,6 +3482,7 @@ static Object* Runtime_NumberToSmi(Arguments args) {
return Heap::nan_value(); return Heap::nan_value();
} }
static Object* Runtime_NumberAdd(Arguments args) { static Object* Runtime_NumberAdd(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
......
...@@ -683,6 +683,18 @@ void ExternalReferenceTable::PopulateTable() { ...@@ -683,6 +683,18 @@ void ExternalReferenceTable::PopulateTable() {
UNCLASSIFIED, UNCLASSIFIED,
10, 10,
"Debug::step_in_fp_addr()"); "Debug::step_in_fp_addr()");
Add(ExternalReference::double_fp_operation(Token::ADD).address(),
UNCLASSIFIED,
11,
"add_two_doubles");
Add(ExternalReference::double_fp_operation(Token::SUB).address(),
UNCLASSIFIED,
12,
"sub_two_doubles");
Add(ExternalReference::double_fp_operation(Token::MUL).address(),
UNCLASSIFIED,
13,
"mul_two_doubles");
} }
......
...@@ -90,12 +90,44 @@ Debugger::~Debugger() { ...@@ -90,12 +90,44 @@ Debugger::~Debugger() {
} }
#ifdef ARM_GENERATED_CODE_COVERAGE
static FILE* coverage_log = NULL;
static void InitializeCoverage() {
char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
if (file_name != NULL) {
coverage_log = fopen(file_name, "aw+");
}
}
void Debugger::Stop(Instr* instr) {
char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff);
if (strlen(str) > 0) {
if (coverage_log != NULL) {
fprintf(coverage_log, "Simulator hit %s\n", str);
fflush(coverage_log);
}
instr->SetInstructionBits(0xe1a00000); // Overwrite with nop.
}
sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
}
#else // ndef ARM_GENERATED_CODE_COVERAGE
static void InitializeCoverage() {
}
void Debugger::Stop(Instr* instr) { void Debugger::Stop(Instr* instr) {
const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff); const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff);
PrintF("Simulator hit %s\n", str); PrintF("Simulator hit %s\n", str);
sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
Debug(); Debug();
} }
#endif
static const char* reg_names[] = { "r0", "r1", "r2", "r3", static const char* reg_names[] = { "r0", "r1", "r2", "r3",
...@@ -375,6 +407,7 @@ Simulator::Simulator() { ...@@ -375,6 +407,7 @@ Simulator::Simulator() {
// access violation if the simulator ever tries to execute it. // access violation if the simulator ever tries to execute it.
registers_[pc] = bad_lr; registers_[pc] = bad_lr;
registers_[lr] = bad_lr; registers_[lr] = bad_lr;
InitializeCoverage();
} }
...@@ -427,6 +460,37 @@ int32_t Simulator::get_pc() const { ...@@ -427,6 +460,37 @@ int32_t Simulator::get_pc() const {
} }
// For use in calls that take two double values, constructed from r0, r1, r2
// and r3.
void Simulator::GetFpArgs(double* x, double* y) {
// We use a char buffer to get around the strict-aliasing rules which
// otherwise allow the compiler to optimize away the copy.
char buffer[2 * sizeof(registers_[0])];
// Registers 0 and 1 -> x.
memcpy(buffer, registers_, sizeof(buffer));
memcpy(x, buffer, sizeof(buffer));
// Registers 2 and 3 -> y.
memcpy(buffer, registers_ + 2, sizeof(buffer));
memcpy(y, buffer, sizeof(buffer));
}
void Simulator::SetFpResult(const double& result) {
char buffer[2 * sizeof(registers_[0])];
memcpy(buffer, &result, sizeof(buffer));
// result -> registers 0 and 1.
memcpy(registers_, buffer, sizeof(buffer));
}
void Simulator::TrashCallerSaveRegisters() {
// We don't trash the registers with the return value.
registers_[2] = 0x50Bad4U;
registers_[3] = 0x50Bad4U;
registers_[12] = 0x50Bad4U;
}
// The ARM cannot do unaligned reads and writes. On some ARM platforms an // The ARM cannot do unaligned reads and writes. On some ARM platforms an
// interrupt is caused. On others it does a funky rotation thing. For now we // interrupt is caused. On others it does a funky rotation thing. For now we
// simply disallow unaligned reads, but at some point we may want to move to // simply disallow unaligned reads, but at some point we may want to move to
...@@ -862,7 +926,8 @@ typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1); ...@@ -862,7 +926,8 @@ typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1);
// Software interrupt instructions are used by the simulator to call into the // Software interrupt instructions are used by the simulator to call into the
// C-based V8 runtime. // C-based V8 runtime.
void Simulator::SoftwareInterrupt(Instr* instr) { void Simulator::SoftwareInterrupt(Instr* instr) {
switch (instr->SwiField()) { int swi = instr->SwiField();
switch (swi) {
case call_rt_r5: { case call_rt_r5: {
SimulatorRuntimeCall target = SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(get_register(r5)); reinterpret_cast<SimulatorRuntimeCall>(get_register(r5));
...@@ -894,6 +959,30 @@ void Simulator::SoftwareInterrupt(Instr* instr) { ...@@ -894,6 +959,30 @@ void Simulator::SoftwareInterrupt(Instr* instr) {
dbg.Debug(); dbg.Debug();
break; break;
} }
{
double x, y, z;
case simulator_fp_add:
GetFpArgs(&x, &y);
z = x + y;
SetFpResult(z);
TrashCallerSaveRegisters();
set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
break;
case simulator_fp_sub:
GetFpArgs(&x, &y);
z = x - y;
SetFpResult(z);
TrashCallerSaveRegisters();
set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
break;
case simulator_fp_mul:
GetFpArgs(&x, &y);
z = x * y;
SetFpResult(z);
TrashCallerSaveRegisters();
set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
break;
}
default: { default: {
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -174,6 +174,12 @@ class Simulator { ...@@ -174,6 +174,12 @@ class Simulator {
// Executes one instruction. // Executes one instruction.
void InstructionDecode(Instr* instr); void InstructionDecode(Instr* instr);
// For use in calls that take two double values, constructed from r0, r1, r2
// and r3.
void GetFpArgs(double* x, double* y);
void SetFpResult(const double& result);
void TrashCallerSaveRegisters();
// architecture state // architecture state
int32_t registers_[16]; int32_t registers_[16];
bool n_flag_; bool n_flag_;
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
namespace v8 { namespace internal { namespace v8 { namespace internal {
#define __ masm-> #define __ DEFINE_MASM(masm)
static void ProbeTable(MacroAssembler* masm, static void ProbeTable(MacroAssembler* masm,
...@@ -183,7 +183,7 @@ void StubCompiler::GenerateLoadField(MacroAssembler* masm, ...@@ -183,7 +183,7 @@ void StubCompiler::GenerateLoadField(MacroAssembler* masm,
// Check that the maps haven't changed. // Check that the maps haven't changed.
Register reg = Register reg =
__ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
GenerateFastPropertyLoad(masm, r0, reg, holder, index); GenerateFastPropertyLoad(masm, r0, reg, holder, index);
__ Ret(); __ Ret();
} }
...@@ -203,7 +203,7 @@ void StubCompiler::GenerateLoadConstant(MacroAssembler* masm, ...@@ -203,7 +203,7 @@ void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
// Check that the maps haven't changed. // Check that the maps haven't changed.
Register reg = Register reg =
__ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Return the constant value. // Return the constant value.
__ mov(r0, Operand(Handle<Object>(value))); __ mov(r0, Operand(Handle<Object>(value)));
...@@ -226,7 +226,7 @@ void StubCompiler::GenerateLoadCallback(MacroAssembler* masm, ...@@ -226,7 +226,7 @@ void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
// Check that the maps haven't changed. // Check that the maps haven't changed.
Register reg = Register reg =
__ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller. // Push the arguments on the JS stack of the caller.
__ push(receiver); // receiver __ push(receiver); // receiver
...@@ -256,7 +256,7 @@ void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm, ...@@ -256,7 +256,7 @@ void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
// Check that the maps haven't changed. // Check that the maps haven't changed.
Register reg = Register reg =
__ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller. // Push the arguments on the JS stack of the caller.
__ push(receiver); // receiver __ push(receiver); // receiver
...@@ -456,8 +456,7 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { ...@@ -456,8 +456,7 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
#undef __ #undef __
#define __ DEFINE_MASM(masm())
#define __ masm()->
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
...@@ -511,7 +510,7 @@ Object* CallStubCompiler::CompileCallField(Object* object, ...@@ -511,7 +510,7 @@ Object* CallStubCompiler::CompileCallField(Object* object,
// Do the right check and compute the holder register. // Do the right check and compute the holder register.
Register reg = Register reg =
__ CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss); masm()->CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
GenerateFastPropertyLoad(masm(), r1, reg, holder, index); GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
// Check that the function really is a function. // Check that the function really is a function.
......
...@@ -36,7 +36,8 @@ namespace v8 { namespace internal { ...@@ -36,7 +36,8 @@ namespace v8 { namespace internal {
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// VirtualFrame implementation. // VirtualFrame implementation.
#define __ masm_-> #define __ DEFINE_MASM(masm_)
// On entry to a function, the virtual frame already contains the // On entry to a function, the virtual frame already contains the
// receiver and the parameters. All initial frame elements are in // receiver and the parameters. All initial frame elements are in
......
...@@ -30,9 +30,9 @@ const SMI_MIN = -(1 << 30); ...@@ -30,9 +30,9 @@ const SMI_MIN = -(1 << 30);
function testmulneg(a, b) { function testmulneg(a, b) {
var base = a * b; var base = a * b;
assertEquals(-base, a * -b); assertEquals(-base, a * -b, "a * -b where a = " + a + ", b = " + b);
assertEquals(-base, -a * b); assertEquals(-base, -a * b, "-a * b where a = " + a + ", b = " + b);
assertEquals(base, -a * -b); assertEquals(base, -a * -b, "*-a * -b where a = " + a + ", b = " + b);
} }
testmulneg(2, 3); testmulneg(2, 3);
......
...@@ -33,10 +33,14 @@ function testLimits() { ...@@ -33,10 +33,14 @@ function testLimits() {
var addAboveMax = Number.MAX_VALUE + 1/eps; var addAboveMax = Number.MAX_VALUE + 1/eps;
var mulBelowMin = Number.MIN_VALUE * (1 - eps); var mulBelowMin = Number.MIN_VALUE * (1 - eps);
var addBelowMin = Number.MIN_VALUE - eps; var addBelowMin = Number.MIN_VALUE - eps;
assertTrue(mulAboveMax == Number.MAX_VALUE || mulAboveMax == Infinity); assertTrue(mulAboveMax == Number.MAX_VALUE ||
assertTrue(addAboveMax == Number.MAX_VALUE || addAboveMax == Infinity); mulAboveMax == Infinity, "mul" + i);
assertTrue(mulBelowMin == Number.MIN_VALUE || mulBelowMin <= 0); assertTrue(addAboveMax == Number.MAX_VALUE ||
assertTrue(addBelowMin == Number.MIN_VALUE || addBelowMin <= 0); addAboveMax == Infinity, "add" + i);
assertTrue(mulBelowMin == Number.MIN_VALUE ||
mulBelowMin <= 0, "mul2" + i);
assertTrue(addBelowMin == Number.MIN_VALUE ||
addBelowMin <= 0, "add2" + i);
} }
} }
......
...@@ -100,3 +100,98 @@ assertEquals(SMI_MIN - ONE_HUNDRED, Sub100(SMI_MIN)); // overflow ...@@ -100,3 +100,98 @@ assertEquals(SMI_MIN - ONE_HUNDRED, Sub100(SMI_MIN)); // overflow
assertEquals(ONE_HUNDRED - SMI_MIN, Sub100Reversed(SMI_MIN)); // overflow assertEquals(ONE_HUNDRED - SMI_MIN, Sub100Reversed(SMI_MIN)); // overflow
assertEquals(42 - ONE_HUNDRED, Sub100(OBJ_42)); // non-smi assertEquals(42 - ONE_HUNDRED, Sub100(OBJ_42)); // non-smi
assertEquals(ONE_HUNDRED - 42, Sub100Reversed(OBJ_42)); // non-smi assertEquals(ONE_HUNDRED - 42, Sub100Reversed(OBJ_42)); // non-smi
function Shr1(x) {
return x >>> 1;
}
function Shr100(x) {
return x >>> 100;
}
function Shr1Reversed(x) {
return 1 >>> x;
}
function Shr100Reversed(x) {
return 100 >>> x;
}
function Sar1(x) {
return x >> 1;
}
function Sar100(x) {
return x >> 100;
}
function Sar1Reversed(x) {
return 1 >> x;
}
function Sar100Reversed(x) {
return 100 >> x;
}
assertEquals(0, Shr1(1));
assertEquals(0, Sar1(1));
assertEquals(0, Shr1Reversed(2));
assertEquals(0, Sar1Reversed(2));
assertEquals(1610612736, Shr1(SMI_MIN));
assertEquals(-536870912, Sar1(SMI_MIN));
assertEquals(1, Shr1Reversed(SMI_MIN));
assertEquals(1, Sar1Reversed(SMI_MIN));
assertEquals(21, Shr1(OBJ_42));
assertEquals(21, Sar1(OBJ_42));
assertEquals(0, Shr1Reversed(OBJ_42));
assertEquals(0, Sar1Reversed(OBJ_42));
assertEquals(6, Shr100(100));
assertEquals(6, Sar100(100));
assertEquals(12, Shr100Reversed(99));
assertEquals(12, Sar100Reversed(99));
assertEquals(201326592, Shr100(SMI_MIN));
assertEquals(-67108864, Sar100(SMI_MIN));
assertEquals(100, Shr100Reversed(SMI_MIN));
assertEquals(100, Sar100Reversed(SMI_MIN));
assertEquals(2, Shr100(OBJ_42));
assertEquals(2, Sar100(OBJ_42));
assertEquals(0, Shr100Reversed(OBJ_42));
assertEquals(0, Sar100Reversed(OBJ_42));
function Xor1(x) {
return x ^ 1;
}
function Xor100(x) {
return x ^ 100;
}
function Xor1Reversed(x) {
return 1 ^ x;
}
function Xor100Reversed(x) {
return 100 ^ x;
}
assertEquals(0, Xor1(1));
assertEquals(3, Xor1Reversed(2));
assertEquals(SMI_MIN + 1, Xor1(SMI_MIN));
assertEquals(SMI_MIN + 1, Xor1Reversed(SMI_MIN));
assertEquals(43, Xor1(OBJ_42));
assertEquals(43, Xor1Reversed(OBJ_42));
assertEquals(0, Xor100(100));
assertEquals(7, Xor100Reversed(99));
assertEquals(-1073741724, Xor100(SMI_MIN));
assertEquals(-1073741724, Xor100Reversed(SMI_MIN));
assertEquals(78, Xor100(OBJ_42));
assertEquals(78, Xor100Reversed(OBJ_42));
var x = 0x23; var y = 0x35;
assertEquals(0x16, x ^ y);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment