Revision: 17292
Author: [email protected]
Date: Mon Oct 21 13:27:29 2013 UTC
Log: Version 3.22.17
Harmony: Implement Math.trunc and Math.sign. (issue 2938)
Performance and stability improvements on all platforms.
http://code.google.com/p/v8/source/detail?r=17292
Added:
/trunk/src/harmony-math.js
/trunk/test/mjsunit/harmony/math-sign.js
/trunk/test/mjsunit/harmony/math-trunc.js
Modified:
/trunk/ChangeLog
/trunk/src/arm/code-stubs-arm.cc
/trunk/src/bootstrapper.cc
/trunk/src/code-stubs-hydrogen.cc
/trunk/src/code-stubs.cc
/trunk/src/code-stubs.h
/trunk/src/flag-definitions.h
/trunk/src/hydrogen.cc
/trunk/src/hydrogen.h
/trunk/src/ia32/code-stubs-ia32.cc
/trunk/src/isolate.cc
/trunk/src/math.js
/trunk/src/version.cc
/trunk/src/x64/code-stubs-x64.cc
/trunk/tools/gyp/v8.gyp
=======================================
--- /dev/null
+++ /trunk/src/harmony-math.js Mon Oct 21 13:27:29 2013 UTC
@@ -0,0 +1,60 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+'use strict';
+
+// ES6 draft 09-27-13, section 20.2.2.28.
+function MathSign(x) {
+ x = TO_NUMBER_INLINE(x);
+ if (x > 0) return 1;
+ if (x < 0) return -1;
+ if (x === 0) return x;
+ return NAN;
+}
+
+
+// ES6 draft 09-27-13, section 20.2.2.34.
+function MathTrunc(x) {
+ x = TO_NUMBER_INLINE(x);
+ if (x > 0) return MathFloor(x);
+ if (x < 0) return MathCeil(x);
+ if (x === 0) return x;
+ return NAN;
+}
+
+
+function ExtendMath() {
+ %CheckIsBootstrapping();
+
+ // Set up the non-enumerable functions on the Math object.
+ InstallFunctions($Math, DONT_ENUM, $Array(
+ "sign", MathSign,
+ "trunc", MathTrunc
+ ));
+}
+
+ExtendMath();
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/harmony/math-sign.js Mon Oct 21 13:27:29 2013 UTC
@@ -0,0 +1,48 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-maths
+
+assertEquals("Infinity", String(1/Math.sign(0)));
+assertEquals("-Infinity", String(1/Math.sign(-0)));
+assertEquals(1, Math.sign(100));
+assertEquals(-1, Math.sign(-199));
+assertEquals(1, Math.sign(100.1));
+assertTrue(isNaN(Math.sign("abc")));
+assertTrue(isNaN(Math.sign({})));
+assertEquals(0, Math.sign([]));
+assertEquals(1, Math.sign([1]));
+assertEquals(-1, Math.sign([-100.1]));
+assertTrue(isNaN(Math.sign([1, 1])));
+assertEquals(1, Math.sign({ toString: function() { return "100"; } }));
+assertEquals(1, Math.sign({ toString: function() { return 100; } }));
+assertEquals(-1, Math.sign({ valueOf: function() { return -1.1; } }));
+assertEquals(-1, Math.sign({ valueOf: function() { return "-1.1"; } }));
+assertEquals(-1, Math.sign(-Infinity));
+assertEquals(1, Math.sign(Infinity));
+assertEquals(-1, Math.sign("-Infinity"));
+assertEquals(1, Math.sign("Infinity"));
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/harmony/math-trunc.js Mon Oct 21 13:27:29 2013 UTC
@@ -0,0 +1,51 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-maths
+
+assertEquals("Infinity", String(1/Math.trunc(0)));
+assertEquals("-Infinity", String(1/Math.trunc(-0)));
+assertEquals("Infinity", String(1/Math.trunc(Math.PI/4)));
+assertEquals("-Infinity", String(1/Math.trunc(-Math.sqrt(2)/2)));
+assertEquals(100, Math.trunc(100));
+assertEquals(-199, Math.trunc(-199));
+assertEquals(100, Math.trunc(100.1));
+assertTrue(isNaN(Math.trunc("abc")));
+assertTrue(isNaN(Math.trunc({})));
+assertEquals(0, Math.trunc([]));
+assertEquals(1, Math.trunc([1]));
+assertEquals(-100, Math.trunc([-100.1]));
+assertTrue(isNaN(Math.trunc([1, 1])));
+assertEquals(-100, Math.trunc({ toString: function() { return "-100.3"; }
}));
+assertEquals(10, Math.trunc({ toString: function() { return 10.1; } }));
+assertEquals(-1, Math.trunc({ valueOf: function() { return -1.1; } }));
+assertEquals("-Infinity",
+ String(1/Math.trunc({ valueOf: function() { return "-0.1"; }
})));
+assertEquals("-Infinity", String(Math.trunc(-Infinity)));
+assertEquals("Infinity", String(Math.trunc(Infinity)));
+assertEquals("-Infinity", String(Math.trunc("-Infinity")));
+assertEquals("Infinity", String(Math.trunc("Infinity")));
=======================================
--- /trunk/ChangeLog Mon Oct 21 07:19:36 2013 UTC
+++ /trunk/ChangeLog Mon Oct 21 13:27:29 2013 UTC
@@ -1,3 +1,10 @@
+2013-10-21: Version 3.22.17
+
+ Harmony: Implement Math.trunc and Math.sign. (issue 2938)
+
+ Performance and stability improvements on all platforms.
+
+
2013-10-21: Version 3.22.16
Performance and stability improvements on all platforms.
=======================================
--- /trunk/src/arm/code-stubs-arm.cc Mon Oct 21 07:19:36 2013 UTC
+++ /trunk/src/arm/code-stubs-arm.cc Mon Oct 21 13:27:29 2013 UTC
@@ -65,7 +65,8 @@
static Register registers[] = { r0 };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->deoptimization_handler_ = NULL;
+ descriptor->deoptimization_handler_ =
+ Runtime::FunctionForId(Runtime::kNumberToString)->entry;
}
=======================================
--- /trunk/src/bootstrapper.cc Tue Oct 15 08:25:05 2013 UTC
+++ /trunk/src/bootstrapper.cc Mon Oct 21 13:27:29 2013 UTC
@@ -2067,6 +2067,11 @@
"native harmony-array.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
+ if (FLAG_harmony_maths &&
+ strcmp(ExperimentalNatives::GetScriptName(i).start(),
+ "native harmony-math.js") == 0) {
+ if (!CompileExperimentalBuiltin(isolate(), i)) return false;
+ }
}
InstallExperimentalNativeFunctions();
=======================================
--- /trunk/src/code-stubs-hydrogen.cc Mon Oct 21 07:19:36 2013 UTC
+++ /trunk/src/code-stubs-hydrogen.cc Mon Oct 21 13:27:29 2013 UTC
@@ -351,7 +351,7 @@
HValue* CodeStubGraphBuilder<NumberToStringStub>::BuildCodeStub() {
info()->MarkAsSavesCallerDoubles();
HValue* number = GetParameter(NumberToStringStub::kNumber);
- return BuildNumberToString(number);
+ return BuildNumberToString(number, handle(Type::Number(), isolate()));
}
@@ -881,35 +881,52 @@
if (stub->operation() == Token::ADD &&
(left_type->Maybe(Type::String()) ||
right_type->Maybe(Type::String())) &&
!left_type->Is(Type::String()) && !right_type->Is(Type::String())) {
- // For the generic add stub a fast case for String add is performance
+ // For the generic add stub a fast case for string addition is
performance
// critical.
if (left_type->Maybe(Type::String())) {
- IfBuilder left_string(this);
- left_string.If<HIsStringAndBranch>(left);
- left_string.Then();
- Push(Add<HStringAdd>(left, right, STRING_ADD_CHECK_RIGHT));
- left_string.Else();
- Push(AddInstruction(BuildBinaryOperation(stub->operation(),
- left, right, left_type, right_type, result_type,
- stub->fixed_right_arg(), true)));
- left_string.End();
+ IfBuilder if_leftisstring(this);
+ if_leftisstring.If<HIsStringAndBranch>(left);
+ if_leftisstring.Then();
+ {
+ Push(AddInstruction(BuildBinaryOperation(
+ stub->operation(), left, right,
+ handle(Type::String(), isolate()), right_type,
+ result_type, stub->fixed_right_arg(), true)));
+ }
+ if_leftisstring.Else();
+ {
+ Push(AddInstruction(BuildBinaryOperation(
+ stub->operation(), left, right,
+ left_type, right_type, result_type,
+ stub->fixed_right_arg(), true)));
+ }
+ if_leftisstring.End();
result = Pop();
} else {
- IfBuilder right_string(this);
- right_string.If<HIsStringAndBranch>(right);
- right_string.Then();
- Push(Add<HStringAdd>(left, right, STRING_ADD_CHECK_LEFT));
- right_string.Else();
- Push(AddInstruction(BuildBinaryOperation(stub->operation(),
- left, right, left_type, right_type, result_type,
- stub->fixed_right_arg(), true)));
- right_string.End();
+ IfBuilder if_rightisstring(this);
+ if_rightisstring.If<HIsStringAndBranch>(right);
+ if_rightisstring.Then();
+ {
+ Push(AddInstruction(BuildBinaryOperation(
+ stub->operation(), left, right,
+ left_type, handle(Type::String(), isolate()),
+ result_type, stub->fixed_right_arg(), true)));
+ }
+ if_rightisstring.Else();
+ {
+ Push(AddInstruction(BuildBinaryOperation(
+ stub->operation(), left, right,
+ left_type, right_type, result_type,
+ stub->fixed_right_arg(), true)));
+ }
+ if_rightisstring.End();
result = Pop();
}
} else {
- result = AddInstruction(BuildBinaryOperation(stub->operation(),
- left, right, left_type, right_type, result_type,
- stub->fixed_right_arg(), true));
+ result = AddInstruction(BuildBinaryOperation(
+ stub->operation(), left, right,
+ left_type, right_type, result_type,
+ stub->fixed_right_arg(), true));
}
// If we encounter a generic argument, the number conversion is
=======================================
--- /trunk/src/code-stubs.cc Mon Oct 21 07:19:36 2013 UTC
+++ /trunk/src/code-stubs.cc Mon Oct 21 13:27:29 2013 UTC
@@ -570,14 +570,8 @@
State max_input = Max(left_state_, right_state_);
- // TODO(olivf) Instead of doing this normalization we should have a
Hydrogen
- // version of the LookupNumberStringCache to avoid a converting
StringAddStub.
- if (left_state_ == STRING && right_state_ < STRING) {
- right_state_ = GENERIC;
- } else if (right_state_ == STRING && left_state_ < STRING) {
- left_state_ = GENERIC;
- } else if (!has_int_result() && op_ != Token::SHR &&
- max_input <= NUMBER && max_input > result_state_) {
+ if (!has_int_result() && op_ != Token::SHR &&
+ max_input <= NUMBER && max_input > result_state_) {
result_state_ = max_input;
}
@@ -1125,6 +1119,12 @@
ArrayNArgumentsConstructorStub stub3(GetInitialFastElementsKind());
InstallDescriptor(isolate, &stub3);
}
+
+
+void NumberToStringStub::InstallDescriptors(Isolate* isolate) {
+ NumberToStringStub stub;
+ InstallDescriptor(isolate, &stub);
+}
void FastNewClosureStub::InstallDescriptors(Isolate* isolate) {
=======================================
--- /trunk/src/code-stubs.h Mon Oct 21 07:19:36 2013 UTC
+++ /trunk/src/code-stubs.h Mon Oct 21 13:27:29 2013 UTC
@@ -477,6 +477,8 @@
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE;
+ static void InstallDescriptors(Isolate* isolate);
+
// Parameters accessed via CodeStubGraphBuilder::GetParameter()
static const int kNumber = 0;
=======================================
--- /trunk/src/flag-definitions.h Mon Oct 21 07:19:36 2013 UTC
+++ /trunk/src/flag-definitions.h Mon Oct 21 13:27:29 2013 UTC
@@ -182,6 +182,7 @@
"enable harmony numeric literals (0o77, 0b11)")
DEFINE_bool(harmony_strings, false, "enable harmony string")
DEFINE_bool(harmony_arrays, false, "enable harmony arrays")
+DEFINE_bool(harmony_maths, false, "enable harmony math functions")
DEFINE_bool(harmony, false, "enable all harmony features (except typeof)")
DEFINE_implication(harmony, harmony_scoping)
DEFINE_implication(harmony, harmony_modules)
@@ -194,6 +195,7 @@
DEFINE_implication(harmony, harmony_numeric_literals)
DEFINE_implication(harmony, harmony_strings)
DEFINE_implication(harmony, harmony_arrays)
+DEFINE_implication(harmony, harmony_maths)
DEFINE_implication(harmony_modules, harmony_scoping)
DEFINE_implication(harmony_observation, harmony_collections)
=======================================
--- /trunk/src/hydrogen.cc Wed Oct 16 09:00:56 2013 UTC
+++ /trunk/src/hydrogen.cc Mon Oct 21 13:27:29 2013 UTC
@@ -1283,9 +1283,10 @@
}
-HValue* HGraphBuilder::BuildLookupNumberStringCache(
- HValue* object,
- HIfContinuation* continuation) {
+HValue* HGraphBuilder::BuildNumberToString(HValue* object,
+ Handle<Type> type) {
+ NoObservableSideEffectsScope scope(this);
+
// Create a joinable continuation.
HIfContinuation found(graph()->CreateBasicBlock(),
graph()->CreateBasicBlock());
@@ -1294,7 +1295,7 @@
HValue* number_string_cache =
Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
- // Make the hash maks from the length of the number string cache. It
+ // Make the hash mask from the length of the number string cache. It
// contains two elements (number and string) for each cache entry.
HValue* mask = AddLoadFixedArrayLength(number_string_cache);
mask->set_type(HType::Smi());
@@ -1317,7 +1318,7 @@
// Check if object == key.
IfBuilder if_objectiskey(this);
- if_objectiskey.If<HCompareObjectEqAndBranch>(key, object);
+ if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
if_objectiskey.Then();
{
// Make the key_index available.
@@ -1327,92 +1328,84 @@
}
if_objectissmi.Else();
{
- // Check if object is a heap number.
- IfBuilder if_objectisnumber(this);
- if_objectisnumber.If<HCompareMap>(
- object, isolate()->factory()->heap_number_map());
- if_objectisnumber.Then();
- {
- // Compute hash for heap number similar to double_get_hash().
- HValue* low = Add<HLoadNamedField>(
- object, HObjectAccess::ForHeapNumberValueLowestBits());
- HValue* high = Add<HLoadNamedField>(
- object, HObjectAccess::ForHeapNumberValueHighestBits());
- HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high);
- hash = Add<HBitwise>(Token::BIT_AND, hash, mask);
+ if (type->Is(Type::Smi())) {
+ if_objectissmi.Deopt("Excepted smi");
+ } else {
+ // Check if the object is a heap number.
+ IfBuilder if_objectisnumber(this);
+ if_objectisnumber.If<HCompareMap>(
+ object, isolate()->factory()->heap_number_map());
+ if_objectisnumber.Then();
+ {
+ // Compute hash for heap number similar to double_get_hash().
+ HValue* low = Add<HLoadNamedField>(
+ object, HObjectAccess::ForHeapNumberValueLowestBits());
+ HValue* high = Add<HLoadNamedField>(
+ object, HObjectAccess::ForHeapNumberValueHighestBits());
+ HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high);
+ hash = Add<HBitwise>(Token::BIT_AND, hash, mask);
- // Load the key.
- HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
- HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
- static_cast<HValue*>(NULL),
- FAST_ELEMENTS, ALLOW_RETURN_HOLE);
+ // Load the key.
+ HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
+ HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS, ALLOW_RETURN_HOLE);
- // Check if key is a heap number.
- IfBuilder if_keyisnumber(this);
- if_keyisnumber.IfNot<HIsSmiAndBranch>(key);
- if_keyisnumber.AndIf<HCompareMap>(
- key, isolate()->factory()->heap_number_map());
- if_keyisnumber.Then();
- {
- // Check if values of key and object match.
- IfBuilder if_keyeqobject(this);
- if_keyeqobject.If<HCompareNumericAndBranch>(
- Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()),
- Add<HLoadNamedField>(object,
HObjectAccess::ForHeapNumberValue()),
- Token::EQ);
- if_keyeqobject.Then();
+ // Check if key is a heap number (the number string cache contains
only
+ // SMIs and heap number, so it is sufficient to do a SMI check
here).
+ IfBuilder if_keyisnotsmi(this);
+ if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
+ if_keyisnotsmi.Then();
{
- // Make the key_index available.
- Push(key_index);
+ // Check if values of key and object match.
+ IfBuilder if_keyeqobject(this);
+ if_keyeqobject.If<HCompareNumericAndBranch>(
+ Add<HLoadNamedField>(key,
HObjectAccess::ForHeapNumberValue()),
+ Add<HLoadNamedField>(object,
HObjectAccess::ForHeapNumberValue()),
+ Token::EQ);
+ if_keyeqobject.Then();
+ {
+ // Make the key_index available.
+ Push(key_index);
+ }
+ if_keyeqobject.JoinContinuation(&found);
}
- if_keyeqobject.JoinContinuation(&found);
+ if_keyisnotsmi.JoinContinuation(&found);
}
- if_keyisnumber.JoinContinuation(&found);
+ if_objectisnumber.Else();
+ {
+ if (type->Is(Type::Number())) {
+ if_objectisnumber.Deopt("Expected heap number");
+ }
+ }
+ if_objectisnumber.JoinContinuation(&found);
}
- if_objectisnumber.JoinContinuation(&found);
}
- if_objectissmi.End();
+ if_objectissmi.JoinContinuation(&found);
// Check for cache hit.
IfBuilder if_found(this, &found);
if_found.Then();
+ {
+ // Count number to string operation in native code.
+ AddIncrementCounter(isolate()->counters()->number_to_string_native());
- // Load the value in case of cache hit.
- HValue* key_index = Pop();
- HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1());
- HValue* value = Add<HLoadKeyed>(number_string_cache, value_index,
- static_cast<HValue*>(NULL),
- FAST_ELEMENTS, ALLOW_RETURN_HOLE);
- AddIncrementCounter(isolate()->counters()->number_to_string_native());
-
- if_found.CaptureContinuation(continuation);
-
- // The value is only available in true branch of continuation.
- return value;
-}
-
-
-HValue* HGraphBuilder::BuildNumberToString(HValue* number) {
- NoObservableSideEffectsScope scope(this);
-
- // Lookup the number in the number string cache.
- HIfContinuation continuation;
- HValue* value = BuildLookupNumberStringCache(number, &continuation);
- IfBuilder if_found(this, &continuation);
- if_found.Then();
-
- // Cache hit.
- Push(value);
-
+ // Load the value in case of cache hit.
+ HValue* key_index = Pop();
+ HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1());
+ Push(Add<HLoadKeyed>(number_string_cache, value_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS, ALLOW_RETURN_HOLE));
+ }
if_found.Else();
-
- // Cache miss, fallback to runtime.
- Add<HPushArgument>(number);
- Push(Add<HCallRuntime>(
- isolate()->factory()->empty_string(),
- Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
- 1));
-
+ {
+ // Cache miss, fallback to runtime.
+ Add<HPushArgument>(object);
+ Push(Add<HCallRuntime>(
+ isolate()->factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
+ 1));
+ }
if_found.End();
return Pop();
@@ -7849,6 +7842,42 @@
if (!maybe_string_add) right = TruncateToNumber(right, &right_type);
right_rep = Representation::FromType(right_type);
}
+
+ // Special case for string addition here.
+ if (op == Token::ADD &&
+ (left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
+ if (left_type->Is(Type::String())) {
+ IfBuilder if_isstring(this);
+ if_isstring.If<HIsStringAndBranch>(left);
+ if_isstring.Then();
+ if_isstring.ElseDeopt("Expected string for LHS of binary operation");
+ } else if (left_type->Is(Type::Number())) {
+ left = BuildNumberToString(left, left_type);
+ } else {
+ ASSERT(right_type->Is(Type::String()));
+ HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT);
+ Add<HPushArgument>(left);
+ Add<HPushArgument>(right);
+ return NewUncasted<HInvokeFunction>(function, 2);
+ }
+
+ if (right_type->Is(Type::String())) {
+ IfBuilder if_isstring(this);
+ if_isstring.If<HIsStringAndBranch>(right);
+ if_isstring.Then();
+ if_isstring.ElseDeopt("Expected string for RHS of binary operation");
+ } else if (right_type->Is(Type::Number())) {
+ right = BuildNumberToString(right, right_type);
+ } else {
+ ASSERT(left_type->Is(Type::String()));
+ HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT);
+ Add<HPushArgument>(left);
+ Add<HPushArgument>(right);
+ return NewUncasted<HInvokeFunction>(function, 2);
+ }
+
+ return NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE);
+ }
if (binop_stub) {
left = EnforceNumberType(left, left_type);
@@ -7859,15 +7888,12 @@
bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
(right_rep.IsTagged() && !right_rep.IsSmi());
- bool is_string_add = op == Token::ADD &&
- (left_type->Is(Type::String()) ||
- right_type->Is(Type::String()));
HInstruction* instr = NULL;
// Only the stub is allowed to call into the runtime, since otherwise we
would
// inline several instructions (including the two pushes) for every
tagged
// operation in optimized code, which is more expensive, than a stub
call.
- if (binop_stub && is_non_primitive && !is_string_add) {
+ if (binop_stub && is_non_primitive) {
HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
Add<HPushArgument>(left);
Add<HPushArgument>(right);
@@ -7875,23 +7901,7 @@
} else {
switch (op) {
case Token::ADD:
- if (is_string_add) {
- StringAddFlags flags = STRING_ADD_CHECK_BOTH;
- if (left_type->Is(Type::String())) {
- BuildCheckHeapObject(left);
- AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
- flags = STRING_ADD_CHECK_RIGHT;
- }
- if (right_type->Is(Type::String())) {
- BuildCheckHeapObject(right);
- AddInstruction(HCheckInstanceType::NewIsString(right, zone()));
- flags = (flags == STRING_ADD_CHECK_BOTH)
- ? STRING_ADD_CHECK_LEFT : STRING_ADD_CHECK_NONE;
- }
- instr = NewUncasted<HStringAdd>(left, right, flags);
- } else {
- instr = NewUncasted<HAdd>(left, right);
- }
+ instr = NewUncasted<HAdd>(left, right);
break;
case Token::SUB:
instr = NewUncasted<HSub>(left, right);
@@ -9090,7 +9100,8 @@
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* number = Pop();
- HValue* result = BuildNumberToString(number);
+ HValue* result = BuildNumberToString(
+ number, handle(Type::Number(), isolate()));
return ast_context()->ReturnValue(result);
}
=======================================
--- /trunk/src/hydrogen.h Wed Oct 16 09:00:56 2013 UTC
+++ /trunk/src/hydrogen.h Mon Oct 21 13:27:29 2013 UTC
@@ -1234,14 +1234,7 @@
ElementsKind to_kind,
bool is_jsarray);
- // Do lookup in the number string cache. If the object is not found
- // in the cache, the false branch of the continuation is taken;
- // otherwise the true branch is taken and the returned value contains
- // the cache value for the object. The returned value must NOT be used
- // on the false branch.
- HValue* BuildLookupNumberStringCache(HValue* object,
- HIfContinuation* continuation);
- HValue* BuildNumberToString(HValue* number);
+ HValue* BuildNumberToString(HValue* object, Handle<Type> type);
HInstruction* BuildUncheckedMonomorphicElementAccess(
HValue* checked_object,
=======================================
--- /trunk/src/ia32/code-stubs-ia32.cc Mon Oct 21 07:19:36 2013 UTC
+++ /trunk/src/ia32/code-stubs-ia32.cc Mon Oct 21 13:27:29 2013 UTC
@@ -70,7 +70,8 @@
static Register registers[] = { eax };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->deoptimization_handler_ = NULL;
+ descriptor->deoptimization_handler_ =
+ Runtime::FunctionForId(Runtime::kNumberToString)->entry;
}
=======================================
--- /trunk/src/isolate.cc Fri Oct 4 15:38:52 2013 UTC
+++ /trunk/src/isolate.cc Mon Oct 21 13:27:29 2013 UTC
@@ -2327,6 +2327,7 @@
ArrayConstructorStubBase::InstallDescriptors(this);
InternalArrayConstructorStubBase::InstallDescriptors(this);
FastNewClosureStub::InstallDescriptors(this);
+ NumberToStringStub::InstallDescriptors(this);
}
if (FLAG_sweeper_threads > 0) {
=======================================
--- /trunk/src/math.js Fri Oct 18 10:34:25 2013 UTC
+++ /trunk/src/math.js Mon Oct 21 13:27:29 2013 UTC
@@ -45,59 +45,51 @@
// ECMA 262 - 15.8.2.1
function MathAbs(x) {
if (%_IsSmi(x)) return x >= 0 ? x : -x;
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ x = TO_NUMBER_INLINE(x);
if (x === 0) return 0; // To handle -0.
return x > 0 ? x : -x;
}
// ECMA 262 - 15.8.2.2
function MathAcos(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %Math_acos(x);
+ return %Math_acos(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.3
function MathAsin(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %Math_asin(x);
+ return %Math_asin(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.4
function MathAtan(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %Math_atan(x);
+ return %Math_atan(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.5
// The naming of y and x matches the spec, as does the order in which
// ToNumber (valueOf) is called.
function MathAtan2(y, x) {
- if (!IS_NUMBER(y)) y = NonNumberToNumber(y);
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %Math_atan2(y, x);
+ return %Math_atan2(TO_NUMBER_INLINE(y), TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.6
function MathCeil(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %Math_ceil(x);
+ return %Math_ceil(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.7
function MathCos(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %_MathCos(x);
+ return %_MathCos(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.8
function MathExp(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %Math_exp(x);
+ return %Math_exp(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.9
function MathFloor(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
+ x = TO_NUMBER_INLINE(x);
// It's more common to call this with a positive number that's out
// of range than negative numbers; check the upper bound first.
if (x < 0x80000000 && x > 0) {
@@ -113,16 +105,15 @@
// ECMA 262 - 15.8.2.10
function MathLog(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %_MathLog(x);
+ return %_MathLog(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.11
function MathMax(arg1, arg2) { // length == 2
var length = %_ArgumentsLength();
if (length == 2) {
- if (!IS_NUMBER(arg1)) arg1 = NonNumberToNumber(arg1);
- if (!IS_NUMBER(arg2)) arg2 = NonNumberToNumber(arg2);
+ arg1 = TO_NUMBER_INLINE(arg1);
+ arg2 = TO_NUMBER_INLINE(arg2);
if (arg2 > arg1) return arg2;
if (arg1 > arg2) return arg1;
if (arg1 == arg2) {
@@ -151,8 +142,8 @@
function MathMin(arg1, arg2) { // length == 2
var length = %_ArgumentsLength();
if (length == 2) {
- if (!IS_NUMBER(arg1)) arg1 = NonNumberToNumber(arg1);
- if (!IS_NUMBER(arg2)) arg2 = NonNumberToNumber(arg2);
+ arg1 = TO_NUMBER_INLINE(arg1);
+ arg2 = TO_NUMBER_INLINE(arg2);
if (arg2 > arg1) return arg1;
if (arg1 > arg2) return arg2;
if (arg1 == arg2) {
@@ -179,9 +170,7 @@
// ECMA 262 - 15.8.2.13
function MathPow(x, y) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- if (!IS_NUMBER(y)) y = NonNumberToNumber(y);
- return %_MathPow(x, y);
+ return %_MathPow(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
}
// ECMA 262 - 15.8.2.14
@@ -191,33 +180,27 @@
// ECMA 262 - 15.8.2.15
function MathRound(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %RoundNumber(x);
+ return %RoundNumber(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.16
function MathSin(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %_MathSin(x);
+ return %_MathSin(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.17
function MathSqrt(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %_MathSqrt(x);
+ return %_MathSqrt(TO_NUMBER_INLINE(x));
}
// ECMA 262 - 15.8.2.18
function MathTan(x) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- return %_MathTan(x);
+ return %_MathTan(TO_NUMBER_INLINE(x));
}
// Non-standard extension.
function MathImul(x, y) {
- if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
- if (!IS_NUMBER(y)) y = NonNumberToNumber(y);
- return %NumberImul(x, y);
+ return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
}
=======================================
--- /trunk/src/version.cc Mon Oct 21 07:19:36 2013 UTC
+++ /trunk/src/version.cc Mon Oct 21 13:27:29 2013 UTC
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 22
-#define BUILD_NUMBER 16
+#define BUILD_NUMBER 17
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
=======================================
--- /trunk/src/x64/code-stubs-x64.cc Mon Oct 21 07:19:36 2013 UTC
+++ /trunk/src/x64/code-stubs-x64.cc Mon Oct 21 13:27:29 2013 UTC
@@ -66,7 +66,8 @@
static Register registers[] = { rax };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
- descriptor->deoptimization_handler_ = NULL;
+ descriptor->deoptimization_handler_ =
+ Runtime::FunctionForId(Runtime::kNumberToString)->entry;
}
=======================================
--- /trunk/tools/gyp/v8.gyp Wed Oct 16 09:00:56 2013 UTC
+++ /trunk/tools/gyp/v8.gyp Mon Oct 21 13:27:29 2013 UTC
@@ -936,6 +936,7 @@
'../../src/array-iterator.js',
'../../src/harmony-string.js',
'../../src/harmony-array.js',
+ '../../src/harmony-math.js'
],
},
'actions': [
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.