mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
deps: upgrade v8 to 4.1.0.7
This commit upgrades V8 from 3.31.74.1 to 4.1.0.7. Despite the major version bump, there are no API or ABI changes, it's a bug fix release only. PR-URL: https://github.com/iojs/io.js/pull/490 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Fedor Indutny <fedor@indutny.com> Reviewed-By: Kenan Sulayman <kenan@sly.mn> Reviewed-By: Rod Vagg <rod@vagg.org>
This commit is contained in:
1 parent
ea7750bddd
commit
5e7ebc7af6
57 files changed
+977
-401
No files matched your search
Vendored
+31
@@ -1,3 +1,34 @@
|
||||
2015-01-07: Version 3.32.3
|
||||
|
||||
Performance and stability improvements on all platforms.
|
||||
|
||||
|
||||
2015-01-07: Version 3.32.2
|
||||
|
||||
Performance and stability improvements on all platforms.
|
||||
|
||||
|
||||
2015-01-07: Version 3.32.1
|
||||
|
||||
[turbofan] Don't crash when typing load from a Uint8ClampedArray
|
||||
(Chromium issue 446156).
|
||||
|
||||
[turbofan] Truncation of Bit/Word8/16 to Word32 is a no-op (Chromium
|
||||
issue 445859).
|
||||
|
||||
[x64] Rearrange code for OOB integer loads (Chromium issue 445858).
|
||||
|
||||
Fix %NeverOptimizeFunction() intrinsic (Chromium issue 445732).
|
||||
|
||||
[turbofan] Fix invalid bounds check with overflowing offset (Chromium
|
||||
issue 445267).
|
||||
|
||||
[turbofan] Raise max virtual registers and call parameter limit (issue
|
||||
3786).
|
||||
|
||||
Performance and stability improvements on all platforms.
|
||||
|
||||
|
||||
2014-12-23: Version 3.31.74
|
||||
|
||||
[turbofan] Turn DCHECK for fixed slot index into a CHECK (Chromium issue
|
||||
|
||||
Vendored
+1
-1
@@ -18,7 +18,7 @@ deps = {
|
||||
"v8/testing/gmock":
|
||||
Var("git_url") + "/external/googlemock.git" + "@" + "29763965ab52f24565299976b936d1265cb6a271", # from svn revision 501
|
||||
"v8/tools/clang":
|
||||
Var("git_url") + "/chromium/src/tools/clang.git" + "@" + "90fb65e7a9a5c9d6d9613dfb0e78921c52ca9cfc",
|
||||
Var("git_url") + "/chromium/src/tools/clang.git" + "@" + "c945be21f6485fa177b43814f910b76cce921653",
|
||||
}
|
||||
|
||||
deps_os = {
|
||||
|
||||
Vendored
+1
-1
@@ -117,7 +117,7 @@
|
||||
'Release': {
|
||||
'variables': {
|
||||
'v8_enable_extra_checks%': 0,
|
||||
'v8_enable_handle_zapping%': 1,
|
||||
'v8_enable_handle_zapping%': 0,
|
||||
},
|
||||
'conditions': [
|
||||
['v8_enable_extra_checks==1', {
|
||||
|
||||
Vendored
+1
@@ -1780,6 +1780,7 @@ Local<Script> ScriptCompiler::Compile(Isolate* v8_isolate,
|
||||
// Do the parsing tasks which need to be done on the main thread. This will
|
||||
// also handle parse errors.
|
||||
source->parser->Internalize();
|
||||
source->parser->HandleSourceURLComments();
|
||||
|
||||
i::Handle<i::SharedFunctionInfo> result =
|
||||
i::Handle<i::SharedFunctionInfo>::null();
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
|
||||
if (bytes_read < 8) break;
|
||||
unsigned end = StringToLong(addr_buffer);
|
||||
char buffer[MAP_LENGTH];
|
||||
bytes_read = -1;
|
||||
int bytes_read = -1;
|
||||
do {
|
||||
bytes_read++;
|
||||
if (bytes_read >= MAP_LENGTH - 1)
|
||||
|
||||
+1
-1
@@ -261,7 +261,7 @@ int OS::GetCurrentThreadId() {
|
||||
#elif V8_OS_ANDROID
|
||||
return static_cast<int>(gettid());
|
||||
#else
|
||||
return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self()));
|
||||
return static_cast<int>(pthread_self());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+19
-5
@@ -196,6 +196,9 @@ class ControlReducerImpl {
|
||||
merge = graph()->NewNode(common_->Merge(2), merge, loop);
|
||||
end->ReplaceInput(0, merge);
|
||||
to_add = merge;
|
||||
// Mark the node as visited so that we can revisit later.
|
||||
EnsureStateSize(merge->id());
|
||||
state_[merge->id()] = kVisited;
|
||||
} else {
|
||||
// Append a new input to the final merge at the end.
|
||||
merge->AppendInput(graph()->zone(), loop);
|
||||
@@ -293,14 +296,17 @@ class ControlReducerImpl {
|
||||
if (replacement != node) Recurse(replacement);
|
||||
}
|
||||
|
||||
void EnsureStateSize(size_t id) {
|
||||
if (id >= state_.size()) {
|
||||
state_.resize((3 * id) / 2, kUnvisited);
|
||||
}
|
||||
}
|
||||
|
||||
// Push a node onto the stack if its state is {kUnvisited} or {kRevisit}.
|
||||
bool Recurse(Node* node) {
|
||||
size_t id = static_cast<size_t>(node->id());
|
||||
if (id < state_.size()) {
|
||||
if (state_[id] != kRevisit && state_[id] != kUnvisited) return false;
|
||||
} else {
|
||||
state_.resize((3 * id) / 2, kUnvisited);
|
||||
}
|
||||
EnsureStateSize(id);
|
||||
if (state_[id] != kRevisit && state_[id] != kUnvisited) return false;
|
||||
Push(node);
|
||||
return true;
|
||||
}
|
||||
@@ -403,6 +409,14 @@ class ControlReducerImpl {
|
||||
if (n <= 1) return dead(); // No non-control inputs.
|
||||
if (n == 2) return node->InputAt(0); // Only one non-control input.
|
||||
|
||||
// Never remove an effect phi from a (potentially non-terminating) loop.
|
||||
// Otherwise, we might end up eliminating effect nodes, such as calls,
|
||||
// before the loop.
|
||||
if (node->opcode() == IrOpcode::kEffectPhi &&
|
||||
NodeProperties::GetControlInput(node)->opcode() == IrOpcode::kLoop) {
|
||||
return node;
|
||||
}
|
||||
|
||||
Node* replacement = NULL;
|
||||
Node::Inputs inputs = node->inputs();
|
||||
for (InputIter it = inputs.begin(); n > 1; --n, ++it) {
|
||||
|
||||
+51
-141
@@ -490,124 +490,34 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) {
|
||||
if (input->opcode() == IrOpcode::kJSToBoolean) {
|
||||
// Recursively try to reduce the input first.
|
||||
Reduction result = ReduceJSToBoolean(input);
|
||||
if (result.Changed()) return result;
|
||||
return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x)
|
||||
}
|
||||
// Check if we have a cached conversion.
|
||||
Node* conversion = FindConversion<IrOpcode::kJSToBoolean>(input);
|
||||
if (conversion) return Replace(conversion);
|
||||
Reduction JSTypedLowering::ReduceJSUnaryNot(Node* node) {
|
||||
Node* input = node->InputAt(0);
|
||||
Type* input_type = NodeProperties::GetBounds(input).upper;
|
||||
if (input_type->Is(Type::Boolean())) {
|
||||
return Changed(input); // JSToBoolean(x:boolean) => x
|
||||
// JSUnaryNot(x:boolean,context) => BooleanNot(x)
|
||||
node->set_op(simplified()->BooleanNot());
|
||||
node->TrimInputCount(1);
|
||||
return Changed(node);
|
||||
}
|
||||
if (input_type->Is(Type::Undefined())) {
|
||||
// JSToBoolean(undefined) => #false
|
||||
return Replace(jsgraph()->FalseConstant());
|
||||
}
|
||||
if (input_type->Is(Type::Null())) {
|
||||
// JSToBoolean(null) => #false
|
||||
return Replace(jsgraph()->FalseConstant());
|
||||
}
|
||||
if (input_type->Is(Type::DetectableReceiver())) {
|
||||
// JSToBoolean(x:detectable) => #true
|
||||
return Replace(jsgraph()->TrueConstant());
|
||||
}
|
||||
if (input_type->Is(Type::Undetectable())) {
|
||||
// JSToBoolean(x:undetectable) => #false
|
||||
return Replace(jsgraph()->FalseConstant());
|
||||
}
|
||||
if (input_type->Is(Type::OrderedNumber())) {
|
||||
// JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
|
||||
Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input,
|
||||
jsgraph()->ZeroConstant());
|
||||
Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
|
||||
return Replace(inv);
|
||||
}
|
||||
if (input_type->Is(Type::String())) {
|
||||
// JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
|
||||
FieldAccess access = AccessBuilder::ForStringLength();
|
||||
Node* length = graph()->NewNode(simplified()->LoadField(access), input,
|
||||
graph()->start(), graph()->start());
|
||||
Node* cmp = graph()->NewNode(simplified()->NumberEqual(), length,
|
||||
jsgraph()->ZeroConstant());
|
||||
Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
|
||||
return Replace(inv);
|
||||
}
|
||||
return NoChange();
|
||||
// JSUnaryNot(x,context) => BooleanNot(AnyToBoolean(x))
|
||||
node->set_op(simplified()->BooleanNot());
|
||||
node->ReplaceInput(0, graph()->NewNode(simplified()->AnyToBoolean(), input));
|
||||
node->TrimInputCount(1);
|
||||
return Changed(node);
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
|
||||
// Try to reduce the input first.
|
||||
Node* const input = node->InputAt(0);
|
||||
Reduction reduction = ReduceJSToBooleanInput(input);
|
||||
if (reduction.Changed()) return reduction;
|
||||
if (input->opcode() == IrOpcode::kPhi) {
|
||||
// JSToBoolean(phi(x1,...,xn,control),context)
|
||||
// => phi(JSToBoolean(x1,no-context),...,JSToBoolean(xn,no-context))
|
||||
int const input_count = input->InputCount() - 1;
|
||||
Node* const control = input->InputAt(input_count);
|
||||
DCHECK_LE(0, input_count);
|
||||
DCHECK(NodeProperties::IsControl(control));
|
||||
DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean()));
|
||||
DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean()));
|
||||
node->set_op(common()->Phi(kMachAnyTagged, input_count));
|
||||
for (int i = 0; i < input_count; ++i) {
|
||||
// We must be very careful not to introduce cycles when pushing
|
||||
// operations into phis. It is safe for {value}, since it appears
|
||||
// as input to the phi that we are replacing, but it's not safe
|
||||
// to simply reuse the context of the {node}. However, ToBoolean()
|
||||
// does not require a context anyways, so it's safe to discard it
|
||||
// here and pass the dummy context.
|
||||
Node* const value = ConvertToBoolean(input->InputAt(i));
|
||||
if (i < node->InputCount()) {
|
||||
node->ReplaceInput(i, value);
|
||||
} else {
|
||||
node->AppendInput(graph()->zone(), value);
|
||||
}
|
||||
}
|
||||
if (input_count < node->InputCount()) {
|
||||
node->ReplaceInput(input_count, control);
|
||||
} else {
|
||||
node->AppendInput(graph()->zone(), control);
|
||||
}
|
||||
node->TrimInputCount(input_count + 1);
|
||||
return Changed(node);
|
||||
Node* input = node->InputAt(0);
|
||||
Type* input_type = NodeProperties::GetBounds(input).upper;
|
||||
if (input_type->Is(Type::Boolean())) {
|
||||
// JSToBoolean(x:boolean,context) => x
|
||||
return Replace(input);
|
||||
}
|
||||
if (input->opcode() == IrOpcode::kSelect) {
|
||||
// JSToBoolean(select(c,x1,x2),context)
|
||||
// => select(c,JSToBoolean(x1,no-context),...,JSToBoolean(x2,no-context))
|
||||
int const input_count = input->InputCount();
|
||||
BranchHint const input_hint = SelectParametersOf(input->op()).hint();
|
||||
DCHECK_EQ(3, input_count);
|
||||
DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean()));
|
||||
DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean()));
|
||||
node->set_op(common()->Select(kMachAnyTagged, input_hint));
|
||||
node->InsertInput(graph()->zone(), 0, input->InputAt(0));
|
||||
for (int i = 1; i < input_count; ++i) {
|
||||
// We must be very careful not to introduce cycles when pushing
|
||||
// operations into selects. It is safe for {value}, since it appears
|
||||
// as input to the select that we are replacing, but it's not safe
|
||||
// to simply reuse the context of the {node}. However, ToBoolean()
|
||||
// does not require a context anyways, so it's safe to discard it
|
||||
// here and pass the dummy context.
|
||||
Node* const value = ConvertToBoolean(input->InputAt(i));
|
||||
node->ReplaceInput(i, value);
|
||||
}
|
||||
DCHECK_EQ(3, node->InputCount());
|
||||
return Changed(node);
|
||||
}
|
||||
InsertConversion(node);
|
||||
if (node->InputAt(1) != jsgraph()->NoContextConstant()) {
|
||||
// JSToBoolean(x,context) => JSToBoolean(x,no-context)
|
||||
node->ReplaceInput(1, jsgraph()->NoContextConstant());
|
||||
return Changed(node);
|
||||
}
|
||||
return NoChange();
|
||||
// JSToBoolean(x,context) => AnyToBoolean(x)
|
||||
node->set_op(simplified()->AnyToBoolean());
|
||||
node->TrimInputCount(1);
|
||||
return Changed(node);
|
||||
}
|
||||
|
||||
|
||||
@@ -927,14 +837,36 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
|
||||
|
||||
Reduction JSTypedLowering::Reduce(Node* node) {
|
||||
// Check if the output type is a singleton. In that case we already know the
|
||||
// result value and can simply replace the node unless there are effects.
|
||||
// result value and can simply replace the node if it's eliminable.
|
||||
if (NodeProperties::IsTyped(node) &&
|
||||
NodeProperties::GetBounds(node).upper->IsConstant() &&
|
||||
!IrOpcode::IsLeafOpcode(node->opcode()) &&
|
||||
node->op()->EffectOutputCount() == 0) {
|
||||
return ReplaceEagerly(node, jsgraph()->Constant(
|
||||
NodeProperties::GetBounds(node).upper->AsConstant()->Value()));
|
||||
// TODO(neis): Extend this to Range(x,x), NaN, MinusZero, ...?
|
||||
node->op()->HasProperty(Operator::kEliminatable)) {
|
||||
Type* upper = NodeProperties::GetBounds(node).upper;
|
||||
if (upper->IsConstant()) {
|
||||
Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
|
||||
NodeProperties::ReplaceWithValue(node, replacement);
|
||||
return Changed(replacement);
|
||||
} else if (upper->Is(Type::MinusZero())) {
|
||||
Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
|
||||
NodeProperties::ReplaceWithValue(node, replacement);
|
||||
return Changed(replacement);
|
||||
} else if (upper->Is(Type::NaN())) {
|
||||
Node* replacement = jsgraph()->NaNConstant();
|
||||
NodeProperties::ReplaceWithValue(node, replacement);
|
||||
return Changed(replacement);
|
||||
} else if (upper->Is(Type::Null())) {
|
||||
Node* replacement = jsgraph()->NullConstant();
|
||||
NodeProperties::ReplaceWithValue(node, replacement);
|
||||
return Changed(replacement);
|
||||
} else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) {
|
||||
Node* replacement = jsgraph()->Constant(upper->Min());
|
||||
NodeProperties::ReplaceWithValue(node, replacement);
|
||||
return Changed(replacement);
|
||||
} else if (upper->Is(Type::Undefined())) {
|
||||
Node* replacement = jsgraph()->UndefinedConstant();
|
||||
NodeProperties::ReplaceWithValue(node, replacement);
|
||||
return Changed(replacement);
|
||||
}
|
||||
}
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kJSEqual:
|
||||
@@ -972,18 +904,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
||||
return ReduceNumberBinop(node, simplified()->NumberDivide());
|
||||
case IrOpcode::kJSModulus:
|
||||
return ReduceNumberBinop(node, simplified()->NumberModulus());
|
||||
case IrOpcode::kJSUnaryNot: {
|
||||
Reduction result = ReduceJSToBooleanInput(node->InputAt(0));
|
||||
if (result.Changed()) {
|
||||
// JSUnaryNot(x:boolean) => BooleanNot(x)
|
||||
node = result.replacement();
|
||||
} else {
|
||||
// JSUnaryNot(x) => BooleanNot(JSToBoolean(x))
|
||||
node->set_op(javascript()->ToBoolean());
|
||||
}
|
||||
Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
|
||||
return Replace(value);
|
||||
}
|
||||
case IrOpcode::kJSUnaryNot:
|
||||
return ReduceJSUnaryNot(node);
|
||||
case IrOpcode::kJSToBoolean:
|
||||
return ReduceJSToBoolean(node);
|
||||
case IrOpcode::kJSToNumber:
|
||||
@@ -1005,17 +927,6 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Node* JSTypedLowering::ConvertToBoolean(Node* input) {
|
||||
// Avoid inserting too many eager ToBoolean() operations.
|
||||
Reduction const reduction = ReduceJSToBooleanInput(input);
|
||||
if (reduction.Changed()) return reduction.replacement();
|
||||
Node* const conversion = graph()->NewNode(javascript()->ToBoolean(), input,
|
||||
jsgraph()->NoContextConstant());
|
||||
InsertConversion(conversion);
|
||||
return conversion;
|
||||
}
|
||||
|
||||
|
||||
Node* JSTypedLowering::ConvertToNumber(Node* input) {
|
||||
DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive()));
|
||||
// Avoid inserting too many eager ToNumber() operations.
|
||||
@@ -1043,8 +954,7 @@ Node* JSTypedLowering::FindConversion(Node* input) {
|
||||
|
||||
|
||||
void JSTypedLowering::InsertConversion(Node* conversion) {
|
||||
DCHECK(conversion->opcode() == IrOpcode::kJSToBoolean ||
|
||||
conversion->opcode() == IrOpcode::kJSToNumber);
|
||||
DCHECK(conversion->opcode() == IrOpcode::kJSToNumber);
|
||||
size_t const input_id = conversion->InputAt(0)->id();
|
||||
if (input_id >= conversions_.size()) {
|
||||
conversions_.resize(2 * input_id + 1);
|
||||
|
||||
+1
-2
@@ -41,7 +41,7 @@ class JSTypedLowering FINAL : public Reducer {
|
||||
Reduction ReduceJSStoreContext(Node* node);
|
||||
Reduction ReduceJSEqual(Node* node, bool invert);
|
||||
Reduction ReduceJSStrictEqual(Node* node, bool invert);
|
||||
Reduction ReduceJSToBooleanInput(Node* input);
|
||||
Reduction ReduceJSUnaryNot(Node* node);
|
||||
Reduction ReduceJSToBoolean(Node* node);
|
||||
Reduction ReduceJSToNumberInput(Node* input);
|
||||
Reduction ReduceJSToNumber(Node* node);
|
||||
@@ -52,7 +52,6 @@ class JSTypedLowering FINAL : public Reducer {
|
||||
Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
|
||||
const Operator* shift_op);
|
||||
|
||||
Node* ConvertToBoolean(Node* input);
|
||||
Node* ConvertToNumber(Node* input);
|
||||
template <IrOpcode::Value>
|
||||
Node* FindConversion(Node* input);
|
||||
|
||||
Vendored
+1
@@ -132,6 +132,7 @@
|
||||
|
||||
// Opcodes for VirtuaMachine-level operators.
|
||||
#define SIMPLIFIED_OP_LIST(V) \
|
||||
V(AnyToBoolean) \
|
||||
V(BooleanNot) \
|
||||
V(BooleanToNumber) \
|
||||
V(NumberEqual) \
|
||||
|
||||
Vendored
+1
-1
@@ -441,7 +441,7 @@ struct SimplifiedLoweringPhase {
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
SourcePositionTable::Scope pos(data->source_positions(),
|
||||
SourcePosition::Unknown());
|
||||
SimplifiedLowering lowering(data->jsgraph());
|
||||
SimplifiedLowering lowering(data->jsgraph(), temp_zone);
|
||||
lowering.LowerAllNodes();
|
||||
ValueNumberingReducer vn_reducer(temp_zone);
|
||||
SimplifiedOperatorReducer simple_reducer(data->jsgraph());
|
||||
|
||||
+36
-5
@@ -77,6 +77,9 @@ class RepresentationSelector {
|
||||
memset(info_, 0, sizeof(NodeInfo) * count_);
|
||||
|
||||
Factory* f = zone->isolate()->factory();
|
||||
safe_bit_range_ =
|
||||
Type::Union(Type::Boolean(),
|
||||
Type::Range(f->NewNumber(0), f->NewNumber(1), zone), zone);
|
||||
safe_int_additive_range_ =
|
||||
Type::Range(f->NewNumber(-std::pow(2.0, 52.0)),
|
||||
f->NewNumber(std::pow(2.0, 52.0)), zone);
|
||||
@@ -304,8 +307,8 @@ class RepresentationSelector {
|
||||
if ((use & kRepMask) == kRepTagged) {
|
||||
// only tagged uses.
|
||||
return kRepTagged;
|
||||
} else if (IsSafeIntAdditiveOperand(node)) {
|
||||
// Integer within [-2^52, 2^52] range.
|
||||
} else if (upper->Is(Type::Integral32())) {
|
||||
// Integer within [-2^31, 2^32[ range.
|
||||
if ((use & kRepMask) == kRepFloat64) {
|
||||
// only float64 uses.
|
||||
return kRepFloat64;
|
||||
@@ -315,12 +318,12 @@ class RepresentationSelector {
|
||||
} else if ((use & kRepMask) == kRepWord32 ||
|
||||
(use & kTypeMask) == kTypeInt32 ||
|
||||
(use & kTypeMask) == kTypeUint32) {
|
||||
// The type is a safe integer, but we only use 32 bits.
|
||||
// We only use 32 bits or we use the result consistently.
|
||||
return kRepWord32;
|
||||
} else {
|
||||
return kRepFloat64;
|
||||
}
|
||||
} else if (upper->Is(Type::Boolean())) {
|
||||
} else if (IsSafeBitOperand(node)) {
|
||||
// multiple uses => pick kRepBit.
|
||||
return kRepBit;
|
||||
} else if (upper->Is(Type::Number())) {
|
||||
@@ -414,6 +417,11 @@ class RepresentationSelector {
|
||||
return BothInputsAre(node, Type::Signed32()) && !CanObserveNonInt32(use);
|
||||
}
|
||||
|
||||
bool IsSafeBitOperand(Node* node) {
|
||||
Type* type = NodeProperties::GetBounds(node).upper;
|
||||
return type->Is(safe_bit_range_);
|
||||
}
|
||||
|
||||
bool IsSafeIntAdditiveOperand(Node* node) {
|
||||
Type* type = NodeProperties::GetBounds(node).upper;
|
||||
// TODO(jarin): Unfortunately, bitset types are not subtypes of larger
|
||||
@@ -521,6 +529,28 @@ class RepresentationSelector {
|
||||
//------------------------------------------------------------------
|
||||
// Simplified operators.
|
||||
//------------------------------------------------------------------
|
||||
case IrOpcode::kAnyToBoolean: {
|
||||
if (IsSafeBitOperand(node->InputAt(0))) {
|
||||
VisitUnop(node, kRepBit, kRepBit);
|
||||
if (lower()) DeferReplacement(node, node->InputAt(0));
|
||||
} else {
|
||||
VisitUnop(node, kMachAnyTagged, kTypeBool | kRepTagged);
|
||||
if (lower()) {
|
||||
// AnyToBoolean(x) => Call(ToBooleanStub, x, no-context)
|
||||
Operator::Properties properties = node->op()->properties();
|
||||
Callable callable = CodeFactory::ToBoolean(
|
||||
jsgraph_->isolate(), ToBooleanStub::RESULT_AS_ODDBALL);
|
||||
CallDescriptor::Flags flags = CallDescriptor::kPatchableCallSite;
|
||||
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
|
||||
callable.descriptor(), 0, flags, properties, jsgraph_->zone());
|
||||
node->set_op(jsgraph_->common()->Call(desc));
|
||||
node->InsertInput(jsgraph_->zone(), 0,
|
||||
jsgraph_->HeapConstant(callable.code()));
|
||||
node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kBooleanNot: {
|
||||
if (lower()) {
|
||||
MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
|
||||
@@ -1034,6 +1064,7 @@ class RepresentationSelector {
|
||||
Phase phase_; // current phase of algorithm
|
||||
RepresentationChanger* changer_; // for inserting representation changes
|
||||
ZoneQueue<Node*> queue_; // queue for traversing the graph
|
||||
Type* safe_bit_range_;
|
||||
Type* safe_int_additive_range_;
|
||||
|
||||
NodeInfo* GetInfo(Node* node) {
|
||||
@@ -1058,7 +1089,7 @@ void SimplifiedLowering::LowerAllNodes() {
|
||||
SimplifiedOperatorBuilder simplified(graph()->zone());
|
||||
RepresentationChanger changer(jsgraph(), &simplified,
|
||||
graph()->zone()->isolate());
|
||||
RepresentationSelector selector(jsgraph(), zone(), &changer);
|
||||
RepresentationSelector selector(jsgraph(), zone_, &changer);
|
||||
selector.Run(this);
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -20,7 +20,8 @@ class RepresentationChanger;
|
||||
|
||||
class SimplifiedLowering FINAL {
|
||||
public:
|
||||
explicit SimplifiedLowering(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
|
||||
SimplifiedLowering(JSGraph* jsgraph, Zone* zone)
|
||||
: jsgraph_(jsgraph), zone_(zone) {}
|
||||
~SimplifiedLowering() {}
|
||||
|
||||
void LowerAllNodes();
|
||||
@@ -41,7 +42,8 @@ class SimplifiedLowering FINAL {
|
||||
void DoStringLessThanOrEqual(Node* node);
|
||||
|
||||
private:
|
||||
JSGraph* jsgraph_;
|
||||
JSGraph* const jsgraph_;
|
||||
Zone* const zone_;
|
||||
|
||||
Node* SmiTag(Node* node);
|
||||
Node* IsTagged(Node* node);
|
||||
|
||||
+39
-1
@@ -2,10 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/simplified-operator-reducer.h"
|
||||
|
||||
#include "src/compiler/access-builder.h"
|
||||
#include "src/compiler/js-graph.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/simplified-operator-reducer.h"
|
||||
#include "src/compiler/node-properties-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@@ -20,6 +23,8 @@ SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {}
|
||||
|
||||
Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kAnyToBoolean:
|
||||
return ReduceAnyToBoolean(node);
|
||||
case IrOpcode::kBooleanNot: {
|
||||
HeapObjectMatcher<HeapObject> m(node->InputAt(0));
|
||||
if (m.Is(Unique<HeapObject>::CreateImmovable(factory()->false_value()))) {
|
||||
@@ -105,8 +110,36 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Reduction SimplifiedOperatorReducer::ReduceAnyToBoolean(Node* node) {
|
||||
Node* const input = NodeProperties::GetValueInput(node, 0);
|
||||
Type* const input_type = NodeProperties::GetBounds(input).upper;
|
||||
if (input_type->Is(Type::Boolean())) {
|
||||
// AnyToBoolean(x:boolean) => x
|
||||
return Replace(input);
|
||||
}
|
||||
if (input_type->Is(Type::OrderedNumber())) {
|
||||
// AnyToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
|
||||
Node* compare = graph()->NewNode(simplified()->NumberEqual(), input,
|
||||
jsgraph()->ZeroConstant());
|
||||
return Change(node, simplified()->BooleanNot(), compare);
|
||||
}
|
||||
if (input_type->Is(Type::String())) {
|
||||
// AnyToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
|
||||
FieldAccess const access = AccessBuilder::ForStringLength();
|
||||
Node* length = graph()->NewNode(simplified()->LoadField(access), input,
|
||||
graph()->start(), graph()->start());
|
||||
Node* compare = graph()->NewNode(simplified()->NumberEqual(), length,
|
||||
jsgraph()->ZeroConstant());
|
||||
return Change(node, simplified()->BooleanNot(), compare);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
||||
Reduction SimplifiedOperatorReducer::Change(Node* node, const Operator* op,
|
||||
Node* a) {
|
||||
DCHECK_EQ(node->InputCount(), OperatorProperties::GetTotalInputCount(op));
|
||||
DCHECK_LE(1, node->InputCount());
|
||||
node->set_op(op);
|
||||
node->ReplaceInput(0, a);
|
||||
return Changed(node);
|
||||
@@ -141,6 +174,11 @@ Factory* SimplifiedOperatorReducer::factory() const {
|
||||
}
|
||||
|
||||
|
||||
CommonOperatorBuilder* SimplifiedOperatorReducer::common() const {
|
||||
return jsgraph()->common();
|
||||
}
|
||||
|
||||
|
||||
MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const {
|
||||
return jsgraph()->machine();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ class Heap;
|
||||
namespace compiler {
|
||||
|
||||
// Forward declarations.
|
||||
class CommonOperatorBuilder;
|
||||
class JSGraph;
|
||||
class MachineOperatorBuilder;
|
||||
|
||||
@@ -28,6 +29,8 @@ class SimplifiedOperatorReducer FINAL : public Reducer {
|
||||
Reduction Reduce(Node* node) FINAL;
|
||||
|
||||
private:
|
||||
Reduction ReduceAnyToBoolean(Node* node);
|
||||
|
||||
Reduction Change(Node* node, const Operator* op, Node* a);
|
||||
Reduction ReplaceFloat64(double value);
|
||||
Reduction ReplaceInt32(int32_t value);
|
||||
@@ -40,6 +43,7 @@ class SimplifiedOperatorReducer FINAL : public Reducer {
|
||||
Graph* graph() const;
|
||||
Factory* factory() const;
|
||||
JSGraph* jsgraph() const { return jsgraph_; }
|
||||
CommonOperatorBuilder* common() const;
|
||||
MachineOperatorBuilder* machine() const;
|
||||
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
|
||||
|
||||
|
||||
+1
@@ -158,6 +158,7 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
|
||||
|
||||
|
||||
#define PURE_OP_LIST(V) \
|
||||
V(AnyToBoolean, Operator::kNoProperties, 1) \
|
||||
V(BooleanNot, Operator::kNoProperties, 1) \
|
||||
V(BooleanToNumber, Operator::kNoProperties, 1) \
|
||||
V(NumberEqual, Operator::kCommutative, 2) \
|
||||
|
||||
+2
@@ -128,6 +128,8 @@ class SimplifiedOperatorBuilder FINAL {
|
||||
public:
|
||||
explicit SimplifiedOperatorBuilder(Zone* zone);
|
||||
|
||||
const Operator* AnyToBoolean();
|
||||
|
||||
const Operator* BooleanNot();
|
||||
const Operator* BooleanToNumber();
|
||||
|
||||
|
||||
Vendored
+26
-23
@@ -33,10 +33,11 @@ enum LazyCachedType {
|
||||
kImulFunc,
|
||||
kClz32Func,
|
||||
kArrayBufferFunc,
|
||||
#define NATIVE_TYPE_CASE(Type) k##Type, k##Type##Array, k##Type##ArrayFunc,
|
||||
NATIVE_TYPES(NATIVE_TYPE_CASE)
|
||||
#undef NATIVE_TYPE_CASE
|
||||
kNumLazyCachedTypes
|
||||
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||
k##Type, k##Type##Array, k##Type##ArrayFunc,
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
||||
#undef TYPED_ARRAY_CASE
|
||||
kNumLazyCachedTypes
|
||||
};
|
||||
|
||||
|
||||
@@ -75,6 +76,8 @@ class LazyTypeCache FINAL : public ZoneObject {
|
||||
return CreateNative(Type::Number(), Type::UntaggedFloat32());
|
||||
case kFloat64:
|
||||
return CreateNative(Type::Number(), Type::UntaggedFloat64());
|
||||
case kUint8Clamped:
|
||||
return Get(kUint8);
|
||||
case kNumberFunc0:
|
||||
return Type::Function(Type::Number(), zone());
|
||||
case kNumberFunc1:
|
||||
@@ -89,13 +92,13 @@ class LazyTypeCache FINAL : public ZoneObject {
|
||||
return Type::Function(CreateRange(0, 32), Type::Number(), zone());
|
||||
case kArrayBufferFunc:
|
||||
return Type::Function(Type::Object(zone()), Type::Unsigned32(), zone());
|
||||
#define NATIVE_TYPE_CASE(Type) \
|
||||
case k##Type##Array: \
|
||||
return CreateArray(Get(k##Type)); \
|
||||
case k##Type##ArrayFunc: \
|
||||
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||
case k##Type##Array: \
|
||||
return CreateArray(Get(k##Type)); \
|
||||
case k##Type##ArrayFunc: \
|
||||
return CreateArrayFunction(Get(k##Type##Array));
|
||||
NATIVE_TYPES(NATIVE_TYPE_CASE)
|
||||
#undef NATIVE_TYPE_CASE
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
||||
#undef TYPED_ARRAY_CASE
|
||||
case kNumLazyCachedTypes:
|
||||
break;
|
||||
}
|
||||
@@ -1438,6 +1441,11 @@ Bounds Typer::Visitor::TypeJSDebugger(Node* node) {
|
||||
// Simplified operators.
|
||||
|
||||
|
||||
Bounds Typer::Visitor::TypeAnyToBoolean(Node* node) {
|
||||
return TypeUnaryOp(node, ToBoolean);
|
||||
}
|
||||
|
||||
|
||||
Bounds Typer::Visitor::TypeBooleanNot(Node* node) {
|
||||
return Bounds(Type::None(zone()), Type::Boolean(zone()));
|
||||
}
|
||||
@@ -1615,13 +1623,11 @@ Bounds Typer::Visitor::TypeLoadBuffer(Node* node) {
|
||||
// TODO(bmeurer): This typing is not yet correct. Since we can still access
|
||||
// out of bounds, the type in the general case has to include Undefined.
|
||||
switch (BufferAccessOf(node->op()).external_array_type()) {
|
||||
#define NATIVE_TYPE_CASE(Type) \
|
||||
case kExternal##Type##Array: \
|
||||
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||
case kExternal##Type##Array: \
|
||||
return Bounds(typer_->cache_->Get(k##Type));
|
||||
NATIVE_TYPES(NATIVE_TYPE_CASE)
|
||||
#undef NATIVE_TYPE_CASE
|
||||
case kExternalUint8ClampedArray:
|
||||
break;
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
||||
#undef TYPED_ARRAY_CASE
|
||||
}
|
||||
UNREACHABLE();
|
||||
return Bounds();
|
||||
@@ -2088,14 +2094,11 @@ Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
|
||||
}
|
||||
} else if (value->IsJSTypedArray()) {
|
||||
switch (JSTypedArray::cast(*value)->type()) {
|
||||
#define NATIVE_TYPE_CASE(Type) \
|
||||
case kExternal##Type##Array: \
|
||||
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||
case kExternal##Type##Array: \
|
||||
return typer_->cache_->Get(k##Type##Array);
|
||||
NATIVE_TYPES(NATIVE_TYPE_CASE)
|
||||
#undef NATIVE_TYPE_CASE
|
||||
case kExternalUint8ClampedArray:
|
||||
// TODO(rossberg): Do we want some ClampedArray type to express this?
|
||||
break;
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
||||
#undef TYPED_ARRAY_CASE
|
||||
}
|
||||
}
|
||||
return Type::Constant(value, zone());
|
||||
|
||||
Vendored
+4
@@ -482,6 +482,10 @@ void Verifier::Visitor::Pre(Node* node) {
|
||||
|
||||
// Simplified operators
|
||||
// -------------------------------
|
||||
case IrOpcode::kAnyToBoolean:
|
||||
// Type is Boolean.
|
||||
CheckUpperIs(node, Type::Boolean());
|
||||
break;
|
||||
case IrOpcode::kBooleanNot:
|
||||
// Boolean -> Boolean
|
||||
CheckValueInputIs(node, 0, Type::Boolean());
|
||||
|
||||
Vendored
+1
-1
@@ -1577,7 +1577,7 @@ class StartupDataHandler {
|
||||
const char* last_slash = strrchr(exec_path, '/');
|
||||
if (last_slash) {
|
||||
int after_slash = last_slash - exec_path + 1;
|
||||
int name_length = strlen(name);
|
||||
int name_length = static_cast<int>(strlen(name));
|
||||
*buffer =
|
||||
reinterpret_cast<char*>(calloc(after_slash + name_length + 1, 1));
|
||||
strncpy(*buffer, exec_path, after_slash);
|
||||
|
||||
Vendored
+1
-1
@@ -573,7 +573,7 @@ void Debug::ThreadInit() {
|
||||
thread_local_.step_out_fp_ = 0;
|
||||
// TODO(isolates): frames_are_dropped_?
|
||||
base::NoBarrier_Store(&thread_local_.current_debug_scope_,
|
||||
static_cast<base::AtomicWord>(0));
|
||||
static_cast<base::AtomicWord>(NULL));
|
||||
thread_local_.restarter_frame_function_pointer_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+5
-10
@@ -637,7 +637,7 @@ Code* Deoptimizer::FindOptimizedCode(JSFunction* function,
|
||||
|
||||
void Deoptimizer::PrintFunctionName() {
|
||||
if (function_->IsJSFunction()) {
|
||||
function_->PrintName(trace_scope_->file());
|
||||
function_->ShortPrint(trace_scope_->file());
|
||||
} else {
|
||||
PrintF(trace_scope_->file(),
|
||||
"%s", Code::Kind2String(compiled_code_->kind()));
|
||||
@@ -761,10 +761,8 @@ void Deoptimizer::DoComputeOutputFrames() {
|
||||
|
||||
if (trace_scope_ != NULL) {
|
||||
timer.Start();
|
||||
PrintF(trace_scope_->file(),
|
||||
"[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
|
||||
MessageFor(bailout_type_),
|
||||
reinterpret_cast<intptr_t>(function_));
|
||||
PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ",
|
||||
MessageFor(bailout_type_));
|
||||
PrintFunctionName();
|
||||
PrintF(trace_scope_->file(),
|
||||
" (opt #%d) @%d, FP to SP delta: %d]\n",
|
||||
@@ -850,11 +848,8 @@ void Deoptimizer::DoComputeOutputFrames() {
|
||||
if (trace_scope_ != NULL) {
|
||||
double ms = timer.Elapsed().InMillisecondsF();
|
||||
int index = output_count_ - 1; // Index of the topmost frame.
|
||||
JSFunction* function = output_[index]->GetFunction();
|
||||
PrintF(trace_scope_->file(),
|
||||
"[deoptimizing (%s): end 0x%08" V8PRIxPTR " ",
|
||||
MessageFor(bailout_type_),
|
||||
reinterpret_cast<intptr_t>(function));
|
||||
PrintF(trace_scope_->file(), "[deoptimizing (%s): end ",
|
||||
MessageFor(bailout_type_));
|
||||
PrintFunctionName();
|
||||
PrintF(trace_scope_->file(),
|
||||
" @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
|
||||
|
||||
Vendored
+6
-5
@@ -183,16 +183,17 @@ DEFINE_IMPLICATION(es_staging, harmony)
|
||||
V(harmony_unicode, "harmony unicode escapes")
|
||||
|
||||
// Features that are complete (but still behind --harmony/es-staging flag).
|
||||
#define HARMONY_STAGED(V) V(harmony_tostring, "harmony toString")
|
||||
#define HARMONY_STAGED(V) \
|
||||
V(harmony_tostring, "harmony toString") \
|
||||
V(harmony_classes, \
|
||||
"harmony classes (implies block scoping & object literal extension)") \
|
||||
V(harmony_object_literals, "harmony object literal extensions")
|
||||
|
||||
// Features that are shipping (turned on by default, but internal flag remains).
|
||||
#define HARMONY_SHIPPING(V) \
|
||||
V(harmony_numeric_literals, "harmony numeric literals") \
|
||||
V(harmony_strings, "harmony string methods") \
|
||||
V(harmony_scoping, "harmony block scoping") \
|
||||
V(harmony_classes, \
|
||||
"harmony classes (implies block scoping & object literal extension)") \
|
||||
V(harmony_object_literals, "harmony object literal extensions") \
|
||||
V(harmony_templates, "harmony template literals")
|
||||
|
||||
// Once a shipping feature has proved stable in the wild, it will be dropped
|
||||
@@ -498,7 +499,7 @@ DEFINE_BOOL(trace_stub_failures, false,
|
||||
"trace deoptimization of generated code stubs")
|
||||
|
||||
DEFINE_BOOL(serialize_toplevel, true, "enable caching of toplevel scripts")
|
||||
DEFINE_BOOL(serialize_inner, false, "enable caching of inner functions")
|
||||
DEFINE_BOOL(serialize_inner, true, "enable caching of inner functions")
|
||||
DEFINE_BOOL(trace_serializer, false, "print code serializer trace")
|
||||
|
||||
// compiler.cc
|
||||
|
||||
Vendored
+1
-1
@@ -4611,7 +4611,7 @@ bool Heap::IdleNotification(double deadline_in_seconds) {
|
||||
}
|
||||
|
||||
|
||||
bool Heap::RecentIdleNotifcationHappened() {
|
||||
bool Heap::RecentIdleNotificationHappened() {
|
||||
return (last_idle_notification_time_ +
|
||||
GCIdleTimeHandler::kMaxFrameRenderingIdleTime) >
|
||||
MonotonicallyIncreasingTimeInMs();
|
||||
|
||||
Vendored
+1
-1
@@ -1298,7 +1298,7 @@ class Heap {
|
||||
|
||||
int gc_count() const { return gc_count_; }
|
||||
|
||||
bool RecentIdleNotifcationHappened();
|
||||
bool RecentIdleNotificationHappened();
|
||||
|
||||
// Completely clear the Instanceof cache (to stop it keeping objects alive
|
||||
// around a GC).
|
||||
|
||||
+1
-1
@@ -891,7 +891,7 @@ intptr_t IncrementalMarking::Step(intptr_t allocated_bytes,
|
||||
|
||||
// If an idle notification happened recently, we delay marking steps.
|
||||
if (marking == DO_NOT_FORCE_MARKING &&
|
||||
heap_->RecentIdleNotifcationHappened()) {
|
||||
heap_->RecentIdleNotificationHappened()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
-1
@@ -140,7 +140,8 @@ bool CodeRange::SetUp(size_t requested) {
|
||||
base += kReservedCodeRangePages * base::OS::CommitPageSize();
|
||||
}
|
||||
Address aligned_base = RoundUp(base, MemoryChunk::kAlignment);
|
||||
size_t size = code_range_->size() - (aligned_base - base);
|
||||
size_t size = code_range_->size() - (aligned_base - base) -
|
||||
kReservedCodeRangePages * base::OS::CommitPageSize();
|
||||
allocation_list_.Add(FreeBlock(aligned_base, size));
|
||||
current_allocation_block_index_ = 0;
|
||||
|
||||
|
||||
Vendored
+30
-3
@@ -34,7 +34,11 @@
|
||||
// significantly by Google Inc.
|
||||
// Copyright 2012 the V8 project authors. All rights reserved.
|
||||
|
||||
#include "src/v8.h"
|
||||
#include "src/ia32/assembler-ia32.h"
|
||||
|
||||
#if V8_OS_MACOSX
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
|
||||
@@ -42,7 +46,7 @@
|
||||
#include "src/base/cpu.h"
|
||||
#include "src/disassembler.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/serialize.h"
|
||||
#include "src/v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@@ -50,6 +54,29 @@ namespace internal {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of CpuFeatures
|
||||
|
||||
namespace {
|
||||
|
||||
bool EnableAVX() {
|
||||
#if V8_OS_MACOSX
|
||||
// Mac OS X 10.9 has a bug where AVX transitions were indeed being caused by
|
||||
// ISRs, so we detect Mac OS X 10.9 here and disable AVX in that case.
|
||||
char buffer[128];
|
||||
size_t buffer_size = arraysize(buffer);
|
||||
int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
|
||||
if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
|
||||
V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
|
||||
}
|
||||
// The buffer now contains a string of the form XX.YY.ZZ, where
|
||||
// XX is the major kernel version component. 13.x.x (Mavericks) is
|
||||
// affected by this bug, so disable AVX there.
|
||||
if (memcmp(buffer, "13.", 3) == 0) return false;
|
||||
#endif // V8_OS_MACOSX
|
||||
return FLAG_enable_avx;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
void CpuFeatures::ProbeImpl(bool cross_compile) {
|
||||
base::CPU cpu;
|
||||
CHECK(cpu.has_sse2()); // SSE2 support is mandatory.
|
||||
@@ -60,7 +87,7 @@ void CpuFeatures::ProbeImpl(bool cross_compile) {
|
||||
|
||||
if (cpu.has_sse41() && FLAG_enable_sse4_1) supported_ |= 1u << SSE4_1;
|
||||
if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3;
|
||||
if (cpu.has_avx() && FLAG_enable_avx) supported_ |= 1u << AVX;
|
||||
if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX;
|
||||
if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-2
@@ -682,6 +682,7 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
// Handle errors detected during parsing, move statistics to Isolate,
|
||||
// internalize strings (move them to the heap).
|
||||
void Internalize();
|
||||
void HandleSourceURLComments();
|
||||
|
||||
private:
|
||||
friend class ParserTraits;
|
||||
@@ -879,8 +880,6 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
const AstRawString* function_name, int pos, Variable* fvar,
|
||||
Token::Value fvar_init_op, bool is_generator, bool* ok);
|
||||
|
||||
void HandleSourceURLComments();
|
||||
|
||||
void ThrowPendingError();
|
||||
|
||||
TemplateLiteralState OpenTemplateLiteral(int pos);
|
||||
|
||||
Vendored
+1
-1
@@ -467,7 +467,7 @@ class ParserBase : public Traits {
|
||||
void ReportMessageAt(Scanner::Location location, const char* message,
|
||||
bool is_reference_error = false) {
|
||||
Traits::ReportMessageAt(location, message,
|
||||
reinterpret_cast<const char*>(0),
|
||||
reinterpret_cast<const char*>(NULL),
|
||||
is_reference_error);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -672,7 +672,7 @@ function DefaultString(x) {
|
||||
}
|
||||
|
||||
function ToPositiveInteger(x, rangeErrorName) {
|
||||
var i = TO_INTEGER(x);
|
||||
var i = TO_INTEGER_MAP_MINUS_ZERO(x);
|
||||
if (i < 0) throw MakeRangeError(rangeErrorName);
|
||||
return i;
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -117,7 +117,7 @@ class Unique {
|
||||
|
||||
// TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
|
||||
static Unique<T> CreateUninitialized(Handle<T> handle) {
|
||||
return Unique<T>(NULL, handle);
|
||||
return Unique<T>(reinterpret_cast<Address>(NULL), handle);
|
||||
}
|
||||
|
||||
static Unique<T> CreateImmovable(Handle<T> handle) {
|
||||
|
||||
Vendored
+4
-4
@@ -32,10 +32,10 @@
|
||||
// These macros define the version number for the current version.
|
||||
// NOTE these macros are used by some of the tool scripts and the build
|
||||
// system so their names cannot be changed without changing the scripts.
|
||||
#define MAJOR_VERSION 3
|
||||
#define MINOR_VERSION 31
|
||||
#define BUILD_NUMBER 74
|
||||
#define PATCH_LEVEL 1
|
||||
#define MAJOR_VERSION 4
|
||||
#define MINOR_VERSION 1
|
||||
#define BUILD_NUMBER 0
|
||||
#define PATCH_LEVEL 7
|
||||
// Use 1 for candidates and 0 otherwise.
|
||||
// (Boolean macro values are not supported by all preprocessors.)
|
||||
#define IS_CANDIDATE_VERSION 0
|
||||
|
||||
Vendored
+30
-3
@@ -2,13 +2,17 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/v8.h"
|
||||
#include "src/x64/assembler-x64.h"
|
||||
|
||||
#if V8_OS_MACOSX
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if V8_TARGET_ARCH_X64
|
||||
|
||||
#include "src/base/bits.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/serialize.h"
|
||||
#include "src/v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@@ -16,6 +20,29 @@ namespace internal {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of CpuFeatures
|
||||
|
||||
namespace {
|
||||
|
||||
bool EnableAVX() {
|
||||
#if V8_OS_MACOSX
|
||||
// Mac OS X 10.9 has a bug where AVX transitions were indeed being caused by
|
||||
// ISRs, so we detect Mac OS X 10.9 here and disable AVX in that case.
|
||||
char buffer[128];
|
||||
size_t buffer_size = arraysize(buffer);
|
||||
int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
|
||||
if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
|
||||
V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
|
||||
}
|
||||
// The buffer now contains a string of the form XX.YY.ZZ, where
|
||||
// XX is the major kernel version component. 13.x.x (Mavericks) is
|
||||
// affected by this bug, so disable AVX there.
|
||||
if (memcmp(buffer, "13.", 3) == 0) return false;
|
||||
#endif // V8_OS_MACOSX
|
||||
return FLAG_enable_avx;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
void CpuFeatures::ProbeImpl(bool cross_compile) {
|
||||
base::CPU cpu;
|
||||
CHECK(cpu.has_sse2()); // SSE2 support is mandatory.
|
||||
@@ -28,7 +55,7 @@ void CpuFeatures::ProbeImpl(bool cross_compile) {
|
||||
if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3;
|
||||
// SAHF is not generally available in long mode.
|
||||
if (cpu.has_sahf() && FLAG_enable_sahf) supported_ |= 1u << SAHF;
|
||||
if (cpu.has_avx() && FLAG_enable_avx) supported_ |= 1u << AVX;
|
||||
if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX;
|
||||
if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3;
|
||||
}
|
||||
|
||||
|
||||
+1
-42
@@ -507,24 +507,6 @@ TEST(JSToBoolean) {
|
||||
CHECK_EQ(IrOpcode::kParameter, r->opcode());
|
||||
}
|
||||
|
||||
{ // ToBoolean(ordered-number)
|
||||
Node* r = R.ReduceUnop(op, Type::OrderedNumber());
|
||||
CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
|
||||
Node* i = r->InputAt(0);
|
||||
CHECK_EQ(IrOpcode::kNumberEqual, i->opcode());
|
||||
// ToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
|
||||
}
|
||||
|
||||
{ // ToBoolean(string)
|
||||
Node* r = R.ReduceUnop(op, Type::String());
|
||||
CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
|
||||
Node* i = r->InputAt(0);
|
||||
CHECK_EQ(IrOpcode::kNumberEqual, i->opcode());
|
||||
Node* j = i->InputAt(0);
|
||||
CHECK_EQ(IrOpcode::kLoadField, j->opcode());
|
||||
// ToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
|
||||
}
|
||||
|
||||
{ // ToBoolean(object)
|
||||
Node* r = R.ReduceUnop(op, Type::DetectableObject());
|
||||
R.CheckTrue(r);
|
||||
@@ -537,30 +519,7 @@ TEST(JSToBoolean) {
|
||||
|
||||
{ // ToBoolean(object)
|
||||
Node* r = R.ReduceUnop(op, Type::Object());
|
||||
CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(JSToBoolean_replacement) {
|
||||
JSTypedLoweringTester R;
|
||||
|
||||
Type* types[] = {Type::Null(), Type::Undefined(),
|
||||
Type::Boolean(), Type::OrderedNumber(),
|
||||
Type::DetectableObject(), Type::Undetectable()};
|
||||
|
||||
for (size_t i = 0; i < arraysize(types); i++) {
|
||||
Node* n = R.Parameter(types[i]);
|
||||
Node* c = R.graph.NewNode(R.javascript.ToBoolean(), n, R.context());
|
||||
Node* r = R.reduce(c);
|
||||
|
||||
if (types[i]->Is(Type::Boolean())) {
|
||||
CHECK_EQ(n, r);
|
||||
} else if (types[i]->Is(Type::OrderedNumber())) {
|
||||
CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
|
||||
} else {
|
||||
CHECK_EQ(IrOpcode::kHeapConstant, r->opcode());
|
||||
}
|
||||
CHECK_EQ(IrOpcode::kAnyToBoolean, r->opcode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+48
-10
@@ -39,7 +39,7 @@ class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> {
|
||||
typer(this->graph(), MaybeHandle<Context>()),
|
||||
javascript(this->zone()),
|
||||
jsgraph(this->graph(), this->common(), &javascript, this->machine()),
|
||||
lowering(&jsgraph) {}
|
||||
lowering(&jsgraph, this->zone()) {}
|
||||
|
||||
Typer typer;
|
||||
JSOperatorBuilder javascript;
|
||||
@@ -698,9 +698,7 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
|
||||
CHECK_EQ(expected, node->opcode());
|
||||
}
|
||||
|
||||
void Lower() {
|
||||
SimplifiedLowering(&jsgraph).LowerAllNodes();
|
||||
}
|
||||
void Lower() { SimplifiedLowering(&jsgraph, jsgraph.zone()).LowerAllNodes(); }
|
||||
|
||||
// Inserts the node as the return value of the graph.
|
||||
Node* Return(Node* node) {
|
||||
@@ -789,6 +787,50 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
|
||||
};
|
||||
|
||||
|
||||
TEST(LowerAnyToBoolean_bit_bit) {
|
||||
// AnyToBoolean(x: kRepBit) used as kRepBit
|
||||
HandleAndZoneScope scope;
|
||||
Factory* f = scope.main_zone()->isolate()->factory();
|
||||
Handle<Object> zero = f->NewNumber(0);
|
||||
Handle<Object> one = f->NewNumber(1);
|
||||
Type* singleton_zero = Type::Constant(zero, scope.main_zone());
|
||||
Type* singleton_one = Type::Constant(one, scope.main_zone());
|
||||
Type* zero_one_range = Type::Range(zero, one, scope.main_zone());
|
||||
static Type* kTypes[] = {
|
||||
singleton_zero, singleton_one, zero_one_range, Type::Boolean(),
|
||||
Type::Union(Type::Boolean(), singleton_zero, scope.main_zone()),
|
||||
Type::Union(Type::Boolean(), singleton_one, scope.main_zone()),
|
||||
Type::Union(Type::Boolean(), zero_one_range, scope.main_zone())};
|
||||
for (Type* type : kTypes) {
|
||||
TestingGraph t(type);
|
||||
Node* x = t.ExampleWithTypeAndRep(type, kRepBit);
|
||||
Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
|
||||
Node* use = t.Branch(cnv);
|
||||
t.Lower();
|
||||
CHECK_EQ(x, use->InputAt(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if V8_TURBOFAN_TARGET
|
||||
|
||||
TEST(LowerAnyToBoolean_tagged_tagged) {
|
||||
// AnyToBoolean(x: kRepTagged) used as kRepTagged
|
||||
TestingGraph t(Type::Any());
|
||||
Node* x = t.p0;
|
||||
Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
|
||||
Node* use = t.Use(cnv, kRepTagged);
|
||||
t.Return(use);
|
||||
t.Lower();
|
||||
CHECK_EQ(IrOpcode::kCall, cnv->opcode());
|
||||
CHECK_EQ(IrOpcode::kHeapConstant, cnv->InputAt(0)->opcode());
|
||||
CHECK_EQ(x, cnv->InputAt(1));
|
||||
CHECK_EQ(t.jsgraph.NoContextConstant(), cnv->InputAt(2));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST(LowerBooleanNot_bit_bit) {
|
||||
// BooleanNot(x: kRepBit) used as kRepBit
|
||||
TestingGraph t(Type::Boolean());
|
||||
@@ -1995,11 +2037,6 @@ TEST(PhiRepresentation) {
|
||||
HandleAndZoneScope scope;
|
||||
Zone* z = scope.main_zone();
|
||||
|
||||
Factory* f = z->isolate()->factory();
|
||||
Handle<Object> range_min = f->NewNumber(-1e13);
|
||||
Handle<Object> range_max = f->NewNumber(1e+15);
|
||||
Type* range = Type::Range(range_min, range_max, z);
|
||||
|
||||
struct TestData {
|
||||
Type* arg1;
|
||||
Type* arg2;
|
||||
@@ -2010,7 +2047,8 @@ TEST(PhiRepresentation) {
|
||||
TestData test_data[] = {
|
||||
{Type::Signed32(), Type::Unsigned32(), kMachInt32,
|
||||
kRepWord32 | kTypeNumber},
|
||||
{range, range, kMachUint32, kRepWord32 | kTypeNumber},
|
||||
{Type::Signed32(), Type::Unsigned32(), kMachUint32,
|
||||
kRepWord32 | kTypeNumber},
|
||||
{Type::Signed32(), Type::Signed32(), kMachInt32, kMachInt32},
|
||||
{Type::Unsigned32(), Type::Unsigned32(), kMachInt32, kMachUint32},
|
||||
{Type::Number(), Type::Signed32(), kMachInt32, kMachFloat64},
|
||||
|
||||
Vendored
+2
-1
@@ -198,7 +198,8 @@ TEST(CodeRange) {
|
||||
const size_t code_range_size = 32*MB;
|
||||
CcTest::InitializeVM();
|
||||
CodeRange code_range(reinterpret_cast<Isolate*>(CcTest::isolate()));
|
||||
code_range.SetUp(code_range_size);
|
||||
code_range.SetUp(code_range_size +
|
||||
kReservedCodeRangePages * v8::base::OS::CommitPageSize());
|
||||
size_t current_allocated = 0;
|
||||
size_t total_allocated = 0;
|
||||
List< ::Block> blocks(1000);
|
||||
|
||||
Vendored
+37
-5
@@ -23999,10 +23999,8 @@ TEST(ScriptNameAndLineNumber) {
|
||||
CHECK_EQ(13, line_number);
|
||||
}
|
||||
|
||||
|
||||
void SourceURLHelper(const char* source, const char* expected_source_url,
|
||||
const char* expected_source_mapping_url) {
|
||||
Local<Script> script = v8_compile(source);
|
||||
void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
|
||||
const char* expected_source_mapping_url) {
|
||||
if (expected_source_url != NULL) {
|
||||
v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
|
||||
CHECK_EQ(expected_source_url, *url);
|
||||
@@ -24018,6 +24016,12 @@ void SourceURLHelper(const char* source, const char* expected_source_url,
|
||||
}
|
||||
}
|
||||
|
||||
void SourceURLHelper(const char* source, const char* expected_source_url,
|
||||
const char* expected_source_mapping_url) {
|
||||
Local<Script> script = v8_compile(source);
|
||||
CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
|
||||
}
|
||||
|
||||
|
||||
TEST(ScriptSourceURLAndSourceMappingURL) {
|
||||
LocalContext env;
|
||||
@@ -24209,7 +24213,9 @@ class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
|
||||
void RunStreamingTest(const char** chunks,
|
||||
v8::ScriptCompiler::StreamedSource::Encoding encoding =
|
||||
v8::ScriptCompiler::StreamedSource::ONE_BYTE,
|
||||
bool expected_success = true) {
|
||||
bool expected_success = true,
|
||||
const char* expected_source_url = NULL,
|
||||
const char* expected_source_mapping_url = NULL) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
@@ -24238,6 +24244,8 @@ void RunStreamingTest(const char** chunks,
|
||||
v8::Handle<Value> result(script->Run());
|
||||
// All scripts are supposed to return the fixed value 13 when ran.
|
||||
CHECK_EQ(13, result->Int32Value());
|
||||
CheckMagicComments(script, expected_source_url,
|
||||
expected_source_mapping_url);
|
||||
} else {
|
||||
CHECK(script.IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
@@ -24727,3 +24735,27 @@ TEST(ClassPrototypeCreationContext) {
|
||||
CompileRun("'use strict'; class Example { }; Example.prototype"));
|
||||
CHECK(env.local() == result->CreationContext());
|
||||
}
|
||||
|
||||
|
||||
TEST(SimpleStreamingScriptWithSourceURL) {
|
||||
const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
|
||||
"//# sourceURL=bar2.js\n", NULL};
|
||||
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
|
||||
"bar2.js");
|
||||
}
|
||||
|
||||
|
||||
TEST(StreamingScriptWithSplitSourceURL) {
|
||||
const char* chunks[] = {"function foo() { ret", "urn 13; } f",
|
||||
"oo();\n//# sourceURL=b", "ar2.js\n", NULL};
|
||||
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
|
||||
"bar2.js");
|
||||
}
|
||||
|
||||
|
||||
TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
|
||||
const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
|
||||
" sourceMappingURL=bar2.js\n", "foo();", NULL};
|
||||
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
|
||||
"bar2.js");
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2015 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(x) {
|
||||
while (1) { s++; }
|
||||
while (x) { s++; }
|
||||
}
|
||||
|
||||
assertThrows(function () { f(1); });
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2015 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 Module(stdlib, foreign, heap) {
|
||||
"use asm";
|
||||
// This is not valid asm.js, but should nevertheless work.
|
||||
var MEM = new Uint8ClampedArray(heap);
|
||||
function foo( ) { MEM[0] ^= 1; }
|
||||
return {foo: foo};
|
||||
})(this, {}, new ArrayBuffer( ) ).foo();
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015 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 Module() {
|
||||
"use asm";
|
||||
function f() {
|
||||
var i = (140737463189505);
|
||||
do {
|
||||
i = i + i | 0;
|
||||
x = undefined + i | 0;
|
||||
} while (!i);
|
||||
}
|
||||
return { f: f };
|
||||
}
|
||||
|
||||
Module().f();
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2015 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 g() {
|
||||
throw 0;
|
||||
}
|
||||
|
||||
function f() {
|
||||
g();
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
assertThrows(function () { f(); });
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// Copyright 2015 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 TestConstructor(c) {
|
||||
var a = new c(-0);
|
||||
assertSame(Infinity, 1 / a.length);
|
||||
assertSame(Infinity, 1 / a.byteLength);
|
||||
|
||||
var ab = new ArrayBuffer(-0);
|
||||
assertSame(Infinity, 1 / ab.byteLength);
|
||||
|
||||
var a1 = new c(ab, -0, -0);
|
||||
assertSame(Infinity, 1 / a1.length);
|
||||
assertSame(Infinity, 1 / a1.byteLength);
|
||||
assertSame(Infinity, 1 / a1.byteOffset);
|
||||
}
|
||||
|
||||
var constructors =
|
||||
[ Uint8Array, Int8Array, Uint8ClampedArray,
|
||||
Uint16Array, Int16Array,
|
||||
Uint32Array, Int32Array,
|
||||
Float32Array, Float64Array ];
|
||||
for (var i = 0; i < constructors.length; i++) {
|
||||
TestConstructor(constructors[i]);
|
||||
}
|
||||
|
||||
|
||||
function TestOptimizedCode() {
|
||||
var a = new Uint8Array(-0);
|
||||
assertSame(Infinity, 1 / a.length);
|
||||
assertSame(Infinity, 1 / a.byteLength);
|
||||
|
||||
var ab = new ArrayBuffer(-0);
|
||||
assertSame(Infinity, 1 / ab.byteLength);
|
||||
|
||||
var a1 = new Uint8Array(ab, -0, -0);
|
||||
assertSame(Infinity, 1 / a1.length);
|
||||
assertSame(Infinity, 1 / a1.byteLength);
|
||||
assertSame(Infinity, 1 / a1.byteOffset);
|
||||
}
|
||||
|
||||
%OptimizeFunctionOnNextCall(Uint8Array);
|
||||
for (var i = 0; i < 1000; i++) {
|
||||
TestOptimizedCode();
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
using testing::_;
|
||||
using testing::AllOf;
|
||||
using testing::BitEq;
|
||||
using testing::Capture;
|
||||
using testing::CaptureEq;
|
||||
|
||||
@@ -78,7 +79,8 @@ class ChangeLoweringTest : public GraphTest {
|
||||
const Matcher<Node*>& control_matcher) {
|
||||
return IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
|
||||
AllocateHeapNumberStub(isolate()).GetCode())),
|
||||
IsNumberConstant(0.0), effect_matcher, control_matcher);
|
||||
IsNumberConstant(BitEq(0.0)), effect_matcher,
|
||||
control_matcher);
|
||||
}
|
||||
Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher,
|
||||
const Matcher<Node*>& control_matcher) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "test/unittests/compiler/node-test-utils.h"
|
||||
#include "testing/gmock-support.h"
|
||||
|
||||
using testing::BitEq;
|
||||
using testing::Capture;
|
||||
|
||||
namespace v8 {
|
||||
@@ -83,9 +84,11 @@ TEST_F(JSBuiltinReducerTest, MathAbs) {
|
||||
} else {
|
||||
Capture<Node*> branch;
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsSelect(kMachNone, IsNumberLessThan(IsNumberConstant(0), p0),
|
||||
p0, IsNumberSubtract(IsNumberConstant(0), p0)));
|
||||
EXPECT_THAT(
|
||||
r.replacement(),
|
||||
IsSelect(kMachNone,
|
||||
IsNumberLessThan(IsNumberConstant(BitEq(0.0)), p0), p0,
|
||||
IsNumberSubtract(IsNumberConstant(BitEq(0.0)), p0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+265
-92
@@ -8,10 +8,14 @@
|
||||
#include "src/compiler/js-typed-lowering.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node-properties-inl.h"
|
||||
#include "src/compiler/typer.h"
|
||||
#include "test/unittests/compiler/compiler-test-utils.h"
|
||||
#include "test/unittests/compiler/graph-unittest.h"
|
||||
#include "test/unittests/compiler/node-test-utils.h"
|
||||
#include "testing/gmock-support.h"
|
||||
|
||||
using testing::BitEq;
|
||||
using testing::IsNaN;
|
||||
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@@ -25,9 +29,35 @@ const ExternalArrayType kExternalArrayTypes[] = {
|
||||
kExternalFloat32Array, kExternalFloat64Array};
|
||||
|
||||
|
||||
const double kFloat64Values[] = {
|
||||
-V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
|
||||
-2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
|
||||
-1.67813e+72, -2.3382e+55, -3.179e+30, -1.441e+09, -1.0647e+09,
|
||||
-7.99361e+08, -5.77375e+08, -2.20984e+08, -32757, -13171, -9970, -3984,
|
||||
-107, -105, -92, -77, -61, -0.000208163, -1.86685e-06, -1.17296e-10,
|
||||
-9.26358e-11, -5.08004e-60, -1.74753e-65, -1.06561e-71, -5.67879e-79,
|
||||
-5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
|
||||
-4.40497e-267, -2.19666e-273, -4.9998e-276, -5.59821e-278, -2.03855e-282,
|
||||
-5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0, 0.0, 2.22507e-308,
|
||||
1.30127e-270, 7.62898e-260, 4.00313e-249, 3.16829e-233, 1.85244e-228,
|
||||
2.03544e-129, 1.35126e-110, 1.01182e-106, 5.26333e-94, 1.35292e-90,
|
||||
2.85394e-83, 1.78323e-77, 5.4967e-57, 1.03207e-25, 4.57401e-25, 1.58738e-05,
|
||||
2, 125, 2310, 9636, 14802, 17168, 28945, 29305, 4.81336e+07, 1.41207e+08,
|
||||
4.65962e+08, 1.40499e+09, 2.12648e+09, 8.80006e+30, 1.4446e+45, 1.12164e+54,
|
||||
2.48188e+89, 6.71121e+102, 3.074e+112, 4.9699e+152, 5.58383e+166,
|
||||
4.30654e+172, 7.08824e+185, 9.6586e+214, 2.028e+223, 6.63277e+243,
|
||||
1.56192e+261, 1.23202e+269, 5.72883e+289, 8.5798e+290, 1.40256e+294,
|
||||
1.79769e+308, V8_INFINITY};
|
||||
|
||||
|
||||
const size_t kIndices[] = {0, 1, 42, 100, 1024};
|
||||
|
||||
|
||||
const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0, -42.0,
|
||||
-1.0, 0.0, 1.0, 42.0,
|
||||
1000.0, INT_MAX, UINT_MAX, V8_INFINITY};
|
||||
|
||||
|
||||
Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
|
||||
Type::Number(), Type::String(), Type::Object()};
|
||||
|
||||
@@ -68,14 +98,193 @@ class JSTypedLoweringTest : public TypedGraphTest {
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// JSUnaryNot
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) {
|
||||
Node* input = Parameter(Type::Boolean(), 0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsBooleanNot(input));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
|
||||
Handle<Object> zero = factory()->NewNumber(0);
|
||||
Node* input = Parameter(
|
||||
Type::Union(
|
||||
Type::MinusZero(),
|
||||
Type::Union(
|
||||
Type::NaN(),
|
||||
Type::Union(
|
||||
Type::Null(),
|
||||
Type::Union(
|
||||
Type::Undefined(),
|
||||
Type::Union(
|
||||
Type::Undetectable(),
|
||||
Type::Union(
|
||||
Type::Constant(factory()->false_value(), zone()),
|
||||
Type::Range(zero, zero, zone()), zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsTrueConstant());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSUnaryNotWithTruish) {
|
||||
Node* input = Parameter(
|
||||
Type::Union(
|
||||
Type::Constant(factory()->true_value(), zone()),
|
||||
Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
|
||||
zone()),
|
||||
0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFalseConstant());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
|
||||
Node* input = Parameter(
|
||||
Type::Range(factory()->NewNumber(1), factory()->NewNumber(42), zone()),
|
||||
0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFalseConstant());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) {
|
||||
Node* input = Parameter(Type::Any(), 0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsBooleanNot(IsAnyToBoolean(input)));
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constant propagation
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) {
|
||||
{
|
||||
Reduction r = Reduce(
|
||||
Parameter(Type::Constant(factory()->minus_zero_value(), zone())));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
|
||||
}
|
||||
{
|
||||
Reduction r = Reduce(Parameter(Type::MinusZero()));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
|
||||
}
|
||||
{
|
||||
Reduction r = Reduce(Parameter(
|
||||
Type::Union(Type::MinusZero(),
|
||||
Type::Constant(factory()->NewNumber(0), zone()), zone())));
|
||||
EXPECT_FALSE(r.Changed());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, ParameterWithNull) {
|
||||
Handle<HeapObject> null = factory()->null_value();
|
||||
{
|
||||
Reduction r = Reduce(Parameter(Type::Constant(null, zone())));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
|
||||
}
|
||||
{
|
||||
Reduction r = Reduce(Parameter(Type::Null()));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, ParameterWithNaN) {
|
||||
const double kNaNs[] = {base::OS::nan_value(),
|
||||
std::numeric_limits<double>::quiet_NaN(),
|
||||
std::numeric_limits<double>::signaling_NaN()};
|
||||
TRACED_FOREACH(double, nan, kNaNs) {
|
||||
Handle<Object> constant = factory()->NewNumber(nan);
|
||||
Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
|
||||
}
|
||||
{
|
||||
Reduction r =
|
||||
Reduce(Parameter(Type::Constant(factory()->nan_value(), zone())));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
|
||||
}
|
||||
{
|
||||
Reduction r = Reduce(Parameter(Type::NaN()));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) {
|
||||
TRACED_FOREACH(double, value, kFloat64Values) {
|
||||
Handle<Object> constant = factory()->NewNumber(value);
|
||||
Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberConstant(value));
|
||||
}
|
||||
TRACED_FOREACH(double, value, kIntegerValues) {
|
||||
Handle<Object> constant = factory()->NewNumber(value);
|
||||
Reduction r = Reduce(Parameter(Type::Range(constant, constant, zone())));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberConstant(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, ParameterWithUndefined) {
|
||||
Handle<HeapObject> undefined = factory()->undefined_value();
|
||||
{
|
||||
Reduction r = Reduce(Parameter(Type::Undefined()));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
|
||||
}
|
||||
{
|
||||
Reduction r = Reduce(Parameter(Type::Constant(undefined, zone())));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// JSToBoolean
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
|
||||
Node* input = Parameter(Type::Boolean());
|
||||
Node* context = UndefinedConstant();
|
||||
|
||||
Node* input = Parameter(Type::Boolean(), 0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
@@ -83,10 +292,29 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithUndefined) {
|
||||
Node* input = Parameter(Type::Undefined());
|
||||
Node* context = UndefinedConstant();
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
|
||||
Handle<Object> zero = factory()->NewNumber(0);
|
||||
Node* input = Parameter(
|
||||
Type::Union(
|
||||
Type::MinusZero(),
|
||||
Type::Union(
|
||||
Type::NaN(),
|
||||
Type::Union(
|
||||
Type::Null(),
|
||||
Type::Union(
|
||||
Type::Undefined(),
|
||||
Type::Union(
|
||||
Type::Undetectable(),
|
||||
Type::Union(
|
||||
Type::Constant(factory()->false_value(), zone()),
|
||||
Type::Range(zero, zero, zone()), zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
@@ -94,21 +322,14 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithUndefined) {
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithNull) {
|
||||
Node* input = Parameter(Type::Null());
|
||||
Node* context = UndefinedConstant();
|
||||
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFalseConstant());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithDetectableReceiver) {
|
||||
Node* input = Parameter(Type::DetectableReceiver());
|
||||
Node* context = UndefinedConstant();
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
|
||||
Node* input = Parameter(
|
||||
Type::Union(
|
||||
Type::Constant(factory()->true_value(), zone()),
|
||||
Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
|
||||
zone()),
|
||||
0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
@@ -116,77 +337,26 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithDetectableReceiver) {
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithUndetectable) {
|
||||
Node* input = Parameter(Type::Undetectable());
|
||||
Node* context = UndefinedConstant();
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
|
||||
Node* input =
|
||||
Parameter(Type::Range(factory()->NewNumber(1),
|
||||
factory()->NewNumber(V8_INFINITY), zone()),
|
||||
0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFalseConstant());
|
||||
EXPECT_THAT(r.replacement(), IsTrueConstant());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) {
|
||||
Node* input = Parameter(Type::OrderedNumber());
|
||||
Node* context = UndefinedConstant();
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
|
||||
Node* input = Parameter(Type::Any(), 0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0))));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithString) {
|
||||
Node* input = Parameter(Type::String());
|
||||
Node* context = UndefinedConstant();
|
||||
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsBooleanNot(IsNumberEqual(
|
||||
IsLoadField(AccessBuilder::ForStringLength(), input,
|
||||
graph()->start(), graph()->start()),
|
||||
IsNumberConstant(0))));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithPhi) {
|
||||
Node* p0 = Parameter(Type::OrderedNumber(), 0);
|
||||
Node* p1 = Parameter(Type::Boolean(), 1);
|
||||
Node* context = UndefinedConstant();
|
||||
Node* control = graph()->start();
|
||||
|
||||
Reduction r = Reduce(graph()->NewNode(
|
||||
javascript()->ToBoolean(),
|
||||
graph()->NewNode(common()->Phi(kMachAnyTagged, 2), p0, p1, control),
|
||||
context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(
|
||||
r.replacement(),
|
||||
IsPhi(kMachAnyTagged,
|
||||
IsBooleanNot(IsNumberEqual(p0, IsNumberConstant(0))), p1, control));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithSelect) {
|
||||
Node* p0 = Parameter(Type::Boolean(), 0);
|
||||
Node* p1 = Parameter(Type::DetectableReceiver(), 1);
|
||||
Node* p2 = Parameter(Type::OrderedNumber(), 2);
|
||||
Node* context = UndefinedConstant();
|
||||
|
||||
Reduction r = Reduce(graph()->NewNode(
|
||||
javascript()->ToBoolean(),
|
||||
graph()->NewNode(common()->Select(kMachAnyTagged, BranchHint::kTrue), p0,
|
||||
p1, p2),
|
||||
context));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsSelect(kMachAnyTagged, p0, IsTrueConstant(),
|
||||
IsBooleanNot(IsNumberEqual(p2, IsNumberConstant(0)))));
|
||||
EXPECT_THAT(r.replacement(), IsAnyToBoolean(input));
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +372,7 @@ TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) {
|
||||
Reduction r = Reduce(graph()->NewNode(javascript()->ToNumber(), input,
|
||||
context, effect, control));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(0),
|
||||
EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
|
||||
graph()->start(), control));
|
||||
}
|
||||
|
||||
@@ -235,12 +405,13 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
|
||||
Node* const context = UndefinedConstant();
|
||||
Node* const effect = graph()->start();
|
||||
Node* const control = graph()->start();
|
||||
TRACED_FORRANGE(int32_t, rhs, 0, 31) {
|
||||
TRACED_FORRANGE(double, rhs, 0, 31) {
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs,
|
||||
NumberConstant(rhs), context, effect, control));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsWord32Shl(lhs, IsNumberConstant(rhs)));
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsWord32Shl(lhs, IsNumberConstant(BitEq(rhs))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,12 +439,13 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
|
||||
Node* const context = UndefinedConstant();
|
||||
Node* const effect = graph()->start();
|
||||
Node* const control = graph()->start();
|
||||
TRACED_FORRANGE(int32_t, rhs, 0, 31) {
|
||||
TRACED_FORRANGE(double, rhs, 0, 31) {
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs,
|
||||
NumberConstant(rhs), context, effect, control));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsWord32Sar(lhs, IsNumberConstant(rhs)));
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsWord32Sar(lhs, IsNumberConstant(BitEq(rhs))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,12 +473,13 @@ TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndConstant) {
|
||||
Node* const context = UndefinedConstant();
|
||||
Node* const effect = graph()->start();
|
||||
Node* const control = graph()->start();
|
||||
TRACED_FORRANGE(int32_t, rhs, 0, 31) {
|
||||
TRACED_FORRANGE(double, rhs, 0, 31) {
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs,
|
||||
NumberConstant(rhs), context, effect, control));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsWord32Shr(lhs, IsNumberConstant(rhs)));
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsWord32Shr(lhs, IsNumberConstant(BitEq(rhs))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "testing/gmock-support.h"
|
||||
|
||||
using testing::AllOf;
|
||||
using testing::BitEq;
|
||||
using testing::Capture;
|
||||
using testing::CaptureEq;
|
||||
|
||||
@@ -291,7 +292,7 @@ TEST_F(MachineOperatorReducerTest, ChangeFloat64ToFloat32WithConstant) {
|
||||
Reduction reduction = Reduce(graph()->NewNode(
|
||||
machine()->ChangeFloat32ToFloat64(), Float32Constant(x)));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(x));
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq<double>(x)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +356,7 @@ TEST_F(MachineOperatorReducerTest, ChangeInt32ToFloat64WithConstant) {
|
||||
Reduction reduction = Reduce(
|
||||
graph()->NewNode(machine()->ChangeInt32ToFloat64(), Int32Constant(x)));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(FastI2D(x)));
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(FastI2D(x))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +385,7 @@ TEST_F(MachineOperatorReducerTest, ChangeUint32ToFloat64WithConstant) {
|
||||
Reduce(graph()->NewNode(machine()->ChangeUint32ToFloat64(),
|
||||
Int32Constant(bit_cast<int32_t>(x))));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(FastUI2D(x)));
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(FastUI2D(x))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,7 +426,8 @@ TEST_F(MachineOperatorReducerTest, TruncateFloat64ToFloat32WithConstant) {
|
||||
Reduction reduction = Reduce(graph()->NewNode(
|
||||
machine()->TruncateFloat64ToFloat32(), Float64Constant(x)));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat32Constant(DoubleToFloat32(x)));
|
||||
EXPECT_THAT(reduction.replacement(),
|
||||
IsFloat32Constant(BitEq(DoubleToFloat32(x))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1268,13 +1270,15 @@ TEST_F(MachineOperatorReducerTest, Float64MulWithMinusOne) {
|
||||
Reduction r = Reduce(
|
||||
graph()->NewNode(machine()->Float64Mul(), p0, Float64Constant(-1.0)));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFloat64Sub(IsFloat64Constant(-0.0), p0));
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsFloat64Sub(IsFloat64Constant(BitEq(-0.0)), p0));
|
||||
}
|
||||
{
|
||||
Reduction r = Reduce(
|
||||
graph()->NewNode(machine()->Float64Mul(), Float64Constant(-1.0), p0));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsFloat64Sub(IsFloat64Constant(-0.0), p0));
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsFloat64Sub(IsFloat64Constant(BitEq(-0.0)), p0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1290,6 +1290,7 @@ IS_BINOP_MATCHER(Float64Sub)
|
||||
Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) { \
|
||||
return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
|
||||
}
|
||||
IS_UNOP_MATCHER(AnyToBoolean)
|
||||
IS_UNOP_MATCHER(BooleanNot)
|
||||
IS_UNOP_MATCHER(ChangeFloat64ToInt32)
|
||||
IS_UNOP_MATCHER(ChangeFloat64ToUint32)
|
||||
|
||||
@@ -75,6 +75,7 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
|
||||
const Matcher<Node*>& effect_matcher,
|
||||
const Matcher<Node*>& control_matcher);
|
||||
|
||||
Matcher<Node*> IsAnyToBoolean(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
|
||||
@@ -2,22 +2,28 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/access-builder.h"
|
||||
#include "src/compiler/js-graph.h"
|
||||
#include "src/compiler/node-properties-inl.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
#include "src/compiler/simplified-operator-reducer.h"
|
||||
#include "src/conversions.h"
|
||||
#include "src/types.h"
|
||||
#include "test/unittests/compiler/graph-unittest.h"
|
||||
#include "test/unittests/compiler/node-test-utils.h"
|
||||
#include "testing/gmock-support.h"
|
||||
|
||||
using testing::BitEq;
|
||||
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class SimplifiedOperatorReducerTest : public GraphTest {
|
||||
class SimplifiedOperatorReducerTest : public TypedGraphTest {
|
||||
public:
|
||||
explicit SimplifiedOperatorReducerTest(int num_parameters = 1)
|
||||
: GraphTest(num_parameters), simplified_(zone()) {}
|
||||
: TypedGraphTest(num_parameters), simplified_(zone()) {}
|
||||
~SimplifiedOperatorReducerTest() OVERRIDE {}
|
||||
|
||||
protected:
|
||||
@@ -114,11 +120,6 @@ static const uint32_t kUint32Values[] = {
|
||||
0xbeb15c0d, 0xc171c53d, 0xc743dd38, 0xc8e2af50, 0xc98e2df0, 0xd9d1cdf9,
|
||||
0xdcc91049, 0xe46f396d, 0xee991950, 0xef64e521, 0xf7aeefc9, 0xffffffff};
|
||||
|
||||
|
||||
MATCHER(IsNaN, std::string(negation ? "isn't" : "is") + " NaN") {
|
||||
return std::isnan(arg);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -140,6 +141,7 @@ std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) {
|
||||
|
||||
|
||||
static const UnaryOperator kUnaryOperators[] = {
|
||||
{&SimplifiedOperatorBuilder::AnyToBoolean, "AnyToBoolean"},
|
||||
{&SimplifiedOperatorBuilder::BooleanNot, "BooleanNot"},
|
||||
{&SimplifiedOperatorBuilder::ChangeBitToBool, "ChangeBitToBool"},
|
||||
{&SimplifiedOperatorBuilder::ChangeBoolToBit, "ChangeBoolToBit"},
|
||||
@@ -161,8 +163,8 @@ typedef SimplifiedOperatorReducerTestWithParam<UnaryOperator>
|
||||
|
||||
TEST_P(SimplifiedUnaryOperatorTest, Parameter) {
|
||||
const UnaryOperator& unop = GetParam();
|
||||
Reduction reduction = Reduce(
|
||||
graph()->NewNode((simplified()->*unop.constructor)(), Parameter(0)));
|
||||
Reduction reduction = Reduce(graph()->NewNode(
|
||||
(simplified()->*unop.constructor)(), Parameter(Type::Any())));
|
||||
EXPECT_FALSE(reduction.Changed());
|
||||
}
|
||||
|
||||
@@ -172,6 +174,39 @@ INSTANTIATE_TEST_CASE_P(SimplifiedOperatorReducerTest,
|
||||
::testing::ValuesIn(kUnaryOperators));
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// AnyToBoolean
|
||||
|
||||
|
||||
TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithBoolean) {
|
||||
Node* p = Parameter(Type::Boolean());
|
||||
Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_EQ(p, r.replacement());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithOrderedNumber) {
|
||||
Node* p = Parameter(Type::OrderedNumber());
|
||||
Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsBooleanNot(IsNumberEqual(p, IsNumberConstant(0))));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithString) {
|
||||
Node* p = Parameter(Type::String());
|
||||
Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsBooleanNot(
|
||||
IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), p,
|
||||
graph()->start(), graph()->start()),
|
||||
IsNumberConstant(0))));
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// BooleanNot
|
||||
|
||||
@@ -271,7 +306,7 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeFloat64ToTaggedWithConstant) {
|
||||
Reduction reduction = Reduce(graph()->NewNode(
|
||||
simplified()->ChangeFloat64ToTagged(), Float64Constant(n)));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsNumberConstant(n));
|
||||
EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(n)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +320,7 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeInt32ToTaggedWithConstant) {
|
||||
Reduction reduction = Reduce(graph()->NewNode(
|
||||
simplified()->ChangeInt32ToTagged(), Int32Constant(n)));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsNumberConstant(FastI2D(n)));
|
||||
EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(FastI2D(n))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,7 +367,7 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithConstant) {
|
||||
Reduction reduction = Reduce(graph()->NewNode(
|
||||
simplified()->ChangeTaggedToFloat64(), NumberConstant(n)));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(n));
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(n)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +377,8 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant1) {
|
||||
Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
|
||||
NumberConstant(-base::OS::nan_value())));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(IsNaN()));
|
||||
EXPECT_THAT(reduction.replacement(),
|
||||
IsFloat64Constant(BitEq(-base::OS::nan_value())));
|
||||
}
|
||||
|
||||
|
||||
@@ -351,7 +387,8 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant2) {
|
||||
Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
|
||||
NumberConstant(base::OS::nan_value())));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsFloat64Constant(IsNaN()));
|
||||
EXPECT_THAT(reduction.replacement(),
|
||||
IsFloat64Constant(BitEq(base::OS::nan_value())));
|
||||
}
|
||||
|
||||
|
||||
@@ -474,7 +511,7 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeUint32ToTagged) {
|
||||
Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(),
|
||||
Int32Constant(bit_cast<int32_t>(n))));
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
EXPECT_THAT(reduction.replacement(), IsNumberConstant(FastUI2D(n)));
|
||||
EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(FastUI2D(n))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ const PureOperator kPureOperators[] = {
|
||||
&SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \
|
||||
Operator::kPure | properties, input_count \
|
||||
}
|
||||
PURE(AnyToBoolean, Operator::kNoProperties, 1),
|
||||
PURE(BooleanNot, Operator::kNoProperties, 1),
|
||||
PURE(BooleanToNumber, Operator::kNoProperties, 1),
|
||||
PURE(NumberEqual, Operator::kCommutative, 2),
|
||||
|
||||
@@ -47,7 +47,7 @@ PASS getSortedOwnPropertyNames(encodeURIComponent) is ['arguments', 'caller', 'l
|
||||
PASS getSortedOwnPropertyNames(Object) is ['arguments', 'caller', 'create', 'defineProperties', 'defineProperty', 'deliverChangeRecords', 'freeze', 'getNotifier', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getOwnPropertySymbols', 'getPrototypeOf', 'is', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'observe', 'preventExtensions', 'prototype', 'seal', 'setPrototypeOf', 'unobserve']
|
||||
PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']
|
||||
PASS getSortedOwnPropertyNames(Function) is ['arguments', 'caller', 'length', 'name', 'prototype']
|
||||
PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toMethod', 'toString']
|
||||
PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toString']
|
||||
PASS getSortedOwnPropertyNames(Array) is ['arguments', 'caller', 'isArray', 'length', 'name', 'observe', 'prototype', 'unobserve']
|
||||
PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'entries', 'every', 'filter', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
|
||||
PASS getSortedOwnPropertyNames(String) is ['arguments', 'caller', 'fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw']
|
||||
|
||||
@@ -74,7 +74,7 @@ var expectedPropertyNamesSet = {
|
||||
"Object": "['arguments', 'caller', 'create', 'defineProperties', 'defineProperty', 'deliverChangeRecords', 'freeze', 'getNotifier', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getOwnPropertySymbols', 'getPrototypeOf', 'is', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'observe', 'preventExtensions', 'prototype', 'seal', 'setPrototypeOf', 'unobserve']",
|
||||
"Object.prototype": "['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']",
|
||||
"Function": "['arguments', 'caller', 'length', 'name', 'prototype']",
|
||||
"Function.prototype": "['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toMethod', 'toString']",
|
||||
"Function.prototype": "['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toString']",
|
||||
"Array": "['arguments', 'caller', 'isArray', 'length', 'name', 'observe', 'prototype', 'unobserve']",
|
||||
"Array.prototype": "['concat', 'constructor', 'entries', 'every', 'filter', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']",
|
||||
"String": "['arguments', 'caller', 'fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw']",
|
||||
|
||||
Vendored
+37
-1
@@ -5,6 +5,9 @@
|
||||
#ifndef V8_TESTING_GMOCK_SUPPORT_H_
|
||||
#define V8_TESTING_GMOCK_SUPPORT_H_
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
|
||||
namespace testing {
|
||||
@@ -31,6 +34,25 @@ class Capture {
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct AnyBitEq {
|
||||
template <typename A, typename B>
|
||||
bool operator()(A const& a, B const& b) const {
|
||||
if (sizeof(A) != sizeof(B)) return false;
|
||||
return std::memcmp(&a, &b, sizeof(A)) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Rhs>
|
||||
class BitEqMatcher : public ComparisonBase<BitEqMatcher<Rhs>, Rhs, AnyBitEq> {
|
||||
public:
|
||||
explicit BitEqMatcher(Rhs const& rhs)
|
||||
: ComparisonBase<BitEqMatcher<Rhs>, Rhs, AnyBitEq>(rhs) {}
|
||||
static const char* Desc() { return "is bitwise equal to"; }
|
||||
static const char* NegatedDesc() { return "isn't bitwise equal to"; }
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CaptureEqMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
@@ -60,13 +82,27 @@ class CaptureEqMatcher : public MatcherInterface<T> {
|
||||
} // namespace internal
|
||||
|
||||
|
||||
// Creates a polymorphic matcher that matches anything whose bit representation
|
||||
// is equal to that of x.
|
||||
template <typename T>
|
||||
inline internal::BitEqMatcher<T> BitEq(T const& x) {
|
||||
return internal::BitEqMatcher<T>(x);
|
||||
}
|
||||
|
||||
|
||||
// CaptureEq(capture) captures the value passed in during matching as long as it
|
||||
// is unset, and once set, compares the value for equality with the argument.
|
||||
template <typename T>
|
||||
Matcher<T> CaptureEq(Capture<T>* capture) {
|
||||
inline Matcher<T> CaptureEq(Capture<T>* capture) {
|
||||
return MakeMatcher(new internal::CaptureEqMatcher<T>(capture));
|
||||
}
|
||||
|
||||
|
||||
// Creates a polymorphic matcher that matches any floating point NaN value.
|
||||
MATCHER(IsNaN, std::string(negation ? "isn't" : "is") + " not a number") {
|
||||
return std::isnan(arg);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // V8_TESTING_GMOCK_SUPPORT_H_
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Script to set v8's version file to the version given by the latest tag.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
CWD = os.path.abspath(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||
VERSION_CC = os.path.join(CWD, "src", "version.cc")
|
||||
|
||||
def main():
|
||||
tag = subprocess.check_output(
|
||||
"git describe --tags",
|
||||
shell=True,
|
||||
cwd=CWD,
|
||||
).strip()
|
||||
assert tag
|
||||
|
||||
# Check for commits not exactly matching a tag. Those are candidate builds
|
||||
# for the next version. The output has the form
|
||||
# <tag name>-<n commits>-<hash>.
|
||||
if "-" in tag:
|
||||
version = tag.split("-")[0]
|
||||
candidate = "1"
|
||||
else:
|
||||
version = tag
|
||||
candidate = "0"
|
||||
version_levels = version.split(".")
|
||||
|
||||
# Set default patch level if none is given.
|
||||
if len(version_levels) == 3:
|
||||
version_levels.append("0")
|
||||
assert len(version_levels) == 4
|
||||
|
||||
major, minor, build, patch = version_levels
|
||||
|
||||
# Increment build level for candidate builds.
|
||||
if candidate == "1":
|
||||
build = str(int(build) + 1)
|
||||
patch = "0"
|
||||
|
||||
# Modify version.cc with the new values.
|
||||
with open(VERSION_CC, "r") as f:
|
||||
text = f.read()
|
||||
output = []
|
||||
for line in text.split("\n"):
|
||||
for definition, substitute in (
|
||||
("MAJOR_VERSION", major),
|
||||
("MINOR_VERSION", minor),
|
||||
("BUILD_NUMBER", build),
|
||||
("PATCH_LEVEL", patch),
|
||||
("IS_CANDIDATE_VERSION", candidate)):
|
||||
if line.startswith("#define %s" % definition):
|
||||
line = re.sub("\d+$", substitute, line)
|
||||
output.append(line)
|
||||
with open(VERSION_CC, "w") as f:
|
||||
f.write("\n".join(output))
|
||||
|
||||
# Log what was done.
|
||||
candidate_txt = " (candidate)" if candidate == "1" else ""
|
||||
patch_txt = ".%s" % patch if patch != "0" else ""
|
||||
version_txt = ("%s.%s.%s%s%s" %
|
||||
(major, minor, build, patch_txt, candidate_txt))
|
||||
print "Modified version.cc. Set V8 version to %s" % version_txt
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Vendored
+17
-2
@@ -529,10 +529,17 @@ class AndroidPlatform(Platform): # pragma: no cover
|
||||
perf.SetDefaultPerfMode()
|
||||
self.device.RunShellCommand(["rm", "-rf", AndroidPlatform.DEVICE_DIR])
|
||||
|
||||
def _SendCommand(self, cmd):
|
||||
logging.info("adb -s %s %s" % (str(self.device), cmd))
|
||||
return self.adb.SendCommand(cmd, timeout_time=60)
|
||||
|
||||
def _PushFile(self, host_dir, file_name, target_rel="."):
|
||||
file_on_host = os.path.join(host_dir, file_name)
|
||||
file_on_device_tmp = os.path.join(
|
||||
AndroidPlatform.DEVICE_DIR, "_tmp_", file_name)
|
||||
file_on_device = os.path.join(
|
||||
AndroidPlatform.DEVICE_DIR, target_rel, file_name)
|
||||
folder_on_device = os.path.dirname(file_on_device)
|
||||
|
||||
# Only push files not yet pushed in one execution.
|
||||
if file_on_host in self.pushed:
|
||||
@@ -540,8 +547,16 @@ class AndroidPlatform(Platform): # pragma: no cover
|
||||
else:
|
||||
self.pushed.add(file_on_host)
|
||||
|
||||
logging.info("adb push %s %s" % (file_on_host, file_on_device))
|
||||
self.adb.Push(file_on_host, file_on_device)
|
||||
# Work-around for "text file busy" errors. Push the files to a temporary
|
||||
# location and then copy them with a shell command.
|
||||
output = self._SendCommand(
|
||||
"push %s %s" % (file_on_host, file_on_device_tmp))
|
||||
# Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)".
|
||||
# Errors look like this: "failed to copy ... ".
|
||||
if output and not re.search('^[0-9]', output.splitlines()[-1]):
|
||||
logging.critical('PUSH FAILED: ' + output)
|
||||
self._SendCommand("shell mkdir -p %s" % folder_on_device)
|
||||
self._SendCommand("shell cp %s %s" % (file_on_device_tmp, file_on_device))
|
||||
|
||||
def PreTests(self, node, path):
|
||||
suite_dir = os.path.abspath(os.path.dirname(path))
|
||||
|
||||
Vendored
+1
-1
@@ -5,4 +5,4 @@ Try to write something funny. And please don't add trailing whitespace.
|
||||
A Smi walks into a bar and says:
|
||||
"I'm so deoptimized today!"
|
||||
The doubles heard this and started to unbox.
|
||||
The Smi looked at them when a crazy v8-autoroll account showed up........
|
||||
The Smi looked at them when a crazy v8-autoroll account showed up...........
|
||||
Reference in new issue
Block a user