Desugar bitwise negation into XOR and kill all UnaryOp stuff.
R=mstarzinger@chromium.org, verwaest@chromium.org Review URL: https://codereview.chromium.org/22184004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16073 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
45f4b685bf
commit
bc6fe88030
@ -246,17 +246,6 @@ void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void UnaryOpStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { r0 };
|
||||
descriptor->register_param_count_ = 1;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ =
|
||||
FUNCTION_ADDR(UnaryOpIC_Miss);
|
||||
}
|
||||
|
||||
|
||||
void StoreGlobalStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
|
@ -4349,32 +4349,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::BIT_NOT:
|
||||
EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
|
||||
const char* comment) {
|
||||
ASSERT_EQ(Token::BIT_NOT, expr->op());
|
||||
// TODO(svenpanne): Allowing format strings in Comment would be nice here...
|
||||
Comment cmt(masm_, comment);
|
||||
UnaryOpStub stub(expr->op());
|
||||
// UnaryOpStub expects the argument to be in the
|
||||
// accumulator register r0.
|
||||
VisitForAccumulatorValue(expr->expression());
|
||||
SetSourcePosition(expr->position());
|
||||
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
|
||||
expr->UnaryOperationFeedbackId());
|
||||
context()->Plug(r0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
Comment cmnt(masm_, "[ CountOperation");
|
||||
SetSourcePosition(expr->position());
|
||||
|
@ -1325,15 +1325,6 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
|
||||
ASSERT(instr->value()->representation().IsInteger32());
|
||||
ASSERT(instr->representation().IsInteger32());
|
||||
if (instr->HasNoUses()) return NULL;
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
return DefineAsRegister(new(zone()) LBitNotI(value));
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
|
||||
if (instr->representation().IsDouble()) {
|
||||
return DoArithmeticD(Token::DIV, instr);
|
||||
|
@ -50,7 +50,6 @@ class LCodeGen;
|
||||
V(ArithmeticD) \
|
||||
V(ArithmeticT) \
|
||||
V(BitI) \
|
||||
V(BitNotI) \
|
||||
V(BoundsCheck) \
|
||||
V(Branch) \
|
||||
V(CallConstantFunction) \
|
||||
@ -1377,18 +1376,6 @@ class LThrow: public LTemplateInstruction<0, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LBitNotI: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LBitNotI(LOperand* value) {
|
||||
inputs_[0] = value;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i")
|
||||
};
|
||||
|
||||
|
||||
class LAddI: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LAddI(LOperand* left, LOperand* right) {
|
||||
|
@ -1669,7 +1669,11 @@ void LCodeGen::DoBitI(LBitI* instr) {
|
||||
__ orr(result, left, right);
|
||||
break;
|
||||
case Token::BIT_XOR:
|
||||
__ eor(result, left, right);
|
||||
if (right_op->IsConstantOperand() && right.immediate() == int32_t(~0)) {
|
||||
__ mvn(result, Operand(left));
|
||||
} else {
|
||||
__ eor(result, left, right);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -1953,13 +1957,6 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoBitNotI(LBitNotI* instr) {
|
||||
Register input = ToRegister(instr->value());
|
||||
Register result = ToRegister(instr->result());
|
||||
__ mvn(result, Operand(input));
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoThrow(LThrow* instr) {
|
||||
Register input_reg = EmitLoadRegister(instr->value(), ip);
|
||||
__ push(input_reg);
|
||||
|
@ -115,7 +115,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
DwVfpRegister EmitLoadDoubleRegister(LOperand* op,
|
||||
SwVfpRegister flt_scratch,
|
||||
DwVfpRegister dbl_scratch);
|
||||
int ToRepresentation(LConstantOperand* op, const Representation& r) const;
|
||||
int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const;
|
||||
int32_t ToInteger32(LConstantOperand* op) const;
|
||||
Smi* ToSmi(LConstantOperand* op) const;
|
||||
double ToDouble(LConstantOperand* op) const;
|
||||
|
10
src/ast.cc
10
src/ast.cc
@ -304,16 +304,6 @@ void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
|
||||
}
|
||||
|
||||
|
||||
bool UnaryOperation::ResultOverwriteAllowed() {
|
||||
switch (op_) {
|
||||
case Token::BIT_NOT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
|
||||
// TODO(olivf) If this Operation is used in a test context, then the right
|
||||
// hand side has a ToBoolean stub and we want to collect the type information.
|
||||
|
@ -1847,8 +1847,6 @@ class UnaryOperation: public Expression {
|
||||
public:
|
||||
DECLARE_NODE_TYPE(UnaryOperation)
|
||||
|
||||
virtual bool ResultOverwriteAllowed();
|
||||
|
||||
Token::Value op() const { return op_; }
|
||||
Expression* expression() const { return expression_; }
|
||||
virtual int position() const { return pos_; }
|
||||
@ -1856,8 +1854,6 @@ class UnaryOperation: public Expression {
|
||||
BailoutId MaterializeTrueId() { return materialize_true_id_; }
|
||||
BailoutId MaterializeFalseId() { return materialize_false_id_; }
|
||||
|
||||
TypeFeedbackId UnaryOperationFeedbackId() const { return reuse(id()); }
|
||||
|
||||
virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
|
||||
|
||||
protected:
|
||||
|
@ -259,7 +259,6 @@ enum BuiltinExtraArguments {
|
||||
V(BIT_OR, 1) \
|
||||
V(BIT_AND, 1) \
|
||||
V(BIT_XOR, 1) \
|
||||
V(BIT_NOT, 0) \
|
||||
V(SHL, 1) \
|
||||
V(SAR, 1) \
|
||||
V(SHR, 1) \
|
||||
|
@ -801,45 +801,6 @@ Handle<Code> CompareNilICStub::GenerateCode() {
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
HValue* CodeStubGraphBuilder<UnaryOpStub>::BuildCodeInitializedStub() {
|
||||
UnaryOpStub* stub = casted_stub();
|
||||
ASSERT_EQ(Token::BIT_NOT, stub->operation());
|
||||
Handle<Type> type = stub->GetType(graph()->isolate());
|
||||
HValue* input = GetParameter(0);
|
||||
|
||||
// Prevent unwanted HChange being inserted to ensure that the stub
|
||||
// deopts on newly encountered types.
|
||||
if (!type->Maybe(Type::Double())) {
|
||||
input = Add<HForceRepresentation>(input, Representation::Smi());
|
||||
}
|
||||
|
||||
if (!type->Is(Type::Number())) {
|
||||
// If we expect to see other things than Numbers, we will create a generic
|
||||
// stub, which handles all numbers and calls into the runtime for the rest.
|
||||
IfBuilder if_number(this);
|
||||
if_number.If<HIsNumberAndBranch>(input);
|
||||
if_number.Then();
|
||||
HInstruction* res = BuildUnaryMathOp(input, type, stub->operation());
|
||||
if_number.Return(AddInstruction(res));
|
||||
if_number.Else();
|
||||
HValue* function = AddLoadJSBuiltin(stub->ToJSBuiltin());
|
||||
Add<HPushArgument>(GetParameter(0));
|
||||
HValue* result = Add<HInvokeFunction>(function, 1);
|
||||
if_number.Return(result);
|
||||
if_number.End();
|
||||
return graph()->GetConstantUndefined();
|
||||
}
|
||||
|
||||
return AddInstruction(BuildUnaryMathOp(input, type, stub->operation()));
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> UnaryOpStub::GenerateCode() {
|
||||
return DoGenerateCode(this);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
|
||||
ToBooleanStub* stub = casted_stub();
|
||||
|
@ -204,65 +204,6 @@ void CodeStub::PrintName(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
Builtins::JavaScript UnaryOpStub::ToJSBuiltin() {
|
||||
switch (operation_) {
|
||||
default:
|
||||
UNREACHABLE();
|
||||
case Token::BIT_NOT:
|
||||
return Builtins::BIT_NOT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Handle<JSFunction> UnaryOpStub::ToJSFunction(Isolate* isolate) {
|
||||
Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
|
||||
Object* builtin = builtins->javascript_builtin(ToJSBuiltin());
|
||||
return Handle<JSFunction>(JSFunction::cast(builtin), isolate);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* UnaryOpStub::Result(Handle<Object> object, Isolate* isolate) {
|
||||
Handle<JSFunction> builtin_function = ToJSFunction(isolate);
|
||||
bool caught_exception;
|
||||
Handle<Object> result = Execution::Call(builtin_function, object,
|
||||
0, NULL, &caught_exception);
|
||||
if (caught_exception) {
|
||||
return Failure::Exception();
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
void UnaryOpStub::UpdateStatus(Handle<Object> object) {
|
||||
State old_state(state_);
|
||||
if (object->IsSmi()) {
|
||||
state_.Add(SMI);
|
||||
} else if (object->IsHeapNumber()) {
|
||||
state_.Add(HEAP_NUMBER);
|
||||
} else {
|
||||
state_.Add(GENERIC);
|
||||
}
|
||||
TraceTransition(old_state, state_);
|
||||
}
|
||||
|
||||
|
||||
Handle<Type> UnaryOpStub::GetType(Isolate* isolate) {
|
||||
if (state_.Contains(GENERIC)) {
|
||||
return handle(Type::Any(), isolate);
|
||||
}
|
||||
Handle<Type> type = handle(Type::None(), isolate);
|
||||
if (state_.Contains(SMI)) {
|
||||
type = handle(
|
||||
Type::Union(type, handle(Type::Smi(), isolate)), isolate);
|
||||
}
|
||||
if (state_.Contains(HEAP_NUMBER)) {
|
||||
type = handle(
|
||||
Type::Union(type, handle(Type::Double(), isolate)), isolate);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
void BinaryOpStub::Generate(MacroAssembler* masm) {
|
||||
// Explicitly allow generation of nested stubs. It is safe here because
|
||||
// generation code does not use any raw pointers.
|
||||
@ -348,28 +289,6 @@ void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
|
||||
#undef __
|
||||
|
||||
|
||||
void UnaryOpStub::PrintBaseName(StringStream* stream) {
|
||||
CodeStub::PrintBaseName(stream);
|
||||
if (operation_ == Token::BIT_NOT) stream->Add("Not");
|
||||
}
|
||||
|
||||
|
||||
void UnaryOpStub::PrintState(StringStream* stream) {
|
||||
state_.Print(stream);
|
||||
}
|
||||
|
||||
|
||||
void UnaryOpStub::State::Print(StringStream* stream) const {
|
||||
stream->Add("(");
|
||||
SimpleListPrinter printer(stream);
|
||||
if (IsEmpty()) printer.Add("None");
|
||||
if (Contains(GENERIC)) printer.Add("Generic");
|
||||
if (Contains(HEAP_NUMBER)) printer.Add("HeapNumber");
|
||||
if (Contains(SMI)) printer.Add("Smi");
|
||||
stream->Add(")");
|
||||
}
|
||||
|
||||
|
||||
void BinaryOpStub::PrintName(StringStream* stream) {
|
||||
const char* op_name = Token::Name(op_);
|
||||
const char* overwrite_name;
|
||||
|
@ -40,7 +40,6 @@ namespace internal {
|
||||
#define CODE_STUB_LIST_ALL_PLATFORMS(V) \
|
||||
V(CallFunction) \
|
||||
V(CallConstruct) \
|
||||
V(UnaryOp) \
|
||||
V(BinaryOp) \
|
||||
V(StringAdd) \
|
||||
V(SubString) \
|
||||
@ -593,73 +592,6 @@ class StoreGlobalStub : public HydrogenCodeStub {
|
||||
};
|
||||
|
||||
|
||||
class UnaryOpStub : public HydrogenCodeStub {
|
||||
public:
|
||||
// Stub without type info available -> construct uninitialized
|
||||
explicit UnaryOpStub(Token::Value operation)
|
||||
: HydrogenCodeStub(UNINITIALIZED), operation_(operation) { }
|
||||
explicit UnaryOpStub(Code::ExtraICState ic_state) :
|
||||
state_(StateBits::decode(ic_state)),
|
||||
operation_(OperatorBits::decode(ic_state)) { }
|
||||
|
||||
virtual void InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor);
|
||||
|
||||
virtual Code::Kind GetCodeKind() const { return Code::UNARY_OP_IC; }
|
||||
virtual InlineCacheState GetICState() {
|
||||
if (state_.Contains(GENERIC)) {
|
||||
return MEGAMORPHIC;
|
||||
} else if (state_.IsEmpty()) {
|
||||
return PREMONOMORPHIC;
|
||||
} else {
|
||||
return MONOMORPHIC;
|
||||
}
|
||||
}
|
||||
virtual Code::ExtraICState GetExtraICState() {
|
||||
return OperatorBits::encode(operation_) |
|
||||
StateBits::encode(state_.ToIntegral());
|
||||
}
|
||||
|
||||
Token::Value operation() { return operation_; }
|
||||
Handle<JSFunction> ToJSFunction(Isolate* isolate);
|
||||
Builtins::JavaScript ToJSBuiltin();
|
||||
|
||||
void UpdateStatus(Handle<Object> object);
|
||||
MaybeObject* Result(Handle<Object> object, Isolate* isolate);
|
||||
Handle<Code> GenerateCode();
|
||||
Handle<Type> GetType(Isolate* isolate);
|
||||
|
||||
protected:
|
||||
void PrintState(StringStream* stream);
|
||||
void PrintBaseName(StringStream* stream);
|
||||
|
||||
private:
|
||||
enum UnaryOpType {
|
||||
SMI,
|
||||
HEAP_NUMBER,
|
||||
GENERIC,
|
||||
NUMBER_OF_TYPES
|
||||
};
|
||||
|
||||
class State : public EnumSet<UnaryOpType, byte> {
|
||||
public:
|
||||
State() : EnumSet<UnaryOpType, byte>() { }
|
||||
explicit State(byte bits) : EnumSet<UnaryOpType, byte>(bits) { }
|
||||
void Print(StringStream* stream) const;
|
||||
};
|
||||
|
||||
class StateBits : public BitField<int, 0, NUMBER_OF_TYPES> { };
|
||||
class OperatorBits : public BitField<Token::Value, NUMBER_OF_TYPES, 8> { };
|
||||
|
||||
State state_;
|
||||
Token::Value operation_;
|
||||
|
||||
virtual CodeStub::Major MajorKey() { return UnaryOp; }
|
||||
virtual int NotMissMinorKey() { return GetExtraICState(); }
|
||||
};
|
||||
|
||||
|
||||
class FastCloneShallowArrayStub : public HydrogenCodeStub {
|
||||
public:
|
||||
// Maximum length of copied elements array.
|
||||
|
@ -159,7 +159,6 @@ void BreakLocationIterator::Next() {
|
||||
Code* code = Code::GetCodeFromTargetAddress(target);
|
||||
if ((code->is_inline_cache_stub() &&
|
||||
!code->is_binary_op_stub() &&
|
||||
!code->is_unary_op_stub() &&
|
||||
!code->is_compare_ic_stub() &&
|
||||
!code->is_to_boolean_ic_stub()) ||
|
||||
RelocInfo::IsConstructCall(rmode())) {
|
||||
|
@ -625,8 +625,6 @@ class FullCodeGenerator: public AstVisitor {
|
||||
AST_NODE_LIST(DECLARE_VISIT)
|
||||
#undef DECLARE_VISIT
|
||||
|
||||
void EmitUnaryOperation(UnaryOperation* expr, const char* comment);
|
||||
|
||||
void VisitComma(BinaryOperation* expr);
|
||||
void VisitLogicalExpression(BinaryOperation* expr);
|
||||
void VisitArithmeticExpression(BinaryOperation* expr);
|
||||
|
@ -1155,6 +1155,29 @@ void HLoadFieldByIndex::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
static bool MatchLeftIsOnes(HValue* l, HValue* r, HValue** negated) {
|
||||
if (!l->EqualsInteger32Constant(~0)) return false;
|
||||
*negated = r;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool MatchNegationViaXor(HValue* instr, HValue** negated) {
|
||||
if (!instr->IsBitwise()) return false;
|
||||
HBitwise* b = HBitwise::cast(instr);
|
||||
return (b->op() == Token::BIT_XOR) &&
|
||||
(MatchLeftIsOnes(b->left(), b->right(), negated) ||
|
||||
MatchLeftIsOnes(b->right(), b->left(), negated));
|
||||
}
|
||||
|
||||
|
||||
static bool MatchDoubleNegation(HValue* instr, HValue** arg) {
|
||||
HValue* negated;
|
||||
return MatchNegationViaXor(instr, &negated) &&
|
||||
MatchNegationViaXor(negated, arg);
|
||||
}
|
||||
|
||||
|
||||
HValue* HBitwise::Canonicalize() {
|
||||
if (!representation().IsSmiOrInteger32()) return this;
|
||||
// If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x.
|
||||
@ -1167,18 +1190,10 @@ HValue* HBitwise::Canonicalize() {
|
||||
!left()->CheckFlag(kUint32)) {
|
||||
return left();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
HValue* HBitNot::Canonicalize() {
|
||||
// Optimize ~~x, a common pattern used for ToInt32(x).
|
||||
if (value()->IsBitNot()) {
|
||||
HValue* result = HBitNot::cast(value())->value();
|
||||
ASSERT(result->representation().IsInteger32());
|
||||
if (!result->CheckFlag(kUint32)) {
|
||||
return result;
|
||||
}
|
||||
// Optimize double negation, a common pattern used for ToInt32(x).
|
||||
HValue* arg;
|
||||
if (MatchDoubleNegation(this, &arg) && !arg->CheckFlag(kUint32)) {
|
||||
return arg;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -72,7 +72,6 @@ class LChunkBuilder;
|
||||
V(ArgumentsLength) \
|
||||
V(ArgumentsObject) \
|
||||
V(Bitwise) \
|
||||
V(BitNot) \
|
||||
V(BlockEntry) \
|
||||
V(BoundsCheck) \
|
||||
V(BoundsCheckBaseIndexInformation) \
|
||||
@ -2392,37 +2391,6 @@ class HElementsKind: public HUnaryOperation {
|
||||
};
|
||||
|
||||
|
||||
class HBitNot: public HUnaryOperation {
|
||||
public:
|
||||
DECLARE_INSTRUCTION_FACTORY_P1(HBitNot, HValue*);
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
return Representation::Integer32();
|
||||
}
|
||||
virtual Representation observed_input_representation(int index) {
|
||||
return Representation::Integer32();
|
||||
}
|
||||
|
||||
virtual HValue* Canonicalize();
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(BitNot)
|
||||
|
||||
protected:
|
||||
virtual bool DataEquals(HValue* other) { return true; }
|
||||
|
||||
private:
|
||||
explicit HBitNot(HValue* value)
|
||||
: HUnaryOperation(value, HType::TaggedNumber()) {
|
||||
set_representation(Representation::Integer32());
|
||||
SetFlag(kUseGVN);
|
||||
SetFlag(kTruncatingToInt32);
|
||||
SetFlag(kAllowUndefinedAsNaN);
|
||||
}
|
||||
|
||||
virtual bool IsDeletable() const { return true; }
|
||||
};
|
||||
|
||||
|
||||
class HUnaryMathOperation: public HTemplateInstruction<2> {
|
||||
public:
|
||||
static HInstruction* New(Zone* zone,
|
||||
|
@ -33,11 +33,7 @@ namespace internal {
|
||||
|
||||
bool HUint32AnalysisPhase::IsSafeUint32Use(HValue* val, HValue* use) {
|
||||
// Operations that operate on bits are safe.
|
||||
if (use->IsBitwise() ||
|
||||
use->IsShl() ||
|
||||
use->IsSar() ||
|
||||
use->IsShr() ||
|
||||
use->IsBitNot()) {
|
||||
if (use->IsBitwise() || use->IsShl() || use->IsSar() || use->IsShr()) {
|
||||
return true;
|
||||
} else if (use->IsChange() || use->IsSimulate()) {
|
||||
// Conversions and deoptimization have special support for unt32.
|
||||
|
@ -1719,19 +1719,6 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate,
|
||||
}
|
||||
|
||||
|
||||
HInstruction* HGraphBuilder::BuildUnaryMathOp(
|
||||
HValue* input, Handle<Type> type, Token::Value operation) {
|
||||
ASSERT_EQ(Token::BIT_NOT, operation);
|
||||
// We only handle the numeric cases here
|
||||
type = handle(
|
||||
Type::Intersect(type, handle(Type::Number(), isolate())), isolate());
|
||||
if (type->Is(Type::None())) {
|
||||
Add<HDeoptimize>(Deoptimizer::SOFT);
|
||||
}
|
||||
return New<HBitNot>(input);
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::BuildCompareNil(
|
||||
HValue* value,
|
||||
Handle<Type> type,
|
||||
@ -7229,7 +7216,6 @@ void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
case Token::DELETE: return VisitDelete(expr);
|
||||
case Token::VOID: return VisitVoid(expr);
|
||||
case Token::TYPEOF: return VisitTypeof(expr);
|
||||
case Token::BIT_NOT: return VisitBitNot(expr);
|
||||
case Token::NOT: return VisitNot(expr);
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
@ -7291,15 +7277,6 @@ void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) {
|
||||
CHECK_ALIVE(VisitForValue(expr->expression()));
|
||||
Handle<Type> operand_type = expr->expression()->bounds().lower;
|
||||
HValue* value = TruncateToNumber(Pop(), &operand_type);
|
||||
HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::BIT_NOT);
|
||||
return ast_context()->ReturnInstruction(instr, expr->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) {
|
||||
if (ast_context()->IsTest()) {
|
||||
TestContext* context = TestContext::cast(ast_context());
|
||||
|
@ -1550,9 +1550,6 @@ class HGraphBuilder {
|
||||
ElementsKind kind,
|
||||
int length);
|
||||
|
||||
HInstruction* BuildUnaryMathOp(
|
||||
HValue* value, Handle<Type> type, Token::Value token);
|
||||
|
||||
void BuildCompareNil(
|
||||
HValue* value,
|
||||
Handle<Type> type,
|
||||
@ -1811,7 +1808,6 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
|
||||
void VisitDelete(UnaryOperation* expr);
|
||||
void VisitVoid(UnaryOperation* expr);
|
||||
void VisitTypeof(UnaryOperation* expr);
|
||||
void VisitBitNot(UnaryOperation* expr);
|
||||
void VisitNot(UnaryOperation* expr);
|
||||
|
||||
void VisitComma(BinaryOperation* expr);
|
||||
|
@ -250,17 +250,6 @@ void ToBooleanStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void UnaryOpStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { eax };
|
||||
descriptor->register_param_count_ = 1;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ =
|
||||
FUNCTION_ADDR(UnaryOpIC_Miss);
|
||||
}
|
||||
|
||||
|
||||
void StoreGlobalStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
|
@ -4347,31 +4347,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::BIT_NOT:
|
||||
EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
|
||||
const char* comment) {
|
||||
ASSERT_EQ(Token::BIT_NOT, expr->op());
|
||||
Comment cmt(masm_, comment);
|
||||
UnaryOpStub stub(expr->op());
|
||||
// UnaryOpStub expects the argument to be in the
|
||||
// accumulator register eax.
|
||||
VisitForAccumulatorValue(expr->expression());
|
||||
SetSourcePosition(expr->position());
|
||||
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
|
||||
expr->UnaryOperationFeedbackId());
|
||||
context()->Plug(eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
Comment cmnt(masm_, "[ CountOperation");
|
||||
SetSourcePosition(expr->position());
|
||||
|
@ -1679,8 +1679,9 @@ void LCodeGen::DoBitI(LBitI* instr) {
|
||||
ASSERT(left->IsRegister());
|
||||
|
||||
if (right->IsConstantOperand()) {
|
||||
int right_operand = ToRepresentation(LConstantOperand::cast(right),
|
||||
instr->hydrogen()->representation());
|
||||
int32_t right_operand =
|
||||
ToRepresentation(LConstantOperand::cast(right),
|
||||
instr->hydrogen()->representation());
|
||||
switch (instr->op()) {
|
||||
case Token::BIT_AND:
|
||||
__ and_(ToRegister(left), right_operand);
|
||||
@ -1689,7 +1690,11 @@ void LCodeGen::DoBitI(LBitI* instr) {
|
||||
__ or_(ToRegister(left), right_operand);
|
||||
break;
|
||||
case Token::BIT_XOR:
|
||||
__ xor_(ToRegister(left), right_operand);
|
||||
if (right_operand == int32_t(~0)) {
|
||||
__ not_(ToRegister(left));
|
||||
} else {
|
||||
__ xor_(ToRegister(left), right_operand);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -1990,13 +1995,6 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoBitNotI(LBitNotI* instr) {
|
||||
LOperand* input = instr->value();
|
||||
ASSERT(input->Equals(instr->result()));
|
||||
__ not_(ToRegister(input));
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoThrow(LThrow* instr) {
|
||||
__ push(ToOperand(instr->value()));
|
||||
ASSERT(ToRegister(instr->context()).is(esi));
|
||||
|
@ -294,7 +294,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
Register ToRegister(int index) const;
|
||||
XMMRegister ToDoubleRegister(int index) const;
|
||||
X87Register ToX87Register(int index) const;
|
||||
int ToRepresentation(LConstantOperand* op, const Representation& r) const;
|
||||
int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const;
|
||||
int32_t ToInteger32(LConstantOperand* op) const;
|
||||
ExternalReference ToExternalReference(LConstantOperand* op) const;
|
||||
|
||||
|
@ -1414,16 +1414,6 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
|
||||
ASSERT(instr->value()->representation().IsInteger32());
|
||||
ASSERT(instr->representation().IsInteger32());
|
||||
if (instr->HasNoUses()) return NULL;
|
||||
LOperand* input = UseRegisterAtStart(instr->value());
|
||||
LBitNotI* result = new(zone()) LBitNotI(input);
|
||||
return DefineSameAsFirst(result);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
|
||||
if (instr->representation().IsDouble()) {
|
||||
return DoArithmeticD(Token::DIV, instr);
|
||||
|
@ -50,7 +50,6 @@ class LCodeGen;
|
||||
V(ArithmeticD) \
|
||||
V(ArithmeticT) \
|
||||
V(BitI) \
|
||||
V(BitNotI) \
|
||||
V(BoundsCheck) \
|
||||
V(Branch) \
|
||||
V(CallConstantFunction) \
|
||||
@ -1357,18 +1356,6 @@ class LThrow: public LTemplateInstruction<0, 2, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LBitNotI: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LBitNotI(LOperand* value) {
|
||||
inputs_[0] = value;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i")
|
||||
};
|
||||
|
||||
|
||||
class LAddI: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LAddI(LOperand* left, LOperand* right) {
|
||||
|
22
src/ic.cc
22
src/ic.cc
@ -390,7 +390,6 @@ void IC::Clear(Address address) {
|
||||
case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
|
||||
case Code::COMPARE_IC: return CompareIC::Clear(address, target);
|
||||
case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target);
|
||||
case Code::UNARY_OP_IC:
|
||||
case Code::BINARY_OP_IC:
|
||||
case Code::TO_BOOLEAN_IC:
|
||||
// Clearing these is tricky and does not
|
||||
@ -2589,27 +2588,6 @@ void BinaryOpIC::StubInfoToType(int minor_key,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* UnaryOpIC::Transition(Handle<Object> object) {
|
||||
Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
|
||||
UnaryOpStub stub(extra_ic_state);
|
||||
|
||||
stub.UpdateStatus(object);
|
||||
|
||||
Handle<Code> code = stub.GetCode(isolate());
|
||||
set_target(*code);
|
||||
|
||||
return stub.Result(object, isolate());
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<Object> object = args.at<Object>(0);
|
||||
UnaryOpIC ic(isolate);
|
||||
return ic.Transition(object);
|
||||
}
|
||||
|
||||
|
||||
static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value,
|
||||
Token::Value op) {
|
||||
v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value);
|
||||
|
8
src/ic.h
8
src/ic.h
@ -714,14 +714,6 @@ class KeyedStoreIC: public StoreIC {
|
||||
};
|
||||
|
||||
|
||||
class UnaryOpIC: public IC {
|
||||
public:
|
||||
explicit UnaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
|
||||
|
||||
MUST_USE_RESULT MaybeObject* Transition(Handle<Object> object);
|
||||
};
|
||||
|
||||
|
||||
// Type Recording BinaryOpIC, that records the types of the inputs and outputs.
|
||||
class BinaryOpIC: public IC {
|
||||
public:
|
||||
|
@ -1644,7 +1644,6 @@ void Logger::LogCodeObject(Object* object) {
|
||||
case Code::FUNCTION:
|
||||
case Code::OPTIMIZED_FUNCTION:
|
||||
return; // We log this later using LogCompiledFunctions.
|
||||
case Code::UNARY_OP_IC: // fall through
|
||||
case Code::BINARY_OP_IC: // fall through
|
||||
case Code::COMPARE_IC: // fall through
|
||||
case Code::COMPARE_NIL_IC: // fall through
|
||||
|
@ -358,6 +358,11 @@ class Operand BASE_EMBEDDED {
|
||||
// Return true if this is a register operand.
|
||||
INLINE(bool is_reg() const);
|
||||
|
||||
inline int32_t immediate() const {
|
||||
ASSERT(!is_reg());
|
||||
return imm32_;
|
||||
}
|
||||
|
||||
Register rm() const { return rm_; }
|
||||
|
||||
private:
|
||||
|
@ -247,17 +247,6 @@ void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void UnaryOpStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { a0 };
|
||||
descriptor->register_param_count_ = 1;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ =
|
||||
FUNCTION_ADDR(UnaryOpIC_Miss);
|
||||
}
|
||||
|
||||
|
||||
void StoreGlobalStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
|
@ -4382,32 +4382,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::BIT_NOT:
|
||||
EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
|
||||
const char* comment) {
|
||||
ASSERT_EQ(Token::BIT_NOT, expr->op());
|
||||
// TODO(svenpanne): Allowing format strings in Comment would be nice here...
|
||||
Comment cmt(masm_, comment);
|
||||
UnaryOpStub stub(expr->op());
|
||||
// GenericUnaryOpStub expects the argument to be in a0.
|
||||
VisitForAccumulatorValue(expr->expression());
|
||||
SetSourcePosition(expr->position());
|
||||
__ mov(a0, result_register());
|
||||
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
|
||||
expr->UnaryOperationFeedbackId());
|
||||
context()->Plug(v0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
Comment cmnt(masm_, "[ CountOperation");
|
||||
SetSourcePosition(expr->position());
|
||||
|
@ -1509,7 +1509,11 @@ void LCodeGen::DoBitI(LBitI* instr) {
|
||||
__ Or(result, left, right);
|
||||
break;
|
||||
case Token::BIT_XOR:
|
||||
__ Xor(result, left, right);
|
||||
if (right_op->IsConstantOperand() && right.immediate() == int32_t(~0)) {
|
||||
__ Nor(result, zero_reg, left);
|
||||
} else {
|
||||
__ Xor(result, left, right);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -1787,13 +1791,6 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoBitNotI(LBitNotI* instr) {
|
||||
Register input = ToRegister(instr->value());
|
||||
Register result = ToRegister(instr->result());
|
||||
__ Nor(result, zero_reg, Operand(input));
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoThrow(LThrow* instr) {
|
||||
Register input_reg = EmitLoadRegister(instr->value(), at);
|
||||
__ push(input_reg);
|
||||
|
@ -114,7 +114,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
DoubleRegister EmitLoadDoubleRegister(LOperand* op,
|
||||
FloatRegister flt_scratch,
|
||||
DoubleRegister dbl_scratch);
|
||||
int ToRepresentation(LConstantOperand* op, const Representation& r) const;
|
||||
int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const;
|
||||
int32_t ToInteger32(LConstantOperand* op) const;
|
||||
Smi* ToSmi(LConstantOperand* op) const;
|
||||
double ToDouble(LConstantOperand* op) const;
|
||||
|
@ -1327,15 +1327,6 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
|
||||
ASSERT(instr->value()->representation().IsInteger32());
|
||||
ASSERT(instr->representation().IsInteger32());
|
||||
if (instr->HasNoUses()) return NULL;
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
return DefineAsRegister(new(zone()) LBitNotI(value));
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
|
||||
if (instr->representation().IsDouble()) {
|
||||
return DoArithmeticD(Token::DIV, instr);
|
||||
|
@ -50,7 +50,6 @@ class LCodeGen;
|
||||
V(ArithmeticD) \
|
||||
V(ArithmeticT) \
|
||||
V(BitI) \
|
||||
V(BitNotI) \
|
||||
V(BoundsCheck) \
|
||||
V(Branch) \
|
||||
V(CallConstantFunction) \
|
||||
@ -1355,18 +1354,6 @@ class LThrow: public LTemplateInstruction<0, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LBitNotI: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LBitNotI(LOperand* value) {
|
||||
inputs_[0] = value;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i")
|
||||
};
|
||||
|
||||
|
||||
class LAddI: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LAddI(LOperand* left, LOperand* right) {
|
||||
|
@ -3822,7 +3822,6 @@ inline void Code::set_is_crankshafted(bool value) {
|
||||
|
||||
int Code::major_key() {
|
||||
ASSERT(kind() == STUB ||
|
||||
kind() == UNARY_OP_IC ||
|
||||
kind() == BINARY_OP_IC ||
|
||||
kind() == COMPARE_IC ||
|
||||
kind() == COMPARE_NIL_IC ||
|
||||
@ -3837,7 +3836,6 @@ int Code::major_key() {
|
||||
|
||||
void Code::set_major_key(int major) {
|
||||
ASSERT(kind() == STUB ||
|
||||
kind() == UNARY_OP_IC ||
|
||||
kind() == BINARY_OP_IC ||
|
||||
kind() == COMPARE_IC ||
|
||||
kind() == COMPARE_NIL_IC ||
|
||||
@ -4027,21 +4025,6 @@ void Code::set_check_type(CheckType value) {
|
||||
}
|
||||
|
||||
|
||||
byte Code::unary_op_type() {
|
||||
ASSERT(is_unary_op_stub());
|
||||
return UnaryOpTypeField::decode(
|
||||
READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
|
||||
}
|
||||
|
||||
|
||||
void Code::set_unary_op_type(byte value) {
|
||||
ASSERT(is_unary_op_stub());
|
||||
int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
|
||||
int updated = UnaryOpTypeField::update(previous, value);
|
||||
WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
|
||||
}
|
||||
|
||||
|
||||
byte Code::to_boolean_state() {
|
||||
return extended_extra_ic_state();
|
||||
}
|
||||
|
@ -4781,7 +4781,6 @@ class Code: public HeapObject {
|
||||
V(KEYED_CALL_IC) \
|
||||
V(STORE_IC) \
|
||||
V(KEYED_STORE_IC) \
|
||||
V(UNARY_OP_IC) \
|
||||
V(BINARY_OP_IC) \
|
||||
V(COMPARE_IC) \
|
||||
V(COMPARE_NIL_IC) \
|
||||
@ -4900,8 +4899,7 @@ class Code: public HeapObject {
|
||||
// TODO(danno): This is a bit of a hack right now since there are still
|
||||
// clients of this API that pass "extra" values in for argc. These clients
|
||||
// should be retrofitted to used ExtendedExtraICState.
|
||||
return kind == COMPARE_NIL_IC || kind == TO_BOOLEAN_IC ||
|
||||
kind == UNARY_OP_IC;
|
||||
return kind == COMPARE_NIL_IC || kind == TO_BOOLEAN_IC;
|
||||
}
|
||||
|
||||
inline StubType type(); // Only valid for monomorphic IC stubs.
|
||||
@ -4916,7 +4914,6 @@ class Code: public HeapObject {
|
||||
inline bool is_keyed_store_stub() { return kind() == KEYED_STORE_IC; }
|
||||
inline bool is_call_stub() { return kind() == CALL_IC; }
|
||||
inline bool is_keyed_call_stub() { return kind() == KEYED_CALL_IC; }
|
||||
inline bool is_unary_op_stub() { return kind() == UNARY_OP_IC; }
|
||||
inline bool is_binary_op_stub() { return kind() == BINARY_OP_IC; }
|
||||
inline bool is_compare_ic_stub() { return kind() == COMPARE_IC; }
|
||||
inline bool is_compare_nil_ic_stub() { return kind() == COMPARE_NIL_IC; }
|
||||
@ -4990,10 +4987,6 @@ class Code: public HeapObject {
|
||||
inline CheckType check_type();
|
||||
inline void set_check_type(CheckType value);
|
||||
|
||||
// [type-recording unary op type]: For kind UNARY_OP_IC.
|
||||
inline byte unary_op_type();
|
||||
inline void set_unary_op_type(byte value);
|
||||
|
||||
// [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in.
|
||||
inline byte to_boolean_state();
|
||||
|
||||
@ -5232,9 +5225,6 @@ class Code: public HeapObject {
|
||||
// KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION)
|
||||
static const int kStackSlotsFirstBit = 0;
|
||||
static const int kStackSlotsBitCount = 24;
|
||||
static const int kUnaryOpTypeFirstBit =
|
||||
kStackSlotsFirstBit + kStackSlotsBitCount;
|
||||
static const int kUnaryOpTypeBitCount = 3;
|
||||
static const int kHasFunctionCacheFirstBit =
|
||||
kStackSlotsFirstBit + kStackSlotsBitCount;
|
||||
static const int kHasFunctionCacheBitCount = 1;
|
||||
@ -5243,15 +5233,12 @@ class Code: public HeapObject {
|
||||
static const int kMarkedForDeoptimizationBitCount = 1;
|
||||
|
||||
STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32);
|
||||
STATIC_ASSERT(kUnaryOpTypeFirstBit + kUnaryOpTypeBitCount <= 32);
|
||||
STATIC_ASSERT(kHasFunctionCacheFirstBit + kHasFunctionCacheBitCount <= 32);
|
||||
STATIC_ASSERT(kMarkedForDeoptimizationFirstBit +
|
||||
kMarkedForDeoptimizationBitCount <= 32);
|
||||
|
||||
class StackSlotsField: public BitField<int,
|
||||
kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT
|
||||
class UnaryOpTypeField: public BitField<int,
|
||||
kUnaryOpTypeFirstBit, kUnaryOpTypeBitCount> {}; // NOLINT
|
||||
class HasFunctionCacheField: public BitField<bool,
|
||||
kHasFunctionCacheFirstBit, kHasFunctionCacheBitCount> {}; // NOLINT
|
||||
class MarkedForDeoptimizationField: public BitField<bool,
|
||||
|
@ -3204,6 +3204,13 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
||||
factory()->NewNumberLiteral(-1),
|
||||
position);
|
||||
}
|
||||
// ...and one more time for '~foo' => 'foo^(~0)'.
|
||||
if (op == Token::BIT_NOT) {
|
||||
return factory()->NewBinaryOperation(Token::BIT_XOR,
|
||||
expression,
|
||||
factory()->NewNumberLiteral(~0),
|
||||
position);
|
||||
}
|
||||
|
||||
return factory()->NewUnaryOperation(op, expression, position);
|
||||
|
||||
|
@ -7245,15 +7245,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
|
||||
SealHandleScope shs(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
|
||||
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
|
||||
return isolate->heap()->NumberFromInt32(~x);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
|
||||
SealHandleScope shs(isolate);
|
||||
ASSERT(args.length() == 2);
|
||||
|
@ -158,7 +158,6 @@ namespace internal {
|
||||
F(NumberOr, 2, 1) \
|
||||
F(NumberAnd, 2, 1) \
|
||||
F(NumberXor, 2, 1) \
|
||||
F(NumberNot, 1, 1) \
|
||||
\
|
||||
F(NumberShl, 2, 1) \
|
||||
F(NumberShr, 2, 1) \
|
||||
|
@ -294,13 +294,6 @@ function BIT_XOR(y) {
|
||||
}
|
||||
|
||||
|
||||
// ECMA-262, section 11.4.8, page 48.
|
||||
function BIT_NOT() {
|
||||
var x = IS_NUMBER(this) ? this : %NonNumberToNumber(this);
|
||||
return %NumberNot(x);
|
||||
}
|
||||
|
||||
|
||||
// ECMA-262, section 11.7.1, page 51.
|
||||
function SHL(y) {
|
||||
var x = IS_NUMBER(this) ? this : %NonNumberToNumber(this);
|
||||
|
@ -384,17 +384,6 @@ void TypeFeedbackOracle::CompareType(TypeFeedbackId id,
|
||||
}
|
||||
|
||||
|
||||
Handle<Type> TypeFeedbackOracle::UnaryType(TypeFeedbackId id) {
|
||||
Handle<Object> object = GetInfo(id);
|
||||
if (!object->IsCode()) {
|
||||
return handle(Type::None(), isolate());
|
||||
}
|
||||
Handle<Code> code = Handle<Code>::cast(object);
|
||||
ASSERT(code->is_unary_op_stub());
|
||||
return UnaryOpStub(code->extended_extra_ic_state()).GetType(isolate());
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
|
||||
Handle<Type>* left,
|
||||
Handle<Type>* right,
|
||||
@ -658,7 +647,6 @@ void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Code::UNARY_OP_IC:
|
||||
case Code::BINARY_OP_IC:
|
||||
case Code::COMPARE_IC:
|
||||
case Code::TO_BOOLEAN_IC:
|
||||
|
@ -297,7 +297,6 @@ class TypeFeedbackOracle: public ZoneObject {
|
||||
byte ToBooleanTypes(TypeFeedbackId id);
|
||||
|
||||
// Get type information for arithmetic operations and compares.
|
||||
Handle<Type> UnaryType(TypeFeedbackId id);
|
||||
void BinaryType(TypeFeedbackId id,
|
||||
Handle<Type>* left,
|
||||
Handle<Type>* right,
|
||||
|
@ -497,8 +497,6 @@ void AstTyper::VisitCallRuntime(CallRuntime* expr) {
|
||||
|
||||
void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
// Collect type feedback.
|
||||
Handle<Type> op_type = oracle()->UnaryType(expr->UnaryOperationFeedbackId());
|
||||
NarrowLowerType(expr->expression(), op_type);
|
||||
if (expr->op() == Token::NOT) {
|
||||
// TODO(rossberg): only do in test or value context.
|
||||
expr->expression()->RecordToBooleanTypeFeedback(oracle());
|
||||
@ -514,9 +512,6 @@ void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
case Token::VOID:
|
||||
NarrowType(expr, Bounds(Type::Undefined(), isolate_));
|
||||
break;
|
||||
case Token::BIT_NOT:
|
||||
NarrowType(expr, Bounds(Type::Smi(), Type::Signed32(), isolate_));
|
||||
break;
|
||||
case Token::TYPEOF:
|
||||
NarrowType(expr, Bounds(Type::InternalizedString(), isolate_));
|
||||
break;
|
||||
|
@ -246,17 +246,6 @@ void ToBooleanStub::InitializeInterfaceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void UnaryOpStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
static Register registers[] = { rax };
|
||||
descriptor->register_param_count_ = 1;
|
||||
descriptor->register_params_ = registers;
|
||||
descriptor->deoptimization_handler_ =
|
||||
FUNCTION_ADDR(UnaryOpIC_Miss);
|
||||
}
|
||||
|
||||
|
||||
void StoreGlobalStub::InitializeInterfaceDescriptor(
|
||||
Isolate* isolate,
|
||||
CodeStubInterfaceDescriptor* descriptor) {
|
||||
|
@ -4335,32 +4335,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::BIT_NOT:
|
||||
EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
|
||||
const char* comment) {
|
||||
ASSERT_EQ(Token::BIT_NOT, expr->op());
|
||||
// TODO(svenpanne): Allowing format strings in Comment would be nice here...
|
||||
Comment cmt(masm_, comment);
|
||||
UnaryOpStub stub(expr->op());
|
||||
// UnaryOpStub expects the argument to be in the
|
||||
// accumulator register rax.
|
||||
VisitForAccumulatorValue(expr->expression());
|
||||
SetSourcePosition(expr->position());
|
||||
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
|
||||
expr->UnaryOperationFeedbackId());
|
||||
context()->Plug(rax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
Comment cmnt(masm_, "[ CountOperation");
|
||||
SetSourcePosition(expr->position());
|
||||
|
@ -1270,7 +1270,7 @@ void LCodeGen::DoMulI(LMulI* instr) {
|
||||
bool can_overflow =
|
||||
instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
||||
if (right->IsConstantOperand()) {
|
||||
int right_value = ToInteger32(LConstantOperand::cast(right));
|
||||
int32_t right_value = ToInteger32(LConstantOperand::cast(right));
|
||||
if (right_value == -1) {
|
||||
__ negl(left);
|
||||
} else if (right_value == 0) {
|
||||
@ -1362,7 +1362,7 @@ void LCodeGen::DoBitI(LBitI* instr) {
|
||||
ASSERT(left->IsRegister());
|
||||
|
||||
if (right->IsConstantOperand()) {
|
||||
int right_operand = ToInteger32(LConstantOperand::cast(right));
|
||||
int32_t right_operand = ToInteger32(LConstantOperand::cast(right));
|
||||
switch (instr->op()) {
|
||||
case Token::BIT_AND:
|
||||
__ andl(ToRegister(left), Immediate(right_operand));
|
||||
@ -1371,7 +1371,11 @@ void LCodeGen::DoBitI(LBitI* instr) {
|
||||
__ orl(ToRegister(left), Immediate(right_operand));
|
||||
break;
|
||||
case Token::BIT_XOR:
|
||||
__ xorl(ToRegister(left), Immediate(right_operand));
|
||||
if (right_operand == int32_t(~0)) {
|
||||
__ not_(ToRegister(left));
|
||||
} else {
|
||||
__ xorl(ToRegister(left), Immediate(right_operand));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -1442,7 +1446,7 @@ void LCodeGen::DoShiftI(LShiftI* instr) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int value = ToInteger32(LConstantOperand::cast(right));
|
||||
int32_t value = ToInteger32(LConstantOperand::cast(right));
|
||||
uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
|
||||
switch (instr->op()) {
|
||||
case Token::ROR:
|
||||
@ -1656,13 +1660,6 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoBitNotI(LBitNotI* instr) {
|
||||
LOperand* input = instr->value();
|
||||
ASSERT(input->Equals(instr->result()));
|
||||
__ not_(ToRegister(input));
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoThrow(LThrow* instr) {
|
||||
__ push(ToRegister(instr->value()));
|
||||
CallRuntime(Runtime::kThrow, 1, instr);
|
||||
@ -2898,8 +2895,8 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
|
||||
|
||||
if (instr->length()->IsConstantOperand() &&
|
||||
instr->index()->IsConstantOperand()) {
|
||||
int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
|
||||
int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
|
||||
int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
|
||||
int32_t const_length = ToInteger32(LConstantOperand::cast(instr->length()));
|
||||
int index = (const_length - const_index) + 1;
|
||||
__ movq(result, Operand(arguments, index * kPointerSize));
|
||||
} else {
|
||||
@ -3086,7 +3083,7 @@ Operand LCodeGen::BuildFastArrayOperand(
|
||||
Register elements_pointer_reg = ToRegister(elements_pointer);
|
||||
int shift_size = ElementsKindToShiftSize(elements_kind);
|
||||
if (key->IsConstantOperand()) {
|
||||
int constant_value = ToInteger32(LConstantOperand::cast(key));
|
||||
int32_t constant_value = ToInteger32(LConstantOperand::cast(key));
|
||||
if (constant_value & 0xF0000000) {
|
||||
Abort(kArrayIndexConstantValueTooBig);
|
||||
}
|
||||
@ -4096,7 +4093,7 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
|
||||
__ AssertZeroExtended(reg);
|
||||
}
|
||||
if (instr->index()->IsConstantOperand()) {
|
||||
int constant_index =
|
||||
int32_t constant_index =
|
||||
ToInteger32(LConstantOperand::cast(instr->index()));
|
||||
if (instr->hydrogen()->length()->representation().IsSmi()) {
|
||||
__ Cmp(reg, Smi::FromInt(constant_index));
|
||||
@ -4113,7 +4110,7 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
|
||||
} else {
|
||||
Operand length = ToOperand(instr->length());
|
||||
if (instr->index()->IsConstantOperand()) {
|
||||
int constant_index =
|
||||
int32_t constant_index =
|
||||
ToInteger32(LConstantOperand::cast(instr->index()));
|
||||
if (instr->hydrogen()->length()->representation().IsSmi()) {
|
||||
__ Cmp(length, Smi::FromInt(constant_index));
|
||||
@ -4400,7 +4397,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
|
||||
// DoStringCharCodeAt above.
|
||||
STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
|
||||
if (instr->index()->IsConstantOperand()) {
|
||||
int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
|
||||
int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
|
||||
__ Push(Smi::FromInt(const_index));
|
||||
} else {
|
||||
Register index = ToRegister(instr->index());
|
||||
|
@ -102,7 +102,6 @@ class LCodeGen BASE_EMBEDDED {
|
||||
XMMRegister ToDoubleRegister(LOperand* op) const;
|
||||
bool IsInteger32Constant(LConstantOperand* op) const;
|
||||
bool IsSmiConstant(LConstantOperand* op) const;
|
||||
int ToRepresentation(LConstantOperand* op, const Representation& r) const;
|
||||
int32_t ToInteger32(LConstantOperand* op) const;
|
||||
Smi* ToSmi(LConstantOperand* op) const;
|
||||
double ToDouble(LConstantOperand* op) const;
|
||||
|
@ -1321,16 +1321,6 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
|
||||
ASSERT(instr->value()->representation().IsInteger32());
|
||||
ASSERT(instr->representation().IsInteger32());
|
||||
if (instr->HasNoUses()) return NULL;
|
||||
LOperand* input = UseRegisterAtStart(instr->value());
|
||||
LBitNotI* result = new(zone()) LBitNotI(input);
|
||||
return DefineSameAsFirst(result);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
|
||||
if (instr->representation().IsDouble()) {
|
||||
return DoArithmeticD(Token::DIV, instr);
|
||||
|
@ -50,7 +50,6 @@ class LCodeGen;
|
||||
V(ArithmeticD) \
|
||||
V(ArithmeticT) \
|
||||
V(BitI) \
|
||||
V(BitNotI) \
|
||||
V(BoundsCheck) \
|
||||
V(Branch) \
|
||||
V(CallConstantFunction) \
|
||||
@ -1311,18 +1310,6 @@ class LThrow: public LTemplateInstruction<0, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LBitNotI: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LBitNotI(LOperand* value) {
|
||||
inputs_[0] = value;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i")
|
||||
};
|
||||
|
||||
|
||||
class LAddI: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LAddI(LOperand* left, LOperand* right) {
|
||||
|
Loading…
Reference in New Issue
Block a user