[type-profile] Return type profile object.
Return a structured objet with the type profile information. Move the test from message to mjsunit. BUG=v8:5933 Change-Id: I3e1c592697924d87f82d46b0ddbdb6d82d9c8467 Reviewed-on: https://chromium-review.googlesource.com/464847 Reviewed-by: Michael Stanton <mvstanton@chromium.org> Commit-Queue: Franziska Hinkelmann <franzih@chromium.org> Cr-Commit-Position: refs/heads/master@{#44364}
This commit is contained in:
parent
e8c109e278
commit
28a3e34bdd
@ -944,54 +944,51 @@ void CollectTypeProfileNexus::Collect(Handle<String> type, int position) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void PrintTypes(Handle<ArrayList> s) {
|
Handle<JSObject> ConvertToJSObject(Isolate* isolate,
|
||||||
for (int i = 0; i < s->Length(); i++) {
|
Handle<UnseededNumberDictionary> feedback) {
|
||||||
Object* entry = s->Get(i);
|
Handle<JSObject> type_profile =
|
||||||
if (entry->IsString()) {
|
isolate->factory()->NewJSObject(isolate->object_function());
|
||||||
PrintF("%s\n", String::cast(entry)->ToCString().get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SortTypes(Isolate* isolate,
|
|
||||||
Handle<UnseededNumberDictionary> unsorted_types,
|
|
||||||
std::map<int, Handle<ArrayList>>* types) {
|
|
||||||
for (int index = UnseededNumberDictionary::kElementsStartIndex;
|
for (int index = UnseededNumberDictionary::kElementsStartIndex;
|
||||||
index < unsorted_types->length();
|
index < feedback->length();
|
||||||
index += UnseededNumberDictionary::kEntrySize) {
|
index += UnseededNumberDictionary::kEntrySize) {
|
||||||
int key_index = index + UnseededNumberDictionary::kEntryKeyIndex;
|
int key_index = index + UnseededNumberDictionary::kEntryKeyIndex;
|
||||||
Object* key = unsorted_types->get(key_index);
|
Object* key = feedback->get(key_index);
|
||||||
if (key->IsSmi()) {
|
if (key->IsSmi()) {
|
||||||
int value_index = index + UnseededNumberDictionary::kEntryValueIndex;
|
int value_index = index + UnseededNumberDictionary::kEntryValueIndex;
|
||||||
Handle<ArrayList> types_for_position = Handle<ArrayList>(
|
|
||||||
ArrayList::cast(unsorted_types->get(value_index)), isolate);
|
|
||||||
|
|
||||||
(*types)[Smi::cast(key)->value()] = types_for_position;
|
Handle<ArrayList> orig = Handle<ArrayList>(
|
||||||
|
ArrayList::cast(feedback->get(value_index)), isolate);
|
||||||
|
|
||||||
|
// Delete the first entry, i.e., the length.
|
||||||
|
Handle<FixedArray> storage =
|
||||||
|
isolate->factory()->NewFixedArray(orig->Length());
|
||||||
|
orig->CopyTo(1, *storage, 0, orig->Length());
|
||||||
|
|
||||||
|
int pos = Smi::cast(key)->value();
|
||||||
|
JSObject::AddDataElement(
|
||||||
|
type_profile, pos,
|
||||||
|
isolate->factory()->NewJSArrayWithElements(storage),
|
||||||
|
PropertyAttributes::NONE)
|
||||||
|
.ToHandleChecked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return type_profile;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void CollectTypeProfileNexus::Print() const {
|
JSObject* CollectTypeProfileNexus::GetTypeProfile() const {
|
||||||
Isolate* isolate = GetIsolate();
|
Isolate* isolate = GetIsolate();
|
||||||
|
|
||||||
Object* const feedback = GetFeedback();
|
Object* const feedback = GetFeedback();
|
||||||
|
|
||||||
if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
|
if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
|
||||||
return;
|
return *isolate->factory()->NewJSMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<UnseededNumberDictionary> unsorted_types =
|
return *ConvertToJSObject(
|
||||||
Handle<UnseededNumberDictionary>(UnseededNumberDictionary::cast(feedback),
|
isolate, Handle<UnseededNumberDictionary>(
|
||||||
isolate);
|
UnseededNumberDictionary::cast(feedback), isolate));
|
||||||
|
|
||||||
std::map<int, Handle<ArrayList>> types;
|
|
||||||
SortTypes(isolate, unsorted_types, &types);
|
|
||||||
|
|
||||||
for (const auto& entry : types) {
|
|
||||||
PrintF("%d:\n", entry.first);
|
|
||||||
PrintTypes(entry.second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -759,13 +759,9 @@ class CollectTypeProfileNexus : public FeedbackNexus {
|
|||||||
DCHECK_EQ(FeedbackSlotKind::kTypeProfile, vector->GetKind(slot));
|
DCHECK_EQ(FeedbackSlotKind::kTypeProfile, vector->GetKind(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a type to the list of types.
|
// Add a type to the list of types for source position <position>.
|
||||||
void Collect(Handle<String> type, int position);
|
void Collect(Handle<String> type, int position);
|
||||||
|
JSObject* GetTypeProfile() const;
|
||||||
// Dump the types to stdout.
|
|
||||||
// TODO(franzih): pass this information to the debugger protocol instead of
|
|
||||||
// stdout.
|
|
||||||
void Print() const;
|
|
||||||
|
|
||||||
InlineCacheState StateFromFeedback() const override;
|
InlineCacheState StateFromFeedback() const override;
|
||||||
};
|
};
|
||||||
|
@ -210,7 +210,7 @@ RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
|
|||||||
isolate->concurrent_recompilation_enabled());
|
isolate->concurrent_recompilation_enabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_PrintTypeProfile) {
|
RUNTIME_FUNCTION(Runtime_TypeProfile) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
DCHECK_EQ(1, args.length());
|
DCHECK_EQ(1, args.length());
|
||||||
|
|
||||||
@ -221,18 +221,13 @@ RUNTIME_FUNCTION(Runtime_PrintTypeProfile) {
|
|||||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
||||||
if (function->has_feedback_vector()) {
|
if (function->has_feedback_vector()) {
|
||||||
FeedbackVector* vector = function->feedback_vector();
|
FeedbackVector* vector = function->feedback_vector();
|
||||||
|
|
||||||
Object* function_name = vector->shared_function_info()->name();
|
|
||||||
PrintF("Function: %s\n", String::cast(function_name)->ToCString().get());
|
|
||||||
|
|
||||||
if (vector->metadata()->HasTypeProfileSlot()) {
|
if (vector->metadata()->HasTypeProfileSlot()) {
|
||||||
FeedbackSlot slot = vector->GetTypeProfileSlot();
|
FeedbackSlot slot = vector->GetTypeProfileSlot();
|
||||||
CollectTypeProfileNexus nexus(vector, slot);
|
CollectTypeProfileNexus nexus(vector, slot);
|
||||||
nexus.Print();
|
return nexus.GetTypeProfile();
|
||||||
PrintF("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isolate->heap()->undefined_value();
|
return *isolate->factory()->NewJSObject(isolate->object_function());
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
|
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
|
||||||
|
@ -552,7 +552,7 @@ namespace internal {
|
|||||||
F(RunningInSimulator, 0, 1) \
|
F(RunningInSimulator, 0, 1) \
|
||||||
F(IsConcurrentRecompilationSupported, 0, 1) \
|
F(IsConcurrentRecompilationSupported, 0, 1) \
|
||||||
F(OptimizeFunctionOnNextCall, -1, 1) \
|
F(OptimizeFunctionOnNextCall, -1, 1) \
|
||||||
F(PrintTypeProfile, 1, 1) \
|
F(TypeProfile, 1, 1) \
|
||||||
F(OptimizeOsr, -1, 1) \
|
F(OptimizeOsr, -1, 1) \
|
||||||
F(NeverOptimizeFunction, 1, 1) \
|
F(NeverOptimizeFunction, 1, 1) \
|
||||||
F(GetOptimizationStatus, -1, 1) \
|
F(GetOptimizationStatus, -1, 1) \
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
// Copyright 2017 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: --type-profile --turbo --allow-natives-syntax
|
|
||||||
|
|
||||||
function testFunction(param, flag) {
|
|
||||||
// We want to test 2 different return positions in one function.
|
|
||||||
if (flag) {
|
|
||||||
var first_var = param;
|
|
||||||
return first_var;
|
|
||||||
}
|
|
||||||
var second_var = param;
|
|
||||||
return second_var;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyClass {
|
|
||||||
constructor() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
%PrintTypeProfile(testFunction);
|
|
||||||
|
|
||||||
testFunction({});
|
|
||||||
testFunction(123, true);
|
|
||||||
testFunction('hello');
|
|
||||||
testFunction(123);
|
|
||||||
%PrintTypeProfile(testFunction);
|
|
||||||
|
|
||||||
testFunction(undefined);
|
|
||||||
testFunction('hello', true);
|
|
||||||
testFunction({x: 12}, true);
|
|
||||||
testFunction({x: 12});
|
|
||||||
testFunction(new MyClass());
|
|
||||||
|
|
||||||
%PrintTypeProfile(testFunction);
|
|
||||||
|
|
||||||
function testReturnOfNonVariable() {
|
|
||||||
return 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return statement is reached but its expression is never really returned.
|
|
||||||
function try_finally() {
|
|
||||||
try {
|
|
||||||
return 23;
|
|
||||||
} finally {
|
|
||||||
return "nope, string is better"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try_finally();
|
|
||||||
%PrintTypeProfile(try_finally);
|
|
||||||
|
|
||||||
function fall_off() {
|
|
||||||
//nothing
|
|
||||||
}
|
|
||||||
fall_off();
|
|
||||||
%PrintTypeProfile(fall_off);
|
|
||||||
|
|
||||||
testReturnOfNonVariable();
|
|
||||||
|
|
||||||
function never_call() {}
|
|
||||||
%PrintTypeProfile(never_call);
|
|
||||||
|
|
||||||
function check_param(a, bbb, ccccccccc, dddddddddddddddd) {
|
|
||||||
//nothing
|
|
||||||
}
|
|
||||||
check_param(2, 'foo', {}, new MyClass());
|
|
||||||
%PrintTypeProfile(check_param);
|
|
||||||
|
|
||||||
|
|
||||||
throw "end";
|
|
@ -1,73 +0,0 @@
|
|||||||
Function: testFunction
|
|
||||||
247:
|
|
||||||
Object
|
|
||||||
number
|
|
||||||
string
|
|
||||||
number
|
|
||||||
254:
|
|
||||||
undefined
|
|
||||||
boolean
|
|
||||||
undefined
|
|
||||||
undefined
|
|
||||||
443:
|
|
||||||
Object
|
|
||||||
number
|
|
||||||
string
|
|
||||||
number
|
|
||||||
|
|
||||||
Function: testFunction
|
|
||||||
247:
|
|
||||||
Object
|
|
||||||
number
|
|
||||||
string
|
|
||||||
number
|
|
||||||
undefined
|
|
||||||
string
|
|
||||||
Object
|
|
||||||
Object
|
|
||||||
MyClass
|
|
||||||
254:
|
|
||||||
undefined
|
|
||||||
boolean
|
|
||||||
undefined
|
|
||||||
undefined
|
|
||||||
undefined
|
|
||||||
boolean
|
|
||||||
boolean
|
|
||||||
undefined
|
|
||||||
undefined
|
|
||||||
443:
|
|
||||||
Object
|
|
||||||
number
|
|
||||||
string
|
|
||||||
number
|
|
||||||
undefined
|
|
||||||
string
|
|
||||||
Object
|
|
||||||
Object
|
|
||||||
MyClass
|
|
||||||
|
|
||||||
Function: try_finally
|
|
||||||
1038:
|
|
||||||
string
|
|
||||||
|
|
||||||
Function: fall_off
|
|
||||||
1122:
|
|
||||||
undefined
|
|
||||||
|
|
||||||
Function: check_param
|
|
||||||
1272:
|
|
||||||
number
|
|
||||||
1275:
|
|
||||||
string
|
|
||||||
1280:
|
|
||||||
Object
|
|
||||||
1291:
|
|
||||||
MyClass
|
|
||||||
1323:
|
|
||||||
undefined
|
|
||||||
|
|
||||||
|
|
||||||
*%(basename)s:70: end
|
|
||||||
throw "end";
|
|
||||||
^
|
|
@ -1,451 +0,0 @@
|
|||||||
// Copyright 2010 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: --type-profile --turbo
|
|
||||||
|
|
||||||
// Copy of mjsunit/array-splice as integration test for type profiling.
|
|
||||||
// It only tests that nothing crashes, no actual test for type profile output.
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
var array = new Array(10);
|
|
||||||
var spliced = array.splice(1, 1, 'one', 'two');
|
|
||||||
assertEquals(1, spliced.length);
|
|
||||||
assertFalse(0 in spliced, "0 in spliced");
|
|
||||||
|
|
||||||
assertEquals(11, array.length);
|
|
||||||
assertFalse(0 in array, "0 in array");
|
|
||||||
assertTrue(1 in array);
|
|
||||||
assertTrue(2 in array);
|
|
||||||
assertFalse(3 in array, "3 in array");
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
// Check various variants of empty array's splicing.
|
|
||||||
(function() {
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
assertEquals([], [].splice(0, 0));
|
|
||||||
assertEquals([], [].splice(1, 0));
|
|
||||||
assertEquals([], [].splice(0, 1));
|
|
||||||
assertEquals([], [].splice(-1, 0));
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
// Check that even if result array is empty, receiver gets sliced.
|
|
||||||
(function() {
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
var a = [1, 2, 3];
|
|
||||||
assertEquals([], a.splice(1, 0, 'a', 'b', 'c'));
|
|
||||||
assertEquals([1, 'a', 'b', 'c', 2, 3], a);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
// Check various forms of arguments omission.
|
|
||||||
(function() {
|
|
||||||
var array;
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
array = [1, 2, 3]
|
|
||||||
assertEquals([], array.splice());
|
|
||||||
assertEquals([1, 2, 3], array);
|
|
||||||
|
|
||||||
// SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
|
|
||||||
// given differently from when an undefined delete count is given.
|
|
||||||
// This does not follow ECMA-262, but we do the same for
|
|
||||||
// compatibility.
|
|
||||||
array = [1, 2, 3]
|
|
||||||
assertEquals([1, 2, 3], array.splice(0));
|
|
||||||
assertEquals([], array);
|
|
||||||
|
|
||||||
array = [1, 2, 3]
|
|
||||||
assertEquals([1, 2, 3], array.splice(undefined));
|
|
||||||
assertEquals([], array);
|
|
||||||
|
|
||||||
array = [1, 2, 3]
|
|
||||||
assertEquals([1, 2, 3], array.splice("foobar"));
|
|
||||||
assertEquals([], array);
|
|
||||||
|
|
||||||
array = [1, 2, 3]
|
|
||||||
assertEquals([], array.splice(undefined, undefined));
|
|
||||||
assertEquals([1, 2, 3], array);
|
|
||||||
|
|
||||||
array = [1, 2, 3]
|
|
||||||
assertEquals([], array.splice("foobar", undefined));
|
|
||||||
assertEquals([1, 2, 3], array);
|
|
||||||
|
|
||||||
array = [1, 2, 3]
|
|
||||||
assertEquals([], array.splice(undefined, "foobar"));
|
|
||||||
assertEquals([1, 2, 3], array);
|
|
||||||
|
|
||||||
array = [1, 2, 3]
|
|
||||||
assertEquals([], array.splice("foobar", "foobar"));
|
|
||||||
assertEquals([1, 2, 3], array);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
// Check variants of negatives and positive indices.
|
|
||||||
(function() {
|
|
||||||
var array, spliced;
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(-100);
|
|
||||||
assertEquals([], array);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(-1e100);
|
|
||||||
assertEquals([], array);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(-3);
|
|
||||||
assertEquals([1, 2, 3, 4], array);
|
|
||||||
assertEquals([5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(-3.999999);
|
|
||||||
assertEquals([1, 2, 3, 4], array);
|
|
||||||
assertEquals([5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(-3.000001);
|
|
||||||
assertEquals([1, 2, 3, 4], array);
|
|
||||||
assertEquals([5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(4);
|
|
||||||
assertEquals([1, 2, 3, 4], array);
|
|
||||||
assertEquals([5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(4.999999);
|
|
||||||
assertEquals([1, 2, 3, 4], array);
|
|
||||||
assertEquals([5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(4.000001);
|
|
||||||
assertEquals([1, 2, 3, 4], array);
|
|
||||||
assertEquals([5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(6);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6], array);
|
|
||||||
assertEquals([7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(7);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], array);
|
|
||||||
assertEquals([], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(8);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], array);
|
|
||||||
assertEquals([], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(100);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], array);
|
|
||||||
assertEquals([], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(1e100);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], array);
|
|
||||||
assertEquals([], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, -100);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], array);
|
|
||||||
assertEquals([], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, -1e100);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], array);
|
|
||||||
assertEquals([], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, -3);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], array);
|
|
||||||
assertEquals([], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, -3.999999);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], array);
|
|
||||||
assertEquals([], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, -3.000001);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], array);
|
|
||||||
assertEquals([], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, 4);
|
|
||||||
assertEquals([5, 6, 7], array);
|
|
||||||
assertEquals([1, 2, 3, 4], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, 4.999999);
|
|
||||||
assertEquals([5, 6, 7], array);
|
|
||||||
assertEquals([1, 2, 3, 4], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, 4.000001);
|
|
||||||
assertEquals([5, 6, 7], array);
|
|
||||||
assertEquals([1, 2, 3, 4], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, 6);
|
|
||||||
assertEquals([7], array);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, 7);
|
|
||||||
assertEquals([], array);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, 8);
|
|
||||||
assertEquals([], array);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, 100);
|
|
||||||
assertEquals([], array);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
|
|
||||||
|
|
||||||
array = [1, 2, 3, 4, 5, 6, 7];
|
|
||||||
spliced = array.splice(0, 1e100);
|
|
||||||
assertEquals([], array);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
|
|
||||||
|
|
||||||
// Some exotic cases.
|
|
||||||
obj = { toString: function() { throw 'Exception'; } };
|
|
||||||
|
|
||||||
// Throwing an exception in conversion:
|
|
||||||
try {
|
|
||||||
[1, 2, 3].splice(obj, 3);
|
|
||||||
throw 'Should have thrown';
|
|
||||||
} catch (e) {
|
|
||||||
assertEquals('Exception', e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
[1, 2, 3].splice(0, obj, 3);
|
|
||||||
throw 'Should have thrown';
|
|
||||||
} catch (e) {
|
|
||||||
assertEquals('Exception', e);
|
|
||||||
}
|
|
||||||
|
|
||||||
array = [1, 2, 3];
|
|
||||||
array.splice(0, 3, obj);
|
|
||||||
assertEquals(1, array.length);
|
|
||||||
|
|
||||||
// Custom conversion:
|
|
||||||
array = [1, 2, 3];
|
|
||||||
spliced = array.splice({valueOf: function() { return 1; }},
|
|
||||||
{toString: function() { return 2; }},
|
|
||||||
'one', 'two');
|
|
||||||
assertEquals([2, 3], spliced);
|
|
||||||
assertEquals([1, 'one', 'two'], array);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
// Nasty: modify the array in ToInteger.
|
|
||||||
(function() {
|
|
||||||
var array = [];
|
|
||||||
var spliced;
|
|
||||||
|
|
||||||
for (var i = 0; i < 13; i++) {
|
|
||||||
bad_start = { valueOf: function() { array.push(2*i); return -1; } };
|
|
||||||
bad_count = { valueOf: function() { array.push(2*i + 1); return 1; } };
|
|
||||||
spliced = array.splice(bad_start, bad_count);
|
|
||||||
// According to the spec (15.4.4.12), length is calculated before
|
|
||||||
// performing ToInteger on arguments. However, v8 ignores elements
|
|
||||||
// we add while converting, so we need corrective pushes.
|
|
||||||
array.push(2*i); array.push(2*i + 1);
|
|
||||||
if (i == 0) {
|
|
||||||
assertEquals([], spliced); // Length was 0, nothing to get.
|
|
||||||
assertEquals([0, 1], array);
|
|
||||||
} else {
|
|
||||||
// When we start splice, array is [0 .. 2*i - 1], so we get
|
|
||||||
// as a result [2*i], this element is removed from the array,
|
|
||||||
// but [2 * i, 2 * i + 1] are added.
|
|
||||||
assertEquals([2 * i - 1], spliced);
|
|
||||||
assertEquals(2 * i, array[i]);
|
|
||||||
assertEquals(2 * i + 1, array[i + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Check the behaviour when approaching maximal values for length.
|
|
||||||
(function() {
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
try {
|
|
||||||
new Array(Math.pow(2, 32) - 3).splice(-1, 0, 1, 2, 3, 4, 5);
|
|
||||||
throw 'Should have thrown RangeError';
|
|
||||||
} catch (e) {
|
|
||||||
assertTrue(e instanceof RangeError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check smi boundary
|
|
||||||
var bigNum = (1 << 30) - 3;
|
|
||||||
var array = new Array(bigNum);
|
|
||||||
array.splice(-1, 0, 1, 2, 3, 4, 5, 6, 7);
|
|
||||||
assertEquals(bigNum + 7, array.length);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
var a = [7, 8, 9];
|
|
||||||
a.splice(0, 0, 1, 2, 3, 4, 5, 6);
|
|
||||||
assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], a);
|
|
||||||
assertFalse(a.hasOwnProperty(10), "a.hasOwnProperty(10)");
|
|
||||||
assertEquals(undefined, a[10]);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
(function testSpliceDeleteDouble() {
|
|
||||||
var a = [1.1, 1.2, 1.3, 1.4];
|
|
||||||
a.splice(2, 1)
|
|
||||||
assertEquals([1.1, 1.2, 1.4], a);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Past this point the ArrayProtector is invalidated since we modify the
|
|
||||||
// Array.prototype.
|
|
||||||
|
|
||||||
// Check the case of JS builtin .splice()
|
|
||||||
(function() {
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
var array = [1, 2, 3, 4];
|
|
||||||
Array.prototype[3] = 'foo'; // To force JS builtin.
|
|
||||||
|
|
||||||
var spliced = array.splice();
|
|
||||||
|
|
||||||
assertEquals([], spliced);
|
|
||||||
assertEquals([1, 2, 3, 4], array);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Now check the case with array of holes and some elements on prototype.
|
|
||||||
(function() {
|
|
||||||
var len = 9;
|
|
||||||
|
|
||||||
var at3 = "@3";
|
|
||||||
var at7 = "@7";
|
|
||||||
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
var array = new Array(len);
|
|
||||||
var array_proto = [];
|
|
||||||
array_proto[3] = at3;
|
|
||||||
array_proto[7] = at7;
|
|
||||||
array.__proto__ = array_proto;
|
|
||||||
|
|
||||||
var spliced = array.splice(2, 2, 'one', undefined, 'two');
|
|
||||||
|
|
||||||
// Second hole (at index 3) of array turns into
|
|
||||||
// value of Array.prototype[3] while copying.
|
|
||||||
assertEquals([, at3], spliced);
|
|
||||||
assertEquals([, , 'one', undefined, 'two', , , at7, at7, ,], array);
|
|
||||||
|
|
||||||
// ... but array[3] and array[7] is actually a hole:
|
|
||||||
assertTrue(delete array_proto[3]);
|
|
||||||
assertEquals(undefined, array[3]);
|
|
||||||
assertTrue(delete array_proto[7]);
|
|
||||||
assertEquals(undefined, array[7]);
|
|
||||||
|
|
||||||
// and now check hasOwnProperty
|
|
||||||
assertFalse(array.hasOwnProperty(0), "array.hasOwnProperty(0)");
|
|
||||||
assertFalse(array.hasOwnProperty(1), "array.hasOwnProperty(1)");
|
|
||||||
assertTrue(array.hasOwnProperty(2));
|
|
||||||
assertTrue(array.hasOwnProperty(3));
|
|
||||||
assertTrue(array.hasOwnProperty(4));
|
|
||||||
assertFalse(array.hasOwnProperty(5), "array.hasOwnProperty(5)");
|
|
||||||
assertFalse(array.hasOwnProperty(6), "array.hasOwnProperty(6)");
|
|
||||||
assertFalse(array.hasOwnProperty(7), "array.hasOwnProperty(7)");
|
|
||||||
assertTrue(array.hasOwnProperty(8));
|
|
||||||
assertFalse(array.hasOwnProperty(9), "array.hasOwnProperty(9)");
|
|
||||||
|
|
||||||
// and now check couple of indices above length.
|
|
||||||
assertFalse(array.hasOwnProperty(10), "array.hasOwnProperty(10)");
|
|
||||||
assertFalse(array.hasOwnProperty(15), "array.hasOwnProperty(15)");
|
|
||||||
assertFalse(array.hasOwnProperty(31), "array.hasOwnProperty(31)");
|
|
||||||
assertFalse(array.hasOwnProperty(63), "array.hasOwnProperty(63)");
|
|
||||||
assertFalse(array.hasOwnProperty(Math.pow(2, 32) - 2),
|
|
||||||
"array.hasOwnProperty(Math.pow(2, 32) - 2)");
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Now check the case with array of holes and some elements on prototype.
|
|
||||||
(function() {
|
|
||||||
var len = 9;
|
|
||||||
|
|
||||||
var at3 = "@3";
|
|
||||||
var at7 = "@7";
|
|
||||||
|
|
||||||
for (var i = 0; i < 7; i++) {
|
|
||||||
var array = new Array(len);
|
|
||||||
Array.prototype[3] = at3;
|
|
||||||
Array.prototype[7] = at7;
|
|
||||||
|
|
||||||
var spliced = array.splice(2, 2, 'one', undefined, 'two');
|
|
||||||
|
|
||||||
// Second hole (at index 3) of array turns into
|
|
||||||
// value of Array.prototype[3] while copying.
|
|
||||||
assertEquals([, at3], spliced);
|
|
||||||
assertEquals([, , 'one', undefined, 'two', , , at7, at7, ,], array);
|
|
||||||
|
|
||||||
// ... but array[3] and array[7] is actually a hole:
|
|
||||||
assertTrue(delete Array.prototype[3]);
|
|
||||||
assertEquals(undefined, array[3]);
|
|
||||||
assertTrue(delete Array.prototype[7]);
|
|
||||||
assertEquals(undefined, array[7]);
|
|
||||||
|
|
||||||
// and now check hasOwnProperty
|
|
||||||
assertFalse(array.hasOwnProperty(0), "array.hasOwnProperty(0)");
|
|
||||||
assertFalse(array.hasOwnProperty(1), "array.hasOwnProperty(1)");
|
|
||||||
assertTrue(array.hasOwnProperty(2));
|
|
||||||
assertTrue(array.hasOwnProperty(3));
|
|
||||||
assertTrue(array.hasOwnProperty(4));
|
|
||||||
assertFalse(array.hasOwnProperty(5), "array.hasOwnProperty(5)");
|
|
||||||
assertFalse(array.hasOwnProperty(6), "array.hasOwnProperty(6)");
|
|
||||||
assertFalse(array.hasOwnProperty(7), "array.hasOwnProperty(7)");
|
|
||||||
assertTrue(array.hasOwnProperty(8));
|
|
||||||
assertFalse(array.hasOwnProperty(9), "array.hasOwnProperty(9)");
|
|
||||||
|
|
||||||
// and now check couple of indices above length.
|
|
||||||
assertFalse(array.hasOwnProperty(10), "array.hasOwnProperty(10)");
|
|
||||||
assertFalse(array.hasOwnProperty(15), "array.hasOwnProperty(15)");
|
|
||||||
assertFalse(array.hasOwnProperty(31), "array.hasOwnProperty(31)");
|
|
||||||
assertFalse(array.hasOwnProperty(63), "array.hasOwnProperty(63)");
|
|
||||||
assertFalse(array.hasOwnProperty(Math.pow(2, 32) - 2),
|
|
||||||
"array.hasOwnProperty(Math.pow(2, 32) - 2)");
|
|
||||||
}
|
|
||||||
})();
|
|
90
test/mjsunit/type-profile/collect-type-profile.js
Normal file
90
test/mjsunit/type-profile/collect-type-profile.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Copyright 2017 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: --type-profile --turbo --allow-natives-syntax
|
||||||
|
|
||||||
|
function check_collect_types(name, expected) {
|
||||||
|
const type_profile = %TypeProfile(name);
|
||||||
|
if (type_profile !== undefined) {
|
||||||
|
const result = JSON.stringify(type_profile);
|
||||||
|
print(result);
|
||||||
|
assertEquals(expected, result, name + " failed");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFunction(param, flag) {
|
||||||
|
// We want to test 2 different return positions in one function.
|
||||||
|
if (flag) {
|
||||||
|
var first_var = param;
|
||||||
|
return first_var;
|
||||||
|
}
|
||||||
|
var second_var = param;
|
||||||
|
return second_var;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyClass {
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected = `{}`;
|
||||||
|
check_collect_types(testFunction, expected);
|
||||||
|
|
||||||
|
testFunction({});
|
||||||
|
testFunction(123, true);
|
||||||
|
testFunction('hello');
|
||||||
|
testFunction(123);
|
||||||
|
|
||||||
|
expected = `{\"503\":[\"Object\",\"number\",\"string\",\"number\"],\"510\":[\"undefined\",\"boolean\",\"undefined\",\"undefined\"],\"699\":[\"Object\",\"number\",\"string\",\"number\"]}`;
|
||||||
|
check_collect_types(testFunction, expected);
|
||||||
|
|
||||||
|
testFunction(undefined);
|
||||||
|
testFunction('hello', true);
|
||||||
|
testFunction({x: 12}, true);
|
||||||
|
testFunction({x: 12});
|
||||||
|
testFunction(new MyClass());
|
||||||
|
|
||||||
|
expected = `{\"503\":[\"Object\",\"number\",\"string\",\"number\",\"undefined\",\"string\",\"Object\",\"Object\",\"MyClass\"],\"510\":[\"undefined\",\"boolean\",\"undefined\",\"undefined\",\"undefined\",\"boolean\",\"boolean\",\"undefined\",\"undefined\"],\"699\":[\"Object\",\"number\",\"string\",\"number\",\"undefined\",\"string\",\"Object\",\"Object\",\"MyClass\"]}`;
|
||||||
|
check_collect_types(testFunction, expected);
|
||||||
|
|
||||||
|
|
||||||
|
function testReturnOfNonVariable() {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
testReturnOfNonVariable();
|
||||||
|
expected = `{\"1732\":[\"number\"]}`;
|
||||||
|
check_collect_types(testReturnOfNonVariable, expected);
|
||||||
|
|
||||||
|
// Return statement is reached but its expression is never really returned.
|
||||||
|
function try_finally() {
|
||||||
|
try {
|
||||||
|
return 23;
|
||||||
|
} finally {
|
||||||
|
return "nope, string is better"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try_finally();
|
||||||
|
expected = `{\"2034\":[\"string\"]}`;
|
||||||
|
check_collect_types(try_finally, expected);
|
||||||
|
|
||||||
|
// Fall-off return.
|
||||||
|
function fall_off() {
|
||||||
|
//nothing
|
||||||
|
}
|
||||||
|
fall_off();
|
||||||
|
expected = `{\"2188\":[\"undefined\"]}`;
|
||||||
|
check_collect_types(fall_off, expected);
|
||||||
|
|
||||||
|
// Do not collect types when the function is never run.
|
||||||
|
function never_called() {}
|
||||||
|
expected = `{}`;
|
||||||
|
check_collect_types(never_called, expected);
|
||||||
|
|
||||||
|
|
||||||
|
function several_params(a, b, c, d) {
|
||||||
|
//nothing
|
||||||
|
}
|
||||||
|
several_params(2, 'foo', {}, new MyClass());
|
||||||
|
expected = `{\"2456\":[\"number\"],\"2459\":[\"string\"],\"2462\":[\"Object\"],\"2465\":[\"MyClass\"],\"2482\":[\"undefined\"]}`;
|
||||||
|
check_collect_types(several_params, expected);
|
Loading…
Reference in New Issue
Block a user