}
-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) {
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());
}
-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);
V(ArithmeticD) \
V(ArithmeticT) \
V(BitI) \
- V(BitNotI) \
V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \
};
-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) {
__ 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();
}
-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);
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;
}
-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.
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_; }
BailoutId MaterializeTrueId() { return materialize_true_id_; }
BailoutId MaterializeFalseId() { return materialize_false_id_; }
- TypeFeedbackId UnaryOperationFeedbackId() const { return reuse(id()); }
-
virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
protected:
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) \
}
-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();
}
-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.
#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;
#define CODE_STUB_LIST_ALL_PLATFORMS(V) \
V(CallFunction) \
V(CallConstruct) \
- V(UnaryOp) \
V(BinaryOp) \
V(StringAdd) \
V(SubString) \
};
-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.
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())) {
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);
}
+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.
!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;
}
V(ArgumentsLength) \
V(ArgumentsObject) \
V(Bitwise) \
- V(BitNot) \
V(BlockEntry) \
V(BoundsCheck) \
V(BoundsCheckBaseIndexInformation) \
};
-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,
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.
}
-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,
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();
}
}
-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());
ElementsKind kind,
int length);
- HInstruction* BuildUnaryMathOp(
- HValue* value, Handle<Type> type, Token::Value token);
-
void BuildCompareNil(
HValue* value,
Handle<Type> type,
void VisitDelete(UnaryOperation* expr);
void VisitVoid(UnaryOperation* expr);
void VisitTypeof(UnaryOperation* expr);
- void VisitBitNot(UnaryOperation* expr);
void VisitNot(UnaryOperation* expr);
void VisitComma(BinaryOperation* expr);
}
-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) {
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());
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);
__ 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();
}
-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));
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;
}
-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);
V(ArithmeticD) \
V(ArithmeticT) \
V(BitI) \
- V(BitNotI) \
V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \
};
-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) {
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
}
-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);
};
-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:
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
// 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:
}
-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) {
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());
__ 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();
}
-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);
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;
}
-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);
V(ArithmeticD) \
V(ArithmeticT) \
V(BitI) \
- V(BitNotI) \
V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \
};
-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) {
int Code::major_key() {
ASSERT(kind() == STUB ||
- kind() == UNARY_OP_IC ||
kind() == BINARY_OP_IC ||
kind() == COMPARE_IC ||
kind() == COMPARE_NIL_IC ||
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 ||
}
-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();
}
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) \
// 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.
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; }
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();
// 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;
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,
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);
}
-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);
F(NumberOr, 2, 1) \
F(NumberAnd, 2, 1) \
F(NumberXor, 2, 1) \
- F(NumberNot, 1, 1) \
\
F(NumberShl, 2, 1) \
F(NumberShr, 2, 1) \
}
-// 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);
}
-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,
}
break;
- case Code::UNARY_OP_IC:
case Code::BINARY_OP_IC:
case Code::COMPARE_IC:
case Code::TO_BOOLEAN_IC:
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,
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());
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;
}
-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) {
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());
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) {
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));
__ 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();
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:
}
-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);
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 {
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);
}
__ 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));
} 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));
// 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());
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;
}
-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);
V(ArithmeticD) \
V(ArithmeticT) \
V(BitI) \
- V(BitNotI) \
V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \
};
-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) {