First part of lithium ARM port.
Implement LoadNamedField, CallConstantFunction, CmpMapAndBranch, JSArrayLength, BoundsCheck, IsNull, CallFunction, and CallStub in the ARM lithium codegenerator. BUG= TEST= Review URL: http://codereview.chromium.org/6069010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6155 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e7ecb74b8a
commit
20c858d514
@ -1292,12 +1292,8 @@ LInstruction* LChunkBuilder::DoCompareMapAndBranch(
|
|||||||
HCompareMapAndBranch* instr) {
|
HCompareMapAndBranch* instr) {
|
||||||
ASSERT(instr->value()->representation().IsTagged());
|
ASSERT(instr->value()->representation().IsTagged());
|
||||||
LOperand* value = UseRegisterAtStart(instr->value());
|
LOperand* value = UseRegisterAtStart(instr->value());
|
||||||
HBasicBlock* first = instr->FirstSuccessor();
|
LOperand* temp = TempRegister();
|
||||||
HBasicBlock* second = instr->SecondSuccessor();
|
return new LCmpMapAndBranch(value, temp);
|
||||||
return new LCmpMapAndBranch(value,
|
|
||||||
instr->map(),
|
|
||||||
first->block_id(),
|
|
||||||
second->block_id());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1367,6 +1363,9 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
|
|||||||
return AssignEnvironment(DefineAsRegister(result));
|
return AssignEnvironment(DefineAsRegister(result));
|
||||||
case kMathSqrt:
|
case kMathSqrt:
|
||||||
return DefineSameAsFirst(result);
|
return DefineSameAsFirst(result);
|
||||||
|
case kMathRound:
|
||||||
|
Abort("MathRound LUnaryMathOperation not implemented");
|
||||||
|
return NULL;
|
||||||
case kMathPowHalf:
|
case kMathPowHalf:
|
||||||
Abort("MathPowHalf LUnaryMathOperation not implemented");
|
Abort("MathPowHalf LUnaryMathOperation not implemented");
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1771,9 +1770,11 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
||||||
LOperand* temp = TempRegister();
|
LOperand* temp1 = TempRegister();
|
||||||
|
LOperand* temp2 = TempRegister();
|
||||||
LInstruction* result =
|
LInstruction* result =
|
||||||
new LCheckPrototypeMaps(temp,
|
new LCheckPrototypeMaps(temp1,
|
||||||
|
temp2,
|
||||||
instr->holder(),
|
instr->holder(),
|
||||||
instr->receiver_map());
|
instr->receiver_map());
|
||||||
return AssignEnvironment(result);
|
return AssignEnvironment(result);
|
||||||
|
@ -1121,27 +1121,25 @@ class LBranch: public LUnaryOperation {
|
|||||||
|
|
||||||
class LCmpMapAndBranch: public LUnaryOperation {
|
class LCmpMapAndBranch: public LUnaryOperation {
|
||||||
public:
|
public:
|
||||||
LCmpMapAndBranch(LOperand* value,
|
LCmpMapAndBranch(LOperand* value, LOperand* temp)
|
||||||
Handle<Map> map,
|
: LUnaryOperation(value), temp_(temp) { }
|
||||||
int true_block_id,
|
|
||||||
int false_block_id)
|
|
||||||
: LUnaryOperation(value),
|
|
||||||
map_(map),
|
|
||||||
true_block_id_(true_block_id),
|
|
||||||
false_block_id_(false_block_id) { }
|
|
||||||
|
|
||||||
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
|
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(CompareMapAndBranch)
|
||||||
|
|
||||||
virtual bool IsControl() const { return true; }
|
virtual bool IsControl() const { return true; }
|
||||||
|
|
||||||
Handle<Map> map() const { return map_; }
|
LOperand* temp() const { return temp_; }
|
||||||
int true_block_id() const { return true_block_id_; }
|
Handle<Map> map() const { return hydrogen()->map(); }
|
||||||
int false_block_id() const { return false_block_id_; }
|
int true_block_id() const {
|
||||||
|
return hydrogen()->true_destination()->block_id();
|
||||||
|
}
|
||||||
|
int false_block_id() const {
|
||||||
|
return hydrogen()->false_destination()->block_id();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Handle<Map> map_;
|
LOperand* temp_;
|
||||||
int true_block_id_;
|
|
||||||
int false_block_id_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1678,21 +1676,25 @@ class LCheckMap: public LUnaryOperation {
|
|||||||
|
|
||||||
class LCheckPrototypeMaps: public LInstruction {
|
class LCheckPrototypeMaps: public LInstruction {
|
||||||
public:
|
public:
|
||||||
LCheckPrototypeMaps(LOperand* temp,
|
LCheckPrototypeMaps(LOperand* temp1,
|
||||||
|
LOperand* temp2,
|
||||||
Handle<JSObject> holder,
|
Handle<JSObject> holder,
|
||||||
Handle<Map> receiver_map)
|
Handle<Map> receiver_map)
|
||||||
: temp_(temp),
|
: temp1_(temp1),
|
||||||
|
temp2_(temp2),
|
||||||
holder_(holder),
|
holder_(holder),
|
||||||
receiver_map_(receiver_map) { }
|
receiver_map_(receiver_map) { }
|
||||||
|
|
||||||
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
|
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
|
||||||
|
|
||||||
LOperand* temp() const { return temp_; }
|
LOperand* temp1() const { return temp1_; }
|
||||||
|
LOperand* temp2() const { return temp2_; }
|
||||||
Handle<JSObject> holder() const { return holder_; }
|
Handle<JSObject> holder() const { return holder_; }
|
||||||
Handle<Map> receiver_map() const { return receiver_map_; }
|
Handle<Map> receiver_map() const { return receiver_map_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LOperand* temp_;
|
LOperand* temp1_;
|
||||||
|
LOperand* temp2_;
|
||||||
Handle<JSObject> holder_;
|
Handle<JSObject> holder_;
|
||||||
Handle<Map> receiver_map_;
|
Handle<Map> receiver_map_;
|
||||||
};
|
};
|
||||||
|
@ -730,7 +730,53 @@ void LCodeGen::DoParameter(LParameter* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCallStub(LCallStub* instr) {
|
void LCodeGen::DoCallStub(LCallStub* instr) {
|
||||||
Abort("DoCallStub unimplemented.");
|
ASSERT(ToRegister(instr->result()).is(r0));
|
||||||
|
switch (instr->hydrogen()->major_key()) {
|
||||||
|
case CodeStub::RegExpConstructResult: {
|
||||||
|
RegExpConstructResultStub stub;
|
||||||
|
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CodeStub::RegExpExec: {
|
||||||
|
RegExpExecStub stub;
|
||||||
|
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CodeStub::SubString: {
|
||||||
|
SubStringStub stub;
|
||||||
|
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CodeStub::StringCharAt: {
|
||||||
|
Abort("StringCharAtStub unimplemented.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CodeStub::MathPow: {
|
||||||
|
Abort("MathPowStub unimplemented.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CodeStub::NumberToString: {
|
||||||
|
NumberToStringStub stub;
|
||||||
|
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CodeStub::StringAdd: {
|
||||||
|
StringAddStub stub(NO_STRING_ADD_FLAGS);
|
||||||
|
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CodeStub::StringCompare: {
|
||||||
|
StringCompareStub stub;
|
||||||
|
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CodeStub::TranscendentalCache: {
|
||||||
|
Abort("TranscendentalCache unimplemented.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -902,7 +948,6 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
|
|||||||
Register result = ToRegister(instr->result());
|
Register result = ToRegister(instr->result());
|
||||||
Register array = ToRegister(instr->input());
|
Register array = ToRegister(instr->input());
|
||||||
__ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset));
|
__ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset));
|
||||||
Abort("DoJSArrayLength untested.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1171,7 +1216,36 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoIsNull(LIsNull* instr) {
|
void LCodeGen::DoIsNull(LIsNull* instr) {
|
||||||
Abort("DoIsNull unimplemented.");
|
Register reg = ToRegister(instr->input());
|
||||||
|
Register result = ToRegister(instr->result());
|
||||||
|
|
||||||
|
__ LoadRoot(ip, Heap::kNullValueRootIndex);
|
||||||
|
__ cmp(reg, ip);
|
||||||
|
if (instr->is_strict()) {
|
||||||
|
__ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
|
||||||
|
__ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
|
||||||
|
} else {
|
||||||
|
Label true_value, false_value, done;
|
||||||
|
__ b(eq, &true_value);
|
||||||
|
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ cmp(ip, reg);
|
||||||
|
__ b(eq, &true_value);
|
||||||
|
__ tst(reg, Operand(kSmiTagMask));
|
||||||
|
__ b(eq, &false_value);
|
||||||
|
// Check for undetectable objects by looking in the bit field in
|
||||||
|
// the map. The object has already been smi checked.
|
||||||
|
Register scratch = result;
|
||||||
|
__ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
|
||||||
|
__ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
|
||||||
|
__ tst(scratch, Operand(1 << Map::kIsUndetectable));
|
||||||
|
__ b(ne, &true_value);
|
||||||
|
__ bind(&false_value);
|
||||||
|
__ LoadRoot(result, Heap::kFalseValueRootIndex);
|
||||||
|
__ jmp(&done);
|
||||||
|
__ bind(&true_value);
|
||||||
|
__ LoadRoot(result, Heap::kTrueValueRootIndex);
|
||||||
|
__ bind(&done);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1327,7 +1401,14 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
|
void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
|
||||||
Abort("DoCmpMapAndBranch unimplemented.");
|
Register reg = ToRegister(instr->input());
|
||||||
|
Register temp = ToRegister(instr->temp());
|
||||||
|
int true_block = instr->true_block_id();
|
||||||
|
int false_block = instr->false_block_id();
|
||||||
|
|
||||||
|
__ ldr(temp, FieldMemOperand(reg, HeapObject::kMapOffset));
|
||||||
|
__ cmp(temp, Operand(instr->map()));
|
||||||
|
EmitBranch(true_block, false_block, eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1429,7 +1510,14 @@ void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
||||||
Abort("DoLoadNamedField unimplemented.");
|
Register object = ToRegister(instr->input());
|
||||||
|
Register result = ToRegister(instr->result());
|
||||||
|
if (instr->hydrogen()->is_in_object()) {
|
||||||
|
__ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset()));
|
||||||
|
} else {
|
||||||
|
__ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
|
||||||
|
__ ldr(result, FieldMemOperand(result, instr->hydrogen()->offset()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1585,7 +1673,9 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
|
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
|
||||||
Abort("DoCallConstantFunction unimplemented.");
|
ASSERT(ToRegister(instr->result()).is(r0));
|
||||||
|
__ mov(r1, Operand(instr->function()));
|
||||||
|
CallKnownFunction(instr->function(), instr->arity(), instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1645,7 +1735,13 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCallFunction(LCallFunction* instr) {
|
void LCodeGen::DoCallFunction(LCallFunction* instr) {
|
||||||
Abort("DoCallFunction unimplemented.");
|
ASSERT(ToRegister(instr->result()).is(r0));
|
||||||
|
|
||||||
|
int arity = instr->arity();
|
||||||
|
CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
|
||||||
|
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||||
|
__ Drop(1);
|
||||||
|
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1693,7 +1789,8 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
|
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
|
||||||
Abort("DoBoundsCheck unimplemented.");
|
__ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
|
||||||
|
DeoptimizeIf(hs, instr->environment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2037,12 +2134,42 @@ void LCodeGen::DoCheckMap(LCheckMap* instr) {
|
|||||||
|
|
||||||
void LCodeGen::LoadPrototype(Register result,
|
void LCodeGen::LoadPrototype(Register result,
|
||||||
Handle<JSObject> prototype) {
|
Handle<JSObject> prototype) {
|
||||||
Abort("LoadPrototype unimplemented.");
|
if (Heap::InNewSpace(*prototype)) {
|
||||||
|
Handle<JSGlobalPropertyCell> cell =
|
||||||
|
Factory::NewJSGlobalPropertyCell(prototype);
|
||||||
|
__ mov(result, Operand(cell));
|
||||||
|
} else {
|
||||||
|
__ mov(result, Operand(prototype));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
||||||
Abort("DoCheckPrototypeMaps unimplemented.");
|
Register temp1 = ToRegister(instr->temp1());
|
||||||
|
Register temp2 = ToRegister(instr->temp2());
|
||||||
|
|
||||||
|
Handle<JSObject> holder = instr->holder();
|
||||||
|
Handle<Map> receiver_map = instr->receiver_map();
|
||||||
|
Handle<JSObject> current_prototype(JSObject::cast(receiver_map->prototype()));
|
||||||
|
|
||||||
|
// Load prototype object.
|
||||||
|
LoadPrototype(temp1, current_prototype);
|
||||||
|
|
||||||
|
// Check prototype maps up to the holder.
|
||||||
|
while (!current_prototype.is_identical_to(holder)) {
|
||||||
|
__ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
|
||||||
|
__ cmp(temp2, Operand(Handle<Map>(current_prototype->map())));
|
||||||
|
DeoptimizeIf(ne, instr->environment());
|
||||||
|
current_prototype =
|
||||||
|
Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
|
||||||
|
// Load next prototype object.
|
||||||
|
LoadPrototype(temp1, current_prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the holder map.
|
||||||
|
__ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
|
||||||
|
__ cmp(temp2, Operand(Handle<Map>(current_prototype->map())));
|
||||||
|
DeoptimizeIf(ne, instr->environment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -910,6 +910,9 @@ class HCompareMapAndBranch: public HUnaryControlInstruction {
|
|||||||
virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
|
virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
|
||||||
virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
|
virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
|
||||||
|
|
||||||
|
HBasicBlock* true_destination() const { return true_destination_; }
|
||||||
|
HBasicBlock* false_destination() const { return false_destination_; }
|
||||||
|
|
||||||
virtual void PrintDataTo(StringStream* stream) const;
|
virtual void PrintDataTo(StringStream* stream) const;
|
||||||
|
|
||||||
Handle<Map> map() const { return map_; }
|
Handle<Map> map() const { return map_; }
|
||||||
|
Loading…
Reference in New Issue
Block a user