Upgrade to v8 1.2.7
This commit is contained in:
parent
f6a7fe2657
commit
696f024557
15
deps/v8/AUTHORS
vendored
15
deps/v8/AUTHORS
vendored
@ -5,11 +5,14 @@
|
||||
|
||||
Google Inc.
|
||||
|
||||
Rene Rebe <rene@exactcode.de>
|
||||
Rafal Krypa <rafal@krypa.net>
|
||||
Jay Freeman <saurik@saurik.com>
|
||||
Daniel James <dnljms@gmail.com>
|
||||
Paolo Giarrusso <p.giarrusso@gmail.com>
|
||||
Daniel Andersson <kodandersson@gmail.com>
|
||||
Alexander Botero-Lowry <alexbl@FreeBSD.org>
|
||||
Craig Schlenter <craig.schlenter@gmail.com>
|
||||
Daniel Andersson <kodandersson@gmail.com>
|
||||
Daniel James <dnljms@gmail.com>
|
||||
Jay Freeman <saurik@saurik.com>
|
||||
Joel Stanley <joel.stan@gmail.com>
|
||||
Matt Hanselman <mjhanselman@gmail.com>
|
||||
Paolo Giarrusso <p.giarrusso@gmail.com>
|
||||
Rafal Krypa <rafal@krypa.net>
|
||||
Rene Rebe <rene@exactcode.de>
|
||||
Ryan Dahl <coldredlemur@gmail.com>
|
||||
|
89
deps/v8/ChangeLog
vendored
89
deps/v8/ChangeLog
vendored
@ -1,3 +1,92 @@
|
||||
2009-06-08: Version 1.2.7
|
||||
|
||||
Improved debugger and profiler support.
|
||||
|
||||
Reduced compilation time by improving the handling of deferred
|
||||
code.
|
||||
|
||||
Optimized interceptor accesses where the property is on the object
|
||||
on which the interceptors is attached.
|
||||
|
||||
Fixed compilation problem on GCC 4.4 by changing the stack
|
||||
alignment to 16 bytes.
|
||||
|
||||
Fixed handle creation to follow stric aliasing rules.
|
||||
|
||||
Fixed compilation on FreeBSD.
|
||||
|
||||
Introduced API for forcing the deletion of a property ignoring
|
||||
interceptors and attributes.
|
||||
|
||||
|
||||
2009-05-29: Version 1.2.6
|
||||
|
||||
Added a histogram recording hit rates at different levels of the
|
||||
compilation cache.
|
||||
|
||||
Added stack overflow check for the RegExp analysis phase. Previously a
|
||||
very long regexp graph could overflow the stack with recursive calls.
|
||||
|
||||
Use a dynamic buffer when collecting log events in memory.
|
||||
|
||||
Added start/stop events to the profiler log.
|
||||
|
||||
Fixed infinite loop which could happen when setting a debug break while
|
||||
executing a RegExp compiled to native code.
|
||||
|
||||
Fixed handling of lastIndexOf called with negative index (issue 351).
|
||||
|
||||
Fixed irregular crash in profiler test (issue 358).
|
||||
|
||||
Fixed compilation issues with some versions of gcc.
|
||||
|
||||
|
||||
2009-05-26: Version 1.2.5
|
||||
|
||||
Fixed bug in initial boundary check for Boyer-Moore text
|
||||
search (issue 349).
|
||||
|
||||
Fixed compilation issues with MinGW and gcc 4.3+ and added support
|
||||
for armv7 and cortex-a8 architectures. Patches by Lei Zhang and
|
||||
Craig Schlenter.
|
||||
|
||||
Added a script cache to the debugger.
|
||||
|
||||
Optimized compilation performance by improving internal data
|
||||
structures and avoiding expensive property load optimizations for
|
||||
code that's infrequently executed.
|
||||
|
||||
Exposed the calling JavaScript context through the static API
|
||||
function Context::GetCalling().
|
||||
|
||||
|
||||
2009-05-18: Version 1.2.4
|
||||
|
||||
Improved performance of floating point number allocation for ARM
|
||||
platforms.
|
||||
|
||||
Fixed crash when using the instanceof operator on functions with
|
||||
number values in their prototype chain (issue 341).
|
||||
|
||||
Optimized virtual frame operations in the code generator to speed
|
||||
up compilation time and allocated the frames in the zone.
|
||||
|
||||
Made the representation of virtual frames and jump targets in the
|
||||
code generator much more compact.
|
||||
|
||||
Avoided linear search for non-locals in scope code when resolving
|
||||
variables inside with and eval scopes.
|
||||
|
||||
Optimized lexical scanner by dealing with whitespace as part of
|
||||
the token scanning instead of as a separate step before it.
|
||||
|
||||
Changed the scavenging collector so that promoted objects do not
|
||||
reside in the old generation while their remembered set is being
|
||||
swept for pointers into the young generation.
|
||||
|
||||
Fixed numeric overflow handling when compiling count operations.
|
||||
|
||||
|
||||
2009-05-11: Version 1.2.3
|
||||
|
||||
Fixed bug in reporting of out-of-memory situations.
|
||||
|
6
deps/v8/SConstruct
vendored
6
deps/v8/SConstruct
vendored
@ -44,10 +44,10 @@ if ANDROID_TOP is None:
|
||||
ANDROID_TOP=""
|
||||
|
||||
# TODO: Sort these issues out properly but as a temporary solution for gcc 4.4
|
||||
# on linux we need these compiler flags to avoid a mksnapshot segfault, avoid
|
||||
# crashes in the v8 test suite and avoid dtoa.c strict aliasing issues
|
||||
# on linux we need these compiler flags to avoid crashes in the v8 test suite
|
||||
# and avoid dtoa.c strict aliasing issues
|
||||
if os.environ.get('GCC_VERSION') == '44':
|
||||
GCC_EXTRA_CCFLAGS = ['-fno-tree-vectorize', '-fno-tree-vrp']
|
||||
GCC_EXTRA_CCFLAGS = ['-fno-tree-vrp']
|
||||
GCC_DTOA_EXTRA_CCFLAGS = ['-fno-strict-aliasing']
|
||||
else:
|
||||
GCC_EXTRA_CCFLAGS = []
|
||||
|
18
deps/v8/benchmarks/README.txt
vendored
18
deps/v8/benchmarks/README.txt
vendored
@ -40,3 +40,21 @@ pages where it occurs and the number of times it is executed while
|
||||
loading each page. Finally the literal letters in the data are
|
||||
encoded using ROT13 in a way that does not affect how the regexps
|
||||
match their input.
|
||||
|
||||
|
||||
Changes from Version 3 to Version 4
|
||||
===================================
|
||||
|
||||
The Splay benchmark is a newcomer in version 4. It manipulates a
|
||||
splay tree by adding and removing data nodes, thus exercising the
|
||||
memory management subsystem of the JavaScript engine.
|
||||
|
||||
Furthermore, all the unused parts of the Prototype library were
|
||||
removed from the RayTrace benchmark. This does not affect the running
|
||||
of the benchmark.
|
||||
|
||||
|
||||
Changes from Version 4 to Version 5
|
||||
===================================
|
||||
|
||||
Removed duplicate line in random seed code.
|
||||
|
51
deps/v8/benchmarks/base.js
vendored
51
deps/v8/benchmarks/base.js
vendored
@ -31,10 +31,15 @@
|
||||
|
||||
|
||||
// A benchmark has a name (string) and a function that will be run to
|
||||
// do the performance measurement.
|
||||
function Benchmark(name, run) {
|
||||
// do the performance measurement. The optional setup and tearDown
|
||||
// arguments are functions that will be invoked before and after
|
||||
// running the benchmark, but the running time of these functions will
|
||||
// not be accounted for in the benchmark score.
|
||||
function Benchmark(name, run, setup, tearDown) {
|
||||
this.name = name;
|
||||
this.run = run;
|
||||
this.Setup = setup ? setup : function() { };
|
||||
this.TearDown = tearDown ? tearDown : function() { };
|
||||
}
|
||||
|
||||
|
||||
@ -73,7 +78,7 @@ BenchmarkSuite.suites = [];
|
||||
// Scores are not comparable across versions. Bump the version if
|
||||
// you're making changes that will affect that scores, e.g. if you add
|
||||
// a new benchmark or change an existing one.
|
||||
BenchmarkSuite.version = '3';
|
||||
BenchmarkSuite.version = '5';
|
||||
|
||||
|
||||
// To make the benchmark results predictable, we replace Math.random
|
||||
@ -86,7 +91,6 @@ Math.random = (function() {
|
||||
seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
|
||||
seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff;
|
||||
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
|
||||
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
|
||||
seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff;
|
||||
seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
|
||||
return (seed & 0xfffffff) / 0x10000000;
|
||||
@ -114,7 +118,7 @@ BenchmarkSuite.RunSuites = function(runner) {
|
||||
continuation = suite.RunStep(runner);
|
||||
}
|
||||
if (continuation && typeof window != 'undefined' && window.setTimeout) {
|
||||
window.setTimeout(RunStep, 100);
|
||||
window.setTimeout(RunStep, 25);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -194,7 +198,7 @@ BenchmarkSuite.prototype.NotifyError = function(error) {
|
||||
|
||||
// Runs a single benchmark for at least a second and computes the
|
||||
// average time it takes to run a single iteration.
|
||||
BenchmarkSuite.prototype.RunSingle = function(benchmark) {
|
||||
BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark) {
|
||||
var elapsed = 0;
|
||||
var start = new Date();
|
||||
for (var n = 0; elapsed < 1000; n++) {
|
||||
@ -216,18 +220,45 @@ BenchmarkSuite.prototype.RunStep = function(runner) {
|
||||
var length = this.benchmarks.length;
|
||||
var index = 0;
|
||||
var suite = this;
|
||||
function RunNext() {
|
||||
|
||||
// Run the setup, the actual benchmark, and the tear down in three
|
||||
// separate steps to allow the framework to yield between any of the
|
||||
// steps.
|
||||
|
||||
function RunNextSetup() {
|
||||
if (index < length) {
|
||||
try {
|
||||
suite.RunSingle(suite.benchmarks[index++]);
|
||||
suite.benchmarks[index].Setup();
|
||||
} catch (e) {
|
||||
suite.NotifyError(e);
|
||||
return null;
|
||||
}
|
||||
return RunNext;
|
||||
return RunNextBenchmark;
|
||||
}
|
||||
suite.NotifyResult();
|
||||
return null;
|
||||
}
|
||||
return RunNext();
|
||||
|
||||
function RunNextBenchmark() {
|
||||
try {
|
||||
suite.RunSingleBenchmark(suite.benchmarks[index]);
|
||||
} catch (e) {
|
||||
suite.NotifyError(e);
|
||||
return null;
|
||||
}
|
||||
return RunNextTearDown;
|
||||
}
|
||||
|
||||
function RunNextTearDown() {
|
||||
try {
|
||||
suite.benchmarks[index++].TearDown();
|
||||
} catch (e) {
|
||||
suite.NotifyError(e);
|
||||
return null;
|
||||
}
|
||||
return RunNextSetup;
|
||||
}
|
||||
|
||||
// Start out running the setup.
|
||||
return RunNextSetup();
|
||||
}
|
||||
|
8
deps/v8/benchmarks/deltablue.js
vendored
8
deps/v8/benchmarks/deltablue.js
vendored
@ -16,10 +16,10 @@
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
// This implementation of the DeltaBlue benchmark is derived
|
||||
// from the Smalltalk implementation by John Maloney and Mario
|
||||
// Wolczko. Some parts have been translated directly, whereas
|
||||
// others have been modified more aggresively to make it feel
|
||||
// This implementation of the DeltaBlue benchmark is derived
|
||||
// from the Smalltalk implementation by John Maloney and Mario
|
||||
// Wolczko. Some parts have been translated directly, whereas
|
||||
// others have been modified more aggresively to make it feel
|
||||
// more like a JavaScript program.
|
||||
|
||||
|
||||
|
1
deps/v8/benchmarks/earley-boyer.js
vendored
1
deps/v8/benchmarks/earley-boyer.js
vendored
@ -4682,4 +4682,3 @@ function RunBenchmark(name, count, run, warn) {
|
||||
}
|
||||
|
||||
var BgL_runzd2benchmarkzd2 = RunBenchmark;
|
||||
|
||||
|
2519
deps/v8/benchmarks/raytrace.js
vendored
2519
deps/v8/benchmarks/raytrace.js
vendored
File diff suppressed because it is too large
Load Diff
23
deps/v8/benchmarks/revisions.html
vendored
23
deps/v8/benchmarks/revisions.html
vendored
@ -20,6 +20,25 @@ the benchmark suite.
|
||||
|
||||
</p>
|
||||
|
||||
<div class="subtitle"><h3>Version 5 (<a href="http://v8.googlecode.com/svn/data/benchmarks/v5/run.html">link</a>)</h3></div>
|
||||
|
||||
<p>Removed a duplicate line in the base random seed code.
|
||||
</p>
|
||||
|
||||
<div class="subtitle"><h3>Version 4 (<a href="http://v8.googlecode.com/svn/data/benchmarks/v4/run.html">link</a>)</h3></div>
|
||||
|
||||
<p>The <i>Splay</i> benchmark is a newcomer in version 4. It
|
||||
manipulates a splay tree by adding and removing data nodes, thus
|
||||
exercising the memory management subsystem of the JavaScript engine.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Furthermore, all the unused parts of the Prototype library were
|
||||
removed from the RayTrace benchmark. This does not affect the running
|
||||
of the benchmark.
|
||||
</p>
|
||||
|
||||
|
||||
<div class="subtitle"><h3>Version 3 (<a href="http://v8.googlecode.com/svn/data/benchmarks/v3/run.html">link</a>)</h3></div>
|
||||
|
||||
<p>Version 3 adds a new benchmark, <i>RegExp</i>. The RegExp
|
||||
@ -32,9 +51,10 @@ encoded using ROT13 in a way that does not affect how the regexps
|
||||
match their input.
|
||||
</p>
|
||||
|
||||
|
||||
<div class="subtitle"><h3>Version 2 (<a href="http://v8.googlecode.com/svn/data/benchmarks/v2/run.html">link</a>)</h3></div>
|
||||
|
||||
<p>For version 2 the crypto benchmark was fixed. Previously, the
|
||||
<p>For version 2 the Crypto benchmark was fixed. Previously, the
|
||||
decryption stage was given plaintext as input, which resulted in an
|
||||
error. Now, the decryption stage is given the output of the
|
||||
encryption stage as input. The result is checked against the original
|
||||
@ -49,6 +69,7 @@ results of their calculations. This is to avoid accidentally
|
||||
obtaining scores that are the result of an incorrect JavaScript engine
|
||||
optimization.</p>
|
||||
|
||||
|
||||
<div class="subtitle"><h3>Version 1 (<a href="http://v8.googlecode.com/svn/data/benchmarks/v1/run.html">link</a>)</h3></div>
|
||||
|
||||
<p>Initial release.</p>
|
||||
|
2
deps/v8/benchmarks/richards.js
vendored
2
deps/v8/benchmarks/richards.js
vendored
@ -30,7 +30,7 @@
|
||||
// benchmark from:
|
||||
//
|
||||
// http://www.cl.cam.ac.uk/~mr10/Bench.html
|
||||
//
|
||||
//
|
||||
// The benchmark was originally implemented in BCPL by
|
||||
// Martin Richards.
|
||||
|
||||
|
12
deps/v8/benchmarks/run.html
vendored
12
deps/v8/benchmarks/run.html
vendored
@ -8,6 +8,7 @@
|
||||
<script type="text/javascript" src="raytrace.js"></script>
|
||||
<script type="text/javascript" src="earley-boyer.js"></script>
|
||||
<script type="text/javascript" src="regexp.js"></script>
|
||||
<script type="text/javascript" src="splay.js"></script>
|
||||
<link type="text/css" rel="stylesheet" href="style.css"></link>
|
||||
<script type="text/javascript">
|
||||
var completed = 0;
|
||||
@ -72,12 +73,13 @@ higher scores means better performance: <em>Bigger is better!</em>
|
||||
<ul>
|
||||
<li><b>Richards</b><br/>OS kernel simulation benchmark, originally written in BCPL by Martin Richards (<i>539 lines</i>).</li>
|
||||
<li><b>DeltaBlue</b><br/>One-way constraint solver, originally written in Smalltalk by John Maloney and Mario Wolczko (<i>880 lines</i>).</li>
|
||||
<li><b>Crypto</b><br/>Encryption and decryption benchmark based on code by Tom Wu (<i>1689 lines</i>).</li>
|
||||
<li><b>RayTrace</b><br/>Ray tracer benchmark based on code by <a href="http://flog.co.nz/">Adam Burmister</a> (<i>3418 lines</i>).</li>
|
||||
<li><b>EarleyBoyer</b><br/>Classic Scheme benchmarks, translated to JavaScript by Florian Loitsch's Scheme2Js compiler (<i>4682 lines</i>).</li>
|
||||
<li><b>Crypto</b><br/>Encryption and decryption benchmark based on code by Tom Wu (<i>1698 lines</i>).</li>
|
||||
<li><b>RayTrace</b><br/>Ray tracer benchmark based on code by <a href="http://flog.co.nz/">Adam Burmister</a> (<i>935 lines</i>).</li>
|
||||
<li><b>EarleyBoyer</b><br/>Classic Scheme benchmarks, translated to JavaScript by Florian Loitsch's Scheme2Js compiler (<i>4685 lines</i>).</li>
|
||||
<li><b>RegExp</b><br/>Regular expression benchmark generated by extracting regular expression operations from 50 of the most popular web pages
|
||||
(<i>4758 lines</i>).
|
||||
(<i>1614 lines</i>).
|
||||
</li>
|
||||
<li><b>Splay</b><br/>Data manipulation benchmark that deals with splay trees and exercises the automatic memory management subsystem (<i>378 lines</i>).</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
@ -90,7 +92,7 @@ the <a href="http://v8.googlecode.com/svn/data/benchmarks/current/revisions.html
|
||||
|
||||
</td><td style="text-align: center">
|
||||
<div class="run">
|
||||
<div id="status" style="text-align: center; margin-top: 60px; font-size: 120%; font-weight: bold;">Starting...</div>
|
||||
<div id="status" style="text-align: center; margin-top: 50px; font-size: 120%; font-weight: bold;">Starting...</div>
|
||||
<div style="text-align: left; margin: 30px 0 0 90px;" id="results">
|
||||
<div>
|
||||
</div>
|
||||
|
1
deps/v8/benchmarks/run.js
vendored
1
deps/v8/benchmarks/run.js
vendored
@ -33,6 +33,7 @@ load('crypto.js');
|
||||
load('raytrace.js');
|
||||
load('earley-boyer.js');
|
||||
load('regexp.js');
|
||||
load('splay.js');
|
||||
|
||||
var success = true;
|
||||
|
||||
|
378
deps/v8/benchmarks/splay.js
vendored
Normal file
378
deps/v8/benchmarks/splay.js
vendored
Normal file
@ -0,0 +1,378 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// This benchmark is based on a JavaScript log processing module used
|
||||
// by the V8 profiler to generate execution time profiles for runs of
|
||||
// JavaScript applications, and it effectively measures how fast the
|
||||
// JavaScript engine is at allocating nodes and reclaiming the memory
|
||||
// used for old nodes. Because of the way splay trees work, the engine
|
||||
// also has to deal with a lot of changes to the large tree object
|
||||
// graph.
|
||||
|
||||
var Splay = new BenchmarkSuite('Splay', 126125, [
|
||||
new Benchmark("Splay", SplayRun, SplaySetup, SplayTearDown)
|
||||
]);
|
||||
|
||||
|
||||
// Configuration.
|
||||
var kSplayTreeSize = 8000;
|
||||
var kSplayTreeModifications = 80;
|
||||
var kSplayTreePayloadDepth = 5;
|
||||
|
||||
var splayTree = null;
|
||||
|
||||
|
||||
function GeneratePayloadTree(depth, key) {
|
||||
if (depth == 0) {
|
||||
return {
|
||||
array : [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
|
||||
string : 'String for key ' + key + ' in leaf node'
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
left: GeneratePayloadTree(depth - 1, key),
|
||||
right: GeneratePayloadTree(depth - 1, key)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function GenerateKey() {
|
||||
// The benchmark framework guarantees that Math.random is
|
||||
// deterministic; see base.js.
|
||||
return Math.random();
|
||||
}
|
||||
|
||||
|
||||
function InsertNewNode() {
|
||||
// Insert new node with a unique key.
|
||||
var key;
|
||||
do {
|
||||
key = GenerateKey();
|
||||
} while (splayTree.find(key) != null);
|
||||
splayTree.insert(key, GeneratePayloadTree(kSplayTreePayloadDepth, key));
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function SplaySetup() {
|
||||
splayTree = new SplayTree();
|
||||
for (var i = 0; i < kSplayTreeSize; i++) InsertNewNode();
|
||||
}
|
||||
|
||||
|
||||
function SplayTearDown() {
|
||||
// Allow the garbage collector to reclaim the memory
|
||||
// used by the splay tree no matter how we exit the
|
||||
// tear down function.
|
||||
var keys = splayTree.exportKeys();
|
||||
splayTree = null;
|
||||
|
||||
// Verify that the splay tree has the right size.
|
||||
var length = keys.length;
|
||||
if (length != kSplayTreeSize) {
|
||||
throw new Error("Splay tree has wrong size");
|
||||
}
|
||||
|
||||
// Verify that the splay tree has sorted, unique keys.
|
||||
for (var i = 0; i < length - 1; i++) {
|
||||
if (keys[i] >= keys[i + 1]) {
|
||||
throw new Error("Splay tree not sorted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function SplayRun() {
|
||||
// Replace a few nodes in the splay tree.
|
||||
for (var i = 0; i < kSplayTreeModifications; i++) {
|
||||
var key = InsertNewNode();
|
||||
var greatest = splayTree.findGreatestLessThan(key);
|
||||
if (greatest == null) splayTree.remove(key);
|
||||
else splayTree.remove(greatest.key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a Splay tree. A splay tree is a self-balancing binary
|
||||
* search tree with the additional property that recently accessed
|
||||
* elements are quick to access again. It performs basic operations
|
||||
* such as insertion, look-up and removal in O(log(n)) amortized time.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function SplayTree() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Pointer to the root node of the tree.
|
||||
*
|
||||
* @type {SplayTree.Node}
|
||||
* @private
|
||||
*/
|
||||
SplayTree.prototype.root_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the tree is empty.
|
||||
*/
|
||||
SplayTree.prototype.isEmpty = function() {
|
||||
return !this.root_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Inserts a node into the tree with the specified key and value if
|
||||
* the tree does not already contain a node with the specified key. If
|
||||
* the value is inserted, it becomes the root of the tree.
|
||||
*
|
||||
* @param {number} key Key to insert into the tree.
|
||||
* @param {*} value Value to insert into the tree.
|
||||
*/
|
||||
SplayTree.prototype.insert = function(key, value) {
|
||||
if (this.isEmpty()) {
|
||||
this.root_ = new SplayTree.Node(key, value);
|
||||
return;
|
||||
}
|
||||
// Splay on the key to move the last node on the search path for
|
||||
// the key to the root of the tree.
|
||||
this.splay_(key);
|
||||
if (this.root_.key == key) {
|
||||
return;
|
||||
}
|
||||
var node = new SplayTree.Node(key, value);
|
||||
if (key > this.root_.key) {
|
||||
node.left = this.root_;
|
||||
node.right = this.root_.right;
|
||||
this.root_.right = null;
|
||||
} else {
|
||||
node.right = this.root_;
|
||||
node.left = this.root_.left;
|
||||
this.root_.left = null;
|
||||
}
|
||||
this.root_ = node;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a node with the specified key from the tree if the tree
|
||||
* contains a node with this key. The removed node is returned. If the
|
||||
* key is not found, an exception is thrown.
|
||||
*
|
||||
* @param {number} key Key to find and remove from the tree.
|
||||
* @return {SplayTree.Node} The removed node.
|
||||
*/
|
||||
SplayTree.prototype.remove = function(key) {
|
||||
if (this.isEmpty()) {
|
||||
throw Error('Key not found: ' + key);
|
||||
}
|
||||
this.splay_(key);
|
||||
if (this.root_.key != key) {
|
||||
throw Error('Key not found: ' + key);
|
||||
}
|
||||
var removed = this.root_;
|
||||
if (!this.root_.left) {
|
||||
this.root_ = this.root_.right;
|
||||
} else {
|
||||
var right = this.root_.right;
|
||||
this.root_ = this.root_.left;
|
||||
// Splay to make sure that the new root has an empty right child.
|
||||
this.splay_(key);
|
||||
// Insert the original right child as the right child of the new
|
||||
// root.
|
||||
this.root_.right = right;
|
||||
}
|
||||
return removed;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the node having the specified key or null if the tree doesn't contain
|
||||
* a node with the specified key.
|
||||
*
|
||||
* @param {number} key Key to find in the tree.
|
||||
* @return {SplayTree.Node} Node having the specified key.
|
||||
*/
|
||||
SplayTree.prototype.find = function(key) {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
this.splay_(key);
|
||||
return this.root_.key == key ? this.root_ : null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {SplayTree.Node} Node having the maximum key value that
|
||||
* is less or equal to the specified key value.
|
||||
*/
|
||||
SplayTree.prototype.findGreatestLessThan = function(key) {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// Splay on the key to move the node with the given key or the last
|
||||
// node on the search path to the top of the tree.
|
||||
this.splay_(key);
|
||||
// Now the result is either the root node or the greatest node in
|
||||
// the left subtree.
|
||||
if (this.root_.key <= key) {
|
||||
return this.root_;
|
||||
} else if (this.root_.left) {
|
||||
return this.findMax(this.root_.left);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array<*>} An array containing all the keys of tree's nodes.
|
||||
*/
|
||||
SplayTree.prototype.exportKeys = function() {
|
||||
var result = [];
|
||||
if (!this.isEmpty()) {
|
||||
this.root_.traverse_(function(node) { result.push(node.key); });
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Perform the splay operation for the given key. Moves the node with
|
||||
* the given key to the top of the tree. If no node has the given
|
||||
* key, the last node on the search path is moved to the top of the
|
||||
* tree. This is the simplified top-down splaying algorithm from:
|
||||
* "Self-adjusting Binary Search Trees" by Sleator and Tarjan
|
||||
*
|
||||
* @param {number} key Key to splay the tree on.
|
||||
* @private
|
||||
*/
|
||||
SplayTree.prototype.splay_ = function(key) {
|
||||
if (this.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// Create a dummy node. The use of the dummy node is a bit
|
||||
// counter-intuitive: The right child of the dummy node will hold
|
||||
// the L tree of the algorithm. The left child of the dummy node
|
||||
// will hold the R tree of the algorithm. Using a dummy node, left
|
||||
// and right will always be nodes and we avoid special cases.
|
||||
var dummy, left, right;
|
||||
dummy = left = right = new SplayTree.Node(null, null);
|
||||
var current = this.root_;
|
||||
while (true) {
|
||||
if (key < current.key) {
|
||||
if (!current.left) {
|
||||
break;
|
||||
}
|
||||
if (key < current.left.key) {
|
||||
// Rotate right.
|
||||
var tmp = current.left;
|
||||
current.left = tmp.right;
|
||||
tmp.right = current;
|
||||
current = tmp;
|
||||
if (!current.left) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Link right.
|
||||
right.left = current;
|
||||
right = current;
|
||||
current = current.left;
|
||||
} else if (key > current.key) {
|
||||
if (!current.right) {
|
||||
break;
|
||||
}
|
||||
if (key > current.right.key) {
|
||||
// Rotate left.
|
||||
var tmp = current.right;
|
||||
current.right = tmp.left;
|
||||
tmp.left = current;
|
||||
current = tmp;
|
||||
if (!current.right) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Link left.
|
||||
left.right = current;
|
||||
left = current;
|
||||
current = current.right;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Assemble.
|
||||
left.right = current.left;
|
||||
right.left = current.right;
|
||||
current.left = dummy.right;
|
||||
current.right = dummy.left;
|
||||
this.root_ = current;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a Splay tree node.
|
||||
*
|
||||
* @param {number} key Key.
|
||||
* @param {*} value Value.
|
||||
*/
|
||||
SplayTree.Node = function(key, value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {SplayTree.Node}
|
||||
*/
|
||||
SplayTree.Node.prototype.left = null;
|
||||
|
||||
|
||||
/**
|
||||
* @type {SplayTree.Node}
|
||||
*/
|
||||
SplayTree.Node.prototype.right = null;
|
||||
|
||||
|
||||
/**
|
||||
* Performs an ordered traversal of the subtree starting at
|
||||
* this SplayTree.Node.
|
||||
*
|
||||
* @param {function(SplayTree.Node)} f Visitor function.
|
||||
* @private
|
||||
*/
|
||||
SplayTree.Node.prototype.traverse_ = function(f) {
|
||||
var current = this;
|
||||
while (current) {
|
||||
var left = current.left;
|
||||
if (left) left.traverse_(f);
|
||||
f(current);
|
||||
current = current.right;
|
||||
}
|
||||
};
|
3
deps/v8/include/v8-debug.h
vendored
3
deps/v8/include/v8-debug.h
vendored
@ -75,7 +75,8 @@ enum DebugEvent {
|
||||
Exception = 2,
|
||||
NewFunction = 3,
|
||||
BeforeCompile = 4,
|
||||
AfterCompile = 5
|
||||
AfterCompile = 5,
|
||||
ScriptCollected = 6
|
||||
};
|
||||
|
||||
|
||||
|
29
deps/v8/include/v8.h
vendored
29
deps/v8/include/v8.h
vendored
@ -41,6 +41,10 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
// When compiling on MinGW stdint.h is available.
|
||||
#ifdef __MINGW32__
|
||||
#include <stdint.h>
|
||||
#else // __MINGW32__
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef short int16_t; // NOLINT
|
||||
@ -49,7 +53,8 @@ typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
// intptr_t is defined in crtdefs.h through stdio.h.
|
||||
// intptr_t and friends are defined in crtdefs.h through stdio.h.
|
||||
#endif // __MINGW32__
|
||||
|
||||
// Setup for Windows DLL export/import. When building the V8 DLL the
|
||||
// BUILDING_V8_SHARED needs to be defined. When building a program which uses
|
||||
@ -1051,7 +1056,7 @@ class V8EXPORT Object : public Value {
|
||||
Handle<Value> value,
|
||||
PropertyAttribute attribs = None);
|
||||
|
||||
// Sets a local property on this object, bypassing interceptors and
|
||||
// Sets a local property on this object bypassing interceptors and
|
||||
// overriding accessors or read-only properties.
|
||||
//
|
||||
// Note that if the object has an interceptor the property will be set
|
||||
@ -1062,13 +1067,21 @@ class V8EXPORT Object : public Value {
|
||||
bool ForceSet(Handle<Value> key,
|
||||
Handle<Value> value,
|
||||
PropertyAttribute attribs = None);
|
||||
|
||||
Local<Value> Get(Handle<Value> key);
|
||||
|
||||
// TODO(1245389): Replace the type-specific versions of these
|
||||
// functions with generic ones that accept a Handle<Value> key.
|
||||
bool Has(Handle<String> key);
|
||||
|
||||
bool Delete(Handle<String> key);
|
||||
|
||||
// Delete a property on this object bypassing interceptors and
|
||||
// ignoring dont-delete attributes.
|
||||
bool ForceDelete(Handle<Value> key);
|
||||
|
||||
bool Has(uint32_t index);
|
||||
|
||||
bool Delete(uint32_t index);
|
||||
|
||||
/**
|
||||
@ -2079,6 +2092,11 @@ class V8EXPORT V8 {
|
||||
*/
|
||||
static void ResumeProfiler();
|
||||
|
||||
/**
|
||||
* Return whether profiler is currently paused.
|
||||
*/
|
||||
static bool IsProfilerPaused();
|
||||
|
||||
/**
|
||||
* If logging is performed into a memory buffer (via --logfile=*), allows to
|
||||
* retrieve previously written messages. This can be used for retrieving
|
||||
@ -2245,6 +2263,13 @@ class V8EXPORT Context {
|
||||
/** Returns the context that is on the top of the stack. */
|
||||
static Local<Context> GetCurrent();
|
||||
|
||||
/**
|
||||
* Returns the context of the calling JavaScript code. That is the
|
||||
* context of the top-most JavaScript frame. If there are no
|
||||
* JavaScript frames an empty handle is returned.
|
||||
*/
|
||||
static Local<Context> GetCalling();
|
||||
|
||||
/**
|
||||
* Sets the security token for the context. To access an object in
|
||||
* another context, the security tokens must match.
|
||||
|
16
deps/v8/src/SConscript
vendored
16
deps/v8/src/SConscript
vendored
@ -43,14 +43,14 @@ SOURCES = {
|
||||
'flags.cc', 'frames.cc', 'func-name-inferrer.cc',
|
||||
'global-handles.cc', 'handles.cc', 'hashmap.cc',
|
||||
'heap.cc', 'ic.cc', 'interpreter-irregexp.cc', 'jsregexp.cc',
|
||||
'jump-target.cc', 'log.cc', 'mark-compact.cc', 'messages.cc', 'objects.cc',
|
||||
'oprofile-agent.cc', 'parser.cc', 'property.cc', 'regexp-macro-assembler.cc',
|
||||
'regexp-macro-assembler-irregexp.cc', 'regexp-stack.cc',
|
||||
'register-allocator.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
|
||||
'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc',
|
||||
'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc',
|
||||
'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc',
|
||||
'v8.cc', 'v8threads.cc', 'variables.cc', 'version.cc',
|
||||
'jump-target.cc', 'log.cc', 'log-utils.cc', 'mark-compact.cc', 'messages.cc',
|
||||
'objects.cc', 'oprofile-agent.cc', 'parser.cc', 'property.cc',
|
||||
'regexp-macro-assembler.cc', 'regexp-macro-assembler-irregexp.cc',
|
||||
'regexp-stack.cc', 'register-allocator.cc', 'rewriter.cc', 'runtime.cc',
|
||||
'scanner.cc', 'scopeinfo.cc', 'scopes.cc', 'serialize.cc',
|
||||
'snapshot-common.cc', 'spaces.cc', 'string-stream.cc', 'stub-cache.cc',
|
||||
'token.cc', 'top.cc', 'unicode.cc', 'usage-analyzer.cc', 'utils.cc',
|
||||
'v8-counters.cc', 'v8.cc', 'v8threads.cc', 'variables.cc', 'version.cc',
|
||||
'virtual-frame.cc', 'zone.cc'
|
||||
],
|
||||
'arch:arm': [
|
||||
|
74
deps/v8/src/accessors.cc
vendored
74
deps/v8/src/accessors.cc
vendored
@ -34,7 +34,8 @@
|
||||
#include "top.h"
|
||||
#include "zone-inl.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
template <class C>
|
||||
@ -287,6 +288,24 @@ const AccessorDescriptor Accessors::ScriptType = {
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Accessors::ScriptCompilationType
|
||||
//
|
||||
|
||||
|
||||
Object* Accessors::ScriptGetCompilationType(Object* object, void*) {
|
||||
Object* script = JSValue::cast(object)->value();
|
||||
return Script::cast(script)->compilation_type();
|
||||
}
|
||||
|
||||
|
||||
const AccessorDescriptor Accessors::ScriptCompilationType = {
|
||||
ScriptGetCompilationType,
|
||||
IllegalSetter,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Accessors::ScriptGetLineEnds
|
||||
//
|
||||
@ -313,9 +332,8 @@ const AccessorDescriptor Accessors::ScriptLineEnds = {
|
||||
|
||||
|
||||
Object* Accessors::ScriptGetContextData(Object* object, void*) {
|
||||
HandleScope scope;
|
||||
Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
|
||||
return script->context_data();
|
||||
Object* script = JSValue::cast(object)->value();
|
||||
return Script::cast(script)->context_data();
|
||||
}
|
||||
|
||||
|
||||
@ -326,6 +344,54 @@ const AccessorDescriptor Accessors::ScriptContextData = {
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Accessors::ScriptGetEvalFromFunction
|
||||
//
|
||||
|
||||
|
||||
Object* Accessors::ScriptGetEvalFromFunction(Object* object, void*) {
|
||||
Object* script = JSValue::cast(object)->value();
|
||||
return Script::cast(script)->eval_from_function();
|
||||
}
|
||||
|
||||
|
||||
const AccessorDescriptor Accessors::ScriptEvalFromFunction = {
|
||||
ScriptGetEvalFromFunction,
|
||||
IllegalSetter,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Accessors::ScriptGetEvalFromPosition
|
||||
//
|
||||
|
||||
|
||||
Object* Accessors::ScriptGetEvalFromPosition(Object* object, void*) {
|
||||
HandleScope scope;
|
||||
Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
|
||||
|
||||
// If this is not a script compiled through eval there is no eval position.
|
||||
int compilation_type = Smi::cast(script->compilation_type())->value();
|
||||
if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
|
||||
return Heap::undefined_value();
|
||||
}
|
||||
|
||||
// Get the function from where eval was called and find the source position
|
||||
// from the instruction offset.
|
||||
Handle<Code> code(JSFunction::cast(script->eval_from_function())->code());
|
||||
return Smi::FromInt(code->SourcePosition(code->instruction_start() +
|
||||
script->eval_from_instructions_offset()->value()));
|
||||
}
|
||||
|
||||
|
||||
const AccessorDescriptor Accessors::ScriptEvalFromPosition = {
|
||||
ScriptGetEvalFromPosition,
|
||||
IllegalSetter,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Accessors::FunctionPrototype
|
||||
//
|
||||
|
41
deps/v8/src/accessors.h
vendored
41
deps/v8/src/accessors.h
vendored
@ -28,27 +28,31 @@
|
||||
#ifndef V8_ACCESSORS_H_
|
||||
#define V8_ACCESSORS_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The list of accessor descriptors. This is a second-order macro
|
||||
// taking a macro to be applied to all accessor descriptor names.
|
||||
#define ACCESSOR_DESCRIPTOR_LIST(V) \
|
||||
V(FunctionPrototype) \
|
||||
V(FunctionLength) \
|
||||
V(FunctionName) \
|
||||
V(FunctionArguments) \
|
||||
V(FunctionCaller) \
|
||||
V(ArrayLength) \
|
||||
V(StringLength) \
|
||||
V(ScriptSource) \
|
||||
V(ScriptName) \
|
||||
V(ScriptId) \
|
||||
V(ScriptLineOffset) \
|
||||
V(ScriptColumnOffset) \
|
||||
V(ScriptData) \
|
||||
V(ScriptType) \
|
||||
V(ScriptLineEnds) \
|
||||
V(ScriptContextData) \
|
||||
V(FunctionPrototype) \
|
||||
V(FunctionLength) \
|
||||
V(FunctionName) \
|
||||
V(FunctionArguments) \
|
||||
V(FunctionCaller) \
|
||||
V(ArrayLength) \
|
||||
V(StringLength) \
|
||||
V(ScriptSource) \
|
||||
V(ScriptName) \
|
||||
V(ScriptId) \
|
||||
V(ScriptLineOffset) \
|
||||
V(ScriptColumnOffset) \
|
||||
V(ScriptData) \
|
||||
V(ScriptType) \
|
||||
V(ScriptCompilationType) \
|
||||
V(ScriptLineEnds) \
|
||||
V(ScriptContextData) \
|
||||
V(ScriptEvalFromFunction) \
|
||||
V(ScriptEvalFromPosition) \
|
||||
V(ObjectPrototype)
|
||||
|
||||
// Accessors contains all predefined proxy accessors.
|
||||
@ -88,8 +92,11 @@ class Accessors : public AllStatic {
|
||||
static Object* ScriptGetColumnOffset(Object* object, void*);
|
||||
static Object* ScriptGetData(Object* object, void*);
|
||||
static Object* ScriptGetType(Object* object, void*);
|
||||
static Object* ScriptGetCompilationType(Object* object, void*);
|
||||
static Object* ScriptGetLineEnds(Object* object, void*);
|
||||
static Object* ScriptGetContextData(Object* object, void*);
|
||||
static Object* ScriptGetEvalFromFunction(Object* object, void*);
|
||||
static Object* ScriptGetEvalFromPosition(Object* object, void*);
|
||||
static Object* ObjectGetPrototype(Object* receiver, void*);
|
||||
static Object* ObjectSetPrototype(JSObject* receiver, Object* value, void*);
|
||||
|
||||
|
3
deps/v8/src/allocation.cc
vendored
3
deps/v8/src/allocation.cc
vendored
@ -29,7 +29,8 @@
|
||||
|
||||
#include "v8.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
void* Malloced::New(size_t size) {
|
||||
|
3
deps/v8/src/allocation.h
vendored
3
deps/v8/src/allocation.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_ALLOCATION_H_
|
||||
#define V8_ALLOCATION_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// A class that controls whether allocation is allowed. This is for
|
||||
|
84
deps/v8/src/api.cc
vendored
84
deps/v8/src/api.cc
vendored
@ -99,7 +99,6 @@ static i::HandleScopeImplementer thread_local;
|
||||
// --- E x c e p t i o n B e h a v i o r ---
|
||||
|
||||
|
||||
static bool has_shut_down = false;
|
||||
static FatalErrorCallback exception_behavior = NULL;
|
||||
|
||||
|
||||
@ -123,7 +122,7 @@ static FatalErrorCallback& GetFatalErrorHandler() {
|
||||
// When V8 cannot allocated memory FatalProcessOutOfMemory is called.
|
||||
// The default fatal error handler is called and execution is stopped.
|
||||
void i::V8::FatalProcessOutOfMemory(const char* location) {
|
||||
has_shut_down = true;
|
||||
i::V8::SetFatalError();
|
||||
FatalErrorCallback callback = GetFatalErrorHandler();
|
||||
{
|
||||
LEAVE_V8;
|
||||
@ -142,13 +141,13 @@ void V8::SetFatalErrorHandler(FatalErrorCallback that) {
|
||||
bool Utils::ReportApiFailure(const char* location, const char* message) {
|
||||
FatalErrorCallback callback = GetFatalErrorHandler();
|
||||
callback(location, message);
|
||||
has_shut_down = true;
|
||||
i::V8::SetFatalError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool V8::IsDead() {
|
||||
return has_shut_down;
|
||||
return i::V8::IsDead();
|
||||
}
|
||||
|
||||
|
||||
@ -186,7 +185,8 @@ static bool ReportEmptyHandle(const char* location) {
|
||||
* yet been done.
|
||||
*/
|
||||
static inline bool IsDeadCheck(const char* location) {
|
||||
return has_shut_down ? ReportV8Dead(location) : false;
|
||||
return !i::V8::IsRunning()
|
||||
&& i::V8::IsDead() ? ReportV8Dead(location) : false;
|
||||
}
|
||||
|
||||
|
||||
@ -205,9 +205,14 @@ static inline bool EmptyCheck(const char* location, const v8::Data* obj) {
|
||||
static i::StringInputBuffer write_input_buffer;
|
||||
|
||||
|
||||
static void EnsureInitialized(const char* location) {
|
||||
if (IsDeadCheck(location)) return;
|
||||
ApiCheck(v8::V8::Initialize(), location, "Error initializing V8");
|
||||
static inline bool EnsureInitialized(const char* location) {
|
||||
if (i::V8::IsRunning()) {
|
||||
return true;
|
||||
}
|
||||
if (IsDeadCheck(location)) {
|
||||
return false;
|
||||
}
|
||||
return ApiCheck(v8::V8::Initialize(), location, "Error initializing V8");
|
||||
}
|
||||
|
||||
|
||||
@ -225,29 +230,25 @@ void ImplementationUtilities::ZapHandleRange(void** begin, void** end) {
|
||||
|
||||
|
||||
v8::Handle<v8::Primitive> ImplementationUtilities::Undefined() {
|
||||
if (IsDeadCheck("v8::Undefined()")) return v8::Handle<v8::Primitive>();
|
||||
EnsureInitialized("v8::Undefined()");
|
||||
if (!EnsureInitialized("v8::Undefined()")) return v8::Handle<v8::Primitive>();
|
||||
return v8::Handle<Primitive>(ToApi<Primitive>(i::Factory::undefined_value()));
|
||||
}
|
||||
|
||||
|
||||
v8::Handle<v8::Primitive> ImplementationUtilities::Null() {
|
||||
if (IsDeadCheck("v8::Null()")) return v8::Handle<v8::Primitive>();
|
||||
EnsureInitialized("v8::Null()");
|
||||
if (!EnsureInitialized("v8::Null()")) return v8::Handle<v8::Primitive>();
|
||||
return v8::Handle<Primitive>(ToApi<Primitive>(i::Factory::null_value()));
|
||||
}
|
||||
|
||||
|
||||
v8::Handle<v8::Boolean> ImplementationUtilities::True() {
|
||||
if (IsDeadCheck("v8::True()")) return v8::Handle<v8::Boolean>();
|
||||
EnsureInitialized("v8::True()");
|
||||
if (!EnsureInitialized("v8::True()")) return v8::Handle<v8::Boolean>();
|
||||
return v8::Handle<v8::Boolean>(ToApi<Boolean>(i::Factory::true_value()));
|
||||
}
|
||||
|
||||
|
||||
v8::Handle<v8::Boolean> ImplementationUtilities::False() {
|
||||
if (IsDeadCheck("v8::False()")) return v8::Handle<v8::Boolean>();
|
||||
EnsureInitialized("v8::False()");
|
||||
if (!EnsureInitialized("v8::False()")) return v8::Handle<v8::Boolean>();
|
||||
return v8::Handle<v8::Boolean>(ToApi<Boolean>(i::Factory::false_value()));
|
||||
}
|
||||
|
||||
@ -373,21 +374,21 @@ void V8::ClearWeak(void** obj) {
|
||||
|
||||
bool V8::IsGlobalNearDeath(void** obj) {
|
||||
LOG_API("IsGlobalNearDeath");
|
||||
if (has_shut_down) return false;
|
||||
if (!i::V8::IsRunning()) return false;
|
||||
return i::GlobalHandles::IsNearDeath(reinterpret_cast<i::Object**>(obj));
|
||||
}
|
||||
|
||||
|
||||
bool V8::IsGlobalWeak(void** obj) {
|
||||
LOG_API("IsGlobalWeak");
|
||||
if (has_shut_down) return false;
|
||||
if (!i::V8::IsRunning()) return false;
|
||||
return i::GlobalHandles::IsWeak(reinterpret_cast<i::Object**>(obj));
|
||||
}
|
||||
|
||||
|
||||
void V8::DisposeGlobal(void** obj) {
|
||||
LOG_API("DisposeGlobal");
|
||||
if (has_shut_down) return;
|
||||
if (!i::V8::IsRunning()) return;
|
||||
i::Object** ptr = reinterpret_cast<i::Object**>(obj);
|
||||
if ((*ptr)->IsGlobalContext()) i::Heap::NotifyContextDisposed();
|
||||
i::GlobalHandles::Destroy(ptr);
|
||||
@ -415,7 +416,8 @@ int HandleScope::NumberOfHandles() {
|
||||
|
||||
|
||||
void** v8::HandleScope::CreateHandle(void* value) {
|
||||
return i::HandleScope::CreateHandle(value);
|
||||
return reinterpret_cast<void**>(
|
||||
i::HandleScope::CreateHandle(reinterpret_cast<i::Object*>(value)));
|
||||
}
|
||||
|
||||
|
||||
@ -431,7 +433,7 @@ void Context::Enter() {
|
||||
|
||||
|
||||
void Context::Exit() {
|
||||
if (has_shut_down) return;
|
||||
if (!i::V8::IsRunning()) return;
|
||||
if (!ApiCheck(thread_local.LeaveLastContext(),
|
||||
"v8::Context::Exit()",
|
||||
"Cannot exit non-entered context")) {
|
||||
@ -1890,6 +1892,19 @@ bool v8::Object::ForceSet(v8::Handle<Value> key,
|
||||
}
|
||||
|
||||
|
||||
bool v8::Object::ForceDelete(v8::Handle<Value> key) {
|
||||
ON_BAILOUT("v8::Object::ForceDelete()", return false);
|
||||
ENTER_V8;
|
||||
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
|
||||
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
|
||||
EXCEPTION_PREAMBLE();
|
||||
i::Handle<i::Object> obj = i::ForceDeleteProperty(self, key_obj);
|
||||
has_pending_exception = obj.is_null();
|
||||
EXCEPTION_BAILOUT_CHECK(false);
|
||||
return obj->IsTrue();
|
||||
}
|
||||
|
||||
|
||||
Local<Value> v8::Object::Get(v8::Handle<Value> key) {
|
||||
ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>());
|
||||
ENTER_V8;
|
||||
@ -2450,7 +2465,7 @@ void v8::Object::SetInternalField(int index, v8::Handle<Value> value) {
|
||||
// --- E n v i r o n m e n t ---
|
||||
|
||||
bool v8::V8::Initialize() {
|
||||
if (i::V8::HasBeenSetup()) return true;
|
||||
if (i::V8::IsRunning()) return true;
|
||||
ENTER_V8;
|
||||
HandleScope scope;
|
||||
if (i::Snapshot::Initialize()) {
|
||||
@ -2612,6 +2627,13 @@ v8::Local<v8::Context> Context::GetCurrent() {
|
||||
}
|
||||
|
||||
|
||||
v8::Local<v8::Context> Context::GetCalling() {
|
||||
if (IsDeadCheck("v8::Context::GetCalling()")) return Local<Context>();
|
||||
i::Handle<i::Context> context(i::Top::GetCallingGlobalContext());
|
||||
return Utils::ToLocal(context);
|
||||
}
|
||||
|
||||
|
||||
v8::Local<v8::Object> Context::Global() {
|
||||
if (IsDeadCheck("v8::Context::Global()")) return Local<v8::Object>();
|
||||
i::Object** ctx = reinterpret_cast<i::Object**>(this);
|
||||
@ -3116,16 +3138,28 @@ void V8::PauseProfiler() {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void V8::ResumeProfiler() {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
i::Logger::ResumeProfiler();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool V8::IsProfilerPaused() {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
return i::Logger::IsProfilerPaused();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int V8::GetLogLines(int from_pos, char* dest_buf, int max_size) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
return i::Logger::GetLogLines(from_pos, dest_buf, max_size);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) {
|
||||
@ -3312,7 +3346,7 @@ bool Debug::SetDebugEventListener(v8::Handle<v8::Object> that,
|
||||
|
||||
|
||||
void Debug::DebugBreak() {
|
||||
if (!i::V8::HasBeenSetup()) return;
|
||||
if (!i::V8::IsRunning()) return;
|
||||
i::StackGuard::DebugBreak();
|
||||
}
|
||||
|
||||
@ -3354,7 +3388,7 @@ void Debug::SetMessageHandler2(v8::Debug::MessageHandler2 handler) {
|
||||
|
||||
void Debug::SendCommand(const uint16_t* command, int length,
|
||||
ClientData* client_data) {
|
||||
if (!i::V8::HasBeenSetup()) return;
|
||||
if (!i::V8::IsRunning()) return;
|
||||
i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length),
|
||||
client_data);
|
||||
}
|
||||
@ -3370,7 +3404,7 @@ void Debug::SetHostDispatchHandler(HostDispatchHandler handler,
|
||||
|
||||
Handle<Value> Debug::Call(v8::Handle<v8::Function> fun,
|
||||
v8::Handle<v8::Value> data) {
|
||||
if (!i::V8::HasBeenSetup()) return Handle<Value>();
|
||||
if (!i::V8::IsRunning()) return Handle<Value>();
|
||||
ON_BAILOUT("v8::Debug::Call()", return Handle<Value>());
|
||||
ENTER_V8;
|
||||
i::Handle<i::Object> result;
|
||||
|
3
deps/v8/src/arguments.h
vendored
3
deps/v8/src/arguments.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_ARGUMENTS_H_
|
||||
#define V8_ARGUMENTS_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Arguments provides access to runtime call parameters.
|
||||
//
|
||||
|
3
deps/v8/src/arm/assembler-arm-inl.h
vendored
3
deps/v8/src/arm/assembler-arm-inl.h
vendored
@ -41,7 +41,8 @@
|
||||
#include "cpu.h"
|
||||
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
Condition NegateCondition(Condition cc) {
|
||||
ASSERT(cc != al);
|
||||
|
7
deps/v8/src/arm/assembler-arm.cc
vendored
7
deps/v8/src/arm/assembler-arm.cc
vendored
@ -39,7 +39,8 @@
|
||||
#include "arm/assembler-arm-inl.h"
|
||||
#include "serialize.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register and CRegister
|
||||
@ -211,6 +212,7 @@ enum {
|
||||
// Instruction bit masks
|
||||
RdMask = 15 << 12, // in str instruction
|
||||
CondMask = 15 << 28,
|
||||
CoprocessorMask = 15 << 8,
|
||||
OpCodeMask = 15 << 21, // in data-processing instructions
|
||||
Imm24Mask = (1 << 24) - 1,
|
||||
Off12Mask = (1 << 12) - 1,
|
||||
@ -616,7 +618,8 @@ void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
|
||||
|
||||
void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
|
||||
// unindexed addressing is not encoded by this function
|
||||
ASSERT((instr & ~(CondMask | P | U | N | W | L)) == (B27 | B26));
|
||||
ASSERT_EQ((B27 | B26),
|
||||
(instr & ~(CondMask | CoprocessorMask | P | U | N | W | L)));
|
||||
ASSERT(x.rn_.is_valid() && !x.rm_.is_valid());
|
||||
int am = x.am_;
|
||||
int offset_8 = x.offset_;
|
||||
|
9
deps/v8/src/arm/assembler-arm.h
vendored
9
deps/v8/src/arm/assembler-arm.h
vendored
@ -42,7 +42,8 @@
|
||||
|
||||
#include "assembler.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// CPU Registers.
|
||||
//
|
||||
@ -83,8 +84,6 @@ struct Register {
|
||||
};
|
||||
|
||||
|
||||
const int kNumRegisters = 16;
|
||||
|
||||
extern Register no_reg;
|
||||
extern Register r0;
|
||||
extern Register r1;
|
||||
@ -622,8 +621,8 @@ class Assembler : public Malloced {
|
||||
// Pseudo instructions
|
||||
void nop() { mov(r0, Operand(r0)); }
|
||||
|
||||
void push(Register src) {
|
||||
str(src, MemOperand(sp, 4, NegPreIndex), al);
|
||||
void push(Register src, Condition cond = al) {
|
||||
str(src, MemOperand(sp, 4, NegPreIndex), cond);
|
||||
}
|
||||
|
||||
void pop(Register dst) {
|
||||
|
5
deps/v8/src/arm/builtins-arm.cc
vendored
5
deps/v8/src/arm/builtins-arm.cc
vendored
@ -31,7 +31,8 @@
|
||||
#include "debug.h"
|
||||
#include "runtime.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
#define __ ACCESS_MASM(masm)
|
||||
@ -187,7 +188,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
|
||||
|
||||
// Set expected number of arguments to zero (not changing r0).
|
||||
__ mov(r2, Operand(0));
|
||||
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
|
||||
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
|
||||
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
||||
RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
46
deps/v8/src/arm/codegen-arm-inl.h
vendored
Normal file
46
deps/v8/src/arm/codegen-arm-inl.h
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
|
||||
#ifndef V8_ARM_CODEGEN_ARM_INL_H_
|
||||
#define V8_ARM_CODEGEN_ARM_INL_H_
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ ACCESS_MASM(masm_)
|
||||
|
||||
// Platform-specific inline functions.
|
||||
|
||||
void DeferredCode::Jump() { __ jmp(&entry_label_); }
|
||||
void DeferredCode::Branch(Condition cc) { __ b(cc, &entry_label_); }
|
||||
|
||||
#undef __
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_ARM_CODEGEN_ARM_INL_H_
|
596
deps/v8/src/arm/codegen-arm.cc
vendored
596
deps/v8/src/arm/codegen-arm.cc
vendored
File diff suppressed because it is too large
Load Diff
11
deps/v8/src/arm/codegen-arm.h
vendored
11
deps/v8/src/arm/codegen-arm.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_ARM_CODEGEN_ARM_H_
|
||||
#define V8_ARM_CODEGEN_ARM_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Forward declarations
|
||||
class DeferredCode;
|
||||
@ -193,8 +194,7 @@ class CodeGenerator: public AstVisitor {
|
||||
// Accessors
|
||||
Scope* scope() const { return scope_; }
|
||||
|
||||
// Clearing and generating deferred code.
|
||||
void ClearDeferred();
|
||||
// Generating deferred code.
|
||||
void ProcessDeferred();
|
||||
|
||||
bool is_eval() { return is_eval_; }
|
||||
@ -205,6 +205,8 @@ class CodeGenerator: public AstVisitor {
|
||||
JumpTarget* true_target() const { return state_->true_target(); }
|
||||
JumpTarget* false_target() const { return state_->false_target(); }
|
||||
|
||||
// We don't track loop nesting level on ARM yet.
|
||||
int loop_nesting() const { return 0; }
|
||||
|
||||
// Node visitors.
|
||||
void VisitStatements(ZoneList<Statement*>* statements);
|
||||
@ -317,8 +319,7 @@ class CodeGenerator: public AstVisitor {
|
||||
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
|
||||
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
|
||||
|
||||
Handle<Code> ComputeCallInitialize(int argc);
|
||||
Handle<Code> ComputeCallInitializeInLoop(int argc);
|
||||
Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
|
||||
|
||||
// Declare global variables and functions in the given array of
|
||||
// name/value pairs.
|
||||
|
3
deps/v8/src/arm/constants-arm.h
vendored
3
deps/v8/src/arm/constants-arm.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_ARM_CONSTANTS_ARM_H_
|
||||
#define V8_ARM_CONSTANTS_ARM_H_
|
||||
|
||||
namespace assembler { namespace arm {
|
||||
namespace assembler {
|
||||
namespace arm {
|
||||
|
||||
// Defines constants and accessor classes to assemble, disassemble and
|
||||
// simulate ARM instructions.
|
||||
|
3
deps/v8/src/arm/cpu-arm.cc
vendored
3
deps/v8/src/arm/cpu-arm.cc
vendored
@ -34,7 +34,8 @@
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
void CPU::Setup() {
|
||||
// Nothing to do.
|
||||
|
3
deps/v8/src/arm/debug-arm.cc
vendored
3
deps/v8/src/arm/debug-arm.cc
vendored
@ -30,7 +30,8 @@
|
||||
#include "codegen-inl.h"
|
||||
#include "debug.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
// Currently debug break is not supported in frame exit code on ARM.
|
||||
|
3
deps/v8/src/arm/disasm-arm.cc
vendored
3
deps/v8/src/arm/disasm-arm.cc
vendored
@ -62,7 +62,8 @@
|
||||
#include "platform.h"
|
||||
|
||||
|
||||
namespace assembler { namespace arm {
|
||||
namespace assembler {
|
||||
namespace arm {
|
||||
|
||||
namespace v8i = v8::internal;
|
||||
|
||||
|
3
deps/v8/src/arm/frames-arm.cc
vendored
3
deps/v8/src/arm/frames-arm.cc
vendored
@ -31,7 +31,8 @@
|
||||
#include "arm/assembler-arm-inl.h"
|
||||
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
StackFrame::Type StackFrame::ComputeType(State* state) {
|
||||
|
3
deps/v8/src/arm/frames-arm.h
vendored
3
deps/v8/src/arm/frames-arm.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_ARM_FRAMES_ARM_H_
|
||||
#define V8_ARM_FRAMES_ARM_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// The ARM ABI does not specify the usage of register r9, which may be reserved
|
||||
|
13
deps/v8/src/arm/ic-arm.cc
vendored
13
deps/v8/src/arm/ic-arm.cc
vendored
@ -32,7 +32,8 @@
|
||||
#include "runtime.h"
|
||||
#include "stub-cache.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -211,7 +212,7 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
|
||||
// Probe the stub cache.
|
||||
Code::Flags flags =
|
||||
Code::ComputeFlags(Code::CALL_IC, MONOMORPHIC, NORMAL, argc);
|
||||
Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
|
||||
StubCache::GenerateProbe(masm, flags, r1, r2, r3);
|
||||
|
||||
// If the stub cache probing failed, the receiver might be a value.
|
||||
@ -422,7 +423,9 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
|
||||
|
||||
__ ldr(r0, MemOperand(sp, 0));
|
||||
// Probe the stub cache.
|
||||
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
|
||||
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
|
||||
NOT_IN_LOOP,
|
||||
MONOMORPHIC);
|
||||
StubCache::GenerateProbe(masm, flags, r0, r2, r3);
|
||||
|
||||
// Cache miss: Jump to runtime.
|
||||
@ -755,7 +758,9 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
||||
|
||||
// Get the receiver from the stack and probe the stub cache.
|
||||
__ ldr(r1, MemOperand(sp));
|
||||
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC);
|
||||
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
|
||||
NOT_IN_LOOP,
|
||||
MONOMORPHIC);
|
||||
StubCache::GenerateProbe(masm, flags, r1, r2, r3);
|
||||
|
||||
// Cache miss: Jump to runtime.
|
||||
|
147
deps/v8/src/arm/jump-target-arm.cc
vendored
147
deps/v8/src/arm/jump-target-arm.cc
vendored
@ -28,46 +28,47 @@
|
||||
#include "v8.h"
|
||||
|
||||
#include "codegen-inl.h"
|
||||
#include "jump-target-inl.h"
|
||||
#include "register-allocator-inl.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// JumpTarget implementation.
|
||||
|
||||
#define __ ACCESS_MASM(masm_)
|
||||
#define __ ACCESS_MASM(cgen()->masm())
|
||||
|
||||
void JumpTarget::DoJump() {
|
||||
ASSERT(cgen_ != NULL);
|
||||
ASSERT(cgen_->has_valid_frame());
|
||||
ASSERT(cgen()->has_valid_frame());
|
||||
// Live non-frame registers are not allowed at unconditional jumps
|
||||
// because we have no way of invalidating the corresponding results
|
||||
// which are still live in the C++ code.
|
||||
ASSERT(cgen_->HasValidEntryRegisters());
|
||||
ASSERT(cgen()->HasValidEntryRegisters());
|
||||
|
||||
if (is_bound()) {
|
||||
// Backward jump. There is an expected frame to merge to.
|
||||
ASSERT(direction_ == BIDIRECTIONAL);
|
||||
cgen_->frame()->MergeTo(entry_frame_);
|
||||
cgen_->DeleteFrame();
|
||||
cgen()->frame()->PrepareMergeTo(entry_frame_);
|
||||
cgen()->frame()->MergeTo(entry_frame_);
|
||||
cgen()->DeleteFrame();
|
||||
__ jmp(&entry_label_);
|
||||
} else {
|
||||
// Preconfigured entry frame is not used on ARM.
|
||||
ASSERT(entry_frame_ == NULL);
|
||||
// Forward jump. The current frame is added to the end of the list
|
||||
// of frames reaching the target block and a jump to the merge code
|
||||
// is emitted.
|
||||
AddReachingFrame(cgen_->frame());
|
||||
AddReachingFrame(cgen()->frame());
|
||||
RegisterFile empty;
|
||||
cgen_->SetFrame(NULL, &empty);
|
||||
cgen()->SetFrame(NULL, &empty);
|
||||
__ jmp(&merge_labels_.last());
|
||||
}
|
||||
|
||||
is_linked_ = !is_bound_;
|
||||
}
|
||||
|
||||
|
||||
void JumpTarget::DoBranch(Condition cc, Hint ignored) {
|
||||
ASSERT(cgen_ != NULL);
|
||||
ASSERT(cgen_->has_valid_frame());
|
||||
ASSERT(cgen()->has_valid_frame());
|
||||
|
||||
if (is_bound()) {
|
||||
ASSERT(direction_ == BIDIRECTIONAL);
|
||||
@ -77,29 +78,29 @@ void JumpTarget::DoBranch(Condition cc, Hint ignored) {
|
||||
// Swap the current frame for a copy (we do the swapping to get
|
||||
// the off-frame registers off the fall through) to use for the
|
||||
// branch.
|
||||
VirtualFrame* fall_through_frame = cgen_->frame();
|
||||
VirtualFrame* fall_through_frame = cgen()->frame();
|
||||
VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame);
|
||||
RegisterFile non_frame_registers = RegisterAllocator::Reserved();
|
||||
cgen_->SetFrame(branch_frame, &non_frame_registers);
|
||||
RegisterFile non_frame_registers;
|
||||
cgen()->SetFrame(branch_frame, &non_frame_registers);
|
||||
|
||||
// Check if we can avoid merge code.
|
||||
cgen_->frame()->PrepareMergeTo(entry_frame_);
|
||||
if (cgen_->frame()->Equals(entry_frame_)) {
|
||||
cgen()->frame()->PrepareMergeTo(entry_frame_);
|
||||
if (cgen()->frame()->Equals(entry_frame_)) {
|
||||
// Branch right in to the block.
|
||||
cgen_->DeleteFrame();
|
||||
cgen()->DeleteFrame();
|
||||
__ b(cc, &entry_label_);
|
||||
cgen_->SetFrame(fall_through_frame, &non_frame_registers);
|
||||
cgen()->SetFrame(fall_through_frame, &non_frame_registers);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we can reuse existing merge code.
|
||||
for (int i = 0; i < reaching_frames_.length(); i++) {
|
||||
if (reaching_frames_[i] != NULL &&
|
||||
cgen_->frame()->Equals(reaching_frames_[i])) {
|
||||
cgen()->frame()->Equals(reaching_frames_[i])) {
|
||||
// Branch to the merge code.
|
||||
cgen_->DeleteFrame();
|
||||
cgen()->DeleteFrame();
|
||||
__ b(cc, &merge_labels_[i]);
|
||||
cgen_->SetFrame(fall_through_frame, &non_frame_registers);
|
||||
cgen()->SetFrame(fall_through_frame, &non_frame_registers);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -108,19 +109,20 @@ void JumpTarget::DoBranch(Condition cc, Hint ignored) {
|
||||
// around the merge code on the fall through path.
|
||||
Label original_fall_through;
|
||||
__ b(NegateCondition(cc), &original_fall_through);
|
||||
cgen_->frame()->MergeTo(entry_frame_);
|
||||
cgen_->DeleteFrame();
|
||||
cgen()->frame()->MergeTo(entry_frame_);
|
||||
cgen()->DeleteFrame();
|
||||
__ b(&entry_label_);
|
||||
cgen_->SetFrame(fall_through_frame, &non_frame_registers);
|
||||
cgen()->SetFrame(fall_through_frame, &non_frame_registers);
|
||||
__ bind(&original_fall_through);
|
||||
|
||||
} else {
|
||||
// Preconfigured entry frame is not used on ARM.
|
||||
ASSERT(entry_frame_ == NULL);
|
||||
// Forward branch. A copy of the current frame is added to the end
|
||||
// of the list of frames reaching the target block and a branch to
|
||||
// the merge code is emitted.
|
||||
AddReachingFrame(new VirtualFrame(cgen_->frame()));
|
||||
AddReachingFrame(new VirtualFrame(cgen()->frame()));
|
||||
__ b(cc, &merge_labels_.last());
|
||||
is_linked_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,70 +134,63 @@ void JumpTarget::Call() {
|
||||
// at the label (which should be the only one) is the spilled current
|
||||
// frame plus an in-memory return address. The "fall-through" frame
|
||||
// at the return site is the spilled current frame.
|
||||
ASSERT(cgen_ != NULL);
|
||||
ASSERT(cgen_->has_valid_frame());
|
||||
ASSERT(cgen()->has_valid_frame());
|
||||
// There are no non-frame references across the call.
|
||||
ASSERT(cgen_->HasValidEntryRegisters());
|
||||
ASSERT(cgen()->HasValidEntryRegisters());
|
||||
ASSERT(!is_linked());
|
||||
|
||||
cgen_->frame()->SpillAll();
|
||||
VirtualFrame* target_frame = new VirtualFrame(cgen_->frame());
|
||||
cgen()->frame()->SpillAll();
|
||||
VirtualFrame* target_frame = new VirtualFrame(cgen()->frame());
|
||||
target_frame->Adjust(1);
|
||||
// We do not expect a call with a preconfigured entry frame.
|
||||
ASSERT(entry_frame_ == NULL);
|
||||
AddReachingFrame(target_frame);
|
||||
__ bl(&merge_labels_.last());
|
||||
|
||||
is_linked_ = !is_bound_;
|
||||
}
|
||||
|
||||
|
||||
void JumpTarget::DoBind(int mergable_elements) {
|
||||
ASSERT(cgen_ != NULL);
|
||||
ASSERT(!is_bound());
|
||||
|
||||
// Live non-frame registers are not allowed at the start of a basic
|
||||
// block.
|
||||
ASSERT(!cgen_->has_valid_frame() || cgen_->HasValidEntryRegisters());
|
||||
ASSERT(!cgen()->has_valid_frame() || cgen()->HasValidEntryRegisters());
|
||||
|
||||
if (direction_ == FORWARD_ONLY) {
|
||||
// A simple case: no forward jumps and no possible backward jumps.
|
||||
if (!is_linked()) {
|
||||
// The stack pointer can be floating above the top of the
|
||||
// virtual frame before the bind. Afterward, it should not.
|
||||
ASSERT(cgen_->has_valid_frame());
|
||||
VirtualFrame* frame = cgen_->frame();
|
||||
int difference =
|
||||
frame->stack_pointer_ - (frame->elements_.length() - 1);
|
||||
ASSERT(cgen()->has_valid_frame());
|
||||
VirtualFrame* frame = cgen()->frame();
|
||||
int difference = frame->stack_pointer_ - (frame->element_count() - 1);
|
||||
if (difference > 0) {
|
||||
frame->stack_pointer_ -= difference;
|
||||
__ add(sp, sp, Operand(difference * kPointerSize));
|
||||
}
|
||||
|
||||
is_bound_ = true;
|
||||
__ bind(&entry_label_);
|
||||
return;
|
||||
}
|
||||
|
||||
// Another simple case: no fall through, a single forward jump,
|
||||
// and no possible backward jumps.
|
||||
if (!cgen_->has_valid_frame() && reaching_frames_.length() == 1) {
|
||||
if (!cgen()->has_valid_frame() && reaching_frames_.length() == 1) {
|
||||
// Pick up the only reaching frame, take ownership of it, and
|
||||
// use it for the block about to be emitted.
|
||||
VirtualFrame* frame = reaching_frames_[0];
|
||||
RegisterFile reserved = RegisterAllocator::Reserved();
|
||||
cgen_->SetFrame(frame, &reserved);
|
||||
RegisterFile empty;
|
||||
cgen()->SetFrame(frame, &empty);
|
||||
reaching_frames_[0] = NULL;
|
||||
__ bind(&merge_labels_[0]);
|
||||
|
||||
// The stack pointer can be floating above the top of the
|
||||
// virtual frame before the bind. Afterward, it should not.
|
||||
int difference =
|
||||
frame->stack_pointer_ - (frame->elements_.length() - 1);
|
||||
int difference = frame->stack_pointer_ - (frame->element_count() - 1);
|
||||
if (difference > 0) {
|
||||
frame->stack_pointer_ -= difference;
|
||||
__ add(sp, sp, Operand(difference * kPointerSize));
|
||||
}
|
||||
|
||||
is_linked_ = false;
|
||||
is_bound_ = true;
|
||||
__ bind(&entry_label_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -203,15 +198,17 @@ void JumpTarget::DoBind(int mergable_elements) {
|
||||
// If there is a current frame, record it as the fall-through. It
|
||||
// is owned by the reaching frames for now.
|
||||
bool had_fall_through = false;
|
||||
if (cgen_->has_valid_frame()) {
|
||||
if (cgen()->has_valid_frame()) {
|
||||
had_fall_through = true;
|
||||
AddReachingFrame(cgen_->frame());
|
||||
AddReachingFrame(cgen()->frame()); // Return value ignored.
|
||||
RegisterFile empty;
|
||||
cgen_->SetFrame(NULL, &empty);
|
||||
cgen()->SetFrame(NULL, &empty);
|
||||
}
|
||||
|
||||
// Compute the frame to use for entry to the block.
|
||||
ComputeEntryFrame(mergable_elements);
|
||||
if (entry_frame_ == NULL) {
|
||||
ComputeEntryFrame(mergable_elements);
|
||||
}
|
||||
|
||||
// Some moves required to merge to an expected frame require purely
|
||||
// frame state changes, and do not require any code generation.
|
||||
@ -242,17 +239,17 @@ void JumpTarget::DoBind(int mergable_elements) {
|
||||
// binding site or as the fall through from a previous merge
|
||||
// code block. Jump around the code we are about to
|
||||
// generate.
|
||||
if (cgen_->has_valid_frame()) {
|
||||
cgen_->DeleteFrame();
|
||||
if (cgen()->has_valid_frame()) {
|
||||
cgen()->DeleteFrame();
|
||||
__ b(&entry_label_);
|
||||
}
|
||||
// Pick up the frame for this block. Assume ownership if
|
||||
// there cannot be backward jumps.
|
||||
RegisterFile reserved = RegisterAllocator::Reserved();
|
||||
RegisterFile empty;
|
||||
if (direction_ == BIDIRECTIONAL) {
|
||||
cgen_->SetFrame(new VirtualFrame(frame), &reserved);
|
||||
cgen()->SetFrame(new VirtualFrame(frame), &empty);
|
||||
} else {
|
||||
cgen_->SetFrame(frame, &reserved);
|
||||
cgen()->SetFrame(frame, &empty);
|
||||
reaching_frames_[i] = NULL;
|
||||
}
|
||||
__ bind(&merge_labels_[i]);
|
||||
@ -261,23 +258,22 @@ void JumpTarget::DoBind(int mergable_elements) {
|
||||
// looking for any that can share merge code with this one.
|
||||
for (int j = 0; j < i; j++) {
|
||||
VirtualFrame* other = reaching_frames_[j];
|
||||
if (other != NULL && other->Equals(cgen_->frame())) {
|
||||
if (other != NULL && other->Equals(cgen()->frame())) {
|
||||
// Set the reaching frame element to null to avoid
|
||||
// processing it later, and then bind its entry label.
|
||||
delete other;
|
||||
reaching_frames_[j] = NULL;
|
||||
__ bind(&merge_labels_[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the merge code.
|
||||
cgen_->frame()->MergeTo(entry_frame_);
|
||||
cgen()->frame()->MergeTo(entry_frame_);
|
||||
} else if (i == reaching_frames_.length() - 1 && had_fall_through) {
|
||||
// If this is the fall through, and it didn't need merge
|
||||
// code, we need to pick up the frame so we can jump around
|
||||
// subsequent merge blocks if necessary.
|
||||
RegisterFile reserved = RegisterAllocator::Reserved();
|
||||
cgen_->SetFrame(frame, &reserved);
|
||||
RegisterFile empty;
|
||||
cgen()->SetFrame(frame, &empty);
|
||||
reaching_frames_[i] = NULL;
|
||||
}
|
||||
}
|
||||
@ -286,22 +282,17 @@ void JumpTarget::DoBind(int mergable_elements) {
|
||||
// The code generator may not have a current frame if there was no
|
||||
// fall through and none of the reaching frames needed merging.
|
||||
// In that case, clone the entry frame as the current frame.
|
||||
if (!cgen_->has_valid_frame()) {
|
||||
RegisterFile reserved_registers = RegisterAllocator::Reserved();
|
||||
cgen_->SetFrame(new VirtualFrame(entry_frame_), &reserved_registers);
|
||||
if (!cgen()->has_valid_frame()) {
|
||||
RegisterFile empty;
|
||||
cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
|
||||
}
|
||||
|
||||
// There is certainly a current frame equal to the entry frame.
|
||||
// Bind the entry frame label.
|
||||
__ bind(&entry_label_);
|
||||
|
||||
// There may be unprocessed reaching frames that did not need
|
||||
// merge code. They will have unbound merge labels. Bind their
|
||||
// merge labels to be the same as the entry label and deallocate
|
||||
// them.
|
||||
for (int i = 0; i < reaching_frames_.length(); i++) {
|
||||
if (!merge_labels_[i].is_bound()) {
|
||||
delete reaching_frames_[i];
|
||||
reaching_frames_[i] = NULL;
|
||||
__ bind(&merge_labels_[i]);
|
||||
}
|
||||
@ -318,15 +309,13 @@ void JumpTarget::DoBind(int mergable_elements) {
|
||||
|
||||
// Use a copy of the reaching frame so the original can be saved
|
||||
// for possible reuse as a backward merge block.
|
||||
RegisterFile reserved = RegisterAllocator::Reserved();
|
||||
cgen_->SetFrame(new VirtualFrame(reaching_frames_[0]), &reserved);
|
||||
RegisterFile empty;
|
||||
cgen()->SetFrame(new VirtualFrame(reaching_frames_[0]), &empty);
|
||||
__ bind(&merge_labels_[0]);
|
||||
cgen_->frame()->MergeTo(entry_frame_);
|
||||
__ bind(&entry_label_);
|
||||
cgen()->frame()->MergeTo(entry_frame_);
|
||||
}
|
||||
|
||||
is_linked_ = false;
|
||||
is_bound_ = true;
|
||||
__ bind(&entry_label_);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
28
deps/v8/src/arm/macro-assembler-arm.cc
vendored
28
deps/v8/src/arm/macro-assembler-arm.cc
vendored
@ -32,7 +32,8 @@
|
||||
#include "debug.h"
|
||||
#include "runtime.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Give alias names to registers
|
||||
Register cp = { 8 }; // JavaScript context pointer
|
||||
@ -58,7 +59,10 @@ MacroAssembler::MacroAssembler(void* buffer, int size)
|
||||
// We do not support thumb inter-working with an arm architecture not supporting
|
||||
// the blx instruction (below v5t)
|
||||
#if defined(__THUMB_INTERWORK__)
|
||||
#if !defined(__ARM_ARCH_5T__) && !defined(__ARM_ARCH_5TE__)
|
||||
#if !defined(__ARM_ARCH_5T__) && \
|
||||
!defined(__ARM_ARCH_5TE__) && \
|
||||
!defined(__ARM_ARCH_7A__) && \
|
||||
!defined(__ARM_ARCH_7__)
|
||||
// add tests for other versions above v5t as required
|
||||
#error "for thumb inter-working we require architecture v5t or above"
|
||||
#endif
|
||||
@ -291,6 +295,12 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
|
||||
|
||||
void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
|
||||
ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
|
||||
|
||||
// Compute the argv pointer and keep it in a callee-saved register.
|
||||
// r0 is argc.
|
||||
add(r6, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
sub(r6, r6, Operand(kPointerSize));
|
||||
|
||||
// Compute parameter pointer before making changes and save it as ip
|
||||
// register so that it is restored as sp register on exit, thereby
|
||||
// popping the args.
|
||||
@ -298,6 +308,17 @@ void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
|
||||
// ip = sp + kPointerSize * #args;
|
||||
add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
|
||||
// Align the stack at this point. After this point we have 5 pushes,
|
||||
// so in fact we have to unalign here! See also the assert on the
|
||||
// alignment immediately below.
|
||||
if (OS::ActivationFrameAlignment() != kPointerSize) {
|
||||
// This code needs to be made more general if this assert doesn't hold.
|
||||
ASSERT(OS::ActivationFrameAlignment() == 2 * kPointerSize);
|
||||
mov(r7, Operand(Smi::FromInt(0)));
|
||||
tst(sp, Operand(OS::ActivationFrameAlignment() - 1));
|
||||
push(r7, eq); // Conditional push instruction.
|
||||
}
|
||||
|
||||
// Push in reverse order: caller_fp, sp_on_exit, and caller_pc.
|
||||
stm(db_w, sp, fp.bit() | ip.bit() | lr.bit());
|
||||
mov(fp, Operand(sp)); // setup new frame pointer
|
||||
@ -316,9 +337,6 @@ void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
|
||||
mov(r4, Operand(r0));
|
||||
mov(r5, Operand(r1));
|
||||
|
||||
// Compute the argv pointer and keep it in a callee-saved register.
|
||||
add(r6, fp, Operand(r4, LSL, kPointerSizeLog2));
|
||||
add(r6, r6, Operand(ExitFrameConstants::kPPDisplacement - kPointerSize));
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
// Save the state of all registers to the stack from the memory
|
||||
|
3
deps/v8/src/arm/macro-assembler-arm.h
vendored
3
deps/v8/src/arm/macro-assembler-arm.h
vendored
@ -30,7 +30,8 @@
|
||||
|
||||
#include "assembler.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// Give alias names to registers
|
||||
|
@ -30,7 +30,8 @@
|
||||
#include "regexp-macro-assembler.h"
|
||||
#include "arm/regexp-macro-assembler-arm.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
RegExpMacroAssemblerARM::RegExpMacroAssemblerARM() {
|
||||
UNIMPLEMENTED();
|
||||
|
3
deps/v8/src/arm/regexp-macro-assembler-arm.h
vendored
3
deps/v8/src/arm/regexp-macro-assembler-arm.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_
|
||||
#define V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class RegExpMacroAssemblerARM: public RegExpMacroAssembler {
|
||||
public:
|
||||
|
103
deps/v8/src/arm/register-allocator-arm-inl.h
vendored
Normal file
103
deps/v8/src/arm/register-allocator-arm-inl.h
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
#ifndef V8_ARM_REGISTER_ALLOCATOR_ARM_INL_H_
|
||||
#define V8_ARM_REGISTER_ALLOCATOR_ARM_INL_H_
|
||||
|
||||
#include "v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// RegisterAllocator implementation.
|
||||
|
||||
bool RegisterAllocator::IsReserved(Register reg) {
|
||||
return reg.is(cp) || reg.is(fp) || reg.is(sp) || reg.is(pc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The register allocator uses small integers to represent the
|
||||
// non-reserved assembler registers. The mapping is:
|
||||
//
|
||||
// r0 <-> 0
|
||||
// r1 <-> 1
|
||||
// r2 <-> 2
|
||||
// r3 <-> 3
|
||||
// r4 <-> 4
|
||||
// r5 <-> 5
|
||||
// r6 <-> 6
|
||||
// r7 <-> 7
|
||||
// r9 <-> 8
|
||||
// r10 <-> 9
|
||||
// ip <-> 10
|
||||
// lr <-> 11
|
||||
|
||||
int RegisterAllocator::ToNumber(Register reg) {
|
||||
ASSERT(reg.is_valid() && !IsReserved(reg));
|
||||
static int numbers[] = {
|
||||
0, // r0
|
||||
1, // r1
|
||||
2, // r2
|
||||
3, // r3
|
||||
4, // r4
|
||||
5, // r5
|
||||
6, // r6
|
||||
7, // r7
|
||||
-1, // cp
|
||||
8, // r9
|
||||
9, // r10
|
||||
-1, // fp
|
||||
10, // ip
|
||||
-1, // sp
|
||||
11, // lr
|
||||
-1 // pc
|
||||
};
|
||||
return numbers[reg.code()];
|
||||
}
|
||||
|
||||
|
||||
Register RegisterAllocator::ToRegister(int num) {
|
||||
ASSERT(num >= 0 && num < kNumRegisters);
|
||||
static Register registers[] =
|
||||
{ r0, r1, r2, r3, r4, r5, r6, r7, r9, r10, ip, lr };
|
||||
return registers[num];
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocator::Initialize() {
|
||||
Reset();
|
||||
// The non-reserved r1 and lr registers are live on JS function entry.
|
||||
Use(r1); // JS function.
|
||||
Use(lr); // Return address.
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_ARM_REGISTER_ALLOCATOR_ARM_INL_H_
|
55
deps/v8/src/arm/register-allocator-arm.cc
vendored
55
deps/v8/src/arm/register-allocator-arm.cc
vendored
@ -30,7 +30,8 @@
|
||||
#include "codegen-inl.h"
|
||||
#include "register-allocator-inl.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Result implementation.
|
||||
@ -48,56 +49,10 @@ void Result::ToRegister(Register target) {
|
||||
// -------------------------------------------------------------------------
|
||||
// RegisterAllocator implementation.
|
||||
|
||||
RegisterFile RegisterAllocator::Reserved() {
|
||||
RegisterFile reserved;
|
||||
reserved.Use(sp);
|
||||
reserved.Use(fp);
|
||||
reserved.Use(cp);
|
||||
reserved.Use(pc);
|
||||
return reserved;
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocator::UnuseReserved(RegisterFile* register_file) {
|
||||
register_file->ref_counts_[sp.code()] = 0;
|
||||
register_file->ref_counts_[fp.code()] = 0;
|
||||
register_file->ref_counts_[cp.code()] = 0;
|
||||
register_file->ref_counts_[pc.code()] = 0;
|
||||
}
|
||||
|
||||
|
||||
bool RegisterAllocator::IsReserved(int reg_code) {
|
||||
return (reg_code == sp.code())
|
||||
|| (reg_code == fp.code())
|
||||
|| (reg_code == cp.code())
|
||||
|| (reg_code == pc.code());
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocator::Initialize() {
|
||||
Reset();
|
||||
// The following registers are live on function entry, saved in the
|
||||
// frame, and available for allocation during execution.
|
||||
Use(r1); // JS function.
|
||||
Use(lr); // Return address.
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocator::Reset() {
|
||||
registers_.Reset();
|
||||
// The following registers are live on function entry and reserved
|
||||
// during execution.
|
||||
Use(sp); // Stack pointer.
|
||||
Use(fp); // Frame pointer (caller's frame pointer on entry).
|
||||
Use(cp); // Context context (callee's context on entry).
|
||||
Use(pc); // Program counter.
|
||||
}
|
||||
|
||||
|
||||
Result RegisterAllocator::AllocateByteRegisterWithoutSpilling() {
|
||||
UNIMPLEMENTED();
|
||||
Result invalid(cgen_);
|
||||
return invalid;
|
||||
// No byte registers on ARM.
|
||||
UNREACHABLE();
|
||||
return Result();
|
||||
}
|
||||
|
||||
|
||||
|
43
deps/v8/src/arm/register-allocator-arm.h
vendored
Normal file
43
deps/v8/src/arm/register-allocator-arm.h
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
#ifndef V8_ARM_REGISTER_ALLOCATOR_ARM_H_
|
||||
#define V8_ARM_REGISTER_ALLOCATOR_ARM_H_
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class RegisterAllocatorConstants : public AllStatic {
|
||||
public:
|
||||
static const int kNumRegisters = 12;
|
||||
static const int kInvalidRegister = -1;
|
||||
};
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_ARM_REGISTER_ALLOCATOR_ARM_H_
|
3
deps/v8/src/arm/simulator-arm.cc
vendored
3
deps/v8/src/arm/simulator-arm.cc
vendored
@ -36,7 +36,8 @@
|
||||
#if !defined(__arm__)
|
||||
|
||||
// Only build the simulator if not compiling for real ARM hardware.
|
||||
namespace assembler { namespace arm {
|
||||
namespace assembler {
|
||||
namespace arm {
|
||||
|
||||
using ::v8::internal::Object;
|
||||
using ::v8::internal::PrintF;
|
||||
|
3
deps/v8/src/arm/simulator-arm.h
vendored
3
deps/v8/src/arm/simulator-arm.h
vendored
@ -66,7 +66,8 @@
|
||||
#include "constants-arm.h"
|
||||
|
||||
|
||||
namespace assembler { namespace arm {
|
||||
namespace assembler {
|
||||
namespace arm {
|
||||
|
||||
class Simulator {
|
||||
public:
|
||||
|
44
deps/v8/src/arm/stub-cache-arm.cc
vendored
44
deps/v8/src/arm/stub-cache-arm.cc
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2006-2008 the V8 project authors. All rights reserved.
|
||||
// Copyright 2006-2009 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:
|
||||
@ -31,7 +31,8 @@
|
||||
#include "codegen-inl.h"
|
||||
#include "stub-cache.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ ACCESS_MASM(masm)
|
||||
|
||||
@ -61,7 +62,7 @@ static void ProbeTable(MacroAssembler* masm,
|
||||
|
||||
// Check that the flags match what we're looking for.
|
||||
__ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
|
||||
__ and_(offset, offset, Operand(~Code::kFlagsTypeMask));
|
||||
__ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
|
||||
__ cmp(offset, Operand(flags));
|
||||
__ b(ne, &miss);
|
||||
|
||||
@ -245,6 +246,7 @@ void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
|
||||
void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
|
||||
JSObject* object,
|
||||
JSObject* holder,
|
||||
Smi* lookup_hint,
|
||||
Register receiver,
|
||||
Register name,
|
||||
Register scratch1,
|
||||
@ -262,11 +264,13 @@ void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
|
||||
__ push(receiver); // receiver
|
||||
__ push(reg); // holder
|
||||
__ push(name); // name
|
||||
__ mov(scratch1, Operand(lookup_hint));
|
||||
__ push(scratch1);
|
||||
|
||||
// Do tail-call to the runtime system.
|
||||
ExternalReference load_ic_property =
|
||||
ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
|
||||
__ TailCallRuntime(load_ic_property, 3);
|
||||
__ TailCallRuntime(load_ic_property, 4);
|
||||
}
|
||||
|
||||
|
||||
@ -494,7 +498,9 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
|
||||
Object* CallStubCompiler::CompileCallField(Object* object,
|
||||
JSObject* holder,
|
||||
int index,
|
||||
String* name) {
|
||||
String* name,
|
||||
Code::Flags flags) {
|
||||
ASSERT_EQ(FIELD, Code::ExtractTypeFromFlags(flags));
|
||||
// ----------- S t a t e -------------
|
||||
// -- lr: return address
|
||||
// -----------------------------------
|
||||
@ -538,14 +544,16 @@ Object* CallStubCompiler::CompileCallField(Object* object,
|
||||
__ Jump(ic, RelocInfo::CODE_TARGET);
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(FIELD, name);
|
||||
return GetCodeWithFlags(flags, name);
|
||||
}
|
||||
|
||||
|
||||
Object* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
JSObject* holder,
|
||||
JSFunction* function,
|
||||
CheckType check) {
|
||||
CheckType check,
|
||||
Code::Flags flags) {
|
||||
ASSERT_EQ(CONSTANT_FUNCTION, Code::ExtractTypeFromFlags(flags));
|
||||
// ----------- S t a t e -------------
|
||||
// -- lr: return address
|
||||
// -----------------------------------
|
||||
@ -663,7 +671,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
if (function->shared()->name()->IsString()) {
|
||||
function_name = String::cast(function->shared()->name());
|
||||
}
|
||||
return GetCode(CONSTANT_FUNCTION, function_name);
|
||||
return GetCodeWithFlags(flags, function_name);
|
||||
}
|
||||
|
||||
|
||||
@ -904,7 +912,15 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
|
||||
|
||||
__ ldr(r0, MemOperand(sp, 0));
|
||||
|
||||
GenerateLoadInterceptor(masm(), object, holder, r0, r2, r3, r1, &miss);
|
||||
GenerateLoadInterceptor(masm(),
|
||||
object,
|
||||
holder,
|
||||
holder->InterceptorPropertyLookupHint(name),
|
||||
r0,
|
||||
r2,
|
||||
r3,
|
||||
r1,
|
||||
&miss);
|
||||
__ bind(&miss);
|
||||
GenerateLoadMiss(masm(), Code::LOAD_IC);
|
||||
|
||||
@ -1010,7 +1026,15 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
|
||||
__ cmp(r2, Operand(Handle<String>(name)));
|
||||
__ b(ne, &miss);
|
||||
|
||||
GenerateLoadInterceptor(masm(), receiver, holder, r0, r2, r3, r1, &miss);
|
||||
GenerateLoadInterceptor(masm(),
|
||||
receiver,
|
||||
holder,
|
||||
Smi::FromInt(JSObject::kLookupInHolder),
|
||||
r0,
|
||||
r2,
|
||||
r3,
|
||||
r1,
|
||||
&miss);
|
||||
__ bind(&miss);
|
||||
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
|
||||
|
||||
|
77
deps/v8/src/arm/virtual-frame-arm.cc
vendored
77
deps/v8/src/arm/virtual-frame-arm.cc
vendored
@ -31,31 +31,25 @@
|
||||
#include "register-allocator-inl.h"
|
||||
#include "scopes.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// VirtualFrame implementation.
|
||||
|
||||
#define __ ACCESS_MASM(masm_)
|
||||
#define __ ACCESS_MASM(masm())
|
||||
|
||||
|
||||
// On entry to a function, the virtual frame already contains the
|
||||
// receiver and the parameters. All initial frame elements are in
|
||||
// memory.
|
||||
VirtualFrame::VirtualFrame(CodeGenerator* cgen)
|
||||
: cgen_(cgen),
|
||||
masm_(cgen->masm()),
|
||||
elements_(cgen->scope()->num_parameters()
|
||||
+ cgen->scope()->num_stack_slots()
|
||||
+ kPreallocatedElements),
|
||||
parameter_count_(cgen->scope()->num_parameters()),
|
||||
local_count_(0),
|
||||
stack_pointer_(parameter_count_), // 0-based index of TOS.
|
||||
frame_pointer_(kIllegalIndex) {
|
||||
for (int i = 0; i < parameter_count_ + 1; i++) {
|
||||
VirtualFrame::VirtualFrame()
|
||||
: elements_(parameter_count() + local_count() + kPreallocatedElements),
|
||||
stack_pointer_(parameter_count()) { // 0-based index of TOS.
|
||||
for (int i = 0; i <= stack_pointer_; i++) {
|
||||
elements_.Add(FrameElement::MemoryElement());
|
||||
}
|
||||
for (int i = 0; i < kNumRegisters; i++) {
|
||||
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
|
||||
register_locations_[i] = kIllegalIndex;
|
||||
}
|
||||
}
|
||||
@ -82,10 +76,10 @@ void VirtualFrame::SyncRange(int begin, int end) {
|
||||
|
||||
|
||||
void VirtualFrame::MergeTo(VirtualFrame* expected) {
|
||||
Comment cmnt(masm_, "[ Merge frame");
|
||||
Comment cmnt(masm(), "[ Merge frame");
|
||||
// We should always be merging the code generator's current frame to an
|
||||
// expected frame.
|
||||
ASSERT(cgen_->frame() == this);
|
||||
ASSERT(cgen()->frame() == this);
|
||||
|
||||
// Adjust the stack pointer upward (toward the top of the virtual
|
||||
// frame) if necessary.
|
||||
@ -102,7 +96,7 @@ void VirtualFrame::MergeTo(VirtualFrame* expected) {
|
||||
// Fix any sync bit problems from the bottom-up, stopping when we
|
||||
// hit the stack pointer or the top of the frame if the stack
|
||||
// pointer is floating above the frame.
|
||||
int limit = Min(stack_pointer_, elements_.length() - 1);
|
||||
int limit = Min(static_cast<int>(stack_pointer_), element_count() - 1);
|
||||
for (int i = 0; i <= limit; i++) {
|
||||
FrameElement source = elements_[i];
|
||||
FrameElement target = expected->elements_[i];
|
||||
@ -134,7 +128,7 @@ void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) {
|
||||
// On ARM, all elements are in memory.
|
||||
|
||||
#ifdef DEBUG
|
||||
int start = Min(stack_pointer_, elements_.length() - 1);
|
||||
int start = Min(static_cast<int>(stack_pointer_), element_count() - 1);
|
||||
for (int i = start; i >= 0; i--) {
|
||||
ASSERT(elements_[i].is_memory());
|
||||
ASSERT(expected->elements_[i].is_memory());
|
||||
@ -147,12 +141,12 @@ void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) {
|
||||
}
|
||||
|
||||
|
||||
void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame *expected) {
|
||||
void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame* expected) {
|
||||
}
|
||||
|
||||
|
||||
void VirtualFrame::Enter() {
|
||||
Comment cmnt(masm_, "[ Enter JS frame");
|
||||
Comment cmnt(masm(), "[ Enter JS frame");
|
||||
|
||||
#ifdef DEBUG
|
||||
// Verify that r1 contains a JS function. The following code relies
|
||||
@ -175,15 +169,14 @@ void VirtualFrame::Enter() {
|
||||
Adjust(4);
|
||||
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
|
||||
// Adjust FP to point to saved FP.
|
||||
frame_pointer_ = elements_.length() - 2;
|
||||
__ add(fp, sp, Operand(2 * kPointerSize));
|
||||
cgen_->allocator()->Unuse(r1);
|
||||
cgen_->allocator()->Unuse(lr);
|
||||
cgen()->allocator()->Unuse(r1);
|
||||
cgen()->allocator()->Unuse(lr);
|
||||
}
|
||||
|
||||
|
||||
void VirtualFrame::Exit() {
|
||||
Comment cmnt(masm_, "[ Exit JS frame");
|
||||
Comment cmnt(masm(), "[ Exit JS frame");
|
||||
// Drop the execution stack down to the frame pointer and restore the caller
|
||||
// frame pointer and return address.
|
||||
__ mov(sp, fp);
|
||||
@ -191,12 +184,11 @@ void VirtualFrame::Exit() {
|
||||
}
|
||||
|
||||
|
||||
void VirtualFrame::AllocateStackSlots(int count) {
|
||||
ASSERT(height() == 0);
|
||||
local_count_ = count;
|
||||
Adjust(count);
|
||||
void VirtualFrame::AllocateStackSlots() {
|
||||
int count = local_count();
|
||||
if (count > 0) {
|
||||
Comment cmnt(masm_, "[ Allocate space for locals");
|
||||
Comment cmnt(masm(), "[ Allocate space for locals");
|
||||
Adjust(count);
|
||||
// Initialize stack slots with 'undefined' value.
|
||||
__ mov(ip, Operand(Factory::undefined_value()));
|
||||
for (int i = 0; i < count; i++) {
|
||||
@ -246,9 +238,9 @@ void VirtualFrame::PushTryHandler(HandlerType type) {
|
||||
|
||||
|
||||
Result VirtualFrame::RawCallStub(CodeStub* stub) {
|
||||
ASSERT(cgen_->HasValidEntryRegisters());
|
||||
ASSERT(cgen()->HasValidEntryRegisters());
|
||||
__ CallStub(stub);
|
||||
Result result = cgen_->allocator()->Allocate(r0);
|
||||
Result result = cgen()->allocator()->Allocate(r0);
|
||||
ASSERT(result.is_valid());
|
||||
return result;
|
||||
}
|
||||
@ -271,9 +263,9 @@ Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) {
|
||||
|
||||
Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
|
||||
PrepareForCall(arg_count, arg_count);
|
||||
ASSERT(cgen_->HasValidEntryRegisters());
|
||||
ASSERT(cgen()->HasValidEntryRegisters());
|
||||
__ CallRuntime(f, arg_count);
|
||||
Result result = cgen_->allocator()->Allocate(r0);
|
||||
Result result = cgen()->allocator()->Allocate(r0);
|
||||
ASSERT(result.is_valid());
|
||||
return result;
|
||||
}
|
||||
@ -281,9 +273,9 @@ Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
|
||||
|
||||
Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
|
||||
PrepareForCall(arg_count, arg_count);
|
||||
ASSERT(cgen_->HasValidEntryRegisters());
|
||||
ASSERT(cgen()->HasValidEntryRegisters());
|
||||
__ CallRuntime(id, arg_count);
|
||||
Result result = cgen_->allocator()->Allocate(r0);
|
||||
Result result = cgen()->allocator()->Allocate(r0);
|
||||
ASSERT(result.is_valid());
|
||||
return result;
|
||||
}
|
||||
@ -297,16 +289,16 @@ Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
|
||||
PrepareForCall(arg_count, arg_count);
|
||||
arg_count_register->Unuse();
|
||||
__ InvokeBuiltin(id, flags);
|
||||
Result result = cgen_->allocator()->Allocate(r0);
|
||||
Result result = cgen()->allocator()->Allocate(r0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
|
||||
RelocInfo::Mode rmode) {
|
||||
ASSERT(cgen_->HasValidEntryRegisters());
|
||||
ASSERT(cgen()->HasValidEntryRegisters());
|
||||
__ Call(code, rmode);
|
||||
Result result = cgen_->allocator()->Allocate(r0);
|
||||
Result result = cgen()->allocator()->Allocate(r0);
|
||||
ASSERT(result.is_valid());
|
||||
return result;
|
||||
}
|
||||
@ -401,7 +393,7 @@ Result VirtualFrame::CallCodeObject(Handle<Code> code,
|
||||
|
||||
void VirtualFrame::Drop(int count) {
|
||||
ASSERT(height() >= count);
|
||||
int num_virtual_elements = (elements_.length() - 1) - stack_pointer_;
|
||||
int num_virtual_elements = (element_count() - 1) - stack_pointer_;
|
||||
|
||||
// Emit code to lower the stack pointer if necessary.
|
||||
if (num_virtual_elements < count) {
|
||||
@ -422,13 +414,12 @@ void VirtualFrame::Drop(int count) {
|
||||
|
||||
Result VirtualFrame::Pop() {
|
||||
UNIMPLEMENTED();
|
||||
Result invalid(cgen_);
|
||||
return invalid;
|
||||
return Result();
|
||||
}
|
||||
|
||||
|
||||
void VirtualFrame::EmitPop(Register reg) {
|
||||
ASSERT(stack_pointer_ == elements_.length() - 1);
|
||||
ASSERT(stack_pointer_ == element_count() - 1);
|
||||
stack_pointer_--;
|
||||
elements_.RemoveLast();
|
||||
__ pop(reg);
|
||||
@ -436,7 +427,7 @@ void VirtualFrame::EmitPop(Register reg) {
|
||||
|
||||
|
||||
void VirtualFrame::EmitPush(Register reg) {
|
||||
ASSERT(stack_pointer_ == elements_.length() - 1);
|
||||
ASSERT(stack_pointer_ == element_count() - 1);
|
||||
elements_.Add(FrameElement::MemoryElement());
|
||||
stack_pointer_++;
|
||||
__ push(reg);
|
||||
|
198
deps/v8/src/arm/virtual-frame-arm.h
vendored
198
deps/v8/src/arm/virtual-frame-arm.h
vendored
@ -29,8 +29,10 @@
|
||||
#define V8_ARM_VIRTUAL_FRAME_ARM_H_
|
||||
|
||||
#include "register-allocator.h"
|
||||
#include "scopes.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Virtual frames
|
||||
@ -41,7 +43,7 @@ namespace v8 { namespace internal {
|
||||
// as random access to the expression stack elements, locals, and
|
||||
// parameters.
|
||||
|
||||
class VirtualFrame : public Malloced {
|
||||
class VirtualFrame : public ZoneObject {
|
||||
public:
|
||||
// A utility class to introduce a scope where the virtual frame is
|
||||
// expected to remain spilled. The constructor spills the code
|
||||
@ -50,42 +52,66 @@ class VirtualFrame : public Malloced {
|
||||
// generator is being transformed.
|
||||
class SpilledScope BASE_EMBEDDED {
|
||||
public:
|
||||
explicit SpilledScope(CodeGenerator* cgen);
|
||||
SpilledScope() : previous_state_(cgen()->in_spilled_code()) {
|
||||
ASSERT(cgen()->has_valid_frame());
|
||||
cgen()->frame()->SpillAll();
|
||||
cgen()->set_in_spilled_code(true);
|
||||
}
|
||||
|
||||
~SpilledScope();
|
||||
~SpilledScope() {
|
||||
cgen()->set_in_spilled_code(previous_state_);
|
||||
}
|
||||
|
||||
private:
|
||||
CodeGenerator* cgen_;
|
||||
bool previous_state_;
|
||||
|
||||
CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
|
||||
};
|
||||
|
||||
// An illegal index into the virtual frame.
|
||||
static const int kIllegalIndex = -1;
|
||||
|
||||
// Construct an initial virtual frame on entry to a JS function.
|
||||
explicit VirtualFrame(CodeGenerator* cgen);
|
||||
VirtualFrame();
|
||||
|
||||
// Construct a virtual frame as a clone of an existing one.
|
||||
explicit VirtualFrame(VirtualFrame* original);
|
||||
|
||||
CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
|
||||
MacroAssembler* masm() { return cgen()->masm(); }
|
||||
|
||||
// Create a duplicate of an existing valid frame element.
|
||||
FrameElement CopyElementAt(int index);
|
||||
|
||||
// The number of elements on the virtual frame.
|
||||
int element_count() { return elements_.length(); }
|
||||
|
||||
// The height of the virtual expression stack.
|
||||
int height() const {
|
||||
return elements_.length() - expression_base_index();
|
||||
int height() {
|
||||
return element_count() - expression_base_index();
|
||||
}
|
||||
|
||||
int register_index(Register reg) {
|
||||
return register_locations_[reg.code()];
|
||||
int register_location(int num) {
|
||||
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
|
||||
return register_locations_[num];
|
||||
}
|
||||
|
||||
bool is_used(int reg_code) {
|
||||
return register_locations_[reg_code] != kIllegalIndex;
|
||||
int register_location(Register reg) {
|
||||
return register_locations_[RegisterAllocator::ToNumber(reg)];
|
||||
}
|
||||
|
||||
void set_register_location(Register reg, int index) {
|
||||
register_locations_[RegisterAllocator::ToNumber(reg)] = index;
|
||||
}
|
||||
|
||||
bool is_used(int num) {
|
||||
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
|
||||
return register_locations_[num] != kIllegalIndex;
|
||||
}
|
||||
|
||||
bool is_used(Register reg) {
|
||||
return is_used(reg.code());
|
||||
return register_locations_[RegisterAllocator::ToNumber(reg)]
|
||||
!= kIllegalIndex;
|
||||
}
|
||||
|
||||
// Add extra in-memory elements to the top of the frame to match an actual
|
||||
@ -95,7 +121,12 @@ class VirtualFrame : public Malloced {
|
||||
|
||||
// Forget elements from the top of the frame to match an actual frame (eg,
|
||||
// the frame after a runtime call). No code is emitted.
|
||||
void Forget(int count);
|
||||
void Forget(int count) {
|
||||
ASSERT(count >= 0);
|
||||
ASSERT(stack_pointer_ == element_count() - 1);
|
||||
stack_pointer_ -= count;
|
||||
ForgetElements(count);
|
||||
}
|
||||
|
||||
// Forget count elements from the top of the frame without adjusting
|
||||
// the stack pointer downward. This is used, for example, before
|
||||
@ -106,7 +137,9 @@ class VirtualFrame : public Malloced {
|
||||
void SpillAll();
|
||||
|
||||
// Spill all occurrences of a specific register from the frame.
|
||||
void Spill(Register reg);
|
||||
void Spill(Register reg) {
|
||||
if (is_used(reg)) SpillElementAt(register_location(reg));
|
||||
}
|
||||
|
||||
// Spill all occurrences of an arbitrary register if possible. Return the
|
||||
// register spilled or no_reg if it was not possible to free any register
|
||||
@ -127,13 +160,23 @@ class VirtualFrame : public Malloced {
|
||||
// tells the register allocator that it is free to use frame-internal
|
||||
// registers. Used when the code generator's frame is switched from this
|
||||
// one to NULL by an unconditional jump.
|
||||
void DetachFromCodeGenerator();
|
||||
void DetachFromCodeGenerator() {
|
||||
RegisterAllocator* cgen_allocator = cgen()->allocator();
|
||||
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
|
||||
if (is_used(i)) cgen_allocator->Unuse(i);
|
||||
}
|
||||
}
|
||||
|
||||
// (Re)attach a frame to its code generator. This informs the register
|
||||
// allocator that the frame-internal register references are active again.
|
||||
// Used when a code generator's frame is switched from NULL to this one by
|
||||
// binding a label.
|
||||
void AttachToCodeGenerator();
|
||||
void AttachToCodeGenerator() {
|
||||
RegisterAllocator* cgen_allocator = cgen()->allocator();
|
||||
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
|
||||
if (is_used(i)) cgen_allocator->Unuse(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Emit code for the physical JS entry and exit frame sequences. After
|
||||
// calling Enter, the virtual frame is ready for use; and after calling
|
||||
@ -149,13 +192,13 @@ class VirtualFrame : public Malloced {
|
||||
void PrepareForReturn();
|
||||
|
||||
// Allocate and initialize the frame-allocated locals.
|
||||
void AllocateStackSlots(int count);
|
||||
void AllocateStackSlots();
|
||||
|
||||
// The current top of the expression stack as an assembly operand.
|
||||
MemOperand Top() const { return MemOperand(sp, 0); }
|
||||
MemOperand Top() { return MemOperand(sp, 0); }
|
||||
|
||||
// An element of the expression stack as an assembly operand.
|
||||
MemOperand ElementAt(int index) const {
|
||||
MemOperand ElementAt(int index) {
|
||||
return MemOperand(sp, index * kPointerSize);
|
||||
}
|
||||
|
||||
@ -165,18 +208,18 @@ class VirtualFrame : public Malloced {
|
||||
|
||||
// Set a frame element to a constant. The index is frame-top relative.
|
||||
void SetElementAt(int index, Handle<Object> value) {
|
||||
Result temp(value, cgen_);
|
||||
Result temp(value);
|
||||
SetElementAt(index, &temp);
|
||||
}
|
||||
|
||||
void PushElementAt(int index) {
|
||||
PushFrameSlotAt(elements_.length() - index - 1);
|
||||
PushFrameSlotAt(element_count() - index - 1);
|
||||
}
|
||||
|
||||
// A frame-allocated local as an assembly operand.
|
||||
MemOperand LocalAt(int index) const {
|
||||
MemOperand LocalAt(int index) {
|
||||
ASSERT(0 <= index);
|
||||
ASSERT(index < local_count_);
|
||||
ASSERT(index < local_count());
|
||||
return MemOperand(fp, kLocal0Offset - index * kPointerSize);
|
||||
}
|
||||
|
||||
@ -202,13 +245,13 @@ class VirtualFrame : public Malloced {
|
||||
void PushReceiverSlotAddress();
|
||||
|
||||
// The function frame slot.
|
||||
MemOperand Function() const { return MemOperand(fp, kFunctionOffset); }
|
||||
MemOperand Function() { return MemOperand(fp, kFunctionOffset); }
|
||||
|
||||
// Push the function on top of the frame.
|
||||
void PushFunction() { PushFrameSlotAt(function_index()); }
|
||||
|
||||
// The context frame slot.
|
||||
MemOperand Context() const { return MemOperand(fp, kContextOffset); }
|
||||
MemOperand Context() { return MemOperand(fp, kContextOffset); }
|
||||
|
||||
// Save the value of the esi register to the context frame slot.
|
||||
void SaveContextRegister();
|
||||
@ -218,10 +261,11 @@ class VirtualFrame : public Malloced {
|
||||
void RestoreContextRegister();
|
||||
|
||||
// A parameter as an assembly operand.
|
||||
MemOperand ParameterAt(int index) const {
|
||||
MemOperand ParameterAt(int index) {
|
||||
// Index -1 corresponds to the receiver.
|
||||
ASSERT(-1 <= index && index <= parameter_count_);
|
||||
return MemOperand(fp, (1 + parameter_count_ - index) * kPointerSize);
|
||||
ASSERT(-1 <= index); // -1 is the receiver.
|
||||
ASSERT(index <= parameter_count());
|
||||
return MemOperand(fp, (1 + parameter_count() - index) * kPointerSize);
|
||||
}
|
||||
|
||||
// Push a copy of the value of a parameter frame slot on top of the frame.
|
||||
@ -243,14 +287,17 @@ class VirtualFrame : public Malloced {
|
||||
}
|
||||
|
||||
// The receiver frame slot.
|
||||
MemOperand Receiver() const { return ParameterAt(-1); }
|
||||
MemOperand Receiver() { return ParameterAt(-1); }
|
||||
|
||||
// Push a try-catch or try-finally handler on top of the virtual frame.
|
||||
void PushTryHandler(HandlerType type);
|
||||
|
||||
// Call stub given the number of arguments it expects on (and
|
||||
// removes from) the stack.
|
||||
Result CallStub(CodeStub* stub, int arg_count);
|
||||
Result CallStub(CodeStub* stub, int arg_count) {
|
||||
PrepareForCall(arg_count, arg_count);
|
||||
return RawCallStub(stub);
|
||||
}
|
||||
|
||||
// Call stub that expects its argument in r0. The argument is given
|
||||
// as a result which must be the register r0.
|
||||
@ -297,7 +344,7 @@ class VirtualFrame : public Malloced {
|
||||
void Drop() { Drop(1); }
|
||||
|
||||
// Duplicate the top element of the frame.
|
||||
void Dup() { PushFrameSlotAt(elements_.length() - 1); }
|
||||
void Dup() { PushFrameSlotAt(element_count() - 1); }
|
||||
|
||||
// Pop an element from the top of the expression stack. Returns a
|
||||
// Result, which may be a constant or a register.
|
||||
@ -317,7 +364,15 @@ class VirtualFrame : public Malloced {
|
||||
void Push(Smi* value) { Push(Handle<Object>(value)); }
|
||||
|
||||
// Pushing a result invalidates it (its contents become owned by the frame).
|
||||
void Push(Result* result);
|
||||
void Push(Result* result) {
|
||||
if (result->is_register()) {
|
||||
Push(result->reg(), result->static_type());
|
||||
} else {
|
||||
ASSERT(result->is_constant());
|
||||
Push(result->handle());
|
||||
}
|
||||
result->Unuse();
|
||||
}
|
||||
|
||||
// Nip removes zero or more elements from immediately below the top
|
||||
// of the frame, leaving the previous top-of-frame value on top of
|
||||
@ -332,70 +387,69 @@ class VirtualFrame : public Malloced {
|
||||
static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize;
|
||||
static const int kPreallocatedElements = 5 + 8; // 8 expression stack slots.
|
||||
|
||||
CodeGenerator* cgen_;
|
||||
MacroAssembler* masm_;
|
||||
|
||||
List<FrameElement> elements_;
|
||||
|
||||
// The number of frame-allocated locals and parameters respectively.
|
||||
int parameter_count_;
|
||||
int local_count_;
|
||||
ZoneList<FrameElement> elements_;
|
||||
|
||||
// The index of the element that is at the processor's stack pointer
|
||||
// (the sp register).
|
||||
int stack_pointer_;
|
||||
|
||||
// The index of the element that is at the processor's frame pointer
|
||||
// (the fp register).
|
||||
int frame_pointer_;
|
||||
|
||||
// The index of the register frame element using each register, or
|
||||
// kIllegalIndex if a register is not on the frame.
|
||||
int register_locations_[kNumRegisters];
|
||||
int register_locations_[RegisterAllocator::kNumRegisters];
|
||||
|
||||
// The number of frame-allocated locals and parameters respectively.
|
||||
int parameter_count() { return cgen()->scope()->num_parameters(); }
|
||||
int local_count() { return cgen()->scope()->num_stack_slots(); }
|
||||
|
||||
// The index of the element that is at the processor's frame pointer
|
||||
// (the fp register). The parameters, receiver, function, and context
|
||||
// are below the frame pointer.
|
||||
int frame_pointer() { return parameter_count() + 3; }
|
||||
|
||||
// The index of the first parameter. The receiver lies below the first
|
||||
// parameter.
|
||||
int param0_index() const { return 1; }
|
||||
int param0_index() { return 1; }
|
||||
|
||||
// The index of the context slot in the frame.
|
||||
int context_index() const {
|
||||
ASSERT(frame_pointer_ != kIllegalIndex);
|
||||
return frame_pointer_ - 1;
|
||||
}
|
||||
// The index of the context slot in the frame. It is immediately
|
||||
// below the frame pointer.
|
||||
int context_index() { return frame_pointer() - 1; }
|
||||
|
||||
// The index of the function slot in the frame. It lies above the context
|
||||
// slot.
|
||||
int function_index() const {
|
||||
ASSERT(frame_pointer_ != kIllegalIndex);
|
||||
return frame_pointer_ - 2;
|
||||
}
|
||||
// The index of the function slot in the frame. It is below the frame
|
||||
// pointer and context slot.
|
||||
int function_index() { return frame_pointer() - 2; }
|
||||
|
||||
// The index of the first local. Between the parameters and the locals
|
||||
// lie the return address, the saved frame pointer, the context, and the
|
||||
// function.
|
||||
int local0_index() const {
|
||||
ASSERT(frame_pointer_ != kIllegalIndex);
|
||||
return frame_pointer_ + 2;
|
||||
}
|
||||
// The index of the first local. Between the frame pointer and the
|
||||
// locals lies the return address.
|
||||
int local0_index() { return frame_pointer() + 2; }
|
||||
|
||||
// The index of the base of the expression stack.
|
||||
int expression_base_index() const { return local0_index() + local_count_; }
|
||||
int expression_base_index() { return local0_index() + local_count(); }
|
||||
|
||||
// Convert a frame index into a frame pointer relative offset into the
|
||||
// actual stack.
|
||||
int fp_relative(int index) const {
|
||||
return (frame_pointer_ - index) * kPointerSize;
|
||||
int fp_relative(int index) {
|
||||
ASSERT(index < element_count());
|
||||
ASSERT(frame_pointer() < element_count()); // FP is on the frame.
|
||||
return (frame_pointer() - index) * kPointerSize;
|
||||
}
|
||||
|
||||
// Record an occurrence of a register in the virtual frame. This has the
|
||||
// effect of incrementing the register's external reference count and
|
||||
// of updating the index of the register's location in the frame.
|
||||
void Use(Register reg, int index);
|
||||
void Use(Register reg, int index) {
|
||||
ASSERT(!is_used(reg));
|
||||
set_register_location(reg, index);
|
||||
cgen()->allocator()->Use(reg);
|
||||
}
|
||||
|
||||
// Record that a register reference has been dropped from the frame. This
|
||||
// decrements the register's external reference count and invalidates the
|
||||
// index of the register's location in the frame.
|
||||
void Unuse(Register reg);
|
||||
void Unuse(Register reg) {
|
||||
ASSERT(is_used(reg));
|
||||
set_register_location(reg, kIllegalIndex);
|
||||
cgen()->allocator()->Unuse(reg);
|
||||
}
|
||||
|
||||
// Spill the element at a particular index---write it to memory if
|
||||
// necessary, free any associated register, and forget its value if
|
||||
@ -407,7 +461,7 @@ class VirtualFrame : public Malloced {
|
||||
// Keep the element type as register or constant, and clear the dirty bit.
|
||||
void SyncElementAt(int index);
|
||||
|
||||
// Sync the range of elements in [begin, end).
|
||||
// Sync the range of elements in [begin, end] with memory.
|
||||
void SyncRange(int begin, int end);
|
||||
|
||||
// Sync a single unsynced element that lies beneath or at the stack pointer.
|
||||
@ -471,6 +525,8 @@ class VirtualFrame : public Malloced {
|
||||
|
||||
bool Equals(VirtualFrame* other);
|
||||
|
||||
// Classes that need raw access to the elements_ array.
|
||||
friend class DeferredCode;
|
||||
friend class JumpTarget;
|
||||
};
|
||||
|
||||
|
33
deps/v8/src/assembler.cc
vendored
33
deps/v8/src/assembler.cc
vendored
@ -43,7 +43,8 @@
|
||||
#include "stub-cache.h"
|
||||
#include "regexp-stack.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -90,13 +91,13 @@ int Label::pos() const {
|
||||
// bits, the lowest 7 bits written first.
|
||||
//
|
||||
// data-jump + pos: 00 1110 11,
|
||||
// signed int, lowest byte written first
|
||||
// signed intptr_t, lowest byte written first
|
||||
//
|
||||
// data-jump + st.pos: 01 1110 11,
|
||||
// signed int, lowest byte written first
|
||||
// signed intptr_t, lowest byte written first
|
||||
//
|
||||
// data-jump + comm.: 10 1110 11,
|
||||
// signed int, lowest byte written first
|
||||
// signed intptr_t, lowest byte written first
|
||||
//
|
||||
const int kMaxRelocModes = 14;
|
||||
|
||||
@ -158,7 +159,7 @@ void RelocInfoWriter::WriteTaggedPC(uint32_t pc_delta, int tag) {
|
||||
}
|
||||
|
||||
|
||||
void RelocInfoWriter::WriteTaggedData(int32_t data_delta, int tag) {
|
||||
void RelocInfoWriter::WriteTaggedData(intptr_t data_delta, int tag) {
|
||||
*--pos_ = data_delta << kPositionTypeTagBits | tag;
|
||||
}
|
||||
|
||||
@ -178,11 +179,12 @@ void RelocInfoWriter::WriteExtraTaggedPC(uint32_t pc_delta, int extra_tag) {
|
||||
}
|
||||
|
||||
|
||||
void RelocInfoWriter::WriteExtraTaggedData(int32_t data_delta, int top_tag) {
|
||||
void RelocInfoWriter::WriteExtraTaggedData(intptr_t data_delta, int top_tag) {
|
||||
WriteExtraTag(kDataJumpTag, top_tag);
|
||||
for (int i = 0; i < kIntSize; i++) {
|
||||
for (int i = 0; i < kIntptrSize; i++) {
|
||||
*--pos_ = data_delta;
|
||||
data_delta = ArithmeticShiftRight(data_delta, kBitsPerByte);
|
||||
// Signed right shift is arithmetic shift. Tested in test-utils.cc.
|
||||
data_delta = data_delta >> kBitsPerByte;
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,11 +207,13 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) {
|
||||
WriteTaggedPC(pc_delta, kCodeTargetTag);
|
||||
} else if (RelocInfo::IsPosition(rmode)) {
|
||||
// Use signed delta-encoding for data.
|
||||
int32_t data_delta = rinfo->data() - last_data_;
|
||||
intptr_t data_delta = rinfo->data() - last_data_;
|
||||
int pos_type_tag = rmode == RelocInfo::POSITION ? kNonstatementPositionTag
|
||||
: kStatementPositionTag;
|
||||
// Check if data is small enough to fit in a tagged byte.
|
||||
if (is_intn(data_delta, kSmallDataBits)) {
|
||||
// We cannot use is_intn because data_delta is not an int32_t.
|
||||
if (data_delta >= -(1 << (kSmallDataBits-1)) &&
|
||||
data_delta < 1 << (kSmallDataBits-1)) {
|
||||
WriteTaggedPC(pc_delta, kPositionTag);
|
||||
WriteTaggedData(data_delta, pos_type_tag);
|
||||
last_data_ = rinfo->data();
|
||||
@ -263,9 +267,9 @@ inline void RelocIterator::AdvanceReadPC() {
|
||||
|
||||
|
||||
void RelocIterator::AdvanceReadData() {
|
||||
int32_t x = 0;
|
||||
for (int i = 0; i < kIntSize; i++) {
|
||||
x |= *--pos_ << i * kBitsPerByte;
|
||||
intptr_t x = 0;
|
||||
for (int i = 0; i < kIntptrSize; i++) {
|
||||
x |= static_cast<intptr_t>(*--pos_) << i * kBitsPerByte;
|
||||
}
|
||||
rinfo_.data_ += x;
|
||||
}
|
||||
@ -294,7 +298,8 @@ inline int RelocIterator::GetPositionTypeTag() {
|
||||
|
||||
inline void RelocIterator::ReadTaggedData() {
|
||||
int8_t signed_b = *pos_;
|
||||
rinfo_.data_ += ArithmeticShiftRight(signed_b, kPositionTypeTagBits);
|
||||
// Signed right shift is arithmetic shift. Tested in test-utils.cc.
|
||||
rinfo_.data_ += signed_b >> kPositionTypeTagBits;
|
||||
}
|
||||
|
||||
|
||||
|
11
deps/v8/src/assembler.h
vendored
11
deps/v8/src/assembler.h
vendored
@ -40,7 +40,8 @@
|
||||
#include "zone-inl.h"
|
||||
#include "token.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -271,8 +272,8 @@ class RelocInfoWriter BASE_EMBEDDED {
|
||||
inline uint32_t WriteVariableLengthPCJump(uint32_t pc_delta);
|
||||
inline void WriteTaggedPC(uint32_t pc_delta, int tag);
|
||||
inline void WriteExtraTaggedPC(uint32_t pc_delta, int extra_tag);
|
||||
inline void WriteExtraTaggedData(int32_t data_delta, int top_tag);
|
||||
inline void WriteTaggedData(int32_t data_delta, int tag);
|
||||
inline void WriteExtraTaggedData(intptr_t data_delta, int top_tag);
|
||||
inline void WriteTaggedData(intptr_t data_delta, int tag);
|
||||
inline void WriteExtraTag(int extra_tag, int top_tag);
|
||||
|
||||
byte* pos_;
|
||||
@ -423,8 +424,6 @@ class ExternalReference BASE_EMBEDDED {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Utility functions
|
||||
|
||||
// Move these into inline file?
|
||||
|
||||
static inline bool is_intn(int x, int n) {
|
||||
return -(1 << (n-1)) <= x && x < (1 << (n-1));
|
||||
}
|
||||
@ -436,9 +435,11 @@ static inline bool is_uintn(int x, int n) {
|
||||
return (x & -(1 << n)) == 0;
|
||||
}
|
||||
|
||||
static inline bool is_uint2(int x) { return is_uintn(x, 2); }
|
||||
static inline bool is_uint3(int x) { return is_uintn(x, 3); }
|
||||
static inline bool is_uint4(int x) { return is_uintn(x, 4); }
|
||||
static inline bool is_uint5(int x) { return is_uintn(x, 5); }
|
||||
static inline bool is_uint6(int x) { return is_uintn(x, 6); }
|
||||
static inline bool is_uint8(int x) { return is_uintn(x, 8); }
|
||||
static inline bool is_uint12(int x) { return is_uintn(x, 12); }
|
||||
static inline bool is_uint16(int x) { return is_uintn(x, 16); }
|
||||
|
3
deps/v8/src/ast.cc
vendored
3
deps/v8/src/ast.cc
vendored
@ -31,7 +31,8 @@
|
||||
#include "scopes.h"
|
||||
#include "string-stream.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
VariableProxySentinel VariableProxySentinel::this_proxy_(true);
|
||||
|
3
deps/v8/src/ast.h
vendored
3
deps/v8/src/ast.h
vendored
@ -37,7 +37,8 @@
|
||||
#include "jsregexp.h"
|
||||
#include "jump-target.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The abstract syntax tree is an intermediate, light-weight
|
||||
// representation of the parsed JavaScript code suitable for
|
||||
|
80
deps/v8/src/bootstrapper.cc
vendored
80
deps/v8/src/bootstrapper.cc
vendored
@ -37,7 +37,8 @@
|
||||
#include "macro-assembler.h"
|
||||
#include "natives.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// A SourceCodeCache uses a FixedArray to store pairs of
|
||||
// (AsciiString*, JSFunction*), mapping names of native code files
|
||||
@ -46,7 +47,7 @@ namespace v8 { namespace internal {
|
||||
// generate an index for each native JS file.
|
||||
class SourceCodeCache BASE_EMBEDDED {
|
||||
public:
|
||||
explicit SourceCodeCache(ScriptType type): type_(type) { }
|
||||
explicit SourceCodeCache(Script::Type type): type_(type) { }
|
||||
|
||||
void Initialize(bool create_heap_objects) {
|
||||
if (create_heap_objects) {
|
||||
@ -88,13 +89,13 @@ class SourceCodeCache BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
private:
|
||||
ScriptType type_;
|
||||
Script::Type type_;
|
||||
FixedArray* cache_;
|
||||
DISALLOW_COPY_AND_ASSIGN(SourceCodeCache);
|
||||
};
|
||||
|
||||
static SourceCodeCache natives_cache(SCRIPT_TYPE_NATIVE);
|
||||
static SourceCodeCache extensions_cache(SCRIPT_TYPE_EXTENSION);
|
||||
static SourceCodeCache natives_cache(Script::TYPE_NATIVE);
|
||||
static SourceCodeCache extensions_cache(Script::TYPE_EXTENSION);
|
||||
|
||||
|
||||
Handle<String> Bootstrapper::NativesSourceLookup(int index) {
|
||||
@ -521,7 +522,7 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
|
||||
empty_function->set_code(*code);
|
||||
Handle<String> source = Factory::NewStringFromAscii(CStrVector("() {}"));
|
||||
Handle<Script> script = Factory::NewScript(source);
|
||||
script->set_type(Smi::FromInt(SCRIPT_TYPE_NATIVE));
|
||||
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
|
||||
empty_function->shared()->set_script(*script);
|
||||
empty_function->shared()->set_start_position(0);
|
||||
empty_function->shared()->set_end_position(source->length());
|
||||
@ -820,14 +821,28 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
|
||||
global_context()->set_context_extension_function(*context_extension_fun);
|
||||
}
|
||||
|
||||
// Setup the call-as-function delegate.
|
||||
Handle<Code> code =
|
||||
Handle<Code>(Builtins::builtin(Builtins::HandleApiCallAsFunction));
|
||||
Handle<JSFunction> delegate =
|
||||
Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
|
||||
JSObject::kHeaderSize, code, true);
|
||||
global_context()->set_call_as_function_delegate(*delegate);
|
||||
delegate->shared()->DontAdaptArguments();
|
||||
|
||||
{
|
||||
// Setup the call-as-function delegate.
|
||||
Handle<Code> code =
|
||||
Handle<Code>(Builtins::builtin(Builtins::HandleApiCallAsFunction));
|
||||
Handle<JSFunction> delegate =
|
||||
Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
|
||||
JSObject::kHeaderSize, code, true);
|
||||
global_context()->set_call_as_function_delegate(*delegate);
|
||||
delegate->shared()->DontAdaptArguments();
|
||||
}
|
||||
|
||||
{
|
||||
// Setup the call-as-constructor delegate.
|
||||
Handle<Code> code =
|
||||
Handle<Code>(Builtins::builtin(Builtins::HandleApiCallAsConstructor));
|
||||
Handle<JSFunction> delegate =
|
||||
Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
|
||||
JSObject::kHeaderSize, code, true);
|
||||
global_context()->set_call_as_constructor_delegate(*delegate);
|
||||
delegate->shared()->DontAdaptArguments();
|
||||
}
|
||||
|
||||
global_context()->set_special_function_table(Heap::empty_fixed_array());
|
||||
|
||||
@ -1047,6 +1062,14 @@ bool Genesis::InstallNatives() {
|
||||
Factory::LookupAsciiSymbol("type"),
|
||||
proxy_type,
|
||||
common_attributes);
|
||||
Handle<Proxy> proxy_compilation_type =
|
||||
Factory::NewProxy(&Accessors::ScriptCompilationType);
|
||||
script_descriptors =
|
||||
Factory::CopyAppendProxyDescriptor(
|
||||
script_descriptors,
|
||||
Factory::LookupAsciiSymbol("compilation_type"),
|
||||
proxy_compilation_type,
|
||||
common_attributes);
|
||||
Handle<Proxy> proxy_line_ends =
|
||||
Factory::NewProxy(&Accessors::ScriptLineEnds);
|
||||
script_descriptors =
|
||||
@ -1063,16 +1086,38 @@ bool Genesis::InstallNatives() {
|
||||
Factory::LookupAsciiSymbol("context_data"),
|
||||
proxy_context_data,
|
||||
common_attributes);
|
||||
Handle<Proxy> proxy_eval_from_function =
|
||||
Factory::NewProxy(&Accessors::ScriptEvalFromFunction);
|
||||
script_descriptors =
|
||||
Factory::CopyAppendProxyDescriptor(
|
||||
script_descriptors,
|
||||
Factory::LookupAsciiSymbol("eval_from_function"),
|
||||
proxy_eval_from_function,
|
||||
common_attributes);
|
||||
Handle<Proxy> proxy_eval_from_position =
|
||||
Factory::NewProxy(&Accessors::ScriptEvalFromPosition);
|
||||
script_descriptors =
|
||||
Factory::CopyAppendProxyDescriptor(
|
||||
script_descriptors,
|
||||
Factory::LookupAsciiSymbol("eval_from_position"),
|
||||
proxy_eval_from_position,
|
||||
common_attributes);
|
||||
|
||||
Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
|
||||
script_map->set_instance_descriptors(*script_descriptors);
|
||||
|
||||
// Allocate the empty script.
|
||||
Handle<Script> script = Factory::NewScript(Factory::empty_string());
|
||||
script->set_type(Smi::FromInt(SCRIPT_TYPE_NATIVE));
|
||||
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
|
||||
global_context()->set_empty_script(*script);
|
||||
}
|
||||
|
||||
#ifdef V8_HOST_ARCH_64_BIT
|
||||
// TODO(X64): Reenable remaining initialization when code generation works.
|
||||
return true;
|
||||
#endif // V8_HOST_ARCH_64_BIT
|
||||
|
||||
|
||||
if (FLAG_natives_file == NULL) {
|
||||
// Without natives file, install default natives.
|
||||
for (int i = Natives::GetDelayCount();
|
||||
@ -1509,8 +1554,8 @@ Genesis::Genesis(Handle<Object> global_object,
|
||||
current_ = this;
|
||||
result_ = NULL;
|
||||
|
||||
// If V8 hasn't been and cannot be initialized, just return.
|
||||
if (!V8::HasBeenSetup() && !V8::Initialize(NULL)) return;
|
||||
// If V8 isn't running and cannot be initialized, just return.
|
||||
if (!V8::IsRunning() && !V8::Initialize(NULL)) return;
|
||||
|
||||
// Before creating the roots we must save the context and restore it
|
||||
// on all function exits.
|
||||
@ -1518,6 +1563,7 @@ Genesis::Genesis(Handle<Object> global_object,
|
||||
SaveContext context;
|
||||
|
||||
CreateRoots(global_template, global_object);
|
||||
|
||||
if (!InstallNatives()) return;
|
||||
|
||||
MakeFunctionInstancePrototypeWritable();
|
||||
|
3
deps/v8/src/bootstrapper.h
vendored
3
deps/v8/src/bootstrapper.h
vendored
@ -29,7 +29,8 @@
|
||||
#ifndef V8_BOOTSTRAPPER_H_
|
||||
#define V8_BOOTSTRAPPER_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The Boostrapper is the public interface for creating a JavaScript global
|
||||
// context.
|
||||
|
46
deps/v8/src/builtins.cc
vendored
46
deps/v8/src/builtins.cc
vendored
@ -32,7 +32,8 @@
|
||||
#include "builtins.h"
|
||||
#include "ic-inl.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Support macros for defining builtins in C.
|
||||
@ -394,12 +395,18 @@ BUILTIN(HandleApiCall) {
|
||||
BUILTIN_END
|
||||
|
||||
|
||||
// Handle calls to non-function objects created through the API that
|
||||
// support calls.
|
||||
BUILTIN(HandleApiCallAsFunction) {
|
||||
// Non-functions are never called as constructors.
|
||||
// Helper function to handle calls to non-function objects created through the
|
||||
// API. The object can be called as either a constructor (using new) or just as
|
||||
// a function (without new).
|
||||
static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
|
||||
int __argc__,
|
||||
Object** __argv__) {
|
||||
// Non-functions are never called as constructors. Even if this is an object
|
||||
// called as a constructor the delegate call is not a construct call.
|
||||
ASSERT(!CalledAsConstructor());
|
||||
|
||||
Handle<Object> receiver(&__argv__[0]);
|
||||
|
||||
// Get the object called.
|
||||
JSObject* obj = JSObject::cast(*receiver);
|
||||
|
||||
@ -431,7 +438,7 @@ BUILTIN(HandleApiCallAsFunction) {
|
||||
data,
|
||||
self,
|
||||
callee,
|
||||
false,
|
||||
is_construct_call,
|
||||
reinterpret_cast<void**>(__argv__ - 1),
|
||||
__argc__ - 1);
|
||||
v8::Handle<v8::Value> value;
|
||||
@ -450,6 +457,21 @@ BUILTIN(HandleApiCallAsFunction) {
|
||||
RETURN_IF_SCHEDULED_EXCEPTION();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Handle calls to non-function objects created through the API. This delegate
|
||||
// function is used when the call is a normal function call.
|
||||
BUILTIN(HandleApiCallAsFunction) {
|
||||
return HandleApiCallAsFunctionOrConstructor(false, __argc__, __argv__);
|
||||
}
|
||||
BUILTIN_END
|
||||
|
||||
|
||||
// Handle calls to non-function objects created through the API. This delegate
|
||||
// function is used when the call is a construct call.
|
||||
BUILTIN(HandleApiCallAsConstructor) {
|
||||
return HandleApiCallAsFunctionOrConstructor(true, __argc__, __argv__);
|
||||
}
|
||||
BUILTIN_END
|
||||
|
||||
|
||||
@ -644,12 +666,12 @@ void Builtins::Setup(bool create_heap_objects) {
|
||||
Code::ComputeFlags(Code::BUILTIN) \
|
||||
},
|
||||
|
||||
#define DEF_FUNCTION_PTR_A(name, kind, state) \
|
||||
{ FUNCTION_ADDR(Generate_##name), \
|
||||
NULL, \
|
||||
#name, \
|
||||
name, \
|
||||
Code::ComputeFlags(Code::kind, state) \
|
||||
#define DEF_FUNCTION_PTR_A(name, kind, state) \
|
||||
{ FUNCTION_ADDR(Generate_##name), \
|
||||
NULL, \
|
||||
#name, \
|
||||
name, \
|
||||
Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state) \
|
||||
},
|
||||
|
||||
// Define array of pointers to generators and C builtin functions.
|
||||
|
65
deps/v8/src/builtins.h
vendored
65
deps/v8/src/builtins.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_BUILTINS_H_
|
||||
#define V8_BUILTINS_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Define list of builtins implemented in C.
|
||||
#define BUILTIN_LIST_C(V) \
|
||||
@ -42,7 +43,8 @@ namespace v8 { namespace internal {
|
||||
V(ArrayPop) \
|
||||
\
|
||||
V(HandleApiCall) \
|
||||
V(HandleApiCallAsFunction)
|
||||
V(HandleApiCallAsFunction) \
|
||||
V(HandleApiCallAsConstructor)
|
||||
|
||||
|
||||
// Define list of builtins implemented in assembly.
|
||||
@ -99,35 +101,36 @@ namespace v8 { namespace internal {
|
||||
#endif
|
||||
|
||||
// Define list of builtins implemented in JavaScript.
|
||||
#define BUILTINS_LIST_JS(V) \
|
||||
V(EQUALS, 1) \
|
||||
V(STRICT_EQUALS, 1) \
|
||||
V(COMPARE, 2) \
|
||||
V(ADD, 1) \
|
||||
V(SUB, 1) \
|
||||
V(MUL, 1) \
|
||||
V(DIV, 1) \
|
||||
V(MOD, 1) \
|
||||
V(BIT_OR, 1) \
|
||||
V(BIT_AND, 1) \
|
||||
V(BIT_XOR, 1) \
|
||||
V(UNARY_MINUS, 0) \
|
||||
V(BIT_NOT, 0) \
|
||||
V(SHL, 1) \
|
||||
V(SAR, 1) \
|
||||
V(SHR, 1) \
|
||||
V(DELETE, 1) \
|
||||
V(IN, 1) \
|
||||
V(INSTANCE_OF, 1) \
|
||||
V(GET_KEYS, 0) \
|
||||
V(FILTER_KEY, 1) \
|
||||
V(CALL_NON_FUNCTION, 0) \
|
||||
V(TO_OBJECT, 0) \
|
||||
V(TO_NUMBER, 0) \
|
||||
V(TO_STRING, 0) \
|
||||
V(STRING_ADD_LEFT, 1) \
|
||||
V(STRING_ADD_RIGHT, 1) \
|
||||
V(APPLY_PREPARE, 1) \
|
||||
#define BUILTINS_LIST_JS(V) \
|
||||
V(EQUALS, 1) \
|
||||
V(STRICT_EQUALS, 1) \
|
||||
V(COMPARE, 2) \
|
||||
V(ADD, 1) \
|
||||
V(SUB, 1) \
|
||||
V(MUL, 1) \
|
||||
V(DIV, 1) \
|
||||
V(MOD, 1) \
|
||||
V(BIT_OR, 1) \
|
||||
V(BIT_AND, 1) \
|
||||
V(BIT_XOR, 1) \
|
||||
V(UNARY_MINUS, 0) \
|
||||
V(BIT_NOT, 0) \
|
||||
V(SHL, 1) \
|
||||
V(SAR, 1) \
|
||||
V(SHR, 1) \
|
||||
V(DELETE, 1) \
|
||||
V(IN, 1) \
|
||||
V(INSTANCE_OF, 1) \
|
||||
V(GET_KEYS, 0) \
|
||||
V(FILTER_KEY, 1) \
|
||||
V(CALL_NON_FUNCTION, 0) \
|
||||
V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \
|
||||
V(TO_OBJECT, 0) \
|
||||
V(TO_NUMBER, 0) \
|
||||
V(TO_STRING, 0) \
|
||||
V(STRING_ADD_LEFT, 1) \
|
||||
V(STRING_ADD_RIGHT, 1) \
|
||||
V(APPLY_PREPARE, 1) \
|
||||
V(APPLY_OVERFLOW, 1)
|
||||
|
||||
|
||||
|
3
deps/v8/src/bytecodes-irregexp.h
vendored
3
deps/v8/src/bytecodes-irregexp.h
vendored
@ -29,7 +29,8 @@
|
||||
#ifndef V8_BYTECODES_IRREGEXP_H_
|
||||
#define V8_BYTECODES_IRREGEXP_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
static const int BYTECODE_MASK = 0xff;
|
||||
|
3
deps/v8/src/char-predicates-inl.h
vendored
3
deps/v8/src/char-predicates-inl.h
vendored
@ -30,7 +30,8 @@
|
||||
|
||||
#include "char-predicates.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
inline bool IsCarriageReturn(uc32 c) {
|
||||
|
3
deps/v8/src/char-predicates.h
vendored
3
deps/v8/src/char-predicates.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_CHAR_PREDICATES_H_
|
||||
#define V8_CHAR_PREDICATES_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Unicode character predicates as defined by ECMA-262, 3rd,
|
||||
// used for lexical analysis.
|
||||
|
5
deps/v8/src/code-stubs.cc
vendored
5
deps/v8/src/code-stubs.cc
vendored
@ -32,7 +32,8 @@
|
||||
#include "factory.h"
|
||||
#include "macro-assembler.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
Handle<Code> CodeStub::GetCode() {
|
||||
uint32_t key = GetKey();
|
||||
@ -58,7 +59,7 @@ Handle<Code> CodeStub::GetCode() {
|
||||
masm.GetCode(&desc);
|
||||
|
||||
// Copy the generated code into a heap object, and store the major key.
|
||||
Code::Flags flags = Code::ComputeFlags(Code::STUB);
|
||||
Code::Flags flags = Code::ComputeFlags(Code::STUB, InLoop());
|
||||
Handle<Code> code = Factory::NewCode(desc, NULL, flags, masm.CodeObject());
|
||||
code->set_major_key(MajorKey());
|
||||
|
||||
|
7
deps/v8/src/code-stubs.h
vendored
7
deps/v8/src/code-stubs.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_CODE_STUBS_H_
|
||||
#define V8_CODE_STUBS_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// Stub is base classes of all stubs.
|
||||
@ -82,6 +83,10 @@ class CodeStub BASE_EMBEDDED {
|
||||
virtual Major MajorKey() = 0;
|
||||
virtual int MinorKey() = 0;
|
||||
|
||||
// The CallFunctionStub needs to override this so it can encode whether a
|
||||
// lazily generated function should be fully optimized or not.
|
||||
virtual InLoopFlag InLoop() { return NOT_IN_LOOP; }
|
||||
|
||||
// Returns a name for logging/debugging purposes.
|
||||
virtual const char* GetName() { return MajorName(MajorKey()); }
|
||||
|
||||
|
3
deps/v8/src/code.h
vendored
3
deps/v8/src/code.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_CODE_H_
|
||||
#define V8_CODE_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// Wrapper class for passing expected and actual parameter counts as
|
||||
|
27
deps/v8/src/codegen-inl.h
vendored
27
deps/v8/src/codegen-inl.h
vendored
@ -30,10 +30,24 @@
|
||||
#define V8_CODEGEN_INL_H_
|
||||
|
||||
#include "codegen.h"
|
||||
#include "register-allocator-inl.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
#include "ia32/codegen-ia32-inl.h"
|
||||
#elif V8_TARGET_ARCH_X64
|
||||
#include "x64/codegen-x64-inl.h"
|
||||
#elif V8_TARGET_ARCH_ARM
|
||||
#include "arm/codegen-arm-inl.h"
|
||||
#else
|
||||
#error Unsupported target architecture.
|
||||
#endif
|
||||
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ ACCESS_MASM(masm_)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Support for "structured" code comments.
|
||||
//
|
||||
@ -44,15 +58,12 @@ namespace v8 { namespace internal {
|
||||
|
||||
class Comment BASE_EMBEDDED {
|
||||
public:
|
||||
Comment(MacroAssembler* masm, const char* msg)
|
||||
: masm_(masm),
|
||||
msg_(msg) {
|
||||
masm_->RecordComment(msg);
|
||||
Comment(MacroAssembler* masm, const char* msg) : masm_(masm), msg_(msg) {
|
||||
__ RecordComment(msg);
|
||||
}
|
||||
|
||||
~Comment() {
|
||||
if (msg_[0] == '[')
|
||||
masm_->RecordComment("]");
|
||||
if (msg_[0] == '[') __ RecordComment("]");
|
||||
}
|
||||
|
||||
private:
|
||||
@ -69,6 +80,8 @@ class Comment BASE_EMBEDDED {
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
#undef __
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
|
96
deps/v8/src/codegen.cc
vendored
96
deps/v8/src/codegen.cc
vendored
@ -38,27 +38,41 @@
|
||||
#include "scopeinfo.h"
|
||||
#include "stub-cache.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
DeferredCode::DeferredCode(CodeGenerator* generator)
|
||||
: generator_(generator),
|
||||
masm_(generator->masm()),
|
||||
enter_(generator),
|
||||
exit_(generator, JumpTarget::BIDIRECTIONAL),
|
||||
statement_position_(masm_->current_statement_position()),
|
||||
position_(masm_->current_position()) {
|
||||
generator->AddDeferred(this);
|
||||
|
||||
CodeGenerator* CodeGeneratorScope::top_ = NULL;
|
||||
|
||||
|
||||
DeferredCode::DeferredCode()
|
||||
: masm_(CodeGeneratorScope::Current()->masm()),
|
||||
statement_position_(masm_->current_statement_position()),
|
||||
position_(masm_->current_position()) {
|
||||
ASSERT(statement_position_ != RelocInfo::kNoPosition);
|
||||
ASSERT(position_ != RelocInfo::kNoPosition);
|
||||
|
||||
CodeGeneratorScope::Current()->AddDeferred(this);
|
||||
#ifdef DEBUG
|
||||
comment_ = "";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::ClearDeferred() {
|
||||
for (int i = 0; i < deferred_.length(); i++) {
|
||||
deferred_[i]->Clear();
|
||||
// Copy the register locations from the code generator's frame.
|
||||
// These are the registers that will be spilled on entry to the
|
||||
// deferred code and restored on exit.
|
||||
VirtualFrame* frame = CodeGeneratorScope::Current()->frame();
|
||||
int sp_offset = frame->fp_relative(frame->stack_pointer_);
|
||||
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
|
||||
int loc = frame->register_location(i);
|
||||
if (loc == VirtualFrame::kIllegalIndex) {
|
||||
registers_[i] = kIgnore;
|
||||
} else if (frame->elements_[loc].is_synced()) {
|
||||
// Needs to be restored on exit but not saved on entry.
|
||||
registers_[i] = frame->fp_relative(loc) | kSyncedFlag;
|
||||
} else {
|
||||
int offset = frame->fp_relative(loc);
|
||||
registers_[i] = (offset < sp_offset) ? kPush : offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,17 +80,19 @@ void CodeGenerator::ClearDeferred() {
|
||||
void CodeGenerator::ProcessDeferred() {
|
||||
while (!deferred_.is_empty()) {
|
||||
DeferredCode* code = deferred_.RemoveLast();
|
||||
MacroAssembler* masm = code->masm();
|
||||
ASSERT(masm_ == code->masm());
|
||||
// Record position of deferred code stub.
|
||||
masm->RecordStatementPosition(code->statement_position());
|
||||
masm_->RecordStatementPosition(code->statement_position());
|
||||
if (code->position() != RelocInfo::kNoPosition) {
|
||||
masm->RecordPosition(code->position());
|
||||
masm_->RecordPosition(code->position());
|
||||
}
|
||||
// Generate the code.
|
||||
Comment cmnt(masm, code->comment());
|
||||
Comment cmnt(masm_, code->comment());
|
||||
masm_->bind(code->entry_label());
|
||||
code->SaveRegisters();
|
||||
code->Generate();
|
||||
ASSERT(code->enter()->is_bound());
|
||||
code->Clear();
|
||||
code->RestoreRegisters();
|
||||
masm_->jmp(code->exit_label());
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +120,6 @@ void CodeGenerator::SetFrame(VirtualFrame* new_frame,
|
||||
void CodeGenerator::DeleteFrame() {
|
||||
if (has_valid_frame()) {
|
||||
frame_->DetachFromCodeGenerator();
|
||||
delete frame_;
|
||||
frame_ = NULL;
|
||||
}
|
||||
}
|
||||
@ -155,17 +170,21 @@ Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* flit,
|
||||
// Generate code.
|
||||
const int initial_buffer_size = 4 * KB;
|
||||
CodeGenerator cgen(initial_buffer_size, script, is_eval);
|
||||
CodeGeneratorScope scope(&cgen);
|
||||
cgen.GenCode(flit);
|
||||
if (cgen.HasStackOverflow()) {
|
||||
ASSERT(!Top::has_pending_exception());
|
||||
return Handle<Code>::null();
|
||||
}
|
||||
|
||||
// Allocate and install the code.
|
||||
// Allocate and install the code. Time the rest of this function as
|
||||
// code creation.
|
||||
HistogramTimerScope timer(&Counters::code_creation);
|
||||
CodeDesc desc;
|
||||
cgen.masm()->GetCode(&desc);
|
||||
ScopeInfo<> sinfo(flit->scope());
|
||||
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
|
||||
ZoneScopeInfo sinfo(flit->scope());
|
||||
InLoopFlag in_loop = (cgen.loop_nesting() != 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop);
|
||||
Handle<Code> code = Factory::NewCode(desc,
|
||||
&sinfo,
|
||||
flags,
|
||||
@ -206,7 +225,7 @@ Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* flit,
|
||||
|
||||
bool CodeGenerator::ShouldGenerateLog(Expression* type) {
|
||||
ASSERT(type != NULL);
|
||||
if (!Logger::is_enabled()) return false;
|
||||
if (!Logger::IsEnabled()) return false;
|
||||
Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
|
||||
if (FLAG_log_regexp) {
|
||||
static Vector<const char> kRegexp = CStrVector("regexp");
|
||||
@ -317,17 +336,18 @@ Handle<JSFunction> CodeGenerator::BuildBoilerplate(FunctionLiteral* node) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> CodeGenerator::ComputeCallInitialize(int argc) {
|
||||
CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc), Code);
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> CodeGenerator::ComputeCallInitializeInLoop(int argc) {
|
||||
// Force the creation of the corresponding stub outside loops,
|
||||
// because it will be used when clearing the ICs later - when we
|
||||
// don't know if we're inside a loop or not.
|
||||
ComputeCallInitialize(argc);
|
||||
CALL_HEAP_FUNCTION(StubCache::ComputeCallInitializeInLoop(argc), Code);
|
||||
Handle<Code> CodeGenerator::ComputeCallInitialize(
|
||||
int argc,
|
||||
InLoopFlag in_loop) {
|
||||
if (in_loop == IN_LOOP) {
|
||||
// Force the creation of the corresponding stub outside loops,
|
||||
// because it may be used when clearing the ICs later - it is
|
||||
// possible for a series of IC transitions to lose the in-loop
|
||||
// information, and the IC clearing code can't generate a stub
|
||||
// that it needs so we need to ensure it is generated already.
|
||||
ComputeCallInitialize(argc, NOT_IN_LOOP);
|
||||
}
|
||||
CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc, in_loop), Code);
|
||||
}
|
||||
|
||||
|
||||
@ -507,8 +527,8 @@ void CodeGenerator::GenerateFastCaseSwitchCases(
|
||||
// frame. Otherwise, we have to merge the existing one to the
|
||||
// start frame as part of the previous case.
|
||||
if (!has_valid_frame()) {
|
||||
RegisterFile non_frame_registers = RegisterAllocator::Reserved();
|
||||
SetFrame(new VirtualFrame(start_frame), &non_frame_registers);
|
||||
RegisterFile empty;
|
||||
SetFrame(new VirtualFrame(start_frame), &empty);
|
||||
} else {
|
||||
frame_->MergeTo(start_frame);
|
||||
}
|
||||
|
89
deps/v8/src/codegen.h
vendored
89
deps/v8/src/codegen.h
vendored
@ -52,7 +52,6 @@
|
||||
// CodeGenerator
|
||||
// ~CodeGenerator
|
||||
// ProcessDeferred
|
||||
// ClearDeferred
|
||||
// GenCode
|
||||
// BuildBoilerplate
|
||||
// ComputeCallInitialize
|
||||
@ -86,14 +85,34 @@ enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
|
||||
#include "arm/codegen-arm.h"
|
||||
#endif
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
#include "register-allocator.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// Use lazy compilation; defaults to true.
|
||||
// NOTE: Do not remove non-lazy compilation until we can properly
|
||||
// install extensions with lazy compilation enabled. At the
|
||||
// moment, this doesn't work for the extensions in Google3,
|
||||
// and we can only run the tests with --nolazy.
|
||||
// Code generation can be nested. Code generation scopes form a stack
|
||||
// of active code generators.
|
||||
class CodeGeneratorScope BASE_EMBEDDED {
|
||||
public:
|
||||
explicit CodeGeneratorScope(CodeGenerator* cgen) {
|
||||
previous_ = top_;
|
||||
top_ = cgen;
|
||||
}
|
||||
|
||||
~CodeGeneratorScope() {
|
||||
top_ = previous_;
|
||||
}
|
||||
|
||||
static CodeGenerator* Current() {
|
||||
ASSERT(top_ != NULL);
|
||||
return top_;
|
||||
}
|
||||
|
||||
private:
|
||||
static CodeGenerator* top_;
|
||||
CodeGenerator* previous_;
|
||||
};
|
||||
|
||||
|
||||
// Deferred code objects are small pieces of code that are compiled
|
||||
@ -101,52 +120,56 @@ namespace v8 { namespace internal {
|
||||
// paths thereby avoiding expensive jumps around uncommon code parts.
|
||||
class DeferredCode: public ZoneObject {
|
||||
public:
|
||||
explicit DeferredCode(CodeGenerator* generator);
|
||||
DeferredCode();
|
||||
virtual ~DeferredCode() { }
|
||||
|
||||
virtual void Generate() = 0;
|
||||
|
||||
// Unuse the entry and exit targets, deallocating all virtual frames
|
||||
// held by them. It will be impossible to emit a (correct) jump
|
||||
// into or out of the deferred code after clearing.
|
||||
void Clear() {
|
||||
enter_.Unuse();
|
||||
exit_.Unuse();
|
||||
}
|
||||
|
||||
MacroAssembler* masm() const { return masm_; }
|
||||
CodeGenerator* generator() const { return generator_; }
|
||||
|
||||
JumpTarget* enter() { return &enter_; }
|
||||
void BindExit() { exit_.Bind(0); }
|
||||
void BindExit(Result* result) { exit_.Bind(result, 1); }
|
||||
void BindExit(Result* result0, Result* result1) {
|
||||
exit_.Bind(result0, result1, 2);
|
||||
}
|
||||
void BindExit(Result* result0, Result* result1, Result* result2) {
|
||||
exit_.Bind(result0, result1, result2, 3);
|
||||
}
|
||||
MacroAssembler* masm() { return masm_; }
|
||||
|
||||
int statement_position() const { return statement_position_; }
|
||||
int position() const { return position_; }
|
||||
|
||||
Label* entry_label() { return &entry_label_; }
|
||||
Label* exit_label() { return &exit_label_; }
|
||||
|
||||
#ifdef DEBUG
|
||||
void set_comment(const char* comment) { comment_ = comment; }
|
||||
const char* comment() const { return comment_; }
|
||||
#else
|
||||
inline void set_comment(const char* comment) { }
|
||||
void set_comment(const char* comment) { }
|
||||
const char* comment() const { return ""; }
|
||||
#endif
|
||||
|
||||
inline void Jump();
|
||||
inline void Branch(Condition cc);
|
||||
void BindExit() { masm_->bind(&exit_label_); }
|
||||
|
||||
void SaveRegisters();
|
||||
void RestoreRegisters();
|
||||
|
||||
protected:
|
||||
CodeGenerator* const generator_;
|
||||
MacroAssembler* const masm_;
|
||||
JumpTarget enter_;
|
||||
JumpTarget exit_;
|
||||
MacroAssembler* masm_;
|
||||
|
||||
private:
|
||||
// Constants indicating special actions. They should not be multiples
|
||||
// of kPointerSize so they will not collide with valid offsets from
|
||||
// the frame pointer.
|
||||
static const int kIgnore = -1;
|
||||
static const int kPush = 1;
|
||||
|
||||
// This flag is ored with a valid offset from the frame pointer, so
|
||||
// it should fit in the low zero bits of a valid offset.
|
||||
static const int kSyncedFlag = 2;
|
||||
|
||||
int statement_position_;
|
||||
int position_;
|
||||
|
||||
Label entry_label_;
|
||||
Label exit_label_;
|
||||
|
||||
int registers_[RegisterAllocator::kNumRegisters];
|
||||
|
||||
#ifdef DEBUG
|
||||
const char* comment_;
|
||||
#endif
|
||||
|
165
deps/v8/src/compilation-cache.cc
vendored
165
deps/v8/src/compilation-cache.cc
vendored
@ -29,15 +29,30 @@
|
||||
|
||||
#include "compilation-cache.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
enum {
|
||||
NUMBER_OF_ENTRY_KINDS = CompilationCache::LAST_ENTRY + 1
|
||||
// The number of script generations tell how many GCs a script can
|
||||
// survive in the compilation cache, before it will be flushed if it
|
||||
// hasn't been used.
|
||||
NUMBER_OF_SCRIPT_GENERATIONS = 5,
|
||||
|
||||
// The compilation cache consists of tables - one for each entry
|
||||
// kind plus extras for the script generations.
|
||||
NUMBER_OF_TABLE_ENTRIES =
|
||||
CompilationCache::LAST_ENTRY + NUMBER_OF_SCRIPT_GENERATIONS
|
||||
};
|
||||
|
||||
|
||||
// Current enable state of the compilation cache.
|
||||
static bool enabled = true;
|
||||
static inline bool IsEnabled() {
|
||||
return FLAG_compilation_cache && enabled;
|
||||
}
|
||||
|
||||
// Keep separate tables for the different entry kinds.
|
||||
static Object* tables[NUMBER_OF_ENTRY_KINDS] = { 0, };
|
||||
static Object* tables[NUMBER_OF_TABLE_ENTRIES] = { 0, };
|
||||
|
||||
|
||||
static Handle<CompilationCacheTable> AllocateTable(int size) {
|
||||
@ -46,14 +61,15 @@ static Handle<CompilationCacheTable> AllocateTable(int size) {
|
||||
}
|
||||
|
||||
|
||||
static Handle<CompilationCacheTable> GetTable(CompilationCache::Entry entry) {
|
||||
static Handle<CompilationCacheTable> GetTable(int index) {
|
||||
ASSERT(index >= 0 && index < NUMBER_OF_TABLE_ENTRIES);
|
||||
Handle<CompilationCacheTable> result;
|
||||
if (tables[entry]->IsUndefined()) {
|
||||
if (tables[index]->IsUndefined()) {
|
||||
static const int kInitialCacheSize = 64;
|
||||
result = AllocateTable(kInitialCacheSize);
|
||||
tables[entry] = *result;
|
||||
tables[index] = *result;
|
||||
} else {
|
||||
CompilationCacheTable* table = CompilationCacheTable::cast(tables[entry]);
|
||||
CompilationCacheTable* table = CompilationCacheTable::cast(tables[index]);
|
||||
result = Handle<CompilationCacheTable>(table);
|
||||
}
|
||||
return result;
|
||||
@ -121,47 +137,80 @@ static bool HasOrigin(Handle<JSFunction> boilerplate,
|
||||
}
|
||||
|
||||
|
||||
static Handle<JSFunction> Lookup(Handle<String> source,
|
||||
CompilationCache::Entry entry) {
|
||||
// Make sure not to leak the table into the surrounding handle
|
||||
// scope. Otherwise, we risk keeping old tables around even after
|
||||
// having cleared the cache.
|
||||
Object* result;
|
||||
{ HandleScope scope;
|
||||
Handle<CompilationCacheTable> table = GetTable(entry);
|
||||
result = table->Lookup(*source);
|
||||
}
|
||||
if (result->IsJSFunction()) {
|
||||
return Handle<JSFunction>(JSFunction::cast(result));
|
||||
} else {
|
||||
return Handle<JSFunction>::null();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO(245): Need to allow identical code from different contexts to be
|
||||
// cached. Currently the first use will be cached, but subsequent code
|
||||
// from different source / line won't.
|
||||
// TODO(245): Need to allow identical code from different contexts to
|
||||
// be cached in the same script generation. Currently the first use
|
||||
// will be cached, but subsequent code from different source / line
|
||||
// won't.
|
||||
Handle<JSFunction> CompilationCache::LookupScript(Handle<String> source,
|
||||
Handle<Object> name,
|
||||
int line_offset,
|
||||
int column_offset) {
|
||||
Handle<JSFunction> result = Lookup(source, SCRIPT);
|
||||
if (result.is_null()) {
|
||||
Counters::compilation_cache_misses.Increment();
|
||||
} else if (HasOrigin(result, name, line_offset, column_offset)) {
|
||||
Counters::compilation_cache_hits.Increment();
|
||||
} else {
|
||||
result = Handle<JSFunction>::null();
|
||||
Counters::compilation_cache_misses.Increment();
|
||||
if (!IsEnabled()) {
|
||||
return Handle<JSFunction>::null();
|
||||
}
|
||||
|
||||
// Use an int for the generation index, so value range propagation
|
||||
// in gcc 4.3+ won't assume it can only go up to LAST_ENTRY when in
|
||||
// fact it can go up to SCRIPT + NUMBER_OF_SCRIPT_GENERATIONS.
|
||||
int generation = SCRIPT;
|
||||
Object* result = NULL;
|
||||
|
||||
// Probe the script generation tables. Make sure not to leak handles
|
||||
// into the caller's handle scope.
|
||||
{ HandleScope scope;
|
||||
while (generation < SCRIPT + NUMBER_OF_SCRIPT_GENERATIONS) {
|
||||
Handle<CompilationCacheTable> table = GetTable(generation);
|
||||
Handle<Object> probe(table->Lookup(*source));
|
||||
if (probe->IsJSFunction()) {
|
||||
Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(probe);
|
||||
// Break when we've found a suitable boilerplate function that
|
||||
// matches the origin.
|
||||
if (HasOrigin(boilerplate, name, line_offset, column_offset)) {
|
||||
result = *boilerplate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Go to the next generation.
|
||||
generation++;
|
||||
}
|
||||
}
|
||||
|
||||
static void* script_histogram = StatsTable::CreateHistogram(
|
||||
"V8.ScriptCache",
|
||||
0,
|
||||
NUMBER_OF_SCRIPT_GENERATIONS,
|
||||
NUMBER_OF_SCRIPT_GENERATIONS + 1);
|
||||
|
||||
if (script_histogram != NULL) {
|
||||
// The level NUMBER_OF_SCRIPT_GENERATIONS is equivalent to a cache miss.
|
||||
StatsTable::AddHistogramSample(script_histogram, generation - SCRIPT);
|
||||
}
|
||||
|
||||
// Once outside the manacles of the handle scope, we need to recheck
|
||||
// to see if we actually found a cached script. If so, we return a
|
||||
// handle created in the caller's handle scope.
|
||||
if (result != NULL) {
|
||||
Handle<JSFunction> boilerplate(JSFunction::cast(result));
|
||||
ASSERT(HasOrigin(boilerplate, name, line_offset, column_offset));
|
||||
// If the script was found in a later generation, we promote it to
|
||||
// the first generation to let it survive longer in the cache.
|
||||
if (generation != SCRIPT) PutScript(source, boilerplate);
|
||||
Counters::compilation_cache_hits.Increment();
|
||||
return boilerplate;
|
||||
} else {
|
||||
Counters::compilation_cache_misses.Increment();
|
||||
return Handle<JSFunction>::null();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source,
|
||||
Handle<Context> context,
|
||||
Entry entry) {
|
||||
if (!IsEnabled()) {
|
||||
return Handle<JSFunction>::null();
|
||||
}
|
||||
|
||||
ASSERT(entry == EVAL_GLOBAL || entry == EVAL_CONTEXTUAL);
|
||||
Handle<JSFunction> result = Lookup(source, context, entry);
|
||||
if (result.is_null()) {
|
||||
@ -175,6 +224,10 @@ Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source,
|
||||
|
||||
Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
|
||||
JSRegExp::Flags flags) {
|
||||
if (!IsEnabled()) {
|
||||
return Handle<FixedArray>::null();
|
||||
}
|
||||
|
||||
Handle<FixedArray> result = Lookup(source, flags);
|
||||
if (result.is_null()) {
|
||||
Counters::compilation_cache_misses.Increment();
|
||||
@ -187,6 +240,10 @@ Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
|
||||
|
||||
void CompilationCache::PutScript(Handle<String> source,
|
||||
Handle<JSFunction> boilerplate) {
|
||||
if (!IsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HandleScope scope;
|
||||
ASSERT(boilerplate->IsBoilerplate());
|
||||
Handle<CompilationCacheTable> table = GetTable(SCRIPT);
|
||||
@ -198,6 +255,10 @@ void CompilationCache::PutEval(Handle<String> source,
|
||||
Handle<Context> context,
|
||||
Entry entry,
|
||||
Handle<JSFunction> boilerplate) {
|
||||
if (!IsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HandleScope scope;
|
||||
ASSERT(boilerplate->IsBoilerplate());
|
||||
Handle<CompilationCacheTable> table = GetTable(entry);
|
||||
@ -209,6 +270,10 @@ void CompilationCache::PutEval(Handle<String> source,
|
||||
void CompilationCache::PutRegExp(Handle<String> source,
|
||||
JSRegExp::Flags flags,
|
||||
Handle<FixedArray> data) {
|
||||
if (!IsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HandleScope scope;
|
||||
Handle<CompilationCacheTable> table = GetTable(REGEXP);
|
||||
CALL_HEAP_FUNCTION_VOID(table->PutRegExp(*source, flags, *data));
|
||||
@ -216,14 +281,36 @@ void CompilationCache::PutRegExp(Handle<String> source,
|
||||
|
||||
|
||||
void CompilationCache::Clear() {
|
||||
for (int i = 0; i < NUMBER_OF_ENTRY_KINDS; i++) {
|
||||
for (int i = 0; i < NUMBER_OF_TABLE_ENTRIES; i++) {
|
||||
tables[i] = Heap::undefined_value();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CompilationCache::Iterate(ObjectVisitor* v) {
|
||||
v->VisitPointers(&tables[0], &tables[NUMBER_OF_ENTRY_KINDS]);
|
||||
v->VisitPointers(&tables[0], &tables[NUMBER_OF_TABLE_ENTRIES]);
|
||||
}
|
||||
|
||||
|
||||
void CompilationCache::MarkCompactPrologue() {
|
||||
ASSERT(LAST_ENTRY == SCRIPT);
|
||||
for (int i = NUMBER_OF_TABLE_ENTRIES - 1; i > SCRIPT; i--) {
|
||||
tables[i] = tables[i - 1];
|
||||
}
|
||||
for (int j = 0; j <= LAST_ENTRY; j++) {
|
||||
tables[j] = Heap::undefined_value();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CompilationCache::Enable() {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
|
||||
void CompilationCache::Disable() {
|
||||
enabled = false;
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
|
18
deps/v8/src/compilation-cache.h
vendored
18
deps/v8/src/compilation-cache.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_COMPILATION_CACHE_H_
|
||||
#define V8_COMPILATION_CACHE_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// The compilation cache keeps function boilerplates for compiled
|
||||
@ -40,11 +41,11 @@ class CompilationCache {
|
||||
// scripts and evals. Internally, we use separate caches to avoid
|
||||
// getting the wrong kind of entry when looking up.
|
||||
enum Entry {
|
||||
SCRIPT,
|
||||
EVAL_GLOBAL,
|
||||
EVAL_CONTEXTUAL,
|
||||
REGEXP,
|
||||
LAST_ENTRY = REGEXP
|
||||
SCRIPT,
|
||||
LAST_ENTRY = SCRIPT
|
||||
};
|
||||
|
||||
// Finds the script function boilerplate for a source
|
||||
@ -93,10 +94,13 @@ class CompilationCache {
|
||||
|
||||
// Notify the cache that a mark-sweep garbage collection is about to
|
||||
// take place. This is used to retire entries from the cache to
|
||||
// avoid keeping them alive too long without using them. For now, we
|
||||
// just clear the cache but we should consider are more
|
||||
// sophisticated LRU scheme.
|
||||
static void MarkCompactPrologue() { Clear(); }
|
||||
// avoid keeping them alive too long without using them.
|
||||
static void MarkCompactPrologue();
|
||||
|
||||
// Enable/disable compilation cache. Used by debugger to disable compilation
|
||||
// cache during debugging to make sure new scripts are always compiled.
|
||||
static void Enable();
|
||||
static void Disable();
|
||||
};
|
||||
|
||||
|
||||
|
49
deps/v8/src/compiler.cc
vendored
49
deps/v8/src/compiler.cc
vendored
@ -37,7 +37,8 @@
|
||||
#include "scopes.h"
|
||||
#include "usage-analyzer.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
static Handle<Code> MakeCode(FunctionLiteral* literal,
|
||||
Handle<Script> script,
|
||||
@ -52,12 +53,15 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
|
||||
return Handle<Code>::null();
|
||||
}
|
||||
|
||||
// Compute top scope and allocate variables. For lazy compilation
|
||||
// the top scope only contains the single lazily compiled function,
|
||||
// so this doesn't re-allocate variables repeatedly.
|
||||
Scope* top = literal->scope();
|
||||
while (top->outer_scope() != NULL) top = top->outer_scope();
|
||||
top->AllocateVariables(context);
|
||||
{
|
||||
// Compute top scope and allocate variables. For lazy compilation
|
||||
// the top scope only contains the single lazily compiled function,
|
||||
// so this doesn't re-allocate variables repeatedly.
|
||||
HistogramTimerScope timer(&Counters::variable_allocation);
|
||||
Scope* top = literal->scope();
|
||||
while (top->outer_scope() != NULL) top = top->outer_scope();
|
||||
top->AllocateVariables(context);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (Bootstrapper::IsActive() ?
|
||||
@ -86,7 +90,7 @@ static bool IsValidJSON(FunctionLiteral* lit) {
|
||||
Statement* stmt = lit->body()->at(0);
|
||||
if (stmt->AsExpressionStatement() == NULL)
|
||||
return false;
|
||||
Expression *expr = stmt->AsExpressionStatement()->expression();
|
||||
Expression* expr = stmt->AsExpressionStatement()->expression();
|
||||
return expr->IsValidJSON();
|
||||
}
|
||||
|
||||
@ -98,7 +102,7 @@ static Handle<JSFunction> MakeFunction(bool is_global,
|
||||
Handle<Context> context,
|
||||
v8::Extension* extension,
|
||||
ScriptDataImpl* pre_data) {
|
||||
ZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
CompilationZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
|
||||
// Make sure we have an initial stack limit.
|
||||
StackGuard guard;
|
||||
@ -106,7 +110,22 @@ static Handle<JSFunction> MakeFunction(bool is_global,
|
||||
|
||||
ASSERT(!i::Top::global_context().is_null());
|
||||
script->set_context_data((*i::Top::global_context())->data());
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
if (is_eval || is_json) {
|
||||
script->set_compilation_type(
|
||||
is_json ? Smi::FromInt(Script::COMPILATION_TYPE_JSON) :
|
||||
Smi::FromInt(Script::COMPILATION_TYPE_EVAL));
|
||||
// For eval scripts add information on the function from which eval was
|
||||
// called.
|
||||
if (is_eval) {
|
||||
JavaScriptFrameIterator it;
|
||||
script->set_eval_from_function(it.frame()->function());
|
||||
int offset = it.frame()->pc() - it.frame()->code()->instruction_start();
|
||||
script->set_eval_from_instructions_offset(Smi::FromInt(offset));
|
||||
}
|
||||
}
|
||||
|
||||
// Notify debugger
|
||||
Debugger::OnBeforeCompile(script);
|
||||
#endif
|
||||
@ -156,7 +175,7 @@ static Handle<JSFunction> MakeFunction(bool is_global,
|
||||
#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
|
||||
// Log the code generation for the script. Check explicit whether logging is
|
||||
// to avoid allocating when not required.
|
||||
if (Logger::is_enabled() || OProfileAgent::is_enabled()) {
|
||||
if (Logger::IsEnabled() || OProfileAgent::is_enabled()) {
|
||||
if (script->name()->IsString()) {
|
||||
SmartPointer<char> data =
|
||||
String::cast(script->name())->ToCString(DISALLOW_NULLS);
|
||||
@ -264,7 +283,6 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source,
|
||||
|
||||
Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
|
||||
Handle<Context> context,
|
||||
int line_offset,
|
||||
bool is_global,
|
||||
bool is_json) {
|
||||
int source_length = source->length();
|
||||
@ -284,7 +302,6 @@ Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
|
||||
if (result.is_null()) {
|
||||
// Create a script object describing the script to be compiled.
|
||||
Handle<Script> script = Factory::NewScript(source);
|
||||
script->set_line_offset(Smi::FromInt(line_offset));
|
||||
result = MakeFunction(is_global,
|
||||
true,
|
||||
is_json,
|
||||
@ -303,7 +320,7 @@ Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
|
||||
|
||||
bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
|
||||
int loop_nesting) {
|
||||
ZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
CompilationZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
|
||||
// The VM is in the COMPILER state until exiting this function.
|
||||
VMState state(COMPILER);
|
||||
@ -355,9 +372,9 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
|
||||
// Log the code generation. If source information is available include script
|
||||
// name and line number. Check explicit whether logging is enabled as finding
|
||||
// the line number is not for free.
|
||||
if (Logger::is_enabled() || OProfileAgent::is_enabled()) {
|
||||
Handle<String> func_name(lit->name()->length() > 0 ?
|
||||
*lit->name() : shared->inferred_name());
|
||||
if (Logger::IsEnabled() || OProfileAgent::is_enabled()) {
|
||||
Handle<String> func_name(name->length() > 0 ?
|
||||
*name : shared->inferred_name());
|
||||
if (script->name()->IsString()) {
|
||||
int line_num = GetScriptLineNumber(script, start_position);
|
||||
if (line_num > 0) {
|
||||
|
22
deps/v8/src/compiler.h
vendored
22
deps/v8/src/compiler.h
vendored
@ -28,9 +28,12 @@
|
||||
#ifndef V8_COMPILER_H_
|
||||
#define V8_COMPILER_H_
|
||||
|
||||
#include "frame-element.h"
|
||||
#include "parser.h"
|
||||
#include "zone.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The V8 compiler
|
||||
//
|
||||
@ -59,7 +62,6 @@ class Compiler : public AllStatic {
|
||||
// Compile a String source within a context for Eval.
|
||||
static Handle<JSFunction> CompileEval(Handle<String> source,
|
||||
Handle<Context> context,
|
||||
int line_offset,
|
||||
bool is_global,
|
||||
bool is_json);
|
||||
|
||||
@ -69,6 +71,22 @@ class Compiler : public AllStatic {
|
||||
static bool CompileLazy(Handle<SharedFunctionInfo> shared, int loop_nesting);
|
||||
};
|
||||
|
||||
|
||||
// During compilation we need a global list of handles to constants
|
||||
// for frame elements. When the zone gets deleted, we make sure to
|
||||
// clear this list of handles as well.
|
||||
class CompilationZoneScope : public ZoneScope {
|
||||
public:
|
||||
explicit CompilationZoneScope(ZoneScopeMode mode) : ZoneScope(mode) { }
|
||||
virtual ~CompilationZoneScope() {
|
||||
if (ShouldDeleteOnExit()) {
|
||||
FrameElement::ClearConstantList();
|
||||
Result::ClearConstantList();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_COMPILER_H_
|
||||
|
3
deps/v8/src/contexts.cc
vendored
3
deps/v8/src/contexts.cc
vendored
@ -31,7 +31,8 @@
|
||||
#include "debug.h"
|
||||
#include "scopeinfo.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
JSBuiltinsObject* Context::builtins() {
|
||||
GlobalObject* object = global();
|
||||
|
6
deps/v8/src/contexts.h
vendored
6
deps/v8/src/contexts.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_CONTEXTS_H_
|
||||
#define V8_CONTEXTS_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
enum ContextLookupFlags {
|
||||
@ -90,6 +91,8 @@ enum ContextLookupFlags {
|
||||
V(FUNCTION_CACHE_INDEX, JSObject, function_cache) \
|
||||
V(RUNTIME_CONTEXT_INDEX, Context, runtime_context) \
|
||||
V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \
|
||||
V(CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, JSFunction, \
|
||||
call_as_constructor_delegate) \
|
||||
V(EMPTY_SCRIPT_INDEX, Script, empty_script) \
|
||||
V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
|
||||
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
|
||||
@ -209,6 +212,7 @@ class Context: public FixedArray {
|
||||
FUNCTION_CACHE_INDEX,
|
||||
RUNTIME_CONTEXT_INDEX,
|
||||
CALL_AS_FUNCTION_DELEGATE_INDEX,
|
||||
CALL_AS_CONSTRUCTOR_DELEGATE_INDEX,
|
||||
EMPTY_SCRIPT_INDEX,
|
||||
SCRIPT_FUNCTION_INDEX,
|
||||
CONTEXT_EXTENSION_FUNCTION_INDEX,
|
||||
|
3
deps/v8/src/conversions-inl.h
vendored
3
deps/v8/src/conversions-inl.h
vendored
@ -38,7 +38,8 @@
|
||||
#include "conversions.h"
|
||||
#include "platform.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The fast double-to-int conversion routine does not guarantee
|
||||
// rounding towards zero.
|
||||
|
3
deps/v8/src/conversions.cc
vendored
3
deps/v8/src/conversions.cc
vendored
@ -33,7 +33,8 @@
|
||||
#include "factory.h"
|
||||
#include "scanner.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
int HexValue(uc32 c) {
|
||||
if ('0' <= c && c <= '9')
|
||||
|
3
deps/v8/src/conversions.h
vendored
3
deps/v8/src/conversions.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_CONVERSIONS_H_
|
||||
#define V8_CONVERSIONS_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The fast double-to-int conversion routine does not guarantee
|
||||
// rounding towards zero.
|
||||
|
3
deps/v8/src/counters.cc
vendored
3
deps/v8/src/counters.cc
vendored
@ -30,7 +30,8 @@
|
||||
#include "counters.h"
|
||||
#include "platform.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
CounterLookupCallback StatsTable::lookup_function_ = NULL;
|
||||
CreateHistogramCallback StatsTable::create_histogram_function_ = NULL;
|
||||
|
5
deps/v8/src/counters.h
vendored
5
deps/v8/src/counters.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_COUNTERS_H_
|
||||
#define V8_COUNTERS_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// StatsCounters is an interface for plugging into external
|
||||
// counters for monitoring. Counters can be looked up and
|
||||
@ -74,7 +75,7 @@ class StatsTable : public AllStatic {
|
||||
// function. min and max define the expected minimum and maximum
|
||||
// sample values. buckets is the maximum number of buckets
|
||||
// that the samples will be grouped into.
|
||||
static void *CreateHistogram(const char* name,
|
||||
static void* CreateHistogram(const char* name,
|
||||
int min,
|
||||
int max,
|
||||
size_t buckets) {
|
||||
|
3
deps/v8/src/cpu.h
vendored
3
deps/v8/src/cpu.h
vendored
@ -36,7 +36,8 @@
|
||||
#ifndef V8_CPU_H_
|
||||
#define V8_CPU_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CPU
|
||||
|
5
deps/v8/src/d8-posix.cc
vendored
5
deps/v8/src/d8-posix.cc
vendored
@ -280,7 +280,10 @@ static void ExecSubprocess(int* exec_error_fds,
|
||||
// Only get here if the exec failed. Write errno to the parent to tell
|
||||
// them it went wrong. If it went well the pipe is closed.
|
||||
int err = errno;
|
||||
write(exec_error_fds[kWriteFD], &err, sizeof(err));
|
||||
int bytes_written;
|
||||
do {
|
||||
bytes_written = write(exec_error_fds[kWriteFD], &err, sizeof(err));
|
||||
} while (bytes_written == -1 && errno == EINTR);
|
||||
// Return (and exit child process).
|
||||
}
|
||||
|
||||
|
12
deps/v8/src/d8.cc
vendored
12
deps/v8/src/d8.cc
vendored
@ -451,7 +451,7 @@ void Shell::Initialize() {
|
||||
i::Handle<i::JSFunction> script_fun = Utils::OpenHandle(*script);
|
||||
i::Handle<i::Script> script_object =
|
||||
i::Handle<i::Script>(i::Script::cast(script_fun->shared()->script()));
|
||||
script_object->set_type(i::Smi::FromInt(i::SCRIPT_TYPE_NATIVE));
|
||||
script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
|
||||
|
||||
// Create the evaluation context
|
||||
evaluation_context_ = Context::New(NULL, global_template);
|
||||
@ -487,7 +487,7 @@ void Shell::OnExit() {
|
||||
}
|
||||
|
||||
|
||||
static char* ReadChars(const char *name, int* size_out) {
|
||||
static char* ReadChars(const char* name, int* size_out) {
|
||||
v8::Unlocker unlocker; // Release the V8 lock while reading files.
|
||||
FILE* file = i::OS::FOpen(name, "rb");
|
||||
if (file == NULL) return NULL;
|
||||
@ -659,7 +659,7 @@ int Shell::Main(int argc, char* argv[]) {
|
||||
use_preemption = false;
|
||||
} else if (strcmp(str, "--preemption-interval") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
char *end = NULL;
|
||||
char* end = NULL;
|
||||
preemption_interval = strtol(argv[++i], &end, 10); // NOLINT
|
||||
if (preemption_interval <= 0 || *end != '\0' || errno == ERANGE) {
|
||||
printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
|
||||
@ -687,9 +687,9 @@ int Shell::Main(int argc, char* argv[]) {
|
||||
i++;
|
||||
} else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
|
||||
int size = 0;
|
||||
const char *files = ReadChars(argv[++i], &size);
|
||||
const char* files = ReadChars(argv[++i], &size);
|
||||
if (files == NULL) return 1;
|
||||
ShellThread *thread =
|
||||
ShellThread* thread =
|
||||
new ShellThread(threads.length(),
|
||||
i::Vector<const char>(files, size));
|
||||
thread->Start();
|
||||
@ -736,7 +736,7 @@ int Shell::Main(int argc, char* argv[]) {
|
||||
if (run_shell)
|
||||
RunShell();
|
||||
for (int i = 0; i < threads.length(); i++) {
|
||||
i::Thread *thread = threads[i];
|
||||
i::Thread* thread = threads[i];
|
||||
thread->Join();
|
||||
delete thread;
|
||||
}
|
||||
|
56
deps/v8/src/d8.js
vendored
56
deps/v8/src/d8.js
vendored
@ -93,6 +93,13 @@ Debug.ScriptType = { Native: 0,
|
||||
Normal: 2 };
|
||||
|
||||
|
||||
// The different types of script compilations matching enum
|
||||
// Script::CompilationType in objects.h.
|
||||
Debug.ScriptCompilationType = { Host: 0,
|
||||
Eval: 1,
|
||||
JSON: 2 };
|
||||
|
||||
|
||||
// Current debug state.
|
||||
const kNoFrame = -1;
|
||||
Debug.State = {
|
||||
@ -498,9 +505,26 @@ DebugRequest.prototype.stepCommandToJSONRequest_ = function(args) {
|
||||
DebugRequest.prototype.backtraceCommandToJSONRequest_ = function(args) {
|
||||
// Build a backtrace request from the text command.
|
||||
var request = this.createRequest('backtrace');
|
||||
|
||||
// Default is to show top 10 frames.
|
||||
request.arguments = {};
|
||||
request.arguments.fromFrame = 0;
|
||||
request.arguments.toFrame = 10;
|
||||
|
||||
args = args.split(/\s*[ ]+\s*/g);
|
||||
if (args.length == 2) {
|
||||
request.arguments = {};
|
||||
if (args.length == 1 && args[0].length > 0) {
|
||||
var frameCount = parseInt(args[0]);
|
||||
if (frameCount > 0) {
|
||||
// Show top frames.
|
||||
request.arguments.fromFrame = 0;
|
||||
request.arguments.toFrame = frameCount;
|
||||
} else {
|
||||
// Show bottom frames.
|
||||
request.arguments.fromFrame = 0;
|
||||
request.arguments.toFrame = -frameCount;
|
||||
request.arguments.bottom = true;
|
||||
}
|
||||
} else if (args.length == 2) {
|
||||
var fromFrame = parseInt(args[0]);
|
||||
var toFrame = parseInt(args[1]);
|
||||
if (isNaN(fromFrame) || fromFrame < 0) {
|
||||
@ -513,9 +537,13 @@ DebugRequest.prototype.backtraceCommandToJSONRequest_ = function(args) {
|
||||
throw new Error('Invalid arguments start frame cannot be larger ' +
|
||||
'than end frame.');
|
||||
}
|
||||
// Show frame range.
|
||||
request.arguments.fromFrame = fromFrame;
|
||||
request.arguments.toFrame = toFrame + 1;
|
||||
} else if (args.length > 2) {
|
||||
throw new Error('Invalid backtrace arguments.');
|
||||
}
|
||||
|
||||
return request.toJSONProtocol();
|
||||
};
|
||||
|
||||
@ -755,7 +783,7 @@ DebugRequest.prototype.helpCommand_ = function(args) {
|
||||
print(' break on function: location is #<id>#');
|
||||
print(' break on script position: location is name:line[:column]');
|
||||
print('clear <breakpoint #>');
|
||||
print('backtrace [from frame #] [to frame #]]');
|
||||
print('backtrace [n] | [-n] | [from to]');
|
||||
print('frame <frame #>');
|
||||
print('step [in | next | out| min [step count]]');
|
||||
print('print <expression>');
|
||||
@ -942,7 +970,18 @@ function DebugResponseDetails(response) {
|
||||
if (body[i].name) {
|
||||
result += body[i].name;
|
||||
} else {
|
||||
result += '[unnamed] ';
|
||||
if (body[i].compilationType == Debug.ScriptCompilationType.Eval) {
|
||||
result += 'eval from ';
|
||||
var script_value = response.lookup(body[i].evalFromScript.ref);
|
||||
result += ' ' + script_value.field('name');
|
||||
result += ':' + (body[i].evalFromLocation.line + 1);
|
||||
result += ':' + body[i].evalFromLocation.column;
|
||||
} else if (body[i].compilationType ==
|
||||
Debug.ScriptCompilationType.JSON) {
|
||||
result += 'JSON ';
|
||||
} else { // body[i].compilation == Debug.ScriptCompilationType.Host
|
||||
result += '[unnamed] ';
|
||||
}
|
||||
}
|
||||
result += ' (lines: ';
|
||||
result += body[i].lineCount;
|
||||
@ -1104,6 +1143,15 @@ ProtocolValue.prototype.type = function() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a metadata field from a protocol value.
|
||||
* @return {Object} the metadata field value
|
||||
*/
|
||||
ProtocolValue.prototype.field = function(name) {
|
||||
return this.value_[name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check is the value is a primitive value.
|
||||
* @return {boolean} true if the value is primitive
|
||||
|
3
deps/v8/src/dateparser-inl.h
vendored
3
deps/v8/src/dateparser-inl.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_DATEPARSER_INL_H_
|
||||
#define V8_DATEPARSER_INL_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
template <typename Char>
|
||||
bool DateParser::Parse(Vector<Char> str, FixedArray* out) {
|
||||
|
3
deps/v8/src/dateparser.cc
vendored
3
deps/v8/src/dateparser.cc
vendored
@ -29,7 +29,8 @@
|
||||
|
||||
#include "dateparser.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
bool DateParser::DayComposer::Write(FixedArray* output) {
|
||||
int year = 0; // Default year is 0 (=> 2000) for KJS compatibility.
|
||||
|
3
deps/v8/src/dateparser.h
vendored
3
deps/v8/src/dateparser.h
vendored
@ -30,7 +30,8 @@
|
||||
|
||||
#include "scanner.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class DateParser : public AllStatic {
|
||||
public:
|
||||
|
3
deps/v8/src/debug-agent.cc
vendored
3
deps/v8/src/debug-agent.cc
vendored
@ -30,7 +30,8 @@
|
||||
#include "debug-agent.h"
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Public V8 debugger API message handler function. This function just delegates
|
||||
// to the debugger agent through it's data parameter.
|
||||
|
3
deps/v8/src/debug-agent.h
vendored
3
deps/v8/src/debug-agent.h
vendored
@ -32,7 +32,8 @@
|
||||
#include "../include/v8-debug.h"
|
||||
#include "platform.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Forward decelrations.
|
||||
class DebuggerAgentSession;
|
||||
|
267
deps/v8/src/debug-delay.js
vendored
267
deps/v8/src/debug-delay.js
vendored
@ -43,7 +43,8 @@ Debug.DebugEvent = { Break: 1,
|
||||
Exception: 2,
|
||||
NewFunction: 3,
|
||||
BeforeCompile: 4,
|
||||
AfterCompile: 5 };
|
||||
AfterCompile: 5,
|
||||
ScriptCollected: 6 };
|
||||
|
||||
// Types of exceptions that can be broken upon.
|
||||
Debug.ExceptionBreak = { All : 0,
|
||||
@ -61,6 +62,12 @@ Debug.ScriptType = { Native: 0,
|
||||
Extension: 1,
|
||||
Normal: 2 };
|
||||
|
||||
// The different types of script compilations matching enum
|
||||
// Script::CompilationType in objects.h.
|
||||
Debug.ScriptCompilationType = { Host: 0,
|
||||
Eval: 1,
|
||||
JSON: 2 };
|
||||
|
||||
// The different script break point types.
|
||||
Debug.ScriptBreakPointType = { ScriptId: 0,
|
||||
ScriptName: 1 };
|
||||
@ -833,7 +840,7 @@ BreakEvent.prototype.toJSONProtocol = function() {
|
||||
event: "break",
|
||||
body: { invocationText: this.exec_state_.frame(0).invocationText(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Add script related information to the event if available.
|
||||
var script = this.func().script();
|
||||
@ -861,8 +868,7 @@ BreakEvent.prototype.toJSONProtocol = function() {
|
||||
o.body.breakpoints.push(number);
|
||||
}
|
||||
}
|
||||
|
||||
return SimpleObjectToJSON_(o);
|
||||
return JSON.stringify(ObjectToProtocolObject_(o));
|
||||
};
|
||||
|
||||
|
||||
@ -923,7 +929,7 @@ ExceptionEvent.prototype.toJSONProtocol = function() {
|
||||
o.event = "exception";
|
||||
o.body = { uncaught: this.uncaught_,
|
||||
exception: MakeMirror(this.exception_)
|
||||
}
|
||||
};
|
||||
|
||||
// Exceptions might happen whithout any JavaScript frames.
|
||||
if (this.exec_state_.frameCount() > 0) {
|
||||
@ -984,7 +990,8 @@ CompileEvent.prototype.toJSONProtocol = function() {
|
||||
o.event = "afterCompile";
|
||||
}
|
||||
o.body = {};
|
||||
o.body.script = MakeScriptObject_(this.script_, true);
|
||||
o.body.script = this.script_;
|
||||
o.setOption('includeSource', true);
|
||||
|
||||
return o.toJSONProtocol();
|
||||
}
|
||||
@ -1015,6 +1022,37 @@ NewFunctionEvent.prototype.setBreakPoint = function(p) {
|
||||
};
|
||||
|
||||
|
||||
function MakeScriptCollectedEvent(exec_state, id) {
|
||||
return new ScriptCollectedEvent(exec_state, id);
|
||||
}
|
||||
|
||||
|
||||
function ScriptCollectedEvent(exec_state, id) {
|
||||
this.exec_state_ = exec_state;
|
||||
this.id_ = id;
|
||||
}
|
||||
|
||||
|
||||
ScriptCollectedEvent.prototype.id = function() {
|
||||
return this.id_;
|
||||
};
|
||||
|
||||
|
||||
ScriptCollectedEvent.prototype.executionState = function() {
|
||||
return this.exec_state_;
|
||||
};
|
||||
|
||||
|
||||
ScriptCollectedEvent.prototype.toJSONProtocol = function() {
|
||||
var o = new ProtocolMessage();
|
||||
o.running = true;
|
||||
o.event = "scriptCollected";
|
||||
o.body = {};
|
||||
o.body.script = { id: this.id() };
|
||||
return o.toJSONProtocol();
|
||||
}
|
||||
|
||||
|
||||
function MakeScriptObject_(script, include_source) {
|
||||
var o = { id: script.id(),
|
||||
name: script.name(),
|
||||
@ -1078,56 +1116,53 @@ ProtocolMessage.prototype.failed = function(message) {
|
||||
|
||||
ProtocolMessage.prototype.toJSONProtocol = function() {
|
||||
// Encode the protocol header.
|
||||
var json = '{';
|
||||
json += '"seq":' + this.seq;
|
||||
var json = {};
|
||||
json.seq= this.seq;
|
||||
if (this.request_seq) {
|
||||
json += ',"request_seq":' + this.request_seq;
|
||||
json.request_seq = this.request_seq;
|
||||
}
|
||||
json += ',"type":"' + this.type + '"';
|
||||
json.type = this.type;
|
||||
if (this.event) {
|
||||
json += ',"event":' + StringToJSON_(this.event);
|
||||
json.event = this.event;
|
||||
}
|
||||
if (this.command) {
|
||||
json += ',"command":' + StringToJSON_(this.command);
|
||||
json.command = this.command;
|
||||
}
|
||||
if (this.success) {
|
||||
json += ',"success":' + this.success;
|
||||
json.success = this.success;
|
||||
} else {
|
||||
json += ',"success":false';
|
||||
json.success = false;
|
||||
}
|
||||
if (this.body) {
|
||||
json += ',"body":';
|
||||
// Encode the body part.
|
||||
var bodyJson;
|
||||
var serializer = MakeMirrorSerializer(true, this.options_);
|
||||
if (this.body instanceof Mirror) {
|
||||
json += serializer.serializeValue(this.body);
|
||||
bodyJson = serializer.serializeValue(this.body);
|
||||
} else if (this.body instanceof Array) {
|
||||
json += '[';
|
||||
bodyJson = [];
|
||||
for (var i = 0; i < this.body.length; i++) {
|
||||
if (i != 0) json += ',';
|
||||
if (this.body[i] instanceof Mirror) {
|
||||
json += serializer.serializeValue(this.body[i]);
|
||||
bodyJson.push(serializer.serializeValue(this.body[i]));
|
||||
} else {
|
||||
json += SimpleObjectToJSON_(this.body[i], serializer);
|
||||
bodyJson.push(ObjectToProtocolObject_(this.body[i], serializer));
|
||||
}
|
||||
}
|
||||
json += ']';
|
||||
} else {
|
||||
json += SimpleObjectToJSON_(this.body, serializer);
|
||||
bodyJson = ObjectToProtocolObject_(this.body, serializer);
|
||||
}
|
||||
json += ',"refs":';
|
||||
json += serializer.serializeReferencedObjects();
|
||||
json.body = bodyJson;
|
||||
json.refs = serializer.serializeReferencedObjects();
|
||||
}
|
||||
if (this.message) {
|
||||
json += ',"message":' + StringToJSON_(this.message) ;
|
||||
json.message = this.message;
|
||||
}
|
||||
if (this.running) {
|
||||
json += ',"running":true';
|
||||
json.running = true;
|
||||
} else {
|
||||
json += ',"running":false';
|
||||
json.running = false;
|
||||
}
|
||||
json += '}';
|
||||
return json;
|
||||
return JSON.stringify(json);
|
||||
}
|
||||
|
||||
|
||||
@ -1142,7 +1177,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
|
||||
try {
|
||||
try {
|
||||
// Convert the JSON string to an object.
|
||||
request = %CompileString('(' + json_request + ')', 0, false)();
|
||||
request = %CompileString('(' + json_request + ')', false)();
|
||||
|
||||
// Create an initial response.
|
||||
response = this.createResponse(request);
|
||||
@ -1451,13 +1486,22 @@ DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response)
|
||||
|
||||
// Get the range from the arguments.
|
||||
if (request.arguments) {
|
||||
from_index = request.arguments.fromFrame;
|
||||
if (from_index < 0) {
|
||||
if (request.arguments.fromFrame) {
|
||||
from_index = request.arguments.fromFrame;
|
||||
}
|
||||
if (request.arguments.toFrame) {
|
||||
to_index = request.arguments.toFrame;
|
||||
}
|
||||
if (request.arguments.bottom) {
|
||||
var tmp_index = total_frames - from_index;
|
||||
from_index = total_frames - to_index
|
||||
to_index = tmp_index;
|
||||
}
|
||||
if (from_index < 0 || to_index < 0) {
|
||||
return response.failed('Invalid frame number');
|
||||
}
|
||||
to_index = request.arguments.toFrame;
|
||||
if (to_index < 0) {
|
||||
return response.failed('Invalid frame number');
|
||||
if (request.arguments.compactFormat) {
|
||||
response.setOption('compactFormat', true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1581,6 +1625,16 @@ DebugCommandProcessor.prototype.lookupRequest_ = function(request, response) {
|
||||
return response.failed('Argument "handles" missing');
|
||||
}
|
||||
|
||||
// Set 'includeSource' option for script lookup.
|
||||
if (!IS_UNDEFINED(request.arguments.includeSource)) {
|
||||
includeSource = %ToBoolean(request.arguments.includeSource);
|
||||
response.setOption('includeSource', includeSource);
|
||||
}
|
||||
|
||||
if (request.arguments.compactFormat) {
|
||||
response.setOption('compactFormat', true);
|
||||
}
|
||||
|
||||
// Lookup handles.
|
||||
var mirrors = {};
|
||||
for (var i = 0; i < handles.length; i++) {
|
||||
@ -1677,6 +1731,7 @@ DebugCommandProcessor.prototype.sourceRequest_ = function(request, response) {
|
||||
DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
|
||||
var types = ScriptTypeFlag(Debug.ScriptType.Normal);
|
||||
var includeSource = false;
|
||||
var idsToInclude = null;
|
||||
if (request.arguments) {
|
||||
// Pull out arguments.
|
||||
if (!IS_UNDEFINED(request.arguments.types)) {
|
||||
@ -1690,6 +1745,14 @@ DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
|
||||
includeSource = %ToBoolean(request.arguments.includeSource);
|
||||
response.setOption('includeSource', includeSource);
|
||||
}
|
||||
|
||||
if (IS_ARRAY(request.arguments.ids)) {
|
||||
idsToInclude = {};
|
||||
var ids = request.arguments.ids;
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
idsToInclude[ids[i]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all scripts in the heap.
|
||||
@ -1698,6 +1761,9 @@ DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
|
||||
response.body = [];
|
||||
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
if (idsToInclude && !idsToInclude[scripts[i].id]) {
|
||||
continue;
|
||||
}
|
||||
if (types & ScriptTypeFlag(scripts[i].type)) {
|
||||
response.body.push(MakeMirror(scripts[i]));
|
||||
}
|
||||
@ -1774,97 +1840,82 @@ DebugCommandProcessor.prototype.formatCFrame = function(cframe_value) {
|
||||
|
||||
|
||||
/**
|
||||
* Convert an Object to its JSON representation (see http://www.json.org/).
|
||||
* This implementation simply runs through all string property names and adds
|
||||
* each property to the JSON representation for some predefined types. For type
|
||||
* "object" the function calls itself recursively unless the object has the
|
||||
* function property "toJSONProtocol" in which case that is used. This is not
|
||||
* a general implementation but sufficient for the debugger. Note that circular
|
||||
* structures will cause infinite recursion.
|
||||
* @param {Object} object The object to format as JSON
|
||||
* Convert an Object to its debugger protocol representation. The representation
|
||||
* may be serilized to a JSON object using JSON.stringify().
|
||||
* This implementation simply runs through all string property names, converts
|
||||
* each property value to a protocol value and adds the property to the result
|
||||
* object. For type "object" the function will be called recursively. Note that
|
||||
* circular structures will cause infinite recursion.
|
||||
* @param {Object} object The object to format as protocol object.
|
||||
* @param {MirrorSerializer} mirror_serializer The serializer to use if any
|
||||
* mirror objects are encountered.
|
||||
* @return {string} JSON formatted object value
|
||||
* @return {Object} Protocol object value.
|
||||
*/
|
||||
function SimpleObjectToJSON_(object, mirror_serializer) {
|
||||
var content = [];
|
||||
function ObjectToProtocolObject_(object, mirror_serializer) {
|
||||
var content = {};
|
||||
for (var key in object) {
|
||||
// Only consider string keys.
|
||||
if (typeof key == 'string') {
|
||||
var property_value = object[key];
|
||||
|
||||
// Format the value based on its type.
|
||||
var property_value_json;
|
||||
switch (typeof property_value) {
|
||||
case 'object':
|
||||
if (property_value instanceof Mirror) {
|
||||
property_value_json = mirror_serializer.serializeValue(property_value);
|
||||
} else if (typeof property_value.toJSONProtocol == 'function') {
|
||||
property_value_json = property_value.toJSONProtocol(true)
|
||||
} else if (IS_ARRAY(property_value)){
|
||||
property_value_json = SimpleArrayToJSON_(property_value, mirror_serializer);
|
||||
} else {
|
||||
property_value_json = SimpleObjectToJSON_(property_value, mirror_serializer);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
property_value_json = BooleanToJSON_(property_value);
|
||||
break;
|
||||
|
||||
case 'number':
|
||||
property_value_json = NumberToJSON_(property_value);
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
property_value_json = StringToJSON_(property_value);
|
||||
break;
|
||||
|
||||
default:
|
||||
property_value_json = null;
|
||||
}
|
||||
|
||||
var property_value_json = ValueToProtocolValue_(object[key],
|
||||
mirror_serializer);
|
||||
// Add the property if relevant.
|
||||
if (property_value_json) {
|
||||
content.push(StringToJSON_(key) + ':' + property_value_json);
|
||||
if (!IS_UNDEFINED(property_value_json)) {
|
||||
content[key] = property_value_json;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make JSON object representation.
|
||||
return '{' + content.join(',') + '}';
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert an array to its JSON representation. This is a VERY simple
|
||||
* implementation just to support what is needed for the debugger.
|
||||
* @param {Array} array The array to format as JSON
|
||||
* Convert an array to its debugger protocol representation. It will convert
|
||||
* each array element to a protocol value.
|
||||
* @param {Array} array The array to format as protocol array.
|
||||
* @param {MirrorSerializer} mirror_serializer The serializer to use if any
|
||||
* mirror objects are encountered.
|
||||
* @return {string} JSON formatted array value
|
||||
* @return {Array} Protocol array value.
|
||||
*/
|
||||
function SimpleArrayToJSON_(array, mirror_serializer) {
|
||||
// Make JSON array representation.
|
||||
var json = '[';
|
||||
function ArrayToProtocolArray_(array, mirror_serializer) {
|
||||
var json = [];
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (i != 0) {
|
||||
json += ',';
|
||||
}
|
||||
var elem = array[i];
|
||||
if (elem instanceof Mirror) {
|
||||
json += mirror_serializer.serializeValue(elem);
|
||||
} else if (IS_OBJECT(elem)) {
|
||||
json += SimpleObjectToJSON_(elem);
|
||||
} else if (IS_BOOLEAN(elem)) {
|
||||
json += BooleanToJSON_(elem);
|
||||
} else if (IS_NUMBER(elem)) {
|
||||
json += NumberToJSON_(elem);
|
||||
} else if (IS_STRING(elem)) {
|
||||
json += StringToJSON_(elem);
|
||||
} else {
|
||||
json += elem;
|
||||
}
|
||||
json.push(ValueToProtocolValue_(array[i], mirror_serializer));
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a value to its debugger protocol representation.
|
||||
* @param {*} value The value to format as protocol value.
|
||||
* @param {MirrorSerializer} mirror_serializer The serializer to use if any
|
||||
* mirror objects are encountered.
|
||||
* @return {*} Protocol value.
|
||||
*/
|
||||
function ValueToProtocolValue_(value, mirror_serializer) {
|
||||
// Format the value based on its type.
|
||||
var json;
|
||||
switch (typeof value) {
|
||||
case 'object':
|
||||
if (value instanceof Mirror) {
|
||||
json = mirror_serializer.serializeValue(value);
|
||||
} else if (IS_ARRAY(value)){
|
||||
json = ArrayToProtocolArray_(value, mirror_serializer);
|
||||
} else {
|
||||
json = ObjectToProtocolObject_(value, mirror_serializer);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
case 'string':
|
||||
case 'number':
|
||||
json = value;
|
||||
break
|
||||
|
||||
default:
|
||||
json = null;
|
||||
}
|
||||
json += ']';
|
||||
return json;
|
||||
}
|
||||
|
319
deps/v8/src/debug.cc
vendored
319
deps/v8/src/debug.cc
vendored
@ -31,6 +31,7 @@
|
||||
#include "arguments.h"
|
||||
#include "bootstrapper.h"
|
||||
#include "code-stubs.h"
|
||||
#include "compilation-cache.h"
|
||||
#include "compiler.h"
|
||||
#include "debug.h"
|
||||
#include "execution.h"
|
||||
@ -43,7 +44,8 @@
|
||||
|
||||
#include "../include/v8-debug.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
static void PrintLn(v8::Local<v8::Value> value) {
|
||||
@ -425,6 +427,7 @@ void BreakLocationIterator::RinfoNext() {
|
||||
|
||||
|
||||
bool Debug::has_break_points_ = false;
|
||||
ScriptCache* Debug::script_cache_ = NULL;
|
||||
DebugInfoListNode* Debug::debug_info_list_ = NULL;
|
||||
|
||||
|
||||
@ -440,7 +443,7 @@ void Debug::ThreadInit() {
|
||||
thread_local_.step_into_fp_ = 0;
|
||||
thread_local_.after_break_target_ = 0;
|
||||
thread_local_.debugger_entry_ = NULL;
|
||||
thread_local_.preemption_pending_ = false;
|
||||
thread_local_.pending_interrupts_ = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -486,6 +489,96 @@ Code* Debug::debug_break_return_entry_ = NULL;
|
||||
Code* Debug::debug_break_return_ = NULL;
|
||||
|
||||
|
||||
void ScriptCache::Add(Handle<Script> script) {
|
||||
// Create an entry in the hash map for the script.
|
||||
int id = Smi::cast(script->id())->value();
|
||||
HashMap::Entry* entry =
|
||||
HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
|
||||
if (entry->value != NULL) {
|
||||
ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
|
||||
return;
|
||||
}
|
||||
|
||||
// Globalize the script object, make it weak and use the location of the
|
||||
// global handle as the value in the hash map.
|
||||
Handle<Script> script_ =
|
||||
Handle<Script>::cast((GlobalHandles::Create(*script)));
|
||||
GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
|
||||
this, ScriptCache::HandleWeakScript);
|
||||
entry->value = script_.location();
|
||||
}
|
||||
|
||||
|
||||
Handle<FixedArray> ScriptCache::GetScripts() {
|
||||
Handle<FixedArray> instances = Factory::NewFixedArray(occupancy());
|
||||
int count = 0;
|
||||
for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
|
||||
ASSERT(entry->value != NULL);
|
||||
if (entry->value != NULL) {
|
||||
instances->set(count, *reinterpret_cast<Script**>(entry->value));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return instances;
|
||||
}
|
||||
|
||||
|
||||
void ScriptCache::ProcessCollectedScripts() {
|
||||
for (int i = 0; i < collected_scripts_.length(); i++) {
|
||||
Debugger::OnScriptCollected(collected_scripts_[i]);
|
||||
}
|
||||
collected_scripts_.Clear();
|
||||
}
|
||||
|
||||
|
||||
void ScriptCache::Clear() {
|
||||
// Iterate the script cache to get rid of all the weak handles.
|
||||
for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
|
||||
ASSERT(entry != NULL);
|
||||
Object** location = reinterpret_cast<Object**>(entry->value);
|
||||
ASSERT((*location)->IsScript());
|
||||
GlobalHandles::ClearWeakness(location);
|
||||
GlobalHandles::Destroy(location);
|
||||
}
|
||||
// Clear the content of the hash map.
|
||||
HashMap::Clear();
|
||||
}
|
||||
|
||||
|
||||
void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
|
||||
ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
|
||||
// Find the location of the global handle.
|
||||
Script** location =
|
||||
reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
|
||||
ASSERT((*location)->IsScript());
|
||||
|
||||
// Remove the entry from the cache.
|
||||
int id = Smi::cast((*location)->id())->value();
|
||||
script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
|
||||
script_cache->collected_scripts_.Add(id);
|
||||
|
||||
// Clear the weak handle.
|
||||
obj.Dispose();
|
||||
obj.Clear();
|
||||
}
|
||||
|
||||
|
||||
void Debug::Setup(bool create_heap_objects) {
|
||||
ThreadInit();
|
||||
if (create_heap_objects) {
|
||||
// Get code to handle entry to debug break on return.
|
||||
debug_break_return_entry_ =
|
||||
Builtins::builtin(Builtins::Return_DebugBreakEntry);
|
||||
ASSERT(debug_break_return_entry_->IsCode());
|
||||
|
||||
// Get code to handle debug break on return.
|
||||
debug_break_return_ =
|
||||
Builtins::builtin(Builtins::Return_DebugBreak);
|
||||
ASSERT(debug_break_return_->IsCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
|
||||
DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
|
||||
RemoveDebugInfo(node->debug_info());
|
||||
@ -512,22 +605,6 @@ DebugInfoListNode::~DebugInfoListNode() {
|
||||
}
|
||||
|
||||
|
||||
void Debug::Setup(bool create_heap_objects) {
|
||||
ThreadInit();
|
||||
if (create_heap_objects) {
|
||||
// Get code to handle entry to debug break on return.
|
||||
debug_break_return_entry_ =
|
||||
Builtins::builtin(Builtins::Return_DebugBreakEntry);
|
||||
ASSERT(debug_break_return_entry_->IsCode());
|
||||
|
||||
// Get code to handle debug break on return.
|
||||
debug_break_return_ =
|
||||
Builtins::builtin(Builtins::Return_DebugBreak);
|
||||
ASSERT(debug_break_return_->IsCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Debug::CompileDebuggerScript(int index) {
|
||||
HandleScope scope;
|
||||
|
||||
@ -575,7 +652,7 @@ bool Debug::CompileDebuggerScript(int index) {
|
||||
|
||||
// Mark this script as native and return successfully.
|
||||
Handle<Script> script(Script::cast(function->shared()->script()));
|
||||
script->set_type(Smi::FromInt(SCRIPT_TYPE_NATIVE));
|
||||
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -627,6 +704,7 @@ bool Debug::Load() {
|
||||
|
||||
// Debugger loaded.
|
||||
debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -637,6 +715,9 @@ void Debug::Unload() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the script cache.
|
||||
DestroyScriptCache();
|
||||
|
||||
// Clear debugger context global handle.
|
||||
GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
|
||||
debug_context_ = Handle<Context>();
|
||||
@ -646,7 +727,7 @@ void Debug::Unload() {
|
||||
// Set the flag indicating that preemption happened during debugging.
|
||||
void Debug::PreemptionWhileInDebugger() {
|
||||
ASSERT(InDebugger());
|
||||
Debug::set_preemption_pending(true);
|
||||
Debug::set_interrupts_pending(PREEMPT);
|
||||
}
|
||||
|
||||
|
||||
@ -1414,6 +1495,94 @@ void Debug::ClearMirrorCache() {
|
||||
}
|
||||
|
||||
|
||||
// If an object given is an external string, check that the underlying
|
||||
// resource is accessible. For other kinds of objects, always return true.
|
||||
static bool IsExternalStringValid(Object* str) {
|
||||
if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
|
||||
return true;
|
||||
}
|
||||
if (String::cast(str)->IsAsciiRepresentation()) {
|
||||
return ExternalAsciiString::cast(str)->resource() != NULL;
|
||||
} else if (String::cast(str)->IsTwoByteRepresentation()) {
|
||||
return ExternalTwoByteString::cast(str)->resource() != NULL;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debug::CreateScriptCache() {
|
||||
HandleScope scope;
|
||||
|
||||
// Perform two GCs to get rid of all unreferenced scripts. The first GC gets
|
||||
// rid of all the cached script wrappers and the second gets rid of the
|
||||
// scripts which is no longer referenced.
|
||||
Heap::CollectAllGarbage();
|
||||
Heap::CollectAllGarbage();
|
||||
|
||||
ASSERT(script_cache_ == NULL);
|
||||
script_cache_ = new ScriptCache();
|
||||
|
||||
// Scan heap for Script objects.
|
||||
int count = 0;
|
||||
HeapIterator iterator;
|
||||
while (iterator.has_next()) {
|
||||
HeapObject* obj = iterator.next();
|
||||
ASSERT(obj != NULL);
|
||||
if (obj->IsScript() && IsExternalStringValid(Script::cast(obj)->source())) {
|
||||
script_cache_->Add(Handle<Script>(Script::cast(obj)));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debug::DestroyScriptCache() {
|
||||
// Get rid of the script cache if it was created.
|
||||
if (script_cache_ != NULL) {
|
||||
delete script_cache_;
|
||||
script_cache_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debug::AddScriptToScriptCache(Handle<Script> script) {
|
||||
if (script_cache_ != NULL) {
|
||||
script_cache_->Add(script);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Handle<FixedArray> Debug::GetLoadedScripts() {
|
||||
// Create and fill the script cache when the loaded scripts is requested for
|
||||
// the first time.
|
||||
if (script_cache_ == NULL) {
|
||||
CreateScriptCache();
|
||||
}
|
||||
|
||||
// If the script cache is not active just return an empty array.
|
||||
ASSERT(script_cache_ != NULL);
|
||||
if (script_cache_ == NULL) {
|
||||
Factory::NewFixedArray(0);
|
||||
}
|
||||
|
||||
// Perform GC to get unreferenced scripts evicted from the cache before
|
||||
// returning the content.
|
||||
Heap::CollectAllGarbage();
|
||||
|
||||
// Get the scripts from the cache.
|
||||
return script_cache_->GetScripts();
|
||||
}
|
||||
|
||||
|
||||
void Debug::AfterGarbageCollection() {
|
||||
// Generate events for collected scripts.
|
||||
if (script_cache_ != NULL) {
|
||||
script_cache_->ProcessCollectedScripts();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Mutex* Debugger::debugger_access_ = OS::CreateMutex();
|
||||
Handle<Object> Debugger::event_listener_ = Handle<Object>();
|
||||
Handle<Object> Debugger::event_listener_data_ = Handle<Object>();
|
||||
@ -1421,7 +1590,7 @@ bool Debugger::compiling_natives_ = false;
|
||||
bool Debugger::is_loading_debugger_ = false;
|
||||
bool Debugger::never_unload_debugger_ = false;
|
||||
v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL;
|
||||
bool Debugger::message_handler_cleared_ = false;
|
||||
bool Debugger::debugger_unload_pending_ = false;
|
||||
v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
|
||||
int Debugger::host_dispatch_micros_ = 100 * 1000;
|
||||
DebuggerAgent* Debugger::agent_ = NULL;
|
||||
@ -1518,6 +1687,21 @@ Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
|
||||
bool* caught_exception) {
|
||||
// Create the script collected event object.
|
||||
Handle<Object> exec_state = MakeExecutionState(caught_exception);
|
||||
Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
|
||||
const int argc = 2;
|
||||
Object** argv[argc] = { exec_state.location(), id_object.location() };
|
||||
|
||||
return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
|
||||
argc,
|
||||
argv,
|
||||
caught_exception);
|
||||
}
|
||||
|
||||
|
||||
void Debugger::OnException(Handle<Object> exception, bool uncaught) {
|
||||
HandleScope scope;
|
||||
|
||||
@ -1624,12 +1808,15 @@ void Debugger::OnBeforeCompile(Handle<Script> script) {
|
||||
void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) {
|
||||
HandleScope scope;
|
||||
|
||||
// No compile events while compiling natives.
|
||||
if (compiling_natives()) return;
|
||||
// Add the newly compiled script to the script cache.
|
||||
Debug::AddScriptToScriptCache(script);
|
||||
|
||||
// No more to do if not debugging.
|
||||
if (!IsDebuggerActive()) return;
|
||||
|
||||
// No compile events while compiling natives.
|
||||
if (compiling_natives()) return;
|
||||
|
||||
// Store whether in debugger before entering debugger.
|
||||
bool in_debugger = Debug::InDebugger();
|
||||
|
||||
@ -1708,11 +1895,43 @@ void Debugger::OnNewFunction(Handle<JSFunction> function) {
|
||||
}
|
||||
|
||||
|
||||
void Debugger::OnScriptCollected(int id) {
|
||||
HandleScope scope;
|
||||
|
||||
// No more to do if not debugging.
|
||||
if (!IsDebuggerActive()) return;
|
||||
if (!Debugger::EventActive(v8::ScriptCollected)) return;
|
||||
|
||||
// Enter the debugger.
|
||||
EnterDebugger debugger;
|
||||
if (debugger.FailedToEnter()) return;
|
||||
|
||||
// Create the script collected state object.
|
||||
bool caught_exception = false;
|
||||
Handle<Object> event_data = MakeScriptCollectedEvent(id,
|
||||
&caught_exception);
|
||||
// Bail out and don't call debugger if exception.
|
||||
if (caught_exception) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process debug event.
|
||||
ProcessDebugEvent(v8::ScriptCollected,
|
||||
Handle<JSObject>::cast(event_data),
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
void Debugger::ProcessDebugEvent(v8::DebugEvent event,
|
||||
Handle<JSObject> event_data,
|
||||
bool auto_continue) {
|
||||
HandleScope scope;
|
||||
|
||||
// Clear any pending debug break if this is a real break.
|
||||
if (!auto_continue) {
|
||||
Debug::clear_interrupt_pending(DEBUGBREAK);
|
||||
}
|
||||
|
||||
// Create the execution state.
|
||||
bool caught_exception = false;
|
||||
Handle<Object> exec_state = MakeExecutionState(&caught_exception);
|
||||
@ -1756,9 +1975,6 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the mirror cache.
|
||||
Debug::ClearMirrorCache();
|
||||
}
|
||||
|
||||
|
||||
@ -1771,8 +1987,8 @@ void Debugger::UnloadDebugger() {
|
||||
Debug::Unload();
|
||||
}
|
||||
|
||||
// Clear the flag indicating that the message handler was recently cleared.
|
||||
message_handler_cleared_ = false;
|
||||
// Clear the flag indicating that the debugger should be unloaded.
|
||||
debugger_unload_pending_ = false;
|
||||
}
|
||||
|
||||
|
||||
@ -1798,6 +2014,9 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
|
||||
case v8::AfterCompile:
|
||||
sendEventMessage = true;
|
||||
break;
|
||||
case v8::ScriptCollected:
|
||||
sendEventMessage = true;
|
||||
break;
|
||||
case v8::NewFunction:
|
||||
break;
|
||||
default:
|
||||
@ -1820,7 +2039,12 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
|
||||
Handle<JSObject>::cast(event_data));
|
||||
InvokeMessageHandler(message);
|
||||
}
|
||||
if (auto_continue && !HasCommands()) {
|
||||
|
||||
// If auto continue don't make the event cause a break, but process messages
|
||||
// in the queue if any. For script collected events don't even process
|
||||
// messages in the queue as the execution state might not be what is expected
|
||||
// by the client.
|
||||
if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1956,10 +2180,7 @@ void Debugger::SetEventListener(Handle<Object> callback,
|
||||
event_listener_data_ = Handle<Object>::cast(GlobalHandles::Create(*data));
|
||||
}
|
||||
|
||||
// Unload the debugger if event listener cleared.
|
||||
if (callback->IsUndefined()) {
|
||||
UnloadDebugger();
|
||||
}
|
||||
ListenersChanged();
|
||||
}
|
||||
|
||||
|
||||
@ -1967,10 +2188,8 @@ void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
|
||||
ScopedLock with(debugger_access_);
|
||||
|
||||
message_handler_ = handler;
|
||||
ListenersChanged();
|
||||
if (handler == NULL) {
|
||||
// Indicate that the message handler was recently cleared.
|
||||
message_handler_cleared_ = true;
|
||||
|
||||
// Send an empty command to the debugger if in a break to make JavaScript
|
||||
// run again if the debugger is closed.
|
||||
if (Debug::InDebugger()) {
|
||||
@ -1980,6 +2199,25 @@ void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
|
||||
}
|
||||
|
||||
|
||||
void Debugger::ListenersChanged() {
|
||||
if (IsDebuggerActive()) {
|
||||
// Disable the compilation cache when the debugger is active.
|
||||
CompilationCache::Disable();
|
||||
} else {
|
||||
CompilationCache::Enable();
|
||||
|
||||
// Unload the debugger if event listener and message handler cleared.
|
||||
if (Debug::InDebugger()) {
|
||||
// If we are in debugger set the flag to unload the debugger when last
|
||||
// EnterDebugger on the current stack is destroyed.
|
||||
debugger_unload_pending_ = true;
|
||||
} else {
|
||||
UnloadDebugger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
|
||||
int period) {
|
||||
host_dispatch_handler_ = handler;
|
||||
@ -2172,7 +2410,14 @@ v8::Handle<v8::String> MessageImpl::GetJSON() const {
|
||||
|
||||
|
||||
v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
|
||||
return v8::Utils::ToLocal(Debug::debugger_entry()->GetContext());
|
||||
Handle<Context> context = Debug::debugger_entry()->GetContext();
|
||||
// Top::context() may have been NULL when "script collected" event occured.
|
||||
if (*context == NULL) {
|
||||
ASSERT(event_ == v8::ScriptCollected);
|
||||
return v8::Local<v8::Context>();
|
||||
}
|
||||
Handle<Context> global_context(context->global_context());
|
||||
return v8::Utils::ToLocal(global_context);
|
||||
}
|
||||
|
||||
|
||||
|
138
deps/v8/src/debug.h
vendored
138
deps/v8/src/debug.h
vendored
@ -33,6 +33,7 @@
|
||||
#include "debug-agent.h"
|
||||
#include "execution.h"
|
||||
#include "factory.h"
|
||||
#include "hashmap.h"
|
||||
#include "platform.h"
|
||||
#include "string-stream.h"
|
||||
#include "v8threads.h"
|
||||
@ -40,7 +41,8 @@
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
#include "../include/v8-debug.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// Forward declarations.
|
||||
@ -144,6 +146,42 @@ class BreakLocationIterator {
|
||||
};
|
||||
|
||||
|
||||
// Cache of all script objects in the heap. When a script is added a weak handle
|
||||
// to it is created and that weak handle is stored in the cache. The weak handle
|
||||
// callback takes care of removing the script from the cache. The key used in
|
||||
// the cache is the script id.
|
||||
class ScriptCache : private HashMap {
|
||||
public:
|
||||
ScriptCache() : HashMap(ScriptMatch), collected_scripts_(10) {}
|
||||
virtual ~ScriptCache() { Clear(); }
|
||||
|
||||
// Add script to the cache.
|
||||
void Add(Handle<Script> script);
|
||||
|
||||
// Return the scripts in the cache.
|
||||
Handle<FixedArray> GetScripts();
|
||||
|
||||
// Generate debugger events for collected scripts.
|
||||
void ProcessCollectedScripts();
|
||||
|
||||
private:
|
||||
// Calculate the hash value from the key (script id).
|
||||
static uint32_t Hash(int key) { return ComputeIntegerHash(key); }
|
||||
|
||||
// Scripts match if their keys (script id) match.
|
||||
static bool ScriptMatch(void* key1, void* key2) { return key1 == key2; }
|
||||
|
||||
// Clear the cache releasing all the weak handles.
|
||||
void Clear();
|
||||
|
||||
// Weak handle callback for scripts in the cache.
|
||||
static void HandleWeakScript(v8::Persistent<v8::Value> obj, void* data);
|
||||
|
||||
// List used during GC to temporarily store id's of collected scripts.
|
||||
List<int> collected_scripts_;
|
||||
};
|
||||
|
||||
|
||||
// Linked list holding debug info objects. The debug info objects are kept as
|
||||
// weak handles to avoid a debug info object to keep a function alive.
|
||||
class DebugInfoListNode {
|
||||
@ -230,9 +268,6 @@ class Debug {
|
||||
}
|
||||
static int break_id() { return thread_local_.break_id_; }
|
||||
|
||||
|
||||
|
||||
|
||||
static bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
|
||||
static void HandleStepIn(Handle<JSFunction> function,
|
||||
Address fp,
|
||||
@ -247,11 +282,19 @@ class Debug {
|
||||
thread_local_.debugger_entry_ = entry;
|
||||
}
|
||||
|
||||
static bool preemption_pending() {
|
||||
return thread_local_.preemption_pending_;
|
||||
// Check whether any of the specified interrupts are pending.
|
||||
static bool is_interrupt_pending(InterruptFlag what) {
|
||||
return (thread_local_.pending_interrupts_ & what) != 0;
|
||||
}
|
||||
static void set_preemption_pending(bool preemption_pending) {
|
||||
thread_local_.preemption_pending_ = preemption_pending;
|
||||
|
||||
// Set specified interrupts as pending.
|
||||
static void set_interrupts_pending(InterruptFlag what) {
|
||||
thread_local_.pending_interrupts_ |= what;
|
||||
}
|
||||
|
||||
// Clear specified interrupts from pending.
|
||||
static void clear_interrupt_pending(InterruptFlag what) {
|
||||
thread_local_.pending_interrupts_ &= ~static_cast<int>(what);
|
||||
}
|
||||
|
||||
// Getter and setter for the disable break state.
|
||||
@ -307,6 +350,15 @@ class Debug {
|
||||
// Mirror cache handling.
|
||||
static void ClearMirrorCache();
|
||||
|
||||
// Script cache handling.
|
||||
static void CreateScriptCache();
|
||||
static void DestroyScriptCache();
|
||||
static void AddScriptToScriptCache(Handle<Script> script);
|
||||
static Handle<FixedArray> GetLoadedScripts();
|
||||
|
||||
// Garbage collection notifications.
|
||||
static void AfterGarbageCollection();
|
||||
|
||||
// Code generation assumptions.
|
||||
static const int kIa32CallInstructionLength = 5;
|
||||
static const int kIa32JSReturnSequenceLength = 6;
|
||||
@ -343,6 +395,11 @@ class Debug {
|
||||
|
||||
// Boolean state indicating whether any break points are set.
|
||||
static bool has_break_points_;
|
||||
|
||||
// Cache of all scripts in the heap.
|
||||
static ScriptCache* script_cache_;
|
||||
|
||||
// List of active debug info objects.
|
||||
static DebugInfoListNode* debug_info_list_;
|
||||
|
||||
static bool disable_break_;
|
||||
@ -382,8 +439,8 @@ class Debug {
|
||||
// Top debugger entry.
|
||||
EnterDebugger* debugger_entry_;
|
||||
|
||||
// Preemption happened while debugging.
|
||||
bool preemption_pending_;
|
||||
// Pending interrupts scheduled while debugging.
|
||||
int pending_interrupts_;
|
||||
};
|
||||
|
||||
// Storage location for registers when handling debug break calls
|
||||
@ -532,12 +589,15 @@ class Debugger {
|
||||
static Handle<Object> MakeCompileEvent(Handle<Script> script,
|
||||
bool before,
|
||||
bool* caught_exception);
|
||||
static Handle<Object> MakeScriptCollectedEvent(int id,
|
||||
bool* caught_exception);
|
||||
static void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
|
||||
static void OnException(Handle<Object> exception, bool uncaught);
|
||||
static void OnBeforeCompile(Handle<Script> script);
|
||||
static void OnAfterCompile(Handle<Script> script,
|
||||
Handle<JSFunction> fun);
|
||||
static void OnNewFunction(Handle<JSFunction> fun);
|
||||
static void OnScriptCollected(int id);
|
||||
static void ProcessDebugEvent(v8::DebugEvent event,
|
||||
Handle<JSObject> event_data,
|
||||
bool auto_continue);
|
||||
@ -578,7 +638,7 @@ class Debugger {
|
||||
ScopedLock with(debugger_access_);
|
||||
|
||||
// Check whether the message handler was been cleared.
|
||||
if (message_handler_cleared_) {
|
||||
if (debugger_unload_pending_) {
|
||||
UnloadDebugger();
|
||||
}
|
||||
|
||||
@ -595,6 +655,7 @@ class Debugger {
|
||||
|
||||
private:
|
||||
static bool IsDebuggerActive();
|
||||
static void ListenersChanged();
|
||||
|
||||
static Mutex* debugger_access_; // Mutex guarding debugger variables.
|
||||
static Handle<Object> event_listener_; // Global handle to listener.
|
||||
@ -603,7 +664,7 @@ class Debugger {
|
||||
static bool is_loading_debugger_; // Are we loading the debugger?
|
||||
static bool never_unload_debugger_; // Can we unload the debugger?
|
||||
static v8::Debug::MessageHandler2 message_handler_;
|
||||
static bool message_handler_cleared_; // Was message handler cleared?
|
||||
static bool debugger_unload_pending_; // Was message handler cleared?
|
||||
static v8::Debug::HostDispatchHandler host_dispatch_handler_;
|
||||
static int host_dispatch_micros_;
|
||||
|
||||
@ -626,7 +687,8 @@ class EnterDebugger BASE_EMBEDDED {
|
||||
EnterDebugger()
|
||||
: prev_(Debug::debugger_entry()),
|
||||
has_js_frames_(!it_.done()) {
|
||||
ASSERT(prev_ == NULL ? !Debug::preemption_pending() : true);
|
||||
ASSERT(prev_ != NULL || !Debug::is_interrupt_pending(PREEMPT));
|
||||
ASSERT(prev_ != NULL || !Debug::is_interrupt_pending(DEBUGBREAK));
|
||||
|
||||
// Link recursive debugger entry.
|
||||
Debug::set_debugger_entry(this);
|
||||
@ -656,22 +718,42 @@ class EnterDebugger BASE_EMBEDDED {
|
||||
// Restore to the previous break state.
|
||||
Debug::SetBreak(break_frame_id_, break_id_);
|
||||
|
||||
// Request preemption when leaving the last debugger entry and a preemption
|
||||
// had been recorded while debugging. This is to avoid starvation in some
|
||||
// debugging scenarios.
|
||||
if (prev_ == NULL && Debug::preemption_pending()) {
|
||||
StackGuard::Preempt();
|
||||
Debug::set_preemption_pending(false);
|
||||
}
|
||||
|
||||
// If there are commands in the queue when leaving the debugger request that
|
||||
// these commands are processed.
|
||||
if (prev_ == NULL && Debugger::HasCommands()) {
|
||||
StackGuard::DebugCommand();
|
||||
}
|
||||
|
||||
// If leaving the debugger with the debugger no longer active unload it.
|
||||
// Check for leaving the debugger.
|
||||
if (prev_ == NULL) {
|
||||
// Clear mirror cache when leaving the debugger. Skip this if there is a
|
||||
// pending exception as clearing the mirror cache calls back into
|
||||
// JavaScript. This can happen if the v8::Debug::Call is used in which
|
||||
// case the exception should end up in the calling code.
|
||||
if (!Top::has_pending_exception()) {
|
||||
// Try to avoid any pending debug break breaking in the clear mirror
|
||||
// cache JavaScript code.
|
||||
if (StackGuard::IsDebugBreak()) {
|
||||
Debug::set_interrupts_pending(DEBUGBREAK);
|
||||
StackGuard::Continue(DEBUGBREAK);
|
||||
}
|
||||
Debug::ClearMirrorCache();
|
||||
}
|
||||
|
||||
// Request preemption and debug break when leaving the last debugger entry
|
||||
// if any of these where recorded while debugging.
|
||||
if (Debug::is_interrupt_pending(PREEMPT)) {
|
||||
// This re-scheduling of preemption is to avoid starvation in some
|
||||
// debugging scenarios.
|
||||
Debug::clear_interrupt_pending(PREEMPT);
|
||||
StackGuard::Preempt();
|
||||
}
|
||||
if (Debug::is_interrupt_pending(DEBUGBREAK)) {
|
||||
Debug::clear_interrupt_pending(DEBUGBREAK);
|
||||
StackGuard::DebugBreak();
|
||||
}
|
||||
|
||||
// If there are commands in the queue when leaving the debugger request
|
||||
// that these commands are processed.
|
||||
if (Debugger::HasCommands()) {
|
||||
StackGuard::DebugCommand();
|
||||
}
|
||||
|
||||
// If leaving the debugger with the debugger no longer active unload it.
|
||||
if (!Debugger::IsDebuggerActive()) {
|
||||
Debugger::UnloadDebugger();
|
||||
}
|
||||
|
12
deps/v8/src/disassembler.cc
vendored
12
deps/v8/src/disassembler.cc
vendored
@ -36,16 +36,18 @@
|
||||
#include "serialize.h"
|
||||
#include "string-stream.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
|
||||
void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
|
||||
for (byte* pc = begin; pc < end; pc++) {
|
||||
if (f == NULL) {
|
||||
PrintF("%p %4d %02x\n", pc, pc - begin, *pc);
|
||||
PrintF("%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n", pc, pc - begin, *pc);
|
||||
} else {
|
||||
fprintf(f, "%p %4d %02x\n", pc, pc - begin, *pc);
|
||||
fprintf(f, "%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n",
|
||||
reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -144,8 +146,8 @@ static int DecodeIt(FILE* f,
|
||||
// raw pointer embedded in code stream, e.g., jump table
|
||||
byte* ptr = *reinterpret_cast<byte**>(pc);
|
||||
OS::SNPrintF(decode_buffer,
|
||||
"%08x jump table entry %4d",
|
||||
reinterpret_cast<int32_t>(ptr),
|
||||
"%08" V8PRIxPTR " jump table entry %4" V8PRIdPTR,
|
||||
ptr,
|
||||
ptr - begin);
|
||||
pc += 4;
|
||||
} else {
|
||||
|
3
deps/v8/src/disassembler.h
vendored
3
deps/v8/src/disassembler.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_DISASSEMBLER_H_
|
||||
#define V8_DISASSEMBLER_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class Disassembler : public AllStatic {
|
||||
public:
|
||||
|
44
deps/v8/src/execution.cc
vendored
44
deps/v8/src/execution.cc
vendored
@ -43,7 +43,8 @@
|
||||
#include "debug.h"
|
||||
#include "v8threads.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
static Handle<Object> Invoke(bool construct,
|
||||
@ -188,6 +189,24 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
|
||||
ASSERT(!object->IsJSFunction());
|
||||
|
||||
// If you return a function from here, it will be called when an
|
||||
// attempt is made to call the given object as a constructor.
|
||||
|
||||
// Objects created through the API can have an instance-call handler
|
||||
// that should be used when calling the object as a function.
|
||||
if (object->IsHeapObject() &&
|
||||
HeapObject::cast(*object)->map()->has_instance_call_handler()) {
|
||||
return Handle<JSFunction>(
|
||||
Top::global_context()->call_as_constructor_delegate());
|
||||
}
|
||||
|
||||
return Factory::undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// Static state for stack guards.
|
||||
StackGuard::ThreadLocal StackGuard::thread_local_;
|
||||
|
||||
@ -569,20 +588,7 @@ Object* Execution::DebugBreakHelper() {
|
||||
return Heap::undefined_value();
|
||||
}
|
||||
|
||||
// Don't break in system functions. If the current function is
|
||||
// either in the builtins object of some context or is in the debug
|
||||
// context just return with the debug break stack guard active.
|
||||
JavaScriptFrameIterator it;
|
||||
JavaScriptFrame* frame = it.frame();
|
||||
Object* fun = frame->function();
|
||||
if (fun->IsJSFunction()) {
|
||||
GlobalObject* global = JSFunction::cast(fun)->context()->global();
|
||||
if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
|
||||
return Heap::undefined_value();
|
||||
}
|
||||
}
|
||||
|
||||
// Check for debug command break only.
|
||||
// Collect the break state before clearing the flags.
|
||||
bool debug_command_only =
|
||||
StackGuard::IsDebugCommand() && !StackGuard::IsDebugBreak();
|
||||
|
||||
@ -590,11 +596,6 @@ Object* Execution::DebugBreakHelper() {
|
||||
StackGuard::Continue(DEBUGBREAK);
|
||||
StackGuard::Continue(DEBUGCOMMAND);
|
||||
|
||||
// If debug command only and already in debugger ignore it.
|
||||
if (debug_command_only && Debug::InDebugger()) {
|
||||
return Heap::undefined_value();
|
||||
}
|
||||
|
||||
HandleScope scope;
|
||||
// Enter the debugger. Just continue if we fail to enter the debugger.
|
||||
EnterDebugger debugger;
|
||||
@ -602,7 +603,8 @@ Object* Execution::DebugBreakHelper() {
|
||||
return Heap::undefined_value();
|
||||
}
|
||||
|
||||
// Notify the debug event listeners.
|
||||
// Notify the debug event listeners. Indicate auto continue if the break was
|
||||
// a debug command break.
|
||||
Debugger::OnDebugBreak(Factory::undefined_value(), debug_command_only);
|
||||
|
||||
// Return to continue execution.
|
||||
|
7
deps/v8/src/execution.h
vendored
7
deps/v8/src/execution.h
vendored
@ -28,7 +28,8 @@
|
||||
#ifndef V8_EXECUTION_H_
|
||||
#define V8_EXECUTION_H_
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// Flag used to set the interrupt causes.
|
||||
@ -129,6 +130,10 @@ class Execution : public AllStatic {
|
||||
// Get a function delegate (or undefined) for the given non-function
|
||||
// object. Used for support calling objects as functions.
|
||||
static Handle<Object> GetFunctionDelegate(Handle<Object> object);
|
||||
|
||||
// Get a function delegate (or undefined) for the given non-function
|
||||
// object. Used for support calling objects as constructors.
|
||||
static Handle<Object> GetConstructorDelegate(Handle<Object> object);
|
||||
};
|
||||
|
||||
|
||||
|
14
deps/v8/src/factory.cc
vendored
14
deps/v8/src/factory.cc
vendored
@ -33,7 +33,8 @@
|
||||
#include "factory.h"
|
||||
#include "macro-assembler.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
Handle<FixedArray> Factory::NewFixedArray(int size, PretenureFlag pretenure) {
|
||||
@ -176,9 +177,12 @@ Handle<Script> Factory::NewScript(Handle<String> source) {
|
||||
script->set_column_offset(Smi::FromInt(0));
|
||||
script->set_data(Heap::undefined_value());
|
||||
script->set_context_data(Heap::undefined_value());
|
||||
script->set_type(Smi::FromInt(SCRIPT_TYPE_NORMAL));
|
||||
script->set_type(Smi::FromInt(Script::TYPE_NORMAL));
|
||||
script->set_compilation_type(Smi::FromInt(Script::COMPILATION_TYPE_HOST));
|
||||
script->set_wrapper(*wrapper);
|
||||
script->set_line_ends(Heap::undefined_value());
|
||||
script->set_eval_from_function(Heap::undefined_value());
|
||||
script->set_eval_from_instructions_offset(Smi::FromInt(0));
|
||||
|
||||
return script;
|
||||
}
|
||||
@ -509,8 +513,10 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> Factory::NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
|
||||
Code::Flags flags, Handle<Object> self_ref) {
|
||||
Handle<Code> Factory::NewCode(const CodeDesc& desc,
|
||||
ZoneScopeInfo* sinfo,
|
||||
Code::Flags flags,
|
||||
Handle<Object> self_ref) {
|
||||
CALL_HEAP_FUNCTION(Heap::CreateCode(desc, sinfo, flags, self_ref), Code);
|
||||
}
|
||||
|
||||
|
10
deps/v8/src/factory.h
vendored
10
deps/v8/src/factory.h
vendored
@ -29,8 +29,10 @@
|
||||
#define V8_FACTORY_H_
|
||||
|
||||
#include "heap.h"
|
||||
#include "zone-inl.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// Interface for handle based allocation.
|
||||
@ -202,8 +204,10 @@ class Factory : public AllStatic {
|
||||
Handle<JSFunction> boilerplate,
|
||||
Handle<Context> context);
|
||||
|
||||
static Handle<Code> NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
|
||||
Code::Flags flags, Handle<Object> self_reference);
|
||||
static Handle<Code> NewCode(const CodeDesc& desc,
|
||||
ZoneScopeInfo* sinfo,
|
||||
Code::Flags flags,
|
||||
Handle<Object> self_reference);
|
||||
|
||||
static Handle<Code> CopyCode(Handle<Code> code);
|
||||
|
||||
|
6
deps/v8/src/flag-definitions.h
vendored
6
deps/v8/src/flag-definitions.h
vendored
@ -133,6 +133,9 @@ DEFINE_bool(strict, false, "strict error checking")
|
||||
DEFINE_int(min_preparse_length, 1024,
|
||||
"Minimum length for automatic enable preparsing")
|
||||
|
||||
// compilation-cache.cc
|
||||
DEFINE_bool(compilation_cache, true, "enable compilation cache")
|
||||
|
||||
// debug.cc
|
||||
DEFINE_bool(remote_debugging, false, "enable remote debugging")
|
||||
DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
|
||||
@ -333,6 +336,9 @@ DEFINE_bool(prof, false,
|
||||
"Log statistical profiling information (implies --log-code).")
|
||||
DEFINE_bool(prof_auto, true,
|
||||
"Used with --prof, starts profiling automatically")
|
||||
DEFINE_bool(prof_lazy, false,
|
||||
"Used with --prof, only does sampling and logging"
|
||||
" when profiler is active (implies --noprof_auto).")
|
||||
DEFINE_bool(log_regexp, false, "Log regular expression execution.")
|
||||
DEFINE_bool(sliding_state_window, false,
|
||||
"Update sliding state window counters.")
|
||||
|
7
deps/v8/src/flags.cc
vendored
7
deps/v8/src/flags.cc
vendored
@ -35,7 +35,8 @@
|
||||
#include "string-stream.h"
|
||||
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Define all of our flags.
|
||||
#define FLAG_MODE_DEFINE
|
||||
@ -86,9 +87,9 @@ struct Flag {
|
||||
return *reinterpret_cast<const char**>(valptr_);
|
||||
}
|
||||
|
||||
void set_string_value(const char *value, bool owns_ptr) {
|
||||
void set_string_value(const char* value, bool owns_ptr) {
|
||||
ASSERT(type_ == TYPE_STRING);
|
||||
const char **ptr = reinterpret_cast<const char **>(valptr_);
|
||||
const char** ptr = reinterpret_cast<const char**>(valptr_);
|
||||
if (owns_ptr_ && *ptr != NULL) DeleteArray(*ptr);
|
||||
*ptr = value;
|
||||
owns_ptr_ = owns_ptr;
|
||||
|
3
deps/v8/src/flags.h
vendored
3
deps/v8/src/flags.h
vendored
@ -29,7 +29,8 @@
|
||||
|
||||
#include "checks.h"
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Declare all of our flags.
|
||||
#define FLAG_MODE_DECLARE
|
||||
|
265
deps/v8/src/frame-element.h
vendored
Normal file
265
deps/v8/src/frame-element.h
vendored
Normal file
@ -0,0 +1,265 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
#ifndef V8_FRAME_ELEMENT_H_
|
||||
#define V8_FRAME_ELEMENT_H_
|
||||
|
||||
#include "register-allocator-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Virtual frame elements
|
||||
//
|
||||
// The internal elements of the virtual frames. There are several kinds of
|
||||
// elements:
|
||||
// * Invalid: elements that are uninitialized or not actually part
|
||||
// of the virtual frame. They should not be read.
|
||||
// * Memory: an element that resides in the actual frame. Its address is
|
||||
// given by its position in the virtual frame.
|
||||
// * Register: an element that resides in a register.
|
||||
// * Constant: an element whose value is known at compile time.
|
||||
|
||||
class FrameElement BASE_EMBEDDED {
|
||||
public:
|
||||
enum SyncFlag {
|
||||
NOT_SYNCED,
|
||||
SYNCED
|
||||
};
|
||||
|
||||
// The default constructor creates an invalid frame element.
|
||||
FrameElement() {
|
||||
value_ = StaticTypeField::encode(StaticType::UNKNOWN_TYPE)
|
||||
| TypeField::encode(INVALID)
|
||||
| CopiedField::encode(false)
|
||||
| SyncedField::encode(false)
|
||||
| DataField::encode(0);
|
||||
}
|
||||
|
||||
// Factory function to construct an invalid frame element.
|
||||
static FrameElement InvalidElement() {
|
||||
FrameElement result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Factory function to construct an in-memory frame element.
|
||||
static FrameElement MemoryElement() {
|
||||
FrameElement result(MEMORY, no_reg, SYNCED);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Factory function to construct an in-register frame element.
|
||||
static FrameElement RegisterElement(Register reg,
|
||||
SyncFlag is_synced,
|
||||
StaticType static_type = StaticType()) {
|
||||
return FrameElement(REGISTER, reg, is_synced, static_type);
|
||||
}
|
||||
|
||||
// Factory function to construct a frame element whose value is known at
|
||||
// compile time.
|
||||
static FrameElement ConstantElement(Handle<Object> value,
|
||||
SyncFlag is_synced) {
|
||||
FrameElement result(value, is_synced);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Static indirection table for handles to constants. If a frame
|
||||
// element represents a constant, the data contains an index into
|
||||
// this table of handles to the actual constants.
|
||||
typedef ZoneList<Handle<Object> > ZoneObjectList;
|
||||
|
||||
static ZoneObjectList* ConstantList() {
|
||||
static ZoneObjectList list(10);
|
||||
return &list;
|
||||
}
|
||||
|
||||
// Clear the constants indirection table.
|
||||
static void ClearConstantList() {
|
||||
ConstantList()->Clear();
|
||||
}
|
||||
|
||||
bool is_synced() const { return SyncedField::decode(value_); }
|
||||
|
||||
void set_sync() {
|
||||
ASSERT(type() != MEMORY);
|
||||
value_ = value_ | SyncedField::encode(true);
|
||||
}
|
||||
|
||||
void clear_sync() {
|
||||
ASSERT(type() != MEMORY);
|
||||
value_ = value_ & ~SyncedField::mask();
|
||||
}
|
||||
|
||||
bool is_valid() const { return type() != INVALID; }
|
||||
bool is_memory() const { return type() == MEMORY; }
|
||||
bool is_register() const { return type() == REGISTER; }
|
||||
bool is_constant() const { return type() == CONSTANT; }
|
||||
bool is_copy() const { return type() == COPY; }
|
||||
|
||||
bool is_copied() const { return CopiedField::decode(value_); }
|
||||
void set_copied() { value_ = value_ | CopiedField::encode(true); }
|
||||
void clear_copied() { value_ = value_ & ~CopiedField::mask(); }
|
||||
|
||||
Register reg() const {
|
||||
ASSERT(is_register());
|
||||
uint32_t reg = DataField::decode(value_);
|
||||
Register result;
|
||||
result.code_ = reg;
|
||||
return result;
|
||||
}
|
||||
|
||||
Handle<Object> handle() const {
|
||||
ASSERT(is_constant());
|
||||
return ConstantList()->at(DataField::decode(value_));
|
||||
}
|
||||
|
||||
int index() const {
|
||||
ASSERT(is_copy());
|
||||
return DataField::decode(value_);
|
||||
}
|
||||
|
||||
StaticType static_type() {
|
||||
return StaticType(StaticTypeField::decode(value_));
|
||||
}
|
||||
|
||||
void set_static_type(StaticType static_type) {
|
||||
value_ = value_ & ~StaticTypeField::mask();
|
||||
value_ = value_ | StaticTypeField::encode(static_type.static_type_);
|
||||
}
|
||||
|
||||
bool Equals(FrameElement other) {
|
||||
uint32_t masked_difference = (value_ ^ other.value_) & ~CopiedField::mask();
|
||||
if (!masked_difference) {
|
||||
// The elements are equal if they agree exactly except on copied field.
|
||||
return true;
|
||||
} else {
|
||||
// If two constants have the same value, and agree otherwise, return true.
|
||||
return !(masked_difference & ~DataField::mask()) &&
|
||||
is_constant() &&
|
||||
handle().is_identical_to(other.handle());
|
||||
}
|
||||
}
|
||||
|
||||
// Test if two FrameElements refer to the same memory or register location.
|
||||
bool SameLocation(FrameElement* other) {
|
||||
if (type() == other->type()) {
|
||||
if (value_ == other->value_) return true;
|
||||
if (is_constant() && handle().is_identical_to(other->handle())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Given a pair of non-null frame element pointers, return one of them
|
||||
// as an entry frame candidate or null if they are incompatible.
|
||||
FrameElement* Combine(FrameElement* other) {
|
||||
// If either is invalid, the result is.
|
||||
if (!is_valid()) return this;
|
||||
if (!other->is_valid()) return other;
|
||||
|
||||
if (!SameLocation(other)) return NULL;
|
||||
// If either is unsynced, the result is. The result static type is
|
||||
// the merge of the static types. It's safe to set it on one of the
|
||||
// frame elements, and harmless too (because we are only going to
|
||||
// merge the reaching frames and will ensure that the types are
|
||||
// coherent, and changing the static type does not emit code).
|
||||
FrameElement* result = is_synced() ? other : this;
|
||||
result->set_static_type(static_type().merge(other->static_type()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
enum Type {
|
||||
INVALID,
|
||||
MEMORY,
|
||||
REGISTER,
|
||||
CONSTANT,
|
||||
COPY
|
||||
};
|
||||
|
||||
// Used to construct memory and register elements.
|
||||
FrameElement(Type type, Register reg, SyncFlag is_synced) {
|
||||
value_ = StaticTypeField::encode(StaticType::UNKNOWN_TYPE)
|
||||
| TypeField::encode(type)
|
||||
| CopiedField::encode(false)
|
||||
| SyncedField::encode(is_synced != NOT_SYNCED)
|
||||
| DataField::encode(reg.code_ > 0 ? reg.code_ : 0);
|
||||
}
|
||||
|
||||
FrameElement(Type type, Register reg, SyncFlag is_synced, StaticType stype) {
|
||||
value_ = StaticTypeField::encode(stype.static_type_)
|
||||
| TypeField::encode(type)
|
||||
| CopiedField::encode(false)
|
||||
| SyncedField::encode(is_synced != NOT_SYNCED)
|
||||
| DataField::encode(reg.code_ > 0 ? reg.code_ : 0);
|
||||
}
|
||||
|
||||
// Used to construct constant elements.
|
||||
FrameElement(Handle<Object> value, SyncFlag is_synced) {
|
||||
value_ = StaticTypeField::encode(StaticType::TypeOf(*value).static_type_)
|
||||
| TypeField::encode(CONSTANT)
|
||||
| CopiedField::encode(false)
|
||||
| SyncedField::encode(is_synced != NOT_SYNCED)
|
||||
| DataField::encode(ConstantList()->length());
|
||||
ConstantList()->Add(value);
|
||||
}
|
||||
|
||||
Type type() const { return TypeField::decode(value_); }
|
||||
void set_type(Type type) {
|
||||
value_ = value_ & ~TypeField::mask();
|
||||
value_ = value_ | TypeField::encode(type);
|
||||
}
|
||||
|
||||
void set_index(int new_index) {
|
||||
ASSERT(is_copy());
|
||||
value_ = value_ & ~DataField::mask();
|
||||
value_ = value_ | DataField::encode(new_index);
|
||||
}
|
||||
|
||||
void set_reg(Register new_reg) {
|
||||
ASSERT(is_register());
|
||||
value_ = value_ & ~DataField::mask();
|
||||
value_ = value_ | DataField::encode(new_reg.code_);
|
||||
}
|
||||
|
||||
// Encode static type, type, copied, synced and data in one 32 bit integer.
|
||||
uint32_t value_;
|
||||
|
||||
class StaticTypeField: public BitField<StaticType::StaticTypeEnum, 0, 3> {};
|
||||
class TypeField: public BitField<Type, 3, 3> {};
|
||||
class CopiedField: public BitField<uint32_t, 6, 1> {};
|
||||
class SyncedField: public BitField<uint32_t, 7, 1> {};
|
||||
class DataField: public BitField<uint32_t, 8, 32 - 9> {};
|
||||
|
||||
friend class VirtualFrame;
|
||||
};
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_FRAME_ELEMENT_H_
|
3
deps/v8/src/frames-inl.h
vendored
3
deps/v8/src/frames-inl.h
vendored
@ -38,7 +38,8 @@
|
||||
#include "arm/frames-arm.h"
|
||||
#endif
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
inline Address StackHandler::address() const {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user