// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#include "v8.h"
!hinstr->HasObservableSideEffects();
if (needs_environment && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
+ // We can't really figure out if the environment is needed or not.
+ instr->environment()->set_has_been_used();
}
return instr;
// the it was just a plain use), so it is free to move the split child into
// the same register that is used for the use-at-start.
// See https://code.google.com/p/chromium/issues/detail?id=201590
- if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) {
+ if (!(instr->ClobbersRegisters() &&
+ instr->ClobbersDoubleRegisters(isolate()))) {
int fixed = 0;
int used_at_start = 0;
for (UseIterator it(instr); !it.Done(); it.Advance()) {
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
- LOperand* value = UseRegisterOrConstantAtStart(instr->index());
- LOperand* length = UseRegister(instr->length());
- return AssignEnvironment(new(zone()) LBoundsCheck(value, length));
+ if (!FLAG_debug_code && instr->skip_check()) return NULL;
+ LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+ LOperand* length = !index->IsConstantOperand()
+ ? UseRegisterOrConstantAtStart(instr->length())
+ : UseRegisterAtStart(instr->length());
+ LInstruction* result = new(zone()) LBoundsCheck(index, length);
+ if (!FLAG_debug_code || !instr->skip_check()) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
Representation from = instr->from();
Representation to = instr->to();
-
+ HValue* val = instr->value();
if (from.IsSmi()) {
if (to.IsTagged()) {
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseRegister(val);
return DefineSameAsFirst(new(zone()) LDummyUse(value));
}
from = Representation::Tagged();
}
-
if (from.IsTagged()) {
if (to.IsDouble()) {
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseRegister(val);
LOperand* temp = TempRegister();
- LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
- return AssignEnvironment(DefineAsRegister(res));
+ LInstruction* result =
+ DefineAsRegister(new(zone()) LNumberUntagD(value, temp));
+ if (!val->representation().IsSmi()) result = AssignEnvironment(result);
+ return result;
} else if (to.IsSmi()) {
- LOperand* value = UseRegister(instr->value());
- if (instr->value()->type().IsSmi()) {
+ LOperand* value = UseRegister(val);
+ if (val->type().IsSmi()) {
return DefineSameAsFirst(new(zone()) LDummyUse(value));
}
return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
} else {
ASSERT(to.IsInteger32());
- LInstruction* res = NULL;
-
- if (instr->value()->type().IsSmi() ||
- instr->value()->representation().IsSmi()) {
- LOperand* value = UseRegisterAtStart(instr->value());
- res = DefineAsRegister(new(zone()) LSmiUntag(value, false));
+ if (val->type().IsSmi() || val->representation().IsSmi()) {
+ LOperand* value = UseRegisterAtStart(val);
+ return DefineAsRegister(new(zone()) LSmiUntag(value, false));
} else {
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseRegister(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = instr->CanTruncateToInt32() ? NULL : FixedTemp(d24);
- res = DefineAsRegister(new(zone()) LTaggedToI(value, temp1, temp2));
- res = AssignEnvironment(res);
+ LInstruction* result =
+ DefineAsRegister(new(zone()) LTaggedToI(value, temp1, temp2));
+ if (!val->representation().IsSmi()) result = AssignEnvironment(result);
+ return result;
}
-
- return res;
}
} else if (from.IsDouble()) {
if (to.IsTagged()) {
info()->MarkAsDeferredCalling();
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseRegister(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
-
LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
return AssignPointerMap(DefineAsRegister(result));
} else {
ASSERT(to.IsSmi() || to.IsInteger32());
- LOperand* value = UseRegister(instr->value());
-
if (instr->CanTruncateToInt32()) {
- LTruncateDoubleToIntOrSmi* result =
- new(zone()) LTruncateDoubleToIntOrSmi(value);
- return DefineAsRegister(result);
+ LOperand* value = UseRegister(val);
+ return DefineAsRegister(new(zone()) LTruncateDoubleToIntOrSmi(value));
} else {
+ LOperand* value = UseRegister(val);
LDoubleToIntOrSmi* result = new(zone()) LDoubleToIntOrSmi(value);
return AssignEnvironment(DefineAsRegister(result));
}
} else if (from.IsInteger32()) {
info()->MarkAsDeferredCalling();
if (to.IsTagged()) {
- if (instr->value()->CheckFlag(HInstruction::kUint32)) {
- LOperand* value = UseRegister(instr->value());
- LNumberTagU* result = new(zone()) LNumberTagU(value,
- TempRegister(),
- TempRegister());
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ if (val->CheckFlag(HInstruction::kUint32)) {
+ LOperand* value = UseRegister(val);
+ LNumberTagU* result =
+ new(zone()) LNumberTagU(value, TempRegister(), TempRegister());
+ return AssignPointerMap(DefineAsRegister(result));
} else {
STATIC_ASSERT((kMinInt == Smi::kMinValue) &&
(kMaxInt == Smi::kMaxValue));
- LOperand* value = UseRegisterAtStart(instr->value());
+ LOperand* value = UseRegisterAtStart(val);
return DefineAsRegister(new(zone()) LSmiTag(value));
}
} else if (to.IsSmi()) {
- LOperand* value = UseRegisterAtStart(instr->value());
+ LOperand* value = UseRegisterAtStart(val);
LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
- if (instr->value()->CheckFlag(HInstruction::kUint32)) {
+ if (val->CheckFlag(HInstruction::kUint32)) {
result = AssignEnvironment(result);
}
return result;
} else {
ASSERT(to.IsDouble());
- if (instr->value()->CheckFlag(HInstruction::kUint32)) {
+ if (val->CheckFlag(HInstruction::kUint32)) {
return DefineAsRegister(
- new(zone()) LUint32ToDouble(UseRegisterAtStart(instr->value())));
+ new(zone()) LUint32ToDouble(UseRegisterAtStart(val)));
} else {
return DefineAsRegister(
- new(zone()) LInteger32ToDouble(UseRegisterAtStart(instr->value())));
+ new(zone()) LInteger32ToDouble(UseRegisterAtStart(val)));
}
}
}
-
UNREACHABLE();
return NULL;
}
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
- if (instr->CanOmitMapChecks()) {
- // LCheckMaps does nothing in this case.
- return new(zone()) LCheckMaps(NULL);
- } else {
- LOperand* value = UseRegisterAtStart(instr->value());
- LOperand* temp = TempRegister();
-
- if (instr->has_migration_target()) {
- info()->MarkAsDeferredCalling();
- LInstruction* result = new(zone()) LCheckMaps(value, temp);
- return AssignPointerMap(AssignEnvironment(result));
- } else {
- return AssignEnvironment(new(zone()) LCheckMaps(value, temp));
- }
+ if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
+ LOperand* value = UseRegisterAtStart(instr->value());
+ LOperand* temp = TempRegister();
+ LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value, temp));
+ if (instr->HasMigrationTarget()) {
+ info()->MarkAsDeferredCalling();
+ result = AssignPointerMap(result);
}
+ return result;
}
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
- return AssignEnvironment(new(zone()) LCheckNonSmi(value));
+ LInstruction* result = new(zone()) LCheckNonSmi(value);
+ if (!instr->value()->IsHeapObject()) result = AssignEnvironment(result);
+ return result;
}
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
HCompareNumericAndBranch* instr) {
+ LInstruction* goto_instr = CheckElideControlInstruction(instr);
+ if (goto_instr != NULL) return goto_instr;
Representation r = instr->representation();
-
if (r.IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().Equals(r));
ASSERT(instr->right()->representation().Equals(r));
LOperand* divisor = UseRegister(instr->right());
LOperand* temp = instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)
? NULL : TempRegister();
- LDivI* div = new(zone()) LDivI(dividend, divisor, temp);
- return AssignEnvironment(DefineAsRegister(div));
+ LInstruction* result =
+ DefineAsRegister(new(zone()) LDivI(dividend, divisor, temp));
+ if (!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
HEnvironment* outer = current_block_->last_environment();
+ outer->set_ast_id(instr->ReturnId());
HConstant* undefined = graph()->GetConstantUndefined();
HEnvironment* inner = outer->CopyForInlining(instr->closure(),
instr->arguments_count(),
LOperand* context = UseRegisterAtStart(instr->value());
LInstruction* result =
DefineAsRegister(new(zone()) LLoadContextSlot(context));
- return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
+ if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
ASSERT(instr->key()->representation().IsSmiOrInteger32());
ElementsKind elements_kind = instr->elements_kind();
LOperand* elements = UseRegister(instr->elements());
- LOperand* key = UseRegisterOrConstantAtStart(instr->key());
if (!instr->is_typed_elements()) {
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+
if (instr->representation().IsDouble()) {
LOperand* temp = (!instr->key()->IsConstant() ||
instr->RequiresHoleCheck())
(instr->representation().IsDouble() &&
IsDoubleOrFloatElementsKind(instr->elements_kind())));
+ LOperand* key = UseRegisterOrConstant(instr->key());
LOperand* temp = instr->key()->IsConstant() ? NULL : TempRegister();
- LLoadKeyedExternal* result =
- new(zone()) LLoadKeyedExternal(elements, key, temp);
- // An unsigned int array load might overflow and cause a deopt. Make sure it
- // has an environment.
- if (instr->RequiresHoleCheck() ||
- elements_kind == EXTERNAL_UINT32_ELEMENTS ||
- elements_kind == UINT32_ELEMENTS) {
- return AssignEnvironment(DefineAsRegister(result));
- } else {
- return DefineAsRegister(result);
+ LInstruction* result = DefineAsRegister(
+ new(zone()) LLoadKeyedExternal(elements, key, temp));
+ if ((elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
+ !instr->CheckFlag(HInstruction::kUint32)) {
+ result = AssignEnvironment(result);
}
+ return result;
}
}
bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
- bool needs_environment = can_overflow || bailout_on_minus_zero;
HValue* least_const = instr->BetterLeftOperand();
HValue* most_const = instr->BetterRightOperand();
- LOperand* left;
-
// LMulConstI can handle a subset of constants:
// With support for overflow detection:
// -1, 0, 1, 2
IsPowerOf2(constant_abs - 1))))) {
LConstantOperand* right = UseConstant(most_const);
bool need_register = IsPowerOf2(constant_abs) && !small_constant;
- left = need_register ? UseRegister(least_const)
- : UseRegisterAtStart(least_const);
- LMulConstIS* mul = new(zone()) LMulConstIS(left, right);
- if (needs_environment) AssignEnvironment(mul);
- return DefineAsRegister(mul);
+ LOperand* left = need_register ? UseRegister(least_const)
+ : UseRegisterAtStart(least_const);
+ LInstruction* result =
+ DefineAsRegister(new(zone()) LMulConstIS(left, right));
+ if ((bailout_on_minus_zero && constant <= 0) || can_overflow) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
}
- left = UseRegisterAtStart(least_const);
// LMulI/S can handle all cases, but it requires that a register is
// allocated for the second operand.
- LInstruction* result;
- if (instr->representation().IsSmi()) {
- LOperand* right = UseRegisterAtStart(most_const);
- result = DefineAsRegister(new(zone()) LMulS(left, right));
- } else {
- LOperand* right = UseRegisterAtStart(most_const);
- result = DefineAsRegister(new(zone()) LMulI(left, right));
+ LOperand* left = UseRegisterAtStart(least_const);
+ LOperand* right = UseRegisterAtStart(most_const);
+ LInstruction* result = instr->representation().IsSmi()
+ ? DefineAsRegister(new(zone()) LMulS(left, right))
+ : DefineAsRegister(new(zone()) LMulI(left, right));
+ if ((bailout_on_minus_zero && least_const != most_const) || can_overflow) {
+ result = AssignEnvironment(result);
}
- if (needs_environment) AssignEnvironment(result);
return result;
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MUL, instr);
} else {
ASSERT(info()->IsStub());
CodeStubInterfaceDescriptor* descriptor =
- info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
+ info()->code_stub()->GetInterfaceDescriptor();
int index = static_cast<int>(instr->index());
Register reg = descriptor->GetParameterRegister(index);
return DefineFixed(result, reg);
value = UseRegister(instr->value());
}
LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
- return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
+ if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
LOperand* temp = NULL;
LOperand* elements = NULL;
LOperand* val = NULL;
- LOperand* key = UseRegisterOrConstantAtStart(instr->key());
if (!instr->is_typed_elements() &&
instr->value()->representation().IsTagged() &&
instr->elements()->representation().IsTagged()) ||
(instr->is_external() &&
instr->elements()->representation().IsExternal()));
+ LOperand* key = UseRegisterOrConstant(instr->key());
return new(zone()) LStoreKeyedExternal(elements, key, val, temp);
} else if (instr->value()->representation().IsDouble()) {
ASSERT(instr->elements()->representation().IsTagged());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
return new(zone()) LStoreKeyedFixedDouble(elements, key, val, temp);
} else {
ASSERT(instr->elements()->representation().IsTagged());
ASSERT(instr->value()->representation().IsSmiOrTagged() ||
instr->value()->representation().IsInteger32());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
return new(zone()) LStoreKeyedFixed(elements, key, val, temp);
}
}
LOperand* context = UseAny(instr->context());
LStringCharCodeAt* result =
new(zone()) LStringCharCodeAt(context, string, index);
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ return AssignPointerMap(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoTransitionElementsKind(
HTransitionElementsKind* instr) {
- LOperand* object = UseRegister(instr->object());
if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
+ LOperand* object = UseRegister(instr->object());
LTransitionElementsKind* result =
new(zone()) LTransitionElementsKind(object, NULL,
TempRegister(), TempRegister());
return result;
} else {
+ LOperand* object = UseFixed(instr->object(), x0);
LOperand* context = UseFixed(instr->context(), cp);
LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object, context, TempRegister());
- return AssignPointerMap(result);
+ new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
+ return MarkAsCall(result, instr);
}
}
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LOperand* temp3 = TempRegister();
- LMathAbsTagged* result =
- new(zone()) LMathAbsTagged(context, input, temp1, temp2, temp3);
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ LInstruction* result = DefineAsRegister(
+ new(zone()) LMathAbsTagged(context, input, temp1, temp2, temp3));
+ return AssignEnvironment(AssignPointerMap(result));
} else {
LOperand* input = UseRegisterAtStart(instr->value());
- LMathAbs* result = new(zone()) LMathAbs(input);
- if (r.IsDouble()) {
- // The Double case can never fail so it doesn't need an environment.
- return DefineAsRegister(result);
- } else {
- ASSERT(r.IsInteger32() || r.IsSmi());
- // The Integer32 and Smi cases need an environment because they can
- // deoptimize on minimum representable number.
- return AssignEnvironment(DefineAsRegister(result));
- }
+ LInstruction* result = DefineAsRegister(new(zone()) LMathAbs(input));
+ if (!r.IsDouble()) result = AssignEnvironment(result);
+ return result;
}
}
case kMathExp: {
return DefineAsRegister(result);
}
case kMathFloor: {
- ASSERT(instr->representation().IsInteger32());
ASSERT(instr->value()->representation().IsDouble());
- // TODO(jbramley): ARM64 can easily handle a double argument with frintm,
- // but we're never asked for it here. At the moment, we fall back to the
- // runtime if the result doesn't fit, like the other architectures.
LOperand* input = UseRegisterAtStart(instr->value());
- LMathFloor* result = new(zone()) LMathFloor(input);
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ if (instr->representation().IsInteger32()) {
+ LMathFloorI* result = new(zone()) LMathFloorI(input);
+ return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ } else {
+ ASSERT(instr->representation().IsDouble());
+ LMathFloorD* result = new(zone()) LMathFloorD(input);
+ return DefineAsRegister(result);
+ }
}
case kMathLog: {
ASSERT(instr->representation().IsDouble());
return DefineAsRegister(new(zone()) LMathPowHalf(input));
}
case kMathRound: {
- ASSERT(instr->representation().IsInteger32());
ASSERT(instr->value()->representation().IsDouble());
- // TODO(jbramley): As with kMathFloor, we can probably handle double
- // results fairly easily, but we are never asked for them.
LOperand* input = UseRegister(instr->value());
- LOperand* temp = FixedTemp(d24); // Choosen arbitrarily.
- LMathRound* result = new(zone()) LMathRound(input, temp);
- return AssignEnvironment(DefineAsRegister(result));
+ if (instr->representation().IsInteger32()) {
+ LMathRoundI* result = new(zone()) LMathRoundI(input, FixedTemp(d24));
+ return AssignEnvironment(DefineAsRegister(result));
+ } else {
+ ASSERT(instr->representation().IsDouble());
+ LMathRoundD* result = new(zone()) LMathRoundD(input);
+ return DefineAsRegister(result);
+ }
}
case kMathSqrt: {
ASSERT(instr->representation().IsDouble());
LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
LOperand* object = UseRegisterAtStart(instr->object());
- LOperand* index = UseRegister(instr->index());
- return DefineAsRegister(new(zone()) LLoadFieldByIndex(object, index));
+ LOperand* index = UseRegisterAndClobber(instr->index());
+ LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
+ LInstruction* result = DefineSameAsFirst(load);
+ return AssignPointerMap(result);
}