}
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { r1, r0 };
StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
- BinaryOpStub::GenerateAheadOfTime(isolate);
+ BinaryOpICStub::GenerateAheadOfTime(isolate);
}
patch_site.EmitJumpIfSmi(scratch1, &smi_case);
__ bind(&stub_call);
- BinaryOpStub stub(op, mode);
+ BinaryOpICStub stub(op, mode);
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
expr->BinaryOperationFeedbackId());
patch_site.EmitPatchInfo();
__ bind(&smi_case);
// Smi case. This code works the same way as the smi-smi case in the type
// recording binary operation stub, see
- // BinaryOpStub::GenerateSmiSmiOperation for comments.
switch (op) {
case Token::SAR:
__ GetLeastBitsFromSmi(scratch1, right, 5);
Token::Value op,
OverwriteMode mode) {
__ pop(r1);
- BinaryOpStub stub(op, mode);
+ BinaryOpICStub stub(op, mode);
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
expr->BinaryOperationFeedbackId());
// Record position before stub call.
SetSourcePosition(expr->position());
- BinaryOpStub stub(Token::ADD, NO_OVERWRITE);
+ BinaryOpICStub stub(Token::ADD, NO_OVERWRITE);
CallIC(stub.GetCode(isolate()),
RelocInfo::CODE_TARGET,
expr->CountBinOpFeedbackId());
ASSERT(ToRegister(instr->right()).is(r0));
ASSERT(ToRegister(instr->result()).is(r0));
- BinaryOpStub stub(instr->op(), NO_OVERWRITE);
+ BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
// Block literal pool emission to ensure nop indicating no inlined smi code
// is in the correct position.
Assembler::BlockConstPoolScope block_const_pool(masm());
template <>
-HValue* CodeStubGraphBuilder<BinaryOpStub>::BuildCodeInitializedStub() {
- BinaryOpStub* stub = casted_stub();
- HValue* left = GetParameter(0);
- HValue* right = GetParameter(1);
+HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
+ BinaryOpIC::State state = casted_stub()->state();
- Handle<Type> left_type = stub->GetLeftType(isolate());
- Handle<Type> right_type = stub->GetRightType(isolate());
- Handle<Type> result_type = stub->GetResultType(isolate());
+ HValue* left = GetParameter(BinaryOpICStub::kLeft);
+ HValue* right = GetParameter(BinaryOpICStub::kRight);
+
+ Handle<Type> left_type = state.GetLeftType(isolate());
+ Handle<Type> right_type = state.GetRightType(isolate());
+ Handle<Type> result_type = state.GetResultType(isolate());
ASSERT(!left_type->Is(Type::None()) && !right_type->Is(Type::None()) &&
- (stub->HasSideEffects(isolate()) || !result_type->Is(Type::None())));
+ (state.HasSideEffects() || !result_type->Is(Type::None())));
HValue* result = NULL;
- if (stub->operation() == Token::ADD &&
+ if (state.op() == Token::ADD &&
(left_type->Maybe(Type::String()) || right_type->Maybe(Type::String())) &&
!left_type->Is(Type::String()) && !right_type->Is(Type::String())) {
// For the generic add stub a fast case for string addition is performance
if_leftisstring.Then();
{
Push(BuildBinaryOperation(
- stub->operation(), left, right,
+ state.op(), left, right,
handle(Type::String(), isolate()), right_type,
- result_type, stub->fixed_right_arg()));
+ result_type, state.fixed_right_arg()));
}
if_leftisstring.Else();
{
Push(BuildBinaryOperation(
- stub->operation(), left, right,
+ state.op(), left, right,
left_type, right_type, result_type,
- stub->fixed_right_arg()));
+ state.fixed_right_arg()));
}
if_leftisstring.End();
result = Pop();
if_rightisstring.Then();
{
Push(BuildBinaryOperation(
- stub->operation(), left, right,
+ state.op(), left, right,
left_type, handle(Type::String(), isolate()),
- result_type, stub->fixed_right_arg()));
+ result_type, state.fixed_right_arg()));
}
if_rightisstring.Else();
{
Push(BuildBinaryOperation(
- stub->operation(), left, right,
+ state.op(), left, right,
left_type, right_type, result_type,
- stub->fixed_right_arg()));
+ state.fixed_right_arg()));
}
if_rightisstring.End();
result = Pop();
}
} else {
result = BuildBinaryOperation(
- stub->operation(), left, right,
+ state.op(), left, right,
left_type, right_type, result_type,
- stub->fixed_right_arg());
+ state.fixed_right_arg());
}
// If we encounter a generic argument, the number conversion is
// observable, thus we cannot afford to bail out after the fact.
- if (!stub->HasSideEffects(isolate())) {
+ if (!state.HasSideEffects()) {
if (result_type->Is(Type::Smi())) {
- if (stub->operation() == Token::SHR) {
+ if (state.op() == Token::SHR) {
// TODO(olivf) Replace this by a SmiTagU Instruction.
// 0x40000000: this number would convert to negative when interpreting
// the register as signed value;
// Reuse the double box of one of the operands if we are allowed to (i.e.
// chained binops).
- if (stub->CanReuseDoubleBox()) {
- HValue* operand = (stub->mode() == OVERWRITE_LEFT) ? left : right;
+ if (state.CanReuseDoubleBox()) {
+ HValue* operand = (state.mode() == OVERWRITE_LEFT) ? left : right;
IfBuilder if_heap_number(this);
if_heap_number.IfNot<HIsSmiAndBranch>(operand);
if_heap_number.Then();
}
-Handle<Code> BinaryOpStub::GenerateCode(Isolate* isolate) {
+Handle<Code> BinaryOpICStub::GenerateCode(Isolate* isolate) {
return DoGenerateCode(isolate, this);
}
}
-void BinaryOpStub::PrintBaseName(StringStream* stream) {
- const char* op_name = Token::Name(op_);
- const char* ovr = "";
- if (mode_ == OVERWRITE_LEFT) ovr = "_ReuseLeft";
- if (mode_ == OVERWRITE_RIGHT) ovr = "_ReuseRight";
- stream->Add("BinaryOpStub_%s%s", op_name, ovr);
-}
-
-
-void BinaryOpStub::PrintState(StringStream* stream) {
- stream->Add("(");
- stream->Add(StateToName(left_state_));
- stream->Add("*");
- if (fixed_right_arg_.has_value) {
- stream->Add("%d", fixed_right_arg_.value);
- } else {
- stream->Add(StateToName(right_state_));
- }
- stream->Add("->");
- stream->Add(StateToName(result_state_));
- stream->Add(")");
-}
-
-
-Maybe<Handle<Object> > BinaryOpStub::Result(Handle<Object> left,
- Handle<Object> right,
- Isolate* isolate) {
- Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
- Builtins::JavaScript func = BinaryOpIC::TokenToJSBuiltin(op_);
- Object* builtin = builtins->javascript_builtin(func);
- Handle<JSFunction> builtin_function =
- Handle<JSFunction>(JSFunction::cast(builtin), isolate);
- bool caught_exception;
- Handle<Object> result = Execution::Call(isolate, builtin_function, left,
- 1, &right, &caught_exception);
- return Maybe<Handle<Object> >(!caught_exception, result);
-}
-
-
-void BinaryOpStub::Initialize() {
- fixed_right_arg_.has_value = false;
- left_state_ = right_state_ = result_state_ = NONE;
-}
-
-
-void BinaryOpStub::Generate(Token::Value op,
- State left,
- State right,
- State result,
- OverwriteMode mode,
- Isolate* isolate) {
- BinaryOpStub stub(INITIALIZED);
- stub.op_ = op;
- stub.left_state_ = left;
- stub.right_state_ = right;
- stub.result_state_ = result;
- stub.mode_ = mode;
- stub.GetCode(isolate);
-}
-
-
-void BinaryOpStub::Generate(Token::Value op,
- State left,
- int right,
- State result,
- OverwriteMode mode,
- Isolate* isolate) {
- BinaryOpStub stub(INITIALIZED);
- stub.op_ = op;
- stub.left_state_ = left;
- stub.fixed_right_arg_.has_value = true;
- stub.fixed_right_arg_.value = right;
- stub.right_state_ = SMI;
- stub.result_state_ = result;
- stub.mode_ = mode;
- stub.GetCode(isolate);
-}
-
-
-void BinaryOpStub::GenerateAheadOfTime(Isolate* isolate) {
- Token::Value binop[] = {Token::SUB, Token::MOD, Token::DIV, Token::MUL,
- Token::ADD, Token::SAR, Token::BIT_OR, Token::BIT_AND,
- Token::BIT_XOR, Token::SHL, Token::SHR};
- for (unsigned i = 0; i < ARRAY_SIZE(binop); i++) {
- BinaryOpStub stub(UNINITIALIZED);
- stub.op_ = binop[i];
- stub.GetCode(isolate);
- }
-
- // TODO(olivf) We should investigate why adding stubs to the snapshot is so
- // expensive at runtime. When solved we should be able to add most binops to
- // the snapshot instead of hand-picking them.
- // Generated list of commonly used stubs
- Generate(Token::ADD, INT32, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::ADD, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, INT32, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::ADD, INT32, INT32, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, INT32, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::ADD, INT32, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::ADD, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::ADD, NUMBER, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::ADD, NUMBER, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::ADD, NUMBER, SMI, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::ADD, SMI, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::ADD, SMI, INT32, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, SMI, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::ADD, SMI, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_AND, INT32, INT32, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_AND, INT32, INT32, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_AND, INT32, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_AND, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_AND, INT32, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_AND, NUMBER, INT32, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_AND, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_AND, NUMBER, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_AND, SMI, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_AND, SMI, INT32, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_AND, SMI, NUMBER, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_AND, SMI, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_OR, INT32, INT32, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_OR, INT32, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_OR, INT32, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_OR, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_OR, NUMBER, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_OR, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_OR, NUMBER, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_OR, SMI, INT32, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_XOR, INT32, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_XOR, INT32, INT32, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_XOR, INT32, INT32, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_XOR, INT32, NUMBER, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_XOR, INT32, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::BIT_XOR, NUMBER, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_XOR, NUMBER, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_XOR, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_XOR, SMI, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::BIT_XOR, SMI, INT32, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_XOR, SMI, INT32, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_XOR, SMI, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::DIV, INT32, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::DIV, INT32, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::DIV, INT32, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::DIV, INT32, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::DIV, INT32, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::DIV, INT32, SMI, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::DIV, NUMBER, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::DIV, NUMBER, INT32, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::DIV, NUMBER, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::DIV, NUMBER, SMI, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::DIV, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::DIV, SMI, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::DIV, SMI, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::DIV, SMI, INT32, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::DIV, SMI, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::DIV, SMI, SMI, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::DIV, SMI, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::DIV, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::DIV, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::MOD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::MOD, SMI, 16, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::MOD, SMI, 2, SMI, NO_OVERWRITE, isolate);
- Generate(Token::MOD, SMI, 2048, SMI, NO_OVERWRITE, isolate);
- Generate(Token::MOD, SMI, 32, SMI, NO_OVERWRITE, isolate);
- Generate(Token::MOD, SMI, 4, SMI, NO_OVERWRITE, isolate);
- Generate(Token::MOD, SMI, 4, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::MOD, SMI, 8, SMI, NO_OVERWRITE, isolate);
- Generate(Token::MOD, SMI, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::MOD, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, INT32, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::MUL, INT32, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::MUL, INT32, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::MUL, INT32, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, INT32, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::MUL, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, INT32, SMI, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::MUL, NUMBER, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::MUL, NUMBER, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::MUL, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, NUMBER, SMI, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::MUL, SMI, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::MUL, SMI, INT32, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, SMI, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::MUL, SMI, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::MUL, SMI, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::MUL, SMI, SMI, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::MUL, SMI, SMI, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, SMI, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::MUL, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::MUL, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::SAR, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::SAR, INT32, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::SAR, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::SAR, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::SAR, NUMBER, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::SAR, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::SAR, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::SHL, INT32, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::SHL, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::SHL, INT32, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::SHL, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::SHL, NUMBER, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::SHL, SMI, SMI, INT32, NO_OVERWRITE, isolate);
- Generate(Token::SHL, SMI, SMI, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::SHL, SMI, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::SHL, SMI, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::SHL, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::SHL, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::SHR, INT32, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::SHR, INT32, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::SHR, INT32, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::SHR, NUMBER, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::SHR, NUMBER, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::SHR, NUMBER, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::SHR, SMI, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::SHR, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::SHR, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
- Generate(Token::SUB, INT32, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::SUB, INT32, INT32, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::SUB, INT32, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::SUB, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::SUB, INT32, SMI, INT32, OVERWRITE_LEFT, isolate);
- Generate(Token::SUB, INT32, SMI, INT32, OVERWRITE_RIGHT, isolate);
- Generate(Token::SUB, NUMBER, INT32, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::SUB, NUMBER, INT32, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::SUB, NUMBER, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::SUB, NUMBER, SMI, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::SUB, SMI, INT32, INT32, NO_OVERWRITE, isolate);
- Generate(Token::SUB, SMI, NUMBER, NUMBER, NO_OVERWRITE, isolate);
- Generate(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_LEFT, isolate);
- Generate(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT, isolate);
- Generate(Token::SUB, SMI, SMI, SMI, NO_OVERWRITE, isolate);
- Generate(Token::SUB, SMI, SMI, SMI, OVERWRITE_LEFT, isolate);
- Generate(Token::SUB, SMI, SMI, SMI, OVERWRITE_RIGHT, isolate);
-}
-
-
-bool BinaryOpStub::can_encode_arg_value(int32_t value) const {
- return op_ == Token::MOD && value > 0 && IsPowerOf2(value) &&
- FixedRightArgValueBits::is_valid(WhichPowerOf2(value));
-}
-
-
-int BinaryOpStub::encode_arg_value(int32_t value) const {
- ASSERT(can_encode_arg_value(value));
- return WhichPowerOf2(value);
-}
-
-
-int32_t BinaryOpStub::decode_arg_value(int value) const {
- return 1 << value;
-}
-
-
-int BinaryOpStub::encode_token(Token::Value op) const {
- ASSERT(op >= FIRST_TOKEN && op <= LAST_TOKEN);
- return op - FIRST_TOKEN;
-}
-
-
-Token::Value BinaryOpStub::decode_token(int op) const {
- int res = op + FIRST_TOKEN;
- ASSERT(res >= FIRST_TOKEN && res <= LAST_TOKEN);
- return static_cast<Token::Value>(res);
-}
-
-
-const char* BinaryOpStub::StateToName(State state) {
- switch (state) {
- case NONE:
- return "None";
- case SMI:
- return "Smi";
- case INT32:
- return "Int32";
- case NUMBER:
- return "Number";
- case STRING:
- return "String";
- case GENERIC:
- return "Generic";
- }
- return "";
-}
-
-
-void BinaryOpStub::UpdateStatus(Handle<Object> left,
- Handle<Object> right,
- Maybe<Handle<Object> > result) {
- int old_state = GetExtraICState();
-
- UpdateStatus(left, &left_state_);
- UpdateStatus(right, &right_state_);
-
- int32_t value;
- bool new_has_fixed_right_arg =
- right->ToInt32(&value) && can_encode_arg_value(value) &&
- (left_state_ == SMI || left_state_ == INT32) &&
- (result_state_ == NONE || !fixed_right_arg_.has_value);
-
- fixed_right_arg_ = Maybe<int32_t>(new_has_fixed_right_arg, value);
-
- if (result.has_value) UpdateStatus(result.value, &result_state_);
-
- State max_input = Max(left_state_, right_state_);
-
- if (!has_int_result() && op_ != Token::SHR &&
- max_input <= NUMBER && max_input > result_state_) {
- result_state_ = max_input;
- }
-
- ASSERT(result_state_ <= (has_int_result() ? INT32 : NUMBER) ||
- op_ == Token::ADD);
-
- // Reset overwrite mode unless we can actually make use of it, or may be able
- // to make use of it at some point in the future.
- if ((mode_ == OVERWRITE_LEFT && left_state_ > NUMBER) ||
- (mode_ == OVERWRITE_RIGHT && right_state_ > NUMBER) ||
- result_state_ > NUMBER) {
- mode_ = NO_OVERWRITE;
- }
-
- if (old_state == GetExtraICState()) {
- // Tagged operations can lead to non-truncating HChanges
- if (left->IsUndefined() || left->IsBoolean()) {
- left_state_ = GENERIC;
- } else if (right->IsUndefined() || right->IsBoolean()) {
- right_state_ = GENERIC;
- } else {
- // Since the fpu is to precise, we might bail out on numbers which
- // actually would truncate with 64 bit precision.
- ASSERT(!CpuFeatures::IsSupported(SSE2) &&
- result_state_ <= INT32);
- result_state_ = NUMBER;
+// static
+void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
+ // Generate the uninitialized versions of the stub.
+ for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
+ for (int mode = NO_OVERWRITE; mode <= OVERWRITE_RIGHT; ++mode) {
+ BinaryOpICStub stub(static_cast<Token::Value>(op),
+ static_cast<OverwriteMode>(mode));
+ stub.GetCode(isolate);
}
}
-}
-
-
-void BinaryOpStub::UpdateStatus(Handle<Object> object,
- State* state) {
- bool is_truncating = (op_ == Token::BIT_AND || op_ == Token::BIT_OR ||
- op_ == Token::BIT_XOR || op_ == Token::SAR ||
- op_ == Token::SHL || op_ == Token::SHR);
- v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(object);
- if (object->IsBoolean() && is_truncating) {
- // Booleans are converted by truncating by HChange.
- type = TypeInfo::Integer32();
- }
- if (object->IsUndefined()) {
- // Undefined will be automatically truncated for us by HChange.
- type = is_truncating ? TypeInfo::Integer32() : TypeInfo::Double();
- }
- State int_state = SmiValuesAre32Bits() ? NUMBER : INT32;
- State new_state = NONE;
- if (type.IsSmi()) {
- new_state = SMI;
- } else if (type.IsInteger32()) {
- new_state = int_state;
- } else if (type.IsNumber()) {
- new_state = NUMBER;
- } else if (object->IsString() && operation() == Token::ADD) {
- new_state = STRING;
- } else {
- new_state = GENERIC;
- }
- if ((new_state <= NUMBER && *state > NUMBER) ||
- (new_state > NUMBER && *state <= NUMBER && *state != NONE)) {
- new_state = GENERIC;
- }
- *state = Max(*state, new_state);
-}
-
-
-Handle<Type> BinaryOpStub::StateToType(State state,
- Isolate* isolate) {
- Handle<Type> t = handle(Type::None(), isolate);
- switch (state) {
- case NUMBER:
- t = handle(Type::Union(t, handle(Type::Double(), isolate)), isolate);
- // Fall through.
- case INT32:
- t = handle(Type::Union(t, handle(Type::Signed32(), isolate)), isolate);
- // Fall through.
- case SMI:
- t = handle(Type::Union(t, handle(Type::Smi(), isolate)), isolate);
- break;
- case STRING:
- t = handle(Type::Union(t, handle(Type::String(), isolate)), isolate);
- break;
- case GENERIC:
- return handle(Type::Any(), isolate);
- break;
- case NONE:
- break;
- }
- return t;
+ // Generate special versions of the stub.
+ BinaryOpIC::State::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
}
-Handle<Type> BinaryOpStub::GetLeftType(Isolate* isolate) const {
- return StateToType(left_state_, isolate);
-}
-
-
-Handle<Type> BinaryOpStub::GetRightType(Isolate* isolate) const {
- return StateToType(right_state_, isolate);
+void BinaryOpICStub::PrintState(StringStream* stream) {
+ state_.Print(stream);
}
-Handle<Type> BinaryOpStub::GetResultType(Isolate* isolate) const {
- if (HasSideEffects(isolate)) return StateToType(NONE, isolate);
- if (result_state_ == GENERIC && op_ == Token::ADD) {
- return handle(Type::Union(handle(Type::Number(), isolate),
- handle(Type::String(), isolate)), isolate);
- }
- ASSERT(result_state_ != GENERIC);
- if (result_state_ == NUMBER && op_ == Token::SHR) {
- return handle(Type::Unsigned32(), isolate);
- }
- return StateToType(result_state_, isolate);
+// static
+void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
+ const BinaryOpIC::State& state) {
+ BinaryOpICStub stub(state);
+ stub.GetCode(isolate);
}
// static
+void BinaryOpICStub::InstallDescriptors(Isolate* isolate) {
+ BinaryOpICStub stub(Token::ADD, NO_OVERWRITE);
+ InstallDescriptor(isolate, &stub);
+}
+
+
+// static
void NewStringAddStub::InstallDescriptors(Isolate* isolate) {
NewStringAddStub stub(STRING_ADD_CHECK_NONE, NOT_TENURED);
InstallDescriptor(isolate, &stub);
#define CODE_STUB_LIST_ALL_PLATFORMS(V) \
V(CallFunction) \
V(CallConstruct) \
- V(BinaryOp) \
+ V(BinaryOpIC) \
V(StringAdd) \
V(NewStringAdd) \
V(SubString) \
CODE_STUB_LIST_ARM(V) \
CODE_STUB_LIST_MIPS(V)
-// Mode to overwrite BinaryExpression values.
-enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
-
// Stub is base classes of all stubs.
class CodeStub BASE_EMBEDDED {
public:
};
-class BinaryOpStub: public HydrogenCodeStub {
+class BinaryOpICStub V8_FINAL : public HydrogenCodeStub {
public:
- BinaryOpStub(Token::Value op, OverwriteMode mode)
- : HydrogenCodeStub(UNINITIALIZED), op_(op), mode_(mode) {
- ASSERT(op <= LAST_TOKEN && op >= FIRST_TOKEN);
- Initialize();
- }
+ BinaryOpICStub(Token::Value op, OverwriteMode mode)
+ : HydrogenCodeStub(UNINITIALIZED), state_(op, mode) {}
- explicit BinaryOpStub(ExtraICState state)
- : op_(decode_token(OpBits::decode(state))),
- mode_(OverwriteModeField::decode(state)),
- fixed_right_arg_(
- Maybe<int>(HasFixedRightArgBits::decode(state),
- decode_arg_value(FixedRightArgValueBits::decode(state)))),
- left_state_(LeftStateField::decode(state)),
- right_state_(fixed_right_arg_.has_value
- ? ((fixed_right_arg_.value <= Smi::kMaxValue) ? SMI : INT32)
- : RightStateField::decode(state)),
- result_state_(ResultStateField::decode(state)) {
- // We don't deserialize the SSE2 Field, since this is only used to be able
- // to include SSE2 as well as non-SSE2 versions in the snapshot. For code
- // generation we always want it to reflect the current state.
- ASSERT(!fixed_right_arg_.has_value ||
- can_encode_arg_value(fixed_right_arg_.value));
- }
-
- static const int FIRST_TOKEN = Token::BIT_OR;
- static const int LAST_TOKEN = Token::MOD;
+ explicit BinaryOpICStub(const BinaryOpIC::State& state) : state_(state) {}
static void GenerateAheadOfTime(Isolate* isolate);
+
virtual void InitializeInterfaceDescriptor(
- Isolate* isolate, CodeStubInterfaceDescriptor* descriptor);
- static void InitializeForIsolate(Isolate* isolate) {
- BinaryOpStub binopStub(UNINITIALIZED);
- binopStub.InitializeInterfaceDescriptor(
- isolate, isolate->code_stub_interface_descriptor(CodeStub::BinaryOp));
- }
+ Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE;
- virtual Code::Kind GetCodeKind() const { return Code::BINARY_OP_IC; }
- virtual InlineCacheState GetICState() {
- if (Max(left_state_, right_state_) == NONE) {
- return ::v8::internal::UNINITIALIZED;
- }
- if (Max(left_state_, right_state_) == GENERIC) return MEGAMORPHIC;
- return MONOMORPHIC;
- }
+ static void InstallDescriptors(Isolate* isolate);
- virtual void VerifyPlatformFeatures(Isolate* isolate) V8_OVERRIDE {
- ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
+ virtual Code::Kind GetCodeKind() const V8_OVERRIDE {
+ return Code::BINARY_OP_IC;
}
- virtual ExtraICState GetExtraICState() {
- bool sse_field = Max(result_state_, Max(left_state_, right_state_)) > SMI &&
- CpuFeatures::IsSafeForSnapshot(SSE2);
-
- return OpBits::encode(encode_token(op_))
- | LeftStateField::encode(left_state_)
- | RightStateField::encode(fixed_right_arg_.has_value
- ? NONE : right_state_)
- | ResultStateField::encode(result_state_)
- | HasFixedRightArgBits::encode(fixed_right_arg_.has_value)
- | FixedRightArgValueBits::encode(fixed_right_arg_.has_value
- ? encode_arg_value(
- fixed_right_arg_.value)
- : 0)
- | SSE2Field::encode(sse_field)
- | OverwriteModeField::encode(mode_);
+ virtual InlineCacheState GetICState() V8_OVERRIDE {
+ return state_.GetICState();
}
- bool CanReuseDoubleBox() {
- return result_state_ <= NUMBER && result_state_ > SMI &&
- ((left_state_ > SMI && left_state_ <= NUMBER &&
- mode_ == OVERWRITE_LEFT) ||
- (right_state_ > SMI && right_state_ <= NUMBER &&
- mode_ == OVERWRITE_RIGHT));
+ virtual ExtraICState GetExtraICState() V8_OVERRIDE {
+ return state_.GetExtraICState();
}
- bool HasSideEffects(Isolate* isolate) const {
- Handle<Type> left = GetLeftType(isolate);
- Handle<Type> right = GetRightType(isolate);
- return left->Maybe(Type::Receiver()) || right->Maybe(Type::Receiver());
+ virtual void VerifyPlatformFeatures(Isolate* isolate) V8_OVERRIDE {
+ ASSERT(CpuFeatures::VerifyCrossCompiling(SSE2));
}
- virtual Handle<Code> GenerateCode(Isolate* isolate);
-
- Maybe<Handle<Object> > Result(Handle<Object> left,
- Handle<Object> right,
- Isolate* isolate);
-
- Token::Value operation() const { return op_; }
- OverwriteMode mode() const { return mode_; }
- Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
+ virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
- Handle<Type> GetLeftType(Isolate* isolate) const;
- Handle<Type> GetRightType(Isolate* isolate) const;
- Handle<Type> GetResultType(Isolate* isolate) const;
+ const BinaryOpIC::State& state() const { return state_; }
- void UpdateStatus(Handle<Object> left,
- Handle<Object> right,
- Maybe<Handle<Object> > result);
+ virtual void PrintState(StringStream* stream) V8_OVERRIDE;
- void PrintState(StringStream* stream);
+ // Parameters accessed via CodeStubGraphBuilder::GetParameter()
+ static const int kLeft = 0;
+ static const int kRight = 1;
private:
- explicit BinaryOpStub(InitializationState state) : HydrogenCodeStub(state),
- op_(Token::ADD),
- mode_(NO_OVERWRITE) {
- Initialize();
- }
- void Initialize();
-
- enum State { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
-
- // We truncate the last bit of the token.
- STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 5));
- class LeftStateField: public BitField<State, 0, 3> {};
- // When fixed right arg is set, we don't need to store the right state.
- // Thus the two fields can overlap.
- class HasFixedRightArgBits: public BitField<bool, 4, 1> {};
- class FixedRightArgValueBits: public BitField<int, 5, 4> {};
- class RightStateField: public BitField<State, 5, 3> {};
- class ResultStateField: public BitField<State, 9, 3> {};
- class SSE2Field: public BitField<bool, 12, 1> {};
- class OverwriteModeField: public BitField<OverwriteMode, 13, 2> {};
- class OpBits: public BitField<int, 15, 5> {};
-
- virtual CodeStub::Major MajorKey() { return BinaryOp; }
- virtual int NotMissMinorKey() { return GetExtraICState(); }
-
- static Handle<Type> StateToType(State state,
- Isolate* isolate);
-
- static void Generate(Token::Value op,
- State left,
- int right,
- State result,
- OverwriteMode mode,
- Isolate* isolate);
-
- static void Generate(Token::Value op,
- State left,
- State right,
- State result,
- OverwriteMode mode,
- Isolate* isolate);
+ static void GenerateAheadOfTime(Isolate* isolate,
+ const BinaryOpIC::State& state);
- void UpdateStatus(Handle<Object> object,
- State* state);
+ virtual Major MajorKey() V8_OVERRIDE { return BinaryOpIC; }
+ virtual int NotMissMinorKey() V8_OVERRIDE { return GetExtraICState(); }
- bool can_encode_arg_value(int32_t value) const;
- int encode_arg_value(int32_t value) const;
- int32_t decode_arg_value(int value) const;
- int encode_token(Token::Value op) const;
- Token::Value decode_token(int op) const;
-
- bool has_int_result() const {
- return op_ == Token::BIT_XOR || op_ == Token::BIT_AND ||
- op_ == Token::BIT_OR || op_ == Token::SAR || op_ == Token::SHL;
- }
-
- const char* StateToName(State state);
-
- void PrintBaseName(StringStream* stream);
-
- Token::Value op_;
- OverwriteMode mode_;
+ BinaryOpIC::State state_;
- Maybe<int> fixed_right_arg_;
- State left_state_;
- State right_state_;
- State result_state_;
+ DISALLOW_COPY_AND_ASSIGN(BinaryOpICStub);
};
}
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { edx, eax };
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
if (Serializer::enabled()) {
PlatformFeatureScope sse2(SSE2);
- BinaryOpStub::GenerateAheadOfTime(isolate);
+ BinaryOpICStub::GenerateAheadOfTime(isolate);
} else {
- BinaryOpStub::GenerateAheadOfTime(isolate);
+ BinaryOpICStub::GenerateAheadOfTime(isolate);
}
}
__ bind(&stub_call);
__ mov(eax, ecx);
- BinaryOpStub stub(op, mode);
+ BinaryOpICStub stub(op, mode);
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
expr->BinaryOperationFeedbackId());
patch_site.EmitPatchInfo();
Token::Value op,
OverwriteMode mode) {
__ pop(edx);
- BinaryOpStub stub(op, mode);
+ BinaryOpICStub stub(op, mode);
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
expr->BinaryOperationFeedbackId());
__ bind(&stub_call);
__ mov(edx, eax);
__ mov(eax, Immediate(Smi::FromInt(1)));
- BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
+ BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE);
CallIC(stub.GetCode(isolate()),
RelocInfo::CODE_TARGET,
expr->CountBinOpFeedbackId());
ASSERT(ToRegister(instr->right()).is(eax));
ASSERT(ToRegister(instr->result()).is(eax));
- BinaryOpStub stub(instr->op(), NO_OVERWRITE);
+ BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
__ nop(); // Signals no inlined code.
}
}
-const char* BinaryOpIC::GetName(TypeInfo type_info) {
- switch (type_info) {
- case UNINITIALIZED: return "Uninitialized";
+BinaryOpIC::State::State(ExtraICState extra_ic_state) {
+ // We don't deserialize the SSE2 Field, since this is only used to be able
+ // to include SSE2 as well as non-SSE2 versions in the snapshot. For code
+ // generation we always want it to reflect the current state.
+ op_ = static_cast<Token::Value>(
+ FIRST_TOKEN + OpField::decode(extra_ic_state));
+ mode_ = OverwriteModeField::decode(extra_ic_state);
+ fixed_right_arg_ = Maybe<int>(
+ HasFixedRightArgField::decode(extra_ic_state),
+ 1 << FixedRightArgValueField::decode(extra_ic_state));
+ left_kind_ = LeftKindField::decode(extra_ic_state);
+ if (fixed_right_arg_.has_value) {
+ right_kind_ = Smi::IsValid(fixed_right_arg_.value) ? SMI : INT32;
+ } else {
+ right_kind_ = RightKindField::decode(extra_ic_state);
+ }
+ result_kind_ = ResultKindField::decode(extra_ic_state);
+ ASSERT_LE(FIRST_TOKEN, op_);
+ ASSERT_LE(op_, LAST_TOKEN);
+}
+
+
+ExtraICState BinaryOpIC::State::GetExtraICState() const {
+ bool sse2 = (Max(result_kind_, Max(left_kind_, right_kind_)) > SMI &&
+ CpuFeatures::IsSafeForSnapshot(SSE2));
+ ExtraICState extra_ic_state =
+ SSE2Field::encode(sse2) |
+ OpField::encode(op_ - FIRST_TOKEN) |
+ OverwriteModeField::encode(mode_) |
+ LeftKindField::encode(left_kind_) |
+ ResultKindField::encode(result_kind_) |
+ HasFixedRightArgField::encode(fixed_right_arg_.has_value);
+ if (fixed_right_arg_.has_value) {
+ extra_ic_state = FixedRightArgValueField::update(
+ extra_ic_state, WhichPowerOf2(fixed_right_arg_.value));
+ } else {
+ extra_ic_state = RightKindField::update(extra_ic_state, right_kind_);
+ }
+ return extra_ic_state;
+}
+
+
+// static
+void BinaryOpIC::State::GenerateAheadOfTime(
+ Isolate* isolate, void (*Generate)(Isolate*, const State&)) {
+ // TODO(olivf) We should investigate why adding stubs to the snapshot is so
+ // expensive at runtime. When solved we should be able to add most binops to
+ // the snapshot instead of hand-picking them.
+ // Generated list of commonly used stubs
+#define GENERATE(op, left_kind, right_kind, result_kind, mode) \
+ do { \
+ State state(op, mode); \
+ state.left_kind_ = left_kind; \
+ state.fixed_right_arg_.has_value = false; \
+ state.right_kind_ = right_kind; \
+ state.result_kind_ = result_kind; \
+ Generate(isolate, state); \
+ } while (false)
+ GENERATE(Token::ADD, INT32, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::ADD, INT32, INT32, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, INT32, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::ADD, INT32, INT32, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, INT32, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::ADD, INT32, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::ADD, NUMBER, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::ADD, NUMBER, SMI, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::ADD, SMI, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::ADD, SMI, INT32, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, SMI, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::ADD, SMI, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_AND, INT32, INT32, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_AND, INT32, INT32, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_AND, INT32, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_AND, INT32, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_AND, INT32, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_AND, NUMBER, INT32, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_AND, SMI, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_AND, SMI, INT32, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_AND, SMI, NUMBER, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_AND, SMI, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_OR, INT32, INT32, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_OR, INT32, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_OR, INT32, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_OR, INT32, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_OR, SMI, INT32, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_XOR, INT32, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_XOR, INT32, INT32, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_XOR, INT32, INT32, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_XOR, INT32, NUMBER, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_XOR, INT32, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::BIT_XOR, NUMBER, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_XOR, NUMBER, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_XOR, NUMBER, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_XOR, SMI, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::BIT_XOR, SMI, INT32, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_XOR, SMI, INT32, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_XOR, SMI, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::DIV, INT32, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::DIV, INT32, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::DIV, INT32, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::DIV, INT32, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::DIV, INT32, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::DIV, INT32, SMI, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::DIV, NUMBER, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::DIV, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::DIV, NUMBER, SMI, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::DIV, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::DIV, SMI, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::DIV, SMI, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::DIV, SMI, INT32, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::DIV, SMI, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::DIV, SMI, SMI, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::DIV, SMI, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::MOD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::MOD, SMI, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::MOD, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, INT32, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::MUL, INT32, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::MUL, INT32, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::MUL, INT32, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, INT32, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::MUL, INT32, SMI, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, INT32, SMI, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::MUL, NUMBER, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, NUMBER, SMI, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::MUL, SMI, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::MUL, SMI, INT32, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, SMI, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::MUL, SMI, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::MUL, SMI, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::MUL, SMI, SMI, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::MUL, SMI, SMI, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, SMI, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::SAR, INT32, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::SAR, INT32, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::SAR, INT32, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::SAR, NUMBER, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::SAR, NUMBER, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::SHL, INT32, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::SHL, INT32, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::SHL, INT32, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::SHL, INT32, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::SHL, NUMBER, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::SHL, SMI, SMI, INT32, NO_OVERWRITE);
+ GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::SHL, SMI, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::SHR, INT32, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::SHR, NUMBER, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::SHR, NUMBER, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::SHR, NUMBER, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::SHR, SMI, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_RIGHT);
+ GENERATE(Token::SUB, INT32, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::SUB, INT32, INT32, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::SUB, INT32, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::SUB, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_LEFT);
+ GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_RIGHT);
+ GENERATE(Token::SUB, NUMBER, INT32, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::SUB, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::SUB, NUMBER, SMI, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::SUB, SMI, INT32, INT32, NO_OVERWRITE);
+ GENERATE(Token::SUB, SMI, NUMBER, NUMBER, NO_OVERWRITE);
+ GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
+ GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
+ GENERATE(Token::SUB, SMI, SMI, SMI, NO_OVERWRITE);
+ GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_RIGHT);
+#undef GENERATE
+#define GENERATE(op, left_kind, fixed_right_arg_value, result_kind, mode) \
+ do { \
+ State state(op, mode); \
+ state.left_kind_ = left_kind; \
+ state.fixed_right_arg_.has_value = true; \
+ state.fixed_right_arg_.value = fixed_right_arg_value; \
+ state.right_kind_ = SMI; \
+ state.result_kind_ = result_kind; \
+ Generate(isolate, state); \
+ } while (false)
+ GENERATE(Token::MOD, SMI, 2, SMI, NO_OVERWRITE);
+ GENERATE(Token::MOD, SMI, 4, SMI, NO_OVERWRITE);
+ GENERATE(Token::MOD, SMI, 4, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::MOD, SMI, 8, SMI, NO_OVERWRITE);
+ GENERATE(Token::MOD, SMI, 16, SMI, OVERWRITE_LEFT);
+ GENERATE(Token::MOD, SMI, 32, SMI, NO_OVERWRITE);
+ GENERATE(Token::MOD, SMI, 2048, SMI, NO_OVERWRITE);
+#undef GENERATE
+}
+
+
+Handle<Type> BinaryOpIC::State::GetResultType(Isolate* isolate) const {
+ Kind result_kind = result_kind_;
+ if (HasSideEffects()) {
+ result_kind = NONE;
+ } else if (result_kind == GENERIC && op_ == Token::ADD) {
+ return handle(Type::Union(handle(Type::Number(), isolate),
+ handle(Type::String(), isolate)), isolate);
+ } else if (result_kind == NUMBER && op_ == Token::SHR) {
+ return handle(Type::Unsigned32(), isolate);
+ }
+ ASSERT_NE(GENERIC, result_kind);
+ return KindToType(result_kind, isolate);
+}
+
+
+void BinaryOpIC::State::Print(StringStream* stream) const {
+ stream->Add("(%s", Token::Name(op_));
+ if (mode_ == OVERWRITE_LEFT) stream->Add("_ReuseLeft");
+ else if (mode_ == OVERWRITE_RIGHT) stream->Add("_ReuseRight");
+ stream->Add(":%s*", KindToString(left_kind_));
+ if (fixed_right_arg_.has_value) {
+ stream->Add("%d", fixed_right_arg_.value);
+ } else {
+ stream->Add("%s", KindToString(right_kind_));
+ }
+ stream->Add("->%s)", KindToString(result_kind_));
+}
+
+
+void BinaryOpIC::State::Update(Handle<Object> left,
+ Handle<Object> right,
+ Handle<Object> result) {
+ ExtraICState old_extra_ic_state = GetExtraICState();
+
+ left_kind_ = UpdateKind(left, left_kind_);
+ right_kind_ = UpdateKind(right, right_kind_);
+
+ int32_t fixed_right_arg_value;
+ bool has_fixed_right_arg =
+ op_ == Token::MOD &&
+ right->ToInt32(&fixed_right_arg_value) &&
+ fixed_right_arg_value > 0 &&
+ IsPowerOf2(fixed_right_arg_value) &&
+ FixedRightArgValueField::is_valid(fixed_right_arg_value) &&
+ (left_kind_ == SMI || left_kind_ == INT32) &&
+ (result_kind_ == NONE || !fixed_right_arg_.has_value);
+ fixed_right_arg_ = Maybe<int32_t>(has_fixed_right_arg,
+ fixed_right_arg_value);
+
+ result_kind_ = UpdateKind(result, result_kind_);
+
+ if (!Token::IsTruncatingBinaryOp(op_)) {
+ Kind input_kind = Max(left_kind_, right_kind_);
+ if (result_kind_ < input_kind && input_kind <= NUMBER) {
+ result_kind_ = input_kind;
+ }
+ }
+
+ // Reset overwrite mode unless we can actually make use of it, or may be able
+ // to make use of it at some point in the future.
+ if ((mode_ == OVERWRITE_LEFT && left_kind_ > NUMBER) ||
+ (mode_ == OVERWRITE_RIGHT && right_kind_ > NUMBER) ||
+ result_kind_ > NUMBER) {
+ mode_ = NO_OVERWRITE;
+ }
+
+ if (old_extra_ic_state == GetExtraICState()) {
+ // Tagged operations can lead to non-truncating HChanges
+ if (left->IsUndefined() || left->IsBoolean()) {
+ left_kind_ = GENERIC;
+ } else if (right->IsUndefined() || right->IsBoolean()) {
+ right_kind_ = GENERIC;
+ } else {
+ // Since the X87 is too precise, we might bail out on numbers which
+ // actually would truncate with 64 bit precision.
+ ASSERT(!CpuFeatures::IsSupported(SSE2));
+ ASSERT(result_kind_ < NUMBER);
+ result_kind_ = NUMBER;
+ }
+ }
+}
+
+
+BinaryOpIC::State::Kind BinaryOpIC::State::UpdateKind(Handle<Object> object,
+ Kind kind) const {
+ Kind new_kind = GENERIC;
+ bool is_truncating = Token::IsTruncatingBinaryOp(op());
+ if (object->IsBoolean() && is_truncating) {
+ // Booleans will be automatically truncated by HChange.
+ new_kind = INT32;
+ } else if (object->IsUndefined()) {
+ // Undefined will be automatically truncated by HChange.
+ new_kind = is_truncating ? INT32 : NUMBER;
+ } else if (object->IsSmi()) {
+ new_kind = SMI;
+ } else if (object->IsHeapNumber()) {
+ double value = Handle<HeapNumber>::cast(object)->value();
+ new_kind = TypeInfo::IsInt32Double(value) ? INT32 : NUMBER;
+ } else if (object->IsString() && op() == Token::ADD) {
+ new_kind = STRING;
+ }
+ if (new_kind == INT32 && SmiValuesAre32Bits()) {
+ new_kind = NUMBER;
+ }
+ if (kind != NONE &&
+ ((new_kind <= NUMBER && kind > NUMBER) ||
+ (new_kind > NUMBER && kind <= NUMBER))) {
+ new_kind = GENERIC;
+ }
+ return Max(kind, new_kind);
+}
+
+
+// static
+const char* BinaryOpIC::State::KindToString(Kind kind) {
+ switch (kind) {
+ case NONE: return "None";
case SMI: return "Smi";
case INT32: return "Int32";
case NUMBER: return "Number";
- case ODDBALL: return "Oddball";
case STRING: return "String";
case GENERIC: return "Generic";
- default: return "Invalid";
}
+ UNREACHABLE();
+ return NULL;
+}
+
+
+// static
+Handle<Type> BinaryOpIC::State::KindToType(Kind kind, Isolate* isolate) {
+ Type* type = NULL;
+ switch (kind) {
+ case NONE: type = Type::None(); break;
+ case SMI: type = Type::Smi(); break;
+ case INT32: type = Type::Signed32(); break;
+ case NUMBER: type = Type::Number(); break;
+ case STRING: type = Type::String(); break;
+ case GENERIC: type = Type::Any(); break;
+ }
+ return handle(type, isolate);
}
MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
- ExtraICState extra_ic_state = target()->extended_extra_ic_state();
- BinaryOpStub stub(extra_ic_state);
+ State state(target()->extended_extra_ic_state());
- Handle<Type> left_type = stub.GetLeftType(isolate());
- Handle<Type> right_type = stub.GetRightType(isolate());
- bool smi_was_enabled = left_type->Maybe(Type::Smi()) &&
- right_type->Maybe(Type::Smi());
+ // Compute the actual result using the builtin for the binary operation.
+ Object* builtin = isolate()->js_builtins_object()->javascript_builtin(
+ TokenToJSBuiltin(state.op()));
+ Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate());
+ bool caught_exception;
+ Handle<Object> result = Execution::Call(
+ isolate(), function, left, 1, &right, &caught_exception);
+ if (caught_exception) return Failure::Exception();
- Maybe<Handle<Object> > result = stub.Result(left, right, isolate());
- if (!result.has_value) return Failure::Exception();
+ // Compute the new state.
+ State old_state = state;
+ state.Update(left, right, result);
+
+ // Install the new stub.
+ BinaryOpICStub stub(state);
+ set_target(*stub.GetCode(isolate()));
if (FLAG_trace_ic) {
- char buffer[100];
- NoAllocationStringAllocator allocator(buffer,
- static_cast<unsigned>(sizeof(buffer)));
+ char buffer[150];
+ NoAllocationStringAllocator allocator(
+ buffer, static_cast<unsigned>(sizeof(buffer)));
StringStream stream(&allocator);
- stream.Add("[");
- stub.PrintName(&stream);
-
- stub.UpdateStatus(left, right, result);
-
+ stream.Add("[BinaryOpIC");
+ old_state.Print(&stream);
stream.Add(" => ");
- stub.PrintState(&stream);
- stream.Add(" ");
+ state.Print(&stream);
+ stream.Add(" @ %p <- ", static_cast<void*>(*target()));
stream.OutputToStdOut();
- PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate())));
JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
PrintF("]\n");
- } else {
- stub.UpdateStatus(left, right, result);
}
- Handle<Code> code = stub.GetCode(isolate());
- set_target(*code);
-
- left_type = stub.GetLeftType(isolate());
- right_type = stub.GetRightType(isolate());
- bool enable_smi = left_type->Maybe(Type::Smi()) &&
- right_type->Maybe(Type::Smi());
-
- if (!smi_was_enabled && enable_smi) {
+ // Patch the inlined smi code as necessary.
+ if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
- } else if (smi_was_enabled && !enable_smi) {
+ } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
}
- ASSERT(result.has_value);
- return static_cast<MaybeObject*>(*result.value);
+ return *result;
}
RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) {
HandleScope scope(isolate);
- Handle<Object> left = args.at<Object>(0);
- Handle<Object> right = args.at<Object>(1);
+ Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
+ Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
BinaryOpIC ic(isolate);
return ic.Transition(left, right);
}
};
+// Mode to overwrite BinaryExpression values.
+enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+
// Type Recording BinaryOpIC, that records the types of the inputs and outputs.
class BinaryOpIC: public IC {
public:
- enum TypeInfo {
- UNINITIALIZED,
- SMI,
- INT32,
- NUMBER,
- ODDBALL,
- STRING, // Only used for addition operation.
- GENERIC
+ class State V8_FINAL BASE_EMBEDDED {
+ public:
+ explicit State(ExtraICState extra_ic_state);
+
+ State(Token::Value op, OverwriteMode mode)
+ : op_(op), mode_(mode), left_kind_(NONE), right_kind_(NONE),
+ result_kind_(NONE) {
+ ASSERT_LE(FIRST_TOKEN, op);
+ ASSERT_LE(op, LAST_TOKEN);
+ }
+
+ InlineCacheState GetICState() const {
+ if (Max(left_kind_, right_kind_) == NONE) {
+ return ::v8::internal::UNINITIALIZED;
+ }
+ if (Max(left_kind_, right_kind_) == GENERIC) {
+ return ::v8::internal::MEGAMORPHIC;
+ }
+ if (Min(left_kind_, right_kind_) == GENERIC) {
+ return ::v8::internal::GENERIC;
+ }
+ return ::v8::internal::MONOMORPHIC;
+ }
+
+ ExtraICState GetExtraICState() const;
+
+ static void GenerateAheadOfTime(
+ Isolate*, void (*Generate)(Isolate*, const State&));
+
+ bool CanReuseDoubleBox() const {
+ return (result_kind_ > SMI && result_kind_ <= NUMBER) &&
+ ((mode_ == OVERWRITE_LEFT &&
+ left_kind_ > SMI && left_kind_ <= NUMBER) ||
+ (mode_ == OVERWRITE_RIGHT &&
+ right_kind_ > SMI && right_kind_ <= NUMBER));
+ }
+
+ bool HasSideEffects() const {
+ return Max(left_kind_, right_kind_) == GENERIC;
+ }
+
+ bool UseInlinedSmiCode() const {
+ return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
+ }
+
+ static const int FIRST_TOKEN = Token::BIT_OR;
+ static const int LAST_TOKEN = Token::MOD;
+
+ Token::Value op() const { return op_; }
+ OverwriteMode mode() const { return mode_; }
+ Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
+
+ Handle<Type> GetLeftType(Isolate* isolate) const {
+ return KindToType(left_kind_, isolate);
+ }
+ Handle<Type> GetRightType(Isolate* isolate) const {
+ return KindToType(right_kind_, isolate);
+ }
+ Handle<Type> GetResultType(Isolate* isolate) const;
+
+ void Print(StringStream* stream) const;
+
+ void Update(Handle<Object> left,
+ Handle<Object> right,
+ Handle<Object> result);
+
+ private:
+ enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
+
+ Kind UpdateKind(Handle<Object> object, Kind kind) const;
+
+ static const char* KindToString(Kind kind);
+ static Handle<Type> KindToType(Kind kind, Isolate* isolate);
+ static bool KindMaybeSmi(Kind kind) {
+ return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
+ }
+
+ // We truncate the last bit of the token.
+ STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
+ class OpField: public BitField<int, 0, 4> {};
+ class OverwriteModeField: public BitField<OverwriteMode, 4, 2> {};
+ class SSE2Field: public BitField<bool, 6, 1> {};
+ class ResultKindField: public BitField<Kind, 7, 3> {};
+ class LeftKindField: public BitField<Kind, 10, 3> {};
+ // When fixed right arg is set, we don't need to store the right kind.
+ // Thus the two fields can overlap.
+ class HasFixedRightArgField: public BitField<bool, 13, 1> {};
+ class FixedRightArgValueField: public BitField<int, 14, 4> {};
+ class RightKindField: public BitField<Kind, 14, 3> {};
+
+ Token::Value op_;
+ OverwriteMode mode_;
+ Kind left_kind_;
+ Kind right_kind_;
+ Kind result_kind_;
+ Maybe<int> fixed_right_arg_;
};
explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
static Builtins::JavaScript TokenToJSBuiltin(Token::Value op);
- static const char* GetName(TypeInfo type_info);
-
MUST_USE_RESULT MaybeObject* Transition(Handle<Object> left,
Handle<Object> right);
};
DONT_TRACK_ALLOCATION_SITE, 0);
stub.InitializeInterfaceDescriptor(
this, code_stub_interface_descriptor(CodeStub::FastCloneShallowArray));
- BinaryOpStub::InitializeForIsolate(this);
+ BinaryOpICStub::InstallDescriptors(this);
CompareNilICStub::InitializeForIsolate(this);
ToBooleanStub::InitializeForIsolate(this);
ArrayConstructorStubBase::InstallDescriptors(this);
case Code::FUNCTION:
case Code::OPTIMIZED_FUNCTION:
return; // We log this later using LogCompiledFunctions.
- case Code::BINARY_OP_IC: {
- BinaryOpStub stub(code_object->extended_extra_ic_state());
- description = stub.GetName().Detach();
- tag = Logger::STUB_TAG;
- break;
- }
+ case Code::BINARY_OP_IC:
case Code::COMPARE_IC: // fall through
case Code::COMPARE_NIL_IC: // fall through
case Code::TO_BOOLEAN_IC: // fall through
return COMMA <= op && op <= MOD;
}
+ static bool IsTruncatingBinaryOp(Value op) {
+ return BIT_OR <= op && op <= ROR;
+ }
+
static bool IsCompareOp(Value op) {
return EQ <= op && op <= IN;
}
Handle<Type>* right,
Handle<Type>* result,
Maybe<int>* fixed_right_arg,
- Token::Value operation) {
+ Token::Value op) {
Handle<Object> object = GetInfo(id);
if (!object->IsCode()) {
// For some binary ops we don't have ICs, e.g. Token::COMMA, but for the
- // operations covered by the BinaryOpStub we should always have them.
- ASSERT(!(operation >= BinaryOpStub::FIRST_TOKEN &&
- operation <= BinaryOpStub::LAST_TOKEN));
+ // operations covered by the BinaryOpIC we should always have them.
+ ASSERT(op < BinaryOpIC::State::FIRST_TOKEN ||
+ op > BinaryOpIC::State::LAST_TOKEN);
*left = *right = *result = handle(Type::None(), isolate_);
+ *fixed_right_arg = Maybe<int>();
return;
}
Handle<Code> code = Handle<Code>::cast(object);
- ASSERT(code->is_binary_op_stub());
+ ASSERT_EQ(Code::BINARY_OP_IC, code->kind());
+ BinaryOpIC::State state(code->extended_extra_ic_state());
+ ASSERT_EQ(op, state.op());
- BinaryOpStub stub(code->extended_extra_ic_state());
-
- // Sanity check.
- ASSERT(stub.operation() == operation);
-
- *left = stub.GetLeftType(isolate());
- *right = stub.GetRightType(isolate());
- *result = stub.GetResultType(isolate());
- *fixed_right_arg = stub.fixed_right_arg();
+ *left = state.GetLeftType(isolate());
+ *right = state.GetRightType(isolate());
+ *result = state.GetResultType(isolate());
+ *fixed_right_arg = state.fixed_right_arg();
}
Handle<Type> TypeFeedbackOracle::CountType(TypeFeedbackId id) {
Handle<Object> object = GetInfo(id);
- Handle<Type> unknown(Type::None(), isolate_);
- if (!object->IsCode()) return unknown;
+ if (!object->IsCode()) return handle(Type::None(), isolate_);
Handle<Code> code = Handle<Code>::cast(object);
- if (!code->is_binary_op_stub()) return unknown;
-
- BinaryOpStub stub(code->extended_extra_ic_state());
- return stub.GetLeftType(isolate());
+ ASSERT_EQ(Code::BINARY_OP_IC, code->kind());
+ BinaryOpIC::State state(code->extended_extra_ic_state());
+ return state.GetLeftType(isolate());
}
}
-void BinaryOpStub::InitializeInterfaceDescriptor(
+void BinaryOpICStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { rdx, rax };
// It is important that the store buffer overflow stubs are generated first.
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
- BinaryOpStub::GenerateAheadOfTime(isolate);
+ BinaryOpICStub::GenerateAheadOfTime(isolate);
}
__ bind(&stub_call);
__ movq(rax, rcx);
- BinaryOpStub stub(op, mode);
+ BinaryOpICStub stub(op, mode);
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
expr->BinaryOperationFeedbackId());
patch_site.EmitPatchInfo();
Token::Value op,
OverwriteMode mode) {
__ pop(rdx);
- BinaryOpStub stub(op, mode);
+ BinaryOpICStub stub(op, mode);
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
expr->BinaryOperationFeedbackId());
__ bind(&stub_call);
__ movq(rdx, rax);
__ Move(rax, Smi::FromInt(1));
- BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
+ BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE);
CallIC(stub.GetCode(isolate()),
RelocInfo::CODE_TARGET,
expr->CountBinOpFeedbackId());
ASSERT(ToRegister(instr->right()).is(rax));
ASSERT(ToRegister(instr->result()).is(rax));
- BinaryOpStub stub(instr->op(), NO_OVERWRITE);
+ BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
__ nop(); // Signals no inlined code.
}