Version 3.26.3 (based on bleeding_edge revision r20415)
Support typed arrays in IsMoreGeneralElementsKindTransition (Chromium issue 357054).
Remove debugger_auto_break flag.
Store i18n meta data in hidden symbols instead of js accessible properties (Chromium issue 354967).
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@20418 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 95c996b..24a7f21 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2014-04-02: Version 3.26.3
+
+ Support typed arrays in IsMoreGeneralElementsKindTransition (Chromium
+ issue 357054).
+
+ Remove debugger_auto_break flag.
+
+ Store i18n meta data in hidden symbols instead of js accessible
+ properties (Chromium issue 354967).
+
+ Performance and stability improvements on all platforms.
+
+
2014-04-01: Version 3.26.2
Performance and stability improvements on all platforms.
diff --git a/Makefile b/Makefile
index cdf5d74..ff01c7d 100644
--- a/Makefile
+++ b/Makefile
@@ -140,9 +140,9 @@
# asan=/path/to/clang++
ifneq ($(strip $(asan)),)
GYPFLAGS += -Dasan=1
- export CXX="$(asan)"
- export CXX_host="$(asan)"
- export LINK="$(asan)"
+ export CXX=$(asan)
+ export CXX_host=$(asan)
+ export LINK=$(asan)
export ASAN_SYMBOLIZER_PATH="$(dir $(asan))llvm-symbolizer"
endif
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 3755a53..41d79eb 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -104,6 +104,12 @@
return {
'tryserver.v8': {
'v8_linux_rel': set(['defaulttests']),
+ 'v8_linux_dbg': set(['defaulttests']),
+ 'v8_linux_nosnap_rel': set(['defaulttests']),
+ 'v8_linux_nosnap_dbg': set(['defaulttests']),
+ 'v8_linux64_rel': set(['defaulttests']),
+ 'v8_linux_arm_dbg': set(['defaulttests']),
+ 'v8_linux_arm64_rel': set(['defaulttests']),
'v8_mac_rel': set(['defaulttests']),
'v8_win_rel': set(['defaulttests']),
},
diff --git a/build/toolchain.gypi b/build/toolchain.gypi
index 4a70d6f..dc25036 100644
--- a/build/toolchain.gypi
+++ b/build/toolchain.gypi
@@ -521,10 +521,7 @@
'conditions': [
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \
OS=="qnx"', {
- 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter',
- '-Wnon-virtual-dtor', '-Woverloaded-virtual',
- '<(wno_array_bounds)',
- ],
+ 'cflags': [ '-Woverloaded-virtual', '<(wno_array_bounds)', ],
'conditions': [
['v8_optimized_debug==0', {
'cflags!': [
diff --git a/include/v8-debug.h b/include/v8-debug.h
index 1a86a06..0199cd2 100644
--- a/include/v8-debug.h
+++ b/include/v8-debug.h
@@ -290,7 +290,7 @@
*
* Generally when message arrives V8 may be in one of 3 states:
* 1. V8 is running script; V8 will automatically interrupt and process all
- * pending messages (however auto_break flag should be enabled);
+ * pending messages;
* 2. V8 is suspended on debug breakpoint; in this state V8 is dedicated
* to reading and processing debug messages;
* 3. V8 is not running at all or has called some long-working C++ function;
diff --git a/include/v8-util.h b/include/v8-util.h
index accc6a4..dacc128 100644
--- a/include/v8-util.h
+++ b/include/v8-util.h
@@ -210,7 +210,7 @@
/**
* Return value for key and remove it from the map.
*/
- V8_INLINE UniquePersistent<V> Remove(const K& key) {
+ UniquePersistent<V> Remove(const K& key) {
return Release(Traits::Remove(&impl_, key)).Pass();
}
@@ -357,7 +357,7 @@
* callback is properly disposed of. All remove functionality should go
* through this.
*/
- V8_INLINE static UniquePersistent<V> Release(PersistentContainerValue v) {
+ static UniquePersistent<V> Release(PersistentContainerValue v) {
UniquePersistent<V> p;
p.val_ = FromVal(v);
if (Traits::kCallbackType != kNotWeak && !p.IsEmpty()) {
diff --git a/include/v8.h b/include/v8.h
index 50480b8..f0dd0e1 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -814,7 +814,7 @@
/**
* Pass allows returning uniques from functions, etc.
*/
- V8_INLINE UniquePersistent Pass() { return UniquePersistent(RValue(this)); }
+ UniquePersistent Pass() { return UniquePersistent(RValue(this)); }
private:
UniquePersistent(UniquePersistent&);
@@ -5581,7 +5581,7 @@
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptyStringRootIndex = 154;
+ static const int kEmptyStringRootIndex = 152;
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
diff --git a/src/api.cc b/src/api.cc
index 9e24fee..34a431d 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -533,7 +533,7 @@
LOG_API(isolate, "Persistent::New");
i::Handle<i::Object> result = isolate->global_handles()->Create(*obj);
#ifdef DEBUG
- (*obj)->Verify();
+ (*obj)->ObjectVerify();
#endif // DEBUG
return result.location();
}
@@ -542,7 +542,7 @@
i::Object** V8::CopyPersistent(i::Object** obj) {
i::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(obj);
#ifdef DEBUG
- (*obj)->Verify();
+ (*obj)->ObjectVerify();
#endif // DEBUG
return result.location();
}
@@ -3597,8 +3597,7 @@
// as optimized code does not always handle access checks.
i::Deoptimizer::DeoptimizeGlobalObject(*obj);
- i::Handle<i::Map> new_map =
- isolate->factory()->CopyMap(i::Handle<i::Map>(obj->map()));
+ i::Handle<i::Map> new_map = i::Map::Copy(i::Handle<i::Map>(obj->map()));
new_map->set_is_access_check_needed(true);
obj->set_map(*new_map);
}
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index aadfb29..81691a3 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -1648,7 +1648,7 @@
__ sub(r6, r6, Operand(kPointerSize));
// Enter the exit frame that transitions from JavaScript to C++.
- FrameAndConstantPoolScope scope(masm, StackFrame::MANUAL);
+ FrameScope scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(save_doubles_);
// Set up argc and the builtin function in callee-saved registers.
@@ -5377,7 +5377,7 @@
// it's not controlled by GC.
const int kApiStackSpace = 4;
- FrameAndConstantPoolScope frame_scope(masm, StackFrame::MANUAL);
+ FrameScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
ASSERT(!api_function_address.is(r0) && !scratch.is(r0));
@@ -5437,7 +5437,7 @@
__ add(r1, r0, Operand(1 * kPointerSize)); // r1 = PCA
const int kApiStackSpace = 1;
- FrameAndConstantPoolScope frame_scope(masm, StackFrame::MANUAL);
+ FrameScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
// Create PropertyAccessorInfo instance on the stack above the exit frame with
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index ba44b50..38acd48 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -931,18 +931,20 @@
if (goto_instr != NULL) return goto_instr;
HValue* value = instr->value();
- LBranch* result = new(zone()) LBranch(UseRegister(value));
- // Tagged values that are not known smis or booleans require a
- // deoptimization environment. If the instruction is generic no
- // environment is needed since all cases are handled.
- Representation rep = value->representation();
+ Representation r = value->representation();
HType type = value->type();
ToBooleanStub::Types expected = instr->expected_input_types();
- if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean() &&
- !expected.IsGeneric()) {
- return AssignEnvironment(result);
+ if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
+
+ bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
+ type.IsJSArray() || type.IsHeapNumber() || type.IsString();
+ LInstruction* branch = new(zone()) LBranch(UseRegister(value));
+ if (!easy_case &&
+ ((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
+ !expected.IsGeneric())) {
+ branch = AssignEnvironment(branch);
}
- return result;
+ return branch;
}
@@ -1138,8 +1140,11 @@
? NULL
: UseFixed(instr->context(), cp);
LOperand* input = UseRegister(instr->value());
- LMathAbs* result = new(zone()) LMathAbs(context, input);
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ LInstruction* result =
+ DefineAsRegister(new(zone()) LMathAbs(context, input));
+ if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
+ if (!r.IsDouble()) result = AssignEnvironment(result);
+ return result;
}
@@ -1284,15 +1289,25 @@
}
-LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
+LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
LOperand* temp = CpuFeatures::IsSupported(SUDIV) ? NULL : FixedTemp(d4);
- 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::kCanBeDivByZero) ||
+ instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
+ (instr->CheckFlag(HValue::kCanOverflow) &&
+ (!CpuFeatures::IsSupported(SUDIV) ||
+ !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) ||
+ (!instr->IsMathFloorOfDiv() &&
+ !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
@@ -1346,13 +1361,25 @@
}
+LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
+ ASSERT(instr->representation().IsSmiOrInteger32());
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
+ LOperand* dividend = UseRegister(instr->left());
+ LOperand* divisor = UseRegister(instr->right());
+ LOperand* temp = CpuFeatures::IsSupported(SUDIV) ? NULL : FixedTemp(d4);
+ LFlooringDivI* div = new(zone()) LFlooringDivI(dividend, divisor, temp);
+ return AssignEnvironment(DefineAsRegister(div));
+}
+
+
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoFlooringDivByConstI(instr);
} else {
- return DoDivI(instr);
+ return DoFlooringDivI(instr);
}
}
@@ -1837,20 +1864,21 @@
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());
- LNumberUntagD* res = new(zone()) LNumberUntagD(value);
- return AssignEnvironment(DefineAsRegister(res));
+ LOperand* value = UseRegister(val);
+ LInstruction* result = DefineAsRegister(new(zone()) LNumberUntagD(value));
+ if (!val->representation().IsSmi()) result = AssignEnvironment(result);
+ return result;
} else if (to.IsSmi()) {
- HValue* val = instr->value();
LOperand* value = UseRegister(val);
if (val->type().IsSmi()) {
return DefineSameAsFirst(new(zone()) LDummyUse(value));
@@ -1858,66 +1886,62 @@
return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
} else {
ASSERT(to.IsInteger32());
- LOperand* value = NULL;
- LInstruction* res = NULL;
- HValue* val = instr->value();
if (val->type().IsSmi() || val->representation().IsSmi()) {
- value = UseRegisterAtStart(val);
- res = DefineAsRegister(new(zone()) LSmiUntag(value, false));
+ LOperand* value = UseRegisterAtStart(val);
+ return DefineAsRegister(new(zone()) LSmiUntag(value, false));
} else {
- value = UseRegister(val);
+ LOperand* value = UseRegister(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = FixedTemp(d11);
- res = DefineSameAsFirst(new(zone()) LTaggedToI(value,
- temp1,
- temp2));
- res = AssignEnvironment(res);
+ LInstruction* result =
+ DefineSameAsFirst(new(zone()) LTaggedToI(value, temp1, temp2));
+ if (!val->representation().IsSmi()) {
+ // Note: Only deopts in deferred code.
+ 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();
-
- // Make sure that the temp and result_temp registers are
- // different.
LUnallocated* result_temp = TempRegister();
LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
- Define(result, result_temp);
- return AssignPointerMap(result);
+ return AssignPointerMap(Define(result, result_temp));
} else if (to.IsSmi()) {
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseRegister(val);
return AssignEnvironment(
DefineAsRegister(new(zone()) LDoubleToSmi(value)));
} else {
ASSERT(to.IsInteger32());
- LOperand* value = UseRegister(instr->value());
- LDoubleToI* res = new(zone()) LDoubleToI(value);
- return AssignEnvironment(DefineAsRegister(res));
+ LOperand* value = UseRegister(val);
+ LInstruction* result = DefineAsRegister(new(zone()) LDoubleToI(value));
+ if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
+ return result;
}
} else if (from.IsInteger32()) {
info()->MarkAsDeferredCalling();
if (to.IsTagged()) {
- HValue* val = instr->value();
- LOperand* value = UseRegisterAtStart(val);
if (!instr->CheckFlag(HValue::kCanOverflow)) {
+ LOperand* value = UseRegisterAtStart(val);
return DefineAsRegister(new(zone()) LSmiTag(value));
} else if (val->CheckFlag(HInstruction::kUint32)) {
+ LOperand* value = UseRegisterAtStart(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ return AssignPointerMap(DefineAsRegister(result));
} else {
+ LOperand* value = UseRegisterAtStart(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LNumberTagI* result = new(zone()) LNumberTagI(value, temp1, temp2);
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ return AssignPointerMap(DefineAsRegister(result));
}
} else if (to.IsSmi()) {
- HValue* val = instr->value();
LOperand* value = UseRegister(val);
LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
if (instr->CheckFlag(HValue::kCanOverflow)) {
@@ -1926,12 +1950,10 @@
return result;
} else {
ASSERT(to.IsDouble());
- if (instr->value()->CheckFlag(HInstruction::kUint32)) {
- return DefineAsRegister(
- new(zone()) LUint32ToDouble(UseRegister(instr->value())));
+ if (val->CheckFlag(HInstruction::kUint32)) {
+ return DefineAsRegister(new(zone()) LUint32ToDouble(UseRegister(val)));
} else {
- return DefineAsRegister(
- new(zone()) LInteger32ToDouble(Use(instr->value())));
+ return DefineAsRegister(new(zone()) LInteger32ToDouble(Use(val)));
}
}
}
@@ -1973,6 +1995,7 @@
}
LCheckMaps* result = new(zone()) LCheckMaps(value);
if (!instr->CanOmitMapChecks()) {
+ // Note: Only deopts in deferred code.
AssignEnvironment(result);
if (instr->has_migration_target()) return AssignPointerMap(result);
}
@@ -2072,7 +2095,10 @@
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;
}
@@ -2087,7 +2113,10 @@
value = UseRegister(instr->value());
}
LInstruction* result = new(zone()) LStoreContextSlot(context, value);
- return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
+ if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
@@ -2122,7 +2151,7 @@
ASSERT(instr->key()->representation().IsSmiOrInteger32());
ElementsKind elements_kind = instr->elements_kind();
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
- LLoadKeyed* result = NULL;
+ LInstruction* result = NULL;
if (!instr->is_typed_elements()) {
LOperand* obj = NULL;
@@ -2132,24 +2161,28 @@
ASSERT(instr->representation().IsSmiOrTagged());
obj = UseRegisterAtStart(instr->elements());
}
- result = new(zone()) LLoadKeyed(obj, key);
+ result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key));
} else {
ASSERT(
(instr->representation().IsInteger32() &&
- !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
+ !IsDoubleOrFloatElementsKind(elements_kind)) ||
(instr->representation().IsDouble() &&
- IsDoubleOrFloatElementsKind(instr->elements_kind())));
+ IsDoubleOrFloatElementsKind(elements_kind)));
LOperand* backing_store = UseRegister(instr->elements());
- result = new(zone()) LLoadKeyed(backing_store, key);
+ result = DefineAsRegister(new(zone()) LLoadKeyed(backing_store, key));
}
- DefineAsRegister(result);
- // An unsigned int array load might overflow and cause a deopt, make sure it
- // has an environment.
- bool can_deoptimize = instr->RequiresHoleCheck() ||
- elements_kind == EXTERNAL_UINT32_ELEMENTS ||
- elements_kind == UINT32_ELEMENTS;
- return can_deoptimize ? AssignEnvironment(result) : result;
+ if ((instr->is_external() || instr->is_fixed_typed_array()) ?
+ // see LCodeGen::DoLoadKeyedExternalArray
+ ((elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+ elements_kind == UINT32_ELEMENTS) &&
+ !instr->CheckFlag(HInstruction::kUint32)) :
+ // see LCodeGen::DoLoadKeyedFixedDoubleArray and
+ // LCodeGen::DoLoadKeyedFixedArray
+ instr->RequiresHoleCheck()) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
@@ -2280,11 +2313,11 @@
// We need a temporary register for write barrier of the map field.
LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
- LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp);
- if (instr->field_representation().IsHeapObject()) {
- if (!instr->value()->type().IsHeapObject()) {
- return AssignEnvironment(result);
- }
+ LInstruction* result = new(zone()) LStoreNamedField(obj, val, temp);
+ if (!instr->access().IsExternalMemory() &&
+ instr->field_representation().IsHeapObject() &&
+ !instr->value()->type().IsHeapObject()) {
+ result = AssignEnvironment(result);
}
return result;
}
@@ -2316,7 +2349,7 @@
LOperand* context = UseAny(instr->context());
LStringCharCodeAt* result =
new(zone()) LStringCharCodeAt(context, string, index);
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ return AssignPointerMap(DefineAsRegister(result));
}
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 34eb510..a09d6f6 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -97,6 +97,7 @@
V(DummyUse) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
+ V(FlooringDivI) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
@@ -713,14 +714,14 @@
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
- LDivI(LOperand* left, LOperand* right, LOperand* temp) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
+ inputs_[0] = dividend;
+ inputs_[1] = divisor;
temps_[0] = temp;
}
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
+ LOperand* dividend() { return inputs_[0]; }
+ LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
@@ -767,6 +768,23 @@
};
+class LFlooringDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+ LFlooringDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
+ inputs_[0] = dividend;
+ inputs_[1] = divisor;
+ temps_[0] = temp;
+ }
+
+ LOperand* dividend() { return inputs_[0]; }
+ LOperand* divisor() { return inputs_[1]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
+ DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+};
+
+
class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LMulI(LOperand* left, LOperand* right) {
@@ -2722,12 +2740,13 @@
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivByConstI(HDiv* instr);
- LInstruction* DoDivI(HBinaryOperation* instr);
+ LInstruction* DoDivI(HDiv* instr);
LInstruction* DoModByPowerOf2I(HMod* instr);
LInstruction* DoModByConstI(HMod* instr);
LInstruction* DoModI(HMod* instr);
LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);
+ LInstruction* DoFlooringDivI(HMathFloorOfDiv* instr);
private:
enum Status {
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index b02574b..63e60ba 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -1293,7 +1293,7 @@
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister(instr->result());
- ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
+ ASSERT(divisor == kMinInt || IsPowerOf2(Abs(divisor)));
ASSERT(!result.is(dividend));
// Check for (0 / -x) that will produce negative zero.
@@ -1363,15 +1363,16 @@
}
+// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
void LCodeGen::DoDivI(LDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
- Register left = ToRegister(instr->left());
- Register right = ToRegister(instr->right());
+ Register dividend = ToRegister(instr->dividend());
+ Register divisor = ToRegister(instr->divisor());
Register result = ToRegister(instr->result());
// Check for x / 0.
if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
- __ cmp(right, Operand::Zero());
+ __ cmp(divisor, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
@@ -1380,10 +1381,10 @@
Label positive;
if (!instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
// Do the test only if it hadn't be done above.
- __ cmp(right, Operand::Zero());
+ __ cmp(divisor, Operand::Zero());
}
__ b(pl, &positive);
- __ cmp(left, Operand::Zero());
+ __ cmp(dividend, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
__ bind(&positive);
}
@@ -1394,39 +1395,30 @@
!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
// We don't need to check for overflow when truncating with sdiv
// support because, on ARM, sdiv kMinInt, -1 -> kMinInt.
- __ cmp(left, Operand(kMinInt));
- __ cmp(right, Operand(-1), eq);
+ __ cmp(dividend, Operand(kMinInt));
+ __ cmp(divisor, Operand(-1), eq);
DeoptimizeIf(eq, instr->environment());
}
if (CpuFeatures::IsSupported(SUDIV)) {
CpuFeatureScope scope(masm(), SUDIV);
- __ sdiv(result, left, right);
+ __ sdiv(result, dividend, divisor);
} else {
DoubleRegister vleft = ToDoubleRegister(instr->temp());
DoubleRegister vright = double_scratch0();
- __ vmov(double_scratch0().low(), left);
+ __ vmov(double_scratch0().low(), dividend);
__ vcvt_f64_s32(vleft, double_scratch0().low());
- __ vmov(double_scratch0().low(), right);
+ __ vmov(double_scratch0().low(), divisor);
__ vcvt_f64_s32(vright, double_scratch0().low());
__ vdiv(vleft, vleft, vright); // vleft now contains the result.
__ vcvt_s32_f64(double_scratch0().low(), vleft);
__ vmov(result, double_scratch0().low());
}
- if (hdiv->IsMathFloorOfDiv()) {
- Label done;
- Register remainder = scratch0();
- __ mls(remainder, result, right, left);
- __ cmp(remainder, Operand::Zero());
- __ b(eq, &done);
- __ eor(remainder, remainder, Operand(right));
- __ add(result, result, Operand(remainder, ASR, 31));
- __ bind(&done);
- } else if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
+ if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
// Compute remainder and deopt if it's not zero.
Register remainder = scratch0();
- __ mls(remainder, result, right, left);
+ __ mls(remainder, result, divisor, dividend);
__ cmp(remainder, Operand::Zero());
DeoptimizeIf(ne, instr->environment());
}
@@ -1538,6 +1530,69 @@
}
+// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
+void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
+ HBinaryOperation* hdiv = instr->hydrogen();
+ Register left = ToRegister(instr->dividend());
+ Register right = ToRegister(instr->divisor());
+ Register result = ToRegister(instr->result());
+
+ // Check for x / 0.
+ if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
+ __ cmp(right, Operand::Zero());
+ DeoptimizeIf(eq, instr->environment());
+ }
+
+ // Check for (0 / -x) that will produce negative zero.
+ if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ Label positive;
+ if (!instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
+ // Do the test only if it hadn't be done above.
+ __ cmp(right, Operand::Zero());
+ }
+ __ b(pl, &positive);
+ __ cmp(left, Operand::Zero());
+ DeoptimizeIf(eq, instr->environment());
+ __ bind(&positive);
+ }
+
+ // Check for (kMinInt / -1).
+ if (hdiv->CheckFlag(HValue::kCanOverflow) &&
+ (!CpuFeatures::IsSupported(SUDIV) ||
+ !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
+ // We don't need to check for overflow when truncating with sdiv
+ // support because, on ARM, sdiv kMinInt, -1 -> kMinInt.
+ __ cmp(left, Operand(kMinInt));
+ __ cmp(right, Operand(-1), eq);
+ DeoptimizeIf(eq, instr->environment());
+ }
+
+ if (CpuFeatures::IsSupported(SUDIV)) {
+ CpuFeatureScope scope(masm(), SUDIV);
+ __ sdiv(result, left, right);
+ } else {
+ DoubleRegister vleft = ToDoubleRegister(instr->temp());
+ DoubleRegister vright = double_scratch0();
+ __ vmov(double_scratch0().low(), left);
+ __ vcvt_f64_s32(vleft, double_scratch0().low());
+ __ vmov(double_scratch0().low(), right);
+ __ vcvt_f64_s32(vright, double_scratch0().low());
+ __ vdiv(vleft, vleft, vright); // vleft now contains the result.
+ __ vcvt_s32_f64(double_scratch0().low(), vleft);
+ __ vmov(result, double_scratch0().low());
+ }
+
+ Label done;
+ Register remainder = scratch0();
+ __ mls(remainder, result, right, left);
+ __ cmp(remainder, Operand::Zero());
+ __ b(eq, &done);
+ __ eor(remainder, remainder, Operand(right));
+ __ add(result, result, Operand(remainder, ASR, 31));
+ __ bind(&done);
+}
+
+
void LCodeGen::DoMulI(LMulI* instr) {
Register result = ToRegister(instr->result());
// Note that result may alias left.
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 2bfe09f..076c042 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -989,7 +989,6 @@
}
if (FLAG_enable_ool_constant_pool) {
str(pp, MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
- LoadConstantPoolPointerRegister();
}
mov(ip, Operand(CodeObject()));
str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset));
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 6b6ecd3..9230df0 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -1524,11 +1524,12 @@
type_(type),
old_has_frame_(masm->has_frame()),
old_constant_pool_available_(masm->is_constant_pool_available()) {
+ // We only want to enable constant pool access for non-manual frame scopes
+ // to ensure the constant pool pointer is valid throughout the scope.
+ ASSERT(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
masm->set_has_frame(true);
masm->set_constant_pool_available(true);
- if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) {
- masm->EnterFrame(type, !old_constant_pool_available_);
- }
+ masm->EnterFrame(type, !old_constant_pool_available_);
}
~FrameAndConstantPoolScope() {
diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc
index 4bed135..1888aff 100644
--- a/src/arm64/lithium-arm64.cc
+++ b/src/arm64/lithium-arm64.cc
@@ -1074,63 +1074,61 @@
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()) {
+ // Note: Only deopts in deferred code.
+ 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));
}
@@ -1138,37 +1136,35 @@
} 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;
}
@@ -1189,21 +1185,20 @@
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));
- }
+ LOperand* value = NULL;
+ LOperand* temp = NULL;
+ if (!instr->CanOmitMapChecks()) {
+ value = UseRegisterAtStart(instr->value());
+ temp = TempRegister();
+ if (instr->has_migration_target()) info()->MarkAsDeferredCalling();
}
+ LInstruction* result = new(zone()) LCheckMaps(value, temp);
+ if (!instr->CanOmitMapChecks()) {
+ // Note: Only deopts in deferred code.
+ result = AssignEnvironment(result);
+ if (instr->has_migration_target()) return AssignPointerMap(result);
+ }
+ return result;
}
@@ -1418,8 +1413,12 @@
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;
}
@@ -1622,7 +1621,10 @@
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;
}
@@ -1687,17 +1689,14 @@
IsDoubleOrFloatElementsKind(instr->elements_kind())));
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;
}
}
@@ -1885,13 +1884,10 @@
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
@@ -1911,26 +1907,27 @@
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);
@@ -2160,7 +2157,10 @@
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;
}
@@ -2294,7 +2294,7 @@
LOperand* context = UseAny(instr->context());
LStringCharCodeAt* result =
new(zone()) LStringCharCodeAt(context, string, index);
- return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+ return AssignPointerMap(DefineAsRegister(result));
}
@@ -2430,21 +2430,15 @@
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));
+ // Note: Only deopts in deferred code.
+ 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: {
diff --git a/src/arm64/lithium-arm64.h b/src/arm64/lithium-arm64.h
index fcb1552..0b9d6e4 100644
--- a/src/arm64/lithium-arm64.h
+++ b/src/arm64/lithium-arm64.h
@@ -927,7 +927,7 @@
class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 1> {
public:
- explicit LCheckMaps(LOperand* value, LOperand* temp = NULL) {
+ explicit LCheckMaps(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
@@ -1324,14 +1324,14 @@
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
- LDivI(LOperand* left, LOperand* right, LOperand* temp) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
+ inputs_[0] = dividend;
+ inputs_[1] = divisor;
temps_[0] = temp;
}
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
+ LOperand* dividend() { return inputs_[0]; }
+ LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc
index bea79ba..9b8156e 100644
--- a/src/arm64/lithium-codegen-arm64.cc
+++ b/src/arm64/lithium-codegen-arm64.cc
@@ -2636,7 +2636,7 @@
Register dividend = ToRegister32(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister32(instr->result());
- ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
+ ASSERT(divisor == kMinInt || IsPowerOf2(Abs(divisor)));
ASSERT(!result.is(dividend));
// Check for (0 / -x) that will produce negative zero.
@@ -2707,10 +2707,11 @@
}
+// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
void LCodeGen::DoDivI(LDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
- Register dividend = ToRegister32(instr->left());
- Register divisor = ToRegister32(instr->right());
+ Register dividend = ToRegister32(instr->dividend());
+ Register divisor = ToRegister32(instr->divisor());
Register result = ToRegister32(instr->result());
// Issue the division first, and then check for any deopt cases whilst the
@@ -3936,6 +3937,7 @@
}
+// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
Register dividend = ToRegister32(instr->dividend());
Register divisor = ToRegister32(instr->divisor());
diff --git a/src/arm64/macro-assembler-arm64-inl.h b/src/arm64/macro-assembler-arm64-inl.h
index 4fd6d76..06bcd11 100644
--- a/src/arm64/macro-assembler-arm64-inl.h
+++ b/src/arm64/macro-assembler-arm64-inl.h
@@ -1513,12 +1513,9 @@
void MacroAssembler::Claim(const Register& count, uint64_t unit_size) {
+ if (unit_size == 0) return;
ASSERT(IsPowerOf2(unit_size));
- if (unit_size == 0) {
- return;
- }
-
const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
const Operand size(count, LSL, shift);
@@ -1535,7 +1532,7 @@
void MacroAssembler::ClaimBySMI(const Register& count_smi, uint64_t unit_size) {
- ASSERT(IsPowerOf2(unit_size));
+ ASSERT(unit_size == 0 || IsPowerOf2(unit_size));
const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
const Operand size(count_smi,
(shift >= 0) ? (LSL) : (LSR),
@@ -1574,12 +1571,9 @@
void MacroAssembler::Drop(const Register& count, uint64_t unit_size) {
+ if (unit_size == 0) return;
ASSERT(IsPowerOf2(unit_size));
- if (unit_size == 0) {
- return;
- }
-
const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
const Operand size(count, LSL, shift);
@@ -1599,7 +1593,7 @@
void MacroAssembler::DropBySMI(const Register& count_smi, uint64_t unit_size) {
- ASSERT(IsPowerOf2(unit_size));
+ ASSERT(unit_size == 0 || IsPowerOf2(unit_size));
const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
const Operand size(count_smi,
(shift >= 0) ? (LSL) : (LSR),
diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc
index cd475b4..d8930c9 100644
--- a/src/arm64/simulator-arm64.cc
+++ b/src/arm64/simulator-arm64.cc
@@ -2108,8 +2108,9 @@
// Rotate source bitfield into place.
int64_t result = (static_cast<uint64_t>(src) >> R) | (src << (reg_size - R));
// Determine the sign extension.
- int64_t topbits = ((1L << (reg_size - diff - 1)) - 1) << (diff + 1);
- int64_t signbits = extend && ((src >> S) & 1) ? topbits : 0;
+ int64_t topbits_preshift = (1L << (reg_size - diff - 1)) - 1;
+ int64_t signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0)
+ << (diff + 1);
// Merge sign extension, dest/zero and bitfield.
result = signbits | (result & mask) | (dst & ~mask);
diff --git a/src/atomicops_internals_x86_gcc.cc b/src/atomicops_internals_x86_gcc.cc
index 950b423..a119cd2 100644
--- a/src/atomicops_internals_x86_gcc.cc
+++ b/src/atomicops_internals_x86_gcc.cc
@@ -77,10 +77,10 @@
void AtomicOps_Internalx86CPUFeaturesInit() {
using v8::internal::AtomicOps_Internalx86CPUFeatures;
- uint32_t eax;
- uint32_t ebx;
- uint32_t ecx;
- uint32_t edx;
+ uint32_t eax = 0;
+ uint32_t ebx = 0;
+ uint32_t ecx = 0;
+ uint32_t edx = 0;
// Get vendor string (issue CPUID with eax = 0)
cpuid(eax, ebx, ecx, edx, 0);
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index dc0d902..9a42e36 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -328,9 +328,8 @@
static void SetObjectPrototype(Handle<JSObject> object, Handle<Object> proto) {
// object.__proto__ = proto;
- Factory* factory = object->GetIsolate()->factory();
Handle<Map> old_to_map = Handle<Map>(object->map());
- Handle<Map> new_to_map = factory->CopyMap(old_to_map);
+ Handle<Map> new_to_map = Map::Copy(old_to_map);
new_to_map->set_prototype(*proto);
object->set_map(*new_to_map);
}
@@ -1017,7 +1016,7 @@
initial_map->set_visitor_id(StaticVisitorBase::GetVisitorId(*initial_map));
// RegExp prototype object is itself a RegExp.
- Handle<Map> proto_map = factory->CopyMap(initial_map);
+ Handle<Map> proto_map = Map::Copy(initial_map);
proto_map->set_prototype(native_context()->initial_object_prototype());
Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map);
proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex,
@@ -1150,7 +1149,7 @@
Handle<Map> old_map(
native_context()->sloppy_arguments_boilerplate()->map());
- Handle<Map> new_map = factory->CopyMap(old_map);
+ Handle<Map> new_map = Map::Copy(old_map);
new_map->set_pre_allocated_property_fields(2);
Handle<JSObject> result = factory->NewJSObjectFromMap(new_map);
// Set elements kind after allocating the object because
@@ -1359,15 +1358,15 @@
// Create maps for generator functions and their prototypes. Store those
// maps in the native context.
Handle<Map> function_map(native_context()->sloppy_function_map());
- Handle<Map> generator_function_map = factory()->CopyMap(function_map);
+ Handle<Map> generator_function_map = Map::Copy(function_map);
generator_function_map->set_prototype(*generator_function_prototype);
native_context()->set_sloppy_generator_function_map(
*generator_function_map);
Handle<Map> strict_mode_function_map(
native_context()->strict_function_map());
- Handle<Map> strict_mode_generator_function_map = factory()->CopyMap(
- strict_mode_function_map);
+ Handle<Map> strict_mode_generator_function_map =
+ Map::Copy(strict_mode_function_map);
strict_mode_generator_function_map->set_prototype(
*generator_function_prototype);
native_context()->set_strict_generator_function_map(
@@ -1612,7 +1611,7 @@
array_function->shared()->DontAdaptArguments();
Handle<Map> original_map(array_function->initial_map());
- Handle<Map> initial_map = factory()->CopyMap(original_map);
+ Handle<Map> initial_map = Map::Copy(original_map);
initial_map->set_elements_kind(elements_kind);
array_function->set_initial_map(*initial_map);
@@ -2000,7 +1999,7 @@
}
#ifdef VERIFY_HEAP
- builtins->Verify();
+ builtins->ObjectVerify();
#endif
return true;
@@ -2524,7 +2523,7 @@
// Transfer the prototype (new map is needed).
Handle<Map> old_to_map = Handle<Map>(to->map());
- Handle<Map> new_to_map = factory()->CopyMap(old_to_map);
+ Handle<Map> new_to_map = Map::Copy(old_to_map);
new_to_map->set_prototype(from->map()->prototype());
to->set_map(*new_to_map);
}
diff --git a/src/elements-kind.cc b/src/elements-kind.cc
index ff458e0..7b1a65a 100644
--- a/src/elements-kind.cc
+++ b/src/elements-kind.cc
@@ -172,8 +172,27 @@
}
+static bool IsTypedArrayElementsKind(ElementsKind elements_kind) {
+ return IsFixedTypedArrayElementsKind(elements_kind) ||
+ IsExternalArrayElementsKind(elements_kind);
+}
+
+
bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
ElementsKind to_kind) {
+ if (IsTypedArrayElementsKind(from_kind) ||
+ IsTypedArrayElementsKind(to_kind)) {
+ switch (from_kind) {
+#define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case TYPE##_ELEMENTS: \
+ return to_kind == EXTERNAL_##TYPE##_ELEMENTS;
+
+ TYPED_ARRAYS(FIXED_TYPED_ARRAY_CASE);
+#undef FIXED_TYPED_ARRAY_CASE
+ default:
+ return false;
+ }
+ }
switch (from_kind) {
case FAST_SMI_ELEMENTS:
return to_kind != FAST_SMI_ELEMENTS;
diff --git a/src/execution.cc b/src/execution.cc
index da07d0f..2e16413 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -519,11 +519,9 @@
void StackGuard::DebugCommand() {
- if (FLAG_debugger_auto_break) {
- ExecutionAccess access(isolate_);
- thread_local_.interrupt_flags_ |= DEBUGCOMMAND;
- set_interrupt_limits(access);
- }
+ ExecutionAccess access(isolate_);
+ thread_local_.interrupt_flags_ |= DEBUGCOMMAND;
+ set_interrupt_limits(access);
}
#endif
diff --git a/src/factory.cc b/src/factory.cc
index cd30743..86b72f6 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -845,11 +845,6 @@
}
-Handle<Map> Factory::CopyMap(Handle<Map> src) {
- CALL_HEAP_FUNCTION(isolate(), src->Copy(), Map);
-}
-
-
Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
CALL_HEAP_FUNCTION(isolate(), array->Copy(), FixedArray);
}
diff --git a/src/factory.h b/src/factory.h
index da58a71..8b3d2aa 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -261,7 +261,6 @@
// Copy the map adding more inobject properties if possible without
// overflowing the instance size.
Handle<Map> CopyMap(Handle<Map> map, int extra_inobject_props);
- Handle<Map> CopyMap(Handle<Map> map);
Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 3f0f7ec..f3eaac8 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -471,9 +471,6 @@
"trace out-of-bounds accesses to all arrays")
DEFINE_implication(trace_array_abuse, trace_js_array_abuse)
DEFINE_implication(trace_array_abuse, trace_external_array_abuse)
-DEFINE_bool(debugger_auto_break, true,
- "automatically set the debug break flag when debugger commands are "
- "in the queue")
DEFINE_bool(enable_liveedit, true, "enable liveedit experimental feature")
DEFINE_bool(hard_abort, true, "abort by crashing")
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index afe5b71..1af2784 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -252,8 +252,8 @@
segment_(segment),
align_(align),
flags_(flags) {
- ASSERT(IsPowerOf2(align));
if (align_ != 0) {
+ ASSERT(IsPowerOf2(align));
align_ = WhichPowerOf2(align_);
}
}
diff --git a/src/heap.cc b/src/heap.cc
index 6374433..f06b8be 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -4964,8 +4964,6 @@
switch (string->map()->instance_type()) {
case STRING_TYPE: return internalized_string_map();
case ASCII_STRING_TYPE: return ascii_internalized_string_map();
- case CONS_STRING_TYPE: return cons_internalized_string_map();
- case CONS_ASCII_STRING_TYPE: return cons_ascii_internalized_string_map();
case EXTERNAL_STRING_TYPE: return external_internalized_string_map();
case EXTERNAL_ASCII_STRING_TYPE:
return external_ascii_internalized_string_map();
diff --git a/src/heap.h b/src/heap.h
index 0f586e9..4b67a95 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -109,8 +109,6 @@
ShortExternalStringWithOneByteDataMap) \
V(Map, internalized_string_map, InternalizedStringMap) \
V(Map, ascii_internalized_string_map, AsciiInternalizedStringMap) \
- V(Map, cons_internalized_string_map, ConsInternalizedStringMap) \
- V(Map, cons_ascii_internalized_string_map, ConsAsciiInternalizedStringMap) \
V(Map, \
external_internalized_string_map, \
ExternalInternalizedStringMap) \
@@ -376,7 +374,9 @@
V(next_string, "next") \
V(byte_length_string, "byteLength") \
V(byte_offset_string, "byteOffset") \
- V(buffer_string, "buffer")
+ V(buffer_string, "buffer") \
+ V(intl_initialized_marker_string, "v8::intl_initialized_marker") \
+ V(intl_impl_object_string, "v8::intl_object")
// Forward declarations.
class GCTracer;
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 84dcb18..d12d47e 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1561,6 +1561,7 @@
HUnaryOperation::PrintDataTo(stream);
stream->Add(" %s to %s", from().Mnemonic(), to().Mnemonic());
+ if (CanTruncateToSmi()) stream->Add(" truncating-smi");
if (CanTruncateToInt32()) stream->Add(" truncating-int32");
if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
if (CheckFlag(kAllowUndefinedAsNaN)) stream->Add(" allow-undefined-as-nan");
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index f920a65..a6a1f86 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -1263,6 +1263,7 @@
position_.set_operand_position(index, pos);
}
+ bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
@@ -1733,7 +1734,7 @@
set_representation(to);
SetFlag(kUseGVN);
SetFlag(kCanOverflow);
- if (is_truncating_to_smi) {
+ if (is_truncating_to_smi && to.IsSmi()) {
SetFlag(kTruncatingToSmi);
SetFlag(kTruncatingToInt32);
}
@@ -3761,7 +3762,7 @@
bool RightIsPowerOf2() {
if (!right()->IsInteger32Constant()) return false;
int32_t value = right()->GetInteger32Constant();
- return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value));
+ return IsPowerOf2(value) || IsPowerOf2(-value);
}
DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 80eff3b..24c2ab4 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -5488,16 +5488,11 @@
Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor));
if (accessor->shared()->IsApiFunction()) {
CallOptimization call_optimization(accessor);
- if (!call_optimization.is_simple_api_call()) return false;
- CallOptimization::HolderLookup holder_lookup;
- api_holder_ = call_optimization.LookupHolderOfExpectedType(
- map, &holder_lookup);
- switch (holder_lookup) {
- case CallOptimization::kHolderNotFound:
- return false;
- case CallOptimization::kHolderIsReceiver:
- case CallOptimization::kHolderFound:
- break;
+ if (call_optimization.is_simple_api_call()) {
+ CallOptimization::HolderLookup holder_lookup;
+ Handle<Map> receiver_map = this->map();
+ api_holder_ = call_optimization.LookupHolderOfExpectedType(
+ receiver_map, &holder_lookup);
}
}
accessor_ = accessor;
@@ -7071,6 +7066,11 @@
return target_shared->inline_builtin() ? 0 : kNotInlinable;
}
+ if (target_shared->IsApiFunction()) {
+ TraceInline(target, caller, "target is api function");
+ return kNotInlinable;
+ }
+
// Do a quick check on source code length to avoid parsing large
// inlining candidates.
if (target_shared->SourceSize() >
diff --git a/src/i18n.js b/src/i18n.js
index 2e54857..edfb065 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -232,8 +232,7 @@
*/
function addBoundMethod(obj, methodName, implementation, length) {
function getter() {
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject === undefined) {
+ if (!%IsInitializedIntlObject(this)) {
throw new $TypeError('Method ' + methodName + ' called on a ' +
'non-object or on a wrong type of object.');
}
@@ -896,7 +895,7 @@
* Useful for subclassing.
*/
function initializeCollator(collator, locales, options) {
- if (collator.hasOwnProperty('__initializedIntlObject')) {
+ if (%IsInitializedIntlObject(collator)) {
throw new $TypeError('Trying to re-initialize Collator object.');
}
@@ -967,9 +966,7 @@
resolved);
// Writable, configurable and enumerable are set to false by default.
- $Object.defineProperty(collator, 'collator', {value: internalCollator});
- $Object.defineProperty(collator, '__initializedIntlObject',
- {value: 'collator'});
+ %MarkAsInitializedIntlObjectOfType(collator, 'collator', internalCollator);
$Object.defineProperty(collator, 'resolved', {value: resolved});
return collator;
@@ -1005,8 +1002,7 @@
throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject !== 'collator') {
+ if (!%IsInitializedIntlObjectOfType(this, 'collator')) {
throw new $TypeError('resolvedOptions method called on a non-object ' +
'or on a object that is not Intl.Collator.');
}
@@ -1063,7 +1059,8 @@
* the sort order, or x comes after y in the sort order, respectively.
*/
function compare(collator, x, y) {
- return %InternalCompare(collator.collator, $String(x), $String(y));
+ return %InternalCompare(%GetImplFromInitializedIntlObject(collator),
+ $String(x), $String(y));
};
@@ -1104,7 +1101,7 @@
* Useful for subclassing.
*/
function initializeNumberFormat(numberFormat, locales, options) {
- if (numberFormat.hasOwnProperty('__initializedIntlObject')) {
+ if (%IsInitializedIntlObject(numberFormat)) {
throw new $TypeError('Trying to re-initialize NumberFormat object.');
}
@@ -1196,10 +1193,8 @@
writable: true});
}
- $Object.defineProperty(numberFormat, 'formatter', {value: formatter});
+ %MarkAsInitializedIntlObjectOfType(numberFormat, 'numberformat', formatter);
$Object.defineProperty(numberFormat, 'resolved', {value: resolved});
- $Object.defineProperty(numberFormat, '__initializedIntlObject',
- {value: 'numberformat'});
return numberFormat;
}
@@ -1234,8 +1229,7 @@
throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject !== 'numberformat') {
+ if (!%IsInitializedIntlObjectOfType(this, 'numberformat')) {
throw new $TypeError('resolvedOptions method called on a non-object' +
' or on a object that is not Intl.NumberFormat.');
}
@@ -1309,7 +1303,8 @@
// Spec treats -0 and +0 as 0.
var number = $Number(value) + 0;
- return %InternalNumberFormat(formatter.formatter, number);
+ return %InternalNumberFormat(%GetImplFromInitializedIntlObject(formatter),
+ number);
}
@@ -1317,7 +1312,8 @@
* Returns a Number that represents string value that was passed in.
*/
function parseNumber(formatter, value) {
- return %InternalNumberParse(formatter.formatter, $String(value));
+ return %InternalNumberParse(%GetImplFromInitializedIntlObject(formatter),
+ $String(value));
}
@@ -1530,7 +1526,7 @@
*/
function initializeDateTimeFormat(dateFormat, locales, options) {
- if (dateFormat.hasOwnProperty('__initializedIntlObject')) {
+ if (%IsInitializedIntlObject(dateFormat)) {
throw new $TypeError('Trying to re-initialize DateTimeFormat object.');
}
@@ -1592,10 +1588,8 @@
throw new $RangeError('Unsupported time zone specified ' + tz);
}
- $Object.defineProperty(dateFormat, 'formatter', {value: formatter});
+ %MarkAsInitializedIntlObjectOfType(dateFormat, 'dateformat', formatter);
$Object.defineProperty(dateFormat, 'resolved', {value: resolved});
- $Object.defineProperty(dateFormat, '__initializedIntlObject',
- {value: 'dateformat'});
return dateFormat;
}
@@ -1630,8 +1624,7 @@
throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject !== 'dateformat') {
+ if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) {
throw new $TypeError('resolvedOptions method called on a non-object or ' +
'on a object that is not Intl.DateTimeFormat.');
}
@@ -1713,7 +1706,8 @@
throw new $RangeError('Provided date is not in valid range.');
}
- return %InternalDateFormat(formatter.formatter, new $Date(dateMs));
+ return %InternalDateFormat(%GetImplFromInitializedIntlObject(formatter),
+ new $Date(dateMs));
}
@@ -1724,7 +1718,8 @@
* Returns undefined if date string cannot be parsed.
*/
function parseDate(formatter, value) {
- return %InternalDateParse(formatter.formatter, $String(value));
+ return %InternalDateParse(%GetImplFromInitializedIntlObject(formatter),
+ $String(value));
}
@@ -1772,7 +1767,7 @@
* Useful for subclassing.
*/
function initializeBreakIterator(iterator, locales, options) {
- if (iterator.hasOwnProperty('__initializedIntlObject')) {
+ if (%IsInitializedIntlObject(iterator)) {
throw new $TypeError('Trying to re-initialize v8BreakIterator object.');
}
@@ -1798,10 +1793,9 @@
internalOptions,
resolved);
- $Object.defineProperty(iterator, 'iterator', {value: internalIterator});
+ %MarkAsInitializedIntlObjectOfType(iterator, 'breakiterator',
+ internalIterator);
$Object.defineProperty(iterator, 'resolved', {value: resolved});
- $Object.defineProperty(iterator, '__initializedIntlObject',
- {value: 'breakiterator'});
return iterator;
}
@@ -1836,8 +1830,7 @@
throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject !== 'breakiterator') {
+ if (!%IsInitializedIntlObjectOfType(this, 'breakiterator')) {
throw new $TypeError('resolvedOptions method called on a non-object or ' +
'on a object that is not Intl.v8BreakIterator.');
}
@@ -1884,7 +1877,8 @@
* gets discarded.
*/
function adoptText(iterator, text) {
- %BreakIteratorAdoptText(iterator.iterator, $String(text));
+ %BreakIteratorAdoptText(%GetImplFromInitializedIntlObject(iterator),
+ $String(text));
}
@@ -1892,7 +1886,7 @@
* Returns index of the first break in the string and moves current pointer.
*/
function first(iterator) {
- return %BreakIteratorFirst(iterator.iterator);
+ return %BreakIteratorFirst(%GetImplFromInitializedIntlObject(iterator));
}
@@ -1900,7 +1894,7 @@
* Returns the index of the next break and moves the pointer.
*/
function next(iterator) {
- return %BreakIteratorNext(iterator.iterator);
+ return %BreakIteratorNext(%GetImplFromInitializedIntlObject(iterator));
}
@@ -1908,7 +1902,7 @@
* Returns index of the current break.
*/
function current(iterator) {
- return %BreakIteratorCurrent(iterator.iterator);
+ return %BreakIteratorCurrent(%GetImplFromInitializedIntlObject(iterator));
}
@@ -1916,7 +1910,7 @@
* Returns type of the current break.
*/
function breakType(iterator) {
- return %BreakIteratorBreakType(iterator.iterator);
+ return %BreakIteratorBreakType(%GetImplFromInitializedIntlObject(iterator));
}
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 4ffbe53..6c934b7 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -1493,7 +1493,7 @@
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister(instr->result());
- ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
+ ASSERT(divisor == kMinInt || IsPowerOf2(Abs(divisor)));
ASSERT(!result.is(dividend));
// Check for (0 / -x) that will produce negative zero.
@@ -1556,15 +1556,15 @@
}
+// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
void LCodeGen::DoDivI(LDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
- Register dividend = ToRegister(instr->left());
- Register divisor = ToRegister(instr->right());
+ Register dividend = ToRegister(instr->dividend());
+ Register divisor = ToRegister(instr->divisor());
Register remainder = ToRegister(instr->temp());
- Register result = ToRegister(instr->result());
ASSERT(dividend.is(eax));
ASSERT(remainder.is(edx));
- ASSERT(result.is(eax));
+ ASSERT(ToRegister(instr->result()).is(eax));
ASSERT(!divisor.is(eax));
ASSERT(!divisor.is(edx));
@@ -1598,15 +1598,7 @@
__ cdq();
__ idiv(divisor);
- if (hdiv->IsMathFloorOfDiv()) {
- Label done;
- __ test(remainder, remainder);
- __ j(zero, &done, Label::kNear);
- __ xor_(remainder, divisor);
- __ sar(remainder, 31);
- __ add(result, remainder);
- __ bind(&done);
- } else if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
+ if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
// Deoptimize if remainder is not 0.
__ test(remainder, remainder);
DeoptimizeIf(not_zero, instr->environment());
@@ -1696,6 +1688,59 @@
}
+// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
+void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
+ HBinaryOperation* hdiv = instr->hydrogen();
+ Register dividend = ToRegister(instr->dividend());
+ Register divisor = ToRegister(instr->divisor());
+ Register remainder = ToRegister(instr->temp());
+ Register result = ToRegister(instr->result());
+ ASSERT(dividend.is(eax));
+ ASSERT(remainder.is(edx));
+ ASSERT(result.is(eax));
+ ASSERT(!divisor.is(eax));
+ ASSERT(!divisor.is(edx));
+
+ // Check for x / 0.
+ if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
+ __ test(divisor, divisor);
+ DeoptimizeIf(zero, instr->environment());
+ }
+
+ // Check for (0 / -x) that will produce negative zero.
+ if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ Label dividend_not_zero;
+ __ test(dividend, dividend);
+ __ j(not_zero, ÷nd_not_zero, Label::kNear);
+ __ test(divisor, divisor);
+ DeoptimizeIf(sign, instr->environment());
+ __ bind(÷nd_not_zero);
+ }
+
+ // Check for (kMinInt / -1).
+ if (hdiv->CheckFlag(HValue::kCanOverflow)) {
+ Label dividend_not_min_int;
+ __ cmp(dividend, kMinInt);
+ __ j(not_zero, ÷nd_not_min_int, Label::kNear);
+ __ cmp(divisor, -1);
+ DeoptimizeIf(zero, instr->environment());
+ __ bind(÷nd_not_min_int);
+ }
+
+ // Sign extend to edx (= remainder).
+ __ cdq();
+ __ idiv(divisor);
+
+ Label done;
+ __ test(remainder, remainder);
+ __ j(zero, &done, Label::kNear);
+ __ xor_(remainder, divisor);
+ __ sar(remainder, 31);
+ __ add(result, remainder);
+ __ bind(&done);
+}
+
+
void LCodeGen::DoMulI(LMulI* instr) {
Register left = ToRegister(instr->left());
LOperand* right = instr->right();
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 384a21c..c230deb 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1365,7 +1365,7 @@
}
-LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
+LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
@@ -1377,8 +1377,7 @@
if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanOverflow) ||
- (!instr->IsMathFloorOfDiv() &&
- !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
+ !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
result = AssignEnvironment(result);
}
return result;
@@ -1442,13 +1441,31 @@
}
+LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
+ ASSERT(instr->representation().IsSmiOrInteger32());
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
+ LOperand* dividend = UseFixed(instr->left(), eax);
+ LOperand* divisor = UseRegister(instr->right());
+ LOperand* temp = FixedTemp(edx);
+ LInstruction* result = DefineFixed(new(zone()) LFlooringDivI(
+ dividend, divisor, temp), eax);
+ if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
+ instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
+ instr->CheckFlag(HValue::kCanOverflow)) {
+ result = AssignEnvironment(result);
+ }
+ return result;
+}
+
+
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoFlooringDivByConstI(instr);
} else {
- return DoDivI(instr);
+ return DoFlooringDivI(instr);
}
}
@@ -1882,29 +1899,23 @@
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();
}
- // Only mark conversions that might need to allocate as calling rather than
- // all changes. This makes simple, non-allocating conversion not have to force
- // building a stack frame.
if (from.IsTagged()) {
if (to.IsDouble()) {
- LOperand* value = UseRegister(instr->value());
- // Temp register only necessary for minus zero check.
+ LOperand* value = UseRegister(val);
LOperand* temp = TempRegister();
- LInstruction* result = DefineAsRegister(
- new(zone()) LNumberUntagD(value, temp));
- if (!instr->value()->representation().IsSmi()) {
- result = AssignEnvironment(result);
- }
+ LInstruction* result =
+ DefineAsRegister(new(zone()) LNumberUntagD(value, temp));
+ if (!val->representation().IsSmi()) result = AssignEnvironment(result);
return result;
} else if (to.IsSmi()) {
- HValue* val = instr->value();
LOperand* value = UseRegister(val);
if (val->type().IsSmi()) {
return DefineSameAsFirst(new(zone()) LDummyUse(value));
@@ -1912,18 +1923,18 @@
return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
} else {
ASSERT(to.IsInteger32());
- HValue* val = instr->value();
if (val->type().IsSmi() || val->representation().IsSmi()) {
LOperand* value = UseRegister(val);
return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
} else {
+ LOperand* value = UseRegister(val);
bool truncating = instr->CanTruncateToInt32();
LOperand* xmm_temp =
(CpuFeatures::IsSafeForSnapshot(SSE2) && !truncating)
? FixedTemp(xmm1) : NULL;
- LInstruction* result = DefineSameAsFirst(
- new(zone()) LTaggedToI(UseRegister(val), xmm_temp));
- if (!instr->value()->representation().IsSmi()) {
+ LInstruction* result =
+ DefineSameAsFirst(new(zone()) LTaggedToI(value, xmm_temp));
+ if (!val->representation().IsSmi()) {
// Note: Only deopts in deferred code.
result = AssignEnvironment(result);
}
@@ -1933,23 +1944,20 @@
} else if (from.IsDouble()) {
if (to.IsTagged()) {
info()->MarkAsDeferredCalling();
- LOperand* value = UseRegisterAtStart(instr->value());
+ LOperand* value = UseRegisterAtStart(val);
LOperand* temp = FLAG_inline_new ? TempRegister() : NULL;
-
- // Make sure that temp and result_temp are different registers.
LUnallocated* result_temp = TempRegister();
LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
return AssignPointerMap(Define(result, result_temp));
} else if (to.IsSmi()) {
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseRegister(val);
return AssignEnvironment(
DefineAsRegister(new(zone()) LDoubleToSmi(value)));
} else {
ASSERT(to.IsInteger32());
bool truncating = instr->CanTruncateToInt32();
bool needs_temp = CpuFeatures::IsSafeForSnapshot(SSE2) && !truncating;
- LOperand* value = needs_temp ?
- UseTempRegister(instr->value()) : UseRegister(instr->value());
+ LOperand* value = needs_temp ? UseTempRegister(val) : UseRegister(val);
LOperand* temp = needs_temp ? TempRegister() : NULL;
LInstruction* result =
DefineAsRegister(new(zone()) LDoubleToI(value, temp));
@@ -1959,23 +1967,23 @@
} else if (from.IsInteger32()) {
info()->MarkAsDeferredCalling();
if (to.IsTagged()) {
- HValue* val = instr->value();
- LOperand* value = UseRegister(val);
if (!instr->CheckFlag(HValue::kCanOverflow)) {
+ LOperand* value = UseRegister(val);
return DefineSameAsFirst(new(zone()) LSmiTag(value));
} else if (val->CheckFlag(HInstruction::kUint32)) {
+ LOperand* value = UseRegister(val);
LOperand* temp1 = TempRegister();
- LOperand* temp2 = CpuFeatures::IsSupported(SSE2) ? FixedTemp(xmm1)
- : NULL;
+ LOperand* temp2 =
+ CpuFeatures::IsSupported(SSE2) ? FixedTemp(xmm1) : NULL;
LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
return AssignPointerMap(DefineSameAsFirst(result));
} else {
+ LOperand* value = UseRegister(val);
LOperand* temp = TempRegister();
LNumberTagI* result = new(zone()) LNumberTagI(value, temp);
return AssignPointerMap(DefineSameAsFirst(result));
}
} else if (to.IsSmi()) {
- HValue* val = instr->value();
LOperand* value = UseRegister(val);
LInstruction* result = DefineSameAsFirst(new(zone()) LSmiTag(value));
if (instr->CheckFlag(HValue::kCanOverflow)) {
@@ -1984,13 +1992,12 @@
return result;
} else {
ASSERT(to.IsDouble());
- if (instr->value()->CheckFlag(HInstruction::kUint32)) {
+ if (val->CheckFlag(HInstruction::kUint32)) {
LOperand* temp = FixedTemp(xmm1);
return DefineAsRegister(
- new(zone()) LUint32ToDouble(UseRegister(instr->value()), temp));
+ new(zone()) LUint32ToDouble(UseRegister(val), temp));
} else {
- return DefineAsRegister(
- new(zone()) LInteger32ToDouble(Use(instr->value())));
+ return DefineAsRegister(new(zone()) LInteger32ToDouble(Use(val)));
}
}
}
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 7964b7f..c7b3bc7 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -99,6 +99,7 @@
V(DummyUse) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
+ V(FlooringDivI) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
@@ -744,14 +745,14 @@
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
- LDivI(LOperand* left, LOperand* right, LOperand* temp) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
+ inputs_[0] = dividend;
+ inputs_[1] = divisor;
temps_[0] = temp;
}
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
+ LOperand* dividend() { return inputs_[0]; }
+ LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
@@ -806,6 +807,23 @@
};
+class LFlooringDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+ LFlooringDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
+ inputs_[0] = dividend;
+ inputs_[1] = divisor;
+ temps_[0] = temp;
+ }
+
+ LOperand* dividend() { return inputs_[0]; }
+ LOperand* divisor() { return inputs_[1]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
+ DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+};
+
+
class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LMulI(LOperand* left, LOperand* right, LOperand* temp) {
@@ -2750,12 +2768,13 @@
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivByConstI(HDiv* instr);
- LInstruction* DoDivI(HBinaryOperation* instr);
+ LInstruction* DoDivI(HDiv* instr);
LInstruction* DoModByPowerOf2I(HMod* instr);
LInstruction* DoModByConstI(HMod* instr);
LInstruction* DoModI(HMod* instr);
LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);
+ LInstruction* DoFlooringDivI(HMathFloorOfDiv* instr);
private:
enum Status {
diff --git a/src/ic.cc b/src/ic.cc
index f01c3d1..8b19a60 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -248,12 +248,7 @@
bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
Handle<String> name) {
- if (target()->is_keyed_stub()) {
- // Determine whether the failure is due to a name failure.
- if (!name->IsName()) return false;
- Name* stub_name = target()->FindFirstName();
- if (*name != stub_name) return false;
- }
+ if (!IsNameCompatibleWithMonomorphicPrototypeFailure(name)) return false;
InlineCacheHolderFlag cache_holder =
Code::ExtractCacheHolderFromFlags(target()->flags());
@@ -336,6 +331,18 @@
}
+bool IC::IsNameCompatibleWithMonomorphicPrototypeFailure(Handle<Object> name) {
+ if (target()->is_keyed_stub()) {
+ // Determine whether the failure is due to a name failure.
+ if (!name->IsName()) return false;
+ Name* stub_name = target()->FindFirstName();
+ if (*name != stub_name) return false;
+ }
+
+ return true;
+}
+
+
void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
if (!name->IsString()) return;
if (state() != MONOMORPHIC) {
@@ -352,8 +359,9 @@
// because of changes in the prototype chain to avoid hitting it
// again.
if (TryRemoveInvalidPrototypeDependentStub(
- receiver, Handle<String>::cast(name))) {
- return MarkMonomorphicPrototypeFailure();
+ receiver, Handle<String>::cast(name)) &&
+ TryMarkMonomorphicPrototypeFailure(name)) {
+ return;
}
// The builtins object is special. It only changes when JavaScript
@@ -634,7 +642,7 @@
if (current_type->IsClass() && current_type->AsClass()->is_deprecated()) {
// Filter out deprecated maps to ensure their instances get migrated.
++deprecated_types;
- } else if (type->IsCurrently(current_type)) {
+ } else if (type->NowIs(current_type)) {
// If the receiver type is already in the polymorphic IC, this indicates
// there was a prototoype chain failure. In that case, just overwrite the
// handler.
@@ -658,7 +666,7 @@
number_of_valid_types++;
if (handler_to_overwrite >= 0) {
handlers.Set(handler_to_overwrite, code);
- if (!type->IsCurrently(types.at(handler_to_overwrite))) {
+ if (!type->NowIs(types.at(handler_to_overwrite))) {
types.Set(handler_to_overwrite, type);
}
} else {
@@ -676,7 +684,7 @@
Handle<HeapType> IC::CurrentTypeOf(Handle<Object> object, Isolate* isolate) {
return object->IsJSGlobalObject()
? HeapType::Constant(Handle<JSGlobalObject>::cast(object), isolate)
- : HeapType::OfCurrently(object, isolate);
+ : HeapType::NowOf(object, isolate);
}
@@ -1184,8 +1192,9 @@
// entirely by the migration above.
receiver->map()->LookupTransition(*holder, *name, lookup);
if (!lookup->IsTransition()) return false;
- ic->MarkMonomorphicPrototypeFailure();
+ return ic->TryMarkMonomorphicPrototypeFailure(name);
}
+
return true;
}
diff --git a/src/ic.h b/src/ic.h
index e70cb82..146b26b 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -96,8 +96,14 @@
// Compute the current IC state based on the target stub, receiver and name.
void UpdateState(Handle<Object> receiver, Handle<Object> name);
- void MarkMonomorphicPrototypeFailure() {
- state_ = MONOMORPHIC_PROTOTYPE_FAILURE;
+
+ bool IsNameCompatibleWithMonomorphicPrototypeFailure(Handle<Object> name);
+ bool TryMarkMonomorphicPrototypeFailure(Handle<Object> name) {
+ if (IsNameCompatibleWithMonomorphicPrototypeFailure(name)) {
+ state_ = MONOMORPHIC_PROTOTYPE_FAILURE;
+ return true;
+ }
+ return false;
}
// Clear the inline cache to initial state.
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index f5b99eb..ebeaedf 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -1174,7 +1174,7 @@
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister(instr->result());
- ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
+ ASSERT(divisor == kMinInt || IsPowerOf2(Abs(divisor)));
ASSERT(!result.is(dividend));
// Check for (0 / -x) that will produce negative zero.
diff --git a/src/msan.h b/src/msan.h
index 484c9fa..b07d66d 100644
--- a/src/msan.h
+++ b/src/msan.h
@@ -30,6 +30,8 @@
#ifndef V8_MSAN_H_
#define V8_MSAN_H_
+#include "globals.h"
+
#ifndef __has_feature
# define __has_feature(x) 0
#endif
@@ -38,12 +40,12 @@
# define MEMORY_SANITIZER
#endif
-#ifdef MEMORY_SANITIZER
-# include <sanitizer/msan_interface.h>
+#if defined(MEMORY_SANITIZER) && !defined(USE_SIMULATOR)
+# include <sanitizer/msan_interface.h> // NOLINT
// Marks a memory range as fully initialized.
-# define MSAN_MEMORY_IS_INITIALIZED(p, s) __msan_unpoison((p), (s))
+# define MSAN_MEMORY_IS_INITIALIZED_IN_JIT(p, s) __msan_unpoison((p), (s))
#else
-# define MSAN_MEMORY_IS_INITIALIZED(p, s)
+# define MSAN_MEMORY_IS_INITIALIZED_IN_JIT(p, s)
#endif
#endif // V8_MSAN_H_
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index ca025e6..ba9ff65 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -41,17 +41,22 @@
void MaybeObject::Verify() {
Object* this_as_object;
if (ToObject(&this_as_object)) {
- if (this_as_object->IsSmi()) {
- Smi::cast(this_as_object)->SmiVerify();
- } else {
- HeapObject::cast(this_as_object)->HeapObjectVerify();
- }
+ this_as_object->ObjectVerify();
} else {
Failure::cast(this)->FailureVerify();
}
}
+void Object::ObjectVerify() {
+ if (IsSmi()) {
+ Smi::cast(this)->SmiVerify();
+ } else {
+ HeapObject::cast(this)->HeapObjectVerify();
+ }
+}
+
+
void Object::VerifyPointer(Object* p) {
if (p->IsHeapObject()) {
HeapObject::VerifyHeapPointer(p);
@@ -380,11 +385,7 @@
void FixedArray::FixedArrayVerify() {
for (int i = 0; i < length(); i++) {
Object* e = get(i);
- if (e->IsHeapObject()) {
- VerifyHeapPointer(e);
- } else {
- e->Verify();
- }
+ VerifyPointer(e);
}
}
@@ -626,7 +627,7 @@
void Code::CodeVerify() {
CHECK(IsAligned(reinterpret_cast<intptr_t>(instruction_start()),
kCodeAlignment));
- relocation_info()->Verify();
+ relocation_info()->ObjectVerify();
Address last_gc_pc = NULL;
for (RelocIterator it(this); !it.done(); it.next()) {
it.rinfo()->Verify();
@@ -811,7 +812,7 @@
void Box::BoxVerify() {
CHECK(IsBox());
- value()->Verify();
+ value()->ObjectVerify();
}
@@ -947,7 +948,7 @@
void JSFunctionResultCache::JSFunctionResultCacheVerify() {
- JSFunction::cast(get(kFactoryIndex))->Verify();
+ JSFunction::cast(get(kFactoryIndex))->ObjectVerify();
int size = Smi::cast(get(kCacheSizeIndex))->value();
CHECK(kEntriesIndex <= size);
@@ -962,18 +963,18 @@
if (FLAG_enable_slow_asserts) {
for (int i = kEntriesIndex; i < size; i++) {
CHECK(!get(i)->IsTheHole());
- get(i)->Verify();
+ get(i)->ObjectVerify();
}
for (int i = size; i < length(); i++) {
CHECK(get(i)->IsTheHole());
- get(i)->Verify();
+ get(i)->ObjectVerify();
}
}
}
void NormalizedMapCache::NormalizedMapCacheVerify() {
- FixedArray::cast(this)->Verify();
+ FixedArray::cast(this)->FixedArrayVerify();
if (FLAG_enable_slow_asserts) {
for (int i = 0; i < length(); i++) {
Object* e = get(i);
diff --git a/src/objects.cc b/src/objects.cc
index 92ec283..7057e9a 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -13872,9 +13872,6 @@
}
MaybeObject* AsObject(Heap* heap) {
- // Attempt to flatten the string, so that internalized strings will most
- // often be flat strings.
- string_ = string_->TryFlattenGetString();
// Internalize the string if possible.
Map* map = heap->InternalizedStringMapForString(string_);
if (map != NULL) {
@@ -13914,7 +13911,7 @@
int at_least_space_for,
MinimumCapacity capacity_option,
PretenureFlag pretenure) {
- ASSERT(!capacity_option || IS_POWER_OF_TWO(at_least_space_for));
+ ASSERT(!capacity_option || IsPowerOf2(at_least_space_for));
int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
? at_least_space_for
: ComputeCapacity(at_least_space_for);
diff --git a/src/objects.h b/src/objects.h
index 98bf122..ce4dd50 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -355,8 +355,6 @@
\
V(INTERNALIZED_STRING_TYPE) \
V(ASCII_INTERNALIZED_STRING_TYPE) \
- V(CONS_INTERNALIZED_STRING_TYPE) \
- V(CONS_ASCII_INTERNALIZED_STRING_TYPE) \
V(EXTERNAL_INTERNALIZED_STRING_TYPE) \
V(EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE) \
V(EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE) \
@@ -514,14 +512,6 @@
kVariableSizeSentinel, \
ascii_internalized_string, \
AsciiInternalizedString) \
- V(CONS_INTERNALIZED_STRING_TYPE, \
- ConsString::kSize, \
- cons_internalized_string, \
- ConsInternalizedString) \
- V(CONS_ASCII_INTERNALIZED_STRING_TYPE, \
- ConsString::kSize, \
- cons_ascii_internalized_string, \
- ConsAsciiInternalizedString) \
V(EXTERNAL_INTERNALIZED_STRING_TYPE, \
ExternalTwoByteString::kSize, \
external_internalized_string, \
@@ -631,7 +621,7 @@
// Use this mask to distinguish between cons and slice only after making
// sure that the string is one of the two (an indirect string).
const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
-STATIC_ASSERT(IS_POWER_OF_TWO(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
+STATIC_ASSERT(IS_POWER_OF_TWO(kSlicedNotConsMask));
// If bit 7 is clear, then bit 3 indicates whether this two-byte
// string actually contains one byte data.
@@ -662,10 +652,6 @@
| kInternalizedTag,
ASCII_INTERNALIZED_STRING_TYPE = kOneByteStringTag | kSeqStringTag
| kInternalizedTag,
- CONS_INTERNALIZED_STRING_TYPE = kTwoByteStringTag | kConsStringTag
- | kInternalizedTag,
- CONS_ASCII_INTERNALIZED_STRING_TYPE = kOneByteStringTag | kConsStringTag
- | kInternalizedTag,
EXTERNAL_INTERNALIZED_STRING_TYPE = kTwoByteStringTag | kExternalStringTag
| kInternalizedTag,
EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE = kOneByteStringTag
@@ -685,9 +671,9 @@
STRING_TYPE = INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
ASCII_STRING_TYPE = ASCII_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
- CONS_STRING_TYPE = CONS_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
+ CONS_STRING_TYPE = kTwoByteStringTag | kConsStringTag | kNotInternalizedTag,
CONS_ASCII_STRING_TYPE =
- CONS_ASCII_INTERNALIZED_STRING_TYPE | kNotInternalizedTag,
+ kOneByteStringTag | kConsStringTag | kNotInternalizedTag,
SLICED_STRING_TYPE =
kTwoByteStringTag | kSlicedStringTag | kNotInternalizedTag,
@@ -1629,6 +1615,7 @@
// < the length of the string. Used to implement [] on strings.
inline bool IsStringObjectWithCharacterAt(uint32_t index);
+ DECLARE_VERIFIER(Object)
#ifdef VERIFY_HEAP
// Verify a pointer is a valid object pointer.
static void VerifyPointer(Object* p);
diff --git a/src/parser.cc b/src/parser.cc
index a00adb8..16a1028 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -304,20 +304,25 @@
}
-Scanner::Location ScriptDataImpl::MessageLocation() {
+Scanner::Location ScriptDataImpl::MessageLocation() const {
int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
int end_pos = Read(PreparseDataConstants::kMessageEndPos);
return Scanner::Location(beg_pos, end_pos);
}
-const char* ScriptDataImpl::BuildMessage() {
+bool ScriptDataImpl::IsReferenceError() const {
+ return Read(PreparseDataConstants::kIsReferenceErrorPos);
+}
+
+
+const char* ScriptDataImpl::BuildMessage() const {
unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
return ReadString(start, NULL);
}
-Vector<const char*> ScriptDataImpl::BuildArgs() {
+Vector<const char*> ScriptDataImpl::BuildArgs() const {
int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
const char** array = NewArray<const char*>(arg_count);
// Position after text found by skipping past length field and
@@ -333,12 +338,12 @@
}
-unsigned ScriptDataImpl::Read(int position) {
+unsigned ScriptDataImpl::Read(int position) const {
return store_[PreparseDataConstants::kHeaderSize + position];
}
-unsigned* ScriptDataImpl::ReadAddress(int position) {
+unsigned* ScriptDataImpl::ReadAddress(int position) const {
return &store_[PreparseDataConstants::kHeaderSize + position];
}
@@ -3385,8 +3390,7 @@
}
ParserTraits::ReportMessageAt(
Scanner::Location(logger.start(), logger.end()),
- logger.message(),
- args);
+ logger.message(), args, logger.is_reference_error());
*ok = false;
return NULL;
}
@@ -4688,7 +4692,8 @@
Scanner::Location loc = cached_data->MessageLocation();
const char* message = cached_data->BuildMessage();
Vector<const char*> args = cached_data->BuildArgs();
- ParserTraits::ReportMessageAt(loc, message, args);
+ ParserTraits::ReportMessageAt(loc, message, args,
+ cached_data->IsReferenceError());
DeleteArray(message);
for (int i = 0; i < args.length(); i++) {
DeleteArray(args[i]);
diff --git a/src/parser.h b/src/parser.h
index 4bb9aad..287dfa4 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -104,9 +104,10 @@
int GetSymbolIdentifier();
bool SanityCheck();
- Scanner::Location MessageLocation();
- const char* BuildMessage();
- Vector<const char*> BuildArgs();
+ Scanner::Location MessageLocation() const;
+ bool IsReferenceError() const;
+ const char* BuildMessage() const;
+ Vector<const char*> BuildArgs() const;
int symbol_count() {
return (store_.length() > PreparseDataConstants::kHeaderSize)
@@ -127,8 +128,8 @@
int function_index_;
bool owns_store_;
- unsigned Read(int position);
- unsigned* ReadAddress(int position);
+ unsigned Read(int position) const;
+ unsigned* ReadAddress(int position) const;
// Reads a number from the current symbols
int ReadNumber(byte** source);
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index 5ca1252..20c2533 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -214,6 +214,11 @@
// See http://code.google.com/p/nativeclient/issues/3341
return NULL;
#endif
+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
+ defined(THREAD_SANITIZER)
+ // Dynamic tools do not support custom mmap addresses.
+ return NULL;
+#endif
Isolate* isolate = Isolate::UncheckedCurrent();
// Note that the current isolate isn't set up in a call path via
// CpuFeatures::Probe. We don't care about randomization in this case because
diff --git a/src/preparse-data-format.h b/src/preparse-data-format.h
index e2cf0a1..f5c3a5f 100644
--- a/src/preparse-data-format.h
+++ b/src/preparse-data-format.h
@@ -51,7 +51,8 @@
static const int kMessageStartPos = 0;
static const int kMessageEndPos = 1;
static const int kMessageArgCountPos = 2;
- static const int kMessageTextPos = 3;
+ static const int kIsReferenceErrorPos = 3;
+ static const int kMessageTextPos = 4;
static const unsigned char kNumberTerminator = 0x80u;
};
diff --git a/src/preparse-data.cc b/src/preparse-data.cc
index 9f585a9..5bc6173 100644
--- a/src/preparse-data.cc
+++ b/src/preparse-data.cc
@@ -88,9 +88,10 @@
void CompleteParserRecorder::LogMessage(int start_pos,
- int end_pos,
- const char* message,
- const char* arg_opt) {
+ int end_pos,
+ const char* message,
+ const char* arg_opt,
+ bool is_reference_error) {
if (has_error()) return;
preamble_[PreparseDataConstants::kHasErrorOffset] = true;
function_store_.Reset();
@@ -100,7 +101,9 @@
function_store_.Add(end_pos);
STATIC_ASSERT(PreparseDataConstants::kMessageArgCountPos == 2);
function_store_.Add((arg_opt == NULL) ? 0 : 1);
- STATIC_ASSERT(PreparseDataConstants::kMessageTextPos == 3);
+ STATIC_ASSERT(PreparseDataConstants::kIsReferenceErrorPos == 3);
+ function_store_.Add(is_reference_error ? 1 : 0);
+ STATIC_ASSERT(PreparseDataConstants::kMessageTextPos == 4);
WriteString(CStrVector(message));
if (arg_opt != NULL) WriteString(CStrVector(arg_opt));
should_log_symbols_ = false;
diff --git a/src/preparse-data.h b/src/preparse-data.h
index 6a968e3..cfc33fe 100644
--- a/src/preparse-data.h
+++ b/src/preparse-data.h
@@ -55,7 +55,8 @@
virtual void LogMessage(int start,
int end,
const char* message,
- const char* argument_opt) = 0;
+ const char* argument_opt,
+ bool is_reference_error) = 0;
// Logs a symbol creation of a literal or identifier.
bool ShouldLogSymbols() { return should_log_symbols_; }
@@ -80,8 +81,9 @@
class SingletonLogger : public ParserRecorder {
public:
- SingletonLogger() : has_error_(false), start_(-1), end_(-1) { }
- virtual ~SingletonLogger() { }
+ SingletonLogger()
+ : has_error_(false), start_(-1), end_(-1), is_reference_error_(false) {}
+ virtual ~SingletonLogger() {}
void Reset() { has_error_ = false; }
@@ -104,36 +106,39 @@
virtual void LogMessage(int start,
int end,
const char* message,
- const char* argument_opt) {
+ const char* argument_opt,
+ bool is_reference_error) {
if (has_error_) return;
has_error_ = true;
start_ = start;
end_ = end;
message_ = message;
argument_opt_ = argument_opt;
+ is_reference_error_ = is_reference_error;
}
- bool has_error() { return has_error_; }
+ bool has_error() const { return has_error_; }
- int start() { return start_; }
- int end() { return end_; }
- int literals() {
+ int start() const { return start_; }
+ int end() const { return end_; }
+ int literals() const {
ASSERT(!has_error_);
return literals_;
}
- int properties() {
+ int properties() const {
ASSERT(!has_error_);
return properties_;
}
- StrictMode strict_mode() {
+ StrictMode strict_mode() const {
ASSERT(!has_error_);
return strict_mode_;
}
+ int is_reference_error() const { return is_reference_error_; }
const char* message() {
ASSERT(has_error_);
return message_;
}
- const char* argument_opt() {
+ const char* argument_opt() const {
ASSERT(has_error_);
return argument_opt_;
}
@@ -149,6 +154,7 @@
// For error messages.
const char* message_;
const char* argument_opt_;
+ bool is_reference_error_;
};
@@ -180,7 +186,8 @@
virtual void LogMessage(int start,
int end,
const char* message,
- const char* argument_opt);
+ const char* argument_opt,
+ bool is_reference_error_);
virtual void PauseRecording() {
ASSERT(should_log_symbols_);
diff --git a/src/preparser.cc b/src/preparser.cc
index 9bcc880..4995ed9 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -83,8 +83,8 @@
const char* type,
const char* name_opt,
bool is_reference_error) {
- pre_parser_->log_
- ->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
+ pre_parser_->log_->LogMessage(location.beg_pos, location.end_pos, type,
+ name_opt, is_reference_error);
}
@@ -93,7 +93,8 @@
const char* type,
const char* name_opt,
bool is_reference_error) {
- pre_parser_->log_->LogMessage(start_pos, end_pos, type, name_opt);
+ pre_parser_->log_->LogMessage(start_pos, end_pos, type, name_opt,
+ is_reference_error);
}
diff --git a/src/property.cc b/src/property.cc
index 2f72eec..591ea0b 100644
--- a/src/property.cc
+++ b/src/property.cc
@@ -1,36 +1,14 @@
-// Copyright 2012 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.
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
-#include "v8.h"
+#include "property.h"
+
+#include "handles-inl.h"
namespace v8 {
namespace internal {
-
void LookupResult::Iterate(ObjectVisitor* visitor) {
LookupResult* current = this; // Could be NULL.
while (current != NULL) {
@@ -114,9 +92,6 @@
PrintF(out, " @ ");
GetValue()->ShortPrint(out);
}
-
-
#endif
-
} } // namespace v8::internal
diff --git a/src/property.h b/src/property.h
index baa5a0f..cfdf9c7 100644
--- a/src/property.h
+++ b/src/property.h
@@ -1,47 +1,20 @@
-// Copyright 2012 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.
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#ifndef V8_PROPERTY_H_
#define V8_PROPERTY_H_
-#include "allocation.h"
-#include "transitions.h"
+#include "isolate.h"
namespace v8 {
namespace internal {
-
// Abstraction for elements in instance-descriptor arrays.
//
// Each descriptor has a key, property attributes, property type,
// property index (in the actual instance-descriptor array) and
// optionally a piece of data.
-//
-
class Descriptor BASE_EMBEDDED {
public:
MUST_USE_RESULT MaybeObject* KeyToUniqueName() {
@@ -96,7 +69,7 @@
};
-class FieldDescriptor: public Descriptor {
+class FieldDescriptor V8_FINAL : public Descriptor {
public:
FieldDescriptor(Name* key,
int field_index,
@@ -107,7 +80,7 @@
};
-class ConstantDescriptor: public Descriptor {
+class ConstantDescriptor V8_FINAL : public Descriptor {
public:
ConstantDescriptor(Name* key,
Object* value,
@@ -117,7 +90,7 @@
};
-class CallbacksDescriptor: public Descriptor {
+class CallbacksDescriptor V8_FINAL : public Descriptor {
public:
CallbacksDescriptor(Name* key,
Object* foreign,
@@ -129,7 +102,7 @@
// Holds a property index value distinguishing if it is a field index or an
// index inside the object header.
-class PropertyIndex {
+class PropertyIndex V8_FINAL {
public:
static PropertyIndex NewFieldIndex(int index) {
return PropertyIndex(index, false);
@@ -177,7 +150,7 @@
};
-class LookupResult BASE_EMBEDDED {
+class LookupResult V8_FINAL BASE_EMBEDDED {
public:
explicit LookupResult(Isolate* isolate)
: isolate_(isolate),
@@ -488,7 +461,6 @@
PropertyDetails details_;
};
-
} } // namespace v8::internal
#endif // V8_PROPERTY_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index 48e81e2..67810ef 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2048,37 +2048,39 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
- SealHandleScope shs(isolate);
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(HeapObject, object, 0);
- Map* old_map = object->map();
+ CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
+ Handle<Map> old_map(object->map());
bool needs_access_checks = old_map->is_access_check_needed();
if (needs_access_checks) {
// Copy map so it won't interfere constructor's initial map.
- Map* new_map;
- MaybeObject* maybe_new_map = old_map->Copy();
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
-
+ Handle<Map> new_map = Map::Copy(old_map);
new_map->set_is_access_check_needed(false);
- object->set_map(new_map);
+ if (object->IsJSObject()) {
+ JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
+ } else {
+ object->set_map(*new_map);
+ }
}
return isolate->heap()->ToBoolean(needs_access_checks);
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
- SealHandleScope shs(isolate);
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(HeapObject, object, 0);
- Map* old_map = object->map();
+ CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
+ Handle<Map> old_map(object->map());
if (!old_map->is_access_check_needed()) {
// Copy map so it won't interfere constructor's initial map.
- Map* new_map;
- MaybeObject* maybe_new_map = old_map->Copy();
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
-
+ Handle<Map> new_map = Map::Copy(old_map);
new_map->set_is_access_check_needed(true);
- object->set_map(new_map);
+ if (object->IsJSObject()) {
+ JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
+ } else {
+ object->set_map(*new_map);
+ }
}
return isolate->heap()->undefined_value();
}
@@ -2945,9 +2947,9 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
- SealHandleScope shs(isolate);
+ HandleScope shs(isolate);
RUNTIME_ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSFunction, function, 0);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
String* name = isolate->heap()->prototype_string();
@@ -2970,9 +2972,10 @@
instance_desc, &new_desc, index, OMIT_TRANSITION);
if (!maybe_map->To(&new_map)) return maybe_map;
- function->set_map(new_map);
+ JSObject::MigrateToMap(function, handle(new_map));
} else { // Dictionary properties.
// Directly manipulate the property details.
+ DisallowHeapAllocation no_gc;
int entry = function->property_dictionary()->FindEntry(name);
ASSERT(entry != NameDictionary::kNotFound);
PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
@@ -2982,7 +2985,7 @@
details.dictionary_index());
function->property_dictionary()->DetailsAtPut(entry, new_details);
}
- return function;
+ return *function;
}
@@ -3084,9 +3087,7 @@
if (!func->shared()->live_objects_may_exist()) {
func->shared()->set_expected_nof_properties(num);
if (func->has_initial_map()) {
- Handle<Map> new_initial_map =
- func->GetIsolate()->factory()->CopyMap(
- Handle<Map>(func->initial_map()));
+ Handle<Map> new_initial_map = Map::Copy(handle(func->initial_map()));
new_initial_map->set_unused_property_fields(num);
func->set_initial_map(*new_initial_map);
}
@@ -7990,11 +7991,10 @@
parameter_map->set_map(
isolate->heap()->sloppy_arguments_elements_map());
- Handle<Map> old_map(result->map());
- Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
- new_map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
+ Handle<Map> map = Map::Copy(handle(result->map()));
+ map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
- result->set_map(*new_map);
+ result->set_map(*map);
result->set_elements(*parameter_map);
// Store the context and the arguments array at the beginning of the
@@ -13899,6 +13899,87 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInitializedIntlObject) {
+ HandleScope scope(isolate);
+
+ ASSERT(args.length() == 1);
+
+ CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+
+ if (!input->IsJSObject()) return isolate->heap()->ToBoolean(false);
+ Handle<JSObject> obj = Handle<JSObject>::cast(input);
+
+ Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
+ Handle<Object> tag(obj->GetHiddenProperty(*marker), isolate);
+ return isolate->heap()->ToBoolean(!tag->IsTheHole());
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInitializedIntlObjectOfType) {
+ HandleScope scope(isolate);
+
+ ASSERT(args.length() == 2);
+
+ CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+ CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1);
+
+ if (!input->IsJSObject()) return isolate->heap()->ToBoolean(false);
+ Handle<JSObject> obj = Handle<JSObject>::cast(input);
+
+ Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
+ Handle<Object> tag(obj->GetHiddenProperty(*marker), isolate);
+ return isolate->heap()->ToBoolean(
+ tag->IsString() && String::cast(*tag)->Equals(*expected_type));
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_MarkAsInitializedIntlObjectOfType) {
+ HandleScope scope(isolate);
+
+ ASSERT(args.length() == 3);
+
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
+ CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2);
+
+ Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
+ JSObject::SetHiddenProperty(input, marker, type);
+
+ marker = isolate->factory()->intl_impl_object_string();
+ JSObject::SetHiddenProperty(input, marker, impl);
+
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetImplFromInitializedIntlObject) {
+ HandleScope scope(isolate);
+
+ ASSERT(args.length() == 1);
+
+ CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+
+ if (!input->IsJSObject()) {
+ Vector< Handle<Object> > arguments = HandleVector(&input, 1);
+ Handle<Object> type_error =
+ isolate->factory()->NewTypeError("not_intl_object", arguments);
+ return isolate->Throw(*type_error);
+ }
+
+ Handle<JSObject> obj = Handle<JSObject>::cast(input);
+
+ Handle<String> marker = isolate->factory()->intl_impl_object_string();
+ Handle<Object> impl(obj->GetHiddenProperty(*marker), isolate);
+ if (impl->IsTheHole()) {
+ Vector< Handle<Object> > arguments = HandleVector(&obj, 1);
+ Handle<Object> type_error =
+ isolate->factory()->NewTypeError("not_intl_object", arguments);
+ return isolate->Throw(*type_error);
+ }
+ return *impl;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) {
HandleScope scope(isolate);
diff --git a/src/runtime.h b/src/runtime.h
index f84355b..50181b6 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -491,6 +491,10 @@
F(AvailableLocalesOf, 1, 1) \
F(GetDefaultICULocale, 0, 1) \
F(GetLanguageTagVariants, 1, 1) \
+ F(IsInitializedIntlObject, 1, 1) \
+ F(IsInitializedIntlObjectOfType, 2, 1) \
+ F(MarkAsInitializedIntlObjectOfType, 3, 1) \
+ F(GetImplFromInitializedIntlObject, 1, 1) \
\
/* Date format and parse. */ \
F(CreateDateTimeFormat, 3, 1) \
diff --git a/src/spaces.cc b/src/spaces.cc
index 2ca8c98..7831ef1 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -711,7 +711,7 @@
executable,
owner);
result->set_reserved_memory(&reservation);
- MSAN_MEMORY_IS_INITIALIZED(base, chunk_size);
+ MSAN_MEMORY_IS_INITIALIZED_IN_JIT(base, chunk_size);
return result;
}
@@ -1195,7 +1195,7 @@
VerifyObject(object);
// The object itself should look OK.
- object->Verify();
+ object->ObjectVerify();
// All the interior pointers should be contained in the heap.
int size = object->Size();
@@ -1478,7 +1478,7 @@
CHECK(!object->IsCode());
// The object itself should look OK.
- object->Verify();
+ object->ObjectVerify();
// All the interior pointers should be contained in the heap.
VerifyPointersVisitor visitor;
@@ -3119,7 +3119,7 @@
object->IsFixedDoubleArray() || object->IsByteArray());
// The object itself should look OK.
- object->Verify();
+ object->ObjectVerify();
// Byte arrays and strings don't have interior pointers.
if (object->IsCode()) {
diff --git a/src/types-inl.h b/src/types-inl.h
new file mode 100644
index 0000000..941fda7
--- /dev/null
+++ b/src/types-inl.h
@@ -0,0 +1,372 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_TYPES_INL_H_
+#define V8_TYPES_INL_H_
+
+#include "types.h"
+
+#include "factory.h"
+#include "handles-inl.h"
+
+namespace v8 {
+namespace internal {
+
+// static
+ZoneTypeConfig::Tagged* ZoneTypeConfig::tagged_create(
+ Tag tag, int size, Zone* zone) {
+ Tagged* tagged = new(zone) Tagged(size + 1, zone);
+ tagged->Add(reinterpret_cast<void*>(tag), zone);
+ tagged->AddBlock(NULL, size, zone);
+ return tagged;
+}
+
+
+// static
+void ZoneTypeConfig::tagged_shrink(Tagged* tagged, int size) {
+ tagged->Rewind(size + 1);
+}
+
+
+// static
+ZoneTypeConfig::Tag ZoneTypeConfig::tagged_tag(Tagged* tagged) {
+ return static_cast<Tag>(reinterpret_cast<intptr_t>(tagged->at(0)));
+}
+
+
+// static
+template<class T>
+T ZoneTypeConfig::tagged_get(Tagged* tagged, int i) {
+ return reinterpret_cast<T>(tagged->at(i + 1));
+}
+
+
+// static
+template<class T>
+void ZoneTypeConfig::tagged_set(Tagged* tagged, int i, T value) {
+ tagged->at(i + 1) = reinterpret_cast<void*>(value);
+}
+
+
+// static
+int ZoneTypeConfig::tagged_length(Tagged* tagged) {
+ return tagged->length() - 1;
+}
+
+
+// static
+Type* ZoneTypeConfig::handle(Type* type) {
+ return type;
+}
+
+
+// static
+bool ZoneTypeConfig::is(Type* type, Tag tag) {
+ return is_tagged(type) && tagged_tag(as_tagged(type)) == tag;
+}
+
+
+// static
+bool ZoneTypeConfig::is_bitset(Type* type) {
+ return reinterpret_cast<intptr_t>(type) & 1;
+}
+
+
+// static
+bool ZoneTypeConfig::is_tagged(Type* type) {
+ return !is_bitset(type);
+}
+
+
+// static
+bool ZoneTypeConfig::is_class(Type* type) {
+ return is(type, kClassTag);
+}
+
+
+// static
+bool ZoneTypeConfig::is_constant(Type* type) {
+ return is(type, kConstantTag);
+}
+
+
+// static
+bool ZoneTypeConfig::is_union(Type* type) {
+ return is(type, kUnionTag);
+}
+
+
+// static
+bool ZoneTypeConfig::tagged_is_union(Tagged* tagged) {
+ return is(from_tagged(tagged), kUnionTag);
+}
+
+
+// static
+int ZoneTypeConfig::as_bitset(Type* type) {
+ ASSERT(is_bitset(type));
+ return static_cast<int>(reinterpret_cast<intptr_t>(type) >> 1);
+}
+
+
+// static
+ZoneTypeConfig::Tagged* ZoneTypeConfig::as_tagged(Type* type) {
+ ASSERT(is_tagged(type));
+ return reinterpret_cast<Tagged*>(type);
+}
+
+
+// static
+i::Handle<i::Map> ZoneTypeConfig::as_class(Type* type) {
+ ASSERT(is_class(type));
+ return i::Handle<i::Map>(tagged_get<i::Map**>(as_tagged(type), 1));
+}
+
+
+// static
+i::Handle<i::Object> ZoneTypeConfig::as_constant(Type* type) {
+ ASSERT(is_constant(type));
+ return i::Handle<i::Object>(tagged_get<i::Object**>(as_tagged(type), 1));
+}
+
+
+// static
+ZoneTypeConfig::Unioned* ZoneTypeConfig::as_union(Type* type) {
+ ASSERT(is_union(type));
+ return tagged_as_union(as_tagged(type));
+}
+
+
+// static
+ZoneTypeConfig::Unioned* ZoneTypeConfig::tagged_as_union(Tagged* tagged) {
+ ASSERT(tagged_is_union(tagged));
+ return reinterpret_cast<Unioned*>(tagged);
+}
+
+
+// static
+ZoneTypeConfig::Type* ZoneTypeConfig::from_bitset(int bitset) {
+ return reinterpret_cast<Type*>((bitset << 1) | 1);
+}
+
+
+// static
+ZoneTypeConfig::Type* ZoneTypeConfig::from_bitset(int bitset, Zone* Zone) {
+ return from_bitset(bitset);
+}
+
+
+// static
+ZoneTypeConfig::Type* ZoneTypeConfig::from_tagged(Tagged* tagged) {
+ return reinterpret_cast<Type*>(tagged);
+}
+
+
+// static
+ZoneTypeConfig::Type* ZoneTypeConfig::from_class(
+ i::Handle<i::Map> map, int lub, Zone* zone) {
+ Tagged* tagged = tagged_create(kClassTag, 2, zone);
+ tagged_set(tagged, 0, lub);
+ tagged_set(tagged, 1, map.location());
+ return from_tagged(tagged);
+}
+
+
+// static
+ZoneTypeConfig::Type* ZoneTypeConfig::from_constant(
+ i::Handle<i::Object> value, int lub, Zone* zone) {
+ Tagged* tagged = tagged_create(kConstantTag, 2, zone);
+ tagged_set(tagged, 0, lub);
+ tagged_set(tagged, 1, value.location());
+ return from_tagged(tagged);
+}
+
+
+// static
+ZoneTypeConfig::Type* ZoneTypeConfig::from_union(Unioned* unioned) {
+ return from_tagged(tagged_from_union(unioned));
+}
+
+
+// static
+ZoneTypeConfig::Tagged* ZoneTypeConfig::tagged_from_union(Unioned* unioned) {
+ return reinterpret_cast<Tagged*>(unioned);
+}
+
+
+// static
+ZoneTypeConfig::Unioned* ZoneTypeConfig::union_create(int size, Zone* zone) {
+ return tagged_as_union(tagged_create(kUnionTag, size, zone));
+}
+
+
+// static
+void ZoneTypeConfig::union_shrink(Unioned* unioned, int size) {
+ tagged_shrink(tagged_from_union(unioned), size);
+}
+
+
+// static
+ZoneTypeConfig::Type* ZoneTypeConfig::union_get(Unioned* unioned, int i) {
+ Type* type = tagged_get<Type*>(tagged_from_union(unioned), i);
+ ASSERT(!is_union(type));
+ return type;
+}
+
+
+// static
+void ZoneTypeConfig::union_set(Unioned* unioned, int i, Type* type) {
+ ASSERT(!is_union(type));
+ tagged_set(tagged_from_union(unioned), i, type);
+}
+
+
+// static
+int ZoneTypeConfig::union_length(Unioned* unioned) {
+ return tagged_length(tagged_from_union(unioned));
+}
+
+
+// static
+int ZoneTypeConfig::lub_bitset(Type* type) {
+ ASSERT(is_class(type) || is_constant(type));
+ return static_cast<int>(tagged_get<intptr_t>(as_tagged(type), 0));
+}
+
+// -------------------------------------------------------------------------- //
+
+// static
+i::Handle<HeapTypeConfig::Type> HeapTypeConfig::handle(Type* type) {
+ return i::handle(type, i::HeapObject::cast(type)->GetIsolate());
+}
+
+
+// static
+bool HeapTypeConfig::is_bitset(Type* type) {
+ return type->IsSmi();
+}
+
+
+// static
+bool HeapTypeConfig::is_class(Type* type) {
+ return type->IsMap();
+}
+
+
+// static
+bool HeapTypeConfig::is_constant(Type* type) {
+ return type->IsBox();
+}
+
+
+// static
+bool HeapTypeConfig::is_union(Type* type) {
+ return type->IsFixedArray();
+}
+
+
+// static
+int HeapTypeConfig::as_bitset(Type* type) {
+ return Smi::cast(type)->value();
+}
+
+
+// static
+i::Handle<i::Map> HeapTypeConfig::as_class(Type* type) {
+ return i::handle(i::Map::cast(type));
+}
+
+
+// static
+i::Handle<i::Object> HeapTypeConfig::as_constant(Type* type) {
+ i::Box* box = i::Box::cast(type);
+ return i::handle(box->value(), box->GetIsolate());
+}
+
+
+// static
+i::Handle<HeapTypeConfig::Unioned> HeapTypeConfig::as_union(Type* type) {
+ return i::handle(i::FixedArray::cast(type));
+}
+
+
+// static
+HeapTypeConfig::Type* HeapTypeConfig::from_bitset(int bitset) {
+ return Type::cast(i::Smi::FromInt(bitset));
+}
+
+
+// static
+i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_bitset(
+ int bitset, Isolate* isolate) {
+ return i::handle(from_bitset(bitset), isolate);
+}
+
+
+// static
+i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_class(
+ i::Handle<i::Map> map, int lub, Isolate* isolate) {
+ return i::Handle<Type>::cast(i::Handle<Object>::cast(map));
+}
+
+
+// static
+i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_constant(
+ i::Handle<i::Object> value, int lub, Isolate* isolate) {
+ i::Handle<Box> box = isolate->factory()->NewBox(value);
+ return i::Handle<Type>::cast(i::Handle<Object>::cast(box));
+}
+
+
+// static
+i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_union(
+ i::Handle<Unioned> unioned) {
+ return i::Handle<Type>::cast(i::Handle<Object>::cast(unioned));
+}
+
+
+// static
+i::Handle<HeapTypeConfig::Unioned> HeapTypeConfig::union_create(
+ int size, Isolate* isolate) {
+ return isolate->factory()->NewFixedArray(size);
+}
+
+
+// static
+void HeapTypeConfig::union_shrink(i::Handle<Unioned> unioned, int size) {
+ unioned->Shrink(size);
+}
+
+
+// static
+i::Handle<HeapTypeConfig::Type> HeapTypeConfig::union_get(
+ i::Handle<Unioned> unioned, int i) {
+ Type* type = static_cast<Type*>(unioned->get(i));
+ ASSERT(!is_union(type));
+ return i::handle(type, unioned->GetIsolate());
+}
+
+
+// static
+void HeapTypeConfig::union_set(
+ i::Handle<Unioned> unioned, int i, i::Handle<Type> type) {
+ ASSERT(!is_union(*type));
+ unioned->set(i, *type);
+}
+
+
+// static
+int HeapTypeConfig::union_length(i::Handle<Unioned> unioned) {
+ return unioned->length();
+}
+
+
+// static
+int HeapTypeConfig::lub_bitset(Type* type) {
+ return 0; // kNone, which causes recomputation.
+}
+
+} } // namespace v8::internal
+
+#endif // V8_TYPES_INL_H_
diff --git a/src/types.cc b/src/types.cc
index 98bb280..5998fdc 100644
--- a/src/types.cc
+++ b/src/types.cc
@@ -1,32 +1,11 @@
-// 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.
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#include "types.h"
+
#include "string-stream.h"
+#include "types-inl.h"
namespace v8 {
namespace internal {
@@ -190,8 +169,6 @@
case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
case INTERNALIZED_STRING_TYPE:
case ASCII_INTERNALIZED_STRING_TYPE:
- case CONS_INTERNALIZED_STRING_TYPE:
- case CONS_ASCII_INTERNALIZED_STRING_TYPE:
case EXTERNAL_INTERNALIZED_STRING_TYPE:
case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
@@ -271,7 +248,7 @@
// Most precise _current_ type of a value (usually its class).
template<class Config>
-typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::OfCurrently(
+typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NowOf(
i::Handle<i::Object> value, Region* region) {
if (value->IsSmi() ||
i::HeapObject::cast(*value)->map()->instance_type() == HEAP_NUMBER_TYPE ||
@@ -326,7 +303,7 @@
template<class Config>
-bool TypeImpl<Config>::IsCurrently(TypeImpl* that) {
+bool TypeImpl<Config>::NowIs(TypeImpl* that) {
return this->Is(that) ||
(this->IsConstant() && that->IsClass() &&
this->AsConstant()->IsHeapObject() &&
@@ -378,6 +355,23 @@
template<class Config>
+bool TypeImpl<Config>::Contains(i::Object* value) {
+ if (this->IsConstant()) {
+ return *this->AsConstant() == value;
+ }
+ return Config::from_bitset(LubBitset(value))->Is(this);
+}
+
+
+template<class Config>
+bool TypeImpl<Config>::NowContains(i::Object* value) {
+ return this->Contains(value) ||
+ (this->IsClass() && value->IsHeapObject() &&
+ *this->AsClass() == i::HeapObject::cast(value)->map());
+}
+
+
+template<class Config>
bool TypeImpl<Config>::InUnion(UnionedHandle unioned, int current_size) {
ASSERT(!this->IsUnion());
for (int i = 0; i < current_size; ++i) {
@@ -690,5 +684,4 @@
TypeImpl<HeapTypeConfig>::Convert<Type>(
TypeImpl<ZoneTypeConfig>::TypeHandle, TypeImpl<HeapTypeConfig>::Region*);
-
} } // namespace v8::internal
diff --git a/src/types.h b/src/types.h
index 4569d13..d5e3ca4 100644
--- a/src/types.h
+++ b/src/types.h
@@ -1,41 +1,15 @@
-// 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.
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#ifndef V8_TYPES_H_
#define V8_TYPES_H_
-#include "v8.h"
-
-#include "objects.h"
+#include "handles.h"
namespace v8 {
namespace internal {
-
// A simple type system for compiler-internal use. It is based entirely on
// union types, and all subtyping hence amounts to set inclusion. Besides the
// obvious primitive types and some predefined unions, the type language also
@@ -246,16 +220,23 @@
bool Is(TypeImpl* that) { return this == that || this->SlowIs(that); }
template<class TypeHandle>
bool Is(TypeHandle that) { return this->Is(*that); }
+
bool Maybe(TypeImpl* that);
template<class TypeHandle>
bool Maybe(TypeHandle that) { return this->Maybe(*that); }
+ // Equivalent to Constant(value)->Is(this), but avoiding allocation.
+ bool Contains(i::Object* val);
+ bool Contains(i::Handle<i::Object> val) { return this->Contains(*val); }
+
// State-dependent versions of Of and Is that consider subtyping between
// a constant and its map class.
- static TypeHandle OfCurrently(i::Handle<i::Object> value, Region* region);
- bool IsCurrently(TypeImpl* that);
+ static TypeHandle NowOf(i::Handle<i::Object> value, Region* region);
+ bool NowIs(TypeImpl* that);
template<class TypeHandle>
- bool IsCurrently(TypeHandle that) { return this->IsCurrently(*that); }
+ bool NowIs(TypeHandle that) { return this->NowIs(*that); }
+ bool NowContains(i::Object* val);
+ bool NowContains(i::Handle<i::Object> val) { return this->NowContains(*val); }
bool IsClass() { return Config::is_class(this); }
bool IsConstant() { return Config::is_constant(this); }
@@ -382,29 +363,12 @@
kUnionTag
};
- static Tagged* tagged_create(Tag tag, int size, Zone* zone) {
- Tagged* tagged = new(zone) Tagged(size + 1, zone);
- tagged->Add(reinterpret_cast<void*>(tag), zone);
- tagged->AddBlock(NULL, size, zone);
- return tagged;
- }
- static void tagged_shrink(Tagged* tagged, int size) {
- tagged->Rewind(size + 1);
- }
- static Tag tagged_tag(Tagged* tagged) {
- return static_cast<Tag>(reinterpret_cast<intptr_t>(tagged->at(0)));
- }
- template<class T>
- static T tagged_get(Tagged* tagged, int i) {
- return reinterpret_cast<T>(tagged->at(i + 1));
- }
- template<class T>
- static void tagged_set(Tagged* tagged, int i, T value) {
- tagged->at(i + 1) = reinterpret_cast<void*>(value);
- }
- static int tagged_length(Tagged* tagged) {
- return tagged->length() - 1;
- }
+ static inline Tagged* tagged_create(Tag tag, int size, Zone* zone);
+ static inline void tagged_shrink(Tagged* tagged, int size);
+ static inline Tag tagged_tag(Tagged* tagged);
+ template<class T> static inline T tagged_get(Tagged* tagged, int i);
+ template<class T> static inline void tagged_set(Tagged* tagged, int i, T val);
+ static inline int tagged_length(Tagged* tagged);
public:
typedef TypeImpl<ZoneTypeConfig> Type;
@@ -413,100 +377,38 @@
typedef i::Zone Region;
template<class T> struct Handle { typedef T* type; };
- static Type* handle(Type* type) { return type; }
-
- static bool is(Type* type, Tag tag) {
- return is_tagged(type) && tagged_tag(as_tagged(type)) == tag;
- }
-
- static bool is_bitset(Type* type) {
- return reinterpret_cast<intptr_t>(type) & 1;
- }
- static bool is_tagged(Type* type) { return !is_bitset(type); }
- static bool is_class(Type* type) { return is(type, kClassTag); }
- static bool is_constant(Type* type) { return is(type, kConstantTag); }
- static bool is_union(Type* type) { return is(type, kUnionTag); }
- static bool tagged_is_union(Tagged* tagged) {
- return is(from_tagged(tagged), kUnionTag);
- }
-
- static int as_bitset(Type* type) {
- ASSERT(is_bitset(type));
- return static_cast<int>(reinterpret_cast<intptr_t>(type) >> 1);
- }
- static Tagged* as_tagged(Type* type) {
- ASSERT(is_tagged(type));
- return reinterpret_cast<Tagged*>(type);
- }
- static i::Handle<i::Map> as_class(Type* type) {
- ASSERT(is_class(type));
- return i::Handle<i::Map>(tagged_get<i::Map**>(as_tagged(type), 1));
- }
- static i::Handle<i::Object> as_constant(Type* type) {
- ASSERT(is_constant(type));
- return i::Handle<i::Object>(tagged_get<i::Object**>(as_tagged(type), 1));
- }
- static Unioned* as_union(Type* type) {
- ASSERT(is_union(type));
- return tagged_as_union(as_tagged(type));
- }
- static Unioned* tagged_as_union(Tagged* tagged) {
- ASSERT(tagged_is_union(tagged));
- return reinterpret_cast<Unioned*>(tagged);
- }
-
- static Type* from_bitset(int bitset) {
- return reinterpret_cast<Type*>((bitset << 1) | 1);
- }
- static Type* from_bitset(int bitset, Zone* Zone) {
- return from_bitset(bitset);
- }
- static Type* from_tagged(Tagged* tagged) {
- return reinterpret_cast<Type*>(tagged);
- }
- static Type* from_class(i::Handle<i::Map> map, int lub, Zone* zone) {
- Tagged* tagged = tagged_create(kClassTag, 2, zone);
- tagged_set(tagged, 0, lub);
- tagged_set(tagged, 1, map.location());
- return from_tagged(tagged);
- }
- static Type* from_constant(i::Handle<i::Object> value, int lub, Zone* zone) {
- Tagged* tagged = tagged_create(kConstantTag, 2, zone);
- tagged_set(tagged, 0, lub);
- tagged_set(tagged, 1, value.location());
- return from_tagged(tagged);
- }
- static Type* from_union(Unioned* unioned) {
- return from_tagged(tagged_from_union(unioned));
- }
- static Tagged* tagged_from_union(Unioned* unioned) {
- return reinterpret_cast<Tagged*>(unioned);
- }
-
- static Unioned* union_create(int size, Zone* zone) {
- return tagged_as_union(tagged_create(kUnionTag, size, zone));
- }
- static void union_shrink(Unioned* unioned, int size) {
- tagged_shrink(tagged_from_union(unioned), size);
- }
- static Type* union_get(Unioned* unioned, int i) {
- Type* type = tagged_get<Type*>(tagged_from_union(unioned), i);
- ASSERT(!is_union(type));
- return type;
- }
- static void union_set(Unioned* unioned, int i, Type* type) {
- ASSERT(!is_union(type));
- tagged_set(tagged_from_union(unioned), i, type);
- }
- static int union_length(Unioned* unioned) {
- return tagged_length(tagged_from_union(unioned));
- }
- static int lub_bitset(Type* type) {
- ASSERT(is_class(type) || is_constant(type));
- return static_cast<int>(tagged_get<intptr_t>(as_tagged(type), 0));
- }
+ static inline Type* handle(Type* type);
+ static inline bool is(Type* type, Tag tag);
+ static inline bool is_bitset(Type* type);
+ static inline bool is_tagged(Type* type);
+ static inline bool is_class(Type* type);
+ static inline bool is_constant(Type* type);
+ static inline bool is_union(Type* type);
+ static inline bool tagged_is_union(Tagged* tagged);
+ static inline int as_bitset(Type* type);
+ static inline Tagged* as_tagged(Type* type);
+ static inline i::Handle<i::Map> as_class(Type* type);
+ static inline i::Handle<i::Object> as_constant(Type* type);
+ static inline Unioned* as_union(Type* type);
+ static inline Unioned* tagged_as_union(Tagged* tagged);
+ static inline Type* from_bitset(int bitset);
+ static inline Type* from_bitset(int bitset, Zone* zone);
+ static inline Type* from_tagged(Tagged* tagged);
+ static inline Type* from_class(i::Handle<i::Map> map, int lub, Zone* zone);
+ static inline Type* from_constant(
+ i::Handle<i::Object> value, int lub, Zone* zone);
+ static inline Type* from_union(Unioned* unioned);
+ static inline Tagged* tagged_from_union(Unioned* unioned);
+ static inline Unioned* union_create(int size, Zone* zone);
+ static inline void union_shrink(Unioned* unioned, int size);
+ static inline Type* union_get(Unioned* unioned, int i);
+ static inline void union_set(Unioned* unioned, int i, Type* type);
+ static inline int union_length(Unioned* unioned);
+ static inline int lub_bitset(Type* type);
};
+typedef TypeImpl<ZoneTypeConfig> Type;
+
// Heap-allocated types are either smis for bitsets, maps for classes, boxes for
// constants, or fixed arrays for unions.
@@ -517,73 +419,31 @@
typedef i::Isolate Region;
template<class T> struct Handle { typedef i::Handle<T> type; };
- static i::Handle<Type> handle(Type* type) {
- return i::handle(type, i::HeapObject::cast(type)->GetIsolate());
- }
-
- static bool is_bitset(Type* type) { return type->IsSmi(); }
- static bool is_class(Type* type) { return type->IsMap(); }
- static bool is_constant(Type* type) { return type->IsBox(); }
- static bool is_union(Type* type) { return type->IsFixedArray(); }
-
- static int as_bitset(Type* type) {
- return Smi::cast(type)->value();
- }
- static i::Handle<i::Map> as_class(Type* type) {
- return i::handle(i::Map::cast(type));
- }
- static i::Handle<i::Object> as_constant(Type* type) {
- i::Box* box = i::Box::cast(type);
- return i::handle(box->value(), box->GetIsolate());
- }
- static i::Handle<Unioned> as_union(Type* type) {
- return i::handle(i::FixedArray::cast(type));
- }
-
- static Type* from_bitset(int bitset) {
- return Type::cast(i::Smi::FromInt(bitset));
- }
- static i::Handle<Type> from_bitset(int bitset, Isolate* isolate) {
- return i::handle(from_bitset(bitset), isolate);
- }
- static i::Handle<Type> from_class(
- i::Handle<i::Map> map, int lub, Isolate* isolate) {
- return i::Handle<Type>::cast(i::Handle<Object>::cast(map));
- }
- static i::Handle<Type> from_constant(
- i::Handle<i::Object> value, int lub, Isolate* isolate) {
- i::Handle<Box> box = isolate->factory()->NewBox(value);
- return i::Handle<Type>::cast(i::Handle<Object>::cast(box));
- }
- static i::Handle<Type> from_union(i::Handle<Unioned> unioned) {
- return i::Handle<Type>::cast(i::Handle<Object>::cast(unioned));
- }
-
- static i::Handle<Unioned> union_create(int size, Isolate* isolate) {
- return isolate->factory()->NewFixedArray(size);
- }
- static void union_shrink(i::Handle<Unioned> unioned, int size) {
- unioned->Shrink(size);
- }
- static i::Handle<Type> union_get(i::Handle<Unioned> unioned, int i) {
- Type* type = static_cast<Type*>(unioned->get(i));
- ASSERT(!is_union(type));
- return i::handle(type, unioned->GetIsolate());
- }
- static void union_set(
- i::Handle<Unioned> unioned, int i, i::Handle<Type> type) {
- ASSERT(!is_union(*type));
- unioned->set(i, *type);
- }
- static int union_length(i::Handle<Unioned> unioned) {
- return unioned->length();
- }
- static int lub_bitset(Type* type) {
- return 0; // kNone, which causes recomputation.
- }
+ static inline i::Handle<Type> handle(Type* type);
+ static inline bool is_bitset(Type* type);
+ static inline bool is_class(Type* type);
+ static inline bool is_constant(Type* type);
+ static inline bool is_union(Type* type);
+ static inline int as_bitset(Type* type);
+ static inline i::Handle<i::Map> as_class(Type* type);
+ static inline i::Handle<i::Object> as_constant(Type* type);
+ static inline i::Handle<Unioned> as_union(Type* type);
+ static inline Type* from_bitset(int bitset);
+ static inline i::Handle<Type> from_bitset(int bitset, Isolate* isolate);
+ static inline i::Handle<Type> from_class(
+ i::Handle<i::Map> map, int lub, Isolate* isolate);
+ static inline i::Handle<Type> from_constant(
+ i::Handle<i::Object> value, int lub, Isolate* isolate);
+ static inline i::Handle<Type> from_union(i::Handle<Unioned> unioned);
+ static inline i::Handle<Unioned> union_create(int size, Isolate* isolate);
+ static inline void union_shrink(i::Handle<Unioned> unioned, int size);
+ static inline i::Handle<Type> union_get(i::Handle<Unioned> unioned, int i);
+ static inline void union_set(
+ i::Handle<Unioned> unioned, int i, i::Handle<Type> type);
+ static inline int union_length(i::Handle<Unioned> unioned);
+ static inline int lub_bitset(Type* type);
};
-typedef TypeImpl<ZoneTypeConfig> Type;
typedef TypeImpl<HeapTypeConfig> HeapType;
@@ -643,7 +503,6 @@
typedef BoundsImpl<ZoneTypeConfig> Bounds;
-
} } // namespace v8::internal
#endif // V8_TYPES_H_
diff --git a/src/typing.cc b/src/typing.cc
index 2a581e2..dd99d19 100644
--- a/src/typing.cc
+++ b/src/typing.cc
@@ -83,7 +83,7 @@
Effect AstTyper::ObservedOnStack(Object* value) {
- Type* lower = Type::OfCurrently(handle(value, isolate()), zone());
+ Type* lower = Type::NowOf(handle(value, isolate()), zone());
return Effect(Bounds(lower, Type::Any(zone())));
}
diff --git a/src/utils.h b/src/utils.h
index 7538226..845cb75 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -43,10 +43,10 @@
// ----------------------------------------------------------------------------
// General helper functions
-#define IS_POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0)
+#define IS_POWER_OF_TWO(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-// Returns true iff x is a power of 2 (or zero). Cannot be used with the
-// maximally negative value of the type T (the -1 overflows).
+// Returns true iff x is a power of 2. Cannot be used with the maximally
+// negative value of the type T (the -1 overflows).
template <typename T>
inline bool IsPowerOf2(T x) {
return IS_POWER_OF_TWO(x);
@@ -56,7 +56,6 @@
// X must be a power of 2. Returns the number of trailing zeros.
inline int WhichPowerOf2(uint32_t x) {
ASSERT(IsPowerOf2(x));
- ASSERT(x != 0);
int bits = 0;
#ifdef DEBUG
int original_x = x;
diff --git a/src/v8.h b/src/v8.h
index d3f5a9c..26cb5a7 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -66,6 +66,7 @@
#include "mark-compact-inl.h"
#include "log-inl.h"
#include "handles-inl.h"
+#include "types-inl.h"
#include "zone-inl.h"
namespace v8 {
@@ -135,6 +136,4 @@
} } // namespace v8::internal
-namespace i = v8::internal;
-
#endif // V8_V8_H_
diff --git a/src/v8globals.h b/src/v8globals.h
index e6cd94d..cb29614 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -565,4 +565,6 @@
} } // namespace v8::internal
+namespace i = v8::internal;
+
#endif // V8_V8GLOBALS_H_
diff --git a/src/v8utils.h b/src/v8utils.h
index 058b153..32c5c2e 100644
--- a/src/v8utils.h
+++ b/src/v8utils.h
@@ -215,6 +215,11 @@
#undef STOS
#endif
+#if defined(MEMORY_SANITIZER)
+ // MemorySanitizer does not understand inline assembly.
+#undef STOS
+#endif
+
#if defined(__GNUC__) && defined(STOS)
asm volatile(
"cld;"
diff --git a/src/version.cc b/src/version.cc
index 6fc3a06..6f804d6 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 26
-#define BUILD_NUMBER 2
+#define BUILD_NUMBER 3
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index ac6d370..a64d3e2 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -1205,11 +1205,64 @@
}
+// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
+void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
+ HBinaryOperation* hdiv = instr->hydrogen();
+ Register dividend = ToRegister(instr->dividend());
+ Register divisor = ToRegister(instr->divisor());
+ Register remainder = ToRegister(instr->temp());
+ Register result = ToRegister(instr->result());
+ ASSERT(dividend.is(rax));
+ ASSERT(remainder.is(rdx));
+ ASSERT(result.is(rax));
+ ASSERT(!divisor.is(rax));
+ ASSERT(!divisor.is(rdx));
+
+ // Check for x / 0.
+ if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
+ __ testl(divisor, divisor);
+ DeoptimizeIf(zero, instr->environment());
+ }
+
+ // Check for (0 / -x) that will produce negative zero.
+ if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ Label dividend_not_zero;
+ __ testl(dividend, dividend);
+ __ j(not_zero, ÷nd_not_zero, Label::kNear);
+ __ testl(divisor, divisor);
+ DeoptimizeIf(sign, instr->environment());
+ __ bind(÷nd_not_zero);
+ }
+
+ // Check for (kMinInt / -1).
+ if (hdiv->CheckFlag(HValue::kCanOverflow)) {
+ Label dividend_not_min_int;
+ __ cmpl(dividend, Immediate(kMinInt));
+ __ j(not_zero, ÷nd_not_min_int, Label::kNear);
+ __ cmpl(divisor, Immediate(-1));
+ DeoptimizeIf(zero, instr->environment());
+ __ bind(÷nd_not_min_int);
+ }
+
+ // Sign extend to rdx (= remainder).
+ __ cdq();
+ __ idivl(divisor);
+
+ Label done;
+ __ testl(remainder, remainder);
+ __ j(zero, &done, Label::kNear);
+ __ xorl(remainder, divisor);
+ __ sarl(remainder, Immediate(31));
+ __ addl(result, remainder);
+ __ bind(&done);
+}
+
+
void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister(instr->result());
- ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
+ ASSERT(divisor == kMinInt || IsPowerOf2(Abs(divisor)));
ASSERT(!result.is(dividend));
// Check for (0 / -x) that will produce negative zero.
@@ -1272,15 +1325,15 @@
}
+// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
void LCodeGen::DoDivI(LDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
- Register dividend = ToRegister(instr->left());
- Register divisor = ToRegister(instr->right());
+ Register dividend = ToRegister(instr->dividend());
+ Register divisor = ToRegister(instr->divisor());
Register remainder = ToRegister(instr->temp());
- Register result = ToRegister(instr->result());
ASSERT(dividend.is(rax));
ASSERT(remainder.is(rdx));
- ASSERT(result.is(rax));
+ ASSERT(ToRegister(instr->result()).is(rax));
ASSERT(!divisor.is(rax));
ASSERT(!divisor.is(rdx));
@@ -1314,15 +1367,7 @@
__ cdq();
__ idivl(divisor);
- if (hdiv->IsMathFloorOfDiv()) {
- Label done;
- __ testl(remainder, remainder);
- __ j(zero, &done, Label::kNear);
- __ xorl(remainder, divisor);
- __ sarl(remainder, Immediate(31));
- __ addl(result, remainder);
- __ bind(&done);
- } else if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
+ if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
// Deoptimize if remainder is not 0.
__ testl(remainder, remainder);
DeoptimizeIf(not_zero, instr->environment());
@@ -1775,6 +1820,7 @@
if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
if (right->IsConstantOperand()) {
+ ASSERT(!target_rep.IsSmi()); // No support for smi-immediates.
int32_t offset = ToInteger32(LConstantOperand::cast(right));
if (is_p) {
__ leap(ToRegister(instr->result()),
@@ -1793,6 +1839,7 @@
}
} else {
if (right->IsConstantOperand()) {
+ ASSERT(!target_rep.IsSmi()); // No support for smi-immediates.
if (is_p) {
__ addp(ToRegister(left),
Immediate(ToInteger32(LConstantOperand::cast(right))));
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 9d99e91..d1c7731 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1310,7 +1310,7 @@
}
-LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
+LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
@@ -1322,8 +1322,7 @@
if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanOverflow) ||
- (!instr->IsMathFloorOfDiv() &&
- !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
+ !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
result = AssignEnvironment(result);
}
return result;
@@ -1387,13 +1386,31 @@
}
+LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
+ ASSERT(instr->representation().IsSmiOrInteger32());
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
+ LOperand* dividend = UseFixed(instr->left(), rax);
+ LOperand* divisor = UseRegister(instr->right());
+ LOperand* temp = FixedTemp(rdx);
+ LInstruction* result = DefineFixed(new(zone()) LFlooringDivI(
+ dividend, divisor, temp), rax);
+ if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
+ instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
+ instr->CheckFlag(HValue::kCanOverflow)) {
+ result = AssignEnvironment(result);
+ }
+ return result;
+}
+
+
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoFlooringDivByConstI(instr);
} else {
- return DoDivI(instr);
+ return DoFlooringDivI(instr);
}
}
@@ -1515,14 +1532,19 @@
ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
HValue* right_candidate = instr->BetterRightOperand();
- LOperand* right = use_lea
- ? UseRegisterOrConstantAtStart(right_candidate)
- : UseOrConstantAtStart(right_candidate);
+ LOperand* right;
+ if (instr->representation().IsSmi()) {
+ // We cannot add a tagged immediate to a tagged value,
+ // so we request it in a register.
+ right = UseRegisterAtStart(right_candidate);
+ } else {
+ right = use_lea ? UseRegisterOrConstantAtStart(right_candidate)
+ : UseOrConstantAtStart(right_candidate);
+ }
LAddI* add = new(zone()) LAddI(left, right);
bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
- LInstruction* result = use_lea
- ? DefineAsRegister(add)
- : DefineSameAsFirst(add);
+ LInstruction* result = use_lea ? DefineAsRegister(add)
+ : DefineSameAsFirst(add);
if (can_overflow) {
result = AssignEnvironment(result);
}
@@ -1804,26 +1826,21 @@
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();
}
- // Only mark conversions that might need to allocate as calling rather than
- // all changes. This makes simple, non-allocating conversion not have to force
- // building a stack frame.
if (from.IsTagged()) {
if (to.IsDouble()) {
- LOperand* value = UseRegister(instr->value());
- LInstruction* res = DefineAsRegister(new(zone()) LNumberUntagD(value));
- if (!instr->value()->representation().IsSmi()) {
- res = AssignEnvironment(res);
- }
- return res;
+ LOperand* value = UseRegister(val);
+ LInstruction* result = DefineAsRegister(new(zone()) LNumberUntagD(value));
+ if (!val->representation().IsSmi()) result = AssignEnvironment(result);
+ return result;
} else if (to.IsSmi()) {
- HValue* val = instr->value();
LOperand* value = UseRegister(val);
if (val->type().IsSmi()) {
return DefineSameAsFirst(new(zone()) LDummyUse(value));
@@ -1831,78 +1848,73 @@
return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
} else {
ASSERT(to.IsInteger32());
- HValue* val = instr->value();
- LOperand* value = UseRegister(val);
if (val->type().IsSmi() || val->representation().IsSmi()) {
+ LOperand* value = UseRegister(val);
return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
} else {
+ LOperand* value = UseRegister(val);
bool truncating = instr->CanTruncateToInt32();
LOperand* xmm_temp = truncating ? NULL : FixedTemp(xmm1);
- LInstruction* res =
+ LInstruction* result =
DefineSameAsFirst(new(zone()) LTaggedToI(value, xmm_temp));
- if (!instr->value()->representation().IsSmi()) {
+ if (!val->representation().IsSmi()) {
// Note: Only deopts in deferred code.
- res = AssignEnvironment(res);
+ result = AssignEnvironment(result);
}
- return res;
+ return result;
}
}
} else if (from.IsDouble()) {
if (to.IsTagged()) {
info()->MarkAsDeferredCalling();
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseRegister(val);
LOperand* temp = TempRegister();
-
- // Make sure that temp and result_temp are different registers.
LUnallocated* result_temp = TempRegister();
LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
return AssignPointerMap(Define(result, result_temp));
} else if (to.IsSmi()) {
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseRegister(val);
return AssignEnvironment(
DefineAsRegister(new(zone()) LDoubleToSmi(value)));
} else {
ASSERT(to.IsInteger32());
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseRegister(val);
LInstruction* result = DefineAsRegister(new(zone()) LDoubleToI(value));
- if (!instr->CanTruncateToInt32()) {
- result = AssignEnvironment(result);
- }
+ if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
return result;
}
} else if (from.IsInteger32()) {
info()->MarkAsDeferredCalling();
if (to.IsTagged()) {
- HValue* val = instr->value();
- LOperand* value = UseRegister(val);
if (!instr->CheckFlag(HValue::kCanOverflow)) {
+ LOperand* value = UseRegister(val);
return DefineAsRegister(new(zone()) LSmiTag(value));
} else if (val->CheckFlag(HInstruction::kUint32)) {
+ LOperand* value = UseRegister(val);
LOperand* temp1 = TempRegister();
LOperand* temp2 = FixedTemp(xmm1);
LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
return AssignPointerMap(DefineSameAsFirst(result));
} else {
+ LOperand* value = UseRegister(val);
LNumberTagI* result = new(zone()) LNumberTagI(value);
return AssignPointerMap(DefineSameAsFirst(result));
}
} else if (to.IsSmi()) {
- HValue* val = instr->value();
LOperand* value = UseRegister(val);
LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
if (instr->CheckFlag(HValue::kCanOverflow)) {
- ASSERT(val->CheckFlag(HValue::kUint32));
result = AssignEnvironment(result);
}
return result;
} else {
- if (instr->value()->CheckFlag(HInstruction::kUint32)) {
+ ASSERT(to.IsDouble());
+ if (val->CheckFlag(HInstruction::kUint32)) {
LOperand* temp = FixedTemp(xmm1);
return DefineAsRegister(
- new(zone()) LUint32ToDouble(UseRegister(instr->value()), temp));
+ new(zone()) LUint32ToDouble(UseRegister(val), temp));
} else {
- ASSERT(to.IsDouble());
- LOperand* value = Use(instr->value());
+ LOperand* value = Use(val);
return DefineAsRegister(new(zone()) LInteger32ToDouble(value));
}
}
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 9d9ac1e..1c8bb0d 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -97,6 +97,7 @@
V(Dummy) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
+ V(FlooringDivI) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
@@ -732,14 +733,14 @@
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
- LDivI(LOperand* left, LOperand* right, LOperand* temp) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
+ inputs_[0] = dividend;
+ inputs_[1] = divisor;
temps_[0] = temp;
}
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
+ LOperand* dividend() { return inputs_[0]; }
+ LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
@@ -794,6 +795,23 @@
};
+class LFlooringDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+ LFlooringDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
+ inputs_[0] = dividend;
+ inputs_[1] = divisor;
+ temps_[0] = temp;
+ }
+
+ LOperand* dividend() { return inputs_[0]; }
+ LOperand* divisor() { return inputs_[1]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
+ DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+};
+
+
class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LMulI(LOperand* left, LOperand* right) {
@@ -2681,12 +2699,13 @@
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivByConstI(HDiv* instr);
- LInstruction* DoDivI(HBinaryOperation* instr);
+ LInstruction* DoDivI(HDiv* instr);
LInstruction* DoModByPowerOf2I(HMod* instr);
LInstruction* DoModByConstI(HMod* instr);
LInstruction* DoModI(HMod* instr);
LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);
+ LInstruction* DoFlooringDivI(HMathFloorOfDiv* instr);
private:
enum Status {
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 2c95a02..b682265 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -140,6 +140,9 @@
# BUG(3005).
'test-alloc/CodeRange': [PASS, FAIL],
+
+ # BUG(3215). Crashes on windows.
+ 'test-lockers/MultithreadedParallelIsolates': [SKIP],
}], # 'system == windows'
##############################################################################
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index b51cb77..bf3e223 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -5409,8 +5409,6 @@
void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
- i::FLAG_debugger_auto_break = true;
-
BreakpointsDebuggerThread breakpoints_debugger_thread(global_evaluate);
BreakpointsV8Thread breakpoints_v8_thread;
@@ -5881,7 +5879,6 @@
TEST(DebuggerHostDispatch) {
HostDispatchDebuggerThread host_dispatch_debugger_thread;
HostDispatchV8Thread host_dispatch_v8_thread;
- i::FLAG_debugger_auto_break = true;
// Create a V8 environment
Barriers stack_allocated_host_dispatch_barriers;
@@ -5948,8 +5945,6 @@
DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
- i::FLAG_debugger_auto_break = true;
-
// Create a V8 environment
Barriers stack_allocated_debug_message_dispatch_barriers;
debug_message_dispatch_barriers =
diff --git a/test/intl/break-iterator/protected-icu-internals.js b/test/intl/break-iterator/protected-icu-internals.js
deleted file mode 100644
index ad1dc54..0000000
--- a/test/intl/break-iterator/protected-icu-internals.js
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-// Internal object we got from native code should not be writable,
-// configurable or enumerable. One can still change its public properties, but
-// we don't use them to do actual work.
-
-var iterator = new Intl.v8BreakIterator([]);
-
-// Direct write should fail.
-iterator.iterator = {'zzz':'some random object'};
-
-assertFalse(iterator.iterator.hasOwnProperty('zzz'));
-
-// Try redefining the property.
-var didThrow = false;
-try {
- Object.defineProperty(iterator, 'iterator', {value: undefined});
-} catch(e) {
- didThrow = true;
-}
-assertTrue(didThrow);
-
-// Try deleting the property.
-assertFalse(delete iterator.iterator);
diff --git a/test/intl/collator/protected-icu-internals.js b/test/intl/collator/protected-icu-internals.js
deleted file mode 100644
index 7acd35e..0000000
--- a/test/intl/collator/protected-icu-internals.js
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-// Internal object we got from native code should not be writable,
-// configurable or enumerable. One can still change its public properties, but
-// we don't use them to do actual work.
-
-var collator = new Intl.Collator([]);
-
-// Direct write should fail.
-collator.collator = {'zzz':'some random object'};
-
-assertFalse(collator.collator.hasOwnProperty('zzz'));
-
-// Try redefining the property.
-var didThrow = false;
-try {
- Object.defineProperty(collator, 'collator', {value: undefined});
-} catch(e) {
- didThrow = true;
-}
-assertTrue(didThrow);
-
-// Try deleting the property.
-assertFalse(delete collator.collator);
diff --git a/test/intl/date-format/protected-icu-internals.js b/test/intl/date-format/protected-icu-internals.js
deleted file mode 100644
index 140f4b5..0000000
--- a/test/intl/date-format/protected-icu-internals.js
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-// Internal object we got from native code should not be writable,
-// configurable or enumerable. One can still change its public properties, but
-// we don't use them to do actual work.
-
-var format = new Intl.DateTimeFormat([]);
-
-// Direct write should fail.
-format.formatter = {'zzz':'some random object'};
-
-assertFalse(format.formatter.hasOwnProperty('zzz'));
-
-// Try redefining the property.
-var didThrow = false;
-try {
- Object.defineProperty(format, 'formatter', {value: undefined});
-} catch(e) {
- didThrow = true;
-}
-assertTrue(didThrow);
-
-// Try deleting the property.
-assertFalse(delete format.formatter);
diff --git a/test/intl/number-format/protected-icu-internals.js b/test/intl/number-format/protected-icu-internals.js
deleted file mode 100644
index fc9b709..0000000
--- a/test/intl/number-format/protected-icu-internals.js
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-// Internal object we got from native code should not be writable,
-// configurable or enumerable. One can still change its public properties, but
-// we don't use them to do actual work.
-
-var format = new Intl.NumberFormat([]);
-
-// Direct write should fail.
-format.formatter = {'zzz':'some random object'};
-
-assertFalse(format.formatter.hasOwnProperty('zzz'));
-
-// Try redefining the property.
-var didThrow = false;
-try {
- Object.defineProperty(format, 'formatter', {value: undefined});
-} catch(e) {
- didThrow = true;
-}
-assertTrue(didThrow);
-
-// Try deleting the property.
-assertFalse(delete format.formatter);
diff --git a/test/mjsunit/regress/regress-357054.js b/test/mjsunit/regress/regress-357054.js
new file mode 100644
index 0000000..92a066e
--- /dev/null
+++ b/test/mjsunit/regress/regress-357054.js
@@ -0,0 +1,10 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[].__defineSetter__(0, function() { });
+function f(a,i,v) { a[i] = v; }
+a = [0,0,0];
+f(a,0,5);
+a = new Float32Array(5);
+f(a,2,5.5);
diff --git a/test/mjsunit/regress/regress-357103.js b/test/mjsunit/regress/regress-357103.js
new file mode 100644
index 0000000..692729d
--- /dev/null
+++ b/test/mjsunit/regress/regress-357103.js
@@ -0,0 +1,14 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+%SetFlags("--gc-interval=1");
+
+var key = "Huckleberry Finn" + "Tom Sawyer";
+var o = {};
+function f() { o[key] = "Adventures"; }
+
+f();
+f();
diff --git a/test/mjsunit/regress/regress-358059.js b/test/mjsunit/regress/regress-358059.js
new file mode 100644
index 0000000..30738f9
--- /dev/null
+++ b/test/mjsunit/regress/regress-358059.js
@@ -0,0 +1,13 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(a, b) { return b + (a.x++); }
+var o = {};
+o.__defineGetter__('x', function() { return 1; });
+assertEquals(4, f(o, 3));
+assertEquals(4, f(o, 3));
+%OptimizeFunctionOnNextCall(f);
+assertEquals(4, f(o, 3));
diff --git a/test/mjsunit/regress/regress-358088.js b/test/mjsunit/regress/regress-358088.js
new file mode 100644
index 0000000..222bba6
--- /dev/null
+++ b/test/mjsunit/regress/regress-358088.js
@@ -0,0 +1,18 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f(a) {
+ a[a.length] = 1;
+}
+
+function g(a, i, v) {
+ a[i] = v;
+}
+
+f([]); // f KeyedStoreIC goes to 1.GROW
+o = {};
+g(o); // We've added property "undefined" to o
+
+o = {}; // A transition on property "undefined" exists from {}
+f(o); // Store should go generic.
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 52143e9..81b1212 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -474,6 +474,7 @@
'../../src/mark-compact.h',
'../../src/messages.cc',
'../../src/messages.h',
+ '../../src/msan.h',
'../../src/natives.h',
'../../src/objects-debug.cc',
'../../src/objects-inl.h',
@@ -569,6 +570,7 @@
'../../src/transitions.h',
'../../src/type-info.cc',
'../../src/type-info.h',
+ '../../src/types-inl.h',
'../../src/types.cc',
'../../src/types.h',
'../../src/typing.cc',