Browse Source

Upgrade V8 to 3.7.12

v0.7.4-release
Ryan Dahl 13 years ago
parent
commit
21d081fd7f
  1. 230
      deps/v8/ChangeLog
  2. 64
      deps/v8/Makefile
  3. 22
      deps/v8/SConstruct
  4. 11
      deps/v8/benchmarks/spinning-balls/index.html
  5. 326
      deps/v8/benchmarks/spinning-balls/splay-tree.js
  6. 498
      deps/v8/benchmarks/spinning-balls/v.js
  7. 45
      deps/v8/build/common.gypi
  8. 5
      deps/v8/build/gyp_v8
  9. 33
      deps/v8/build/mipsu.gypi
  10. 32
      deps/v8/build/standalone.gypi
  11. 5
      deps/v8/include/v8-debug.h
  12. 59
      deps/v8/include/v8.h
  13. 35
      deps/v8/preparser/preparser-process.cc
  14. 7
      deps/v8/src/SConscript
  15. 18
      deps/v8/src/accessors.cc
  16. 6
      deps/v8/src/allocation.h
  17. 220
      deps/v8/src/api.cc
  18. 18
      deps/v8/src/api.h
  19. 41
      deps/v8/src/arm/assembler-arm-inl.h
  20. 12
      deps/v8/src/arm/assembler-arm.cc
  21. 16
      deps/v8/src/arm/assembler-arm.h
  22. 1206
      deps/v8/src/arm/builtins-arm.cc
  23. 1148
      deps/v8/src/arm/code-stubs-arm.cc
  24. 321
      deps/v8/src/arm/code-stubs-arm.h
  25. 349
      deps/v8/src/arm/codegen-arm.cc
  26. 26
      deps/v8/src/arm/codegen-arm.h
  27. 47
      deps/v8/src/arm/constants-arm.h
  28. 88
      deps/v8/src/arm/debug-arm.cc
  29. 116
      deps/v8/src/arm/deoptimizer-arm.cc
  30. 43
      deps/v8/src/arm/frames-arm.h
  31. 781
      deps/v8/src/arm/full-codegen-arm.cc
  32. 259
      deps/v8/src/arm/ic-arm.cc
  33. 177
      deps/v8/src/arm/lithium-arm.cc
  34. 119
      deps/v8/src/arm/lithium-arm.h
  35. 835
      deps/v8/src/arm/lithium-codegen-arm.cc
  36. 64
      deps/v8/src/arm/lithium-codegen-arm.h
  37. 865
      deps/v8/src/arm/macro-assembler-arm.cc
  38. 337
      deps/v8/src/arm/macro-assembler-arm.h
  39. 20
      deps/v8/src/arm/regexp-macro-assembler-arm.cc
  40. 29
      deps/v8/src/arm/simulator-arm.cc
  41. 7
      deps/v8/src/arm/simulator-arm.h
  42. 1655
      deps/v8/src/arm/stub-cache-arm.cc
  43. 188
      deps/v8/src/array.js
  44. 90
      deps/v8/src/assembler.cc
  45. 86
      deps/v8/src/assembler.h
  46. 121
      deps/v8/src/ast-inl.h
  47. 199
      deps/v8/src/ast.cc
  48. 300
      deps/v8/src/ast.h
  49. 48
      deps/v8/src/atomicops_internals_mips_gcc.h
  50. 288
      deps/v8/src/bootstrapper.cc
  51. 178
      deps/v8/src/builtins.cc
  52. 47
      deps/v8/src/builtins.h
  53. 8
      deps/v8/src/bytecodes-irregexp.h
  54. 12
      deps/v8/src/cached-powers.cc
  55. 4
      deps/v8/src/char-predicates-inl.h
  56. 121
      deps/v8/src/checks.h
  57. 113
      deps/v8/src/code-stubs.cc
  58. 249
      deps/v8/src/code-stubs.h
  59. 2
      deps/v8/src/codegen.cc
  60. 15
      deps/v8/src/codegen.h
  61. 117
      deps/v8/src/collection.js
  62. 45
      deps/v8/src/compilation-cache.cc
  63. 34
      deps/v8/src/compilation-cache.h
  64. 77
      deps/v8/src/compiler-intrinsics.h
  65. 124
      deps/v8/src/compiler.cc
  66. 58
      deps/v8/src/compiler.h
  67. 206
      deps/v8/src/contexts.cc
  68. 105
      deps/v8/src/contexts.h
  69. 48
      deps/v8/src/conversions-inl.h
  70. 20
      deps/v8/src/conversions.h
  71. 5
      deps/v8/src/d8-debug.cc
  72. 78
      deps/v8/src/d8.cc
  73. 2
      deps/v8/src/d8.gyp
  74. 109
      deps/v8/src/d8.js
  75. 51
      deps/v8/src/date.js
  76. 147
      deps/v8/src/debug-debugger.js
  77. 480
      deps/v8/src/debug.cc
  78. 99
      deps/v8/src/debug.h
  79. 97
      deps/v8/src/deoptimizer.cc
  80. 36
      deps/v8/src/deoptimizer.h
  81. 2
      deps/v8/src/disassembler.cc
  82. 6
      deps/v8/src/double.h
  83. 4
      deps/v8/src/dtoa.h
  84. 344
      deps/v8/src/elements.cc
  85. 5
      deps/v8/src/elements.h
  86. 177
      deps/v8/src/execution.cc
  87. 13
      deps/v8/src/execution.h
  88. 12
      deps/v8/src/extensions/gc-extension.cc
  89. 192
      deps/v8/src/factory.cc
  90. 55
      deps/v8/src/factory.h
  91. 4
      deps/v8/src/fast-dtoa.h
  92. 60
      deps/v8/src/flag-definitions.h
  93. 88
      deps/v8/src/frames-inl.h
  94. 211
      deps/v8/src/frames.cc
  95. 93
      deps/v8/src/frames.h
  96. 248
      deps/v8/src/full-codegen.cc
  97. 152
      deps/v8/src/full-codegen.h
  98. 6
      deps/v8/src/gdb-jit.cc
  99. 42
      deps/v8/src/globals.h
  100. 156
      deps/v8/src/handles.cc

230
deps/v8/ChangeLog

@ -1,3 +1,231 @@
2011-12-01: Version 3.7.12
Increase tick interval for the android platform.
Fix a bug in the register allocator. (chromium:105112)
Fix handling of recompiling code. (chromium:105375, v8:1782)
Start incremental marking on idle notification. (v8:1458)
Build fixes for various platforms.
Various performance improvements.
2011-11-29: Version 3.7.11
Fixed bug when generating padding to ensure space for lazy
deoptimization.
(issue 1846)
Further reduced pause times due to GC.
Stability and performance improvements on all platforms.
2011-11-23: Version 3.7.10
Set maximum length of FixedArray in terms of elements instead an
absolute number of bytes.
(Chromium issue 103103)
Stability and performance improvements on all platforms.
2011-11-21: Version 3.7.9
Removed exit-time destructors.
Stability and performance improvements on all platforms.
2011-11-17: Version 3.7.8
Removed hidden prototype from builtins, i.e., deleting an overridden
function on builtins will not make the original function reappear.
Added NetBSD support for scons build.
Performance improvements on all platforms.
2011-11-14: Version 3.7.7
Fix missing fast property accessors in heap snapshots.
(issue 1818)
2011-11-11: Version 3.7.6
Fixed filtering of store buffer for large object pages.
(issue 1817)
Fixed generated hash function on all platforms.
(issue 1808)
Fixed Heap::Shrink to ensure that it does not free pages that are
still in use.
(Chromium issue 100414)
Stability and performance improvements on all platforms.
2011-11-10: Version 3.7.5
Added initial gyp infrastructure for MIPS.
Implemented performance improvements to the incremental garbage
collector.
Added optimizations and stability improvements on all platforms.
2011-11-07: Version 3.7.4
Proper "libv8.so.3.7.4" SONAME for Linux shared library (issue 1786).
Fix Harmony sets and maps to allow null and undefined as keys
(still hidden behind --harmony flag) (issue 1622).
Implement VirtualMemory on FreeBSD to fix build (issue 1807).
Enable VFP instructions for Android.
Fix error handling in Date.prototype.toISOString (issue 1792).
Bug fixes and performance improvements for all platforms.
Not officially supported but noteworthy: Crankshaft for MIPS :-)
2011-10-28: Version 3.7.3
Slight deoptimization as a workaround for issue with jslint: Issue
1789.
2011-10-27: Version 3.7.2
Fix bug in deoptimization. Known issue with jslint: Issue 1789.
2011-10-26: Version 3.7.1
Achieved 33% speedup in debug-mode tests.
Removed special casing of calls to RegExp test and exec methods with no
argument. Now matches new JSC behaviour. crbug.com/75740.
Return the empty string on cyclic references in toString (ES5
conformance).
Fixed bug triggered by JSBeautifier. crbug.com/100409.
Made Math.random state per-context instead of per-process (issue 864).
Fixed stack traces to skip native functions.
Make snapshots (new contexts) smaller and faster.
Fixed handling of Function.apply for non-array arguments.
Fixed evaluation order in defineProperties to match FireFox.
Fixed handling of non-object receivers for array builtins,
crbug.com/100702.
Multiple fixes to improve compliance with test262.
Fixed compatibility with older Android releases.
Fixed compilation with gcc-4.5.3.
Improved performance of WriteUtf8, issue 1665.
Made native syntax an early error in the preparser.
Fixed issues 793 and 893 relating to Function.prototype.bind.
Improved let, const, Set and Map support and other Harmony features
(behind the --harmony flag).
Changed evaluation order for > and <= to match ES5 instead of ES3.
Bug fixes and performance improvements on all platforms.
2011-10-13: Version 3.7.0
Fixed array handling for Object.defineOwnProperty (ES5 conformance).
Fixed issue 1757 (string slices of external strings).
Fixed issue 1759 (ARM).
Added flag --noclever-optimizations to disable some things that
caused trouble in the past.
Added flag --stress-compaction for testing.
Added flag --harmony to activate all experimental Harmony features.
2011-10-10: Version 3.6.6
Added a GC pause visualization tool.
Added presubmit=no and werror=no flags to Makefile.
ES5/Test262 conformance improvements.
Fixed compilation issues with GCC 4.5.x (issue 1743).
Bug fixes and performance improvements on all platforms.
2011-10-05: Version 3.6.5
New incremental garbage collector.
Removed the hard heap size limit (soft heap size limit is still
700/1400Mbytes by default).
Implemented ES5 generic Array.prototype.toString (Issue 1361).
V8 now allows surrogate pair codes in decodeURIComponent (Issue 1415).
Fixed x64 RegExp start-of-string bug (Issues 1746, 1748).
Fixed propertyIsEnumerable for numeric properties (Issue 1692).
Fixed the MinGW and Windows 2000 builds.
Fixed "Prototype chain is not searched if named property handler does
not set a property" (Issue 1636).
Made the RegExp.prototype object be a RegExp object (Issue 1217).
Disallowed future reserved words as labels in strict mode.
Fixed string split to correctly coerce the separator to a string
(Issue 1711).
API: Added an optional source length field to the Extension
constructor.
API: Added Debug::DisableAgent to match existing Debug::EnableAgent
(Issue 1573).
Added "native" target to Makefile for the benefit of Linux distros.
Fixed: debugger stops stepping outside evaluate (Issue 1639).
More work on ES-Harmony proxies. Still hidden behind a flag.
Bug fixes and performance improvements on all platforms.
2011-09-15: Version 3.6.4
Fixed d8's broken readline history.
@ -194,7 +422,7 @@
Fix the debugger for strict-mode functions. (Chromium issue 89236)
Add GetPropertyAttribute method for Object in the API. (Patch by
Add GetPropertyAttribute method for Object in the API. (Patch by
Peter Varga)
Fix -Wunused-but-set-variable for gcc-4.6 on x64. (Issue 1291)

64
deps/v8/Makefile

@ -27,11 +27,12 @@
# Variable default definitions. Override them by exporting them in your shell.
CXX ?= "g++" # For distcc: export CXX="distcc g++"
LINK ?= "g++"
CXX ?= g++
LINK ?= g++
OUTDIR ?= out
TESTJOBS ?= -j16
GYPFLAGS ?=
TESTFLAGS ?=
# Special build flags. Use them like this: "make library=shared"
@ -50,6 +51,10 @@ endif
ifeq ($(disassembler), on)
GYPFLAGS += -Dv8_enable_disassembler=1
endif
# objectprint=on
ifeq ($(objectprint), on)
GYPFLAGS += -Dv8_object_print=1
endif
# snapshot=off
ifeq ($(snapshot), off)
GYPFLAGS += -Dv8_use_snapshot='false'
@ -72,14 +77,23 @@ endif
ifdef soname_version
GYPFLAGS += -Dsoname_version=$(soname_version)
endif
# werror=no
ifeq ($(werror), no)
GYPFLAGS += -Dwerror=''
endif
# presubmit=no
ifeq ($(presubmit), no)
TESTFLAGS += --no-presubmit
endif
# ----------------- available targets: --------------------
# - "dependencies": pulls in external dependencies (currently: GYP)
# - any arch listed in ARCHES (see below)
# - any mode listed in MODES
# - every combination <arch>.<mode>, e.g. "ia32.release"
# - "native": current host's architecture, release mode
# - any of the above with .check appended, e.g. "ia32.release.check"
# - default (no target specified): build all ARCHES and MODES
# - default (no target specified): build all DEFAULT_ARCHES and MODES
# - "check": build all targets and run all tests
# - "<arch>.clean" for any <arch> in ARCHES
# - "clean": clean all ARCHES
@ -88,7 +102,8 @@ endif
# Architectures and modes to be compiled. Consider these to be internal
# variables, don't override them (use the targets instead).
ARCHES = ia32 x64 arm
ARCHES = ia32 x64 arm mips
DEFAULT_ARCHES = ia32 x64 arm
MODES = release debug
# List of files that trigger Makefile regeneration:
@ -103,7 +118,7 @@ CHECKS = $(addsuffix .check,$(BUILDS))
# File where previously used GYPFLAGS are stored.
ENVFILE = $(OUTDIR)/environment
.PHONY: all check clean dependencies $(ENVFILE).new \
.PHONY: all check clean dependencies $(ENVFILE).new native \
$(ARCHES) $(MODES) $(BUILDS) $(CHECKS) $(addsuffix .clean,$(ARCHES)) \
$(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES))
@ -112,7 +127,7 @@ all: $(MODES)
# Compile targets. MODES and ARCHES are convenience targets.
.SECONDEXPANSION:
$(MODES): $(addsuffix .$$@,$(ARCHES))
$(MODES): $(addsuffix .$$@,$(DEFAULT_ARCHES))
$(ARCHES): $(addprefix $$@.,$(MODES))
@ -124,21 +139,32 @@ $(BUILDS): $(OUTDIR)/Makefile-$$(basename $$@)
python -c "print raw_input().capitalize()") \
builddir="$(shell pwd)/$(OUTDIR)/$@"
native: $(OUTDIR)/Makefile-native
@$(MAKE) -C "$(OUTDIR)" -f Makefile-native \
CXX="$(CXX)" LINK="$(LINK)" BUILDTYPE=Release \
builddir="$(shell pwd)/$(OUTDIR)/$@"
# Test targets.
check: all
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR)
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch=$(shell echo $(DEFAULT_ARCHES) | sed -e 's/ /,/g') \
$(TESTFLAGS)
$(addsuffix .check,$(MODES)): $$(basename $$@)
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \
--mode=$(basename $@)
--mode=$(basename $@) $(TESTFLAGS)
$(addsuffix .check,$(ARCHES)): $$(basename $$@)
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch=$(basename $@)
--arch=$(basename $@) $(TESTFLAGS)
$(CHECKS): $$(basename $$@)
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(basename $@)
--arch-and-mode=$(basename $@) $(TESTFLAGS)
native.check: native
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR)/native \
--arch-and-mode=. $(TESTFLAGS)
# Clean targets. You can clean each architecture individually, or everything.
$(addsuffix .clean,$(ARCHES)):
@ -147,7 +173,12 @@ $(addsuffix .clean,$(ARCHES)):
rm -rf $(OUTDIR)/$(basename $@).debug
find $(OUTDIR) -regex '.*\(host\|target\)-$(basename $@)\.mk' -delete
clean: $(addsuffix .clean,$(ARCHES))
native.clean:
rm -f $(OUTDIR)/Makefile-native
rm -rf $(OUTDIR)/native
find $(OUTDIR) -regex '.*\(host\|target\)-native\.mk' -delete
clean: $(addsuffix .clean,$(ARCHES)) native.clean
# GYP file generation targets.
$(OUTDIR)/Makefile-ia32: $(GYPFILES) $(ENVFILE)
@ -160,11 +191,20 @@ $(OUTDIR)/Makefile-x64: $(GYPFILES) $(ENVFILE)
-Ibuild/standalone.gypi --depth=. -Dtarget_arch=x64 \
-S-x64 $(GYPFLAGS)
$(OUTDIR)/Makefile-arm: $(GYPFILES) $(ENVFILE)
$(OUTDIR)/Makefile-arm: $(GYPFILES) $(ENVFILE) build/armu.gypi
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
-Ibuild/standalone.gypi --depth=. -Ibuild/armu.gypi \
-S-arm $(GYPFLAGS)
$(OUTDIR)/Makefile-mips: $(GYPFILES) $(ENVFILE) build/mipsu.gypi
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
-Ibuild/standalone.gypi --depth=. -Ibuild/mipsu.gypi \
-S-mips $(GYPFLAGS)
$(OUTDIR)/Makefile-native: $(GYPFILES) $(ENVFILE)
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
-Ibuild/standalone.gypi --depth=. -S-native $(GYPFLAGS)
# Replaces the old with the new environment file if they're different, which
# will trigger GYP to regenerate Makefiles.
$(ENVFILE): $(ENVFILE).new

22
deps/v8/SConstruct

@ -129,6 +129,10 @@ LIBRARY_FLAGS = {
'LIBPATH' : ['/usr/local/lib'],
'CCFLAGS': ['-ansi'],
},
'os:netbsd': {
'CPPPATH' : ['/usr/pkg/include'],
'LIBPATH' : ['/usr/pkg/lib'],
},
'os:win32': {
'CCFLAGS': ['-DWIN32'],
'CXXFLAGS': ['-DWIN32'],
@ -288,6 +292,7 @@ V8_EXTRA_FLAGS = {
'gcc': {
'all': {
'WARNINGFLAGS': ['-Wall',
'-Werror',
'-W',
'-Wno-unused-parameter',
'-Wnon-virtual-dtor']
@ -363,6 +368,9 @@ MKSNAPSHOT_EXTRA_FLAGS = {
'os:win32': {
'LIBS': ['winmm', 'ws2_32'],
},
'os:netbsd': {
'LIBS': ['execinfo', 'pthread']
},
'compress_startup_data:bz2': {
'os:linux': {
'LIBS': ['bz2']
@ -381,7 +389,7 @@ MKSNAPSHOT_EXTRA_FLAGS = {
DTOA_EXTRA_FLAGS = {
'gcc': {
'all': {
'WARNINGFLAGS': ['-Wno-uninitialized'],
'WARNINGFLAGS': ['-Werror', '-Wno-uninitialized'],
'CCFLAGS': GCC_DTOA_EXTRA_CCFLAGS
}
},
@ -427,6 +435,9 @@ CCTEST_EXTRA_FLAGS = {
'os:win32': {
'LIBS': ['winmm', 'ws2_32']
},
'os:netbsd': {
'LIBS': ['execinfo', 'pthread']
},
'arch:arm': {
'LINKFLAGS': ARM_LINK_FLAGS
},
@ -486,6 +497,10 @@ SAMPLE_FLAGS = {
'os:win32': {
'LIBS': ['winmm', 'ws2_32']
},
'os:netbsd': {
'LIBPATH' : ['/usr/pkg/lib'],
'LIBS': ['execinfo', 'pthread']
},
'arch:arm': {
'LINKFLAGS': ARM_LINK_FLAGS,
'armeabi:soft' : {
@ -817,6 +832,9 @@ D8_FLAGS = {
'os:win32': {
'LIBS': ['winmm', 'ws2_32'],
},
'os:netbsd': {
'LIBS': ['pthread'],
},
'arch:arm': {
'LINKFLAGS': ARM_LINK_FLAGS
},
@ -950,7 +968,7 @@ PLATFORM_OPTIONS = {
'help': 'the architecture to build for'
},
'os': {
'values': ['freebsd', 'linux', 'macos', 'win32', 'openbsd', 'solaris', 'cygwin'],
'values': ['freebsd', 'linux', 'macos', 'win32', 'openbsd', 'solaris', 'cygwin', 'netbsd'],
'guess': GuessOS,
'help': 'the os to build for'
},

11
deps/v8/benchmarks/spinning-balls/index.html

@ -0,0 +1,11 @@
<html>
<head>
<style>
body { text-align: center; }
</style>
</head>
<body>
<script type="text/javascript" src="splay-tree.js"></script>
<script type="text/javascript" src="v.js"></script>
</body>
</html>

326
deps/v8/benchmarks/spinning-balls/splay-tree.js

@ -0,0 +1,326 @@
// Copyright 2011 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.
/**
* 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.
*/
SplayTree.prototype.findMax = function(opt_startNode) {
if (this.isEmpty()) {
return null;
}
var current = opt_startNode || this.root_;
while (current.right) {
current = current.right;
}
return current;
};
/**
* @return {SplayTree.Node} Node having the maximum key value that
* is less than 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;
}
};
SplayTree.prototype.traverseBreadthFirst = function (f) {
if (f(this.root_.value)) return;
var stack = [this.root_];
var length = 1;
while (length > 0) {
var new_stack = new Array(stack.length * 2);
var new_length = 0;
for (var i = 0; i < length; i++) {
var n = stack[i];
var l = n.left;
var r = n.right;
if (l) {
if (f(l.value)) return;
new_stack[new_length++] = l;
}
if (r) {
if (f(r.value)) return;
new_stack[new_length++] = r;
}
}
stack = new_stack;
length = new_length;
}
};

498
deps/v8/benchmarks/spinning-balls/v.js

@ -0,0 +1,498 @@
// Copyright 2011 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 function provides requestAnimationFrame in a cross browser way.
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
*/
if ( !window.requestAnimationFrame ) {
window.requestAnimationFrame = ( function() {
return window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, element) {
window.setTimeout( callback, 1000 / 60 );
};
} )();
}
var kNPoints = 8000;
var kNModifications = 20;
var kNVisiblePoints = 200;
var kDecaySpeed = 20;
var kPointRadius = 4;
var kInitialLifeForce = 100;
var livePoints = void 0;
var dyingPoints = void 0;
var scene = void 0;
var renderingStartTime = void 0;
var scene = void 0;
var pausePlot = void 0;
var splayTree = void 0;
var numberOfFrames = 0;
var sumOfSquaredPauses = 0;
var benchmarkStartTime = void 0;
var benchmarkTimeLimit = void 0;
var autoScale = void 0;
var pauseDistribution = [];
function Point(x, y, z, payload) {
this.x = x;
this.y = y;
this.z = z;
this.next = null;
this.prev = null;
this.payload = payload;
this.lifeForce = kInitialLifeForce;
}
Point.prototype.color = function () {
return "rgba(0, 0, 0, " + (this.lifeForce / kInitialLifeForce) + ")";
};
Point.prototype.decay = function () {
this.lifeForce -= kDecaySpeed;
return this.lifeForce <= 0;
};
function PointsList() {
this.head = null;
this.count = 0;
}
PointsList.prototype.add = function (point) {
if (this.head !== null) this.head.prev = point;
point.next = this.head;
this.head = point;
this.count++;
}
PointsList.prototype.remove = function (point) {
if (point.next !== null) {
point.next.prev = point.prev;
}
if (point.prev !== null) {
point.prev.next = point.next;
} else {
this.head = point.next;
}
this.count--;
}
function GeneratePayloadTree(depth, tag) {
if (depth == 0) {
return {
array : [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
string : 'String for key ' + tag + ' in leaf node'
};
} else {
return {
left: GeneratePayloadTree(depth - 1, tag),
right: GeneratePayloadTree(depth - 1, tag)
};
}
}
// To make the benchmark results predictable, we replace Math.random
// with a 100% deterministic alternative.
Math.random = (function() {
var seed = 49734321;
return function() {
// Robert Jenkins' 32 bit integer hash function.
seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff;
seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff;
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff;
seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
return (seed & 0xfffffff) / 0x10000000;
};
})();
function GenerateKey() {
// The benchmark framework guarantees that Math.random is
// deterministic; see base.js.
return Math.random();
}
function CreateNewPoint() {
// Insert new node with a unique key.
var key;
do { key = GenerateKey(); } while (splayTree.find(key) != null);
var point = new Point(Math.random() * 40 - 20,
Math.random() * 40 - 20,
Math.random() * 40 - 20,
GeneratePayloadTree(5, "" + key));
livePoints.add(point);
splayTree.insert(key, point);
return key;
}
function ModifyPointsSet() {
if (livePoints.count < kNPoints) {
for (var i = 0; i < kNModifications; i++) {
CreateNewPoint();
}
} else if (kNModifications === 20) {
kNModifications = 80;
kDecay = 30;
}
for (var i = 0; i < kNModifications; i++) {
var key = CreateNewPoint();
var greatest = splayTree.findGreatestLessThan(key);
if (greatest == null) {
var point = splayTree.remove(key).value;
} else {
var point = splayTree.remove(greatest.key).value;
}
livePoints.remove(point);
point.payload = null;
dyingPoints.add(point);
}
}
function PausePlot(width, height, size, scale) {
var canvas = document.createElement("canvas");
canvas.width = this.width = width;
canvas.height = this.height = height;
document.body.appendChild(canvas);
this.ctx = canvas.getContext('2d');
if (typeof scale !== "number") {
this.autoScale = true;
this.maxPause = 0;
} else {
this.autoScale = false;
this.maxPause = scale;
}
this.size = size;
// Initialize cyclic buffer for pauses.
this.pauses = new Array(this.size);
this.start = this.size;
this.idx = 0;
}
PausePlot.prototype.addPause = function (p) {
if (this.idx === this.size) {
this.idx = 0;
}
if (this.idx === this.start) {
this.start++;
}
if (this.start === this.size) {
this.start = 0;
}
this.pauses[this.idx++] = p;
};
PausePlot.prototype.iteratePauses = function (f) {
if (this.start < this.idx) {
for (var i = this.start; i < this.idx; i++) {
f.call(this, i - this.start, this.pauses[i]);
}
} else {
for (var i = this.start; i < this.size; i++) {
f.call(this, i - this.start, this.pauses[i]);
}
var offs = this.size - this.start;
for (var i = 0; i < this.idx; i++) {
f.call(this, i + offs, this.pauses[i]);
}
}
};
PausePlot.prototype.draw = function () {
var first = null;
if (this.autoScale) {
this.iteratePauses(function (i, v) {
if (first === null) {
first = v;
}
this.maxPause = Math.max(v, this.maxPause);
});
}
var dx = this.width / this.size;
var dy = this.height / this.maxPause;
this.ctx.save();
this.ctx.clearRect(0, 0, this.width, this.height);
this.ctx.beginPath();
this.ctx.moveTo(1, dy * this.pauses[this.start]);
var p = first;
this.iteratePauses(function (i, v) {
var delta = v - p;
var x = 1 + dx * i;
var y = dy * v;
this.ctx.lineTo(x, y);
if (delta > 2 * (p / 3)) {
this.ctx.font = "bold 12px sans-serif";
this.ctx.textBaseline = "bottom";
this.ctx.fillText(v + "ms", x + 2, y);
}
p = v;
});
this.ctx.strokeStyle = "black";
this.ctx.stroke();
this.ctx.restore();
}
function Scene(width, height) {
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
document.body.appendChild(canvas);
this.ctx = canvas.getContext('2d');
this.width = canvas.width;
this.height = canvas.height;
// Projection configuration.
this.x0 = canvas.width / 2;
this.y0 = canvas.height / 2;
this.z0 = 100;
this.f = 1000; // Focal length.
// Camera is rotating around y-axis.
this.angle = 0;
}
Scene.prototype.drawPoint = function (x, y, z, color) {
// Rotate the camera around y-axis.
var rx = x * Math.cos(this.angle) - z * Math.sin(this.angle);
var ry = y;
var rz = x * Math.sin(this.angle) + z * Math.cos(this.angle);
// Perform perspective projection.
var px = (this.f * rx) / (rz - this.z0) + this.x0;
var py = (this.f * ry) / (rz - this.z0) + this.y0;
this.ctx.save();
this.ctx.fillStyle = color
this.ctx.beginPath();
this.ctx.arc(px, py, kPointRadius, 0, 2 * Math.PI, true);
this.ctx.fill();
this.ctx.restore();
};
Scene.prototype.drawDyingPoints = function () {
var point_next = null;
for (var point = dyingPoints.head; point !== null; point = point_next) {
// Rotate the scene around y-axis.
scene.drawPoint(point.x, point.y, point.z, point.color());
point_next = point.next;
// Decay the current point and remove it from the list
// if it's life-force ran out.
if (point.decay()) {
dyingPoints.remove(point);
}
}
};
Scene.prototype.draw = function () {
this.ctx.save();
this.ctx.clearRect(0, 0, this.width, this.height);
this.drawDyingPoints();
this.ctx.restore();
this.angle += Math.PI / 90.0;
};
function updateStats(pause) {
numberOfFrames++;
if (pause > 20) {
sumOfSquaredPauses += (pause - 20) * (pause - 20);
}
pauseDistribution[Math.floor(pause / 10)] |= 0;
pauseDistribution[Math.floor(pause / 10)]++;
}
function renderStats() {
var msg = document.createElement("p");
msg.innerHTML = "Score " +
Math.round(numberOfFrames * 1000 / sumOfSquaredPauses);
var table = document.createElement("table");
table.align = "center";
for (var i = 0; i < pauseDistribution.length; i++) {
if (pauseDistribution[i] > 0) {
var row = document.createElement("tr");
var time = document.createElement("td");
var count = document.createElement("td");
time.innerHTML = i*10 + "-" + (i+1)*10 + "ms";
count.innerHTML = " => " + pauseDistribution[i];
row.appendChild(time);
row.appendChild(count);
table.appendChild(row);
}
}
div.appendChild(msg);
div.appendChild(table);
}
function render() {
if (typeof renderingStartTime === 'undefined') {
renderingStartTime = Date.now();
benchmarkStartTime = renderingStartTime;
}
ModifyPointsSet();
scene.draw();
var renderingEndTime = Date.now();
var pause = renderingEndTime - renderingStartTime;
pausePlot.addPause(pause);
renderingStartTime = renderingEndTime;
pausePlot.draw();
updateStats(pause);
div.innerHTML =
livePoints.count + "/" + dyingPoints.count + " " +
pause + "(max = " + pausePlot.maxPause + ") ms " +
numberOfFrames + " frames";
if (renderingEndTime < benchmarkStartTime + benchmarkTimeLimit) {
// Schedule next frame.
requestAnimationFrame(render);
} else {
renderStats();
}
}
function Form() {
function create(tag) { return document.createElement(tag); }
function text(value) { return document.createTextNode(value); }
this.form = create("form");
this.form.setAttribute("action", "javascript:start()");
var table = create("table");
table.setAttribute("style", "margin-left: auto; margin-right: auto;");
function col(a) {
var td = create("td");
td.appendChild(a);
return td;
}
function row(a, b) {
var tr = create("tr");
tr.appendChild(col(a));
tr.appendChild(col(b));
return tr;
}
this.timelimit = create("input");
this.timelimit.setAttribute("value", "60");
table.appendChild(row(text("Time limit in seconds"), this.timelimit));
this.autoscale = create("input");
this.autoscale.setAttribute("type", "checkbox");
this.autoscale.setAttribute("checked", "true");
table.appendChild(row(text("Autoscale pauses plot"), this.autoscale));
var button = create("input");
button.setAttribute("type", "submit");
button.setAttribute("value", "Start");
this.form.appendChild(table);
this.form.appendChild(button);
document.body.appendChild(this.form);
}
Form.prototype.remove = function () {
document.body.removeChild(this.form);
};
function init() {
livePoints = new PointsList;
dyingPoints = new PointsList;
splayTree = new SplayTree();
scene = new Scene(640, 480);
div = document.createElement("div");
document.body.appendChild(div);
pausePlot = new PausePlot(480, autoScale ? 240 : 500, 160, autoScale ? void 0 : 500);
}
function start() {
benchmarkTimeLimit = form.timelimit.value * 1000;
autoScale = form.autoscale.checked;
form.remove();
init();
render();
}
var form = new Form();

45
deps/v8/build/common.gypi

@ -50,16 +50,24 @@
# probing when running on the target.
'v8_can_use_vfp_instructions%': 'false',
# Similar to vfp but on MIPS.
'v8_can_use_fpu_instructions%': 'true',
# Setting v8_use_arm_eabi_hardfloat to true will turn on V8 support for ARM
# EABI calling convention where double arguments are passed in VFP
# registers. Note that the GCC flag '-mfloat-abi=hard' should be used as
# well when compiling for the ARM target.
'v8_use_arm_eabi_hardfloat%': 'false',
# Similar to the ARM hard float ABI but on MIPS.
'v8_use_mips_abi_hardfloat%': 'true',
'v8_enable_debugger_support%': 1,
'v8_enable_disassembler%': 0,
'v8_object_print%': 0,
'v8_enable_gdbjit%': 0,
# Enable profiling support. Only required on Windows.
@ -72,6 +80,7 @@
'v8_use_snapshot%': 'true',
'host_os%': '<(OS)',
'v8_use_liveobjectlist%': 'false',
'werror%': '-Werror',
# For a shared library build, results in "libv8-<(soname_version).so".
'soname_version%': '',
@ -84,6 +93,9 @@
['v8_enable_disassembler==1', {
'defines': ['ENABLE_DISASSEMBLER',],
}],
['v8_object_print==1', {
'defines': ['OBJECT_PRINT',],
}],
['v8_enable_gdbjit==1', {
'defines': ['ENABLE_GDB_JIT_INTERFACE',],
}],
@ -129,7 +141,7 @@
}],
# The ARM assembler assumes the host is 32 bits,
# so force building 32-bit host tools.
['host_arch=="x64"', {
['host_arch=="x64" or OS=="android"', {
'target_conditions': [
['_toolset=="host"', {
'cflags': ['-m32'],
@ -148,6 +160,33 @@
'defines': [
'V8_TARGET_ARCH_MIPS',
],
'conditions': [
[ 'v8_can_use_fpu_instructions=="true"', {
'defines': [
'CAN_USE_FPU_INSTRUCTIONS',
],
}],
[ 'v8_use_mips_abi_hardfloat=="true"', {
'defines': [
'__mips_hard_float=1',
'CAN_USE_FPU_INSTRUCTIONS',
],
}, {
'defines': [
'__mips_soft_float=1'
],
}],
# The MIPS assembler assumes the host is 32 bits,
# so force building 32-bit host tools.
['host_arch=="x64"', {
'target_conditions': [
['_toolset=="host"', {
'cflags': ['-m32'],
'ldflags': ['-m32'],
}],
],
}],
],
}],
['v8_target_arch=="x64"', {
'defines': [
@ -221,7 +260,7 @@
'cflags': [ '-I/usr/local/include' ],
}],
['OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
'cflags': [ '-Wall', '-Werror', '-W', '-Wno-unused-parameter',
'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter',
'-Wnon-virtual-dtor' ],
}],
],
@ -264,7 +303,7 @@
}],
['OS=="win"', {
'msvs_configuration_attributes': {
'OutputDirectory': '$(SolutionDir)$(ConfigurationName)',
'OutputDirectory': '<(DEPTH)\\build\\$(ConfigurationName)',
'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)',
'CharacterSet': '1',
},

5
deps/v8/build/gyp_v8

@ -171,3 +171,8 @@ if __name__ == '__main__':
gyp_args.append('-I' + v8_root + '/build/armu.gypi')
gyp_args.append('-S-armu')
run_gyp(gyp_args)
gyp_args = list(args)
gyp_args.append('-I' + v8_root + '/build/mipsu.gypi')
gyp_args.append('-S-mipsu')
run_gyp(gyp_args)

33
deps/v8/build/mipsu.gypi

@ -0,0 +1,33 @@
# Copyright 2011 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.
{
'variables': {
'target_arch': 'ia32',
'v8_target_arch': 'mips',
},
}

32
deps/v8/build/standalone.gypi

@ -35,27 +35,33 @@
'msvs_multi_core_compile%': '1',
'variables': {
'variables': {
'conditions': [
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
# This handles the Linux platforms we generally deal with. Anything
# else gets passed through, which probably won't work very well; such
# hosts should pass an explicit target_arch to gyp.
'host_arch%':
'<!(uname -m | sed -e "s/i.86/ia32/;s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/")',
}, { # OS!="linux" and OS!="freebsd" and OS!="openbsd"
'host_arch%': 'ia32',
}],
],
'variables': {
'conditions': [
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
# This handles the Linux platforms we generally deal with. Anything
# else gets passed through, which probably won't work very well; such
# hosts should pass an explicit target_arch to gyp.
'host_arch%':
'<!(uname -m | sed -e "s/i.86/ia32/;s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/;s/mips.*/mips/")',
}, { # OS!="linux" and OS!="freebsd" and OS!="openbsd"
'host_arch%': 'ia32',
}],
],
},
'host_arch%': '<(host_arch)',
'target_arch%': '<(host_arch)',
},
'host_arch%': '<(host_arch)',
'target_arch%': '<(host_arch)',
'target_arch%': '<(target_arch)',
'v8_target_arch%': '<(target_arch)',
},
'host_arch%': '<(host_arch)',
'target_arch%': '<(target_arch)',
'v8_target_arch%': '<(v8_target_arch)',
'werror%': '-Werror',
'conditions': [
['(v8_target_arch=="arm" and host_arch!="arm") or \
(v8_target_arch=="mips" and host_arch!="mips") or \
(v8_target_arch=="x64" and host_arch!="x64")', {
'want_separate_host_toolset': 1,
}, {
@ -74,7 +80,7 @@
'conditions': [
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
'target_defaults': {
'cflags': [ '-Wall', '-Werror', '-W', '-Wno-unused-parameter',
'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter',
'-Wnon-virtual-dtor', '-pthread', '-fno-rtti',
'-fno-exceptions', '-pedantic' ],
'ldflags': [ '-pthread', ],

5
deps/v8/include/v8-debug.h

@ -339,6 +339,11 @@ class EXPORT Debug {
static bool EnableAgent(const char* name, int port,
bool wait_for_connection = false);
/**
* Disable the V8 builtin debug agent. The TCP/IP connection will be closed.
*/
static void DisableAgent();
/**
* Makes V8 process all pending debug messages.
*

59
deps/v8/include/v8.h

@ -1171,7 +1171,8 @@ class String : public Primitive {
* Get the ExternalAsciiStringResource for an external ASCII string.
* Returns NULL if IsExternalAscii() doesn't return true.
*/
V8EXPORT ExternalAsciiStringResource* GetExternalAsciiStringResource() const;
V8EXPORT const ExternalAsciiStringResource* GetExternalAsciiStringResource()
const;
static inline String* Cast(v8::Value* obj);
@ -1735,9 +1736,16 @@ class Function : public Object {
* kLineOffsetNotFound if no information available.
*/
V8EXPORT int GetScriptLineNumber() const;
/**
* Returns zero based column number of function body and
* kLineOffsetNotFound if no information available.
*/
V8EXPORT int GetScriptColumnNumber() const;
V8EXPORT Handle<Value> GetScriptId() const;
V8EXPORT ScriptOrigin GetScriptOrigin() const;
static inline Function* Cast(Value* obj);
V8EXPORT static const int kLineOffsetNotFound;
private:
V8EXPORT Function();
V8EXPORT static void CheckCast(Value* obj);
@ -2451,24 +2459,42 @@ class V8EXPORT TypeSwitch : public Data {
// --- Extensions ---
class V8EXPORT ExternalAsciiStringResourceImpl
: public String::ExternalAsciiStringResource {
public:
ExternalAsciiStringResourceImpl() : data_(0), length_(0) {}
ExternalAsciiStringResourceImpl(const char* data, size_t length)
: data_(data), length_(length) {}
const char* data() const { return data_; }
size_t length() const { return length_; }
private:
const char* data_;
size_t length_;
};
/**
* Ignore
*/
class V8EXPORT Extension { // NOLINT
public:
// Note that the strings passed into this constructor must live as long
// as the Extension itself.
Extension(const char* name,
const char* source = 0,
int dep_count = 0,
const char** deps = 0);
const char** deps = 0,
int source_length = -1);
virtual ~Extension() { }
virtual v8::Handle<v8::FunctionTemplate>
GetNativeFunction(v8::Handle<v8::String> name) {
return v8::Handle<v8::FunctionTemplate>();
}
const char* name() { return name_; }
const char* source() { return source_; }
const char* name() const { return name_; }
size_t source_length() const { return source_length_; }
const String::ExternalAsciiStringResource* source() const {
return &source_; }
int dependency_count() { return dep_count_; }
const char** dependencies() { return deps_; }
void set_auto_enable(bool value) { auto_enable_ = value; }
@ -2476,7 +2502,8 @@ class V8EXPORT Extension { // NOLINT
private:
const char* name_;
const char* source_;
size_t source_length_; // expected to initialize before source_
ExternalAsciiStringResourceImpl source_;
int dep_count_;
const char** deps_;
bool auto_enable_;
@ -3167,8 +3194,12 @@ class V8EXPORT V8 {
* Returns true if the embedder should stop calling IdleNotification
* until real work has been done. This indicates that V8 has done
* as much cleanup as it will be able to do.
*
* The hint argument specifies the amount of work to be done in the function
* on scale from 1 to 1000. There is no guarantee that the actual work will
* match the hint.
*/
static bool IdleNotification();
static bool IdleNotification(int hint = 1000);
/**
* Optional notification that the system is running low on memory.
@ -3498,9 +3529,9 @@ class V8EXPORT Context {
*
* v8::Locker is a scoped lock object. While it's
* active (i.e. between its construction and destruction) the current thread is
* allowed to use the locked isolate. V8 guarantees that an isolate can be locked
* by at most one thread at any time. In other words, the scope of a v8::Locker is
* a critical section.
* allowed to use the locked isolate. V8 guarantees that an isolate can be
* locked by at most one thread at any time. In other words, the scope of a
* v8::Locker is a critical section.
*
* Sample usage:
* \code
@ -3602,8 +3633,8 @@ class V8EXPORT Locker {
static void StopPreemption();
/**
* Returns whether or not the locker for a given isolate, or default isolate if NULL is given,
* is locked by the current thread.
* Returns whether or not the locker for a given isolate, or default isolate
* if NULL is given, is locked by the current thread.
*/
static bool IsLocked(Isolate* isolate = NULL);
@ -3677,8 +3708,8 @@ class V8EXPORT ActivityControl { // NOLINT
namespace internal {
static const int kApiPointerSize = sizeof(void*); // NOLINT
static const int kApiIntSize = sizeof(int); // NOLINT
const int kApiPointerSize = sizeof(void*); // NOLINT
const int kApiIntSize = sizeof(int); // NOLINT
// Tag information for HeapObject.
const int kHeapObjectTag = 1;
@ -3769,7 +3800,7 @@ class Internals {
static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02;
static const int kJSObjectType = 0xa3;
static const int kJSObjectType = 0xa6;
static const int kFirstNonstringType = 0x80;
static const int kForeignType = 0x85;

35
deps/v8/preparser/preparser-process.cc

@ -267,34 +267,22 @@ void CheckException(v8::PreParserData* data,
ExceptionExpectation ParseExpectation(int argc, const char* argv[]) {
// Parse ["throws" [<exn-type> [<start> [<end>]]]].
ExceptionExpectation expects;
// Parse exception expectations from (the remainder of) the command line.
int arg_index = 0;
// Skip any flags.
while (argc > arg_index && IsFlag(argv[arg_index])) arg_index++;
while (argc > arg_index && strncmp("throws", argv[arg_index], 7)) {
arg_index++;
}
if (argc > arg_index) {
if (strncmp("throws", argv[arg_index], 7)) {
// First argument after filename, if present, must be the verbatim
// "throws", marking that the preparsing should fail with an exception.
fail(NULL, "ERROR: Extra arguments not prefixed by \"throws\".\n");
}
expects.throws = true;
do {
arg_index++;
} while (argc > arg_index && IsFlag(argv[arg_index]));
if (argc > arg_index) {
// Next argument is the exception type identifier.
arg_index++;
if (argc > arg_index && !IsFlag(argv[arg_index])) {
expects.type = argv[arg_index];
do {
arg_index++;
} while (argc > arg_index && IsFlag(argv[arg_index]));
if (argc > arg_index) {
arg_index++;
if (argc > arg_index && !IsFlag(argv[arg_index])) {
expects.beg_pos = atoi(argv[arg_index]); // NOLINT
do {
arg_index++;
} while (argc > arg_index && IsFlag(argv[arg_index]));
if (argc > arg_index) {
arg_index++;
if (argc > arg_index && !IsFlag(argv[arg_index])) {
expects.end_pos = atoi(argv[arg_index]); // NOLINT
}
}
@ -308,7 +296,8 @@ int main(int argc, const char* argv[]) {
// Parse command line.
// Format: preparser (<scriptfile> | -e "<source>")
// ["throws" [<exn-type> [<start> [<end>]]]]
// Any flags (except an initial -s) are ignored.
// Any flags (except an initial -e) are ignored.
// Flags must not separate "throws" and its arguments.
// Check for mandatory filename argument.
int arg_index = 1;

7
deps/v8/src/SConscript

@ -84,6 +84,7 @@ SOURCES = {
hydrogen.cc
hydrogen-instructions.cc
ic.cc
incremental-marking.cc
inspector.cc
interpreter-irregexp.cc
isolate.cc
@ -133,6 +134,7 @@ SOURCES = {
v8utils.cc
variables.cc
version.cc
store-buffer.cc
zone.cc
extensions/gc-extension.cc
extensions/externalize-string-extension.cc
@ -170,6 +172,9 @@ SOURCES = {
mips/frames-mips.cc
mips/full-codegen-mips.cc
mips/ic-mips.cc
mips/lithium-codegen-mips.cc
mips/lithium-gap-resolver-mips.cc
mips/lithium-mips.cc
mips/macro-assembler-mips.cc
mips/regexp-macro-assembler-mips.cc
mips/stub-cache-mips.cc
@ -319,7 +324,7 @@ debug-debugger.js
EXPERIMENTAL_LIBRARY_FILES = '''
proxy.js
weakmap.js
collection.js
'''.split()

18
deps/v8/src/accessors.cc

@ -527,7 +527,9 @@ MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
// correctly yet. Compile it now and return the right length.
HandleScope scope;
Handle<JSFunction> handle(function);
if (!CompileLazy(handle, KEEP_EXCEPTION)) return Failure::Exception();
if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) {
return Failure::Exception();
}
return Smi::FromInt(handle->shared()->length());
} else {
return Smi::FromInt(function->shared()->length());
@ -619,8 +621,9 @@ MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
if (!frame->is_optimized()) {
// If there is an arguments variable in the stack, we return that.
Handle<SerializedScopeInfo> info(function->shared()->scope_info());
int index = info->StackSlotIndex(isolate->heap()->arguments_symbol());
Handle<ScopeInfo> scope_info(function->shared()->scope_info());
int index = scope_info->StackSlotIndex(
isolate->heap()->arguments_symbol());
if (index >= 0) {
Handle<Object> arguments(frame->GetExpression(index), isolate);
if (!arguments->IsArgumentsMarker()) return *arguments;
@ -672,7 +675,7 @@ static MaybeObject* CheckNonStrictCallerOrThrow(
Isolate* isolate,
JSFunction* caller) {
DisableAssertNoAllocation enable_allocation;
if (caller->shared()->strict_mode()) {
if (!caller->shared()->is_classic_mode()) {
return isolate->Throw(
*isolate->factory()->NewTypeError("strict_caller",
HandleVector<Object>(NULL, 0)));
@ -759,7 +762,12 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
caller = potential_caller;
potential_caller = it.next();
}
// If caller is bound, return null. This is compatible with JSC, and
// allows us to make bound functions use the strict function map
// and its associated throwing caller and arguments.
if (caller->shared()->bound()) {
return isolate->heap()->null_value();
}
return CheckNonStrictCallerOrThrow(isolate, caller);
}

6
deps/v8/src/allocation.h

@ -1,4 +1,4 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -81,7 +81,7 @@ class AllStatic {
template <typename T>
static T* NewArray(int size) {
T* NewArray(int size) {
T* result = new T[size];
if (result == NULL) Malloced::FatalProcessOutOfMemory();
return result;
@ -89,7 +89,7 @@ static T* NewArray(int size) {
template <typename T>
static void DeleteArray(T* array) {
void DeleteArray(T* array) {
delete[] array;
}

220
deps/v8/src/api.cc

@ -185,7 +185,10 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) {
int end_marker;
heap_stats.end_marker = &end_marker;
i::Isolate* isolate = i::Isolate::Current();
isolate->heap()->RecordStats(&heap_stats, take_snapshot);
// BUG(1718):
// Don't use the take_snapshot since we don't support HeapIterator here
// without doing a special GC.
isolate->heap()->RecordStats(&heap_stats, false);
i::V8::SetFatalError();
FatalErrorCallback callback = GetFatalErrorHandler();
{
@ -483,7 +486,7 @@ RegisteredExtension* RegisteredExtension::first_extension_ = NULL;
RegisteredExtension::RegisteredExtension(Extension* extension)
: extension_(extension), state_(UNVISITED) { }
: extension_(extension) { }
void RegisteredExtension::Register(RegisteredExtension* that) {
@ -501,9 +504,12 @@ void RegisterExtension(Extension* that) {
Extension::Extension(const char* name,
const char* source,
int dep_count,
const char** deps)
const char** deps,
int source_length)
: name_(name),
source_(source),
source_length_(source_length >= 0 ?
source_length : (source ? strlen(source) : 0)),
source_(source, source_length_),
dep_count_(dep_count),
deps_(deps),
auto_enable_(false) { }
@ -1407,7 +1413,7 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
ScriptData* ScriptData::PreCompile(const char* input, int length) {
i::Utf8ToUC16CharacterStream stream(
reinterpret_cast<const unsigned char*>(input), length);
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping);
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
}
@ -1416,10 +1422,10 @@ ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
if (str->IsExternalTwoByteString()) {
i::ExternalTwoByteStringUC16CharacterStream stream(
i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length());
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping);
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
} else {
i::GenericStringUC16CharacterStream stream(str, 0, str->length());
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping);
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
}
}
@ -1781,7 +1787,7 @@ v8::Handle<v8::StackTrace> Message::GetStackTrace() const {
static i::Handle<i::Object> CallV8HeapFunction(const char* name,
i::Handle<i::Object> recv,
int argc,
i::Object** argv[],
i::Handle<i::Object> argv[],
bool* has_pending_exception) {
i::Isolate* isolate = i::Isolate::Current();
i::Handle<i::String> fmt_str = isolate->factory()->LookupAsciiSymbol(name);
@ -1798,10 +1804,10 @@ static i::Handle<i::Object> CallV8HeapFunction(const char* name,
static i::Handle<i::Object> CallV8HeapFunction(const char* name,
i::Handle<i::Object> data,
bool* has_pending_exception) {
i::Object** argv[1] = { data.location() };
i::Handle<i::Object> argv[] = { data };
return CallV8HeapFunction(name,
i::Isolate::Current()->js_builtins_object(),
1,
ARRAY_SIZE(argv),
argv,
has_pending_exception);
}
@ -2621,10 +2627,11 @@ bool Value::Equals(Handle<Value> that) const {
if (obj->IsJSObject() && other->IsJSObject()) {
return *obj == *other;
}
i::Object** args[1] = { other.location() };
i::Handle<i::Object> args[] = { other };
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result =
CallV8HeapFunction("EQUALS", obj, 1, args, &has_pending_exception);
CallV8HeapFunction("EQUALS", obj, ARRAY_SIZE(args), args,
&has_pending_exception);
EXCEPTION_BAILOUT_CHECK(isolate, false);
return *result == i::Smi::FromInt(i::EQUAL);
}
@ -2787,7 +2794,7 @@ Local<Value> v8::Object::Get(uint32_t index) {
ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = i::GetElement(self, index);
i::Handle<i::Object> result = i::Object::GetElement(self, index);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
return Utils::ToLocal(result);
@ -2867,8 +2874,10 @@ Local<Array> v8::Object::GetPropertyNames() {
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
bool threw = false;
i::Handle<i::FixedArray> value =
i::GetKeysInFixedArrayFor(self, i::INCLUDE_PROTOS);
i::GetKeysInFixedArrayFor(self, i::INCLUDE_PROTOS, &threw);
if (threw) return Local<v8::Array>();
// Because we use caching to speed up enumeration it is important
// to never change the result of the basic enumeration function so
// we clone the result.
@ -2886,8 +2895,10 @@ Local<Array> v8::Object::GetOwnPropertyNames() {
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
bool threw = false;
i::Handle<i::FixedArray> value =
i::GetKeysInFixedArrayFor(self, i::LOCAL_ONLY);
i::GetKeysInFixedArrayFor(self, i::LOCAL_ONLY, &threw);
if (threw) return Local<v8::Array>();
// Because we use caching to speed up enumeration it is important
// to never change the result of the basic enumeration function so
// we clone the result.
@ -3086,7 +3097,10 @@ static Local<Value> GetPropertyByLookup(i::Isolate* isolate,
// If the property being looked up is a callback, it can throw
// an exception.
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = i::GetProperty(receiver, name, lookup);
PropertyAttributes ignored;
i::Handle<i::Object> result =
i::Object::GetProperty(receiver, receiver, lookup, name,
&ignored);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
@ -3103,7 +3117,7 @@ Local<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
ENTER_V8(isolate);
i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::LookupResult lookup;
i::LookupResult lookup(isolate);
self_obj->LookupRealNamedPropertyInPrototypes(*key_obj, &lookup);
return GetPropertyByLookup(isolate, self_obj, key_obj, &lookup);
}
@ -3116,7 +3130,7 @@ Local<Value> v8::Object::GetRealNamedProperty(Handle<String> key) {
ENTER_V8(isolate);
i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::LookupResult lookup;
i::LookupResult lookup(isolate);
self_obj->LookupRealNamedProperty(*key_obj, &lookup);
return GetPropertyByLookup(isolate, self_obj, key_obj, &lookup);
}
@ -3204,21 +3218,10 @@ bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props(i::GetHiddenProperties(
self,
i::JSObject::ALLOW_CREATION));
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj = i::SetProperty(
hidden_props,
key_obj,
value_obj,
static_cast<PropertyAttributes>(None),
i::kNonStrictMode);
has_pending_exception = obj.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, false);
return true;
i::Handle<i::Object> result = i::SetHiddenProperty(self, key_obj, value_obj);
return *result == *self;
}
@ -3228,20 +3231,9 @@ v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
return Local<v8::Value>());
ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props(i::GetHiddenProperties(
self,
i::JSObject::OMIT_CREATION));
if (hidden_props->IsUndefined()) {
return v8::Local<v8::Value>();
}
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = i::GetProperty(hidden_props, key_obj);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, v8::Local<v8::Value>());
if (result->IsUndefined()) {
return v8::Local<v8::Value>();
}
i::Handle<i::Object> result(self->GetHiddenProperty(*key_obj));
if (result->IsUndefined()) return v8::Local<v8::Value>();
return Utils::ToLocal(result);
}
@ -3252,15 +3244,9 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props(i::GetHiddenProperties(
self,
i::JSObject::OMIT_CREATION));
if (hidden_props->IsUndefined()) {
return true;
}
i::Handle<i::JSObject> js_obj(i::JSObject::cast(*hidden_props));
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
return i::DeleteProperty(js_obj, key_obj)->IsTrue();
self->DeleteHiddenProperty(*key_obj);
return true;
}
@ -3310,22 +3296,12 @@ void PrepareExternalArrayElements(i::Handle<i::JSObject> object,
i::Handle<i::ExternalArray> array =
isolate->factory()->NewExternalArray(length, array_type, data);
// If the object already has external elements, create a new, unique
// map if the element type is now changing, because assumptions about
// generated code based on the receiver's map will be invalid.
i::Handle<i::HeapObject> elements(object->elements());
bool cant_reuse_map =
elements->map()->IsUndefined() ||
!elements->map()->has_external_array_elements() ||
elements->map() != isolate->heap()->MapForExternalArrayType(array_type);
if (cant_reuse_map) {
i::Handle<i::Map> external_array_map =
isolate->factory()->GetElementsTransitionMap(
i::Handle<i::Map>(object->map()),
GetElementsKindFromExternalArrayType(array_type),
object->HasFastProperties());
object->set_map(*external_array_map);
}
i::Handle<i::Map> external_array_map =
isolate->factory()->GetElementsTransitionMap(
object,
GetElementsKindFromExternalArrayType(array_type));
object->set_map(*external_array_map);
object->set_elements(*array);
}
@ -3484,7 +3460,8 @@ bool v8::Object::IsCallable() {
}
Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv,
int argc,
v8::Handle<v8::Value> argv[]) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::CallAsFunction()",
@ -3495,7 +3472,7 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
i::Object*** args = reinterpret_cast<i::Object***>(argv);
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>();
if (obj->IsJSFunction()) {
fun = i::Handle<i::JSFunction>::cast(obj);
@ -3525,7 +3502,7 @@ Local<v8::Value> Object::CallAsConstructor(int argc,
i::HandleScope scope(isolate);
i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
i::Object*** args = reinterpret_cast<i::Object***>(argv);
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
if (obj->IsJSFunction()) {
i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(obj);
EXCEPTION_PREAMBLE(isolate);
@ -3567,7 +3544,7 @@ Local<v8::Object> Function::NewInstance(int argc,
HandleScope scope;
i::Handle<i::JSFunction> function = Utils::OpenHandle(this);
STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
i::Object*** args = reinterpret_cast<i::Object***>(argv);
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> returned =
i::Execution::New(function, argc, args, &has_pending_exception);
@ -3588,7 +3565,7 @@ Local<v8::Value> Function::Call(v8::Handle<v8::Object> recv, int argc,
i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
i::Object*** args = reinterpret_cast<i::Object***>(argv);
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> returned =
i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception);
@ -3642,6 +3619,23 @@ int Function::GetScriptLineNumber() const {
}
int Function::GetScriptColumnNumber() const {
i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
if (func->shared()->script()->IsScript()) {
i::Handle<i::Script> script(i::Script::cast(func->shared()->script()));
return i::GetScriptColumnNumber(script, func->shared()->start_position());
}
return kLineOffsetNotFound;
}
Handle<Value> Function::GetScriptId() const {
i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
if (!func->shared()->script()->IsScript())
return v8::Undefined();
i::Handle<i::Script> script(i::Script::cast(func->shared()->script()));
return Utils::ToLocal(i::Handle<i::Object>(script->id()));
}
int String::Length() const {
i::Handle<i::String> str = Utils::OpenHandle(this);
if (IsDeadCheck(str->GetIsolate(), "v8::String::Length()")) return 0;
@ -3664,13 +3658,30 @@ int String::WriteUtf8(char* buffer,
if (IsDeadCheck(isolate, "v8::String::WriteUtf8()")) return 0;
LOG_API(isolate, "String::WriteUtf8");
ENTER_V8(isolate);
i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer();
i::Handle<i::String> str = Utils::OpenHandle(this);
if (str->IsAsciiRepresentation()) {
int len;
if (capacity == -1) {
capacity = str->length() + 1;
len = str->length();
} else {
len = i::Min(capacity, str->length());
}
i::String::WriteToFlat(*str, buffer, 0, len);
if (nchars_ref != NULL) *nchars_ref = len;
if (!(options & NO_NULL_TERMINATION) && capacity > len) {
buffer[len] = '\0';
return len + 1;
}
return len;
}
i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer();
isolate->string_tracker()->RecordWrite(str);
if (options & HINT_MANY_WRITES_EXPECTED) {
// Flatten the string for efficiency. This applies whether we are
// using StringInputBuffer or Get(i) to access the characters.
str->TryFlatten();
FlattenString(str);
}
write_input_buffer.Reset(0, *str);
int len = str->length();
@ -3799,10 +3810,11 @@ bool v8::String::IsExternalAscii() const {
void v8::String::VerifyExternalStringResource(
v8::String::ExternalStringResource* value) const {
i::Handle<i::String> str = Utils::OpenHandle(this);
v8::String::ExternalStringResource* expected;
const v8::String::ExternalStringResource* expected;
if (i::StringShape(*str).IsExternalTwoByte()) {
void* resource = i::Handle<i::ExternalTwoByteString>::cast(str)->resource();
expected = reinterpret_cast<ExternalStringResource*>(resource);
const void* resource =
i::Handle<i::ExternalTwoByteString>::cast(str)->resource();
expected = reinterpret_cast<const ExternalStringResource*>(resource);
} else {
expected = NULL;
}
@ -3810,7 +3822,7 @@ void v8::String::VerifyExternalStringResource(
}
v8::String::ExternalAsciiStringResource*
const v8::String::ExternalAsciiStringResource*
v8::String::GetExternalAsciiStringResource() const {
i::Handle<i::String> str = Utils::OpenHandle(this);
if (IsDeadCheck(str->GetIsolate(),
@ -3818,8 +3830,9 @@ v8::String::ExternalAsciiStringResource*
return NULL;
}
if (i::StringShape(*str).IsExternalAscii()) {
void* resource = i::Handle<i::ExternalAsciiString>::cast(str)->resource();
return reinterpret_cast<ExternalAsciiStringResource*>(resource);
const void* resource =
i::Handle<i::ExternalAsciiString>::cast(str)->resource();
return reinterpret_cast<const ExternalAsciiStringResource*>(resource);
} else {
return NULL;
}
@ -3989,6 +4002,15 @@ HeapStatistics::HeapStatistics(): total_heap_size_(0),
void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
if (!i::Isolate::Current()->IsInitialized()) {
// Isolate is unitialized thus heap is not configured yet.
heap_statistics->set_total_heap_size(0);
heap_statistics->set_total_heap_size_executable(0);
heap_statistics->set_used_heap_size(0);
heap_statistics->set_heap_size_limit(0);
return;
}
i::Heap* heap = i::Isolate::Current()->heap();
heap_statistics->set_total_heap_size(heap->CommittedMemory());
heap_statistics->set_total_heap_size_executable(
@ -3998,18 +4020,19 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
}
bool v8::V8::IdleNotification() {
bool v8::V8::IdleNotification(int hint) {
// Returning true tells the caller that it need not
// continue to call IdleNotification.
if (!i::Isolate::Current()->IsInitialized()) return true;
return i::V8::IdleNotification();
i::Isolate* isolate = i::Isolate::Current();
if (isolate == NULL || !isolate->IsInitialized()) return true;
return i::V8::IdleNotification(hint);
}
void v8::V8::LowMemoryNotification() {
i::Isolate* isolate = i::Isolate::Current();
if (!isolate->IsInitialized()) return;
isolate->heap()->CollectAllGarbage(true);
if (isolate == NULL || !isolate->IsInitialized()) return;
isolate->heap()->CollectAllAvailableGarbage();
}
@ -4103,8 +4126,9 @@ Persistent<Context> v8::Context::New(
}
// Leave V8.
if (env.is_null())
if (env.is_null()) {
return Persistent<Context>();
}
return Persistent<Context>(Utils::ToLocal(env));
}
@ -4292,7 +4316,7 @@ static Local<External> ExternalNewImpl(void* data) {
}
static void* ExternalValueImpl(i::Handle<i::Object> obj) {
return reinterpret_cast<void*>(i::Foreign::cast(*obj)->address());
return reinterpret_cast<void*>(i::Foreign::cast(*obj)->foreign_address());
}
@ -4318,7 +4342,7 @@ void* v8::Object::SlowGetPointerFromInternalField(int index) {
if (value->IsSmi()) {
return i::Internals::GetExternalPointerFromSmi(value);
} else if (value->IsForeign()) {
return reinterpret_cast<void*>(i::Foreign::cast(value)->address());
return reinterpret_cast<void*>(i::Foreign::cast(value)->foreign_address());
} else {
return NULL;
}
@ -4528,15 +4552,13 @@ bool v8::String::MakeExternal(
bool v8::String::CanMakeExternal() {
if (!internal::FLAG_clever_optimizations) return false;
i::Handle<i::String> obj = Utils::OpenHandle(this);
i::Isolate* isolate = obj->GetIsolate();
if (IsDeadCheck(isolate, "v8::String::CanMakeExternal()")) return false;
if (isolate->string_tracker()->IsFreshUnusedString(obj)) {
return false;
}
if (isolate->string_tracker()->IsFreshUnusedString(obj)) return false;
int size = obj->Size(); // Byte size of the original string.
if (size < i::ExternalString::kSize)
return false;
if (size < i::ExternalString::kShortSize) return false;
i::StringShape shape(*obj);
return !shape.IsExternal();
}
@ -4870,7 +4892,7 @@ void V8::RemoveMessageListeners(MessageCallback that) {
NeanderObject listener(i::JSObject::cast(listeners.get(i)));
i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listener.get(0)));
if (callback_obj->address() == FUNCTION_ADDR(that)) {
if (callback_obj->foreign_address() == FUNCTION_ADDR(that)) {
listeners.set(i, isolate->heap()->undefined_value());
}
}
@ -5480,6 +5502,12 @@ bool Debug::EnableAgent(const char* name, int port, bool wait_for_connection) {
wait_for_connection);
}
void Debug::DisableAgent() {
return i::Isolate::Current()->debugger()->StopAgent();
}
void Debug::ProcessDebugMessages() {
i::Execution::ProcessDebugMesssages(true);
}

18
deps/v8/src/api.h

@ -112,15 +112,16 @@ void NeanderObject::set(int offset, v8::internal::Object* value) {
}
template <typename T> static inline T ToCData(v8::internal::Object* obj) {
template <typename T> inline T ToCData(v8::internal::Object* obj) {
STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address));
return reinterpret_cast<T>(
reinterpret_cast<intptr_t>(v8::internal::Foreign::cast(obj)->address()));
reinterpret_cast<intptr_t>(
v8::internal::Foreign::cast(obj)->foreign_address()));
}
template <typename T>
static inline v8::internal::Handle<v8::internal::Object> FromCData(T obj) {
inline v8::internal::Handle<v8::internal::Object> FromCData(T obj) {
STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address));
return FACTORY->NewForeign(
reinterpret_cast<v8::internal::Address>(reinterpret_cast<intptr_t>(obj)));
@ -136,10 +137,6 @@ class ApiFunction {
};
enum ExtensionTraversalState {
UNVISITED, VISITED, INSTALLED
};
class RegisteredExtension {
public:
@ -148,14 +145,11 @@ class RegisteredExtension {
Extension* extension() { return extension_; }
RegisteredExtension* next() { return next_; }
RegisteredExtension* next_auto() { return next_auto_; }
ExtensionTraversalState state() { return state_; }
void set_state(ExtensionTraversalState value) { state_ = value; }
static RegisteredExtension* first_extension() { return first_extension_; }
private:
Extension* extension_;
RegisteredExtension* next_;
RegisteredExtension* next_auto_;
ExtensionTraversalState state_;
static RegisteredExtension* first_extension_;
};
@ -242,7 +236,7 @@ class Utils {
template <class T>
static inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) {
inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) {
return reinterpret_cast<T*>(obj.location());
}
@ -483,7 +477,7 @@ class HandleScopeImplementer {
};
static const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page
const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page
void HandleScopeImplementer::SaveContext(Context* context) {

41
deps/v8/src/arm/assembler-arm-inl.h

@ -64,7 +64,9 @@ Address RelocInfo::target_address() {
Address RelocInfo::target_address_address() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY
|| rmode_ == EMBEDDED_OBJECT
|| rmode_ == EXTERNAL_REFERENCE);
return reinterpret_cast<Address>(Assembler::target_address_address_at(pc_));
}
@ -74,9 +76,14 @@ int RelocInfo::target_address_size() {
}
void RelocInfo::set_target_address(Address target) {
void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
Assembler::set_target_address_at(pc_, target);
if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) {
Object* target_code = Code::GetCodeFromTargetAddress(target);
host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
host(), this, HeapObject::cast(target_code));
}
}
@ -98,9 +105,15 @@ Object** RelocInfo::target_object_address() {
}
void RelocInfo::set_target_object(Object* target) {
void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target));
if (mode == UPDATE_WRITE_BARRIER &&
host() != NULL &&
target->IsHeapObject()) {
host()->GetHeap()->incremental_marking()->RecordWrite(
host(), &Memory::Object_at(pc_), HeapObject::cast(target));
}
}
@ -127,10 +140,17 @@ JSGlobalPropertyCell* RelocInfo::target_cell() {
}
void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell) {
void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell,
WriteBarrierMode mode) {
ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
Address address = cell->address() + JSGlobalPropertyCell::kValueOffset;
Memory::Address_at(pc_) = address;
if (mode == UPDATE_WRITE_BARRIER && host() != NULL) {
// TODO(1550) We are passing NULL as a slot because cell can never be on
// evacuation candidate.
host()->GetHeap()->incremental_marking()->RecordWrite(
host(), NULL, cell);
}
}
@ -147,6 +167,11 @@ void RelocInfo::set_call_address(Address target) {
ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target;
if (host() != NULL) {
Object* target_code = Code::GetCodeFromTargetAddress(target);
host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
host(), this, HeapObject::cast(target_code));
}
}
@ -195,13 +220,13 @@ bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
void RelocInfo::Visit(ObjectVisitor* visitor) {
RelocInfo::Mode mode = rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
visitor->VisitPointer(target_object_address());
visitor->VisitEmbeddedPointer(this);
} else if (RelocInfo::IsCodeTarget(mode)) {
visitor->VisitCodeTarget(this);
} else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
visitor->VisitGlobalPropertyCell(this);
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
visitor->VisitExternalReference(target_reference_address());
visitor->VisitExternalReference(this);
#ifdef ENABLE_DEBUGGER_SUPPORT
// TODO(isolates): Get a cached isolate below.
} else if (((RelocInfo::IsJSReturn(mode) &&
@ -221,13 +246,13 @@ template<typename StaticVisitor>
void RelocInfo::Visit(Heap* heap) {
RelocInfo::Mode mode = rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
StaticVisitor::VisitPointer(heap, target_object_address());
StaticVisitor::VisitEmbeddedPointer(heap, this);
} else if (RelocInfo::IsCodeTarget(mode)) {
StaticVisitor::VisitCodeTarget(heap, this);
} else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
StaticVisitor::VisitGlobalPropertyCell(heap, this);
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
StaticVisitor::VisitExternalReference(target_reference_address());
StaticVisitor::VisitExternalReference(this);
#ifdef ENABLE_DEBUGGER_SUPPORT
} else if (heap->isolate()->debug()->has_break_points() &&
((RelocInfo::IsJSReturn(mode) &&

12
deps/v8/src/arm/assembler-arm.cc

@ -78,7 +78,9 @@ static uint64_t CpuFeaturesImpliedByCompiler() {
void CpuFeatures::Probe() {
ASSERT(!initialized_);
unsigned standard_features = (OS::CpuFeaturesImpliedByPlatform() |
CpuFeaturesImpliedByCompiler());
ASSERT(supported_ == 0 || supported_ == standard_features);
#ifdef DEBUG
initialized_ = true;
#endif
@ -86,8 +88,7 @@ void CpuFeatures::Probe() {
// Get the features implied by the OS and the compiler settings. This is the
// minimal set of features which is also alowed for generated code in the
// snapshot.
supported_ |= OS::CpuFeaturesImpliedByPlatform();
supported_ |= CpuFeaturesImpliedByCompiler();
supported_ |= standard_features;
if (Serializer::enabled()) {
// No probing for features if we might serialize (generate snapshot).
@ -2505,7 +2506,8 @@ void Assembler::dd(uint32_t data) {
void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants
// We do not try to reuse pool constants.
RelocInfo rinfo(pc_, rmode, data, NULL);
if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
// Adjust code for new modes.
ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
@ -2537,7 +2539,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
}
ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId());
RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId(), NULL);
ClearRecordedAstId();
reloc_info_writer.Write(&reloc_info_with_ast_id);
} else {

16
deps/v8/src/arm/assembler-arm.h

@ -304,9 +304,9 @@ const DwVfpRegister d14 = { 14 };
const DwVfpRegister d15 = { 15 };
// Aliases for double registers.
const DwVfpRegister kFirstCalleeSavedDoubleReg = d8;
const DwVfpRegister kLastCalleeSavedDoubleReg = d15;
const DwVfpRegister kDoubleRegZero = d14;
static const DwVfpRegister& kFirstCalleeSavedDoubleReg = d8;
static const DwVfpRegister& kLastCalleeSavedDoubleReg = d15;
static const DwVfpRegister& kDoubleRegZero = d14;
// Coprocessor register
@ -1209,6 +1209,10 @@ class Assembler : public AssemblerBase {
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
// Read/patch instructions
Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
void instr_at_put(int pos, Instr instr) {
*reinterpret_cast<Instr*>(buffer_ + pos) = instr;
}
static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
static void instr_at_put(byte* pc, Instr instr) {
*reinterpret_cast<Instr*>(pc) = instr;
@ -1263,12 +1267,6 @@ class Assembler : public AssemblerBase {
int buffer_space() const { return reloc_info_writer.pos() - pc_; }
// Read/patch instructions
Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
void instr_at_put(int pos, Instr instr) {
*reinterpret_cast<Instr*>(buffer_ + pos) = instr;
}
// Decode branch instruction at pos and return branch target pos
int target_at(int pos);

1206
deps/v8/src/arm/builtins-arm.cc

File diff suppressed because it is too large

1148
deps/v8/src/arm/code-stubs-arm.cc

File diff suppressed because it is too large

321
deps/v8/src/arm/code-stubs-arm.h

@ -58,6 +58,25 @@ class TranscendentalCacheStub: public CodeStub {
};
class StoreBufferOverflowStub: public CodeStub {
public:
explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
: save_doubles_(save_fp) { }
void Generate(MacroAssembler* masm);
virtual bool IsPregenerated();
static void GenerateFixedRegStubsAheadOfTime();
virtual bool SometimesSetsUpAFrame() { return false; }
private:
SaveFPRegsMode save_doubles_;
Major MajorKey() { return StoreBufferOverflow; }
int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
};
class UnaryOpStub: public CodeStub {
public:
UnaryOpStub(Token::Value op,
@ -117,7 +136,7 @@ class UnaryOpStub: public CodeStub {
return UnaryOpIC::ToState(operand_type_);
}
virtual void FinishCode(Code* code) {
virtual void FinishCode(Handle<Code> code) {
code->set_unary_op_type(operand_type_);
}
};
@ -216,7 +235,7 @@ class BinaryOpStub: public CodeStub {
return BinaryOpIC::ToState(operands_type_);
}
virtual void FinishCode(Code* code) {
virtual void FinishCode(Handle<Code> code) {
code->set_binary_op_type(operands_type_);
code->set_binary_op_result_type(result_type_);
}
@ -225,6 +244,70 @@ class BinaryOpStub: public CodeStub {
};
class StringHelper : public AllStatic {
public:
// Generate code for copying characters using a simple loop. This should only
// be used in places where the number of characters is small and the
// additional setup and checking in GenerateCopyCharactersLong adds too much
// overhead. Copying of overlapping regions is not supported.
// Dest register ends at the position after the last character written.
static void GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
Register count,
Register scratch,
bool ascii);
// Generate code for copying a large number of characters. This function
// is allowed to spend extra time setting up conditions to make copying
// faster. Copying of overlapping regions is not supported.
// Dest register ends at the position after the last character written.
static void GenerateCopyCharactersLong(MacroAssembler* masm,
Register dest,
Register src,
Register count,
Register scratch1,
Register scratch2,
Register scratch3,
Register scratch4,
Register scratch5,
int flags);
// Probe the symbol table for a two character string. If the string is
// not found by probing a jump to the label not_found is performed. This jump
// does not guarantee that the string is not in the symbol table. If the
// string is found the code falls through with the string in register r0.
// Contents of both c1 and c2 registers are modified. At the exit c1 is
// guaranteed to contain halfword with low and high bytes equal to
// initial contents of c1 and c2 respectively.
static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
Register scratch2,
Register scratch3,
Register scratch4,
Register scratch5,
Label* not_found);
// Generate string hash.
static void GenerateHashInit(MacroAssembler* masm,
Register hash,
Register character);
static void GenerateHashAddCharacter(MacroAssembler* masm,
Register hash,
Register character);
static void GenerateHashGetHash(MacroAssembler* masm,
Register hash);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
};
// Flag that indicates how to generate code for the stub StringAddStub.
enum StringAddFlags {
NO_STRING_ADD_FLAGS = 0,
@ -323,6 +406,9 @@ class WriteInt32ToHeapNumberStub : public CodeStub {
the_heap_number_(the_heap_number),
scratch_(scratch) { }
bool IsPregenerated();
static void GenerateFixedRegStubsAheadOfTime();
private:
Register the_int_;
Register the_heap_number_;
@ -371,6 +457,218 @@ class NumberToStringStub: public CodeStub {
};
class RecordWriteStub: public CodeStub {
public:
RecordWriteStub(Register object,
Register value,
Register address,
RememberedSetAction remembered_set_action,
SaveFPRegsMode fp_mode)
: object_(object),
value_(value),
address_(address),
remembered_set_action_(remembered_set_action),
save_fp_regs_mode_(fp_mode),
regs_(object, // An input reg.
address, // An input reg.
value) { // One scratch reg.
}
enum Mode {
STORE_BUFFER_ONLY,
INCREMENTAL,
INCREMENTAL_COMPACTION
};
virtual bool IsPregenerated();
static void GenerateFixedRegStubsAheadOfTime();
virtual bool SometimesSetsUpAFrame() { return false; }
static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20));
ASSERT(Assembler::IsTstImmediate(masm->instr_at(pos)));
}
static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27);
ASSERT(Assembler::IsBranch(masm->instr_at(pos)));
}
static Mode GetMode(Code* stub) {
Instr first_instruction = Assembler::instr_at(stub->instruction_start());
Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
Assembler::kInstrSize);
if (Assembler::IsBranch(first_instruction)) {
return INCREMENTAL;
}
ASSERT(Assembler::IsTstImmediate(first_instruction));
if (Assembler::IsBranch(second_instruction)) {
return INCREMENTAL_COMPACTION;
}
ASSERT(Assembler::IsTstImmediate(second_instruction));
return STORE_BUFFER_ONLY;
}
static void Patch(Code* stub, Mode mode) {
MacroAssembler masm(NULL,
stub->instruction_start(),
stub->instruction_size());
switch (mode) {
case STORE_BUFFER_ONLY:
ASSERT(GetMode(stub) == INCREMENTAL ||
GetMode(stub) == INCREMENTAL_COMPACTION);
PatchBranchIntoNop(&masm, 0);
PatchBranchIntoNop(&masm, Assembler::kInstrSize);
break;
case INCREMENTAL:
ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
PatchNopIntoBranch(&masm, 0);
break;
case INCREMENTAL_COMPACTION:
ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
PatchNopIntoBranch(&masm, Assembler::kInstrSize);
break;
}
ASSERT(GetMode(stub) == mode);
CPU::FlushICache(stub->instruction_start(), 2 * Assembler::kInstrSize);
}
private:
// This is a helper class for freeing up 3 scratch registers. The input is
// two registers that must be preserved and one scratch register provided by
// the caller.
class RegisterAllocation {
public:
RegisterAllocation(Register object,
Register address,
Register scratch0)
: object_(object),
address_(address),
scratch0_(scratch0) {
ASSERT(!AreAliased(scratch0, object, address, no_reg));
scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_);
}
void Save(MacroAssembler* masm) {
ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
// We don't have to save scratch0_ because it was given to us as
// a scratch register.
masm->push(scratch1_);
}
void Restore(MacroAssembler* masm) {
masm->pop(scratch1_);
}
// If we have to call into C then we need to save and restore all caller-
// saved registers that were not already preserved. The scratch registers
// will be restored by other means so we don't bother pushing them here.
void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
if (mode == kSaveFPRegs) {
CpuFeatures::Scope scope(VFP3);
masm->sub(sp,
sp,
Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
// Save all VFP registers except d0.
for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
DwVfpRegister reg = DwVfpRegister::from_code(i);
masm->vstr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
}
}
}
inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
SaveFPRegsMode mode) {
if (mode == kSaveFPRegs) {
CpuFeatures::Scope scope(VFP3);
// Restore all VFP registers except d0.
for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
DwVfpRegister reg = DwVfpRegister::from_code(i);
masm->vldr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
}
masm->add(sp,
sp,
Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
}
masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
}
inline Register object() { return object_; }
inline Register address() { return address_; }
inline Register scratch0() { return scratch0_; }
inline Register scratch1() { return scratch1_; }
private:
Register object_;
Register address_;
Register scratch0_;
Register scratch1_;
Register GetRegThatIsNotOneOf(Register r1,
Register r2,
Register r3) {
for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
Register candidate = Register::FromAllocationIndex(i);
if (candidate.is(r1)) continue;
if (candidate.is(r2)) continue;
if (candidate.is(r3)) continue;
return candidate;
}
UNREACHABLE();
return no_reg;
}
friend class RecordWriteStub;
};
enum OnNoNeedToInformIncrementalMarker {
kReturnOnNoNeedToInformIncrementalMarker,
kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
};
void Generate(MacroAssembler* masm);
void GenerateIncremental(MacroAssembler* masm, Mode mode);
void CheckNeedsToInformIncrementalMarker(
MacroAssembler* masm,
OnNoNeedToInformIncrementalMarker on_no_need,
Mode mode);
void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
Major MajorKey() { return RecordWrite; }
int MinorKey() {
return ObjectBits::encode(object_.code()) |
ValueBits::encode(value_.code()) |
AddressBits::encode(address_.code()) |
RememberedSetActionBits::encode(remembered_set_action_) |
SaveFPRegsModeBits::encode(save_fp_regs_mode_);
}
void Activate(Code* code) {
code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
}
class ObjectBits: public BitField<int, 0, 4> {};
class ValueBits: public BitField<int, 4, 4> {};
class AddressBits: public BitField<int, 8, 4> {};
class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
Register object_;
Register value_;
Register address_;
RememberedSetAction remembered_set_action_;
SaveFPRegsMode save_fp_regs_mode_;
Label slow_;
RegisterAllocation regs_;
};
// Enter C code from generated RegExp code in a way that allows
// the C code to fix the return address in case of a GC.
// Currently only needed on ARM.
@ -558,14 +856,13 @@ class StringDictionaryLookupStub: public CodeStub {
void Generate(MacroAssembler* masm);
MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
Register receiver,
Register properties,
String* name,
Register scratch0);
static void GenerateNegativeLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register receiver,
Register properties,
Handle<String> name,
Register scratch0);
static void GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
@ -575,6 +872,8 @@ class StringDictionaryLookupStub: public CodeStub {
Register r0,
Register r1);
virtual bool SometimesSetsUpAFrame() { return false; }
private:
static const int kInlinedProbes = 4;
static const int kTotalProbes = 20;
@ -587,7 +886,7 @@ class StringDictionaryLookupStub: public CodeStub {
StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
Major MajorKey() { return StringDictionaryNegativeLookup; }
Major MajorKey() { return StringDictionaryLookup; }
int MinorKey() {
return LookupModeBits::encode(mode_);

349
deps/v8/src/arm/codegen-arm.cc

@ -30,22 +30,367 @@
#if defined(V8_TARGET_ARCH_ARM)
#include "codegen.h"
#include "macro-assembler.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm)
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
masm->EnterInternalFrame();
masm->EnterFrame(StackFrame::INTERNAL);
ASSERT(!masm->has_frame());
masm->set_has_frame(true);
}
void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
masm->LeaveInternalFrame();
masm->LeaveFrame(StackFrame::INTERNAL);
ASSERT(masm->has_frame());
masm->set_has_frame(false);
}
// -------------------------------------------------------------------------
// Code generators
void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -- r3 : target map, scratch for subsequent call
// -- r4 : scratch (elements)
// -----------------------------------
// Set transitioned map.
__ str(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
__ RecordWriteField(r2,
HeapObject::kMapOffset,
r3,
r9,
kLRHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
}
void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
MacroAssembler* masm, Label* fail) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -- r3 : target map, scratch for subsequent call
// -- r4 : scratch (elements)
// -----------------------------------
Label loop, entry, convert_hole, gc_required;
bool vfp3_supported = CpuFeatures::IsSupported(VFP3);
__ push(lr);
__ ldr(r4, FieldMemOperand(r2, JSObject::kElementsOffset));
__ ldr(r5, FieldMemOperand(r4, FixedArray::kLengthOffset));
// r4: source FixedArray
// r5: number of elements (smi-tagged)
// Allocate new FixedDoubleArray.
__ mov(lr, Operand(FixedDoubleArray::kHeaderSize));
__ add(lr, lr, Operand(r5, LSL, 2));
__ AllocateInNewSpace(lr, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS);
// r6: destination FixedDoubleArray, not tagged as heap object
__ LoadRoot(r9, Heap::kFixedDoubleArrayMapRootIndex);
__ str(r9, MemOperand(r6, HeapObject::kMapOffset));
// Set destination FixedDoubleArray's length.
__ str(r5, MemOperand(r6, FixedDoubleArray::kLengthOffset));
// Update receiver's map.
__ str(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
__ RecordWriteField(r2,
HeapObject::kMapOffset,
r3,
r9,
kLRHasBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
// Replace receiver's backing store with newly created FixedDoubleArray.
__ add(r3, r6, Operand(kHeapObjectTag));
__ str(r3, FieldMemOperand(r2, JSObject::kElementsOffset));
__ RecordWriteField(r2,
JSObject::kElementsOffset,
r3,
r9,
kLRHasBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
// Prepare for conversion loop.
__ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ add(r7, r6, Operand(FixedDoubleArray::kHeaderSize));
__ add(r6, r7, Operand(r5, LSL, 2));
__ mov(r4, Operand(kHoleNanLower32));
__ mov(r5, Operand(kHoleNanUpper32));
// r3: begin of source FixedArray element fields, not tagged
// r4: kHoleNanLower32
// r5: kHoleNanUpper32
// r6: end of destination FixedDoubleArray, not tagged
// r7: begin of FixedDoubleArray element fields, not tagged
if (!vfp3_supported) __ Push(r1, r0);
__ b(&entry);
// Call into runtime if GC is required.
__ bind(&gc_required);
__ pop(lr);
__ b(fail);
// Convert and copy elements.
__ bind(&loop);
__ ldr(r9, MemOperand(r3, 4, PostIndex));
// r9: current element
__ JumpIfNotSmi(r9, &convert_hole);
// Normal smi, convert to double and store.
__ SmiUntag(r9);
if (vfp3_supported) {
CpuFeatures::Scope scope(VFP3);
__ vmov(s0, r9);
__ vcvt_f64_s32(d0, s0);
__ vstr(d0, r7, 0);
__ add(r7, r7, Operand(8));
} else {
FloatingPointHelper::ConvertIntToDouble(masm,
r9,
FloatingPointHelper::kCoreRegisters,
d0,
r0,
r1,
lr,
s0);
__ Strd(r0, r1, MemOperand(r7, 8, PostIndex));
}
__ b(&entry);
// Hole found, store the-hole NaN.
__ bind(&convert_hole);
if (FLAG_debug_code) {
__ CompareRoot(r9, Heap::kTheHoleValueRootIndex);
__ Assert(eq, "object found in smi-only array");
}
__ Strd(r4, r5, MemOperand(r7, 8, PostIndex));
__ bind(&entry);
__ cmp(r7, r6);
__ b(lt, &loop);
if (!vfp3_supported) __ Pop(r1, r0);
__ pop(lr);
}
void ElementsTransitionGenerator::GenerateDoubleToObject(
MacroAssembler* masm, Label* fail) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -- r3 : target map, scratch for subsequent call
// -- r4 : scratch (elements)
// -----------------------------------
Label entry, loop, convert_hole, gc_required;
__ push(lr);
__ Push(r3, r2, r1, r0);
__ ldr(r4, FieldMemOperand(r2, JSObject::kElementsOffset));
__ ldr(r5, FieldMemOperand(r4, FixedArray::kLengthOffset));
// r4: source FixedDoubleArray
// r5: number of elements (smi-tagged)
// Allocate new FixedArray.
__ mov(r0, Operand(FixedDoubleArray::kHeaderSize));
__ add(r0, r0, Operand(r5, LSL, 1));
__ AllocateInNewSpace(r0, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS);
// r6: destination FixedArray, not tagged as heap object
__ LoadRoot(r9, Heap::kFixedArrayMapRootIndex);
__ str(r9, MemOperand(r6, HeapObject::kMapOffset));
// Set destination FixedDoubleArray's length.
__ str(r5, MemOperand(r6, FixedDoubleArray::kLengthOffset));
// Prepare for conversion loop.
__ add(r4, r4, Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag + 4));
__ add(r3, r6, Operand(FixedArray::kHeaderSize));
__ add(r6, r6, Operand(kHeapObjectTag));
__ add(r5, r3, Operand(r5, LSL, 1));
__ LoadRoot(r7, Heap::kTheHoleValueRootIndex);
__ LoadRoot(r9, Heap::kHeapNumberMapRootIndex);
// Using offsetted addresses in r4 to fully take advantage of post-indexing.
// r3: begin of destination FixedArray element fields, not tagged
// r4: begin of source FixedDoubleArray element fields, not tagged, +4
// r5: end of destination FixedArray, not tagged
// r6: destination FixedArray
// r7: the-hole pointer
// r9: heap number map
__ b(&entry);
// Call into runtime if GC is required.
__ bind(&gc_required);
__ Pop(r3, r2, r1, r0);
__ pop(lr);
__ b(fail);
__ bind(&loop);
__ ldr(r1, MemOperand(r4, 8, PostIndex));
// lr: current element's upper 32 bit
// r4: address of next element's upper 32 bit
__ cmp(r1, Operand(kHoleNanUpper32));
__ b(eq, &convert_hole);
// Non-hole double, copy value into a heap number.
__ AllocateHeapNumber(r2, r0, lr, r9, &gc_required);
// r2: new heap number
__ ldr(r0, MemOperand(r4, 12, NegOffset));
__ Strd(r0, r1, FieldMemOperand(r2, HeapNumber::kValueOffset));
__ mov(r0, r3);
__ str(r2, MemOperand(r3, 4, PostIndex));
__ RecordWrite(r6,
r0,
r2,
kLRHasBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ b(&entry);
// Replace the-hole NaN with the-hole pointer.
__ bind(&convert_hole);
__ str(r7, MemOperand(r3, 4, PostIndex));
__ bind(&entry);
__ cmp(r3, r5);
__ b(lt, &loop);
__ Pop(r3, r2, r1, r0);
// Update receiver's map.
__ str(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
__ RecordWriteField(r2,
HeapObject::kMapOffset,
r3,
r9,
kLRHasBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
// Replace receiver's backing store with newly created and filled FixedArray.
__ str(r6, FieldMemOperand(r2, JSObject::kElementsOffset));
__ RecordWriteField(r2,
JSObject::kElementsOffset,
r6,
r9,
kLRHasBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ pop(lr);
}
void StringCharLoadGenerator::Generate(MacroAssembler* masm,
Register string,
Register index,
Register result,
Label* call_runtime) {
// Fetch the instance type of the receiver into result register.
__ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
__ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
// We need special handling for indirect strings.
Label check_sequential;
__ tst(result, Operand(kIsIndirectStringMask));
__ b(eq, &check_sequential);
// Dispatch on the indirect string shape: slice or cons.
Label cons_string;
__ tst(result, Operand(kSlicedNotConsMask));
__ b(eq, &cons_string);
// Handle slices.
Label indirect_string_loaded;
__ ldr(result, FieldMemOperand(string, SlicedString::kOffsetOffset));
__ add(index, index, Operand(result, ASR, kSmiTagSize));
__ ldr(string, FieldMemOperand(string, SlicedString::kParentOffset));
__ jmp(&indirect_string_loaded);
// Handle cons strings.
// Check whether the right hand side is the empty string (i.e. if
// this is really a flat string in a cons string). If that is not
// the case we would rather go to the runtime system now to flatten
// the string.
__ bind(&cons_string);
__ ldr(result, FieldMemOperand(string, ConsString::kSecondOffset));
__ LoadRoot(ip, Heap::kEmptyStringRootIndex);
__ cmp(result, ip);
__ b(ne, call_runtime);
// Get the first of the two strings and load its instance type.
__ ldr(string, FieldMemOperand(string, ConsString::kFirstOffset));
__ bind(&indirect_string_loaded);
__ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
__ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
// Distinguish sequential and external strings. Only these two string
// representations can reach here (slices and flat cons strings have been
// reduced to the underlying sequential or external string).
Label external_string, check_encoding;
__ bind(&check_sequential);
STATIC_ASSERT(kSeqStringTag == 0);
__ tst(result, Operand(kStringRepresentationMask));
__ b(ne, &external_string);
// Prepare sequential strings
STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
__ add(string,
string,
Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
__ jmp(&check_encoding);
// Handle external strings.
__ bind(&external_string);
if (FLAG_debug_code) {
// Assert that we do not have a cons or slice (indirect strings) here.
// Sequential strings have already been ruled out.
__ tst(result, Operand(kIsIndirectStringMask));
__ Assert(eq, "external string expected, but not found");
}
// Rule out short external strings.
STATIC_CHECK(kShortExternalStringTag != 0);
__ tst(result, Operand(kShortExternalStringMask));
__ b(ne, call_runtime);
__ ldr(string, FieldMemOperand(string, ExternalString::kResourceDataOffset));
Label ascii, done;
__ bind(&check_encoding);
STATIC_ASSERT(kTwoByteStringTag == 0);
__ tst(result, Operand(kStringEncodingMask));
__ b(ne, &ascii);
// Two-byte string.
__ ldrh(result, MemOperand(string, index, LSL, 1));
__ jmp(&done);
__ bind(&ascii);
// Ascii string.
__ ldrb(result, MemOperand(string, index));
__ bind(&done);
}
#undef __
} } // namespace v8::internal

26
deps/v8/src/arm/codegen-arm.h

@ -29,7 +29,6 @@
#define V8_ARM_CODEGEN_ARM_H_
#include "ast.h"
#include "code-stubs-arm.h"
#include "ic-inl.h"
namespace v8 {
@ -69,21 +68,26 @@ class CodeGenerator: public AstVisitor {
int pos,
bool right_here = false);
// Constants related to patching of inlined load/store.
static int GetInlinedKeyedLoadInstructionsAfterPatch() {
return FLAG_debug_code ? 32 : 13;
}
static const int kInlinedKeyedStoreInstructionsAfterPatch = 8;
static int GetInlinedNamedStoreInstructionsAfterPatch() {
ASSERT(Isolate::Current()->inlined_write_barrier_size() != -1);
return Isolate::Current()->inlined_write_barrier_size() + 4;
}
private:
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
class StringCharLoadGenerator : public AllStatic {
public:
// Generates the code for handling different string types and loading the
// indexed character into |result|. We expect |index| as untagged input and
// |result| as untagged output.
static void Generate(MacroAssembler* masm,
Register string,
Register index,
Register result,
Label* call_runtime);
private:
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
};
} } // namespace v8::internal
#endif // V8_ARM_CODEGEN_ARM_H_

47
deps/v8/src/arm/constants-arm.h

@ -87,22 +87,21 @@ namespace v8 {
namespace internal {
// Constant pool marker.
static const int kConstantPoolMarkerMask = 0xffe00000;
static const int kConstantPoolMarker = 0x0c000000;
static const int kConstantPoolLengthMask = 0x001ffff;
const int kConstantPoolMarkerMask = 0xffe00000;
const int kConstantPoolMarker = 0x0c000000;
const int kConstantPoolLengthMask = 0x001ffff;
// Number of registers in normal ARM mode.
static const int kNumRegisters = 16;
const int kNumRegisters = 16;
// VFP support.
static const int kNumVFPSingleRegisters = 32;
static const int kNumVFPDoubleRegisters = 16;
static const int kNumVFPRegisters =
kNumVFPSingleRegisters + kNumVFPDoubleRegisters;
const int kNumVFPSingleRegisters = 32;
const int kNumVFPDoubleRegisters = 16;
const int kNumVFPRegisters = kNumVFPSingleRegisters + kNumVFPDoubleRegisters;
// PC is register 15.
static const int kPCRegister = 15;
static const int kNoRegister = -1;
const int kPCRegister = 15;
const int kNoRegister = -1;
// -----------------------------------------------------------------------------
// Conditions.
@ -371,9 +370,9 @@ enum SoftwareInterruptCodes {
// stop
kStopCode = 1 << 23
};
static const uint32_t kStopCodeMask = kStopCode - 1;
static const uint32_t kMaxStopCode = kStopCode - 1;
static const int32_t kDefaultStopCode = -1;
const uint32_t kStopCodeMask = kStopCode - 1;
const uint32_t kMaxStopCode = kStopCode - 1;
const int32_t kDefaultStopCode = -1;
// Type of VFP register. Determines register encoding.
@ -391,17 +390,17 @@ enum VFPConversionMode {
// This mask does not include the "inexact" or "input denormal" cumulative
// exceptions flags, because we usually don't want to check for it.
static const uint32_t kVFPExceptionMask = 0xf;
static const uint32_t kVFPInvalidOpExceptionBit = 1 << 0;
static const uint32_t kVFPOverflowExceptionBit = 1 << 2;
static const uint32_t kVFPUnderflowExceptionBit = 1 << 3;
static const uint32_t kVFPInexactExceptionBit = 1 << 4;
static const uint32_t kVFPFlushToZeroMask = 1 << 24;
const uint32_t kVFPExceptionMask = 0xf;
const uint32_t kVFPInvalidOpExceptionBit = 1 << 0;
const uint32_t kVFPOverflowExceptionBit = 1 << 2;
const uint32_t kVFPUnderflowExceptionBit = 1 << 3;
const uint32_t kVFPInexactExceptionBit = 1 << 4;
const uint32_t kVFPFlushToZeroMask = 1 << 24;
static const uint32_t kVFPNConditionFlagBit = 1 << 31;
static const uint32_t kVFPZConditionFlagBit = 1 << 30;
static const uint32_t kVFPCConditionFlagBit = 1 << 29;
static const uint32_t kVFPVConditionFlagBit = 1 << 28;
const uint32_t kVFPNConditionFlagBit = 1 << 31;
const uint32_t kVFPZConditionFlagBit = 1 << 30;
const uint32_t kVFPCConditionFlagBit = 1 << 29;
const uint32_t kVFPVConditionFlagBit = 1 << 28;
// VFP rounding modes. See ARM DDI 0406B Page A2-29.
@ -418,7 +417,7 @@ enum VFPRoundingMode {
kRoundToZero = RZ
};
static const uint32_t kVFPRoundingModeMask = 3 << 22;
const uint32_t kVFPRoundingModeMask = 3 << 22;
enum CheckForInexactConversion {
kCheckForInexactConversion,

88
deps/v8/src/arm/debug-arm.cc

@ -132,55 +132,57 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() {
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList object_regs,
RegList non_object_regs) {
__ EnterInternalFrame();
// Store the registers containing live values on the expression stack to
// make sure that these are correctly updated during GC. Non object values
// are stored as a smi causing it to be untouched by GC.
ASSERT((object_regs & ~kJSCallerSaved) == 0);
ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
ASSERT((object_regs & non_object_regs) == 0);
if ((object_regs | non_object_regs) != 0) {
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = { r };
if ((non_object_regs & (1 << r)) != 0) {
if (FLAG_debug_code) {
__ tst(reg, Operand(0xc0000000));
__ Assert(eq, "Unable to encode value as smi");
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Store the registers containing live values on the expression stack to
// make sure that these are correctly updated during GC. Non object values
// are stored as a smi causing it to be untouched by GC.
ASSERT((object_regs & ~kJSCallerSaved) == 0);
ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
ASSERT((object_regs & non_object_regs) == 0);
if ((object_regs | non_object_regs) != 0) {
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = { r };
if ((non_object_regs & (1 << r)) != 0) {
if (FLAG_debug_code) {
__ tst(reg, Operand(0xc0000000));
__ Assert(eq, "Unable to encode value as smi");
}
__ mov(reg, Operand(reg, LSL, kSmiTagSize));
}
__ mov(reg, Operand(reg, LSL, kSmiTagSize));
}
__ stm(db_w, sp, object_regs | non_object_regs);
}
__ stm(db_w, sp, object_regs | non_object_regs);
}
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ mov(r0, Operand(0, RelocInfo::NONE)); // no arguments
__ mov(r1, Operand(ExternalReference::debug_break(masm->isolate())));
CEntryStub ceb(1);
__ CallStub(&ceb);
// Restore the register values from the expression stack.
if ((object_regs | non_object_regs) != 0) {
__ ldm(ia_w, sp, object_regs | non_object_regs);
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = { r };
if ((non_object_regs & (1 << r)) != 0) {
__ mov(reg, Operand(reg, LSR, kSmiTagSize));
}
if (FLAG_debug_code &&
(((object_regs |non_object_regs) & (1 << r)) == 0)) {
__ mov(reg, Operand(kDebugZapValue));
__ mov(r0, Operand(0, RelocInfo::NONE)); // no arguments
__ mov(r1, Operand(ExternalReference::debug_break(masm->isolate())));
CEntryStub ceb(1);
__ CallStub(&ceb);
// Restore the register values from the expression stack.
if ((object_regs | non_object_regs) != 0) {
__ ldm(ia_w, sp, object_regs | non_object_regs);
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = { r };
if ((non_object_regs & (1 << r)) != 0) {
__ mov(reg, Operand(reg, LSR, kSmiTagSize));
}
if (FLAG_debug_code &&
(((object_regs |non_object_regs) & (1 << r)) == 0)) {
__ mov(reg, Operand(kDebugZapValue));
}
}
}
}
__ LeaveInternalFrame();
// Leave the internal frame.
}
// Now that the break point has been handled, resume normal execution by
// jumping to the target address intended by the caller and that was
@ -265,11 +267,11 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
}
void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
// ----------- S t a t e -------------
// No registers used on entry.
// -- r1 : function
// -----------------------------------
Generate_DebugBreakCallHelper(masm, 0, 0);
Generate_DebugBreakCallHelper(masm, r1.bit(), 0);
}

116
deps/v8/src/arm/deoptimizer-arm.cc

@ -44,12 +44,6 @@ int Deoptimizer::patch_size() {
}
void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
// Nothing to do. No new relocation information is written for lazy
// deoptimization on ARM.
}
void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
HandleScope scope;
AssertNoAllocation no_allocation;
@ -58,66 +52,51 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
// Get the optimized code.
Code* code = function->code();
Address code_start_address = code->instruction_start();
// Invalidate the relocation information, as it will become invalid by the
// code patching below, and is not needed any more.
code->InvalidateRelocation();
// For each return after a safepoint insert an absolute call to the
// corresponding deoptimization entry.
unsigned last_pc_offset = 0;
SafepointTable table(function->code());
for (unsigned i = 0; i < table.length(); i++) {
unsigned pc_offset = table.GetPcOffset(i);
SafepointEntry safepoint_entry = table.GetEntry(i);
int deoptimization_index = safepoint_entry.deoptimization_index();
int gap_code_size = safepoint_entry.gap_code_size();
// Check that we did not shoot past next safepoint.
CHECK(pc_offset >= last_pc_offset);
// For each LLazyBailout instruction insert a call to the corresponding
// deoptimization entry.
DeoptimizationInputData* deopt_data =
DeoptimizationInputData::cast(code->deoptimization_data());
#ifdef DEBUG
// Destroy the code which is not supposed to be run again.
int instructions = (pc_offset - last_pc_offset) / Assembler::kInstrSize;
CodePatcher destroyer(code->instruction_start() + last_pc_offset,
instructions);
for (int x = 0; x < instructions; x++) {
destroyer.masm()->bkpt(0);
}
Address prev_call_address = NULL;
#endif
last_pc_offset = pc_offset;
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry(
deoptimization_index, Deoptimizer::LAZY);
last_pc_offset += gap_code_size;
int call_size_in_bytes = MacroAssembler::CallSize(deoptimization_entry,
RelocInfo::NONE);
int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
ASSERT(call_size_in_bytes <= patch_size());
CodePatcher patcher(code->instruction_start() + last_pc_offset,
call_size_in_words);
patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE);
last_pc_offset += call_size_in_bytes;
}
}
for (int i = 0; i < deopt_data->DeoptCount(); i++) {
if (deopt_data->Pc(i)->value() == -1) continue;
Address call_address = code_start_address + deopt_data->Pc(i)->value();
Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry,
RelocInfo::NONE);
int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
ASSERT(call_size_in_bytes <= patch_size());
CodePatcher patcher(call_address, call_size_in_words);
patcher.masm()->Call(deopt_entry, RelocInfo::NONE);
ASSERT(prev_call_address == NULL ||
call_address >= prev_call_address + patch_size());
ASSERT(call_address + patch_size() <= code->instruction_end());
#ifdef DEBUG
// Destroy the code which is not supposed to be run again.
int instructions =
(code->safepoint_table_offset() - last_pc_offset) / Assembler::kInstrSize;
CodePatcher destroyer(code->instruction_start() + last_pc_offset,
instructions);
for (int x = 0; x < instructions; x++) {
destroyer.masm()->bkpt(0);
}
prev_call_address = call_address;
#endif
}
Isolate* isolate = code->GetIsolate();
// Add the deoptimizing code to the list.
DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
DeoptimizerData* data = code->GetIsolate()->deoptimizer_data();
DeoptimizerData* data = isolate->deoptimizer_data();
node->set_next(data->deoptimizing_code_list_);
data->deoptimizing_code_list_ = node;
// We might be in the middle of incremental marking with compaction.
// Tell collector to treat this code object in a special way and
// ignore all slots that might have been recorded on it.
isolate->heap()->mark_compact_collector()->InvalidateCode(code);
// Set the code for the function to non-optimized version.
function->ReplaceCode(function->shared()->code());
@ -125,16 +104,12 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
PrintF("[forced deoptimization: ");
function->PrintName();
PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
#ifdef DEBUG
if (FLAG_print_code) {
code->PrintLn();
}
#endif
}
}
void Deoptimizer::PatchStackCheckCodeAt(Address pc_after,
void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
Address pc_after,
Code* check_code,
Code* replacement_code) {
const int kInstrSize = Assembler::kInstrSize;
@ -169,10 +144,14 @@ void Deoptimizer::PatchStackCheckCodeAt(Address pc_after,
reinterpret_cast<uint32_t>(check_code->entry()));
Memory::uint32_at(stack_check_address_pointer) =
reinterpret_cast<uint32_t>(replacement_code->entry());
unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
unoptimized_code, pc_after - 2 * kInstrSize, replacement_code);
}
void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
Address pc_after,
Code* check_code,
Code* replacement_code) {
const int kInstrSize = Assembler::kInstrSize;
@ -193,6 +172,9 @@ void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
reinterpret_cast<uint32_t>(replacement_code->entry()));
Memory::uint32_at(stack_check_address_pointer) =
reinterpret_cast<uint32_t>(check_code->entry());
check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
unoptimized_code, pc_after - 2 * kInstrSize, check_code);
}
@ -632,7 +614,10 @@ void Deoptimizer::EntryGenerator::Generate() {
__ mov(r5, Operand(ExternalReference::isolate_address()));
__ str(r5, MemOperand(sp, 1 * kPointerSize)); // Isolate.
// Call Deoptimizer::New().
__ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 6);
{
AllowExternalCallThatCantCauseGC scope(masm());
__ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 6);
}
// Preserve "deoptimizer" object in register r0 and get the input
// frame descriptor pointer to r1 (deoptimizer->input_);
@ -686,8 +671,11 @@ void Deoptimizer::EntryGenerator::Generate() {
// r0: deoptimizer object; r1: scratch.
__ PrepareCallCFunction(1, r1);
// Call Deoptimizer::ComputeOutputFrames().
__ CallCFunction(
ExternalReference::compute_output_frames_function(isolate), 1);
{
AllowExternalCallThatCantCauseGC scope(masm());
__ CallCFunction(
ExternalReference::compute_output_frames_function(isolate), 1);
}
__ pop(r0); // Restore deoptimizer object (class Deoptimizer).
// Replace the current (input) frame with the output frames.
@ -703,7 +691,6 @@ void Deoptimizer::EntryGenerator::Generate() {
__ ldr(r3, MemOperand(r2, FrameDescription::frame_size_offset()));
__ bind(&inner_push_loop);
__ sub(r3, r3, Operand(sizeof(uint32_t)));
// __ add(r6, r2, Operand(r3, LSL, 1));
__ add(r6, r2, Operand(r3));
__ ldr(r7, MemOperand(r6, FrameDescription::frame_content_offset()));
__ push(r7);
@ -737,8 +724,9 @@ void Deoptimizer::EntryGenerator::Generate() {
__ pop(ip); // remove lr
// Set up the roots register.
ExternalReference roots_address = ExternalReference::roots_address(isolate);
__ mov(r10, Operand(roots_address));
ExternalReference roots_array_start =
ExternalReference::roots_array_start(isolate);
__ mov(r10, Operand(roots_array_start));
__ pop(ip); // remove pc
__ pop(r7); // get continuation, leave pc on stack

43
deps/v8/src/arm/frames-arm.h

@ -35,22 +35,22 @@ namespace internal {
// The ARM ABI does not specify the usage of register r9, which may be reserved
// as the static base or thread register on some platforms, in which case we
// leave it alone. Adjust the value of kR9Available accordingly:
static const int kR9Available = 1; // 1 if available to us, 0 if reserved
const int kR9Available = 1; // 1 if available to us, 0 if reserved
// Register list in load/store instructions
// Note that the bit values must match those used in actual instruction encoding
static const int kNumRegs = 16;
const int kNumRegs = 16;
// Caller-saved/arguments registers
static const RegList kJSCallerSaved =
const RegList kJSCallerSaved =
1 << 0 | // r0 a1
1 << 1 | // r1 a2
1 << 2 | // r2 a3
1 << 3; // r3 a4
static const int kNumJSCallerSaved = 4;
const int kNumJSCallerSaved = 4;
typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
@ -60,7 +60,7 @@ int JSCallerSavedCode(int n);
// Callee-saved registers preserved when switching from C to JavaScript
static const RegList kCalleeSaved =
const RegList kCalleeSaved =
1 << 4 | // r4 v1
1 << 5 | // r5 v2
1 << 6 | // r6 v3
@ -70,36 +70,45 @@ static const RegList kCalleeSaved =
1 << 10 | // r10 v7
1 << 11; // r11 v8 (fp in JavaScript code)
static const int kNumCalleeSaved = 7 + kR9Available;
// When calling into C++ (only for C++ calls that can't cause a GC).
// The call code will take care of lr, fp, etc.
const RegList kCallerSaved =
1 << 0 | // r0
1 << 1 | // r1
1 << 2 | // r2
1 << 3 | // r3
1 << 9; // r9
const int kNumCalleeSaved = 7 + kR9Available;
// Double registers d8 to d15 are callee-saved.
static const int kNumDoubleCalleeSaved = 8;
const int kNumDoubleCalleeSaved = 8;
// Number of registers for which space is reserved in safepoints. Must be a
// multiple of 8.
// TODO(regis): Only 8 registers may actually be sufficient. Revisit.
static const int kNumSafepointRegisters = 16;
const int kNumSafepointRegisters = 16;
// Define the list of registers actually saved at safepoints.
// Note that the number of saved registers may be smaller than the reserved
// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
static const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
static const int kNumSafepointSavedRegisters =
kNumJSCallerSaved + kNumCalleeSaved;
const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
// ----------------------------------------------------
class StackHandlerConstants : public AllStatic {
public:
static const int kNextOffset = 0 * kPointerSize;
static const int kStateOffset = 1 * kPointerSize;
static const int kContextOffset = 2 * kPointerSize;
static const int kFPOffset = 3 * kPointerSize;
static const int kPCOffset = 4 * kPointerSize;
static const int kNextOffset = 0 * kPointerSize;
static const int kCodeOffset = 1 * kPointerSize;
static const int kStateOffset = 2 * kPointerSize;
static const int kContextOffset = 3 * kPointerSize;
static const int kFPOffset = 4 * kPointerSize;
static const int kSize = kPCOffset + kPointerSize;
static const int kSize = kFPOffset + kPointerSize;
};

781
deps/v8/src/arm/full-codegen-arm.cc

File diff suppressed because it is too large

259
deps/v8/src/arm/ic-arm.cc

@ -208,7 +208,8 @@ static void GenerateDictionaryStore(MacroAssembler* masm,
// Update the write barrier. Make sure not to clobber the value.
__ mov(scratch1, value);
__ RecordWrite(elements, scratch2, scratch1);
__ RecordWrite(
elements, scratch2, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs);
}
@ -381,10 +382,10 @@ Object* CallIC_Miss(Arguments args);
// The generated code does not accept smi keys.
// The generated code falls through if both probes miss.
static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
int argc,
Code::Kind kind,
Code::ExtraICState extra_ic_state) {
void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
int argc,
Code::Kind kind,
Code::ExtraICState extra_state) {
// ----------- S t a t e -------------
// -- r1 : receiver
// -- r2 : name
@ -394,7 +395,7 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
MONOMORPHIC,
extra_ic_state,
extra_state,
NORMAL,
argc);
Isolate::Current()->stub_cache()->GenerateProbe(
@ -463,7 +464,7 @@ static void GenerateFunctionTailCall(MacroAssembler* masm,
}
static void GenerateCallNormal(MacroAssembler* masm, int argc) {
void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
@ -485,10 +486,10 @@ static void GenerateCallNormal(MacroAssembler* masm, int argc) {
}
static void GenerateCallMiss(MacroAssembler* masm,
int argc,
IC::UtilityId id,
Code::ExtraICState extra_ic_state) {
void CallICBase::GenerateMiss(MacroAssembler* masm,
int argc,
IC::UtilityId id,
Code::ExtraICState extra_state) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
@ -504,21 +505,22 @@ static void GenerateCallMiss(MacroAssembler* masm,
// Get the receiver of the function from the stack.
__ ldr(r3, MemOperand(sp, argc * kPointerSize));
__ EnterInternalFrame();
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Push the receiver and the name of the function.
__ Push(r3, r2);
// Push the receiver and the name of the function.
__ Push(r3, r2);
// Call the entry.
__ mov(r0, Operand(2));
__ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate)));
// Call the entry.
__ mov(r0, Operand(2));
__ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate)));
CEntryStub stub(1);
__ CallStub(&stub);
CEntryStub stub(1);
__ CallStub(&stub);
// Move result to r1 and leave the internal frame.
__ mov(r1, Operand(r0));
__ LeaveInternalFrame();
// Move result to r1 and leave the internal frame.
__ mov(r1, Operand(r0));
}
// Check if the receiver is a global object of some sort.
// This can happen only for regular CallIC but not KeyedCallIC.
@ -539,7 +541,7 @@ static void GenerateCallMiss(MacroAssembler* masm,
}
// Invoke the function.
CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
CallKind call_kind = CallICBase::Contextual::decode(extra_state)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
ParameterCount actual(argc);
@ -551,18 +553,6 @@ static void GenerateCallMiss(MacroAssembler* masm,
}
void CallIC::GenerateMiss(MacroAssembler* masm,
int argc,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -----------------------------------
GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
}
void CallIC::GenerateMegamorphic(MacroAssembler* masm,
int argc,
Code::ExtraICState extra_ic_state) {
@ -578,27 +568,6 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm,
}
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -----------------------------------
GenerateCallNormal(masm, argc);
GenerateMiss(masm, argc, Code::kNoExtraICState);
}
void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -----------------------------------
GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
}
void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- r2 : name
@ -650,12 +619,13 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// This branch is taken when calling KeyedCallIC_Miss is neither required
// nor beneficial.
__ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3);
__ EnterInternalFrame();
__ push(r2); // save the key
__ Push(r1, r2); // pass the receiver and the key
__ CallRuntime(Runtime::kKeyedGetProperty, 2);
__ pop(r2); // restore the key
__ LeaveInternalFrame();
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(r2); // save the key
__ Push(r1, r2); // pass the receiver and the key
__ CallRuntime(Runtime::kKeyedGetProperty, 2);
__ pop(r2); // restore the key
}
__ mov(r1, r0);
__ jmp(&do_call);
@ -715,7 +685,7 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
__ JumpIfSmi(r2, &miss);
__ IsObjectJSStringType(r2, r0, &miss);
GenerateCallNormal(masm, argc);
CallICBase::GenerateNormal(masm, argc);
__ bind(&miss);
GenerateMiss(masm, argc);
}
@ -908,7 +878,8 @@ void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
GenerateMappedArgumentsLookup(masm, r2, r1, r3, r4, r5, &notin, &slow);
__ str(r0, mapped_location);
__ add(r6, r3, r5);
__ RecordWrite(r3, r6, r9);
__ mov(r9, r0);
__ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
__ Ret();
__ bind(&notin);
// The unmapped lookup expects that the parameter map is in r3.
@ -916,7 +887,8 @@ void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
GenerateUnmappedArgumentsLookup(masm, r1, r3, r4, &slow);
__ str(r0, unmapped_location);
__ add(r6, r3, r4);
__ RecordWrite(r3, r6, r9);
__ mov(r9, r0);
__ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
__ Ret();
__ bind(&slow);
GenerateMiss(masm, false);
@ -1137,14 +1109,12 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
Register receiver = r1;
Register index = r0;
Register scratch1 = r2;
Register scratch2 = r3;
Register scratch = r3;
Register result = r0;
StringCharAtGenerator char_at_generator(receiver,
index,
scratch1,
scratch2,
scratch,
result,
&miss, // When not a string.
&miss, // When not a number.
@ -1239,6 +1209,47 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
}
void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
// ---------- S t a t e --------------
// -- r2 : receiver
// -- r3 : target map
// -- lr : return address
// -----------------------------------
// Must return the modified receiver in r0.
if (!FLAG_trace_elements_transitions) {
Label fail;
ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
__ mov(r0, r2);
__ Ret();
__ bind(&fail);
}
__ push(r2);
__ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
}
void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
MacroAssembler* masm) {
// ---------- S t a t e --------------
// -- r2 : receiver
// -- r3 : target map
// -- lr : return address
// -----------------------------------
// Must return the modified receiver in r0.
if (!FLAG_trace_elements_transitions) {
Label fail;
ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
__ mov(r0, r2);
__ Ret();
__ bind(&fail);
}
__ push(r2);
__ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
}
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ---------- S t a t e --------------
@ -1267,13 +1278,17 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// -- r2 : receiver
// -- lr : return address
// -----------------------------------
Label slow, fast, array, extra;
Label slow, array, extra, check_if_double_array;
Label fast_object_with_map_check, fast_object_without_map_check;
Label fast_double_with_map_check, fast_double_without_map_check;
// Register usage.
Register value = r0;
Register key = r1;
Register receiver = r2;
Register elements = r3; // Elements array of the receiver.
Register elements_map = r6;
Register receiver_map = r7;
// r4 and r5 are used as general scratch registers.
// Check that the key is a smi.
@ -1281,35 +1296,26 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// Check that the object isn't a smi.
__ JumpIfSmi(receiver, &slow);
// Get the map of the object.
__ ldr(r4, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
// Check that the receiver does not require access checks. We need
// to do this because this generic stub does not perform map checks.
__ ldrb(ip, FieldMemOperand(r4, Map::kBitFieldOffset));
__ ldrb(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
__ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
__ b(ne, &slow);
// Check if the object is a JS array or not.
__ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
__ ldrb(r4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
__ cmp(r4, Operand(JS_ARRAY_TYPE));
__ b(eq, &array);
// Check that the object is some kind of JSObject.
__ cmp(r4, Operand(FIRST_JS_RECEIVER_TYPE));
__ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
__ b(lt, &slow);
__ cmp(r4, Operand(JS_PROXY_TYPE));
__ b(eq, &slow);
__ cmp(r4, Operand(JS_FUNCTION_PROXY_TYPE));
__ b(eq, &slow);
// Object case: Check key against length in the elements array.
__ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the object is in fast mode and writable.
__ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
__ cmp(r4, ip);
__ b(ne, &slow);
// Check array bounds. Both the key and the length of FixedArray are smis.
__ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
__ cmp(key, Operand(ip));
__ b(lo, &fast);
__ b(lo, &fast_object_with_map_check);
// Slow case, handle jump to runtime.
__ bind(&slow);
@ -1330,21 +1336,31 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
__ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
__ cmp(key, Operand(ip));
__ b(hs, &slow);
__ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
__ cmp(elements_map,
Operand(masm->isolate()->factory()->fixed_array_map()));
__ b(ne, &check_if_double_array);
// Calculate key + 1 as smi.
STATIC_ASSERT(kSmiTag == 0);
__ add(r4, key, Operand(Smi::FromInt(1)));
__ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ b(&fast);
__ b(&fast_object_without_map_check);
__ bind(&check_if_double_array);
__ cmp(elements_map,
Operand(masm->isolate()->factory()->fixed_double_array_map()));
__ b(ne, &slow);
// Add 1 to key, and go to common element store code for doubles.
STATIC_ASSERT(kSmiTag == 0);
__ add(r4, key, Operand(Smi::FromInt(1)));
__ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ jmp(&fast_double_without_map_check);
// Array case: Get the length and the elements array from the JS
// array. Check that the array is in fast mode (and writable); if it
// is the length is always a smi.
__ bind(&array);
__ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
__ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
__ cmp(r4, ip);
__ b(ne, &slow);
// Check the key against the length in the array.
__ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
@ -1352,18 +1368,57 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
__ b(hs, &extra);
// Fall through to fast case.
__ bind(&fast);
// Fast case, store the value to the elements backing store.
__ add(r5, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ add(r5, r5, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
__ str(value, MemOperand(r5));
// Skip write barrier if the written value is a smi.
__ tst(value, Operand(kSmiTagMask));
__ Ret(eq);
__ bind(&fast_object_with_map_check);
Register scratch_value = r4;
Register address = r5;
__ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
__ cmp(elements_map,
Operand(masm->isolate()->factory()->fixed_array_map()));
__ b(ne, &fast_double_with_map_check);
__ bind(&fast_object_without_map_check);
// Smi stores don't require further checks.
Label non_smi_value;
__ JumpIfNotSmi(value, &non_smi_value);
// It's irrelevant whether array is smi-only or not when writing a smi.
__ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
__ str(value, MemOperand(address));
__ Ret();
__ bind(&non_smi_value);
// Escape to slow case when writing non-smi into smi-only array.
__ CheckFastObjectElements(receiver_map, scratch_value, &slow);
// Fast elements array, store the value to the elements backing store.
__ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
__ str(value, MemOperand(address));
// Update write barrier for the elements array address.
__ sub(r4, r5, Operand(elements));
__ RecordWrite(elements, Operand(r4), r5, r6);
__ mov(scratch_value, value); // Preserve the value which is returned.
__ RecordWrite(elements,
address,
scratch_value,
kLRHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
__ Ret();
__ bind(&fast_double_with_map_check);
// Check for fast double array case. If this fails, call through to the
// runtime.
__ cmp(elements_map,
Operand(masm->isolate()->factory()->fixed_double_array_map()));
__ b(ne, &slow);
__ bind(&fast_double_without_map_check);
__ StoreNumberToDoubleElements(value,
key,
receiver,
elements,
r4,
r5,
r6,
r7,
&slow);
__ Ret();
}
@ -1510,11 +1565,9 @@ Condition CompareIC::ComputeCondition(Token::Value op) {
case Token::LT:
return lt;
case Token::GT:
// Reverse left and right operands to obtain ECMA-262 conversion order.
return lt;
return gt;
case Token::LTE:
// Reverse left and right operands to obtain ECMA-262 conversion order.
return ge;
return le;
case Token::GTE:
return ge;
default:

177
deps/v8/src/arm/lithium-arm.cc

@ -212,10 +212,11 @@ void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
}
void LIsNullAndBranch::PrintDataTo(StringStream* stream) {
void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
InputAt(0)->PrintTo(stream);
stream->Add(is_strict() ? " === null" : " == null");
stream->Add(kind() == kStrictEquality ? " === " : " == ");
stream->Add(nil() == kNullValue ? "null" : "undefined");
stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}
@ -227,6 +228,13 @@ void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
}
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_string(");
InputAt(0)->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_smi(");
InputAt(0)->PrintTo(stream);
@ -241,6 +249,14 @@ void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
}
void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if string_compare(");
InputAt(0)->PrintTo(stream);
InputAt(1)->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if has_instance_type(");
InputAt(0)->PrintTo(stream);
@ -390,6 +406,12 @@ void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
}
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add(" %p -> %p", *original_map(), *transitioned_map());
}
LChunk::LChunk(CompilationInfo* info, HGraph* graph)
: spill_slot_count_(0),
info_(info),
@ -711,7 +733,9 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
instr->set_environment(CreateEnvironment(hydrogen_env));
int argument_index_accumulator = 0;
instr->set_environment(CreateEnvironment(hydrogen_env,
&argument_index_accumulator));
return instr;
}
@ -741,7 +765,7 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
instr->MarkAsCall();
instr = AssignPointerMap(instr);
if (hinstr->HasSideEffects()) {
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
instr = SetInstructionPendingDeoptimizationEnvironment(
@ -753,7 +777,8 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
// Thus we still need to attach environment to this call even if
// call sequence can not deoptimize eagerly.
bool needs_environment =
(can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
(can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
!hinstr->HasObservableSideEffects();
if (needs_environment && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
}
@ -811,28 +836,6 @@ LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
}
LInstruction* LChunkBuilder::DoBit(Token::Value op,
HBitwiseBinaryOperation* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
return DefineAsRegister(new LBitI(op, left, right));
} else {
ASSERT(instr->representation().IsTagged());
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
LOperand* left = UseFixed(instr->left(), r1);
LOperand* right = UseFixed(instr->right(), r0);
LArithmeticT* result = new LArithmeticT(op, left, right);
return MarkAsCall(DefineFixed(result, r0), instr);
}
}
LInstruction* LChunkBuilder::DoShift(Token::Value op,
HBitwiseBinaryOperation* instr) {
if (instr->representation().IsTagged()) {
@ -994,10 +997,13 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
}
LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
LEnvironment* LChunkBuilder::CreateEnvironment(
HEnvironment* hydrogen_env,
int* argument_index_accumulator) {
if (hydrogen_env == NULL) return NULL;
LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
LEnvironment* outer =
CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
int value_count = hydrogen_env->length();
@ -1007,7 +1013,6 @@ LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
argument_count_,
value_count,
outer);
int argument_index = 0;
for (int i = 0; i < value_count; ++i) {
if (hydrogen_env->is_special_index(i)) continue;
@ -1016,7 +1021,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
if (value->IsArgumentsObject()) {
op = NULL;
} else if (value->IsPushArgument()) {
op = new LArgument(argument_index++);
op = new LArgument((*argument_index_accumulator)++);
} else {
op = UseAny(value);
}
@ -1206,8 +1211,9 @@ LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* function = UseFixed(instr->function(), r1);
argument_count_ -= instr->argument_count();
return MarkAsCall(DefineFixed(new LCallFunction, r0), instr);
return MarkAsCall(DefineFixed(new LCallFunction(function), r0), instr);
}
@ -1232,8 +1238,24 @@ LInstruction* LChunkBuilder::DoShl(HShl* instr) {
}
LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
return DoBit(Token::BIT_AND, instr);
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
return DefineAsRegister(new LBitI(left, right));
} else {
ASSERT(instr->representation().IsTagged());
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
LOperand* left = UseFixed(instr->left(), r1);
LOperand* right = UseFixed(instr->right(), r0);
LArithmeticT* result = new LArithmeticT(instr->op(), left, right);
return MarkAsCall(DefineFixed(result, r0), instr);
}
}
@ -1244,16 +1266,6 @@ LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
}
LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
return DoBit(Token::BIT_OR, instr);
}
LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
return DoBit(Token::BIT_XOR, instr);
}
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
@ -1399,12 +1411,10 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
Token::Value op = instr->token();
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
bool reversed = (op == Token::GT || op == Token::LTE);
LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1);
LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0);
LOperand* left = UseFixed(instr->left(), r1);
LOperand* right = UseFixed(instr->right(), r0);
LCmpT* result = new LCmpT(left, right);
return MarkAsCall(DefineFixed(result, r0), instr);
}
@ -1416,8 +1426,8 @@ LInstruction* LChunkBuilder::DoCompareIDAndBranch(
if (r.IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
LOperand* left = UseRegisterOrConstantAtStart(instr->left());
LOperand* right = UseRegisterOrConstantAtStart(instr->right());
return new LCmpIDAndBranch(left, right);
} else {
ASSERT(r.IsDouble());
@ -1444,9 +1454,9 @@ LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch(
}
LInstruction* LChunkBuilder::DoIsNullAndBranch(HIsNullAndBranch* instr) {
LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
return new LIsNullAndBranch(UseRegisterAtStart(instr->value()));
return new LIsNilAndBranch(UseRegisterAtStart(instr->value()));
}
@ -1457,6 +1467,13 @@ LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
}
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* temp = TempRegister();
return new LIsStringAndBranch(UseRegisterAtStart(instr->value()), temp);
}
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
return new LIsSmiAndBranch(Use(instr->value()));
@ -1471,6 +1488,17 @@ LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
}
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
HStringCompareAndBranch* instr) {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
LOperand* left = UseFixed(instr->left(), r1);
LOperand* right = UseFixed(instr->right(), r0);
LStringCompareAndBranch* result = new LStringCompareAndBranch(left, right);
return MarkAsCall(result, instr);
}
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
HHasInstanceTypeAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
@ -1734,7 +1762,7 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
LLoadGlobalCell* result = new LLoadGlobalCell;
return instr->check_hole_value()
return instr->RequiresHoleCheck()
? AssignEnvironment(DefineAsRegister(result))
: DefineAsRegister(result);
}
@ -1748,14 +1776,11 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
if (instr->check_hole_value()) {
LOperand* temp = TempRegister();
LOperand* value = UseRegister(instr->value());
return AssignEnvironment(new LStoreGlobalCell(value, temp));
} else {
LOperand* value = UseRegisterAtStart(instr->value());
return new LStoreGlobalCell(value, NULL);
}
LOperand* temp = TempRegister();
LOperand* value = UseTempRegister(instr->value());
LInstruction* result = new LStoreGlobalCell(value, temp);
if (instr->RequiresHoleCheck()) result = AssignEnvironment(result);
return result;
}
@ -1968,6 +1993,26 @@ LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
}
LInstruction* LChunkBuilder::DoTransitionElementsKind(
HTransitionElementsKind* instr) {
if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) {
LOperand* object = UseRegister(instr->object());
LOperand* new_map_reg = TempRegister();
LTransitionElementsKind* result =
new LTransitionElementsKind(object, new_map_reg, NULL);
return DefineSameAsFirst(result);
} else {
LOperand* object = UseFixed(instr->object(), r0);
LOperand* fixed_object_reg = FixedTemp(r2);
LOperand* new_map_reg = FixedTemp(r3);
LTransitionElementsKind* result =
new LTransitionElementsKind(object, new_map_reg, fixed_object_reg);
return MarkAsCall(DefineFixed(result, r0), instr);
}
}
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool needs_write_barrier = instr->NeedsWriteBarrier();
@ -2025,8 +2070,14 @@ LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
}
LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
return MarkAsCall(DefineFixed(new LObjectLiteral, r0), instr);
LInstruction* LChunkBuilder::DoObjectLiteralFast(HObjectLiteralFast* instr) {
return MarkAsCall(DefineFixed(new LObjectLiteralFast, r0), instr);
}
LInstruction* LChunkBuilder::DoObjectLiteralGeneric(
HObjectLiteralGeneric* instr) {
return MarkAsCall(DefineFixed(new LObjectLiteralGeneric, r0), instr);
}

119
deps/v8/src/arm/lithium-arm.h

@ -107,10 +107,12 @@ class LCodeGen;
V(Integer32ToDouble) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
V(IsNullAndBranch) \
V(IsNilAndBranch) \
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
V(StringCompareAndBranch) \
V(JSArrayLength) \
V(Label) \
V(LazyBailout) \
@ -132,7 +134,8 @@ class LCodeGen;
V(NumberTagD) \
V(NumberTagI) \
V(NumberUntagD) \
V(ObjectLiteral) \
V(ObjectLiteralFast) \
V(ObjectLiteralGeneric) \
V(OsrEntry) \
V(OuterContext) \
V(Parameter) \
@ -162,6 +165,7 @@ class LCodeGen;
V(ThisFunction) \
V(Throw) \
V(ToFastProperties) \
V(TransitionElementsKind) \
V(Typeof) \
V(TypeofIsAndBranch) \
V(UnaryMathOperation) \
@ -627,16 +631,17 @@ class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
};
class LIsNullAndBranch: public LControlInstruction<1, 0> {
class LIsNilAndBranch: public LControlInstruction<1, 0> {
public:
explicit LIsNullAndBranch(LOperand* value) {
explicit LIsNilAndBranch(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsNullAndBranch)
DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch)
bool is_strict() const { return hydrogen()->is_strict(); }
EqualityKind kind() const { return hydrogen()->kind(); }
NilValue nil() const { return hydrogen()->nil(); }
virtual void PrintDataTo(StringStream* stream);
};
@ -656,6 +661,20 @@ class LIsObjectAndBranch: public LControlInstruction<1, 1> {
};
class LIsStringAndBranch: public LControlInstruction<1, 1> {
public:
LIsStringAndBranch(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
virtual void PrintDataTo(StringStream* stream);
};
class LIsSmiAndBranch: public LControlInstruction<1, 0> {
public:
explicit LIsSmiAndBranch(LOperand* value) {
@ -684,6 +703,23 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> {
};
class LStringCompareAndBranch: public LControlInstruction<2, 0> {
public:
LStringCompareAndBranch(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
"string-compare-and-branch")
DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
Token::Value op() const { return hydrogen()->token(); }
virtual void PrintDataTo(StringStream* stream);
};
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
public:
explicit LHasInstanceTypeAndBranch(LOperand* value) {
@ -794,18 +830,15 @@ class LBoundsCheck: public LTemplateInstruction<0, 2, 0> {
class LBitI: public LTemplateInstruction<1, 2, 0> {
public:
LBitI(Token::Value op, LOperand* left, LOperand* right)
: op_(op) {
LBitI(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
Token::Value op() const { return op_; }
Token::Value op() const { return hydrogen()->op(); }
DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i")
private:
Token::Value op_;
DECLARE_HYDROGEN_ACCESSOR(Bitwise)
};
@ -1226,7 +1259,7 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> {
LOperand* global_object() { return InputAt(0); }
Handle<Object> name() const { return hydrogen()->name(); }
LOperand* value() { return InputAt(1); }
bool strict_mode() { return hydrogen()->strict_mode(); }
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
};
@ -1259,7 +1292,6 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 0> {
LOperand* context() { return InputAt(0); }
LOperand* value() { return InputAt(1); }
int slot_index() { return hydrogen()->slot_index(); }
int needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
virtual void PrintDataTo(StringStream* stream);
};
@ -1276,7 +1308,9 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> {
class LThisFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
DECLARE_HYDROGEN_ACCESSOR(ThisFunction)
};
@ -1379,12 +1413,17 @@ class LCallNamed: public LTemplateInstruction<1, 0, 0> {
};
class LCallFunction: public LTemplateInstruction<1, 0, 0> {
class LCallFunction: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCallFunction(LOperand* function) {
inputs_[0] = function;
}
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
int arity() const { return hydrogen()->argument_count() - 2; }
LOperand* function() { return inputs_[0]; }
int arity() const { return hydrogen()->argument_count() - 1; }
};
@ -1560,7 +1599,6 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 0> {
Handle<Object> name() const { return hydrogen()->name(); }
bool is_in_object() { return hydrogen()->is_in_object(); }
int offset() { return hydrogen()->offset(); }
bool needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); }
Handle<Map> transition() const { return hydrogen()->transition(); }
};
@ -1580,7 +1618,7 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> {
LOperand* object() { return inputs_[0]; }
LOperand* value() { return inputs_[1]; }
Handle<Object> name() const { return hydrogen()->name(); }
bool strict_mode() { return hydrogen()->strict_mode(); }
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
};
@ -1642,7 +1680,7 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> {
LOperand* object() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
bool strict_mode() { return hydrogen()->strict_mode(); }
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
};
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
@ -1668,6 +1706,30 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
};
class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> {
public:
LTransitionElementsKind(LOperand* object,
LOperand* new_map_temp,
LOperand* temp_reg) {
inputs_[0] = object;
temps_[0] = new_map_temp;
temps_[1] = temp_reg;
}
DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind,
"transition-elements-kind")
DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
virtual void PrintDataTo(StringStream* stream);
LOperand* object() { return inputs_[0]; }
LOperand* new_map_reg() { return temps_[0]; }
LOperand* temp_reg() { return temps_[1]; }
Handle<Map> original_map() { return hydrogen()->original_map(); }
Handle<Map> transitioned_map() { return hydrogen()->transitioned_map(); }
};
class LStringAdd: public LTemplateInstruction<1, 2, 0> {
public:
LStringAdd(LOperand* left, LOperand* right) {
@ -1838,10 +1900,17 @@ class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
};
class LObjectLiteral: public LTemplateInstruction<1, 0, 0> {
class LObjectLiteralFast: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralFast, "object-literal-fast")
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteralFast)
};
class LObjectLiteralGeneric: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteralGeneric, "object-literal-generic")
DECLARE_HYDROGEN_ACCESSOR(ObjectLiteralGeneric)
};
@ -2159,12 +2228,12 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* instr, int ast_id);
void ClearInstructionPendingDeoptimizationEnvironment();
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env);
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
int* argument_index_accumulator);
void VisitInstruction(HInstruction* current);
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
LInstruction* DoBit(Token::Value op, HBitwiseBinaryOperation* instr);
LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr);
LInstruction* DoArithmeticD(Token::Value op,
HArithmeticBinaryOperation* instr);

835
deps/v8/src/arm/lithium-codegen-arm.cc

File diff suppressed because it is too large

64
deps/v8/src/arm/lithium-codegen-arm.h

@ -58,6 +58,7 @@ class LCodeGen BASE_EMBEDDED {
status_(UNUSED),
deferred_(8),
osr_pc_offset_(-1),
last_lazy_deopt_pc_(0),
resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) {
PopulateDeoptimizationLiteralsWithInlinedFunctions();
@ -86,6 +87,7 @@ class LCodeGen BASE_EMBEDDED {
SwVfpRegister flt_scratch,
DoubleRegister dbl_scratch);
int ToInteger32(LConstantOperand* op) const;
double ToDouble(LConstantOperand* op) const;
Operand ToOperand(LOperand* op);
MemOperand ToMemOperand(LOperand* op) const;
// Returns a MemOperand pointing to the high word of a DoubleStackSlot.
@ -111,8 +113,8 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
// Parallel move support.
void DoParallelMove(LParallelMove* move);
@ -139,8 +141,8 @@ class LCodeGen BASE_EMBEDDED {
bool is_done() const { return status_ == DONE; }
bool is_aborted() const { return status_ == ABORTED; }
int strict_mode_flag() const {
return info()->is_strict_mode() ? kStrictMode : kNonStrictMode;
StrictModeFlag strict_mode_flag() const {
return info()->is_classic_mode() ? kNonStrictMode : kStrictMode;
}
LChunk* chunk() const { return chunk_; }
@ -206,7 +208,7 @@ class LCodeGen BASE_EMBEDDED {
LInstruction* instr);
// Generate a direct call to a known function. Expects the function
// to be in edi.
// to be in r1.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
@ -214,10 +216,11 @@ class LCodeGen BASE_EMBEDDED {
void LoadHeapObject(Register result, Handle<HeapObject> object);
void RegisterLazyDeoptimization(LInstruction* instr,
SafepointMode safepoint_mode);
void RecordSafepointWithLazyDeopt(LInstruction* instr,
SafepointMode safepoint_mode);
void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
Safepoint::DeoptMode mode);
void DeoptimizeIf(Condition cc, LEnvironment* environment);
void AddToTranslation(Translation* translation,
@ -239,6 +242,7 @@ class LCodeGen BASE_EMBEDDED {
void DoMathSqrt(LUnaryMathOperation* instr);
void DoMathPowHalf(LUnaryMathOperation* instr);
void DoMathLog(LUnaryMathOperation* instr);
void DoMathTan(LUnaryMathOperation* instr);
void DoMathCos(LUnaryMathOperation* instr);
void DoMathSin(LUnaryMathOperation* instr);
@ -246,24 +250,20 @@ class LCodeGen BASE_EMBEDDED {
void RecordSafepoint(LPointerMap* pointers,
Safepoint::Kind kind,
int arguments,
int deoptimization_index);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
void RecordSafepoint(int deoptimization_index);
Safepoint::DeoptMode mode);
void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
void RecordSafepoint(Safepoint::DeoptMode mode);
void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index);
Safepoint::DeoptMode mode);
void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
int arguments,
int deoptimization_index);
Safepoint::DeoptMode mode);
void RecordPosition(int position);
int LastSafepointEnd() {
return static_cast<int>(safepoints_.GetPcAfterGap());
}
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block);
void EmitBranch(int left_block, int right_block, Condition cc);
void EmitCmpI(LOperand* left, LOperand* right);
void EmitNumberUntagD(Register input,
DoubleRegister result,
bool deoptimize_on_undefined,
@ -272,8 +272,10 @@ class LCodeGen BASE_EMBEDDED {
// Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitTypeofIs(Label* true_label, Label* false_label,
Register input, Handle<String> type_name);
Condition EmitTypeofIs(Label* true_label,
Label* false_label,
Register input,
Handle<String> type_name);
// Emits optimized code for %_IsObject(x). Preserves input register.
// Returns the condition on which a final split to
@ -283,6 +285,13 @@ class LCodeGen BASE_EMBEDDED {
Label* is_not_object,
Label* is_object);
// Emits optimized code for %_IsString(x). Preserves input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitIsString(Register input,
Register temp1,
Label* is_not_string);
// Emits optimized code for %_IsConstructCall().
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp1, Register temp2);
@ -292,6 +301,13 @@ class LCodeGen BASE_EMBEDDED {
Handle<Map> type,
Handle<String> name);
// Emits optimized code to deep-copy the contents of statically known
// object graphs (e.g. object literal boilerplate).
void EmitDeepCopy(Handle<JSObject> object,
Register result,
Register source,
int* offset);
struct JumpTableEntry {
explicit inline JumpTableEntry(Address entry)
: label(),
@ -300,6 +316,8 @@ class LCodeGen BASE_EMBEDDED {
Address address;
};
void EnsureSpaceForLazyDeopt();
LChunk* const chunk_;
MacroAssembler* const masm_;
CompilationInfo* const info_;
@ -316,6 +334,7 @@ class LCodeGen BASE_EMBEDDED {
TranslationBuffer translations_;
ZoneList<LDeferredCode*> deferred_;
int osr_pc_offset_;
int last_lazy_deopt_pc_;
// Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code.
@ -376,16 +395,20 @@ class LCodeGen BASE_EMBEDDED {
class LDeferredCode: public ZoneObject {
public:
explicit LDeferredCode(LCodeGen* codegen)
: codegen_(codegen), external_exit_(NULL) {
: codegen_(codegen),
external_exit_(NULL),
instruction_index_(codegen->current_instruction_) {
codegen->AddDeferredCode(this);
}
virtual ~LDeferredCode() { }
virtual void Generate() = 0;
virtual LInstruction* instr() = 0;
void SetExit(Label *exit) { external_exit_ = exit; }
Label* entry() { return &entry_; }
Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
int instruction_index() const { return instruction_index_; }
protected:
LCodeGen* codegen() const { return codegen_; }
@ -396,6 +419,7 @@ class LDeferredCode: public ZoneObject {
Label entry_;
Label exit_;
Label* external_exit_;
int instruction_index_;
};
} } // namespace v8::internal

865
deps/v8/src/arm/macro-assembler-arm.cc

File diff suppressed because it is too large

337
deps/v8/src/arm/macro-assembler-arm.h

@ -29,6 +29,7 @@
#define V8_ARM_MACRO_ASSEMBLER_ARM_H_
#include "assembler.h"
#include "frames.h"
#include "v8globals.h"
namespace v8 {
@ -38,12 +39,12 @@ namespace internal {
// Static helper functions
// Generate a MemOperand for loading a field from an object.
static inline MemOperand FieldMemOperand(Register object, int offset) {
inline MemOperand FieldMemOperand(Register object, int offset) {
return MemOperand(object, offset - kHeapObjectTag);
}
static inline Operand SmiUntagOperand(Register object) {
inline Operand SmiUntagOperand(Register object) {
return Operand(object, ASR, kSmiTagSize);
}
@ -79,6 +80,14 @@ enum ObjectToDoubleFlags {
};
enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
bool AreAliased(Register r1, Register r2, Register r3, Register r4);
// MacroAssembler implements a collection of frequently used macros.
class MacroAssembler: public Assembler {
public:
@ -157,40 +166,126 @@ class MacroAssembler: public Assembler {
Heap::RootListIndex index,
Condition cond = al);
// ---------------------------------------------------------------------------
// GC Support
void IncrementalMarkingRecordWriteHelper(Register object,
Register value,
Register address);
enum RememberedSetFinalAction {
kReturnAtEnd,
kFallThroughAtEnd
};
// Record in the remembered set the fact that we have a pointer to new space
// at the address pointed to by the addr register. Only works if addr is not
// in new space.
void RememberedSetHelper(Register object, // Used for debug code.
Register addr,
Register scratch,
SaveFPRegsMode save_fp,
RememberedSetFinalAction and_then);
void CheckPageFlag(Register object,
Register scratch,
int mask,
Condition cc,
Label* condition_met);
// Check if object is in new space. Jumps if the object is not in new space.
// The register scratch can be object itself, but scratch will be clobbered.
void JumpIfNotInNewSpace(Register object,
Register scratch,
Label* branch) {
InNewSpace(object, scratch, ne, branch);
}
// Check if object is in new space.
// scratch can be object itself, but it will be clobbered.
void InNewSpace(Register object,
Register scratch,
Condition cond, // eq for new space, ne otherwise
Label* branch);
// Check if object is in new space. Jumps if the object is in new space.
// The register scratch can be object itself, but it will be clobbered.
void JumpIfInNewSpace(Register object,
Register scratch,
Label* branch) {
InNewSpace(object, scratch, eq, branch);
}
// For the page containing |object| mark the region covering [address]
// dirty. The object address must be in the first 8K of an allocated page.
void RecordWriteHelper(Register object,
Register address,
Register scratch);
// Check if an object has a given incremental marking color.
void HasColor(Register object,
Register scratch0,
Register scratch1,
Label* has_color,
int first_bit,
int second_bit);
// For the page containing |object| mark the region covering
// [object+offset] dirty. The object address must be in the first 8K
// of an allocated page. The 'scratch' registers are used in the
// implementation and all 3 registers are clobbered by the
// operation, as well as the ip register. RecordWrite updates the
// write barrier even when storing smis.
void RecordWrite(Register object,
Operand offset,
void JumpIfBlack(Register object,
Register scratch0,
Register scratch1);
Register scratch1,
Label* on_black);
// Checks the color of an object. If the object is already grey or black
// then we just fall through, since it is already live. If it is white and
// we can determine that it doesn't need to be scanned, then we just mark it
// black and fall through. For the rest we jump to the label so the
// incremental marker can fix its assumptions.
void EnsureNotWhite(Register object,
Register scratch1,
Register scratch2,
Register scratch3,
Label* object_is_white_and_not_data);
// For the page containing |object| mark the region covering
// [address] dirty. The object address must be in the first 8K of an
// allocated page. All 3 registers are clobbered by the operation,
// as well as the ip register. RecordWrite updates the write barrier
// even when storing smis.
void RecordWrite(Register object,
Register address,
Register scratch);
// Detects conservatively whether an object is data-only, ie it does need to
// be scanned by the garbage collector.
void JumpIfDataObject(Register value,
Register scratch,
Label* not_data_object);
// Notify the garbage collector that we wrote a pointer into an object.
// |object| is the object being stored into, |value| is the object being
// stored. value and scratch registers are clobbered by the operation.
// The offset is the offset from the start of the object, not the offset from
// the tagged HeapObject pointer. For use with FieldOperand(reg, off).
void RecordWriteField(
Register object,
int offset,
Register value,
Register scratch,
LinkRegisterStatus lr_status,
SaveFPRegsMode save_fp,
RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
SmiCheck smi_check = INLINE_SMI_CHECK);
// As above, but the offset has the tag presubtracted. For use with
// MemOperand(reg, off).
inline void RecordWriteContextSlot(
Register context,
int offset,
Register value,
Register scratch,
LinkRegisterStatus lr_status,
SaveFPRegsMode save_fp,
RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
SmiCheck smi_check = INLINE_SMI_CHECK) {
RecordWriteField(context,
offset + kHeapObjectTag,
value,
scratch,
lr_status,
save_fp,
remembered_set_action,
smi_check);
}
// For a given |object| notify the garbage collector that the slot |address|
// has been written. |value| is the object being stored. The value and
// address registers are clobbered by the operation.
void RecordWrite(
Register object,
Register address,
Register value,
LinkRegisterStatus lr_status,
SaveFPRegsMode save_fp,
RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
SmiCheck smi_check = INLINE_SMI_CHECK);
// Push a handle.
void Push(Handle<Object> handle);
@ -225,8 +320,11 @@ class MacroAssembler: public Assembler {
}
// Push four registers. Pushes leftmost register first (to highest address).
void Push(Register src1, Register src2,
Register src3, Register src4, Condition cond = al) {
void Push(Register src1,
Register src2,
Register src3,
Register src4,
Condition cond = al) {
ASSERT(!src1.is(src2));
ASSERT(!src2.is(src3));
ASSERT(!src1.is(src3));
@ -265,6 +363,57 @@ class MacroAssembler: public Assembler {
}
}
// Pop three registers. Pops rightmost register first (from lower address).
void Pop(Register src1, Register src2, Register src3, Condition cond = al) {
ASSERT(!src1.is(src2));
ASSERT(!src2.is(src3));
ASSERT(!src1.is(src3));
if (src1.code() > src2.code()) {
if (src2.code() > src3.code()) {
ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
} else {
ldr(src3, MemOperand(sp, 4, PostIndex), cond);
ldm(ia_w, sp, src1.bit() | src2.bit(), cond);
}
} else {
Pop(src2, src3, cond);
str(src1, MemOperand(sp, 4, PostIndex), cond);
}
}
// Pop four registers. Pops rightmost register first (from lower address).
void Pop(Register src1,
Register src2,
Register src3,
Register src4,
Condition cond = al) {
ASSERT(!src1.is(src2));
ASSERT(!src2.is(src3));
ASSERT(!src1.is(src3));
ASSERT(!src1.is(src4));
ASSERT(!src2.is(src4));
ASSERT(!src3.is(src4));
if (src1.code() > src2.code()) {
if (src2.code() > src3.code()) {
if (src3.code() > src4.code()) {
ldm(ia_w,
sp,
src1.bit() | src2.bit() | src3.bit() | src4.bit(),
cond);
} else {
ldr(src4, MemOperand(sp, 4, PostIndex), cond);
ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
}
} else {
Pop(src3, src4, cond);
ldm(ia_w, sp, src1.bit() | src2.bit(), cond);
}
} else {
Pop(src2, src3, src4, cond);
ldr(src1, MemOperand(sp, 4, PostIndex), cond);
}
}
// Push and pop the registers that can hold pointers, as defined by the
// RegList constant kSafepointSavedRegisters.
void PushSafepointRegisters();
@ -318,16 +467,6 @@ class MacroAssembler: public Assembler {
const double imm,
const Condition cond = al);
// ---------------------------------------------------------------------------
// Activation frames
void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
// Enter exit frame.
// stack_space - extra stack space, used for alignment before call to C.
void EnterExitFrame(bool save_doubles, int stack_space = 0);
@ -381,7 +520,7 @@ class MacroAssembler: public Assembler {
const CallWrapper& call_wrapper,
CallKind call_kind);
void InvokeFunction(JSFunction* function,
void InvokeFunction(Handle<JSFunction> function,
const ParameterCount& actual,
InvokeFlag flag,
CallKind call_kind);
@ -410,9 +549,9 @@ class MacroAssembler: public Assembler {
// Exception handling
// Push a new try handler and link into try handler chain.
// The return address must be passed in register lr.
// On exit, r0 contains TOS (code slot).
void PushTryHandler(CodeLocation try_location, HandlerType type);
void PushTryHandler(CodeLocation try_location,
HandlerType type,
int handler_index);
// Unlink the stack handler on top of the stack from the try handler chain.
// Must preserve the result register.
@ -569,6 +708,13 @@ class MacroAssembler: public Assembler {
Register length,
Register scratch);
// Initialize fields with filler values. Fields starting at |start_offset|
// not including end_offset are overwritten with the value in |filler|. At
// the end the loop, |start_offset| takes the value of |end_offset|.
void InitializeFieldsWithFiller(Register start_offset,
Register end_offset,
Register filler);
// ---------------------------------------------------------------------------
// Support functions.
@ -580,7 +726,8 @@ class MacroAssembler: public Assembler {
void TryGetFunctionPrototype(Register function,
Register result,
Register scratch,
Label* miss);
Label* miss,
bool miss_on_bound_function = false);
// Compare object type for heap object. heap_object contains a non-Smi
// whose object type should be compared with the given type. This both
@ -608,6 +755,31 @@ class MacroAssembler: public Assembler {
Register scratch,
Label* fail);
// Check if a map for a JSObject indicates that the object can have both smi
// and HeapObject elements. Jump to the specified label if it does not.
void CheckFastObjectElements(Register map,
Register scratch,
Label* fail);
// Check if a map for a JSObject indicates that the object has fast smi only
// elements. Jump to the specified label if it does not.
void CheckFastSmiOnlyElements(Register map,
Register scratch,
Label* fail);
// Check to see if maybe_number can be stored as a double in
// FastDoubleElements. If it can, store it at the index specified by key in
// the FastDoubleElements array elements, otherwise jump to fail.
void StoreNumberToDoubleElements(Register value_reg,
Register key_reg,
Register receiver_reg,
Register elements_reg,
Register scratch1,
Register scratch2,
Register scratch3,
Register scratch4,
Label* fail);
// Check if the map of an object is equal to a specified map (either
// given directly or as an index into the root list) and branch to
// label if not. Skip the smi check if not required (object is known
@ -754,20 +926,9 @@ class MacroAssembler: public Assembler {
// Call a code stub.
void CallStub(CodeStub* stub, Condition cond = al);
// Call a code stub and return the code object called. Try to generate
// the code if necessary. Do not perform a GC but instead return a retry
// after GC failure.
MUST_USE_RESULT MaybeObject* TryCallStub(CodeStub* stub, Condition cond = al);
// Call a code stub.
void TailCallStub(CodeStub* stub, Condition cond = al);
// Tail call a code stub (jump) and return the code object called. Try to
// generate the code if necessary. Do not perform a GC but instead return
// a retry after GC failure.
MUST_USE_RESULT MaybeObject* TryTailCallStub(CodeStub* stub,
Condition cond = al);
// Call a runtime routine.
void CallRuntime(const Runtime::Function* f, int num_arguments);
void CallRuntimeSaveDoubles(Runtime::FunctionId id);
@ -786,12 +947,6 @@ class MacroAssembler: public Assembler {
int num_arguments,
int result_size);
// Tail call of a runtime routine (jump). Try to generate the code if
// necessary. Do not perform a GC but instead return a retry after GC
// failure.
MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
const ExternalReference& ext, int num_arguments, int result_size);
// Convenience function: tail call a runtime routine (jump).
void TailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
@ -830,28 +985,25 @@ class MacroAssembler: public Assembler {
// return address (unless this is somehow accounted for by the called
// function).
void CallCFunction(ExternalReference function, int num_arguments);
void CallCFunction(Register function, Register scratch, int num_arguments);
void CallCFunction(Register function, int num_arguments);
void CallCFunction(ExternalReference function,
int num_reg_arguments,
int num_double_arguments);
void CallCFunction(Register function, Register scratch,
void CallCFunction(Register function,
int num_reg_arguments,
int num_double_arguments);
void GetCFunctionDoubleResult(const DoubleRegister dst);
// Calls an API function. Allocates HandleScope, extracts returned value
// from handle and propagates exceptions. Restores context.
// stack_space - space to be unwound on exit (includes the call js
// arguments space and the additional space allocated for the fast call).
MaybeObject* TryCallApiFunctionAndReturn(ExternalReference function,
int stack_space);
// Calls an API function. Allocates HandleScope, extracts returned value
// from handle and propagates exceptions. Restores context. stack_space
// - space to be unwound on exit (includes the call js arguments space and
// the additional space allocated for the fast call).
void CallApiFunctionAndReturn(ExternalReference function, int stack_space);
// Jump to a runtime routine.
void JumpToExternalReference(const ExternalReference& builtin);
MaybeObject* TryJumpToExternalReference(const ExternalReference& ext);
// Invoke specified builtin JavaScript function. Adds an entry to
// the unresolved list if the name does not resolve.
void InvokeBuiltin(Builtins::JavaScript id,
@ -902,6 +1054,9 @@ class MacroAssembler: public Assembler {
bool generating_stub() { return generating_stub_; }
void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
bool allow_stub_calls() { return allow_stub_calls_; }
void set_has_frame(bool value) { has_frame_ = value; }
bool has_frame() { return has_frame_; }
inline bool AllowThisStubCall(CodeStub* stub);
// EABI variant for double arguments in use.
bool use_eabi_hardfloat() {
@ -1048,10 +1203,12 @@ class MacroAssembler: public Assembler {
void LoadInstanceDescriptors(Register map, Register descriptors);
// Activation support.
void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type);
private:
void CallCFunctionHelper(Register function,
ExternalReference function_reference,
Register scratch,
int num_reg_arguments,
int num_double_arguments);
@ -1067,16 +1224,29 @@ class MacroAssembler: public Assembler {
const CallWrapper& call_wrapper,
CallKind call_kind);
// Activation support.
void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type);
void InitializeNewString(Register string,
Register length,
Heap::RootListIndex map_index,
Register scratch1,
Register scratch2);
// Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
void InNewSpace(Register object,
Register scratch,
Condition cond, // eq for new space, ne otherwise.
Label* branch);
// Helper for finding the mark bits for an address. Afterwards, the
// bitmap register points at the word with the mark bits and the mask
// the position of the first bit. Leaves addr_reg unchanged.
inline void GetMarkBits(Register addr_reg,
Register bitmap_reg,
Register mask_reg);
// Helper for throwing exceptions. Compute a handler address and jump to
// it. See the implementation for register usage.
void JumpToHandlerEntry();
// Compute memory operands for safepoint stack slots.
static int SafepointRegisterStackIndex(int reg_code);
MemOperand SafepointRegisterSlot(Register reg);
@ -1084,6 +1254,7 @@ class MacroAssembler: public Assembler {
bool generating_stub_;
bool allow_stub_calls_;
bool has_frame_;
// This handle will be patched with the code object on installation.
Handle<Object> code_object_;
@ -1129,12 +1300,12 @@ class CodePatcher {
// -----------------------------------------------------------------------------
// Static helper functions.
static MemOperand ContextOperand(Register context, int index) {
inline MemOperand ContextOperand(Register context, int index) {
return MemOperand(context, Context::SlotOffset(index));
}
static inline MemOperand GlobalObjectOperand() {
inline MemOperand GlobalObjectOperand() {
return ContextOperand(cp, Context::GLOBAL_INDEX);
}

20
deps/v8/src/arm/regexp-macro-assembler-arm.cc

@ -371,9 +371,12 @@ void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
// Isolate.
__ mov(r3, Operand(ExternalReference::isolate_address()));
ExternalReference function =
ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
__ CallCFunction(function, argument_count);
{
AllowExternalCallThatCantCauseGC scope(masm_);
ExternalReference function =
ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
__ CallCFunction(function, argument_count);
}
// Check if function returned non-zero for success or zero for failure.
__ cmp(r0, Operand(0, RelocInfo::NONE));
@ -611,6 +614,12 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
// Entry code:
__ bind(&entry_label_);
// Tell the system that we have a stack frame. Because the type is MANUAL, no
// is generated.
FrameScope scope(masm_, StackFrame::MANUAL);
// Actually emit code to start a new stack frame.
// Push arguments
// Save callee-save registers.
// Start new stack frame.
@ -1102,6 +1111,11 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
frame_entry<const String*>(re_frame, kInputString) = *subject;
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
} else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
// Subject string might have been a ConsString that underwent
// short-circuiting during GC. That will not change start_address but
// will change pointer inside the subject handle.
frame_entry<const String*>(re_frame, kInputString) = *subject;
}
return 0;

29
deps/v8/src/arm/simulator-arm.cc

@ -53,7 +53,7 @@ namespace internal {
// code.
class ArmDebugger {
public:
explicit ArmDebugger(Simulator* sim);
explicit ArmDebugger(Simulator* sim) : sim_(sim) { }
~ArmDebugger();
void Stop(Instruction* instr);
@ -84,11 +84,6 @@ class ArmDebugger {
};
ArmDebugger::ArmDebugger(Simulator* sim) {
sim_ = sim;
}
ArmDebugger::~ArmDebugger() {
}
@ -296,6 +291,13 @@ void ArmDebugger::Debug() {
if (line == NULL) {
break;
} else {
char* last_input = sim_->last_debugger_input();
if (strcmp(line, "\n") == 0 && last_input != NULL) {
line = last_input;
} else {
// Ownership is transferred to sim_;
sim_->set_last_debugger_input(line);
}
// Use sscanf to parse the individual parts of the command line. At the
// moment no command expects more than two parameters.
int argc = SScanF(line,
@ -611,7 +613,6 @@ void ArmDebugger::Debug() {
PrintF("Unknown command: %s\n", cmd);
}
}
DeleteArray(line);
}
// Add all the breakpoints back to stop execution and enter the debugger
@ -645,6 +646,12 @@ static bool AllOnOnePage(uintptr_t start, int size) {
}
void Simulator::set_last_debugger_input(char* input) {
DeleteArray(last_debugger_input_);
last_debugger_input_ = input;
}
void Simulator::FlushICache(v8::internal::HashMap* i_cache,
void* start_addr,
size_t size) {
@ -781,6 +788,8 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
registers_[pc] = bad_lr;
registers_[lr] = bad_lr;
InitializeCoverage();
last_debugger_input_ = NULL;
}
@ -1268,9 +1277,9 @@ void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
// Returns the limit of the stack area to enable checking for stack overflows.
uintptr_t Simulator::StackLimit() const {
// Leave a safety margin of 256 bytes to prevent overrunning the stack when
// Leave a safety margin of 512 bytes to prevent overrunning the stack when
// pushing values.
return reinterpret_cast<uintptr_t>(stack_) + 256;
return reinterpret_cast<uintptr_t>(stack_) + 512;
}
@ -1618,6 +1627,8 @@ void Simulator::HandleRList(Instruction* instr, bool load) {
ProcessPUW(instr, num_regs, kPointerSize, &start_address, &end_address);
intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
// Catch null pointers a little earlier.
ASSERT(start_address > 8191 || start_address < 0);
int reg = 0;
while (rlist != 0) {
if ((rlist & 1) != 0) {

7
deps/v8/src/arm/simulator-arm.h

@ -194,6 +194,10 @@ class Simulator {
// Pop an address from the JS stack.
uintptr_t PopAddress();
// Debugger input.
void set_last_debugger_input(char* input);
char* last_debugger_input() { return last_debugger_input_; }
// ICache checking.
static void FlushICache(v8::internal::HashMap* i_cache, void* start,
size_t size);
@ -360,6 +364,9 @@ class Simulator {
bool pc_modified_;
int icount_;
// Debugger input.
char* last_debugger_input_;
// Icache simulation
v8::internal::HashMap* i_cache_;

1655
deps/v8/src/arm/stub-cache-arm.cc

File diff suppressed because it is too large

188
deps/v8/src/array.js

@ -201,17 +201,14 @@ function ConvertToString(x) {
function ConvertToLocaleString(e) {
if (e == null) {
if (IS_NULL_OR_UNDEFINED(e)) {
return '';
} else {
// e_obj's toLocaleString might be overwritten, check if it is a function.
// Call ToString if toLocaleString is not a function.
// See issue 877615.
// According to ES5, seciton 15.4.4.3, the toLocaleString conversion
// must throw a TypeError if ToObject(e).toLocaleString isn't
// callable.
var e_obj = ToObject(e);
if (IS_SPEC_FUNCTION(e_obj.toLocaleString))
return ToString(e_obj.toLocaleString());
else
return ToString(e);
return %ToString(e_obj.toLocaleString());
}
}
@ -331,8 +328,9 @@ function SimpleSlice(array, start_i, del_count, len, deleted_elements) {
// would be the appropriate test. We follow KJS in consulting the
// prototype.
var current = array[index];
if (!IS_UNDEFINED(current) || index in array)
if (!IS_UNDEFINED(current) || index in array) {
deleted_elements[i] = current;
}
}
}
@ -381,18 +379,31 @@ function SimpleMove(array, start_i, del_count, len, num_additional_args) {
function ArrayToString() {
if (!IS_ARRAY(this)) {
throw new $TypeError('Array.prototype.toString is not generic');
var array;
var func;
if (IS_ARRAY(this)) {
func = this.join;
if (func === ArrayJoin) {
return Join(this, this.length, ',', ConvertToString);
}
array = this;
} else {
array = ToObject(this);
func = array.join;
}
return Join(this, this.length, ',', ConvertToString);
if (!IS_SPEC_FUNCTION(func)) {
return %_CallFunction(array, ObjectToString);
}
return %_CallFunction(array, func);
}
function ArrayToLocaleString() {
if (!IS_ARRAY(this)) {
throw new $TypeError('Array.prototype.toString is not generic');
}
return Join(this, this.length, ',', ConvertToLocaleString);
var array = ToObject(this);
var arrayLen = array.length;
var len = TO_UINT32(arrayLen);
if (len === 0) return "";
return Join(array, len, ',', ConvertToLocaleString);
}
@ -485,12 +496,12 @@ function SparseReverse(array, len) {
if (j_complement <= i) {
high = j;
while (keys[--high_counter] == j);
while (keys[--high_counter] == j) { }
low = j_complement;
}
if (j_complement >= i) {
low = i;
while (keys[++low_counter] == i);
while (keys[++low_counter] == i) { }
high = len - i - 1;
}
@ -566,10 +577,11 @@ function ArrayShift() {
var first = this[0];
if (IS_ARRAY(this))
if (IS_ARRAY(this)) {
SmartMove(this, 0, 1, len, 0);
else
} else {
SimpleMove(this, 0, 1, len, 0);
}
this.length = len - 1;
@ -586,10 +598,11 @@ function ArrayUnshift(arg1) { // length == 1
var len = TO_UINT32(this.length);
var num_arguments = %_ArgumentsLength();
if (IS_ARRAY(this))
if (IS_ARRAY(this)) {
SmartMove(this, 0, 0, len, num_arguments);
else
} else {
SimpleMove(this, 0, 0, len, num_arguments);
}
for (var i = 0; i < num_arguments; i++) {
this[i] = %_Arguments(i);
@ -993,25 +1006,32 @@ function ArrayFilter(f, receiver) {
["Array.prototype.filter"]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = ToUint32(array.length);
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
} else if (!IS_SPEC_OBJECT(receiver)) {
receiver = ToObject(receiver);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = ToUint32(this.length);
var result = [];
var result_length = 0;
var result = new $Array();
var accumulator = new InternalArray();
var accumulator_length = 0;
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
if (%_CallFunction(receiver, current, i, this, f)) {
result[result_length++] = current;
var current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
if (%_CallFunction(receiver, current, i, array, f)) {
accumulator[accumulator_length++] = current;
}
}
}
%MoveArrayContents(accumulator, result);
return result;
}
@ -1022,19 +1042,24 @@ function ArrayForEach(f, receiver) {
["Array.prototype.forEach"]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = TO_UINT32(array.length);
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
} else if (!IS_SPEC_OBJECT(receiver)) {
receiver = ToObject(receiver);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = TO_UINT32(this.length);
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
%_CallFunction(receiver, current, i, this, f);
var current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
%_CallFunction(receiver, current, i, array, f);
}
}
}
@ -1048,19 +1073,24 @@ function ArraySome(f, receiver) {
["Array.prototype.some"]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = TO_UINT32(array.length);
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
} else if (!IS_SPEC_OBJECT(receiver)) {
receiver = ToObject(receiver);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = TO_UINT32(this.length);
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
if (%_CallFunction(receiver, current, i, this, f)) return true;
var current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
if (%_CallFunction(receiver, current, i, array, f)) return true;
}
}
return false;
@ -1073,19 +1103,24 @@ function ArrayEvery(f, receiver) {
["Array.prototype.every"]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = TO_UINT32(array.length);
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
} else if (!IS_SPEC_OBJECT(receiver)) {
receiver = ToObject(receiver);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = TO_UINT32(this.length);
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
if (!%_CallFunction(receiver, current, i, this, f)) return false;
var current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
if (!%_CallFunction(receiver, current, i, array, f)) return false;
}
}
return true;
@ -1097,21 +1132,26 @@ function ArrayMap(f, receiver) {
["Array.prototype.map"]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = TO_UINT32(array.length);
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
} else if (!IS_SPEC_OBJECT(receiver)) {
receiver = ToObject(receiver);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = TO_UINT32(this.length);
var result = new $Array();
var accumulator = new InternalArray(length);
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
accumulator[i] = %_CallFunction(receiver, current, i, this, f);
var current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
accumulator[i] = %_CallFunction(receiver, current, i, array, f);
}
}
%MoveArrayContents(accumulator, result);
@ -1245,19 +1285,20 @@ function ArrayReduce(callback, current) {
["Array.prototype.reduce"]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = ToUint32(array.length);
if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = ToUint32(this.length);
var i = 0;
find_initial: if (%_ArgumentsLength() < 2) {
for (; i < length; i++) {
current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
i++;
break find_initial;
}
@ -1267,9 +1308,9 @@ function ArrayReduce(callback, current) {
var receiver = %GetDefaultReceiver(callback);
for (; i < length; i++) {
var element = this[i];
if (!IS_UNDEFINED(element) || i in this) {
current = %_CallFunction(receiver, current, element, i, this, callback);
var element = array[i];
if (!IS_UNDEFINED(element) || i in array) {
current = %_CallFunction(receiver, current, element, i, array, callback);
}
}
return current;
@ -1281,15 +1322,20 @@ function ArrayReduceRight(callback, current) {
["Array.prototype.reduceRight"]);
}
// Pull out the length so that side effects are visible before the
// callback function is checked.
var array = ToObject(this);
var length = ToUint32(array.length);
if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]);
}
var i = ToUint32(this.length) - 1;
var i = length - 1;
find_initial: if (%_ArgumentsLength() < 2) {
for (; i >= 0; i--) {
current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
i--;
break find_initial;
}
@ -1299,9 +1345,9 @@ function ArrayReduceRight(callback, current) {
var receiver = %GetDefaultReceiver(callback);
for (; i >= 0; i--) {
var element = this[i];
if (!IS_UNDEFINED(element) || i in this) {
current = %_CallFunction(receiver, current, element, i, this, callback);
var element = array[i];
if (!IS_UNDEFINED(element) || i in array) {
current = %_CallFunction(receiver, current, element, i, array, callback);
}
}
return current;
@ -1342,7 +1388,7 @@ function SetUpArray() {
// set their names.
// Manipulate the length of some of the functions to meet
// expectations set by ECMA-262 or Mozilla.
InstallFunctionsOnHiddenPrototype($Array.prototype, DONT_ENUM, $Array(
InstallFunctions($Array.prototype, DONT_ENUM, $Array(
"toString", getFunction("toString", ArrayToString),
"toLocaleString", getFunction("toLocaleString", ArrayToLocaleString),
"join", getFunction("join", ArrayJoin),

90
deps/v8/src/assembler.cc

@ -38,6 +38,7 @@
#include "deoptimizer.h"
#include "execution.h"
#include "ic-inl.h"
#include "incremental-marking.h"
#include "factory.h"
#include "runtime.h"
#include "runtime-profiler.h"
@ -47,6 +48,7 @@
#include "ast.h"
#include "regexp-macro-assembler.h"
#include "platform.h"
#include "store-buffer.h"
// Include native regexp-macro-assembler.
#ifndef V8_INTERPRETED_REGEXP
#if V8_TARGET_ARCH_IA32
@ -516,6 +518,7 @@ void RelocIterator::next() {
RelocIterator::RelocIterator(Code* code, int mode_mask) {
rinfo_.host_ = code;
rinfo_.pc_ = code->instruction_start();
rinfo_.data_ = 0;
// Relocation info is read backwards.
@ -736,9 +739,38 @@ ExternalReference::ExternalReference(const SCTableReference& table_ref)
: address_(table_ref.address()) {}
ExternalReference ExternalReference::
incremental_marking_record_write_function(Isolate* isolate) {
return ExternalReference(Redirect(
isolate,
FUNCTION_ADDR(IncrementalMarking::RecordWriteFromCode)));
}
ExternalReference ExternalReference::
incremental_evacuation_record_write_function(Isolate* isolate) {
return ExternalReference(Redirect(
isolate,
FUNCTION_ADDR(IncrementalMarking::RecordWriteForEvacuationFromCode)));
}
ExternalReference ExternalReference::
store_buffer_overflow_function(Isolate* isolate) {
return ExternalReference(Redirect(
isolate,
FUNCTION_ADDR(StoreBuffer::StoreBufferOverflow)));
}
ExternalReference ExternalReference::flush_icache_function(Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(CPU::FlushICache)));
}
ExternalReference ExternalReference::perform_gc_function(Isolate* isolate) {
return ExternalReference(Redirect(isolate,
FUNCTION_ADDR(Runtime::PerformGC)));
return
ExternalReference(Redirect(isolate, FUNCTION_ADDR(Runtime::PerformGC)));
}
@ -802,19 +834,8 @@ ExternalReference ExternalReference::keyed_lookup_cache_field_offsets(
}
ExternalReference ExternalReference::the_hole_value_location(Isolate* isolate) {
return ExternalReference(isolate->factory()->the_hole_value().location());
}
ExternalReference ExternalReference::arguments_marker_location(
Isolate* isolate) {
return ExternalReference(isolate->factory()->arguments_marker().location());
}
ExternalReference ExternalReference::roots_address(Isolate* isolate) {
return ExternalReference(isolate->heap()->roots_address());
ExternalReference ExternalReference::roots_array_start(Isolate* isolate) {
return ExternalReference(isolate->heap()->roots_array_start());
}
@ -840,9 +861,14 @@ ExternalReference ExternalReference::new_space_start(Isolate* isolate) {
}
ExternalReference ExternalReference::store_buffer_top(Isolate* isolate) {
return ExternalReference(isolate->heap()->store_buffer()->TopAddress());
}
ExternalReference ExternalReference::new_space_mask(Isolate* isolate) {
Address mask = reinterpret_cast<Address>(isolate->heap()->NewSpaceMask());
return ExternalReference(mask);
return ExternalReference(reinterpret_cast<Address>(
isolate->heap()->NewSpaceMask()));
}
@ -1025,6 +1051,11 @@ static double math_cos_double(double x) {
}
static double math_tan_double(double x) {
return tan(x);
}
static double math_log_double(double x) {
return log(x);
}
@ -1046,6 +1077,14 @@ ExternalReference ExternalReference::math_cos_double_function(
}
ExternalReference ExternalReference::math_tan_double_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate,
FUNCTION_ADDR(math_tan_double),
BUILTIN_FP_CALL));
}
ExternalReference ExternalReference::math_log_double_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate,
@ -1111,6 +1150,23 @@ static int native_compare_doubles(double y, double x) {
}
bool EvalComparison(Token::Value op, double op1, double op2) {
ASSERT(Token::IsCompareOp(op));
switch (op) {
case Token::EQ:
case Token::EQ_STRICT: return (op1 == op2);
case Token::NE: return (op1 != op2);
case Token::LT: return (op1 < op2);
case Token::GT: return (op1 > op2);
case Token::LTE: return (op1 <= op2);
case Token::GTE: return (op1 >= op2);
default:
UNREACHABLE();
return false;
}
}
ExternalReference ExternalReference::double_fp_operation(
Token::Value operation, Isolate* isolate) {
typedef double BinaryFPOperation(double x, double y);

86
deps/v8/src/assembler.h

@ -143,6 +143,9 @@ class Label BASE_EMBEDDED {
};
enum SaveFPRegsMode { kDontSaveFPRegs, kSaveFPRegs };
// -----------------------------------------------------------------------------
// Relocation information
@ -216,8 +219,9 @@ class RelocInfo BASE_EMBEDDED {
RelocInfo() {}
RelocInfo(byte* pc, Mode rmode, intptr_t data)
: pc_(pc), rmode_(rmode), data_(data) {
RelocInfo(byte* pc, Mode rmode, intptr_t data, Code* host)
: pc_(pc), rmode_(rmode), data_(data), host_(host) {
}
static inline bool IsConstructCall(Mode mode) {
@ -226,6 +230,9 @@ class RelocInfo BASE_EMBEDDED {
static inline bool IsCodeTarget(Mode mode) {
return mode <= LAST_CODE_ENUM;
}
static inline bool IsEmbeddedObject(Mode mode) {
return mode == EMBEDDED_OBJECT;
}
// Is the relocation mode affected by GC?
static inline bool IsGCRelocMode(Mode mode) {
return mode <= LAST_GCED_ENUM;
@ -258,6 +265,7 @@ class RelocInfo BASE_EMBEDDED {
void set_pc(byte* pc) { pc_ = pc; }
Mode rmode() const { return rmode_; }
intptr_t data() const { return data_; }
Code* host() const { return host_; }
// Apply a relocation by delta bytes
INLINE(void apply(intptr_t delta));
@ -271,14 +279,17 @@ class RelocInfo BASE_EMBEDDED {
// this relocation applies to;
// can only be called if IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY
INLINE(Address target_address());
INLINE(void set_target_address(Address target));
INLINE(void set_target_address(Address target,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER));
INLINE(Object* target_object());
INLINE(Handle<Object> target_object_handle(Assembler* origin));
INLINE(Object** target_object_address());
INLINE(void set_target_object(Object* target));
INLINE(void set_target_object(Object* target,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER));
INLINE(JSGlobalPropertyCell* target_cell());
INLINE(Handle<JSGlobalPropertyCell> target_cell_handle());
INLINE(void set_target_cell(JSGlobalPropertyCell* cell));
INLINE(void set_target_cell(JSGlobalPropertyCell* cell,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER));
// Read the address of the word containing the target_address in an
@ -353,6 +364,7 @@ class RelocInfo BASE_EMBEDDED {
byte* pc_;
Mode rmode_;
intptr_t data_;
Code* host_;
#ifdef V8_TARGET_ARCH_MIPS
// Code and Embedded Object pointers in mips are stored split
// across two consecutive 32-bit instructions. Heap management
@ -561,6 +573,13 @@ class ExternalReference BASE_EMBEDDED {
// pattern. This means that they have to be added to the
// ExternalReferenceTable in serialize.cc manually.
static ExternalReference incremental_marking_record_write_function(
Isolate* isolate);
static ExternalReference incremental_evacuation_record_write_function(
Isolate* isolate);
static ExternalReference store_buffer_overflow_function(
Isolate* isolate);
static ExternalReference flush_icache_function(Isolate* isolate);
static ExternalReference perform_gc_function(Isolate* isolate);
static ExternalReference fill_heap_number_with_random_function(
Isolate* isolate);
@ -577,14 +596,8 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference keyed_lookup_cache_keys(Isolate* isolate);
static ExternalReference keyed_lookup_cache_field_offsets(Isolate* isolate);
// Static variable Factory::the_hole_value.location()
static ExternalReference the_hole_value_location(Isolate* isolate);
// Static variable Factory::arguments_marker.location()
static ExternalReference arguments_marker_location(Isolate* isolate);
// Static variable Heap::roots_address()
static ExternalReference roots_address(Isolate* isolate);
// Static variable Heap::roots_array_start()
static ExternalReference roots_array_start(Isolate* isolate);
// Static variable StackGuard::address_of_jslimit()
static ExternalReference address_of_stack_limit(Isolate* isolate);
@ -606,6 +619,10 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference new_space_start(Isolate* isolate);
static ExternalReference new_space_mask(Isolate* isolate);
static ExternalReference heap_always_allocate_scope_depth(Isolate* isolate);
static ExternalReference new_space_mark_bits(Isolate* isolate);
// Write barrier.
static ExternalReference store_buffer_top(Isolate* isolate);
// Used for fast allocation in generated code.
static ExternalReference new_space_allocation_top_address(Isolate* isolate);
@ -635,6 +652,7 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference math_sin_double_function(Isolate* isolate);
static ExternalReference math_cos_double_function(Isolate* isolate);
static ExternalReference math_tan_double_function(Isolate* isolate);
static ExternalReference math_log_double_function(Isolate* isolate);
Address address() const {return reinterpret_cast<Address>(address_);}
@ -799,33 +817,33 @@ class PreservePositionScope BASE_EMBEDDED {
// -----------------------------------------------------------------------------
// Utility functions
static inline bool is_intn(int x, int n) {
inline bool is_intn(int x, int n) {
return -(1 << (n-1)) <= x && x < (1 << (n-1));
}
static inline bool is_int8(int x) { return is_intn(x, 8); }
static inline bool is_int16(int x) { return is_intn(x, 16); }
static inline bool is_int18(int x) { return is_intn(x, 18); }
static inline bool is_int24(int x) { return is_intn(x, 24); }
inline bool is_int8(int x) { return is_intn(x, 8); }
inline bool is_int16(int x) { return is_intn(x, 16); }
inline bool is_int18(int x) { return is_intn(x, 18); }
inline bool is_int24(int x) { return is_intn(x, 24); }
static inline bool is_uintn(int x, int n) {
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_uint10(int x) { return is_uintn(x, 10); }
static inline bool is_uint12(int x) { return is_uintn(x, 12); }
static inline bool is_uint16(int x) { return is_uintn(x, 16); }
static inline bool is_uint24(int x) { return is_uintn(x, 24); }
static inline bool is_uint26(int x) { return is_uintn(x, 26); }
static inline bool is_uint28(int x) { return is_uintn(x, 28); }
static inline int NumberOfBitsSet(uint32_t x) {
inline bool is_uint2(int x) { return is_uintn(x, 2); }
inline bool is_uint3(int x) { return is_uintn(x, 3); }
inline bool is_uint4(int x) { return is_uintn(x, 4); }
inline bool is_uint5(int x) { return is_uintn(x, 5); }
inline bool is_uint6(int x) { return is_uintn(x, 6); }
inline bool is_uint8(int x) { return is_uintn(x, 8); }
inline bool is_uint10(int x) { return is_uintn(x, 10); }
inline bool is_uint12(int x) { return is_uintn(x, 12); }
inline bool is_uint16(int x) { return is_uintn(x, 16); }
inline bool is_uint24(int x) { return is_uintn(x, 24); }
inline bool is_uint26(int x) { return is_uintn(x, 26); }
inline bool is_uint28(int x) { return is_uintn(x, 28); }
inline int NumberOfBitsSet(uint32_t x) {
unsigned int num_bits_set;
for (num_bits_set = 0; x; x >>= 1) {
num_bits_set += x & 1;
@ -833,6 +851,8 @@ static inline int NumberOfBitsSet(uint32_t x) {
return num_bits_set;
}
bool EvalComparison(Token::Value op, double op1, double op2);
// Computes pow(x, y) with the special cases in the spec for Math.pow.
double power_double_int(double x, int y);
double power_double_double(double x, double y);

121
deps/v8/src/ast-inl.h

@ -1,121 +0,0 @@
// Copyright 2011 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_AST_INL_H_
#define V8_AST_INL_H_
#include "v8.h"
#include "ast.h"
#include "scopes.h"
namespace v8 {
namespace internal {
SwitchStatement::SwitchStatement(Isolate* isolate,
ZoneStringList* labels)
: BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
tag_(NULL), cases_(NULL) {
}
Block::Block(Isolate* isolate,
ZoneStringList* labels,
int capacity,
bool is_initializer_block)
: BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY),
statements_(capacity),
is_initializer_block_(is_initializer_block),
block_scope_(NULL) {
}
BreakableStatement::BreakableStatement(Isolate* isolate,
ZoneStringList* labels,
Type type)
: labels_(labels),
type_(type),
entry_id_(GetNextId(isolate)),
exit_id_(GetNextId(isolate)) {
ASSERT(labels == NULL || labels->length() > 0);
}
IterationStatement::IterationStatement(Isolate* isolate, ZoneStringList* labels)
: BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
body_(NULL),
continue_target_(),
osr_entry_id_(GetNextId(isolate)) {
}
DoWhileStatement::DoWhileStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(isolate, labels),
cond_(NULL),
condition_position_(-1),
continue_id_(GetNextId(isolate)),
back_edge_id_(GetNextId(isolate)) {
}
WhileStatement::WhileStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(isolate, labels),
cond_(NULL),
may_have_function_literal_(true),
body_id_(GetNextId(isolate)) {
}
ForStatement::ForStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(isolate, labels),
init_(NULL),
cond_(NULL),
next_(NULL),
may_have_function_literal_(true),
loop_variable_(NULL),
continue_id_(GetNextId(isolate)),
body_id_(GetNextId(isolate)) {
}
ForInStatement::ForInStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(isolate, labels),
each_(NULL),
enumerable_(NULL),
assignment_id_(GetNextId(isolate)) {
}
bool FunctionLiteral::strict_mode() const {
return scope()->is_strict_mode();
}
} } // namespace v8::internal
#endif // V8_AST_INL_H_

199
deps/v8/src/ast.cc

@ -48,16 +48,19 @@ AST_NODE_LIST(DECL_ACCEPT)
// ----------------------------------------------------------------------------
// Implementation of other node functionality.
Assignment* ExpressionStatement::StatementAsSimpleAssignment() {
return (expression()->AsAssignment() != NULL &&
!expression()->AsAssignment()->is_compound())
? expression()->AsAssignment()
: NULL;
bool Expression::IsSmiLiteral() {
return AsLiteral() != NULL && AsLiteral()->handle()->IsSmi();
}
bool Expression::IsStringLiteral() {
return AsLiteral() != NULL && AsLiteral()->handle()->IsString();
}
CountOperation* ExpressionStatement::StatementAsCountOperation() {
return expression()->AsCountOperation();
bool Expression::IsNullLiteral() {
return AsLiteral() != NULL && AsLiteral()->handle()->IsNull();
}
@ -66,7 +69,6 @@ VariableProxy::VariableProxy(Isolate* isolate, Variable* var)
name_(var->name()),
var_(NULL), // Will be set by the call to BindTo.
is_this_(var->is_this()),
inside_with_(false),
is_trivial_(false),
position_(RelocInfo::kNoPosition) {
BindTo(var);
@ -76,13 +78,11 @@ VariableProxy::VariableProxy(Isolate* isolate, Variable* var)
VariableProxy::VariableProxy(Isolate* isolate,
Handle<String> name,
bool is_this,
bool inside_with,
int position)
: Expression(isolate),
name_(name),
var_(NULL),
is_this_(is_this),
inside_with_(inside_with),
is_trivial_(false),
position_(position) {
// Names must be canonicalized for fast equality checks.
@ -157,6 +157,21 @@ bool FunctionLiteral::AllowsLazyCompilation() {
}
int FunctionLiteral::start_position() const {
return scope()->start_position();
}
int FunctionLiteral::end_position() const {
return scope()->end_position();
}
LanguageMode FunctionLiteral::language_mode() const {
return scope()->language_mode();
}
ObjectLiteral::Property::Property(Literal* key, Expression* value) {
emit_store_ = true;
key_ = key;
@ -327,56 +342,77 @@ bool BinaryOperation::ResultOverwriteAllowed() {
}
bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
Handle<String>* check) {
if (op_ != Token::EQ && op_ != Token::EQ_STRICT) return false;
UnaryOperation* left_unary = left_->AsUnaryOperation();
UnaryOperation* right_unary = right_->AsUnaryOperation();
Literal* left_literal = left_->AsLiteral();
Literal* right_literal = right_->AsLiteral();
// Check for the pattern: typeof <expression> == <string literal>.
if (left_unary != NULL && left_unary->op() == Token::TYPEOF &&
right_literal != NULL && right_literal->handle()->IsString()) {
*expr = left_unary->expression();
*check = Handle<String>::cast(right_literal->handle());
static bool IsTypeof(Expression* expr) {
UnaryOperation* maybe_unary = expr->AsUnaryOperation();
return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
}
// Check for the pattern: typeof <expression> equals <string literal>.
static bool MatchLiteralCompareTypeof(Expression* left,
Token::Value op,
Expression* right,
Expression** expr,
Handle<String>* check) {
if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
*expr = left->AsUnaryOperation()->expression();
*check = Handle<String>::cast(right->AsLiteral()->handle());
return true;
}
return false;
}
// Check for the pattern: <string literal> == typeof <expression>.
if (right_unary != NULL && right_unary->op() == Token::TYPEOF &&
left_literal != NULL && left_literal->handle()->IsString()) {
*expr = right_unary->expression();
*check = Handle<String>::cast(left_literal->handle());
bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
Handle<String>* check) {
return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) ||
MatchLiteralCompareTypeof(right_, op_, left_, expr, check);
}
static bool IsVoidOfLiteral(Expression* expr) {
UnaryOperation* maybe_unary = expr->AsUnaryOperation();
return maybe_unary != NULL &&
maybe_unary->op() == Token::VOID &&
maybe_unary->expression()->AsLiteral() != NULL;
}
// Check for the pattern: void <literal> equals <expression>
static bool MatchLiteralCompareUndefined(Expression* left,
Token::Value op,
Expression* right,
Expression** expr) {
if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
*expr = right;
return true;
}
return false;
}
bool CompareOperation::IsLiteralCompareUndefined(Expression** expr) {
if (op_ != Token::EQ_STRICT) return false;
return MatchLiteralCompareUndefined(left_, op_, right_, expr) ||
MatchLiteralCompareUndefined(right_, op_, left_, expr);
}
UnaryOperation* left_unary = left_->AsUnaryOperation();
UnaryOperation* right_unary = right_->AsUnaryOperation();
// Check for the pattern: <expression> === void <literal>.
if (right_unary != NULL && right_unary->op() == Token::VOID &&
right_unary->expression()->AsLiteral() != NULL) {
*expr = left_;
// Check for the pattern: null equals <expression>
static bool MatchLiteralCompareNull(Expression* left,
Token::Value op,
Expression* right,
Expression** expr) {
if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
*expr = right;
return true;
}
return false;
}
// Check for the pattern: void <literal> === <expression>.
if (left_unary != NULL && left_unary->op() == Token::VOID &&
left_unary->expression()->AsLiteral() != NULL) {
*expr = right_;
return true;
}
return false;
bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
return MatchLiteralCompareNull(left_, op_, right_, expr) ||
MatchLiteralCompareNull(right_, op_, left_, expr);
}
@ -447,7 +483,7 @@ bool FunctionLiteral::IsInlineable() const {
bool ThisFunction::IsInlineable() const {
return false;
return true;
}
@ -529,7 +565,9 @@ bool Conditional::IsInlineable() const {
bool VariableProxy::IsInlineable() const {
return var()->IsUnallocated() || var()->IsStackAllocated();
return var()->IsUnallocated()
|| var()->IsStackAllocated()
|| var()->IsContextSlot();
}
@ -598,11 +636,6 @@ bool CompareOperation::IsInlineable() const {
}
bool CompareToNull::IsInlineable() const {
return expression()->IsInlineable();
}
bool CountOperation::IsInlineable() const {
return expression()->IsInlineable();
}
@ -677,6 +710,10 @@ void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
TypeInfo info = oracle->SwitchType(this);
if (info.IsSmi()) {
compare_type_ = SMI_ONLY;
} else if (info.IsSymbol()) {
compare_type_ = SYMBOL_ONLY;
} else if (info.IsNonSymbol()) {
compare_type_ = STRING_ONLY;
} else if (info.IsNonPrimitive()) {
compare_type_ = OBJECT_ONLY;
} else {
@ -705,7 +742,7 @@ bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
holder_ = Handle<JSObject>::null();
}
while (true) {
LookupResult lookup;
LookupResult lookup(type->GetIsolate());
type->LookupInDescriptors(NULL, *name, &lookup);
// If the function wasn't found directly in the map, we start
// looking upwards through the prototype chain.
@ -746,37 +783,41 @@ bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
CallKind call_kind) {
is_monomorphic_ = oracle->CallIsMonomorphic(this);
Property* property = expression()->AsProperty();
ASSERT(property != NULL);
// Specialize for the receiver types seen at runtime.
Literal* key = property->key()->AsLiteral();
ASSERT(key != NULL && key->handle()->IsString());
Handle<String> name = Handle<String>::cast(key->handle());
receiver_types_.Clear();
oracle->CallReceiverTypes(this, name, call_kind, &receiver_types_);
if (property == NULL) {
// Function call. Specialize for monomorphic calls.
if (is_monomorphic_) target_ = oracle->GetCallTarget(this);
} else {
// Method call. Specialize for the receiver types seen at runtime.
Literal* key = property->key()->AsLiteral();
ASSERT(key != NULL && key->handle()->IsString());
Handle<String> name = Handle<String>::cast(key->handle());
receiver_types_.Clear();
oracle->CallReceiverTypes(this, name, call_kind, &receiver_types_);
#ifdef DEBUG
if (FLAG_enable_slow_asserts) {
int length = receiver_types_.length();
for (int i = 0; i < length; i++) {
Handle<Map> map = receiver_types_.at(i);
ASSERT(!map.is_null() && *map != NULL);
if (FLAG_enable_slow_asserts) {
int length = receiver_types_.length();
for (int i = 0; i < length; i++) {
Handle<Map> map = receiver_types_.at(i);
ASSERT(!map.is_null() && *map != NULL);
}
}
}
#endif
is_monomorphic_ = oracle->CallIsMonomorphic(this);
check_type_ = oracle->GetCallCheckType(this);
if (is_monomorphic_) {
Handle<Map> map;
if (receiver_types_.length() > 0) {
ASSERT(check_type_ == RECEIVER_MAP_CHECK);
map = receiver_types_.at(0);
} else {
ASSERT(check_type_ != RECEIVER_MAP_CHECK);
holder_ = Handle<JSObject>(
oracle->GetPrototypeForPrimitiveCheck(check_type_));
map = Handle<Map>(holder_->map());
check_type_ = oracle->GetCallCheckType(this);
if (is_monomorphic_) {
Handle<Map> map;
if (receiver_types_.length() > 0) {
ASSERT(check_type_ == RECEIVER_MAP_CHECK);
map = receiver_types_.at(0);
} else {
ASSERT(check_type_ != RECEIVER_MAP_CHECK);
holder_ = Handle<JSObject>(
oracle->GetPrototypeForPrimitiveCheck(check_type_));
map = Handle<Map>(holder_->map());
}
is_monomorphic_ = ComputeTarget(map, name);
}
is_monomorphic_ = ComputeTarget(map, name);
}
}
@ -856,8 +897,6 @@ FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
#undef MAKE_TYPE_CASE
RegExpEmpty RegExpEmpty::kInstance;
static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) {
Interval result = Interval::Empty();

300
deps/v8/src/ast.h

@ -90,7 +90,6 @@ namespace internal {
V(CountOperation) \
V(BinaryOperation) \
V(CompareOperation) \
V(CompareToNull) \
V(ThisFunction)
#define AST_NODE_LIST(V) \
@ -119,7 +118,6 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
#define DECLARE_NODE_TYPE(type) \
virtual void Accept(AstVisitor* v); \
virtual AstNode::Type node_type() const { return AstNode::k##type; } \
virtual type* As##type() { return this; }
class AstNode: public ZoneObject {
@ -154,7 +152,8 @@ class AstNode: public ZoneObject {
// Type testing & conversion functions overridden by concrete subclasses.
#define DECLARE_NODE_FUNCTIONS(type) \
virtual type* As##type() { return NULL; }
bool Is##type() { return node_type() == AstNode::k##type; } \
type* As##type() { return Is##type() ? reinterpret_cast<type*>(this) : NULL; }
AST_NODE_LIST(DECLARE_NODE_FUNCTIONS)
#undef DECLARE_NODE_FUNCTIONS
@ -197,9 +196,6 @@ class Statement: public AstNode {
virtual Statement* AsStatement() { return this; }
virtual Assignment* StatementAsSimpleAssignment() { return NULL; }
virtual CountOperation* StatementAsCountOperation() { return NULL; }
bool IsEmpty() { return AsEmptyStatement() != NULL; }
void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; }
@ -265,7 +261,6 @@ class Expression: public AstNode {
virtual Expression* AsExpression() { return this; }
virtual bool IsTrivial() { return false; }
virtual bool IsValidLeftHandSide() { return false; }
// Helpers for ToBoolean conversion.
@ -277,27 +272,24 @@ class Expression: public AstNode {
// names because [] for string objects is handled only by keyed ICs.
virtual bool IsPropertyName() { return false; }
// Mark the expression as being compiled as an expression
// statement. This is used to transform postfix increments to
// (faster) prefix increments.
virtual void MarkAsStatement() { /* do nothing */ }
// True iff the result can be safely overwritten (to avoid allocation).
// False for operations that can return one of their operands.
virtual bool ResultOverwriteAllowed() { return false; }
// True iff the expression is a literal represented as a smi.
virtual bool IsSmiLiteral() { return false; }
bool IsSmiLiteral();
// True iff the expression is a string literal.
bool IsStringLiteral();
// True iff the expression is the null literal.
bool IsNullLiteral();
// Type feedback information for assignments and properties.
virtual bool IsMonomorphic() {
UNREACHABLE();
return false;
}
virtual bool IsArrayLength() {
UNREACHABLE();
return false;
}
virtual SmallMapList* GetReceiverTypes() {
UNREACHABLE();
return NULL;
@ -343,7 +335,14 @@ class BreakableStatement: public Statement {
int ExitId() const { return exit_id_; }
protected:
BreakableStatement(Isolate* isolate, ZoneStringList* labels, Type type);
BreakableStatement(Isolate* isolate, ZoneStringList* labels, Type type)
: labels_(labels),
type_(type),
entry_id_(GetNextId(isolate)),
exit_id_(GetNextId(isolate)) {
ASSERT(labels == NULL || labels->length() > 0);
}
private:
ZoneStringList* labels_;
@ -356,22 +355,18 @@ class BreakableStatement: public Statement {
class Block: public BreakableStatement {
public:
inline Block(Isolate* isolate,
ZoneStringList* labels,
int capacity,
bool is_initializer_block);
DECLARE_NODE_TYPE(Block)
virtual Assignment* StatementAsSimpleAssignment() {
if (statements_.length() != 1) return NULL;
return statements_[0]->StatementAsSimpleAssignment();
Block(Isolate* isolate,
ZoneStringList* labels,
int capacity,
bool is_initializer_block)
: BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY),
statements_(capacity),
is_initializer_block_(is_initializer_block),
block_scope_(NULL) {
}
virtual CountOperation* StatementAsCountOperation() {
if (statements_.length() != 1) return NULL;
return statements_[0]->StatementAsCountOperation();
}
DECLARE_NODE_TYPE(Block)
virtual bool IsInlineable() const;
@ -393,31 +388,32 @@ class Block: public BreakableStatement {
class Declaration: public AstNode {
public:
Declaration(VariableProxy* proxy,
Variable::Mode mode,
VariableMode mode,
FunctionLiteral* fun,
Scope* scope)
: proxy_(proxy),
mode_(mode),
fun_(fun),
scope_(scope) {
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
ASSERT(mode == VAR ||
mode == CONST ||
mode == CONST_HARMONY ||
mode == LET);
// At the moment there are no "const functions"'s in JavaScript...
ASSERT(fun == NULL || mode == Variable::VAR || mode == Variable::LET);
ASSERT(fun == NULL || mode == VAR || mode == LET);
}
DECLARE_NODE_TYPE(Declaration)
VariableProxy* proxy() const { return proxy_; }
Variable::Mode mode() const { return mode_; }
VariableMode mode() const { return mode_; }
FunctionLiteral* fun() const { return fun_; } // may be NULL
virtual bool IsInlineable() const;
Scope* scope() const { return scope_; }
private:
VariableProxy* proxy_;
Variable::Mode mode_;
VariableMode mode_;
FunctionLiteral* fun_;
// Nested scope from which the declaration originated.
@ -441,7 +437,11 @@ class IterationStatement: public BreakableStatement {
Label* continue_target() { return &continue_target_; }
protected:
inline IterationStatement(Isolate* isolate, ZoneStringList* labels);
IterationStatement(Isolate* isolate, ZoneStringList* labels)
: BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
body_(NULL),
osr_entry_id_(GetNextId(isolate)) {
}
void Initialize(Statement* body) {
body_ = body;
@ -456,7 +456,13 @@ class IterationStatement: public BreakableStatement {
class DoWhileStatement: public IterationStatement {
public:
inline DoWhileStatement(Isolate* isolate, ZoneStringList* labels);
DoWhileStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(isolate, labels),
cond_(NULL),
condition_position_(-1),
continue_id_(GetNextId(isolate)),
back_edge_id_(GetNextId(isolate)) {
}
DECLARE_NODE_TYPE(DoWhileStatement)
@ -489,7 +495,12 @@ class DoWhileStatement: public IterationStatement {
class WhileStatement: public IterationStatement {
public:
inline WhileStatement(Isolate* isolate, ZoneStringList* labels);
WhileStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(isolate, labels),
cond_(NULL),
may_have_function_literal_(true),
body_id_(GetNextId(isolate)) {
}
DECLARE_NODE_TYPE(WhileStatement)
@ -522,7 +533,16 @@ class WhileStatement: public IterationStatement {
class ForStatement: public IterationStatement {
public:
inline ForStatement(Isolate* isolate, ZoneStringList* labels);
ForStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(isolate, labels),
init_(NULL),
cond_(NULL),
next_(NULL),
may_have_function_literal_(true),
loop_variable_(NULL),
continue_id_(GetNextId(isolate)),
body_id_(GetNextId(isolate)) {
}
DECLARE_NODE_TYPE(ForStatement)
@ -571,7 +591,12 @@ class ForStatement: public IterationStatement {
class ForInStatement: public IterationStatement {
public:
inline ForInStatement(Isolate* isolate, ZoneStringList* labels);
ForInStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(isolate, labels),
each_(NULL),
enumerable_(NULL),
assignment_id_(GetNextId(isolate)) {
}
DECLARE_NODE_TYPE(ForInStatement)
@ -606,9 +631,6 @@ class ExpressionStatement: public Statement {
virtual bool IsInlineable() const;
virtual Assignment* StatementAsSimpleAssignment();
virtual CountOperation* StatementAsCountOperation();
void set_expression(Expression* e) { expression_ = e; }
Expression* expression() const { return expression_; }
@ -704,6 +726,8 @@ class CaseClause: public ZoneObject {
// Type feedback information.
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
bool IsSmiCompare() { return compare_type_ == SMI_ONLY; }
bool IsSymbolCompare() { return compare_type_ == SYMBOL_ONLY; }
bool IsStringCompare() { return compare_type_ == STRING_ONLY; }
bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; }
private:
@ -711,7 +735,13 @@ class CaseClause: public ZoneObject {
Label body_target_;
ZoneList<Statement*>* statements_;
int position_;
enum CompareTypeFeedback { NONE, SMI_ONLY, OBJECT_ONLY };
enum CompareTypeFeedback {
NONE,
SMI_ONLY,
SYMBOL_ONLY,
STRING_ONLY,
OBJECT_ONLY
};
CompareTypeFeedback compare_type_;
int compare_id_;
int entry_id_;
@ -720,7 +750,12 @@ class CaseClause: public ZoneObject {
class SwitchStatement: public BreakableStatement {
public:
inline SwitchStatement(Isolate* isolate, ZoneStringList* labels);
SwitchStatement(Isolate* isolate, ZoneStringList* labels)
: BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
tag_(NULL),
cases_(NULL) {
}
DECLARE_NODE_TYPE(SwitchStatement)
@ -808,18 +843,25 @@ class TargetCollector: public AstNode {
class TryStatement: public Statement {
public:
explicit TryStatement(Block* try_block)
: try_block_(try_block), escaping_targets_(NULL) { }
explicit TryStatement(int index, Block* try_block)
: index_(index),
try_block_(try_block),
escaping_targets_(NULL) {
}
void set_escaping_targets(ZoneList<Label*>* targets) {
escaping_targets_ = targets;
}
int index() const { return index_; }
Block* try_block() const { return try_block_; }
ZoneList<Label*>* escaping_targets() const { return escaping_targets_; }
virtual bool IsInlineable() const;
private:
// Unique (per-function) index of this handler. This is not an AST ID.
int index_;
Block* try_block_;
ZoneList<Label*>* escaping_targets_;
};
@ -827,11 +869,12 @@ class TryStatement: public Statement {
class TryCatchStatement: public TryStatement {
public:
TryCatchStatement(Block* try_block,
TryCatchStatement(int index,
Block* try_block,
Scope* scope,
Variable* variable,
Block* catch_block)
: TryStatement(try_block),
: TryStatement(index, try_block),
scope_(scope),
variable_(variable),
catch_block_(catch_block) {
@ -853,8 +896,8 @@ class TryCatchStatement: public TryStatement {
class TryFinallyStatement: public TryStatement {
public:
TryFinallyStatement(Block* try_block, Block* finally_block)
: TryStatement(try_block),
TryFinallyStatement(int index, Block* try_block, Block* finally_block)
: TryStatement(index, try_block),
finally_block_(finally_block) { }
DECLARE_NODE_TYPE(TryFinallyStatement)
@ -889,9 +932,6 @@ class Literal: public Expression {
DECLARE_NODE_TYPE(Literal)
virtual bool IsTrivial() { return true; }
virtual bool IsSmiLiteral() { return handle_->IsSmi(); }
// Check if this literal is identical to the other literal.
bool IsIdenticalTo(const Literal* other) const {
return handle_.is_identical_to(other->handle_);
@ -1100,18 +1140,17 @@ class VariableProxy: public Expression {
public:
VariableProxy(Isolate* isolate, Variable* var);
VariableProxy(Isolate* isolate,
Handle<String> name,
bool is_this,
int position = RelocInfo::kNoPosition);
DECLARE_NODE_TYPE(VariableProxy)
virtual bool IsValidLeftHandSide() {
return var_ == NULL ? true : var_->IsValidLeftHandSide();
}
virtual bool IsTrivial() {
// Reading from a mutable variable is a side effect, but the
// variable for 'this' is immutable.
return is_this_ || is_trivial_;
}
virtual bool IsInlineable() const;
bool IsVariable(Handle<String> n) {
@ -1123,7 +1162,6 @@ class VariableProxy: public Expression {
Handle<String> name() const { return name_; }
Variable* var() const { return var_; }
bool is_this() const { return is_this_; }
bool inside_with() const { return inside_with_; }
int position() const { return position_; }
void MarkAsTrivial() { is_trivial_ = true; }
@ -1135,17 +1173,8 @@ class VariableProxy: public Expression {
Handle<String> name_;
Variable* var_; // resolved variable, or NULL
bool is_this_;
bool inside_with_;
bool is_trivial_;
int position_;
VariableProxy(Isolate* isolate,
Handle<String> name,
bool is_this,
bool inside_with,
int position = RelocInfo::kNoPosition);
friend class Scope;
};
@ -1182,7 +1211,7 @@ class Property: public Expression {
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
virtual bool IsMonomorphic() { return is_monomorphic_; }
virtual SmallMapList* GetReceiverTypes() { return &receiver_types_; }
virtual bool IsArrayLength() { return is_array_length_; }
bool IsArrayLength() { return is_array_length_; }
private:
Expression* obj_;
@ -1320,8 +1349,17 @@ class UnaryOperation: public Expression {
Token::Value op,
Expression* expression,
int pos)
: Expression(isolate), op_(op), expression_(expression), pos_(pos) {
: Expression(isolate),
op_(op),
expression_(expression),
pos_(pos),
materialize_true_id_(AstNode::kNoNumber),
materialize_false_id_(AstNode::kNoNumber) {
ASSERT(Token::IsUnaryOp(op));
if (op == Token::NOT) {
materialize_true_id_ = GetNextId(isolate);
materialize_false_id_ = GetNextId(isolate);
}
}
DECLARE_NODE_TYPE(UnaryOperation)
@ -1334,10 +1372,18 @@ class UnaryOperation: public Expression {
Expression* expression() const { return expression_; }
virtual int position() const { return pos_; }
int MaterializeTrueId() { return materialize_true_id_; }
int MaterializeFalseId() { return materialize_false_id_; }
private:
Token::Value op_;
Expression* expression_;
int pos_;
// For unary not (Token::NOT), the AST ids where true and false will
// actually be materialized, respectively.
int materialize_true_id_;
int materialize_false_id_;
};
@ -1465,6 +1511,7 @@ class CompareOperation: public Expression {
// Match special cases.
bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
bool IsLiteralCompareUndefined(Expression** expr);
bool IsLiteralCompareNull(Expression** expr);
private:
Token::Value op_;
@ -1477,25 +1524,6 @@ class CompareOperation: public Expression {
};
class CompareToNull: public Expression {
public:
CompareToNull(Isolate* isolate, bool is_strict, Expression* expression)
: Expression(isolate), is_strict_(is_strict), expression_(expression) { }
DECLARE_NODE_TYPE(CompareToNull)
virtual bool IsInlineable() const;
bool is_strict() const { return is_strict_; }
Token::Value op() const { return is_strict_ ? Token::EQ_STRICT : Token::EQ; }
Expression* expression() const { return expression_; }
private:
bool is_strict_;
Expression* expression_;
};
class Conditional: public Expression {
public:
Conditional(Isolate* isolate,
@ -1630,31 +1658,30 @@ class FunctionLiteral: public Expression {
ZoneList<Statement*>* body,
int materialized_literal_count,
int expected_property_count,
int handler_count,
bool has_only_simple_this_property_assignments,
Handle<FixedArray> this_property_assignments,
int num_parameters,
int start_position,
int end_position,
int parameter_count,
Type type,
bool has_duplicate_parameters)
: Expression(isolate),
name_(name),
scope_(scope),
body_(body),
this_property_assignments_(this_property_assignments),
inferred_name_(isolate->factory()->empty_string()),
materialized_literal_count_(materialized_literal_count),
expected_property_count_(expected_property_count),
has_only_simple_this_property_assignments_(
has_only_simple_this_property_assignments),
this_property_assignments_(this_property_assignments),
num_parameters_(num_parameters),
start_position_(start_position),
end_position_(end_position),
function_token_position_(RelocInfo::kNoPosition),
inferred_name_(HEAP->empty_string()),
is_expression_(type != DECLARATION),
is_anonymous_(type == ANONYMOUS_EXPRESSION),
pretenure_(false),
has_duplicate_parameters_(has_duplicate_parameters) {
handler_count_(handler_count),
parameter_count_(parameter_count),
function_token_position_(RelocInfo::kNoPosition) {
bitfield_ =
HasOnlySimpleThisPropertyAssignments::encode(
has_only_simple_this_property_assignments) |
IsExpression::encode(type != DECLARATION) |
IsAnonymous::encode(type == ANONYMOUS_EXPRESSION) |
Pretenure::encode(false) |
HasDuplicateParameters::encode(has_duplicate_parameters);
}
DECLARE_NODE_TYPE(FunctionLiteral)
@ -1664,21 +1691,23 @@ class FunctionLiteral: public Expression {
ZoneList<Statement*>* body() const { return body_; }
void set_function_token_position(int pos) { function_token_position_ = pos; }
int function_token_position() const { return function_token_position_; }
int start_position() const { return start_position_; }
int end_position() const { return end_position_; }
bool is_expression() const { return is_expression_; }
bool is_anonymous() const { return is_anonymous_; }
bool strict_mode() const;
int start_position() const;
int end_position() const;
bool is_expression() const { return IsExpression::decode(bitfield_); }
bool is_anonymous() const { return IsAnonymous::decode(bitfield_); }
bool is_classic_mode() const { return language_mode() == CLASSIC_MODE; }
LanguageMode language_mode() const;
int materialized_literal_count() { return materialized_literal_count_; }
int expected_property_count() { return expected_property_count_; }
int handler_count() { return handler_count_; }
bool has_only_simple_this_property_assignments() {
return has_only_simple_this_property_assignments_;
return HasOnlySimpleThisPropertyAssignments::decode(bitfield_);
}
Handle<FixedArray> this_property_assignments() {
return this_property_assignments_;
}
int num_parameters() { return num_parameters_; }
int parameter_count() { return parameter_count_; }
bool AllowsLazyCompilation();
@ -1692,29 +1721,33 @@ class FunctionLiteral: public Expression {
inferred_name_ = inferred_name;
}
bool pretenure() { return pretenure_; }
void set_pretenure(bool value) { pretenure_ = value; }
bool pretenure() { return Pretenure::decode(bitfield_); }
void set_pretenure() { bitfield_ |= Pretenure::encode(true); }
virtual bool IsInlineable() const;
bool has_duplicate_parameters() { return has_duplicate_parameters_; }
bool has_duplicate_parameters() {
return HasDuplicateParameters::decode(bitfield_);
}
private:
Handle<String> name_;
Scope* scope_;
ZoneList<Statement*>* body_;
Handle<FixedArray> this_property_assignments_;
Handle<String> inferred_name_;
int materialized_literal_count_;
int expected_property_count_;
bool has_only_simple_this_property_assignments_;
Handle<FixedArray> this_property_assignments_;
int num_parameters_;
int start_position_;
int end_position_;
int handler_count_;
int parameter_count_;
int function_token_position_;
Handle<String> inferred_name_;
bool is_expression_;
bool is_anonymous_;
bool pretenure_;
bool has_duplicate_parameters_;
unsigned bitfield_;
class HasOnlySimpleThisPropertyAssignments: public BitField<bool, 0, 1> {};
class IsExpression: public BitField<bool, 1, 1> {};
class IsAnonymous: public BitField<bool, 2, 1> {};
class Pretenure: public BitField<bool, 3, 1> {};
class HasDuplicateParameters: public BitField<bool, 4, 1> {};
};
@ -2096,9 +2129,10 @@ class RegExpEmpty: public RegExpTree {
virtual bool IsEmpty();
virtual int min_match() { return 0; }
virtual int max_match() { return 0; }
static RegExpEmpty* GetInstance() { return &kInstance; }
private:
static RegExpEmpty kInstance;
static RegExpEmpty* GetInstance() {
static RegExpEmpty* instance = ::new RegExpEmpty();
return instance;
}
};

48
deps/v8/src/atomicops_internals_mips_gcc.h

@ -30,7 +30,7 @@
#ifndef V8_ATOMICOPS_INTERNALS_MIPS_GCC_H_
#define V8_ATOMICOPS_INTERNALS_MIPS_GCC_H_
#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("sync" : : : "memory")
#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
namespace v8 {
namespace internal {
@ -48,16 +48,19 @@ namespace internal {
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
Atomic32 prev;
__asm__ __volatile__("1:\n"
"ll %0, %1\n" // prev = *ptr
Atomic32 prev, tmp;
__asm__ __volatile__(".set push\n"
".set noreorder\n"
"1:\n"
"ll %0, %5\n" // prev = *ptr
"bne %0, %3, 2f\n" // if (prev != old_value) goto 2
"nop\n" // delay slot nop
"sc %2, %1\n" // *ptr = new_value (with atomic check)
"move %2, %4\n" // tmp = new_value
"sc %2, %1\n" // *ptr = tmp (with atomic check)
"beqz %2, 1b\n" // start again on atomic error
"nop\n" // delay slot nop
"2:\n"
: "=&r" (prev), "=m" (*ptr), "+&r" (new_value)
".set pop\n"
: "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
: "Ir" (old_value), "r" (new_value), "m" (*ptr)
: "memory");
return prev;
@ -68,12 +71,15 @@ inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
Atomic32 new_value) {
Atomic32 temp, old;
__asm__ __volatile__("1:\n"
__asm__ __volatile__(".set push\n"
".set noreorder\n"
"1:\n"
"ll %1, %2\n" // old = *ptr
"move %0, %3\n" // temp = new_value
"sc %0, %2\n" // *ptr = temp (with atomic check)
"beqz %0, 1b\n" // start again on atomic error
"nop\n" // delay slot nop
".set pop\n"
: "=&r" (temp), "=&r" (old), "=m" (*ptr)
: "r" (new_value), "m" (*ptr)
: "memory");
@ -87,13 +93,15 @@ inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
Atomic32 increment) {
Atomic32 temp, temp2;
__asm__ __volatile__("1:\n"
__asm__ __volatile__(".set push\n"
".set noreorder\n"
"1:\n"
"ll %0, %2\n" // temp = *ptr
"addu %0, %3\n" // temp = temp + increment
"move %1, %0\n" // temp2 = temp
"sc %0, %2\n" // *ptr = temp (with atomic check)
"beqz %0, 1b\n" // start again on atomic error
"nop\n" // delay slot nop
"addu %1, %0, %3\n" // temp2 = temp + increment
"sc %1, %2\n" // *ptr = temp2 (with atomic check)
"beqz %1, 1b\n" // start again on atomic error
"addu %1, %0, %3\n" // temp2 = temp + increment
".set pop\n"
: "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
: "Ir" (increment), "m" (*ptr)
: "memory");
@ -103,6 +111,7 @@ inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
Atomic32 increment) {
ATOMICOPS_COMPILER_BARRIER();
Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
ATOMICOPS_COMPILER_BARRIER();
return res;
@ -117,16 +126,19 @@ inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
ATOMICOPS_COMPILER_BARRIER();
return x;
Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
ATOMICOPS_COMPILER_BARRIER();
return res;
}
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
ATOMICOPS_COMPILER_BARRIER();
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
ATOMICOPS_COMPILER_BARRIER();
return res;
}
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
@ -134,7 +146,7 @@ inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
}
inline void MemoryBarrier() {
ATOMICOPS_COMPILER_BARRIER();
__asm__ __volatile__("sync" : : : "memory");
}
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {

288
deps/v8/src/bootstrapper.cc

@ -34,9 +34,11 @@
#include "debug.h"
#include "execution.h"
#include "global-handles.h"
#include "isolate-inl.h"
#include "macro-assembler.h"
#include "natives.h"
#include "objects-visiting.h"
#include "platform.h"
#include "snapshot.h"
#include "extensions/externalize-string-extension.h"
#include "extensions/gc-extension.h"
@ -209,12 +211,31 @@ class Genesis BASE_EMBEDDED {
void InstallBuiltinFunctionIds();
void InstallJSFunctionResultCaches();
void InitializeNormalizedMapCaches();
enum ExtensionTraversalState {
UNVISITED, VISITED, INSTALLED
};
class ExtensionStates {
public:
ExtensionStates();
ExtensionTraversalState get_state(RegisteredExtension* extension);
void set_state(RegisteredExtension* extension,
ExtensionTraversalState state);
private:
Allocator allocator_;
HashMap map_;
DISALLOW_COPY_AND_ASSIGN(ExtensionStates);
};
// Used both for deserialized and from-scratch contexts to add the extensions
// provided.
static bool InstallExtensions(Handle<Context> global_context,
v8::ExtensionConfiguration* extensions);
static bool InstallExtension(const char* name);
static bool InstallExtension(v8::RegisteredExtension* current);
static bool InstallExtension(const char* name,
ExtensionStates* extension_states);
static bool InstallExtension(v8::RegisteredExtension* current,
ExtensionStates* extension_states);
static void InstallSpecialObjects(Handle<Context> global_context);
bool InstallJSBuiltins(Handle<JSBuiltinsObject> builtins);
bool ConfigureApiObject(Handle<JSObject> object,
@ -361,6 +382,7 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
if (is_ecma_native) {
function->shared()->set_instance_class_name(*symbol);
}
function->shared()->set_native(true);
return function;
}
@ -374,26 +396,28 @@ Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
PropertyAttributes attributes =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
DescriptorArray::WhitenessWitness witness(*descriptors);
{ // Add length.
Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionLength);
CallbacksDescriptor d(*factory()->length_symbol(), *foreign, attributes);
descriptors->Set(0, &d);
descriptors->Set(0, &d, witness);
}
{ // Add name.
Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionName);
CallbacksDescriptor d(*factory()->name_symbol(), *foreign, attributes);
descriptors->Set(1, &d);
descriptors->Set(1, &d, witness);
}
{ // Add arguments.
Handle<Foreign> foreign =
factory()->NewForeign(&Accessors::FunctionArguments);
CallbacksDescriptor d(*factory()->arguments_symbol(), *foreign, attributes);
descriptors->Set(2, &d);
descriptors->Set(2, &d, witness);
}
{ // Add caller.
Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionCaller);
CallbacksDescriptor d(*factory()->caller_symbol(), *foreign, attributes);
descriptors->Set(3, &d);
descriptors->Set(3, &d, witness);
}
if (prototypeMode != DONT_ADD_PROTOTYPE) {
// Add prototype.
@ -403,9 +427,9 @@ Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
Handle<Foreign> foreign =
factory()->NewForeign(&Accessors::FunctionPrototype);
CallbacksDescriptor d(*factory()->prototype_symbol(), *foreign, attributes);
descriptors->Set(4, &d);
descriptors->Set(4, &d, witness);
}
descriptors->Sort();
descriptors->Sort(witness);
return descriptors;
}
@ -478,7 +502,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
// 262 15.3.4.
Handle<String> symbol = factory->LookupAsciiSymbol("Empty");
Handle<JSFunction> empty_function =
factory->NewFunctionWithoutPrototype(symbol, kNonStrictMode);
factory->NewFunctionWithoutPrototype(symbol, CLASSIC_MODE);
// --- E m p t y ---
Handle<Code> code =
@ -521,41 +545,43 @@ Handle<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
? 4
: 5);
PropertyAttributes attributes = static_cast<PropertyAttributes>(
DONT_ENUM | DONT_DELETE | READ_ONLY);
DONT_ENUM | DONT_DELETE);
DescriptorArray::WhitenessWitness witness(*descriptors);
{ // length
Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionLength);
CallbacksDescriptor d(*factory()->length_symbol(), *foreign, attributes);
descriptors->Set(0, &d);
descriptors->Set(0, &d, witness);
}
{ // name
Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionName);
CallbacksDescriptor d(*factory()->name_symbol(), *foreign, attributes);
descriptors->Set(1, &d);
descriptors->Set(1, &d, witness);
}
{ // arguments
CallbacksDescriptor d(*factory()->arguments_symbol(),
*arguments,
attributes);
descriptors->Set(2, &d);
descriptors->Set(2, &d, witness);
}
{ // caller
CallbacksDescriptor d(*factory()->caller_symbol(), *caller, attributes);
descriptors->Set(3, &d);
descriptors->Set(3, &d, witness);
}
// prototype
if (prototypeMode != DONT_ADD_PROTOTYPE) {
if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
attributes = static_cast<PropertyAttributes>(attributes & ~READ_ONLY);
if (prototypeMode != ADD_WRITEABLE_PROTOTYPE) {
attributes = static_cast<PropertyAttributes>(attributes | READ_ONLY);
}
Handle<Foreign> foreign =
factory()->NewForeign(&Accessors::FunctionPrototype);
CallbacksDescriptor d(*factory()->prototype_symbol(), *foreign, attributes);
descriptors->Set(4, &d);
descriptors->Set(4, &d, witness);
}
descriptors->Sort();
descriptors->Sort(witness);
return descriptors;
}
@ -565,7 +591,7 @@ Handle<JSFunction> Genesis::GetThrowTypeErrorFunction() {
if (throw_type_error_function.is_null()) {
Handle<String> name = factory()->LookupAsciiSymbol("ThrowTypeError");
throw_type_error_function =
factory()->NewFunctionWithoutPrototype(name, kNonStrictMode);
factory()->NewFunctionWithoutPrototype(name, CLASSIC_MODE);
Handle<Code> code(isolate()->builtins()->builtin(
Builtins::kStrictModePoisonPill));
throw_type_error_function->set_map(
@ -940,6 +966,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
ASSERT_EQ(0, initial_map->inobject_properties());
Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(5);
DescriptorArray::WhitenessWitness witness(*descriptors);
PropertyAttributes final =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
int enum_index = 0;
@ -949,7 +976,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
JSRegExp::kSourceFieldIndex,
final,
enum_index++);
descriptors->Set(0, &field);
descriptors->Set(0, &field, witness);
}
{
// ECMA-262, section 15.10.7.2.
@ -957,7 +984,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
JSRegExp::kGlobalFieldIndex,
final,
enum_index++);
descriptors->Set(1, &field);
descriptors->Set(1, &field, witness);
}
{
// ECMA-262, section 15.10.7.3.
@ -965,7 +992,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
JSRegExp::kIgnoreCaseFieldIndex,
final,
enum_index++);
descriptors->Set(2, &field);
descriptors->Set(2, &field, witness);
}
{
// ECMA-262, section 15.10.7.4.
@ -973,7 +1000,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
JSRegExp::kMultilineFieldIndex,
final,
enum_index++);
descriptors->Set(3, &field);
descriptors->Set(3, &field, witness);
}
{
// ECMA-262, section 15.10.7.5.
@ -983,10 +1010,10 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
JSRegExp::kLastIndexFieldIndex,
writable,
enum_index++);
descriptors->Set(4, &field);
descriptors->Set(4, &field, witness);
}
descriptors->SetNextEnumerationIndex(enum_index);
descriptors->Sort();
descriptors->Sort(witness);
initial_map->set_inobject_properties(5);
initial_map->set_pre_allocated_property_fields(5);
@ -995,6 +1022,26 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
initial_map->instance_size() + 5 * kPointerSize);
initial_map->set_instance_descriptors(*descriptors);
initial_map->set_visitor_id(StaticVisitorBase::GetVisitorId(*initial_map));
// RegExp prototype object is itself a RegExp.
Handle<Map> proto_map = factory->CopyMapDropTransitions(initial_map);
proto_map->set_prototype(global_context()->initial_object_prototype());
Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map);
proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex,
heap->empty_string());
proto->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex,
heap->false_value());
proto->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex,
heap->false_value());
proto->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex,
heap->false_value());
proto->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
Smi::FromInt(0),
SKIP_WRITE_BARRIER); // It's a Smi.
initial_map->set_prototype(*proto);
factory->SetRegExpIrregexpData(Handle<JSRegExp>::cast(proto),
JSRegExp::IRREGEXP, factory->empty_string(),
JSRegExp::Flags(0), 0);
}
{ // -- J S O N
@ -1044,7 +1091,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
DONT_ENUM);
#ifdef DEBUG
LookupResult lookup;
LookupResult lookup(isolate);
result->LocalLookup(heap->callee_symbol(), &lookup);
ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsCalleeIndex);
@ -1063,11 +1110,6 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
}
{ // --- aliased_arguments_boilerplate_
Handle<Map> old_map(global_context()->arguments_boilerplate()->map());
Handle<Map> new_map = factory->CopyMapDropTransitions(old_map);
new_map->set_pre_allocated_property_fields(2);
Handle<JSObject> result = factory->NewJSObjectFromMap(new_map);
new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
// Set up a well-formed parameter map to make assertions happy.
Handle<FixedArray> elements = factory->NewFixedArray(2);
elements->set_map(heap->non_strict_arguments_elements_map());
@ -1076,7 +1118,16 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
elements->set(0, *array);
array = factory->NewFixedArray(0);
elements->set(1, *array);
Handle<Map> old_map(global_context()->arguments_boilerplate()->map());
Handle<Map> new_map = factory->CopyMapDropTransitions(old_map);
new_map->set_pre_allocated_property_fields(2);
Handle<JSObject> result = factory->NewJSObjectFromMap(new_map);
// Set elements kind after allocating the object because
// NewJSObjectFromMap assumes a fast elements map.
new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
result->set_elements(*elements);
ASSERT(result->HasNonStrictArgumentsElements());
global_context()->set_aliased_arguments_boilerplate(*result);
}
@ -1099,19 +1150,20 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// Create the descriptor array for the arguments object.
Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(3);
DescriptorArray::WhitenessWitness witness(*descriptors);
{ // length
FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM);
descriptors->Set(0, &d);
descriptors->Set(0, &d, witness);
}
{ // callee
CallbacksDescriptor d(*factory->callee_symbol(), *callee, attributes);
descriptors->Set(1, &d);
descriptors->Set(1, &d, witness);
}
{ // caller
CallbacksDescriptor d(*factory->caller_symbol(), *caller, attributes);
descriptors->Set(2, &d);
descriptors->Set(2, &d, witness);
}
descriptors->Sort();
descriptors->Sort(witness);
// Create the map. Allocate one in-object field for length.
Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE,
@ -1136,7 +1188,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
DONT_ENUM);
#ifdef DEBUG
LookupResult lookup;
LookupResult lookup(isolate);
result->LocalLookup(heap->length_symbol(), &lookup);
ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex);
@ -1195,6 +1247,14 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// Initialize the data slot.
global_context()->set_data(heap->undefined_value());
{
// Initialize the random seed slot.
Handle<ByteArray> zeroed_byte_array(
factory->NewByteArray(kRandomStateSize));
global_context()->set_random_seed(*zeroed_byte_array);
memset(zeroed_byte_array->GetDataStartAddress(), 0, kRandomStateSize);
}
}
@ -1202,12 +1262,26 @@ void Genesis::InitializeExperimentalGlobal() {
Handle<JSObject> global = Handle<JSObject>(global_context()->global());
// TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no
// longer need to live behind a flag, so WeakMap gets added to the snapshot.
if (FLAG_harmony_weakmaps) { // -- W e a k M a p
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
prototype, Builtins::kIllegal, true);
// longer need to live behind a flag, so functions get added to the snapshot.
if (FLAG_harmony_collections) {
{ // -- S e t
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize,
prototype, Builtins::kIllegal, true);
}
{ // -- M a p
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize,
prototype, Builtins::kIllegal, true);
}
{ // -- W e a k M a p
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
prototype, Builtins::kIllegal, true);
}
}
}
@ -1327,6 +1401,8 @@ void Genesis::InstallNativeFunctions() {
configure_instance_fun);
INSTALL_NATIVE(JSFunction, "GetStackTraceLine", get_stack_trace_line_fun);
INSTALL_NATIVE(JSObject, "functionCache", function_cache);
INSTALL_NATIVE(JSFunction, "ToCompletePropertyDescriptor",
to_complete_property_descriptor);
}
void Genesis::InstallExperimentalNativeFunctions() {
@ -1334,6 +1410,7 @@ void Genesis::InstallExperimentalNativeFunctions() {
INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate);
}
}
@ -1555,6 +1632,18 @@ bool Genesis::InstallNatives() {
isolate()->builtins()->builtin(Builtins::kArrayConstructCode));
array_function->shared()->DontAdaptArguments();
// InternalArrays should not use Smi-Only array optimizations. There are too
// many places in the C++ runtime code (e.g. RegEx) that assume that
// elements in InternalArrays can be set to non-Smi values without going
// through a common bottleneck that would make the SMI_ONLY -> FAST_ELEMENT
// transition easy to trap. Moreover, they rarely are smi-only.
MaybeObject* maybe_map =
array_function->initial_map()->CopyDropTransitions();
Map* new_map;
if (!maybe_map->To<Map>(&new_map)) return maybe_map;
new_map->set_elements_kind(FAST_ELEMENTS);
array_function->set_initial_map(new_map);
// Make "length" magic on instances.
Handle<DescriptorArray> array_descriptors =
factory()->CopyAppendForeignDescriptor(
@ -1656,7 +1745,9 @@ bool Genesis::InstallNatives() {
Handle<DescriptorArray> reresult_descriptors =
factory()->NewDescriptorArray(3);
reresult_descriptors->CopyFrom(0, *array_descriptors, 0);
DescriptorArray::WhitenessWitness witness(*reresult_descriptors);
reresult_descriptors->CopyFrom(0, *array_descriptors, 0, witness);
int enum_index = 0;
{
@ -1664,7 +1755,7 @@ bool Genesis::InstallNatives() {
JSRegExpResult::kIndexIndex,
NONE,
enum_index++);
reresult_descriptors->Set(1, &index_field);
reresult_descriptors->Set(1, &index_field, witness);
}
{
@ -1672,9 +1763,9 @@ bool Genesis::InstallNatives() {
JSRegExpResult::kInputIndex,
NONE,
enum_index++);
reresult_descriptors->Set(2, &input_field);
reresult_descriptors->Set(2, &input_field, witness);
}
reresult_descriptors->Sort();
reresult_descriptors->Sort(witness);
initial_map->set_inobject_properties(2);
initial_map->set_pre_allocated_property_fields(2);
@ -1701,9 +1792,9 @@ bool Genesis::InstallExperimentalNatives() {
"native proxy.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
if (FLAG_harmony_weakmaps &&
if (FLAG_harmony_collections &&
strcmp(ExperimentalNatives::GetScriptName(i).start(),
"native weakmap.js") == 0) {
"native collection.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
}
@ -1863,6 +1954,34 @@ void Genesis::InstallSpecialObjects(Handle<Context> global_context) {
#endif
}
static uint32_t Hash(RegisteredExtension* extension) {
return v8::internal::ComputePointerHash(extension);
}
static bool MatchRegisteredExtensions(void* key1, void* key2) {
return key1 == key2;
}
Genesis::ExtensionStates::ExtensionStates()
: allocator_(),
map_(MatchRegisteredExtensions, &allocator_, 8)
{}
Genesis::ExtensionTraversalState Genesis::ExtensionStates::get_state(
RegisteredExtension* extension) {
i::HashMap::Entry* entry = map_.Lookup(extension, Hash(extension), false);
if (entry == NULL) {
return UNVISITED;
}
return static_cast<ExtensionTraversalState>(
reinterpret_cast<intptr_t>(entry->value));
}
void Genesis::ExtensionStates::set_state(RegisteredExtension* extension,
ExtensionTraversalState state) {
map_.Lookup(extension, Hash(extension), true)->value =
reinterpret_cast<void*>(static_cast<intptr_t>(state));
}
bool Genesis::InstallExtensions(Handle<Context> global_context,
v8::ExtensionConfiguration* extensions) {
@ -1870,29 +1989,27 @@ bool Genesis::InstallExtensions(Handle<Context> global_context,
// effort. (The external API reads 'ignore'-- does that mean
// we can break the interface?)
// Clear coloring of extension list
v8::RegisteredExtension* current = v8::RegisteredExtension::first_extension();
while (current != NULL) {
current->set_state(v8::UNVISITED);
current = current->next();
}
ExtensionStates extension_states; // All extensions have state UNVISITED.
// Install auto extensions.
current = v8::RegisteredExtension::first_extension();
v8::RegisteredExtension* current = v8::RegisteredExtension::first_extension();
while (current != NULL) {
if (current->extension()->auto_enable())
InstallExtension(current);
InstallExtension(current, &extension_states);
current = current->next();
}
if (FLAG_expose_gc) InstallExtension("v8/gc");
if (FLAG_expose_externalize_string) InstallExtension("v8/externalize");
if (FLAG_expose_gc) InstallExtension("v8/gc", &extension_states);
if (FLAG_expose_externalize_string) {
InstallExtension("v8/externalize", &extension_states);
}
if (extensions == NULL) return true;
// Install required extensions
int count = v8::ImplementationUtilities::GetNameCount(extensions);
const char** names = v8::ImplementationUtilities::GetNames(extensions);
for (int i = 0; i < count; i++) {
if (!InstallExtension(names[i]))
if (!InstallExtension(names[i], &extension_states))
return false;
}
@ -1902,7 +2019,8 @@ bool Genesis::InstallExtensions(Handle<Context> global_context,
// Installs a named extension. This methods is unoptimized and does
// not scale well if we want to support a large number of extensions.
bool Genesis::InstallExtension(const char* name) {
bool Genesis::InstallExtension(const char* name,
ExtensionStates* extension_states) {
v8::RegisteredExtension* current = v8::RegisteredExtension::first_extension();
// Loop until we find the relevant extension
while (current != NULL) {
@ -1915,42 +2033,52 @@ bool Genesis::InstallExtension(const char* name) {
"v8::Context::New()", "Cannot find required extension");
return false;
}
return InstallExtension(current);
return InstallExtension(current, extension_states);
}
bool Genesis::InstallExtension(v8::RegisteredExtension* current) {
bool Genesis::InstallExtension(v8::RegisteredExtension* current,
ExtensionStates* extension_states) {
HandleScope scope;
if (current->state() == v8::INSTALLED) return true;
if (extension_states->get_state(current) == INSTALLED) return true;
// The current node has already been visited so there must be a
// cycle in the dependency graph; fail.
if (current->state() == v8::VISITED) {
if (extension_states->get_state(current) == VISITED) {
v8::Utils::ReportApiFailure(
"v8::Context::New()", "Circular extension dependency");
return false;
}
ASSERT(current->state() == v8::UNVISITED);
current->set_state(v8::VISITED);
ASSERT(extension_states->get_state(current) == UNVISITED);
extension_states->set_state(current, VISITED);
v8::Extension* extension = current->extension();
// Install the extension's dependencies
for (int i = 0; i < extension->dependency_count(); i++) {
if (!InstallExtension(extension->dependencies()[i])) return false;
if (!InstallExtension(extension->dependencies()[i], extension_states))
return false;
}
Isolate* isolate = Isolate::Current();
Vector<const char> source = CStrVector(extension->source());
Handle<String> source_code = isolate->factory()->NewStringFromAscii(source);
bool result = CompileScriptCached(CStrVector(extension->name()),
source_code,
isolate->bootstrapper()->extensions_cache(),
extension,
Handle<Context>(isolate->context()),
false);
Handle<String> source_code =
isolate->factory()->NewExternalStringFromAscii(extension->source());
bool result = CompileScriptCached(
CStrVector(extension->name()),
source_code,
isolate->bootstrapper()->extensions_cache(),
extension,
Handle<Context>(isolate->context()),
false);
ASSERT(isolate->has_pending_exception() != result);
if (!result) {
// We print out the name of the extension that fail to install.
// When an error is thrown during bootstrapping we automatically print
// the line number at which this happened to the console in the isolate
// error throwing functionality.
OS::PrintError("Error installing extension '%s'.\n",
current->extension()->name());
isolate->clear_pending_exception();
}
current->set_state(v8::INSTALLED);
extension_states->set_state(current, INSTALLED);
isolate->NotifyExtensionInstalled();
return result;
}
@ -1967,7 +2095,9 @@ bool Genesis::InstallJSBuiltins(Handle<JSBuiltinsObject> builtins) {
builtins->set_javascript_builtin(id, *function);
Handle<SharedFunctionInfo> shared
= Handle<SharedFunctionInfo>(function->shared());
if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
if (!SharedFunctionInfo::EnsureCompiled(shared, CLEAR_EXCEPTION)) {
return false;
}
// Set the code object on the function object.
function->ReplaceCode(function->shared()->code());
builtins->set_javascript_builtin_code(id, shared->code());
@ -2047,7 +2177,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
break;
}
case CALLBACKS: {
LookupResult result;
LookupResult result(isolate());
to->LocalLookup(descs->GetKey(i), &result);
// If the property is already there we skip it
if (result.IsProperty()) continue;
@ -2085,7 +2215,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
if (properties->IsKey(raw_key)) {
ASSERT(raw_key->IsString());
// If the property is already there we skip it.
LookupResult result;
LookupResult result(isolate());
to->LocalLookup(String::cast(raw_key), &result);
if (result.IsProperty()) continue;
// Set the property.

178
deps/v8/src/builtins.cc

@ -33,6 +33,7 @@
#include "builtins.h"
#include "gdb-jit.h"
#include "ic-inl.h"
#include "mark-compact.h"
#include "vm-state-inl.h"
namespace v8 {
@ -202,7 +203,7 @@ BUILTIN(ArrayCodeGeneric) {
}
// 'array' now contains the JSArray we should initialize.
ASSERT(array->HasFastElements());
ASSERT(array->HasFastTypeElements());
// Optimize the case where there is one argument and the argument is a
// small smi.
@ -215,7 +216,8 @@ BUILTIN(ArrayCodeGeneric) {
{ MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
array->SetContent(FixedArray::cast(obj));
MaybeObject* maybe_obj = array->SetContent(FixedArray::cast(obj));
if (maybe_obj->IsFailure()) return maybe_obj;
return array;
}
}
@ -239,6 +241,11 @@ BUILTIN(ArrayCodeGeneric) {
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
// Set length and elements on the array.
MaybeObject* maybe_object =
array->EnsureCanContainElements(FixedArray::cast(obj));
if (maybe_object->IsFailure()) return maybe_object;
AssertNoAllocation no_gc;
FixedArray* elms = FixedArray::cast(obj);
WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
@ -247,7 +254,6 @@ BUILTIN(ArrayCodeGeneric) {
elms->set(index, args[index+1], mode);
}
// Set length and elements on the array.
array->set_elements(FixedArray::cast(obj));
array->set_length(len);
@ -295,6 +301,7 @@ static void CopyElements(Heap* heap,
if (mode == UPDATE_WRITE_BARRIER) {
heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
}
heap->incremental_marking()->RecordWrites(dst);
}
@ -313,6 +320,7 @@ static void MoveElements(Heap* heap,
if (mode == UPDATE_WRITE_BARRIER) {
heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
}
heap->incremental_marking()->RecordWrites(dst);
}
@ -358,6 +366,14 @@ static FixedArray* LeftTrimFixedArray(Heap* heap,
former_start[to_trim] = heap->fixed_array_map();
former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
// Maintain marking consistency for HeapObjectIterator and
// IncrementalMarking.
int size_delta = to_trim * kPointerSize;
if (heap->marking()->TransferMark(elms->address(),
elms->address() + size_delta)) {
MemoryChunk::IncrementLiveBytes(elms->address(), -size_delta);
}
return FixedArray::cast(HeapObject::FromAddress(
elms->address() + to_trim * kPointerSize));
}
@ -369,9 +385,6 @@ static bool ArrayPrototypeHasNoElements(Heap* heap,
// This method depends on non writability of Object and Array prototype
// fields.
if (array_proto->elements() != heap->empty_fixed_array()) return false;
// Hidden prototype
array_proto = JSObject::cast(array_proto->GetPrototype());
ASSERT(array_proto->elements() == heap->empty_fixed_array());
// Object.prototype
Object* proto = array_proto->GetPrototype();
if (proto == heap->null_value()) return false;
@ -384,20 +397,42 @@ static bool ArrayPrototypeHasNoElements(Heap* heap,
MUST_USE_RESULT
static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
Heap* heap, Object* receiver) {
Heap* heap, Object* receiver, Arguments* args, int first_added_arg) {
if (!receiver->IsJSArray()) return NULL;
JSArray* array = JSArray::cast(receiver);
HeapObject* elms = array->elements();
if (elms->map() == heap->fixed_array_map()) return elms;
if (elms->map() == heap->fixed_cow_array_map()) {
return array->EnsureWritableFastElements();
Map* map = elms->map();
if (map == heap->fixed_array_map()) {
if (args == NULL || !array->HasFastSmiOnlyElements()) {
return elms;
}
} else if (map == heap->fixed_cow_array_map()) {
MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
if (args == NULL || !array->HasFastSmiOnlyElements() ||
maybe_writable_result->IsFailure()) {
return maybe_writable_result;
}
} else {
return NULL;
}
return NULL;
// Need to ensure that the arguments passed in args can be contained in
// the array.
int args_length = args->length();
if (first_added_arg >= args_length) return array->elements();
MaybeObject* maybe_array = array->EnsureCanContainElements(
args,
first_added_arg,
args_length - first_added_arg);
if (maybe_array->IsFailure()) return maybe_array;
return array->elements();
}
static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
JSArray* receiver) {
if (!FLAG_clever_optimizations) return false;
Context* global_context = heap->isolate()->context()->global_context();
JSObject* array_proto =
JSObject::cast(global_context->array_function()->prototype());
@ -413,20 +448,18 @@ MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
HandleScope handleScope(isolate);
Handle<Object> js_builtin =
GetProperty(Handle<JSObject>(
isolate->global_context()->builtins()),
name);
ASSERT(js_builtin->IsJSFunction());
Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
ScopedVector<Object**> argv(args.length() - 1);
int n_args = args.length() - 1;
for (int i = 0; i < n_args; i++) {
argv[i] = args.at<Object>(i + 1).location();
}
bool pending_exception = false;
GetProperty(Handle<JSObject>(isolate->global_context()->builtins()),
name);
Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
int argc = args.length() - 1;
ScopedVector<Handle<Object> > argv(argc);
for (int i = 0; i < argc; ++i) {
argv[i] = args.at<Object>(i + 1);
}
bool pending_exception;
Handle<Object> result = Execution::Call(function,
args.receiver(),
n_args,
argc,
argv.start(),
&pending_exception);
if (pending_exception) return Failure::Exception();
@ -439,7 +472,7 @@ BUILTIN(ArrayPush) {
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(heap, receiver);
EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
if (maybe_elms_obj == NULL) {
return CallJsBuiltin(isolate, "ArrayPush", args);
}
@ -475,7 +508,6 @@ BUILTIN(ArrayPush) {
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
}
// Add the provided values.
@ -485,6 +517,10 @@ BUILTIN(ArrayPush) {
elms->set(index + len, args[index + 1], mode);
}
if (elms != array->elements()) {
array->set_elements(elms);
}
// Set the length.
array->set_length(Smi::FromInt(new_length));
return Smi::FromInt(new_length);
@ -496,7 +532,7 @@ BUILTIN(ArrayPop) {
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(heap, receiver);
EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
}
@ -529,7 +565,7 @@ BUILTIN(ArrayShift) {
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(heap, receiver);
EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
if (maybe_elms_obj == NULL)
return CallJsBuiltin(isolate, "ArrayShift", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
@ -539,7 +575,7 @@ BUILTIN(ArrayShift) {
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastElements());
ASSERT(array->HasFastTypeElements());
int len = Smi::cast(array->length())->value();
if (len == 0) return heap->undefined_value();
@ -551,9 +587,7 @@ BUILTIN(ArrayShift) {
}
if (!heap->lo_space()->Contains(elms)) {
// As elms still in the same space they used to be,
// there is no need to update region dirty mark.
array->set_elements(LeftTrimFixedArray(heap, elms, 1), SKIP_WRITE_BARRIER);
array->set_elements(LeftTrimFixedArray(heap, elms, 1));
} else {
// Shift the elements.
AssertNoAllocation no_gc;
@ -573,7 +607,7 @@ BUILTIN(ArrayUnshift) {
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(heap, receiver);
EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
if (maybe_elms_obj == NULL)
return CallJsBuiltin(isolate, "ArrayUnshift", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
@ -583,7 +617,7 @@ BUILTIN(ArrayUnshift) {
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastElements());
ASSERT(array->HasFastTypeElements());
int len = Smi::cast(array->length())->value();
int to_add = args.length() - 1;
@ -592,6 +626,10 @@ BUILTIN(ArrayUnshift) {
// we should never hit this case.
ASSERT(to_add <= (Smi::kMaxValue - len));
MaybeObject* maybe_object =
array->EnsureCanContainElements(&args, 1, to_add);
if (maybe_object->IsFailure()) return maybe_object;
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
@ -600,13 +638,11 @@ BUILTIN(ArrayUnshift) {
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* new_elms = FixedArray::cast(obj);
AssertNoAllocation no_gc;
if (len > 0) {
CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len);
}
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
} else {
@ -634,7 +670,7 @@ BUILTIN(ArraySlice) {
int len = -1;
if (receiver->IsJSArray()) {
JSArray* array = JSArray::cast(receiver);
if (!array->HasFastElements() ||
if (!array->HasFastTypeElements() ||
!IsJSArrayFastElementMovingAllowed(heap, array)) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@ -650,7 +686,7 @@ BUILTIN(ArraySlice) {
bool is_arguments_object_with_fast_elements =
receiver->IsJSObject()
&& JSObject::cast(receiver)->map() == arguments_map
&& JSObject::cast(receiver)->HasFastElements();
&& JSObject::cast(receiver)->HasFastTypeElements();
if (!is_arguments_object_with_fast_elements) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@ -721,6 +757,10 @@ BUILTIN(ArraySlice) {
}
FixedArray* result_elms = FixedArray::cast(result);
MaybeObject* maybe_object =
result_array->EnsureCanContainElements(result_elms);
if (maybe_object->IsFailure()) return maybe_object;
AssertNoAllocation no_gc;
CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len);
@ -729,6 +769,14 @@ BUILTIN(ArraySlice) {
// Set the length.
result_array->set_length(Smi::FromInt(result_len));
// Set the ElementsKind.
ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(),
elements_kind)) {
MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind);
if (maybe->IsFailure()) return maybe;
}
return result_array;
}
@ -738,7 +786,7 @@ BUILTIN(ArraySplice) {
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(heap, receiver);
EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
if (maybe_elms_obj == NULL)
return CallJsBuiltin(isolate, "ArraySplice", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
@ -748,7 +796,7 @@ BUILTIN(ArraySplice) {
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastElements());
ASSERT(array->HasFastTypeElements());
int len = Smi::cast(array->length())->value();
@ -822,12 +870,20 @@ BUILTIN(ArraySplice) {
// Set the length.
result_array->set_length(Smi::FromInt(actual_delete_count));
// Set the ElementsKind.
ElementsKind elements_kind = array->GetElementsKind();
if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(),
elements_kind)) {
MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind);
if (maybe->IsFailure()) return maybe;
}
}
int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
int new_length = len - actual_delete_count + item_count;
bool elms_changed = false;
if (item_count < actual_delete_count) {
// Shrink the array.
const bool trim_array = !heap->lo_space()->Contains(elms) &&
@ -842,7 +898,8 @@ BUILTIN(ArraySplice) {
}
elms = LeftTrimFixedArray(heap, elms, delta);
array->set_elements(elms, SKIP_WRITE_BARRIER);
elms_changed = true;
} else {
AssertNoAllocation no_gc;
MoveElements(heap, &no_gc,
@ -882,7 +939,7 @@ BUILTIN(ArraySplice) {
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
elms_changed = true;
} else {
AssertNoAllocation no_gc;
MoveElements(heap, &no_gc,
@ -898,6 +955,10 @@ BUILTIN(ArraySplice) {
elms->set(k, args[3 + k - actual_start], mode);
}
if (elms_changed) {
array->set_elements(elms);
}
// Set the length.
array->set_length(Smi::FromInt(new_length));
@ -920,7 +981,7 @@ BUILTIN(ArrayConcat) {
int result_len = 0;
for (int i = 0; i < n_arguments; i++) {
Object* arg = args[i];
if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastTypeElements()
|| JSArray::cast(arg)->GetPrototype() != array_proto) {
return CallJsBuiltin(isolate, "ArrayConcat", args);
}
@ -956,6 +1017,17 @@ BUILTIN(ArrayConcat) {
}
FixedArray* result_elms = FixedArray::cast(result);
// Ensure element type transitions happen before copying elements in.
if (result_array->HasFastSmiOnlyElements()) {
for (int i = 0; i < n_arguments; i++) {
JSArray* array = JSArray::cast(args[i]);
if (!array->HasFastSmiOnlyElements()) {
result_array->EnsureCanContainNonSmiElements();
break;
}
}
}
// Copy data.
AssertNoAllocation no_gc;
int start_pos = 0;
@ -1448,6 +1520,14 @@ static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) {
KeyedStoreIC::GenerateNonStrictArguments(masm);
}
static void Generate_TransitionElementsSmiToDouble(MacroAssembler* masm) {
KeyedStoreIC::GenerateTransitionElementsSmiToDouble(masm);
}
static void Generate_TransitionElementsDoubleToObject(MacroAssembler* masm) {
KeyedStoreIC::GenerateTransitionElementsDoubleToObject(masm);
}
#ifdef ENABLE_DEBUGGER_SUPPORT
static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
Debug::GenerateLoadICDebugBreak(masm);
@ -1479,8 +1559,8 @@ static void Generate_Return_DebugBreak(MacroAssembler* masm) {
}
static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
Debug::GenerateStubNoRegistersDebugBreak(masm);
static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
Debug::GenerateCallFunctionStubDebugBreak(masm);
}
@ -1607,20 +1687,22 @@ void Builtins::Setup(bool create_heap_objects) {
const BuiltinDesc* functions = BuiltinFunctionTable::functions();
// For now we generate builtin adaptor code into a stack-allocated
// buffer, before copying it into individual code objects.
byte buffer[4*KB];
// buffer, before copying it into individual code objects. Be careful
// with alignment, some platforms don't like unaligned code.
union { int force_alignment; byte buffer[4*KB]; } u;
// Traverse the list of builtins and generate an adaptor in a
// separate code object for each one.
for (int i = 0; i < builtin_count; i++) {
if (create_heap_objects) {
MacroAssembler masm(isolate, buffer, sizeof buffer);
MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
// Generate the code/adaptor.
typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
// We pass all arguments to the generator, but it may not use all of
// them. This works because the first arguments are on top of the
// stack.
ASSERT(!masm.has_frame());
g(&masm, functions[i].name, functions[i].extra_args);
// Move the code into the object heap.
CodeDesc desc;

47
deps/v8/src/builtins.h

@ -167,6 +167,10 @@ enum BuiltinExtraArguments {
kStrictMode) \
V(KeyedStoreIC_NonStrictArguments, KEYED_STORE_IC, MEGAMORPHIC, \
Code::kNoExtraICState) \
V(TransitionElementsSmiToDouble, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(TransitionElementsDoubleToObject, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
\
/* Uses KeyedLoadIC_Initialize; must be after in list. */ \
V(FunctionCall, BUILTIN, UNINITIALIZED, \
@ -188,27 +192,27 @@ enum BuiltinExtraArguments {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Define list of builtins used by the debugger implemented in assembly.
#define BUILTIN_LIST_DEBUG_A(V) \
V(Return_DebugBreak, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(FrameDropper_LiveEdit, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState)
#define BUILTIN_LIST_DEBUG_A(V) \
V(Return_DebugBreak, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(CallFunctionStub_DebugBreak, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState) \
V(FrameDropper_LiveEdit, BUILTIN, DEBUG_BREAK, \
Code::kNoExtraICState)
#else
#define BUILTIN_LIST_DEBUG_A(V)
#endif
@ -234,7 +238,6 @@ enum BuiltinExtraArguments {
V(DELETE, 2) \
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) \

8
deps/v8/src/bytecodes-irregexp.h

@ -1,4 +1,4 @@
// Copyright 2008-2009 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -33,12 +33,12 @@ namespace v8 {
namespace internal {
static const int BYTECODE_MASK = 0xff;
const int BYTECODE_MASK = 0xff;
// The first argument is packed in with the byte code in one word, but so it
// has 24 bits, but it can be positive and negative so only use 23 bits for
// positive values.
static const unsigned int MAX_FIRST_ARG = 0x7fffffu;
static const int BYTECODE_SHIFT = 8;
const unsigned int MAX_FIRST_ARG = 0x7fffffu;
const int BYTECODE_SHIFT = 8;
#define BYTECODE_ITERATOR(V) \
V(BREAK, 0, 4) /* bc8 */ \

12
deps/v8/src/cached-powers.cc

@ -134,14 +134,12 @@ static const CachedPower kCachedPowers[] = {
};
static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers);
static const int kCachedPowersOffset = -kCachedPowers[0].decimal_exponent;
static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent.
static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10)
const int PowersOfTenCache::kDecimalExponentDistance =
kCachedPowers[1].decimal_exponent - kCachedPowers[0].decimal_exponent;
const int PowersOfTenCache::kMinDecimalExponent =
kCachedPowers[0].decimal_exponent;
const int PowersOfTenCache::kMaxDecimalExponent =
kCachedPowers[kCachedPowersLength - 1].decimal_exponent;
// Difference between the decimal exponents in the table above.
const int PowersOfTenCache::kDecimalExponentDistance = 8;
const int PowersOfTenCache::kMinDecimalExponent = -348;
const int PowersOfTenCache::kMaxDecimalExponent = 340;
void PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
int min_exponent,

4
deps/v8/src/char-predicates-inl.h

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -52,7 +52,7 @@ inline bool IsLineFeed(uc32 c) {
}
static inline bool IsInRange(int value, int lower_limit, int higher_limit) {
inline bool IsInRange(int value, int lower_limit, int higher_limit) {
ASSERT(lower_limit <= higher_limit);
return static_cast<unsigned int>(value - lower_limit) <=
static_cast<unsigned int>(higher_limit - lower_limit);

121
deps/v8/src/checks.h

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -52,10 +52,10 @@ extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
// Used by the CHECK macro -- should not be called directly.
static inline void CheckHelper(const char* file,
int line,
const char* source,
bool condition) {
inline void CheckHelper(const char* file,
int line,
const char* source,
bool condition) {
if (!condition)
V8_Fatal(file, line, "CHECK(%s) failed", source);
}
@ -63,14 +63,16 @@ static inline void CheckHelper(const char* file,
// The CHECK macro checks that the given condition is true; if not, it
// prints a message to stderr and aborts.
#define CHECK(condition) CheckHelper(__FILE__, __LINE__, #condition, condition)
#define CHECK(condition) do { \
if (!(condition)) CheckHelper(__FILE__, __LINE__, #condition, false); \
} while (0)
// Helper function used by the CHECK_EQ function when given int
// arguments. Should not be called directly.
static inline void CheckEqualsHelper(const char* file, int line,
const char* expected_source, int expected,
const char* value_source, int value) {
inline void CheckEqualsHelper(const char* file, int line,
const char* expected_source, int expected,
const char* value_source, int value) {
if (expected != value) {
V8_Fatal(file, line,
"CHECK_EQ(%s, %s) failed\n# Expected: %i\n# Found: %i",
@ -81,11 +83,11 @@ static inline void CheckEqualsHelper(const char* file, int line,
// Helper function used by the CHECK_EQ function when given int64_t
// arguments. Should not be called directly.
static inline void CheckEqualsHelper(const char* file, int line,
const char* expected_source,
int64_t expected,
const char* value_source,
int64_t value) {
inline void CheckEqualsHelper(const char* file, int line,
const char* expected_source,
int64_t expected,
const char* value_source,
int64_t value) {
if (expected != value) {
// Print int64_t values in hex, as two int32s,
// to avoid platform-dependencies.
@ -103,12 +105,12 @@ static inline void CheckEqualsHelper(const char* file, int line,
// Helper function used by the CHECK_NE function when given int
// arguments. Should not be called directly.
static inline void CheckNonEqualsHelper(const char* file,
int line,
const char* unexpected_source,
int unexpected,
const char* value_source,
int value) {
inline void CheckNonEqualsHelper(const char* file,
int line,
const char* unexpected_source,
int unexpected,
const char* value_source,
int value) {
if (unexpected == value) {
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %i",
unexpected_source, value_source, value);
@ -118,12 +120,12 @@ static inline void CheckNonEqualsHelper(const char* file,
// Helper function used by the CHECK function when given string
// arguments. Should not be called directly.
static inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
const char* expected,
const char* value_source,
const char* value) {
inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
const char* expected,
const char* value_source,
const char* value) {
if ((expected == NULL && value != NULL) ||
(expected != NULL && value == NULL) ||
(expected != NULL && value != NULL && strcmp(expected, value) != 0)) {
@ -134,12 +136,12 @@ static inline void CheckEqualsHelper(const char* file,
}
static inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
const char* expected,
const char* value_source,
const char* value) {
inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
const char* expected,
const char* value_source,
const char* value) {
if (expected == value ||
(expected != NULL && value != NULL && strcmp(expected, value) == 0)) {
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %s",
@ -150,12 +152,12 @@ static inline void CheckNonEqualsHelper(const char* file,
// Helper function used by the CHECK function when given pointer
// arguments. Should not be called directly.
static inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
const void* expected,
const char* value_source,
const void* value) {
inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
const void* expected,
const char* value_source,
const void* value) {
if (expected != value) {
V8_Fatal(file, line,
"CHECK_EQ(%s, %s) failed\n# Expected: %p\n# Found: %p",
@ -165,12 +167,12 @@ static inline void CheckEqualsHelper(const char* file,
}
static inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
const void* expected,
const char* value_source,
const void* value) {
inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
const void* expected,
const char* value_source,
const void* value) {
if (expected == value) {
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",
expected_source, value_source, value);
@ -180,12 +182,12 @@ static inline void CheckNonEqualsHelper(const char* file,
// Helper function used by the CHECK function when given floating
// point arguments. Should not be called directly.
static inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
double expected,
const char* value_source,
double value) {
inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
double expected,
const char* value_source,
double value) {
// Force values to 64 bit memory to truncate 80 bit precision on IA32.
volatile double* exp = new double[1];
*exp = expected;
@ -201,12 +203,12 @@ static inline void CheckEqualsHelper(const char* file,
}
static inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
double expected,
const char* value_source,
double value) {
inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
double expected,
const char* value_source,
double value) {
// Force values to 64 bit memory to truncate 80 bit precision on IA32.
volatile double* exp = new double[1];
*exp = expected;
@ -257,11 +259,8 @@ template <int> class StaticAssertionHelper { };
SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__)
namespace v8 { namespace internal {
extern bool FLAG_enable_slow_asserts;
bool EnableSlowAsserts();
} } // namespace v8::internal
// The ASSERT macro is equivalent to CHECK except that it only
// generates code in debug builds.
@ -273,7 +272,7 @@ bool EnableSlowAsserts();
#define ASSERT_GE(v1, v2) CHECK_GE(v1, v2)
#define ASSERT_LT(v1, v2) CHECK_LT(v1, v2)
#define ASSERT_LE(v1, v2) CHECK_LE(v1, v2)
#define SLOW_ASSERT(condition) if (EnableSlowAsserts()) CHECK(condition)
#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)
#else
#define ASSERT_RESULT(expr) (expr)
#define ASSERT(condition) ((void) 0)

113
deps/v8/src/code-stubs.cc

@ -52,11 +52,12 @@ void CodeStub::GenerateCode(MacroAssembler* masm) {
// Update the static counter each time a new code stub is generated.
masm->isolate()->counters()->code_stubs()->Increment();
// Nested stubs are not allowed for leafs.
AllowStubCallsScope allow_scope(masm, AllowsStubCalls());
// Nested stubs are not allowed for leaves.
AllowStubCallsScope allow_scope(masm, false);
// Generate the code for the stub.
masm->set_generating_stub(true);
NoCurrentFrameScope scope(masm);
Generate(masm);
}
@ -118,7 +119,7 @@ Handle<Code> CodeStub::GetCode() {
Handle<Code> new_object = factory->NewCode(
desc, flags, masm.CodeObject(), NeedsImmovableCode());
RecordCodeGeneration(*new_object, &masm);
FinishCode(*new_object);
FinishCode(new_object);
// Update the dictionary and the root in Heap.
Handle<NumberDictionary> dict =
@ -127,8 +128,10 @@ Handle<Code> CodeStub::GetCode() {
GetKey(),
new_object);
heap->public_set_code_stubs(*dict);
code = *new_object;
Activate(code);
} else {
CHECK(IsPregenerated() == code->is_pregenerated());
}
ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code));
@ -136,43 +139,6 @@ Handle<Code> CodeStub::GetCode() {
}
MaybeObject* CodeStub::TryGetCode() {
Code* code;
if (!FindCodeInCache(&code)) {
// Generate the new code.
MacroAssembler masm(Isolate::Current(), NULL, 256);
GenerateCode(&masm);
Heap* heap = masm.isolate()->heap();
// Create the code object.
CodeDesc desc;
masm.GetCode(&desc);
// Try to copy the generated code into a heap object.
Code::Flags flags = Code::ComputeFlags(
static_cast<Code::Kind>(GetCodeKind()),
GetICState());
Object* new_object;
{ MaybeObject* maybe_new_object =
heap->CreateCode(desc, flags, masm.CodeObject());
if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
}
code = Code::cast(new_object);
RecordCodeGeneration(code, &masm);
FinishCode(code);
// Try to update the code cache but do not fail if unable.
MaybeObject* maybe_new_object =
heap->code_stubs()->AtNumberPut(GetKey(), code);
if (maybe_new_object->ToObject(&new_object)) {
heap->public_set_code_stubs(NumberDictionary::cast(new_object));
}
}
return code;
}
const char* CodeStub::MajorName(CodeStub::Major major_key,
bool allow_unknown_keys) {
switch (major_key) {
@ -188,6 +154,11 @@ const char* CodeStub::MajorName(CodeStub::Major major_key,
}
void CodeStub::PrintName(StringStream* stream) {
stream->Add("%s", MajorName(MajorKey(), false));
}
int ICCompareStub::MinorKey() {
return OpField::encode(op_ - Token::EQ) | StateField::encode(state_);
}
@ -242,9 +213,18 @@ void InstanceofStub::PrintName(StringStream* stream) {
}
void JSEntryStub::FinishCode(Handle<Code> code) {
Handle<FixedArray> handler_table =
code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
handler_table->set(0, Smi::FromInt(handler_offset_));
code->set_handler_table(*handler_table);
}
void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
case FAST_ELEMENTS:
case FAST_SMI_ONLY_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
break;
case FAST_DOUBLE_ELEMENTS:
@ -274,7 +254,11 @@ void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
case FAST_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
case FAST_SMI_ONLY_ELEMENTS: {
KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
is_js_array_,
elements_kind_);
}
break;
case FAST_DOUBLE_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
@ -302,24 +286,20 @@ void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
void ArgumentsAccessStub::PrintName(StringStream* stream) {
const char* type_name = NULL; // Make g++ happy.
stream->Add("ArgumentsAccessStub_");
switch (type_) {
case READ_ELEMENT: type_name = "ReadElement"; break;
case NEW_NON_STRICT_FAST: type_name = "NewNonStrictFast"; break;
case NEW_NON_STRICT_SLOW: type_name = "NewNonStrictSlow"; break;
case NEW_STRICT: type_name = "NewStrict"; break;
case READ_ELEMENT: stream->Add("ReadElement"); break;
case NEW_NON_STRICT_FAST: stream->Add("NewNonStrictFast"); break;
case NEW_NON_STRICT_SLOW: stream->Add("NewNonStrictSlow"); break;
case NEW_STRICT: stream->Add("NewStrict"); break;
}
stream->Add("ArgumentsAccessStub_%s", type_name);
}
void CallFunctionStub::PrintName(StringStream* stream) {
const char* flags_name = NULL; // Make g++ happy.
switch (flags_) {
case NO_CALL_FUNCTION_FLAGS: flags_name = ""; break;
case RECEIVER_MIGHT_BE_IMPLICIT: flags_name = "_Implicit"; break;
}
stream->Add("CallFunctionStub_Args%d%s", argc_, flags_name);
stream->Add("CallFunctionStub_Args%d", argc_);
if (ReceiverMightBeImplicit()) stream->Add("_Implicit");
if (RecordCallTarget()) stream->Add("_Recording");
}
@ -402,4 +382,29 @@ bool ToBooleanStub::Types::CanBeUndetectable() const {
}
void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
Label fail;
if (!FLAG_trace_elements_transitions) {
if (to_ == FAST_ELEMENTS) {
if (from_ == FAST_SMI_ONLY_ELEMENTS) {
ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
} else if (from_ == FAST_DOUBLE_ELEMENTS) {
ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
} else {
UNREACHABLE();
}
KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
is_jsarray_,
FAST_ELEMENTS);
} else if (from_ == FAST_SMI_ONLY_ELEMENTS && to_ == FAST_DOUBLE_ELEMENTS) {
ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm, is_jsarray_);
} else {
UNREACHABLE();
}
}
masm->bind(&fail);
KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
}
} } // namespace v8::internal

249
deps/v8/src/code-stubs.h

@ -30,6 +30,7 @@
#include "allocation.h"
#include "globals.h"
#include "codegen.h"
namespace v8 {
namespace internal {
@ -45,27 +46,22 @@ namespace internal {
V(Compare) \
V(CompareIC) \
V(MathPow) \
V(RecordWrite) \
V(StoreBufferOverflow) \
V(RegExpExec) \
V(TranscendentalCache) \
V(Instanceof) \
/* All stubs above this line only exist in a few versions, which are */ \
/* generated ahead of time. Therefore compiling a call to one of */ \
/* them can't cause a new stub to be compiled, so compiling a call to */ \
/* them is GC safe. The ones below this line exist in many variants */ \
/* so code compiling a call to one can cause a GC. This means they */ \
/* can't be called from other stubs, since stub generation code is */ \
/* not GC safe. */ \
V(ConvertToDouble) \
V(WriteInt32ToHeapNumber) \
V(StackCheck) \
V(FastNewClosure) \
V(FastNewContext) \
V(FastNewBlockContext) \
V(FastCloneShallowArray) \
V(RevertToNumber) \
V(FastCloneShallowObject) \
V(ToBoolean) \
V(ToNumber) \
V(CounterOp) \
V(ArgumentsAccess) \
V(RegExpExec) \
V(RegExpConstructResult) \
V(NumberToString) \
V(CEntry) \
@ -73,7 +69,9 @@ namespace internal {
V(KeyedLoadElement) \
V(KeyedStoreElement) \
V(DebuggerStatement) \
V(StringDictionaryNegativeLookup)
V(StringDictionaryLookup) \
V(ElementsTransitionAndStore) \
V(StoreArrayLiteralElement)
// List of code stubs only used on ARM platforms.
#ifdef V8_TARGET_ARCH_ARM
@ -121,11 +119,6 @@ class CodeStub BASE_EMBEDDED {
// Retrieve the code for the stub. Generate the code if needed.
Handle<Code> GetCode();
// Retrieve the code for the stub if already generated. Do not
// generate the code if not already generated and instead return a
// retry after GC Failure object.
MUST_USE_RESULT MaybeObject* TryGetCode();
static Major MajorKeyFromKey(uint32_t key) {
return static_cast<Major>(MajorKeyBits::decode(key));
}
@ -142,14 +135,35 @@ class CodeStub BASE_EMBEDDED {
virtual ~CodeStub() {}
bool CompilingCallsToThisStubIsGCSafe() {
bool is_pregenerated = IsPregenerated();
Code* code = NULL;
CHECK(!is_pregenerated || FindCodeInCache(&code));
return is_pregenerated;
}
// See comment above, where Instanceof is defined.
virtual bool IsPregenerated() { return false; }
static void GenerateStubsAheadOfTime();
static void GenerateFPStubs();
// Some stubs put untagged junk on the stack that cannot be scanned by the
// GC. This means that we must be statically sure that no GC can occur while
// they are running. If that is the case they should override this to return
// true, which will cause an assertion if we try to call something that can
// GC or if we try to put a stack frame on top of the junk, which would not
// result in a traversable stack.
virtual bool SometimesSetsUpAFrame() { return true; }
// Lookup the code in the (possibly custom) cache.
bool FindCodeInCache(Code** code_out);
protected:
static const int kMajorBits = 6;
static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits;
private:
// Lookup the code in the (possibly custom) cache.
bool FindCodeInCache(Code** code_out);
// Nonvirtual wrapper around the stub-specific Generate function. Call
// this function to set up the macro assembler and generate the code.
void GenerateCode(MacroAssembler* masm);
@ -162,7 +176,11 @@ class CodeStub BASE_EMBEDDED {
void RecordCodeGeneration(Code* code, MacroAssembler* masm);
// Finish the code object after it has been generated.
virtual void FinishCode(Code* code) { }
virtual void FinishCode(Handle<Code> code) { }
// Activate newly generated stub. Is called after
// registering stub in the stub cache.
virtual void Activate(Code* code) { }
// Returns information for computing the number key.
virtual Major MajorKey() = 0;
@ -178,9 +196,7 @@ class CodeStub BASE_EMBEDDED {
// Returns a name for logging/debugging purposes.
SmartArrayPointer<const char> GetName();
virtual void PrintName(StringStream* stream) {
stream->Add("%s", MajorName(MajorKey(), false));
}
virtual void PrintName(StringStream* stream);
// Returns whether the code generated for this stub needs to be allocated as
// a fixed (non-moveable) code object.
@ -193,9 +209,6 @@ class CodeStub BASE_EMBEDDED {
MajorKeyBits::encode(MajorKey());
}
// See comment above, where Instanceof is defined.
bool AllowsStubCalls() { return MajorKey() <= Instanceof; }
class MajorKeyBits: public BitField<uint32_t, 0, kMajorBits> {};
class MinorKeyBits: public BitField<uint32_t, kMajorBits, kMinorBits> {};
@ -286,16 +299,17 @@ class ToNumberStub: public CodeStub {
class FastNewClosureStub : public CodeStub {
public:
explicit FastNewClosureStub(StrictModeFlag strict_mode)
: strict_mode_(strict_mode) { }
explicit FastNewClosureStub(LanguageMode language_mode)
: language_mode_(language_mode) { }
void Generate(MacroAssembler* masm);
private:
Major MajorKey() { return FastNewClosure; }
int MinorKey() { return strict_mode_; }
int MinorKey() { return language_mode_ == CLASSIC_MODE
? kNonStrictMode : kStrictMode; }
StrictModeFlag strict_mode_;
LanguageMode language_mode_;
};
@ -304,7 +318,7 @@ class FastNewContextStub : public CodeStub {
static const int kMaximumSlots = 64;
explicit FastNewContextStub(int slots) : slots_(slots) {
ASSERT(slots_ > 0 && slots <= kMaximumSlots);
ASSERT(slots_ > 0 && slots_ <= kMaximumSlots);
}
void Generate(MacroAssembler* masm);
@ -317,6 +331,24 @@ class FastNewContextStub : public CodeStub {
};
class FastNewBlockContextStub : public CodeStub {
public:
static const int kMaximumSlots = 64;
explicit FastNewBlockContextStub(int slots) : slots_(slots) {
ASSERT(slots_ > 0 && slots_ <= kMaximumSlots);
}
void Generate(MacroAssembler* masm);
private:
int slots_;
Major MajorKey() { return FastNewBlockContext; }
int MinorKey() { return slots_; }
};
class FastCloneShallowArrayStub : public CodeStub {
public:
// Maximum length of copied elements array.
@ -324,14 +356,16 @@ class FastCloneShallowArrayStub : public CodeStub {
enum Mode {
CLONE_ELEMENTS,
COPY_ON_WRITE_ELEMENTS
CLONE_DOUBLE_ELEMENTS,
COPY_ON_WRITE_ELEMENTS,
CLONE_ANY_ELEMENTS
};
FastCloneShallowArrayStub(Mode mode, int length)
: mode_(mode),
length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) {
ASSERT(length_ >= 0);
ASSERT(length_ <= kMaximumClonedLength);
ASSERT_GE(length_, 0);
ASSERT_LE(length_, kMaximumClonedLength);
}
void Generate(MacroAssembler* masm);
@ -342,12 +376,32 @@ class FastCloneShallowArrayStub : public CodeStub {
Major MajorKey() { return FastCloneShallowArray; }
int MinorKey() {
ASSERT(mode_ == 0 || mode_ == 1);
return (length_ << 1) | mode_;
ASSERT(mode_ == 0 || mode_ == 1 || mode_ == 2 || mode_ == 3);
return length_ * 4 + mode_;
}
};
class FastCloneShallowObjectStub : public CodeStub {
public:
// Maximum number of properties in copied object.
static const int kMaximumClonedProperties = 6;
explicit FastCloneShallowObjectStub(int length) : length_(length) {
ASSERT_GE(length_, 0);
ASSERT_LE(length_, kMaximumClonedProperties);
}
void Generate(MacroAssembler* masm);
private:
int length_;
Major MajorKey() { return FastCloneShallowObject; }
int MinorKey() { return length_; }
};
class InstanceofStub: public CodeStub {
public:
enum Flags {
@ -410,7 +464,9 @@ class ICCompareStub: public CodeStub {
class OpField: public BitField<int, 0, 3> { };
class StateField: public BitField<int, 3, 5> { };
virtual void FinishCode(Code* code) { code->set_compare_state(state_); }
virtual void FinishCode(Handle<Code> code) {
code->set_compare_state(state_);
}
virtual CodeStub::Major MajorKey() { return CompareIC; }
virtual int MinorKey();
@ -513,7 +569,7 @@ class CompareStub: public CodeStub {
int MinorKey();
virtual int GetCodeKind() { return Code::COMPARE_IC; }
virtual void FinishCode(Code* code) {
virtual void FinishCode(Handle<Code> code) {
code->set_compare_state(CompareIC::GENERIC);
}
@ -531,11 +587,18 @@ class CompareStub: public CodeStub {
class CEntryStub : public CodeStub {
public:
explicit CEntryStub(int result_size)
: result_size_(result_size), save_doubles_(false) { }
explicit CEntryStub(int result_size,
SaveFPRegsMode save_doubles = kDontSaveFPRegs)
: result_size_(result_size), save_doubles_(save_doubles) { }
void Generate(MacroAssembler* masm);
void SaveDoubles() { save_doubles_ = true; }
// The version of this stub that doesn't save doubles is generated ahead of
// time, so it's OK to call it from other stubs that can't cope with GC during
// their code generation. On machines that always have gp registers (x64) we
// can generate both variants ahead of time.
virtual bool IsPregenerated();
static void GenerateAheadOfTime();
private:
void GenerateCore(MacroAssembler* masm,
@ -550,7 +613,7 @@ class CEntryStub : public CodeStub {
// Number of pointers/values returned.
const int result_size_;
bool save_doubles_;
SaveFPRegsMode save_doubles_;
Major MajorKey() { return CEntry; }
int MinorKey();
@ -571,6 +634,10 @@ class JSEntryStub : public CodeStub {
private:
Major MajorKey() { return JSEntry; }
int MinorKey() { return 0; }
virtual void FinishCode(Handle<Code> code);
int handler_offset_;
};
@ -647,10 +714,32 @@ class CallFunctionStub: public CodeStub {
void Generate(MacroAssembler* masm);
virtual void FinishCode(Handle<Code> code);
static void Clear(Heap* heap, Address address);
static Object* GetCachedValue(Address address);
static int ExtractArgcFromMinorKey(int minor_key) {
return ArgcBits::decode(minor_key);
}
// The object that indicates an uninitialized cache.
static Handle<Object> UninitializedSentinel(Isolate* isolate) {
return isolate->factory()->the_hole_value();
}
// A raw version of the uninitialized sentinel that's safe to read during
// garbage collection (e.g., for patching the cache).
static Object* RawUninitializedSentinel(Heap* heap) {
return heap->raw_unchecked_the_hole_value();
}
// The object that indicates a megamorphic state.
static Handle<Object> MegamorphicSentinel(Isolate* isolate) {
return isolate->factory()->undefined_value();
}
private:
int argc_;
CallFunctionFlags flags_;
@ -658,8 +747,8 @@ class CallFunctionStub: public CodeStub {
virtual void PrintName(StringStream* stream);
// Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
class FlagBits: public BitField<CallFunctionFlags, 0, 1> {};
class ArgcBits: public BitField<unsigned, 1, 32 - 1> {};
class FlagBits: public BitField<CallFunctionFlags, 0, 2> {};
class ArgcBits: public BitField<unsigned, 2, 32 - 2> {};
Major MajorKey() { return CallFunction; }
int MinorKey() {
@ -670,6 +759,10 @@ class CallFunctionStub: public CodeStub {
bool ReceiverMightBeImplicit() {
return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0;
}
bool RecordCallTarget() {
return (flags_ & RECORD_CALL_TARGET) != 0;
}
};
@ -698,7 +791,6 @@ class StringCharCodeAtGenerator {
public:
StringCharCodeAtGenerator(Register object,
Register index,
Register scratch,
Register result,
Label* receiver_not_string,
Label* index_not_number,
@ -706,15 +798,11 @@ class StringCharCodeAtGenerator {
StringIndexFlags index_flags)
: object_(object),
index_(index),
scratch_(scratch),
result_(result),
receiver_not_string_(receiver_not_string),
index_not_number_(index_not_number),
index_out_of_range_(index_out_of_range),
index_flags_(index_flags) {
ASSERT(!scratch_.is(object_));
ASSERT(!scratch_.is(index_));
ASSERT(!scratch_.is(result_));
ASSERT(!result_.is(object_));
ASSERT(!result_.is(index_));
}
@ -732,7 +820,6 @@ class StringCharCodeAtGenerator {
private:
Register object_;
Register index_;
Register scratch_;
Register result_;
Label* receiver_not_string_;
@ -795,8 +882,7 @@ class StringCharAtGenerator {
public:
StringCharAtGenerator(Register object,
Register index,
Register scratch1,
Register scratch2,
Register scratch,
Register result,
Label* receiver_not_string,
Label* index_not_number,
@ -804,13 +890,12 @@ class StringCharAtGenerator {
StringIndexFlags index_flags)
: char_code_at_generator_(object,
index,
scratch1,
scratch2,
scratch,
receiver_not_string,
index_not_number,
index_out_of_range,
index_flags),
char_from_code_generator_(scratch2, result) {}
char_from_code_generator_(scratch, result) {}
// Generates the fast case code. On the fallthrough path |result|
// register contains the result.
@ -934,11 +1019,13 @@ class ToBooleanStub: public CodeStub {
virtual int GetCodeKind() { return Code::TO_BOOLEAN_IC; }
virtual void PrintName(StringStream* stream);
virtual bool SometimesSetsUpAFrame() { return false; }
private:
Major MajorKey() { return ToBoolean; }
int MinorKey() { return (tos_.code() << NUMBER_OF_TYPES) | types_.ToByte(); }
virtual void FinishCode(Code* code) {
virtual void FinishCode(Handle<Code> code) {
code->set_to_boolean_state(types_.ToByte());
}
@ -952,6 +1039,56 @@ class ToBooleanStub: public CodeStub {
Types types_;
};
class ElementsTransitionAndStoreStub : public CodeStub {
public:
ElementsTransitionAndStoreStub(ElementsKind from,
ElementsKind to,
bool is_jsarray,
StrictModeFlag strict_mode)
: from_(from),
to_(to),
is_jsarray_(is_jsarray),
strict_mode_(strict_mode) {}
private:
class FromBits: public BitField<ElementsKind, 0, 8> {};
class ToBits: public BitField<ElementsKind, 8, 8> {};
class IsJSArrayBits: public BitField<bool, 16, 8> {};
class StrictModeBits: public BitField<StrictModeFlag, 24, 8> {};
Major MajorKey() { return ElementsTransitionAndStore; }
int MinorKey() {
return FromBits::encode(from_) |
ToBits::encode(to_) |
IsJSArrayBits::encode(is_jsarray_) |
StrictModeBits::encode(strict_mode_);
}
void Generate(MacroAssembler* masm);
ElementsKind from_;
ElementsKind to_;
bool is_jsarray_;
StrictModeFlag strict_mode_;
DISALLOW_COPY_AND_ASSIGN(ElementsTransitionAndStoreStub);
};
class StoreArrayLiteralElementStub : public CodeStub {
public:
explicit StoreArrayLiteralElementStub() {}
private:
Major MajorKey() { return StoreArrayLiteralElement; }
int MinorKey() { return 0; }
void Generate(MacroAssembler* masm);
DISALLOW_COPY_AND_ASSIGN(StoreArrayLiteralElementStub);
};
} } // namespace v8::internal
#endif // V8_CODE_STUBS_H_

2
deps/v8/src/codegen.cc

@ -218,8 +218,8 @@ void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
int CEntryStub::MinorKey() {
int result = (save_doubles_ == kSaveFPRegs) ? 1 : 0;
ASSERT(result_size_ == 1 || result_size_ == 2);
int result = save_doubles_ ? 1 : 0;
#ifdef _WIN64
return result | ((result_size_ == 1) ? 0 : 2);
#else

15
deps/v8/src/codegen.h

@ -81,4 +81,19 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
#error Unsupported target architecture.
#endif
namespace v8 {
namespace internal {
class ElementsTransitionGenerator : public AllStatic {
public:
static void GenerateSmiOnlyToObject(MacroAssembler* masm);
static void GenerateSmiOnlyToDouble(MacroAssembler* masm, Label* fail);
static void GenerateDoubleToObject(MacroAssembler* masm, Label* fail);
private:
DISALLOW_COPY_AND_ASSIGN(ElementsTransitionGenerator);
};
} } // namespace v8::internal
#endif // V8_CODEGEN_H_

117
deps/v8/src/weakmap.js → deps/v8/src/collection.js

@ -26,12 +26,95 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file relies on the fact that the following declaration has been made
// in runtime.js:
// const $Object = global.Object;
const $Set = global.Set;
const $Map = global.Map;
const $WeakMap = global.WeakMap;
// -------------------------------------------------------------------
//-------------------------------------------------------------------
// Global sentinel to be used instead of undefined keys, which are not
// supported internally but required for Harmony sets and maps.
var undefined_sentinel = {};
function SetConstructor() {
if (%_IsConstructCall()) {
%SetInitialize(this);
} else {
return new $Set();
}
}
function SetAdd(key) {
if (IS_UNDEFINED(key)) {
key = undefined_sentinel;
}
return %SetAdd(this, key);
}
function SetHas(key) {
if (IS_UNDEFINED(key)) {
key = undefined_sentinel;
}
return %SetHas(this, key);
}
function SetDelete(key) {
if (IS_UNDEFINED(key)) {
key = undefined_sentinel;
}
return %SetDelete(this, key);
}
function MapConstructor() {
if (%_IsConstructCall()) {
%MapInitialize(this);
} else {
return new $Map();
}
}
function MapGet(key) {
if (IS_UNDEFINED(key)) {
key = undefined_sentinel;
}
return %MapGet(this, key);
}
function MapSet(key, value) {
if (IS_UNDEFINED(key)) {
key = undefined_sentinel;
}
return %MapSet(this, key, value);
}
function MapHas(key) {
if (IS_UNDEFINED(key)) {
key = undefined_sentinel;
}
return !IS_UNDEFINED(%MapGet(this, key));
}
function MapDelete(key) {
if (IS_UNDEFINED(key)) {
key = undefined_sentinel;
}
if (!IS_UNDEFINED(%MapGet(this, key))) {
%MapSet(this, key, void 0);
return true;
} else {
return false;
}
}
function WeakMapConstructor() {
if (%_IsConstructCall()) {
@ -82,6 +165,30 @@ function WeakMapDelete(key) {
(function () {
%CheckIsBootstrapping();
// Set up the Set and Map constructor function.
%SetCode($Set, SetConstructor);
%SetCode($Map, MapConstructor);
// Set up the constructor property on the Set and Map prototype object.
%SetProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
%SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
// Set up the non-enumerable functions on the Set prototype object.
InstallFunctions($Set.prototype, DONT_ENUM, $Array(
"add", SetAdd,
"has", SetHas,
"delete", SetDelete
));
// Set up the non-enumerable functions on the Map prototype object.
InstallFunctions($Map.prototype, DONT_ENUM, $Array(
"get", MapGet,
"set", MapSet,
"has", MapHas,
"delete", MapDelete
));
// Set up the WeakMap constructor function.
%SetCode($WeakMap, WeakMapConstructor);
@ -89,7 +196,7 @@ function WeakMapDelete(key) {
%SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);
// Set up the non-enumerable functions on the WeakMap prototype object.
InstallFunctionsOnHiddenPrototype($WeakMap.prototype, DONT_ENUM, $Array(
InstallFunctions($WeakMap.prototype, DONT_ENUM, $Array(
"get", WeakMapGet,
"set", WeakMapSet,
"has", WeakMapHas,

45
deps/v8/src/compilation-cache.cc

@ -1,4 +1,4 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -27,6 +27,7 @@
#include "v8.h"
#include "assembler.h"
#include "compilation-cache.h"
#include "serialize.h"
@ -250,7 +251,8 @@ void CompilationCacheScript::Put(Handle<String> source,
Handle<SharedFunctionInfo> CompilationCacheEval::Lookup(
Handle<String> source,
Handle<Context> context,
StrictModeFlag strict_mode) {
LanguageMode language_mode,
int scope_position) {
// 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.
@ -259,7 +261,8 @@ Handle<SharedFunctionInfo> CompilationCacheEval::Lookup(
{ HandleScope scope(isolate());
for (generation = 0; generation < generations(); generation++) {
Handle<CompilationCacheTable> table = GetTable(generation);
result = table->LookupEval(*source, *context, strict_mode);
result = table->LookupEval(
*source, *context, language_mode, scope_position);
if (result->IsSharedFunctionInfo()) {
break;
}
@ -269,7 +272,7 @@ Handle<SharedFunctionInfo> CompilationCacheEval::Lookup(
Handle<SharedFunctionInfo>
function_info(SharedFunctionInfo::cast(result), isolate());
if (generation != 0) {
Put(source, context, function_info);
Put(source, context, function_info, scope_position);
}
isolate()->counters()->compilation_cache_hits()->Increment();
return function_info;
@ -283,27 +286,31 @@ Handle<SharedFunctionInfo> CompilationCacheEval::Lookup(
MaybeObject* CompilationCacheEval::TryTablePut(
Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info) {
Handle<SharedFunctionInfo> function_info,
int scope_position) {
Handle<CompilationCacheTable> table = GetFirstTable();
return table->PutEval(*source, *context, *function_info);
return table->PutEval(*source, *context, *function_info, scope_position);
}
Handle<CompilationCacheTable> CompilationCacheEval::TablePut(
Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info) {
Handle<SharedFunctionInfo> function_info,
int scope_position) {
CALL_HEAP_FUNCTION(isolate(),
TryTablePut(source, context, function_info),
TryTablePut(
source, context, function_info, scope_position),
CompilationCacheTable);
}
void CompilationCacheEval::Put(Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info) {
Handle<SharedFunctionInfo> function_info,
int scope_position) {
HandleScope scope(isolate());
SetFirstTable(TablePut(source, context, function_info));
SetFirstTable(TablePut(source, context, function_info, scope_position));
}
@ -389,16 +396,20 @@ Handle<SharedFunctionInfo> CompilationCache::LookupEval(
Handle<String> source,
Handle<Context> context,
bool is_global,
StrictModeFlag strict_mode) {
LanguageMode language_mode,
int scope_position) {
if (!IsEnabled()) {
return Handle<SharedFunctionInfo>::null();
}
Handle<SharedFunctionInfo> result;
if (is_global) {
result = eval_global_.Lookup(source, context, strict_mode);
result = eval_global_.Lookup(
source, context, language_mode, scope_position);
} else {
result = eval_contextual_.Lookup(source, context, strict_mode);
ASSERT(scope_position != RelocInfo::kNoPosition);
result = eval_contextual_.Lookup(
source, context, language_mode, scope_position);
}
return result;
}
@ -427,16 +438,18 @@ void CompilationCache::PutScript(Handle<String> source,
void CompilationCache::PutEval(Handle<String> source,
Handle<Context> context,
bool is_global,
Handle<SharedFunctionInfo> function_info) {
Handle<SharedFunctionInfo> function_info,
int scope_position) {
if (!IsEnabled()) {
return;
}
HandleScope scope(isolate());
if (is_global) {
eval_global_.Put(source, context, function_info);
eval_global_.Put(source, context, function_info, scope_position);
} else {
eval_contextual_.Put(source, context, function_info);
ASSERT(scope_position != RelocInfo::kNoPosition);
eval_contextual_.Put(source, context, function_info, scope_position);
}
}

34
deps/v8/src/compilation-cache.h

@ -1,4 +1,4 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -123,7 +123,19 @@ class CompilationCacheScript : public CompilationSubCache {
};
// Sub-cache for eval scripts.
// Sub-cache for eval scripts. Two caches for eval are used. One for eval calls
// in global contexts and one for eval calls in other contexts. The cache
// considers the following pieces of information when checking for matching
// entries:
// 1. The source string.
// 2. The shared function info of the calling function.
// 3. Whether the source should be compiled as strict code or as non-strict
// code.
// Note: Currently there are clients of CompileEval that always compile
// non-strict code even if the calling function is a strict mode function.
// More specifically these are the CompileString, DebugEvaluate and
// DebugEvaluateGlobal runtime functions.
// 4. The start position of the calling scope.
class CompilationCacheEval: public CompilationSubCache {
public:
CompilationCacheEval(Isolate* isolate, int generations)
@ -131,23 +143,27 @@ class CompilationCacheEval: public CompilationSubCache {
Handle<SharedFunctionInfo> Lookup(Handle<String> source,
Handle<Context> context,
StrictModeFlag strict_mode);
LanguageMode language_mode,
int scope_position);
void Put(Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info);
Handle<SharedFunctionInfo> function_info,
int scope_position);
private:
MUST_USE_RESULT MaybeObject* TryTablePut(
Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info);
Handle<SharedFunctionInfo> function_info,
int scope_position);
// Note: Returns a new hash table if operation results in expansion.
Handle<CompilationCacheTable> TablePut(
Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info);
Handle<SharedFunctionInfo> function_info,
int scope_position);
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval);
};
@ -198,7 +214,8 @@ class CompilationCache {
Handle<SharedFunctionInfo> LookupEval(Handle<String> source,
Handle<Context> context,
bool is_global,
StrictModeFlag strict_mode);
LanguageMode language_mode,
int scope_position);
// Returns the regexp data associated with the given regexp if it
// is in cache, otherwise an empty handle.
@ -215,7 +232,8 @@ class CompilationCache {
void PutEval(Handle<String> source,
Handle<Context> context,
bool is_global,
Handle<SharedFunctionInfo> function_info);
Handle<SharedFunctionInfo> function_info,
int scope_position);
// Associate the (source, flags) pair to the given regexp data.
// This may overwrite an existing mapping.

77
deps/v8/src/compiler-intrinsics.h

@ -0,0 +1,77 @@
// Copyright 2006-2008 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_COMPILER_INTRINSICS_H_
#define V8_COMPILER_INTRINSICS_H_
namespace v8 {
namespace internal {
class CompilerIntrinsics {
public:
// Returns number of zero bits preceding least significant 1 bit.
// Undefined for zero value.
INLINE(static int CountTrailingZeros(uint32_t value));
// Returns number of zero bits following most significant 1 bit.
// Undefined for zero value.
INLINE(static int CountLeadingZeros(uint32_t value));
};
#ifdef __GNUC__
int CompilerIntrinsics::CountTrailingZeros(uint32_t value) {
return __builtin_ctz(value);
}
int CompilerIntrinsics::CountLeadingZeros(uint32_t value) {
return __builtin_clz(value);
}
#elif defined(_MSC_VER)
#pragma intrinsic(_BitScanForward)
#pragma intrinsic(_BitScanReverse)
int CompilerIntrinsics::CountTrailingZeros(uint32_t value) {
unsigned long result; //NOLINT
_BitScanForward(&result, static_cast<long>(value)); //NOLINT
return static_cast<int>(result);
}
int CompilerIntrinsics::CountLeadingZeros(uint32_t value) {
unsigned long result; //NOLINT
_BitScanReverse(&result, static_cast<long>(value)); //NOLINT
return 31 - static_cast<int>(result);
}
#else
#error Unsupported compiler
#endif
} } // namespace v8::internal
#endif // V8_COMPILER_INTRINSICS_H_

124
deps/v8/src/compiler.cc

@ -36,6 +36,7 @@
#include "full-codegen.h"
#include "gdb-jit.h"
#include "hydrogen.h"
#include "isolate-inl.h"
#include "lithium.h"
#include "liveedit.h"
#include "parser.h"
@ -52,13 +53,13 @@ namespace internal {
CompilationInfo::CompilationInfo(Handle<Script> script)
: isolate_(script->GetIsolate()),
flags_(0),
flags_(LanguageModeField::encode(CLASSIC_MODE)),
function_(NULL),
scope_(NULL),
global_scope_(NULL),
script_(script),
extension_(NULL),
pre_parse_data_(NULL),
supports_deoptimization_(false),
osr_ast_id_(AstNode::kNoNumber) {
Initialize(NONOPT);
}
@ -66,14 +67,15 @@ CompilationInfo::CompilationInfo(Handle<Script> script)
CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
: isolate_(shared_info->GetIsolate()),
flags_(IsLazy::encode(true)),
flags_(LanguageModeField::encode(CLASSIC_MODE) |
IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
global_scope_(NULL),
shared_info_(shared_info),
script_(Handle<Script>(Script::cast(shared_info->script()))),
extension_(NULL),
pre_parse_data_(NULL),
supports_deoptimization_(false),
osr_ast_id_(AstNode::kNoNumber) {
Initialize(BASE);
}
@ -81,15 +83,16 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
CompilationInfo::CompilationInfo(Handle<JSFunction> closure)
: isolate_(closure->GetIsolate()),
flags_(IsLazy::encode(true)),
flags_(LanguageModeField::encode(CLASSIC_MODE) |
IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
global_scope_(NULL),
closure_(closure),
shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
script_(Handle<Script>(Script::cast(shared_info_->script()))),
extension_(NULL),
pre_parse_data_(NULL),
supports_deoptimization_(false),
osr_ast_id_(AstNode::kNoNumber) {
Initialize(BASE);
}
@ -167,7 +170,11 @@ static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
static bool MakeCrankshaftCode(CompilationInfo* info) {
// Test if we can optimize this function when asked to. We can only
// do this after the scopes are computed.
if (!info->AllowOptimize()) info->DisableOptimization();
if (!info->AllowOptimize()) {
info->DisableOptimization();
} else if (info->IsOptimizable()) {
info->EnableDeoptimizationSupport();
}
// In case we are not optimizing simply return the code from
// the full code generator.
@ -275,7 +282,7 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
}
Handle<Context> global_context(info->closure()->context()->global_context());
TypeFeedbackOracle oracle(code, global_context);
TypeFeedbackOracle oracle(code, global_context, info->isolate());
HGraphBuilder builder(info, &oracle);
HPhase phase(HPhase::kTotal);
HGraph* graph = builder.CreateGraph();
@ -308,9 +315,9 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
static bool GenerateCode(CompilationInfo* info) {
return V8::UseCrankshaft() ?
MakeCrankshaftCode(info) :
FullCodeGenerator::MakeCode(info);
return info->IsCompilingForDebugging() || !V8::UseCrankshaft() ?
FullCodeGenerator::MakeCode(info) :
MakeCrankshaftCode(info);
}
@ -328,8 +335,7 @@ bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) {
// the compilation info is set if compilation succeeded.
bool succeeded = MakeCode(info);
if (!info->shared_info().is_null()) {
Handle<SerializedScopeInfo> scope_info =
SerializedScopeInfo::Create(info->scope());
Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope());
info->shared_info()->set_scope_info(*scope_info);
}
return succeeded;
@ -371,8 +377,14 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
// Only allow non-global compiles for eval.
ASSERT(info->is_eval() || info->is_global());
if (!ParserApi::Parse(info)) return Handle<SharedFunctionInfo>::null();
ParsingFlags flags = kNoParsingFlags;
if (info->pre_parse_data() != NULL ||
String::cast(script->source())->length() > FLAG_min_preparse_length) {
flags = kAllowLazy;
}
if (!ParserApi::Parse(info, flags)) {
return Handle<SharedFunctionInfo>::null();
}
// Measure how long it takes to do the compilation; only take the
// rest of the function into account to avoid overlap with the
@ -397,7 +409,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
lit->name(),
lit->materialized_literal_count(),
info->code(),
SerializedScopeInfo::Create(info->scope()));
ScopeInfo::Create(info->scope()));
ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
Compiler::SetFunctionInfo(result, lit, true, script);
@ -447,7 +459,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
int line_offset,
int column_offset,
v8::Extension* extension,
ScriptDataImpl* input_pre_data,
ScriptDataImpl* pre_data,
Handle<Object> script_data,
NativesFlag natives) {
Isolate* isolate = source->GetIsolate();
@ -478,23 +490,12 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
// for small sources, odds are that there aren't many functions
// that would be compiled lazily anyway, so we skip the preparse step
// in that case too.
ScriptDataImpl* pre_data = input_pre_data;
bool harmony_block_scoping = natives != NATIVES_CODE &&
FLAG_harmony_block_scoping;
if (pre_data == NULL
&& source_length >= FLAG_min_preparse_length) {
if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
pre_data = ParserApi::PartialPreParse(&stream,
extension,
harmony_block_scoping);
} else {
GenericStringUC16CharacterStream stream(source, 0, source->length());
pre_data = ParserApi::PartialPreParse(&stream,
extension,
harmony_block_scoping);
}
int flags = kNoParsingFlags;
if ((natives == NATIVES_CODE) || FLAG_allow_natives_syntax) {
flags |= kAllowNativesSyntax;
}
if (natives != NATIVES_CODE && FLAG_harmony_scoping) {
flags |= EXTENDED_MODE;
}
// Create a script object describing the script to be compiled.
@ -520,11 +521,6 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
if (extension == NULL && !result.is_null()) {
compilation_cache->PutScript(source, result);
}
// Get rid of the pre-parsing data (if necessary).
if (input_pre_data == NULL && pre_data != NULL) {
delete pre_data;
}
}
if (result.is_null()) isolate->ReportPendingMessages();
@ -535,7 +531,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
Handle<Context> context,
bool is_global,
StrictModeFlag strict_mode) {
LanguageMode language_mode,
int scope_position) {
Isolate* isolate = source->GetIsolate();
int source_length = source->length();
isolate->counters()->total_eval_size()->Increment(source_length);
@ -551,7 +548,8 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
result = compilation_cache->LookupEval(source,
context,
is_global,
strict_mode);
language_mode,
scope_position);
if (result.is_null()) {
// Create a script object describing the script to be compiled.
@ -559,16 +557,20 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
CompilationInfo info(script);
info.MarkAsEval();
if (is_global) info.MarkAsGlobal();
if (strict_mode == kStrictMode) info.MarkAsStrictMode();
info.SetLanguageMode(language_mode);
info.SetCallingContext(context);
result = MakeFunctionInfo(&info);
if (!result.is_null()) {
CompilationCache* compilation_cache = isolate->compilation_cache();
// If caller is strict mode, the result must be strict as well,
// but not the other way around. Consider:
// If caller is strict mode, the result must be in strict mode or
// extended mode as well, but not the other way around. Consider:
// eval("'use strict'; ...");
ASSERT(strict_mode == kNonStrictMode || result->strict_mode());
compilation_cache->PutEval(source, context, is_global, result);
ASSERT(language_mode != STRICT_MODE || !result->is_classic_mode());
// If caller is in extended mode, the result must also be in
// extended mode.
ASSERT(language_mode != EXTENDED_MODE ||
result->is_extended_mode());
compilation_cache->PutEval(
source, context, is_global, result, scope_position);
}
}
@ -591,17 +593,16 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
isolate->counters()->total_compile_size()->Increment(compiled_size);
// Generate the AST for the lazily compiled function.
if (ParserApi::Parse(info)) {
if (ParserApi::Parse(info, kNoParsingFlags)) {
// Measure how long it takes to do the lazy compilation; only take the
// rest of the function into account to avoid overlap with the lazy
// parsing statistics.
HistogramTimerScope timer(isolate->counters()->compile_lazy());
// After parsing we know function's strict mode. Remember it.
if (info->function()->strict_mode()) {
shared->set_strict_mode(true);
info->MarkAsStrictMode();
}
// After parsing we know the function's language mode. Remember it.
LanguageMode language_mode = info->function()->language_mode();
info->SetLanguageMode(language_mode);
shared->set_language_mode(language_mode);
// Compile the code.
if (!MakeCode(info)) {
@ -620,7 +621,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
if (info->IsOptimizing()) {
ASSERT(shared->scope_info() != SerializedScopeInfo::Empty());
ASSERT(shared->scope_info() != ScopeInfo::Empty());
function->ReplaceCode(*code);
} else {
// Update the shared function info with the compiled code and the
@ -628,8 +629,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
// info initialization is important since set_scope_info might
// trigger a GC, causing the ASSERT below to be invalid if the code
// was flushed. By settting the code object last we avoid this.
Handle<SerializedScopeInfo> scope_info =
SerializedScopeInfo::Create(info->scope());
Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope());
shared->set_scope_info(*scope_info);
shared->set_code(*code);
if (!function.is_null()) {
@ -681,7 +681,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
CompilationInfo info(script);
info.SetFunction(literal);
info.SetScope(literal->scope());
if (literal->scope()->is_strict_mode()) info.MarkAsStrictMode();
info.SetLanguageMode(literal->scope()->language_mode());
LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal);
// Determine if the function can be lazily compiled. This is necessary to
@ -692,7 +692,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
bool allow_lazy = literal->AllowsLazyCompilation() &&
!LiveEditFunctionTracker::IsActive(info.isolate());
Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
Handle<ScopeInfo> scope_info(ScopeInfo::Empty());
// Generate code
if (FLAG_lazy && allow_lazy) {
@ -701,7 +701,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
} else if ((V8::UseCrankshaft() && MakeCrankshaftCode(&info)) ||
(!V8::UseCrankshaft() && FullCodeGenerator::MakeCode(&info))) {
ASSERT(!info.code().is_null());
scope_info = SerializedScopeInfo::Create(info.scope());
scope_info = ScopeInfo::Create(info.scope());
} else {
return Handle<SharedFunctionInfo>::null();
}
@ -733,8 +733,8 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
FunctionLiteral* lit,
bool is_toplevel,
Handle<Script> script) {
function_info->set_length(lit->num_parameters());
function_info->set_formal_parameter_count(lit->num_parameters());
function_info->set_length(lit->parameter_count());
function_info->set_formal_parameter_count(lit->parameter_count());
function_info->set_script(*script);
function_info->set_function_token_position(lit->function_token_position());
function_info->set_start_position(lit->start_position());
@ -747,7 +747,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
lit->has_only_simple_this_property_assignments(),
*lit->this_property_assignments());
function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
function_info->set_strict_mode(lit->strict_mode());
function_info->set_language_mode(lit->language_mode());
function_info->set_uses_arguments(lit->scope()->arguments() != NULL);
function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
}

58
deps/v8/src/compiler.h

@ -52,10 +52,15 @@ class CompilationInfo BASE_EMBEDDED {
bool is_lazy() const { return IsLazy::decode(flags_); }
bool is_eval() const { return IsEval::decode(flags_); }
bool is_global() const { return IsGlobal::decode(flags_); }
bool is_strict_mode() const { return IsStrictMode::decode(flags_); }
bool is_classic_mode() const { return language_mode() == CLASSIC_MODE; }
bool is_extended_mode() const { return language_mode() == EXTENDED_MODE; }
LanguageMode language_mode() const {
return LanguageModeField::decode(flags_);
}
bool is_in_loop() const { return IsInLoop::decode(flags_); }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; }
Scope* global_scope() const { return global_scope_; }
Handle<Code> code() const { return code_; }
Handle<JSFunction> closure() const { return closure_; }
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
@ -73,11 +78,11 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(!is_lazy());
flags_ |= IsGlobal::encode(true);
}
void MarkAsStrictMode() {
flags_ |= IsStrictMode::encode(true);
}
StrictModeFlag StrictMode() {
return is_strict_mode() ? kStrictMode : kNonStrictMode;
void SetLanguageMode(LanguageMode language_mode) {
ASSERT(this->language_mode() == CLASSIC_MODE ||
this->language_mode() == language_mode ||
language_mode == EXTENDED_MODE);
flags_ = LanguageModeField::update(flags_, language_mode);
}
void MarkAsInLoop() {
ASSERT(is_lazy());
@ -97,6 +102,10 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(scope_ == NULL);
scope_ = scope;
}
void SetGlobalScope(Scope* global_scope) {
ASSERT(global_scope_ == NULL);
global_scope_ = global_scope;
}
void SetCode(Handle<Code> code) { code_ = code; }
void SetExtension(v8::Extension* extension) {
ASSERT(!is_lazy());
@ -114,6 +123,19 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(IsOptimizing());
osr_ast_id_ = osr_ast_id;
}
void MarkCompilingForDebugging(Handle<Code> current_code) {
ASSERT(mode_ != OPTIMIZE);
ASSERT(current_code->kind() == Code::FUNCTION);
flags_ |= IsCompilingForDebugging::encode(true);
if (current_code->is_compiled_optimizable()) {
EnableDeoptimizationSupport();
} else {
mode_ = CompilationInfo::NONOPT;
}
}
bool IsCompilingForDebugging() {
return IsCompilingForDebugging::decode(flags_);
}
bool has_global_object() const {
return !closure().is_null() && (closure()->context()->global() != NULL);
@ -133,10 +155,12 @@ class CompilationInfo BASE_EMBEDDED {
void DisableOptimization();
// Deoptimization support.
bool HasDeoptimizationSupport() const { return supports_deoptimization_; }
bool HasDeoptimizationSupport() const {
return SupportsDeoptimization::decode(flags_);
}
void EnableDeoptimizationSupport() {
ASSERT(IsOptimizable());
supports_deoptimization_ = true;
flags_ |= SupportsDeoptimization::encode(true);
}
// Determine whether or not we can adaptively optimize.
@ -171,8 +195,9 @@ class CompilationInfo BASE_EMBEDDED {
if (script_->type()->value() == Script::TYPE_NATIVE) {
MarkAsNative();
}
if (!shared_info_.is_null() && shared_info_->strict_mode()) {
MarkAsStrictMode();
if (!shared_info_.is_null()) {
ASSERT(language_mode() == CLASSIC_MODE);
SetLanguageMode(shared_info_->language_mode());
}
}
@ -192,9 +217,14 @@ class CompilationInfo BASE_EMBEDDED {
// Flags that can be set for lazy compilation.
class IsInLoop: public BitField<bool, 3, 1> {};
// Strict mode - used in eager compilation.
class IsStrictMode: public BitField<bool, 4, 1> {};
class LanguageModeField: public BitField<LanguageMode, 4, 2> {};
// Is this a function from our natives.
class IsNative: public BitField<bool, 6, 1> {};
// Is this code being compiled with support for deoptimization..
class SupportsDeoptimization: public BitField<bool, 7, 1> {};
// If compiling for debugging produce just full code matching the
// initial mode setting.
class IsCompilingForDebugging: public BitField<bool, 8, 1> {};
unsigned flags_;
@ -205,6 +235,8 @@ class CompilationInfo BASE_EMBEDDED {
// The scope of the function literal as a convenience. Set to indicate
// that scopes have been analyzed.
Scope* scope_;
// The global scope provided as a convenience.
Scope* global_scope_;
// The compiled code.
Handle<Code> code_;
@ -223,7 +255,6 @@ class CompilationInfo BASE_EMBEDDED {
// Compilation mode flag and whether deoptimization is allowed.
Mode mode_;
bool supports_deoptimization_;
int osr_ast_id_;
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
@ -267,7 +298,8 @@ class Compiler : public AllStatic {
static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
Handle<Context> context,
bool is_global,
StrictModeFlag strict_mode);
LanguageMode language_mode,
int scope_position);
// Compile from function info (used for lazy compilation). Returns true on
// success and false if the compilation resulted in a stack overflow.

206
deps/v8/src/contexts.cc

@ -86,14 +86,14 @@ void Context::set_global_proxy(JSObject* object) {
Handle<Object> Context::Lookup(Handle<String> name,
ContextLookupFlags flags,
int* index_,
int* index,
PropertyAttributes* attributes,
BindingFlags* binding_flags) {
Isolate* isolate = GetIsolate();
Handle<Context> context(this, isolate);
bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
*index_ = -1;
*index = -1;
*attributes = ABSENT;
*binding_flags = MISSING_BINDING;
@ -110,70 +110,51 @@ Handle<Object> Context::Lookup(Handle<String> name,
PrintF("\n");
}
// Check extension/with/global object.
if (!context->IsBlockContext() && context->has_extension()) {
if (context->IsCatchContext()) {
// Catch contexts have the variable name in the extension slot.
if (name->Equals(String::cast(context->extension()))) {
if (FLAG_trace_contexts) {
PrintF("=> found in catch context\n");
}
*index_ = Context::THROWN_OBJECT_INDEX;
*attributes = NONE;
*binding_flags = MUTABLE_IS_INITIALIZED;
return context;
}
// 1. Check global objects, subjects of with, and extension objects.
if (context->IsGlobalContext() ||
context->IsWithContext() ||
(context->IsFunctionContext() && context->has_extension())) {
Handle<JSObject> object(JSObject::cast(context->extension()), isolate);
// Context extension objects needs to behave as if they have no
// prototype. So even if we want to follow prototype chains, we need
// to only do a local lookup for context extension objects.
if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
object->IsJSContextExtensionObject()) {
*attributes = object->GetLocalPropertyAttribute(*name);
} else {
ASSERT(context->IsGlobalContext() ||
context->IsFunctionContext() ||
context->IsWithContext());
// Global, function, and with contexts may have an object in the
// extension slot.
Handle<JSObject> extension(JSObject::cast(context->extension()),
isolate);
// Context extension objects needs to behave as if they have no
// prototype. So even if we want to follow prototype chains, we
// need to only do a local lookup for context extension objects.
if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
extension->IsJSContextExtensionObject()) {
*attributes = extension->GetLocalPropertyAttribute(*name);
} else {
*attributes = extension->GetPropertyAttribute(*name);
}
if (*attributes != ABSENT) {
// property found
if (FLAG_trace_contexts) {
PrintF("=> found property in context object %p\n",
reinterpret_cast<void*>(*extension));
}
return extension;
*attributes = object->GetPropertyAttribute(*name);
}
if (*attributes != ABSENT) {
if (FLAG_trace_contexts) {
PrintF("=> found property in context object %p\n",
reinterpret_cast<void*>(*object));
}
return object;
}
}
// Check serialized scope information of functions and blocks. Only
// functions can have parameters, and a function name.
// 2. Check the context proper if it has slots.
if (context->IsFunctionContext() || context->IsBlockContext()) {
// We may have context-local slots. Check locals in the context.
Handle<SerializedScopeInfo> scope_info;
// Use serialized scope information of functions and blocks to search
// for the context index.
Handle<ScopeInfo> scope_info;
if (context->IsFunctionContext()) {
scope_info = Handle<SerializedScopeInfo>(
scope_info = Handle<ScopeInfo>(
context->closure()->shared()->scope_info(), isolate);
} else {
ASSERT(context->IsBlockContext());
scope_info = Handle<SerializedScopeInfo>(
SerializedScopeInfo::cast(context->extension()), isolate);
scope_info = Handle<ScopeInfo>(
ScopeInfo::cast(context->extension()), isolate);
}
Variable::Mode mode;
int index = scope_info->ContextSlotIndex(*name, &mode);
ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
if (index >= 0) {
VariableMode mode;
InitializationFlag init_flag;
int slot_index = scope_info->ContextSlotIndex(*name, &mode, &init_flag);
ASSERT(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
if (slot_index >= 0) {
if (FLAG_trace_contexts) {
PrintF("=> found local in context slot %d (mode = %d)\n",
index, mode);
slot_index, mode);
}
*index_ = index;
*index = slot_index;
// Note: Fixed context slots are statically allocated by the compiler.
// Statically allocated variables always have a statically known mode,
// which is the mode with which they were declared when added to the
@ -181,23 +162,31 @@ Handle<Object> Context::Lookup(Handle<String> name,
// declared variables that were introduced through declaration nodes)
// must not appear here.
switch (mode) {
case Variable::INTERNAL: // Fall through.
case Variable::VAR:
case INTERNAL: // Fall through.
case VAR:
*attributes = NONE;
*binding_flags = MUTABLE_IS_INITIALIZED;
break;
case Variable::LET:
case LET:
*attributes = NONE;
*binding_flags = MUTABLE_CHECK_INITIALIZED;
*binding_flags = (init_flag == kNeedsInitialization)
? MUTABLE_CHECK_INITIALIZED : MUTABLE_IS_INITIALIZED;
break;
case CONST:
*attributes = READ_ONLY;
*binding_flags = (init_flag == kNeedsInitialization)
? IMMUTABLE_CHECK_INITIALIZED : IMMUTABLE_IS_INITIALIZED;
break;
case Variable::CONST:
case CONST_HARMONY:
*attributes = READ_ONLY;
*binding_flags = IMMUTABLE_CHECK_INITIALIZED;
*binding_flags = (init_flag == kNeedsInitialization)
? IMMUTABLE_CHECK_INITIALIZED_HARMONY :
IMMUTABLE_IS_INITIALIZED_HARMONY;
break;
case Variable::DYNAMIC:
case Variable::DYNAMIC_GLOBAL:
case Variable::DYNAMIC_LOCAL:
case Variable::TEMPORARY:
case DYNAMIC:
case DYNAMIC_GLOBAL:
case DYNAMIC_LOCAL:
case TEMPORARY:
UNREACHABLE();
break;
}
@ -206,22 +195,37 @@ Handle<Object> Context::Lookup(Handle<String> name,
// Check the slot corresponding to the intermediate context holding
// only the function name variable.
if (follow_context_chain) {
int index = scope_info->FunctionContextSlotIndex(*name);
if (index >= 0) {
if (follow_context_chain && context->IsFunctionContext()) {
VariableMode mode;
int function_index = scope_info->FunctionContextSlotIndex(*name, &mode);
if (function_index >= 0) {
if (FLAG_trace_contexts) {
PrintF("=> found intermediate function in context slot %d\n",
index);
function_index);
}
*index_ = index;
*index = function_index;
*attributes = READ_ONLY;
*binding_flags = IMMUTABLE_IS_INITIALIZED;
ASSERT(mode == CONST || mode == CONST_HARMONY);
*binding_flags = (mode == CONST)
? IMMUTABLE_IS_INITIALIZED : IMMUTABLE_IS_INITIALIZED_HARMONY;
return context;
}
}
} else if (context->IsCatchContext()) {
// Catch contexts have the variable name in the extension slot.
if (name->Equals(String::cast(context->extension()))) {
if (FLAG_trace_contexts) {
PrintF("=> found in catch context\n");
}
*index = Context::THROWN_OBJECT_INDEX;
*attributes = NONE;
*binding_flags = MUTABLE_IS_INITIALIZED;
return context;
}
}
// Proceed with the previous context.
// 3. Prepare to continue with the previous (next outermost) context.
if (context->IsGlobalContext()) {
follow_context_chain = false;
} else {
@ -236,68 +240,6 @@ Handle<Object> Context::Lookup(Handle<String> name,
}
bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
Context* context = this;
// Check that there is no local with the given name in contexts
// before the global context and check that there are no context
// extension objects (conservative check for with statements).
while (!context->IsGlobalContext()) {
// Check if the context is a catch or with context, or has introduced
// bindings by calling non-strict eval.
if (context->has_extension()) return false;
// Not a with context so it must be a function context.
ASSERT(context->IsFunctionContext());
// Check non-parameter locals.
Handle<SerializedScopeInfo> scope_info(
context->closure()->shared()->scope_info());
Variable::Mode mode;
int index = scope_info->ContextSlotIndex(*name, &mode);
ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
if (index >= 0) return false;
// Check parameter locals.
int param_index = scope_info->ParameterIndex(*name);
if (param_index >= 0) return false;
// Check context only holding the function name variable.
index = scope_info->FunctionContextSlotIndex(*name);
if (index >= 0) return false;
context = context->previous();
}
// No local or potential with statement found so the variable is
// global unless it is shadowed by an eval-introduced variable.
return true;
}
void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
bool* outer_scope_calls_non_strict_eval) {
// Skip up the context chain checking all the function contexts to see
// whether they call eval.
Context* context = this;
while (!context->IsGlobalContext()) {
if (context->IsFunctionContext()) {
Handle<SerializedScopeInfo> scope_info(
context->closure()->shared()->scope_info());
if (scope_info->CallsEval()) {
*outer_scope_calls_eval = true;
if (!scope_info->IsStrictMode()) {
// No need to go further since the answers will not change from
// here.
*outer_scope_calls_non_strict_eval = true;
return;
}
}
}
context = context->previous();
}
}
void Context::AddOptimizedFunction(JSFunction* function) {
ASSERT(IsGlobalContext());
#ifdef DEBUG

105
deps/v8/src/contexts.h

@ -46,24 +46,43 @@ enum ContextLookupFlags {
// ES5 10.2 defines lexical environments with mutable and immutable bindings.
// Immutable bindings have two states, initialized and uninitialized, and
// their state is changed by the InitializeImmutableBinding method.
// their state is changed by the InitializeImmutableBinding method. The
// BindingFlags enum represents information if a binding has definitely been
// initialized. A mutable binding does not need to be checked and thus has
// the BindingFlag MUTABLE_IS_INITIALIZED.
//
// There are two possibilities for immutable bindings
// * 'const' declared variables. They are initialized when evaluating the
// corresponding declaration statement. They need to be checked for being
// initialized and thus get the flag IMMUTABLE_CHECK_INITIALIZED.
// * The function name of a named function literal. The binding is immediately
// initialized when entering the function and thus does not need to be
// checked. it gets the BindingFlag IMMUTABLE_IS_INITIALIZED.
// Accessing an uninitialized binding produces the undefined value.
//
// The harmony proposal for block scoped bindings also introduces the
// uninitialized state for mutable bindings. A 'let' declared variable
// is a mutable binding that is created uninitalized upon activation of its
// lexical environment and it is initialized when evaluating its declaration
// statement. Var declared variables are mutable bindings that are
// immediately initialized upon creation. The BindingFlags enum represents
// information if a binding has definitely been initialized. 'const' declared
// variables are created as uninitialized immutable bindings.
// In harmony mode accessing an uninitialized binding produces a reference
// error.
// uninitialized state for mutable bindings.
// * A 'let' declared variable. They are initialized when evaluating the
// corresponding declaration statement. They need to be checked for being
// initialized and thus get the flag MUTABLE_CHECK_INITIALIZED.
// * A 'var' declared variable. It is initialized immediately upon creation
// and thus doesn't need to be checked. It gets the flag
// MUTABLE_IS_INITIALIZED.
// * Catch bound variables, function parameters and variables introduced by
// function declarations are initialized immediately and do not need to be
// checked. Thus they get the flag MUTABLE_IS_INITIALIZED.
// Immutable bindings in harmony mode get the _HARMONY flag variants. Accessing
// an uninitialized binding produces a reference error.
//
// In V8 uninitialized bindings are set to the hole value upon creation and set
// to a different value upon initialization.
enum BindingFlags {
MUTABLE_IS_INITIALIZED,
MUTABLE_CHECK_INITIALIZED,
IMMUTABLE_IS_INITIALIZED,
IMMUTABLE_CHECK_INITIALIZED,
IMMUTABLE_IS_INITIALIZED_HARMONY,
IMMUTABLE_CHECK_INITIALIZED_HARMONY,
MISSING_BINDING
};
@ -134,9 +153,13 @@ enum BindingFlags {
V(MAP_CACHE_INDEX, Object, map_cache) \
V(CONTEXT_DATA_INDEX, Object, data) \
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \
to_complete_property_descriptor) \
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap)
V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap) \
V(PROXY_ENUMERATE, JSFunction, proxy_enumerate) \
V(RANDOM_SEED_INDEX, ByteArray, random_seed)
// JSFunctions are pairs (context, function code), sometimes also called
// closures. A Context object is used to represent function contexts and
@ -192,7 +215,8 @@ class Context: public FixedArray {
PREVIOUS_INDEX,
// The extension slot is used for either the global object (in global
// contexts), eval extension object (function contexts), subject of with
// (with contexts), or the variable name (catch contexts).
// (with contexts), or the variable name (catch contexts), the serialized
// scope info (block contexts).
EXTENSION_INDEX,
GLOBAL_INDEX,
MIN_CONTEXT_SLOTS,
@ -252,9 +276,12 @@ class Context: public FixedArray {
OUT_OF_MEMORY_INDEX,
CONTEXT_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX,
DERIVED_HAS_TRAP_INDEX,
DERIVED_GET_TRAP_INDEX,
DERIVED_SET_TRAP_INDEX,
PROXY_ENUMERATE,
RANDOM_SEED_INDEX,
// Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references.
@ -330,12 +357,6 @@ class Context: public FixedArray {
// Mark the global context with out of memory.
inline void mark_out_of_memory();
// The exception holder is the object used as a with object in
// the implementation of a catch block.
bool is_exception_holder(Object* object) {
return IsCatchContext() && extension() == object;
}
// A global context hold a list of all functions which have been optimized.
void AddOptimizedFunction(JSFunction* function);
void RemoveOptimizedFunction(JSFunction* function);
@ -355,46 +376,28 @@ class Context: public FixedArray {
#undef GLOBAL_CONTEXT_FIELD_ACCESSORS
// Lookup the the slot called name, starting with the current context.
// There are 4 possible outcomes:
//
// 1) index_ >= 0 && result->IsContext():
// most common case, the result is a Context, and index is the
// context slot index, and the slot exists.
// attributes == READ_ONLY for the function name variable, NONE otherwise.
// There are three possibilities:
//
// 2) index_ >= 0 && result->IsJSObject():
// the result is the JSObject arguments object, the index is the parameter
// index, i.e., key into the arguments object, and the property exists.
// attributes != ABSENT.
// 1) result->IsContext():
// The binding was found in a context. *index is always the
// non-negative slot index. *attributes is NONE for var and let
// declarations, READ_ONLY for const declarations (never ABSENT).
//
// 3) index_ < 0 && result->IsJSObject():
// the result is the JSObject extension context or the global object,
// and the name is the property name, and the property exists.
// attributes != ABSENT.
// 2) result->IsJSObject():
// The binding was found as a named property in a context extension
// object (i.e., was introduced via eval), as a property on the subject
// of with, or as a property of the global object. *index is -1 and
// *attributes is not ABSENT.
//
// 4) index_ < 0 && result.is_null():
// there was no context found with the corresponding property.
// attributes == ABSENT.
// 3) result.is_null():
// There was no binding found, *index is always -1 and *attributes is
// always ABSENT.
Handle<Object> Lookup(Handle<String> name,
ContextLookupFlags flags,
int* index_,
int* index,
PropertyAttributes* attributes,
BindingFlags* binding_flags);
// Determine if a local variable with the given name exists in a
// context. Do not consider context extension objects. This is
// used for compiling code using eval. If the context surrounding
// the eval call does not have a local variable with this name and
// does not contain a with statement the property is global unless
// it is shadowed by a property in an extension object introduced by
// eval.
bool GlobalIfNotShadowedByEval(Handle<String> name);
// Determine if any function scope in the context call eval and if
// any of those calls are in non-strict mode.
void ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
bool* outer_scope_calls_non_strict_eval);
// Code generation support.
static int SlotOffset(int index) {
return kHeaderSize + index * kPointerSize - kHeapObjectTag;

48
deps/v8/src/conversions-inl.h

@ -46,15 +46,15 @@
namespace v8 {
namespace internal {
static inline double JunkStringValue() {
return std::numeric_limits<double>::quiet_NaN();
inline double JunkStringValue() {
return BitCast<double, uint64_t>(kQuietNaNMask);
}
// The fast double-to-unsigned-int conversion routine does not guarantee
// rounding towards zero, or any reasonable value if the argument is larger
// than what fits in an unsigned 32-bit integer.
static inline unsigned int FastD2UI(double x) {
inline unsigned int FastD2UI(double x) {
// There is no unsigned version of lrint, so there is no fast path
// in this function as there is in FastD2I. Using lrint doesn't work
// for values of 2^31 and above.
@ -80,7 +80,7 @@ static inline unsigned int FastD2UI(double x) {
}
static inline double DoubleToInteger(double x) {
inline double DoubleToInteger(double x) {
if (isnan(x)) return 0;
if (!isfinite(x) || x == 0) return x;
return (x >= 0) ? floor(x) : ceil(x);
@ -103,9 +103,9 @@ int32_t DoubleToInt32(double x) {
template <class Iterator, class EndMark>
static bool SubStringEquals(Iterator* current,
EndMark end,
const char* substring) {
bool SubStringEquals(Iterator* current,
EndMark end,
const char* substring) {
ASSERT(**current == *substring);
for (substring++; *substring != '\0'; substring++) {
++*current;
@ -119,9 +119,9 @@ static bool SubStringEquals(Iterator* current,
// Returns true if a nonspace character has been found and false if the
// end was been reached before finding a nonspace character.
template <class Iterator, class EndMark>
static inline bool AdvanceToNonspace(UnicodeCache* unicode_cache,
Iterator* current,
EndMark end) {
inline bool AdvanceToNonspace(UnicodeCache* unicode_cache,
Iterator* current,
EndMark end) {
while (*current != end) {
if (!unicode_cache->IsWhiteSpace(**current)) return true;
++*current;
@ -132,11 +132,11 @@ static inline bool AdvanceToNonspace(UnicodeCache* unicode_cache,
// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
template <int radix_log_2, class Iterator, class EndMark>
static double InternalStringToIntDouble(UnicodeCache* unicode_cache,
Iterator current,
EndMark end,
bool negative,
bool allow_trailing_junk) {
double InternalStringToIntDouble(UnicodeCache* unicode_cache,
Iterator current,
EndMark end,
bool negative,
bool allow_trailing_junk) {
ASSERT(current != end);
// Skip leading 0s.
@ -235,10 +235,10 @@ static double InternalStringToIntDouble(UnicodeCache* unicode_cache,
template <class Iterator, class EndMark>
static double InternalStringToInt(UnicodeCache* unicode_cache,
Iterator current,
EndMark end,
int radix) {
double InternalStringToInt(UnicodeCache* unicode_cache,
Iterator current,
EndMark end,
int radix) {
const bool allow_trailing_junk = true;
const double empty_string_val = JunkStringValue();
@ -430,11 +430,11 @@ static double InternalStringToInt(UnicodeCache* unicode_cache,
// 2. *current - gets the current character in the sequence.
// 3. ++current (advances the position).
template <class Iterator, class EndMark>
static double InternalStringToDouble(UnicodeCache* unicode_cache,
Iterator current,
EndMark end,
int flags,
double empty_string_val) {
double InternalStringToDouble(UnicodeCache* unicode_cache,
Iterator current,
EndMark end,
int flags,
double empty_string_val) {
// To make sure that iterator dereferencing is valid the following
// convention is used:
// 1. Each '++current' statement is followed by check for equality to 'end'.

20
deps/v8/src/conversions.h

@ -28,8 +28,6 @@
#ifndef V8_CONVERSIONS_H_
#define V8_CONVERSIONS_H_
#include <limits>
#include "utils.h"
namespace v8 {
@ -47,14 +45,14 @@ class UnicodeCache;
const int kMaxSignificantDigits = 772;
static inline bool isDigit(int x, int radix) {
inline bool isDigit(int x, int radix) {
return (x >= '0' && x <= '9' && x < '0' + radix)
|| (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
|| (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
}
static inline double SignedZero(bool negative) {
inline double SignedZero(bool negative) {
return negative ? -0.0 : 0.0;
}
@ -63,16 +61,16 @@ static inline double SignedZero(bool negative) {
// rounding towards zero.
// The result is unspecified if x is infinite or NaN, or if the rounded
// integer value is outside the range of type int.
static inline int FastD2I(double x) {
inline int FastD2I(double x) {
// The static_cast convertion from double to int used to be slow, but
// as new benchmarks show, now it is much faster than lrint().
return static_cast<int>(x);
}
static inline unsigned int FastD2UI(double x);
inline unsigned int FastD2UI(double x);
static inline double FastI2D(int x) {
inline double FastI2D(int x) {
// There is no rounding involved in converting an integer to a
// double, so this code should compile to a few instructions without
// any FPU pipeline stalls.
@ -80,7 +78,7 @@ static inline double FastI2D(int x) {
}
static inline double FastUI2D(unsigned x) {
inline double FastUI2D(unsigned x) {
// There is no rounding involved in converting an unsigned integer to a
// double, so this code should compile to a few instructions without
// any FPU pipeline stalls.
@ -89,15 +87,15 @@ static inline double FastUI2D(unsigned x) {
// This function should match the exact semantics of ECMA-262 9.4.
static inline double DoubleToInteger(double x);
inline double DoubleToInteger(double x);
// This function should match the exact semantics of ECMA-262 9.5.
static inline int32_t DoubleToInt32(double x);
inline int32_t DoubleToInt32(double x);
// This function should match the exact semantics of ECMA-262 9.6.
static inline uint32_t DoubleToUint32(double x) {
inline uint32_t DoubleToUint32(double x) {
return static_cast<uint32_t>(DoubleToInt32(x));
}

5
deps/v8/src/d8-debug.cc

@ -1,4 +1,4 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -25,6 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef ENABLE_DEBUGGER_SUPPORT
#include "d8.h"
#include "d8-debug.h"
@ -367,3 +368,5 @@ void KeyboardThread::Run() {
} // namespace v8
#endif // ENABLE_DEBUGGER_SUPPORT

78
deps/v8/src/d8.cc

@ -146,11 +146,11 @@ bool Shell::ExecuteString(Handle<String> source,
Handle<Value> name,
bool print_result,
bool report_exceptions) {
#ifndef V8_SHARED
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
bool FLAG_debugger = i::FLAG_debugger;
#else
bool FLAG_debugger = false;
#endif // V8_SHARED
#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
HandleScope handle_scope;
TryCatch try_catch;
options.script_executed = true;
@ -178,7 +178,8 @@ bool Shell::ExecuteString(Handle<String> source,
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::Utf8Value str(result);
fwrite(*str, sizeof(**str), str.length(), stdout);
size_t count = fwrite(*str, sizeof(**str), str.length(), stdout);
(void) count; // Silence GCC-4.5.x "unused result" warning.
printf("\n");
}
return true;
@ -594,6 +595,7 @@ void Shell::InstallUtilityScript() {
Context::Scope utility_scope(utility_context_);
#ifdef ENABLE_DEBUGGER_SUPPORT
if (i::FLAG_debugger) printf("JavaScript debugger enabled\n");
// Install the debugger object in the utility scope
i::Debug* debug = i::Isolate::Current()->debug();
debug->Load();
@ -792,22 +794,47 @@ void Shell::Exit(int exit_code) {
#ifndef V8_SHARED
struct CounterAndKey {
Counter* counter;
const char* key;
};
int CompareKeys(const void* a, const void* b) {
return strcmp(static_cast<const CounterAndKey*>(a)->key,
static_cast<const CounterAndKey*>(b)->key);
}
void Shell::OnExit() {
if (console != NULL) console->Close();
if (i::FLAG_dump_counters) {
printf("+----------------------------------------+-------------+\n");
printf("| Name | Value |\n");
printf("+----------------------------------------+-------------+\n");
int number_of_counters = 0;
for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
Counter* counter = i.CurrentValue();
number_of_counters++;
}
CounterAndKey* counters = new CounterAndKey[number_of_counters];
int j = 0;
for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
counters[j].counter = i.CurrentValue();
counters[j].key = i.CurrentKey();
}
qsort(counters, number_of_counters, sizeof(counters[0]), CompareKeys);
printf("+--------------------------------------------+-------------+\n");
printf("| Name | Value |\n");
printf("+--------------------------------------------+-------------+\n");
for (j = 0; j < number_of_counters; j++) {
Counter* counter = counters[j].counter;
const char* key = counters[j].key;
if (counter->is_histogram()) {
printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
printf("| t:%-36s | %11i |\n", i.CurrentKey(), counter->sample_total());
printf("| c:%-40s | %11i |\n", key, counter->count());
printf("| t:%-40s | %11i |\n", key, counter->sample_total());
} else {
printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
printf("| %-42s | %11i |\n", key, counter->count());
}
}
printf("+----------------------------------------+-------------+\n");
printf("+--------------------------------------------+-------------+\n");
delete [] counters;
}
if (counters_file_ != NULL)
delete counters_file_;
@ -816,7 +843,7 @@ void Shell::OnExit() {
static FILE* FOpen(const char* path, const char* mode) {
#if (defined(_WIN32) || defined(_WIN64))
#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
FILE* result;
if (fopen_s(&result, path, mode) == 0) {
return result;
@ -900,9 +927,6 @@ void Shell::RunShell() {
#ifndef V8_SHARED
console = LineEditor::Get();
printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
if (i::FLAG_debugger) {
printf("JavaScript debugger enabled\n");
}
console->Open();
while (true) {
i::SmartArrayPointer<char> input = console->Prompt(Shell::kPrompt);
@ -1253,14 +1277,22 @@ int Shell::RunMain(int argc, char* argv[]) {
Locker lock;
HandleScope scope;
Persistent<Context> context = CreateEvaluationContext();
if (options.last_run) {
// Keep using the same context in the interactive shell.
evaluation_context_ = context;
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
// If the interactive debugger is enabled make sure to activate
// it before running the files passed on the command line.
if (i::FLAG_debugger) {
InstallUtilityScript();
}
#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
}
{
Context::Scope cscope(context);
options.isolate_sources[0].Execute();
}
if (options.last_run) {
// Keep using the same context in the interactive shell
evaluation_context_ = context;
} else {
if (!options.last_run) {
context.Dispose();
}
@ -1331,9 +1363,11 @@ int Shell::Main(int argc, char* argv[]) {
if (( options.interactive_shell
|| !options.script_executed )
&& !options.test_shell ) {
#ifndef V8_SHARED
InstallUtilityScript();
#endif // V8_SHARED
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
if (!i::FLAG_debugger) {
InstallUtilityScript();
}
#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
RunShell();
}

2
deps/v8/src/d8.gyp

@ -65,7 +65,7 @@
'sources': [ 'd8-readline.cc' ],
}],
[ '(OS=="linux" or OS=="mac" or OS=="freebsd" \
or OS=="openbsd" or OS=="solaris")', {
or OS=="openbsd" or OS=="solaris" or OS=="android")', {
'sources': [ 'd8-posix.cc', ]
}],
[ 'OS=="win"', {

109
deps/v8/src/d8.js

@ -26,10 +26,11 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
String.prototype.startsWith = function (str) {
if (str.length > this.length)
if (str.length > this.length) {
return false;
}
return this.substr(0, str.length) == str;
}
};
function log10(num) {
return Math.log(num)/Math.log(10);
@ -52,8 +53,9 @@ function GetCompletions(global, last, full) {
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
var next = current[part];
if (!next)
if (!next) {
return [];
}
current = next;
}
var result = [];
@ -63,8 +65,9 @@ function GetCompletions(global, last, full) {
var properties = mirror.properties();
for (var i = 0; i < properties.length; i++) {
var name = properties[i].name();
if (typeof name === 'string' && name.startsWith(last))
if (typeof name === 'string' && name.startsWith(last)) {
result.push(name);
}
}
current = ToInspectableObject(current.__proto__);
}
@ -114,7 +117,7 @@ Debug.State = {
displaySourceStartLine: -1,
displaySourceEndLine: -1,
currentSourceLine: -1
}
};
var trace_compile = false; // Tracing all compile events?
var trace_debug_json = false; // Tracing all debug json packets?
var last_cmd_line = '';
@ -150,7 +153,7 @@ function DebugMessageDetails(message) {
}
function DebugEventDetails(response) {
details = {text:'', running:false}
details = {text:'', running:false};
// Get the running state.
details.running = response.running();
@ -217,7 +220,7 @@ function DebugEventDetails(response) {
case 'afterCompile':
if (trace_compile) {
result = 'Source ' + body.script.name + ' compiled:\n'
result = 'Source ' + body.script.name + ' compiled:\n';
var source = body.script.source;
if (!(source[source.length - 1] == '\n')) {
result += source;
@ -237,7 +240,7 @@ function DebugEventDetails(response) {
}
return details;
};
}
function SourceInfo(body) {
@ -279,7 +282,7 @@ function SourceUnderline(source_text, position) {
// Return the source line text with the underline beneath.
return source_text + '\n' + underline;
};
}
// Converts a text command to a JSON request.
@ -289,7 +292,7 @@ function DebugCommandToJSONRequest(cmd_line) {
print("sending: '" + result + "'");
}
return result;
};
}
function DebugRequest(cmd_line) {
@ -514,7 +517,7 @@ function DebugRequest(cmd_line) {
DebugRequest.prototype.JSONRequest = function() {
return this.request_;
}
};
function RequestPacket(command) {
@ -536,14 +539,14 @@ RequestPacket.prototype.toJSONProtocol = function() {
json += ',"arguments":';
// Encode the arguments part.
if (this.arguments.toJSONProtocol) {
json += this.arguments.toJSONProtocol()
json += this.arguments.toJSONProtocol();
} else {
json += SimpleObjectToJSON_(this.arguments);
}
}
json += '}';
return json;
}
};
DebugRequest.prototype.createRequest = function(command) {
@ -1310,7 +1313,7 @@ DebugRequest.prototype.lolMakeListRequest =
}
return request;
}
};
function extractObjId(args) {
@ -1499,7 +1502,7 @@ DebugRequest.prototype.traceCommand_ = function(args) {
} else {
throw new Error('Invalid trace arguments.');
}
}
};
// Handle the help command.
DebugRequest.prototype.helpCommand_ = function(args) {
@ -1608,7 +1611,7 @@ DebugRequest.prototype.helpCommand_ = function(args) {
print('');
print('disconnect|exit|quit - disconnects and quits the debugger');
print('help - prints this help information');
}
};
function formatHandleReference_(value) {
@ -1623,7 +1626,7 @@ function formatHandleReference_(value) {
function formatObject_(value, include_properties) {
var result = '';
result += formatHandleReference_(value);
result += ', type: object'
result += ', type: object';
result += ', constructor ';
var ctor = value.constructorFunctionValue();
result += formatHandleReference_(ctor);
@ -1943,7 +1946,7 @@ function roundNumber(num, length) {
// Convert a JSON response to text for display in a text based debugger.
function DebugResponseDetails(response) {
details = {text:'', running:false}
details = { text: '', running: false };
try {
if (!response.success()) {
@ -2308,7 +2311,7 @@ function DebugResponseDetails(response) {
}
return details;
};
}
/**
@ -2334,7 +2337,7 @@ function ProtocolPackage(json) {
*/
ProtocolPackage.prototype.type = function() {
return this.packet_.type;
}
};
/**
@ -2343,7 +2346,7 @@ ProtocolPackage.prototype.type = function() {
*/
ProtocolPackage.prototype.event = function() {
return this.packet_.event;
}
};
/**
@ -2352,7 +2355,7 @@ ProtocolPackage.prototype.event = function() {
*/
ProtocolPackage.prototype.requestSeq = function() {
return this.packet_.request_seq;
}
};
/**
@ -2361,27 +2364,27 @@ ProtocolPackage.prototype.requestSeq = function() {
*/
ProtocolPackage.prototype.running = function() {
return this.packet_.running ? true : false;
}
};
ProtocolPackage.prototype.success = function() {
return this.packet_.success ? true : false;
}
};
ProtocolPackage.prototype.message = function() {
return this.packet_.message;
}
};
ProtocolPackage.prototype.command = function() {
return this.packet_.command;
}
};
ProtocolPackage.prototype.body = function() {
return this.packet_.body;
}
};
ProtocolPackage.prototype.bodyValue = function(index) {
@ -2390,12 +2393,12 @@ ProtocolPackage.prototype.bodyValue = function(index) {
} else {
return new ProtocolValue(this.packet_.body, this);
}
}
};
ProtocolPackage.prototype.body = function() {
return this.packet_.body;
}
};
ProtocolPackage.prototype.lookup = function(handle) {
@ -2405,12 +2408,12 @@ ProtocolPackage.prototype.lookup = function(handle) {
} else {
return new ProtocolReference(handle);
}
}
};
ProtocolPackage.prototype.raw_json = function() {
return this.raw_json_;
}
};
function ProtocolValue(value, packet) {
@ -2425,7 +2428,7 @@ function ProtocolValue(value, packet) {
*/
ProtocolValue.prototype.type = function() {
return this.value_.type;
}
};
/**
@ -2434,7 +2437,7 @@ ProtocolValue.prototype.type = function() {
*/
ProtocolValue.prototype.field = function(name) {
return this.value_[name];
}
};
/**
@ -2444,7 +2447,7 @@ ProtocolValue.prototype.field = function(name) {
ProtocolValue.prototype.isPrimitive = function() {
return this.isUndefined() || this.isNull() || this.isBoolean() ||
this.isNumber() || this.isString();
}
};
/**
@ -2453,7 +2456,7 @@ ProtocolValue.prototype.isPrimitive = function() {
*/
ProtocolValue.prototype.handle = function() {
return this.value_.handle;
}
};
/**
@ -2462,7 +2465,7 @@ ProtocolValue.prototype.handle = function() {
*/
ProtocolValue.prototype.isUndefined = function() {
return this.value_.type == 'undefined';
}
};
/**
@ -2471,7 +2474,7 @@ ProtocolValue.prototype.isUndefined = function() {
*/
ProtocolValue.prototype.isNull = function() {
return this.value_.type == 'null';
}
};
/**
@ -2480,7 +2483,7 @@ ProtocolValue.prototype.isNull = function() {
*/
ProtocolValue.prototype.isBoolean = function() {
return this.value_.type == 'boolean';
}
};
/**
@ -2489,7 +2492,7 @@ ProtocolValue.prototype.isBoolean = function() {
*/
ProtocolValue.prototype.isNumber = function() {
return this.value_.type == 'number';
}
};
/**
@ -2498,7 +2501,7 @@ ProtocolValue.prototype.isNumber = function() {
*/
ProtocolValue.prototype.isString = function() {
return this.value_.type == 'string';
}
};
/**
@ -2508,7 +2511,7 @@ ProtocolValue.prototype.isString = function() {
ProtocolValue.prototype.isObject = function() {
return this.value_.type == 'object' || this.value_.type == 'function' ||
this.value_.type == 'error' || this.value_.type == 'regexp';
}
};
/**
@ -2518,7 +2521,7 @@ ProtocolValue.prototype.isObject = function() {
ProtocolValue.prototype.constructorFunctionValue = function() {
var ctor = this.value_.constructorFunction;
return this.packet_.lookup(ctor.ref);
}
};
/**
@ -2528,7 +2531,7 @@ ProtocolValue.prototype.constructorFunctionValue = function() {
ProtocolValue.prototype.protoObjectValue = function() {
var proto = this.value_.protoObject;
return this.packet_.lookup(proto.ref);
}
};
/**
@ -2537,7 +2540,7 @@ ProtocolValue.prototype.protoObjectValue = function() {
*/
ProtocolValue.prototype.propertyCount = function() {
return this.value_.properties ? this.value_.properties.length : 0;
}
};
/**
@ -2547,7 +2550,7 @@ ProtocolValue.prototype.propertyCount = function() {
ProtocolValue.prototype.propertyName = function(index) {
var property = this.value_.properties[index];
return property.name;
}
};
/**
@ -2562,7 +2565,7 @@ ProtocolValue.prototype.propertyIndex = function(name) {
}
}
return null;
}
};
/**
@ -2572,7 +2575,7 @@ ProtocolValue.prototype.propertyIndex = function(name) {
ProtocolValue.prototype.propertyValue = function(index) {
var property = this.value_.properties[index];
return this.packet_.lookup(property.ref);
}
};
/**
@ -2581,12 +2584,12 @@ ProtocolValue.prototype.propertyValue = function(index) {
*/
ProtocolValue.prototype.value = function() {
return this.value_.value;
}
};
ProtocolValue.prototype.valueString = function() {
return this.value_.text;
}
};
function ProtocolReference(handle) {
@ -2596,7 +2599,7 @@ function ProtocolReference(handle) {
ProtocolReference.prototype.handle = function() {
return this.handle_;
}
};
function MakeJSONPair_(name, value) {
@ -2667,7 +2670,7 @@ function StringToJSON_(value) {
// Convert control character to unicode escape sequence.
return '\\u00' +
'0' + // TODO %NumberToRadixString(Math.floor(mapped / 16), 16) +
'0' // TODO %NumberToRadixString(mapped % 16, 16);
'0'; // TODO %NumberToRadixString(mapped % 16, 16)
})
+ '"';
}
@ -2738,7 +2741,7 @@ function SimpleObjectToJSON_(object) {
if (property_value === null) {
property_value_json = 'null';
} else if (typeof property_value.toJSONProtocol == 'function') {
property_value_json = property_value.toJSONProtocol(true)
property_value_json = property_value.toJSONProtocol(true);
} else if (property_value.constructor.name == 'Array'){
property_value_json = SimpleArrayToJSON_(property_value);
} else {
@ -2789,7 +2792,7 @@ function SimpleArrayToJSON_(array) {
}
var elem = array[i];
if (elem.toJSONProtocol) {
json += elem.toJSONProtocol(true)
json += elem.toJSONProtocol(true);
} else if (typeof(elem) === 'object') {
json += SimpleObjectToJSON_(elem);
} else if (typeof(elem) === 'boolean') {

51
deps/v8/src/date.js

@ -294,8 +294,8 @@ function TimeInYear(year) {
}
var ymd_from_time_cache = [$NaN, $NaN, $NaN];
var ymd_from_time_cached_time = $NaN;
var ymd_from_time_cache = [1970, 0, 1];
var ymd_from_time_cached_time = 0;
function YearFromTime(t) {
if (t !== ymd_from_time_cached_time) {
@ -304,7 +304,7 @@ function YearFromTime(t) {
}
%DateYMDFromTime(t, ymd_from_time_cache);
ymd_from_time_cached_time = t
ymd_from_time_cached_time = t;
}
return ymd_from_time_cache[0];
@ -316,7 +316,7 @@ function MonthFromTime(t) {
return $NaN;
}
%DateYMDFromTime(t, ymd_from_time_cache);
ymd_from_time_cached_time = t
ymd_from_time_cached_time = t;
}
return ymd_from_time_cache[1];
@ -329,7 +329,7 @@ function DateFromTime(t) {
}
%DateYMDFromTime(t, ymd_from_time_cache);
ymd_from_time_cached_time = t
ymd_from_time_cached_time = t;
}
return ymd_from_time_cache[2];
@ -351,13 +351,12 @@ function MakeDay(year, month, date) {
date = TO_INTEGER_MAP_MINUS_ZERO(date);
if (year < kMinYear || year > kMaxYear ||
month < kMinMonth || month > kMaxMonth ||
date < kMinDate || date > kMaxDate) {
month < kMinMonth || month > kMaxMonth) {
return $NaN;
}
// Now we rely on year, month and date being SMIs.
return %DateMakeDay(year, month, date);
// Now we rely on year and month being SMIs.
return %DateMakeDay(year, month) + date - 1;
}
@ -446,8 +445,9 @@ var Date_cache = {
minutes = argc > 4 ? ToNumber(minutes) : 0;
seconds = argc > 5 ? ToNumber(seconds) : 0;
ms = argc > 6 ? ToNumber(ms) : 0;
year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
? 1900 + TO_INTEGER(year) : year;
year = (!NUMBER_IS_NAN(year) &&
0 <= TO_INTEGER(year) &&
TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
var day = MakeDay(year, month, date);
var time = MakeTime(hours, minutes, seconds, ms);
value = TimeClip(UTC(MakeDate(day, time)));
@ -460,7 +460,8 @@ var Date_cache = {
var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
function TwoDigitString(value) {
@ -476,8 +477,10 @@ function DateString(time) {
}
var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday'];
var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'];
function LongDateString(time) {
@ -557,8 +560,9 @@ function DateUTC(year, month, date, hours, minutes, seconds, ms) {
minutes = argc > 4 ? ToNumber(minutes) : 0;
seconds = argc > 5 ? ToNumber(seconds) : 0;
ms = argc > 6 ? ToNumber(ms) : 0;
year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
? 1900 + TO_INTEGER(year) : year;
year = (!NUMBER_IS_NAN(year) &&
0 <= TO_INTEGER(year) &&
TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
var day = MakeDay(year, month, date);
var time = MakeTime(hours, minutes, seconds, ms);
return %_SetValueOf(this, TimeClip(MakeDate(day, time)));
@ -778,7 +782,10 @@ function DateSetTime(ms) {
function DateSetMilliseconds(ms) {
var t = LocalTime(DATE_VALUE(this));
ms = ToNumber(ms);
var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), SEC_FROM_TIME(t), ms);
var time = MakeTime(HOUR_FROM_TIME(t),
MIN_FROM_TIME(t),
SEC_FROM_TIME(t),
ms);
return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
}
@ -787,7 +794,10 @@ function DateSetMilliseconds(ms) {
function DateSetUTCMilliseconds(ms) {
var t = DATE_VALUE(this);
ms = ToNumber(ms);
var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), SEC_FROM_TIME(t), ms);
var time = MakeTime(HOUR_FROM_TIME(t),
MIN_FROM_TIME(t),
SEC_FROM_TIME(t),
ms);
return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
}
@ -978,9 +988,10 @@ function PadInt(n, digits) {
}
// ECMA 262 - 15.9.5.43
function DateToISOString() {
var t = DATE_VALUE(this);
if (NUMBER_IS_NAN(t)) return kInvalidDate;
if (NUMBER_IS_NAN(t)) throw MakeRangeError("invalid_time_value", []);
var year = this.getUTCFullYear();
var year_string;
if (year >= 0 && year <= 9999) {
@ -1062,7 +1073,7 @@ function SetUpDate() {
// Set up non-enumerable functions of the Date prototype object and
// set their names.
InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
InstallFunctions($Date.prototype, DONT_ENUM, $Array(
"toString", DateToString,
"toDateString", DateToDateString,
"toTimeString", DateToTimeString,

147
deps/v8/src/debug-debugger.js

@ -286,7 +286,7 @@ ScriptBreakPoint.prototype.cloneForOtherScript = function (other_script) {
copy.condition_ = this.condition_;
copy.ignoreCount_ = this.ignoreCount_;
return copy;
}
};
ScriptBreakPoint.prototype.number = function() {
@ -335,13 +335,13 @@ ScriptBreakPoint.prototype.actual_locations = function() {
locations.push(this.break_points_[i].actual_location);
}
return locations;
}
};
ScriptBreakPoint.prototype.update_positions = function(line, column) {
this.line_ = line;
this.column_ = column;
}
};
ScriptBreakPoint.prototype.hit_count = function() {
@ -477,9 +477,10 @@ ScriptBreakPoint.prototype.clear = function () {
// break points set in this script.
function UpdateScriptBreakPoints(script) {
for (var i = 0; i < script_break_points.length; i++) {
if (script_break_points[i].type() == Debug.ScriptBreakPointType.ScriptName &&
script_break_points[i].matchesScript(script)) {
script_break_points[i].set(script);
var break_point = script_break_points[i];
if ((break_point.type() == Debug.ScriptBreakPointType.ScriptName) &&
break_point.matchesScript(script)) {
break_point.set(script);
}
}
}
@ -585,7 +586,7 @@ Debug.findFunctionSourceLocation = function(func, opt_line, opt_column) {
var script = %FunctionGetScript(func);
var script_offset = %FunctionGetScriptSourcePosition(func);
return script.locationFromLine(opt_line, opt_column, script_offset);
}
};
// Returns the character position in a script based on a line number and an
@ -593,7 +594,7 @@ Debug.findFunctionSourceLocation = function(func, opt_line, opt_column) {
Debug.findScriptSourcePosition = function(script, opt_line, opt_column) {
var location = script.locationFromLine(opt_line, opt_column);
return location ? location.position : null;
}
};
Debug.findBreakPoint = function(break_point_number, remove) {
@ -627,7 +628,7 @@ Debug.findBreakPointActualLocations = function(break_point_number) {
}
}
return [];
}
};
Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) {
if (!IS_FUNCTION(func)) throw new Error('Parameters have wrong types.');
@ -677,8 +678,9 @@ Debug.setBreakPointByScriptIdAndPosition = function(script_id, position,
{
break_point = MakeBreakPoint(position);
break_point.setCondition(condition);
if (!enabled)
if (!enabled) {
break_point.disable();
}
var scripts = this.scripts();
for (var i = 0; i < scripts.length; i++) {
if (script_id == scripts[i].id) {
@ -771,7 +773,7 @@ Debug.findScriptBreakPoint = function(break_point_number, remove) {
}
}
return script_break_point;
}
};
// Sets a breakpoint in a script identified through id or name at the
@ -799,7 +801,7 @@ Debug.setScriptBreakPoint = function(type, script_id_or_name,
}
return script_break_point.number();
}
};
Debug.setScriptBreakPointById = function(script_id,
@ -808,7 +810,7 @@ Debug.setScriptBreakPointById = function(script_id,
return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
script_id, opt_line, opt_column,
opt_condition, opt_groupId);
}
};
Debug.setScriptBreakPointByName = function(script_name,
@ -817,7 +819,7 @@ Debug.setScriptBreakPointByName = function(script_name,
return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptName,
script_name, opt_line, opt_column,
opt_condition, opt_groupId);
}
};
Debug.setScriptBreakPointByRegExp = function(script_regexp,
@ -826,7 +828,7 @@ Debug.setScriptBreakPointByRegExp = function(script_regexp,
return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptRegExp,
script_regexp, opt_line, opt_column,
opt_condition, opt_groupId);
}
};
Debug.enableScriptBreakPoint = function(break_point_number) {
@ -841,13 +843,15 @@ Debug.disableScriptBreakPoint = function(break_point_number) {
};
Debug.changeScriptBreakPointCondition = function(break_point_number, condition) {
Debug.changeScriptBreakPointCondition = function(
break_point_number, condition) {
var script_break_point = this.findScriptBreakPoint(break_point_number, false);
script_break_point.setCondition(condition);
};
Debug.changeScriptBreakPointIgnoreCount = function(break_point_number, ignoreCount) {
Debug.changeScriptBreakPointIgnoreCount = function(
break_point_number, ignoreCount) {
if (ignoreCount < 0) {
throw new Error('Invalid argument');
}
@ -858,12 +862,12 @@ Debug.changeScriptBreakPointIgnoreCount = function(break_point_number, ignoreCou
Debug.scriptBreakPoints = function() {
return script_break_points;
}
};
Debug.clearStepping = function() {
%ClearStepping();
}
};
Debug.setBreakOnException = function() {
return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, true);
@ -940,7 +944,7 @@ ExecutionState.prototype.prepareStep = function(opt_action, opt_count) {
var count = opt_count ? %ToNumber(opt_count) : 1;
return %PrepareStep(this.break_id, action, count);
}
};
ExecutionState.prototype.evaluateGlobal = function(source, disable_break,
opt_additional_context) {
@ -960,8 +964,9 @@ ExecutionState.prototype.threadCount = function() {
ExecutionState.prototype.frame = function(opt_index) {
// If no index supplied return the selected frame.
if (opt_index == null) opt_index = this.selected_frame;
if (opt_index < 0 || opt_index >= this.frameCount())
if (opt_index < 0 || opt_index >= this.frameCount()) {
throw new Error('Illegal frame index.');
}
return new FrameMirror(this.break_id, opt_index);
};
@ -1088,12 +1093,12 @@ ExceptionEvent.prototype.eventType = function() {
ExceptionEvent.prototype.exception = function() {
return this.exception_;
}
};
ExceptionEvent.prototype.uncaught = function() {
return this.uncaught_;
}
};
ExceptionEvent.prototype.func = function() {
@ -1185,7 +1190,7 @@ CompileEvent.prototype.toJSONProtocol = function() {
o.body.script = this.script_;
return o.toJSONProtocol();
}
};
function MakeNewFunctionEvent(func) {
@ -1241,7 +1246,7 @@ ScriptCollectedEvent.prototype.toJSONProtocol = function() {
o.body = {};
o.body.script = { id: this.id() };
return o.toJSONProtocol();
}
};
function MakeScriptObject_(script, include_source) {
@ -1258,18 +1263,18 @@ function MakeScriptObject_(script, include_source) {
o.source = script.source();
}
return o;
};
}
function DebugCommandProcessor(exec_state, opt_is_running) {
this.exec_state_ = exec_state;
this.running_ = opt_is_running || false;
};
}
DebugCommandProcessor.prototype.processDebugRequest = function (request) {
return this.processDebugJSONRequest(request);
}
};
function ProtocolMessage(request) {
@ -1297,13 +1302,13 @@ ProtocolMessage.prototype.setOption = function(name, value) {
this.options_ = {};
}
this.options_[name] = value;
}
};
ProtocolMessage.prototype.failed = function(message) {
this.success = false;
this.message = message;
}
};
ProtocolMessage.prototype.toJSONProtocol = function() {
@ -1351,7 +1356,7 @@ ProtocolMessage.prototype.toJSONProtocol = function() {
}
json.running = this.running;
return JSON.stringify(json);
}
};
DebugCommandProcessor.prototype.createResponse = function(request) {
@ -1359,7 +1364,8 @@ DebugCommandProcessor.prototype.createResponse = function(request) {
};
DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request) {
DebugCommandProcessor.prototype.processDebugJSONRequest = function(
json_request) {
var request; // Current request.
var response; // Generated response.
try {
@ -1646,7 +1652,7 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ =
// Add the break point number to the response.
response.body = { type: type,
breakpoint: break_point_number }
breakpoint: break_point_number };
// Add break point information to the response.
if (break_point instanceof ScriptBreakPoint) {
@ -1660,7 +1666,8 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ =
response.body.type = 'scriptRegExp';
response.body.script_regexp = break_point.script_regexp_object().source;
} else {
throw new Error("Internal error: Unexpected breakpoint type: " + break_point.type());
throw new Error("Internal error: Unexpected breakpoint type: " +
break_point.type());
}
response.body.line = break_point.line();
response.body.column = break_point.column();
@ -1672,7 +1679,8 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ =
};
DebugCommandProcessor.prototype.changeBreakPointRequest_ = function(request, response) {
DebugCommandProcessor.prototype.changeBreakPointRequest_ = function(
request, response) {
// Check for legal request.
if (!request.arguments) {
response.failed('Missing arguments');
@ -1709,10 +1717,11 @@ DebugCommandProcessor.prototype.changeBreakPointRequest_ = function(request, res
if (!IS_UNDEFINED(ignoreCount)) {
Debug.changeBreakPointIgnoreCount(break_point, ignoreCount);
}
}
};
DebugCommandProcessor.prototype.clearBreakPointGroupRequest_ = function(request, response) {
DebugCommandProcessor.prototype.clearBreakPointGroupRequest_ = function(
request, response) {
// Check for legal request.
if (!request.arguments) {
response.failed('Missing arguments');
@ -1743,10 +1752,11 @@ DebugCommandProcessor.prototype.clearBreakPointGroupRequest_ = function(request,
// Add the cleared break point numbers to the response.
response.body = { breakpoints: cleared_break_points };
}
};
DebugCommandProcessor.prototype.clearBreakPointRequest_ = function(request, response) {
DebugCommandProcessor.prototype.clearBreakPointRequest_ = function(
request, response) {
// Check for legal request.
if (!request.arguments) {
response.failed('Missing arguments');
@ -1766,11 +1776,12 @@ DebugCommandProcessor.prototype.clearBreakPointRequest_ = function(request, resp
Debug.clearBreakPoint(break_point);
// Add the cleared break point number to the response.
response.body = { breakpoint: break_point }
}
response.body = { breakpoint: break_point };
};
DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(request, response) {
DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(
request, response) {
var array = [];
for (var i = 0; i < script_break_points.length; i++) {
var break_point = script_break_points[i];
@ -1785,7 +1796,7 @@ DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(request, resp
condition: break_point.condition(),
ignoreCount: break_point.ignoreCount(),
actual_locations: break_point.actual_locations()
}
};
if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) {
description.type = 'scriptId';
@ -1797,7 +1808,8 @@ DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(request, resp
description.type = 'scriptRegExp';
description.script_regexp = break_point.script_regexp_object().source;
} else {
throw new Error("Internal error: Unexpected breakpoint type: " + break_point.type());
throw new Error("Internal error: Unexpected breakpoint type: " +
break_point.type());
}
array.push(description);
}
@ -1806,15 +1818,15 @@ DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(request, resp
breakpoints: array,
breakOnExceptions: Debug.isBreakOnException(),
breakOnUncaughtExceptions: Debug.isBreakOnUncaughtException()
}
}
};
};
DebugCommandProcessor.prototype.disconnectRequest_ =
function(request, response) {
Debug.disableAllBreakPoints();
this.continueRequest_(request, response);
}
};
DebugCommandProcessor.prototype.setExceptionBreakRequest_ =
@ -1859,10 +1871,11 @@ DebugCommandProcessor.prototype.setExceptionBreakRequest_ =
// Add the cleared break point number to the response.
response.body = { 'type': type, 'enabled': enabled };
}
};
DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response) {
DebugCommandProcessor.prototype.backtraceRequest_ = function(
request, response) {
// Get the number of frames.
var total_frames = this.exec_state_.frameCount();
@ -1870,12 +1883,12 @@ DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response)
if (total_frames == 0) {
response.body = {
totalFrames: total_frames
}
};
return;
}
// Default frame range to include in backtrace.
var from_index = 0
var from_index = 0;
var to_index = kDefaultBacktraceLength;
// Get the range from the arguments.
@ -1888,7 +1901,7 @@ DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response)
}
if (request.arguments.bottom) {
var tmp_index = total_frames - from_index;
from_index = total_frames - to_index
from_index = total_frames - to_index;
to_index = tmp_index;
}
if (from_index < 0 || to_index < 0) {
@ -1914,7 +1927,7 @@ DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response)
toFrame: to_index,
totalFrames: total_frames,
frames: frames
}
};
};
@ -1938,8 +1951,8 @@ DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
// Get the frame for which the scope or scopes are requested. With no frameNumber
// argument use the currently selected frame.
// Get the frame for which the scope or scopes are requested.
// With no frameNumber argument use the currently selected frame.
if (request.arguments && !IS_UNDEFINED(request.arguments.frameNumber)) {
frame_index = request.arguments.frameNumber;
if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
@ -1949,7 +1962,7 @@ DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
} else {
return this.exec_state_.frame();
}
}
};
DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
@ -1972,7 +1985,7 @@ DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
toScope: total_scopes,
totalScopes: total_scopes,
scopes: scopes
}
};
};
@ -2217,7 +2230,8 @@ DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
if (!IS_UNDEFINED(request.arguments.types)) {
types = %ToNumber(request.arguments.types);
if (isNaN(types) || types < 0) {
return response.failed('Invalid types "' + request.arguments.types + '"');
return response.failed('Invalid types "' +
request.arguments.types + '"');
}
}
@ -2286,7 +2300,7 @@ DebugCommandProcessor.prototype.threadsRequest_ = function(request, response) {
var details = %GetThreadDetails(this.exec_state_.break_id, i);
var thread_info = { current: details[0],
id: details[1]
}
};
threads.push(thread_info);
}
@ -2294,7 +2308,7 @@ DebugCommandProcessor.prototype.threadsRequest_ = function(request, response) {
response.body = {
totalThreads: total_threads,
threads: threads
}
};
};
@ -2306,7 +2320,7 @@ DebugCommandProcessor.prototype.suspendRequest_ = function(request, response) {
DebugCommandProcessor.prototype.versionRequest_ = function(request, response) {
response.body = {
V8Version: %GetV8Version()
}
};
};
@ -2322,7 +2336,8 @@ DebugCommandProcessor.prototype.profileRequest_ = function(request, response) {
};
DebugCommandProcessor.prototype.changeLiveRequest_ = function(request, response) {
DebugCommandProcessor.prototype.changeLiveRequest_ = function(
request, response) {
if (!Debug.LiveEdit) {
return response.failed('LiveEdit feature is not supported');
}
@ -2393,7 +2408,7 @@ DebugCommandProcessor.prototype.debuggerFlagsRequest_ = function(request,
response.body.flags.push({ name: name, value: value });
}
}
}
};
DebugCommandProcessor.prototype.v8FlagsRequest_ = function(request, response) {
@ -2499,7 +2514,7 @@ DebugCommandProcessor.prototype.lolPrintRequest_ = function(request, response) {
// running.
DebugCommandProcessor.prototype.isRunning = function() {
return this.running_;
}
};
DebugCommandProcessor.prototype.systemBreak = function(cmd, args) {
@ -2515,7 +2530,7 @@ function NumberToHex8Str(n) {
n = n >>> 4;
}
return r;
};
}
/**
@ -2591,7 +2606,7 @@ function ValueToProtocolValue_(value, mirror_serializer) {
case 'string':
case 'number':
json = value;
break
break;
default:
json = null;

480
deps/v8/src/debug.cc

@ -40,6 +40,7 @@
#include "global-handles.h"
#include "ic.h"
#include "ic-inl.h"
#include "isolate-inl.h"
#include "list.h"
#include "messages.h"
#include "natives.h"
@ -86,19 +87,13 @@ static void PrintLn(v8::Local<v8::Value> value) {
static Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind) {
Isolate* isolate = Isolate::Current();
CALL_HEAP_FUNCTION(
isolate,
isolate->stub_cache()->ComputeCallDebugBreak(argc, kind),
Code);
return isolate->stub_cache()->ComputeCallDebugBreak(argc, kind);
}
static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
Isolate* isolate = Isolate::Current();
CALL_HEAP_FUNCTION(
isolate,
isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind),
Code);
return isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind);
}
@ -401,15 +396,15 @@ void BreakLocationIterator::PrepareStepIn() {
// Step in can only be prepared if currently positioned on an IC call,
// construct call or CallFunction stub call.
Address target = rinfo()->target_address();
Handle<Code> code(Code::GetCodeFromTargetAddress(target));
if (code->is_call_stub() || code->is_keyed_call_stub()) {
Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
if (target_code->is_call_stub() || target_code->is_keyed_call_stub()) {
// Step in through IC call is handled by the runtime system. Therefore make
// sure that the any current IC is cleared and the runtime system is
// called. If the executing code has a debug break at the location change
// the call in the original code as it is the code there that will be
// executed in place of the debug break call.
Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count(),
code->kind());
Handle<Code> stub = ComputeCallDebugPrepareStepIn(
target_code->arguments_count(), target_code->kind());
if (IsDebugBreak()) {
original_rinfo()->set_target_address(stub->entry());
} else {
@ -419,7 +414,7 @@ void BreakLocationIterator::PrepareStepIn() {
#ifdef DEBUG
// All the following stuff is needed only for assertion checks so the code
// is wrapped in ifdef.
Handle<Code> maybe_call_function_stub = code;
Handle<Code> maybe_call_function_stub = target_code;
if (IsDebugBreak()) {
Address original_target = original_rinfo()->target_address();
maybe_call_function_stub =
@ -436,8 +431,9 @@ void BreakLocationIterator::PrepareStepIn() {
// Step in through CallFunction stub should also be prepared by caller of
// this function (Debug::PrepareStep) which should flood target function
// with breakpoints.
ASSERT(RelocInfo::IsConstructCall(rmode()) || code->is_inline_cache_stub()
|| is_call_function_stub);
ASSERT(RelocInfo::IsConstructCall(rmode()) ||
target_code->is_inline_cache_stub() ||
is_call_function_stub);
#endif
}
}
@ -474,11 +470,11 @@ void BreakLocationIterator::SetDebugBreakAtIC() {
RelocInfo::Mode mode = rmode();
if (RelocInfo::IsCodeTarget(mode)) {
Address target = rinfo()->target_address();
Handle<Code> code(Code::GetCodeFromTargetAddress(target));
Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
// Patch the code to invoke the builtin debug break function matching the
// calling convention used by the call site.
Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode));
Handle<Code> dbgbrk_code(Debug::FindDebugBreak(target_code, mode));
rinfo()->set_target_address(dbgbrk_code->entry());
}
}
@ -772,7 +768,7 @@ bool Debug::CompileDebuggerScript(int index) {
// Execute the shared function in the debugger context.
Handle<Context> context = isolate->global_context();
bool caught_exception = false;
bool caught_exception;
Handle<JSFunction> function =
factory->NewFunctionFromSharedFunctionInfo(function_info, context);
@ -1103,14 +1099,13 @@ bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
// Call HandleBreakPointx.
bool caught_exception = false;
const int argc = 2;
Object** argv[argc] = {
break_id.location(),
reinterpret_cast<Object**>(break_point_object.location())
};
bool caught_exception;
Handle<Object> argv[] = { break_id, break_point_object };
Handle<Object> result = Execution::TryCall(check_break_point,
isolate_->js_builtins_object(), argc, argv, &caught_exception);
isolate_->js_builtins_object(),
ARRAY_SIZE(argv),
argv,
&caught_exception);
// If exception or non boolean result handle as not triggered
if (caught_exception || !result->IsBoolean()) {
@ -1575,7 +1570,7 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
if (code->kind() == Code::STUB) {
ASSERT(code->major_key() == CodeStub::CallFunction);
Handle<Code> result =
Isolate::Current()->builtins()->StubNoRegisters_DebugBreak();
Isolate::Current()->builtins()->CallFunctionStub_DebugBreak();
return result;
}
@ -1726,46 +1721,218 @@ void Debug::ClearStepNext() {
}
// Helper function to compile full code for debugging. This code will
// have debug break slots and deoptimization
// information. Deoptimization information is required in case that an
// optimized version of this function is still activated on the
// stack. It will also make sure that the full code is compiled with
// the same flags as the previous version - that is flags which can
// change the code generated. The current method of mapping from
// already compiled full code without debug break slots to full code
// with debug break slots depends on the generated code is otherwise
// exactly the same.
static bool CompileFullCodeForDebugging(Handle<SharedFunctionInfo> shared,
Handle<Code> current_code) {
ASSERT(!current_code->has_debug_break_slots());
CompilationInfo info(shared);
info.MarkCompilingForDebugging(current_code);
ASSERT(!info.shared_info()->is_compiled());
ASSERT(!info.isolate()->has_pending_exception());
// Use compile lazy which will end up compiling the full code in the
// configuration configured above.
bool result = Compiler::CompileLazy(&info);
ASSERT(result != Isolate::Current()->has_pending_exception());
info.isolate()->clear_pending_exception();
#if DEBUG
if (result) {
Handle<Code> new_code(shared->code());
ASSERT(new_code->has_debug_break_slots());
ASSERT(current_code->is_compiled_optimizable() ==
new_code->is_compiled_optimizable());
ASSERT(current_code->instruction_size() <= new_code->instruction_size());
}
#endif
return result;
}
void Debug::PrepareForBreakPoints() {
// If preparing for the first break point make sure to deoptimize all
// functions as debugging does not work with optimized code.
if (!has_break_points_) {
Deoptimizer::DeoptimizeAll();
AssertNoAllocation no_allocation;
Builtins* builtins = isolate_->builtins();
Code* lazy_compile = builtins->builtin(Builtins::kLazyCompile);
// Find all non-optimized code functions with activation frames on
// the stack.
List<JSFunction*> active_functions(100);
for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) {
JavaScriptFrame* frame = it.frame();
if (frame->function()->IsJSFunction()) {
JSFunction* function = JSFunction::cast(frame->function());
if (function->code()->kind() == Code::FUNCTION)
active_functions.Add(function);
Handle<Code> lazy_compile =
Handle<Code>(isolate_->builtins()->builtin(Builtins::kLazyCompile));
// Keep the list of activated functions in a handlified list as it
// is used both in GC and non-GC code.
List<Handle<JSFunction> > active_functions(100);
{
// We are going to iterate heap to find all functions without
// debug break slots.
isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
// Ensure no GC in this scope as we are comparing raw pointer
// values and performing a heap iteration.
AssertNoAllocation no_allocation;
// Find all non-optimized code functions with activation frames
// on the stack. This includes functions which have optimized
// activations (including inlined functions) on the stack as the
// non-optimized code is needed for the lazy deoptimization.
for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) {
JavaScriptFrame* frame = it.frame();
if (frame->is_optimized()) {
List<JSFunction*> functions(Compiler::kMaxInliningLevels + 1);
frame->GetFunctions(&functions);
for (int i = 0; i < functions.length(); i++) {
if (!functions[i]->shared()->code()->has_debug_break_slots()) {
active_functions.Add(Handle<JSFunction>(functions[i]));
}
}
} else if (frame->function()->IsJSFunction()) {
JSFunction* function = JSFunction::cast(frame->function());
if (function->code()->kind() == Code::FUNCTION &&
!function->code()->has_debug_break_slots()) {
active_functions.Add(Handle<JSFunction>(function));
}
}
}
// Sort the functions on the object pointer value to prepare for
// the binary search below.
active_functions.Sort(HandleObjectPointerCompare<JSFunction>);
// Scan the heap for all non-optimized functions which has no
// debug break slots.
HeapIterator iterator;
HeapObject* obj = NULL;
while (((obj = iterator.next()) != NULL)) {
if (obj->IsJSFunction()) {
JSFunction* function = JSFunction::cast(obj);
if (function->shared()->allows_lazy_compilation() &&
function->shared()->script()->IsScript() &&
function->code()->kind() == Code::FUNCTION &&
!function->code()->has_debug_break_slots()) {
bool has_activation =
SortedListBSearch<Handle<JSFunction> >(
active_functions,
Handle<JSFunction>(function),
HandleObjectPointerCompare<JSFunction>) != -1;
if (!has_activation) {
function->set_code(*lazy_compile);
function->shared()->set_code(*lazy_compile);
}
}
}
}
}
active_functions.Sort();
// Scan the heap for all non-optimized functions which has no
// debug break slots.
HeapIterator iterator;
HeapObject* obj = NULL;
while (((obj = iterator.next()) != NULL)) {
if (obj->IsJSFunction()) {
JSFunction* function = JSFunction::cast(obj);
if (function->shared()->allows_lazy_compilation() &&
function->shared()->script()->IsScript() &&
function->code()->kind() == Code::FUNCTION &&
!function->code()->has_debug_break_slots()) {
bool has_activation =
SortedListBSearch<JSFunction*>(active_functions, function) != -1;
if (!has_activation) {
function->set_code(lazy_compile);
function->shared()->set_code(lazy_compile);
// Now the non-GC scope is left, and the sorting of the functions
// in active_function is not ensured any more. The code below does
// not rely on it.
// Now recompile all functions with activation frames and and
// patch the return address to run in the new compiled code.
for (int i = 0; i < active_functions.length(); i++) {
Handle<JSFunction> function = active_functions[i];
Handle<SharedFunctionInfo> shared(function->shared());
// If recompilation is not possible just skip it.
if (shared->is_toplevel() ||
!shared->allows_lazy_compilation() ||
shared->code()->kind() == Code::BUILTIN) {
continue;
}
// Make sure that the shared full code is compiled with debug
// break slots.
if (function->code() == *lazy_compile) {
function->set_code(shared->code());
}
Handle<Code> current_code(function->code());
if (shared->code()->has_debug_break_slots()) {
// if the code is already recompiled to have break slots skip
// recompilation.
ASSERT(!function->code()->has_debug_break_slots());
} else {
// Try to compile the full code with debug break slots. If it
// fails just keep the current code.
ASSERT(shared->code() == *current_code);
ZoneScope zone_scope(isolate_, DELETE_ON_EXIT);
shared->set_code(*lazy_compile);
bool prev_force_debugger_active =
isolate_->debugger()->force_debugger_active();
isolate_->debugger()->set_force_debugger_active(true);
CompileFullCodeForDebugging(shared, current_code);
isolate_->debugger()->set_force_debugger_active(
prev_force_debugger_active);
if (!shared->is_compiled()) {
shared->set_code(*current_code);
continue;
}
}
Handle<Code> new_code(shared->code());
// Find the function and patch the return address.
for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) {
JavaScriptFrame* frame = it.frame();
// If the current frame is for this function in its
// non-optimized form rewrite the return address to continue
// in the newly compiled full code with debug break slots.
if (frame->function()->IsJSFunction() &&
frame->function() == *function &&
frame->LookupCode()->kind() == Code::FUNCTION) {
intptr_t delta = frame->pc() - current_code->instruction_start();
int debug_break_slot_count = 0;
int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT);
for (RelocIterator it(*new_code, mask); !it.done(); it.next()) {
// Check if the pc in the new code with debug break
// slots is before this slot.
RelocInfo* info = it.rinfo();
int debug_break_slot_bytes =
debug_break_slot_count * Assembler::kDebugBreakSlotLength;
intptr_t new_delta =
info->pc() -
new_code->instruction_start() -
debug_break_slot_bytes;
if (new_delta > delta) {
break;
}
// Passed a debug break slot in the full code with debug
// break slots.
debug_break_slot_count++;
}
int debug_break_slot_bytes =
debug_break_slot_count * Assembler::kDebugBreakSlotLength;
if (FLAG_trace_deopt) {
PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
"with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
"for debugging, "
"changing pc from %08" V8PRIxPTR " to %08" V8PRIxPTR "\n",
reinterpret_cast<intptr_t>(
current_code->instruction_start()),
reinterpret_cast<intptr_t>(
current_code->instruction_start()) +
current_code->instruction_size(),
current_code->instruction_size(),
reinterpret_cast<intptr_t>(new_code->instruction_start()),
reinterpret_cast<intptr_t>(new_code->instruction_start()) +
new_code->instruction_size(),
new_code->instruction_size(),
reinterpret_cast<intptr_t>(frame->pc()),
reinterpret_cast<intptr_t>(new_code->instruction_start()) +
delta + debug_break_slot_bytes);
}
// Patch the return address to return into the code with
// debug break slots.
frame->set_pc(
new_code->instruction_start() + delta + debug_break_slot_bytes);
}
}
}
@ -1782,7 +1949,9 @@ bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
}
// Ensure shared in compiled. Return false if this failed.
if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
if (!SharedFunctionInfo::EnsureCompiled(shared, CLEAR_EXCEPTION)) {
return false;
}
// Create the debug info object.
Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared);
@ -1997,9 +2166,10 @@ void Debug::CreateScriptCache() {
// 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 are no longer referenced.
heap->CollectAllGarbage(false);
heap->CollectAllGarbage(false);
// scripts which are no longer referenced. The second also sweeps precisely,
// which saves us doing yet another GC to make the heap iterable.
heap->CollectAllGarbage(Heap::kNoGCFlags);
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask);
ASSERT(script_cache_ == NULL);
script_cache_ = new ScriptCache();
@ -2007,6 +2177,8 @@ void Debug::CreateScriptCache() {
// Scan heap for Script objects.
int count = 0;
HeapIterator iterator;
AssertNoAllocation no_allocation;
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
script_cache_->Add(Handle<Script>(Script::cast(obj)));
@ -2047,7 +2219,7 @@ Handle<FixedArray> Debug::GetLoadedScripts() {
// Perform GC to get unreferenced scripts evicted from the cache before
// returning the content.
isolate_->heap()->CollectAllGarbage(false);
isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags);
// Get the scripts from the cache.
return script_cache_->GetScripts();
@ -2069,6 +2241,7 @@ Debugger::Debugger(Isolate* isolate)
compiling_natives_(false),
is_loading_debugger_(false),
never_unload_debugger_(false),
force_debugger_active_(false),
message_handler_(NULL),
debugger_unload_pending_(false),
host_dispatch_handler_(NULL),
@ -2093,7 +2266,8 @@ Debugger::~Debugger() {
Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
int argc, Object*** argv,
int argc,
Handle<Object> argv[],
bool* caught_exception) {
ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
@ -2110,7 +2284,9 @@ Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
Handle<Object> js_object = Execution::TryCall(
Handle<JSFunction>::cast(constructor),
Handle<JSObject>(isolate_->debug()->debug_context()->global()),
argc, argv, caught_exception);
argc,
argv,
caught_exception);
return js_object;
}
@ -2119,10 +2295,11 @@ Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
// Create the execution state object.
Handle<Object> break_id = isolate_->factory()->NewNumberFromInt(
isolate_->debug()->break_id());
const int argc = 1;
Object** argv[argc] = { break_id.location() };
Handle<Object> argv[] = { break_id };
return MakeJSObject(CStrVector("MakeExecutionState"),
argc, argv, caught_exception);
ARRAY_SIZE(argv),
argv,
caught_exception);
}
@ -2130,11 +2307,9 @@ Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
Handle<Object> break_points_hit,
bool* caught_exception) {
// Create the new break event object.
const int argc = 2;
Object** argv[argc] = { exec_state.location(),
break_points_hit.location() };
Handle<Object> argv[] = { exec_state, break_points_hit };
return MakeJSObject(CStrVector("MakeBreakEvent"),
argc,
ARRAY_SIZE(argv),
argv,
caught_exception);
}
@ -2146,23 +2321,24 @@ Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
bool* caught_exception) {
Factory* factory = isolate_->factory();
// Create the new exception event object.
const int argc = 3;
Object** argv[argc] = { exec_state.location(),
exception.location(),
uncaught ? factory->true_value().location() :
factory->false_value().location()};
Handle<Object> argv[] = { exec_state,
exception,
factory->ToBoolean(uncaught) };
return MakeJSObject(CStrVector("MakeExceptionEvent"),
argc, argv, caught_exception);
ARRAY_SIZE(argv),
argv,
caught_exception);
}
Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
bool* caught_exception) {
// Create the new function event object.
const int argc = 1;
Object** argv[argc] = { function.location() };
Handle<Object> argv[] = { function };
return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
argc, argv, caught_exception);
ARRAY_SIZE(argv),
argv,
caught_exception);
}
@ -2173,14 +2349,11 @@ Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
// Create the compile event object.
Handle<Object> exec_state = MakeExecutionState(caught_exception);
Handle<Object> script_wrapper = GetScriptWrapper(script);
const int argc = 3;
Object** argv[argc] = { exec_state.location(),
script_wrapper.location(),
before ? factory->true_value().location() :
factory->false_value().location() };
Handle<Object> argv[] = { exec_state,
script_wrapper,
factory->ToBoolean(before) };
return MakeJSObject(CStrVector("MakeCompileEvent"),
argc,
ARRAY_SIZE(argv),
argv,
caught_exception);
}
@ -2191,11 +2364,10 @@ Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
// 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() };
Handle<Object> argv[] = { exec_state, id_object };
return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
argc,
ARRAY_SIZE(argv),
argv,
caught_exception);
}
@ -2345,12 +2517,13 @@ void Debugger::OnAfterCompile(Handle<Script> script,
Handle<JSValue> wrapper = GetScriptWrapper(script);
// Call UpdateScriptBreakPoints expect no exceptions.
bool caught_exception = false;
const int argc = 1;
Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
bool caught_exception;
Handle<Object> argv[] = { wrapper };
Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
Isolate::Current()->js_builtins_object(), argc, argv,
&caught_exception);
Isolate::Current()->js_builtins_object(),
ARRAY_SIZE(argv),
argv,
&caught_exception);
if (caught_exception) {
return;
}
@ -2463,7 +2636,8 @@ void Debugger::CallCEventCallback(v8::DebugEvent event,
v8::Debug::ClientData* client_data) {
Handle<Foreign> callback_obj(Handle<Foreign>::cast(event_listener_));
v8::Debug::EventCallback2 callback =
FUNCTION_CAST<v8::Debug::EventCallback2>(callback_obj->address());
FUNCTION_CAST<v8::Debug::EventCallback2>(
callback_obj->foreign_address());
EventDetailsImpl event_details(
event,
Handle<JSObject>::cast(exec_state),
@ -2481,13 +2655,16 @@ void Debugger::CallJSEventCallback(v8::DebugEvent event,
Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
// Invoke the JavaScript debug event listener.
const int argc = 4;
Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
exec_state.location(),
Handle<Object>::cast(event_data).location(),
event_listener_data_.location() };
bool caught_exception = false;
Execution::TryCall(fun, isolate_->global(), argc, argv, &caught_exception);
Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event)),
exec_state,
event_data,
event_listener_data_ };
bool caught_exception;
Execution::TryCall(fun,
isolate_->global(),
ARRAY_SIZE(argv),
argv,
&caught_exception);
// Silently ignore exceptions from debug event listeners.
}
@ -2833,7 +3010,9 @@ void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
bool Debugger::IsDebuggerActive() {
ScopedLock with(debugger_access_);
return message_handler_ != NULL || !event_listener_.is_null();
return message_handler_ != NULL ||
!event_listener_.is_null() ||
force_debugger_active_;
}
@ -2856,12 +3035,11 @@ Handle<Object> Debugger::Call(Handle<JSFunction> fun,
return isolate_->factory()->undefined_value();
}
static const int kArgc = 2;
Object** argv[kArgc] = { exec_state.location(), data.location() };
Handle<Object> argv[] = { exec_state, data };
Handle<Object> result = Execution::Call(
fun,
Handle<Object>(isolate_->debug()->debug_context_->global_proxy()),
kArgc,
ARRAY_SIZE(argv),
argv,
pending_exception);
return result;
@ -2929,6 +3107,94 @@ void Debugger::CallMessageDispatchHandler() {
}
EnterDebugger::EnterDebugger()
: isolate_(Isolate::Current()),
prev_(isolate_->debug()->debugger_entry()),
it_(isolate_),
has_js_frames_(!it_.done()),
save_(isolate_) {
Debug* debug = isolate_->debug();
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);
// Store the previous break id and frame id.
break_id_ = debug->break_id();
break_frame_id_ = debug->break_frame_id();
// Create the new break info. If there is no JavaScript frames there is no
// break frame id.
if (has_js_frames_) {
debug->NewBreak(it_.frame()->id());
} else {
debug->NewBreak(StackFrame::NO_ID);
}
// Make sure that debugger is loaded and enter the debugger context.
load_failed_ = !debug->Load();
if (!load_failed_) {
// NOTE the member variable save which saves the previous context before
// this change.
isolate_->set_context(*debug->debug_context());
}
}
EnterDebugger::~EnterDebugger() {
ASSERT(Isolate::Current() == isolate_);
Debug* debug = isolate_->debug();
// Restore to the previous break state.
debug->SetBreak(break_frame_id_, break_id_);
// 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 (!isolate_->has_pending_exception()) {
// Try to avoid any pending debug break breaking in the clear mirror
// cache JavaScript code.
if (isolate_->stack_guard()->IsDebugBreak()) {
debug->set_interrupts_pending(DEBUGBREAK);
isolate_->stack_guard()->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);
isolate_->stack_guard()->Preempt();
}
if (debug->is_interrupt_pending(DEBUGBREAK)) {
debug->clear_interrupt_pending(DEBUGBREAK);
isolate_->stack_guard()->DebugBreak();
}
// If there are commands in the queue when leaving the debugger request
// that these commands are processed.
if (isolate_->debugger()->HasCommands()) {
isolate_->stack_guard()->DebugCommand();
}
// If leaving the debugger with the debugger no longer active unload it.
if (!isolate_->debugger()->IsDebuggerActive()) {
isolate_->debugger()->UnloadDebugger();
}
}
// Leaving this debugger entry.
debug->set_debugger_entry(prev_);
}
MessageImpl MessageImpl::NewEvent(DebugEvent event,
bool running,
Handle<JSObject> exec_state,

99
deps/v8/src/debug.h

@ -402,7 +402,7 @@ class Debug {
static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm);
static void GenerateConstructCallDebugBreak(MacroAssembler* masm);
static void GenerateReturnDebugBreak(MacroAssembler* masm);
static void GenerateStubNoRegistersDebugBreak(MacroAssembler* masm);
static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm);
static void GenerateSlotDebugBreak(MacroAssembler* masm);
static void GeneratePlainReturnLiveEdit(MacroAssembler* masm);
@ -705,7 +705,8 @@ class Debugger {
void DebugRequest(const uint16_t* json_request, int length);
Handle<Object> MakeJSObject(Vector<const char> constructor_name,
int argc, Object*** argv,
int argc,
Handle<Object> argv[],
bool* caught_exception);
Handle<Object> MakeExecutionState(bool* caught_exception);
Handle<Object> MakeBreakEvent(Handle<Object> exec_state,
@ -809,11 +810,15 @@ class Debugger {
}
void set_compiling_natives(bool compiling_natives) {
Debugger::compiling_natives_ = compiling_natives;
compiling_natives_ = compiling_natives;
}
bool compiling_natives() const { return compiling_natives_; }
void set_loading_debugger(bool v) { is_loading_debugger_ = v; }
bool is_loading_debugger() const { return is_loading_debugger_; }
void set_force_debugger_active(bool force_debugger_active) {
force_debugger_active_ = force_debugger_active;
}
bool force_debugger_active() const { return force_debugger_active_; }
bool IsDebuggerActive();
@ -839,6 +844,7 @@ class Debugger {
bool compiling_natives_; // Are we compiling natives?
bool is_loading_debugger_; // Are we loading the debugger?
bool never_unload_debugger_; // Can we unload the debugger?
bool force_debugger_active_; // Activate debugger without event listeners.
v8::Debug::MessageHandler2 message_handler_;
bool debugger_unload_pending_; // Was message handler cleared?
v8::Debug::HostDispatchHandler host_dispatch_handler_;
@ -869,91 +875,8 @@ class Debugger {
// some reason could not be entered FailedToEnter will return true.
class EnterDebugger BASE_EMBEDDED {
public:
EnterDebugger()
: isolate_(Isolate::Current()),
prev_(isolate_->debug()->debugger_entry()),
it_(isolate_),
has_js_frames_(!it_.done()),
save_(isolate_) {
Debug* debug = isolate_->debug();
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);
// Store the previous break id and frame id.
break_id_ = debug->break_id();
break_frame_id_ = debug->break_frame_id();
// Create the new break info. If there is no JavaScript frames there is no
// break frame id.
if (has_js_frames_) {
debug->NewBreak(it_.frame()->id());
} else {
debug->NewBreak(StackFrame::NO_ID);
}
// Make sure that debugger is loaded and enter the debugger context.
load_failed_ = !debug->Load();
if (!load_failed_) {
// NOTE the member variable save which saves the previous context before
// this change.
isolate_->set_context(*debug->debug_context());
}
}
~EnterDebugger() {
ASSERT(Isolate::Current() == isolate_);
Debug* debug = isolate_->debug();
// Restore to the previous break state.
debug->SetBreak(break_frame_id_, break_id_);
// 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 (!isolate_->has_pending_exception()) {
// Try to avoid any pending debug break breaking in the clear mirror
// cache JavaScript code.
if (isolate_->stack_guard()->IsDebugBreak()) {
debug->set_interrupts_pending(DEBUGBREAK);
isolate_->stack_guard()->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);
isolate_->stack_guard()->Preempt();
}
if (debug->is_interrupt_pending(DEBUGBREAK)) {
debug->clear_interrupt_pending(DEBUGBREAK);
isolate_->stack_guard()->DebugBreak();
}
// If there are commands in the queue when leaving the debugger request
// that these commands are processed.
if (isolate_->debugger()->HasCommands()) {
isolate_->stack_guard()->DebugCommand();
}
// If leaving the debugger with the debugger no longer active unload it.
if (!isolate_->debugger()->IsDebuggerActive()) {
isolate_->debugger()->UnloadDebugger();
}
}
// Leaving this debugger entry.
debug->set_debugger_entry(prev_);
}
EnterDebugger();
~EnterDebugger();
// Check whether the debugger could be entered.
inline bool FailedToEnter() { return load_failed_; }

97
deps/v8/src/deoptimizer.cc

@ -52,11 +52,13 @@ DeoptimizerData::DeoptimizerData() {
DeoptimizerData::~DeoptimizerData() {
if (eager_deoptimization_entry_code_ != NULL) {
eager_deoptimization_entry_code_->Free(EXECUTABLE);
Isolate::Current()->memory_allocator()->Free(
eager_deoptimization_entry_code_);
eager_deoptimization_entry_code_ = NULL;
}
if (lazy_deoptimization_entry_code_ != NULL) {
lazy_deoptimization_entry_code_->Free(EXECUTABLE);
Isolate::Current()->memory_allocator()->Free(
lazy_deoptimization_entry_code_);
lazy_deoptimization_entry_code_ = NULL;
}
}
@ -71,6 +73,8 @@ void DeoptimizerData::Iterate(ObjectVisitor* v) {
#endif
// We rely on this function not causing a GC. It is called from generated code
// without having a real stack frame in place.
Deoptimizer* Deoptimizer::New(JSFunction* function,
BailoutType type,
unsigned bailout_id,
@ -112,25 +116,11 @@ DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
// Get the function and code from the frame.
JSFunction* function = JSFunction::cast(frame->function());
Code* code = frame->LookupCode();
Address code_start_address = code->instruction_start();
// Locate the deoptimization point in the code. As we are at a call the
// return address must be at a place in the code with deoptimization support.
int deoptimization_index = Safepoint::kNoDeoptimizationIndex;
// Scope this as the safe point constructor will disallow allocation.
{
SafepointTable table(code);
for (unsigned i = 0; i < table.length(); ++i) {
Address address = code_start_address + table.GetPcOffset(i);
if (address == frame->pc()) {
SafepointEntry safepoint_entry = table.GetEntry(i);
ASSERT(safepoint_entry.deoptimization_index() !=
Safepoint::kNoDeoptimizationIndex);
deoptimization_index = safepoint_entry.deoptimization_index();
break;
}
}
}
SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
int deoptimization_index = safepoint_entry.deoptimization_index();
ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
// Always use the actual stack slots when calculating the fp to sp
@ -319,6 +309,8 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
input_(NULL),
output_count_(0),
output_(NULL),
frame_alignment_marker_(isolate->heap()->frame_alignment_marker()),
has_alignment_padding_(0),
deferred_heap_numbers_(0) {
if (FLAG_trace_deopt && type != OSR) {
if (type == DEBUGGER) {
@ -343,6 +335,26 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
if (type == EAGER) {
ASSERT(from == NULL);
optimized_code_ = function_->code();
if (FLAG_trace_deopt && FLAG_code_comments) {
// Print instruction associated with this bailout.
const char* last_comment = NULL;
int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
| RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
for (RelocIterator it(optimized_code_, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
if (info->rmode() == RelocInfo::COMMENT) {
last_comment = reinterpret_cast<const char*>(info->data());
}
if (info->rmode() == RelocInfo::RUNTIME_ENTRY) {
unsigned id = Deoptimizer::GetDeoptimizationId(
info->target_address(), Deoptimizer::EAGER);
if (id == bailout_id && last_comment != NULL) {
PrintF(" %s\n", last_comment);
break;
}
}
}
}
} else if (type == LAZY) {
optimized_code_ = FindDeoptimizingCodeFromAddress(from);
ASSERT(optimized_code_ != NULL);
@ -386,7 +398,7 @@ void Deoptimizer::DeleteFrameDescriptions() {
Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
ASSERT(id >= 0);
if (id >= kNumberOfEntries) return NULL;
LargeObjectChunk* base = NULL;
MemoryChunk* base = NULL;
DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
if (type == EAGER) {
if (data->eager_deoptimization_entry_code_ == NULL) {
@ -400,12 +412,12 @@ Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
base = data->lazy_deoptimization_entry_code_;
}
return
static_cast<Address>(base->GetStartAddress()) + (id * table_entry_size_);
static_cast<Address>(base->body()) + (id * table_entry_size_);
}
int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
LargeObjectChunk* base = NULL;
MemoryChunk* base = NULL;
DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
if (type == EAGER) {
base = data->eager_deoptimization_entry_code_;
@ -413,14 +425,14 @@ int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
base = data->lazy_deoptimization_entry_code_;
}
if (base == NULL ||
addr < base->GetStartAddress() ||
addr >= base->GetStartAddress() +
addr < base->body() ||
addr >= base->body() +
(kNumberOfEntries * table_entry_size_)) {
return kNotDeoptimizationEntry;
}
ASSERT_EQ(0,
static_cast<int>(addr - base->GetStartAddress()) % table_entry_size_);
return static_cast<int>(addr - base->GetStartAddress()) / table_entry_size_;
static_cast<int>(addr - base->body()) % table_entry_size_);
return static_cast<int>(addr - base->body()) / table_entry_size_;
}
@ -462,6 +474,8 @@ int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
}
// We rely on this function not causing a GC. It is called from generated code
// without having a real stack frame in place.
void Deoptimizer::DoComputeOutputFrames() {
if (bailout_type_ == OSR) {
DoComputeOsrOutputFrame();
@ -613,11 +627,13 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
intptr_t input_value = input_->GetRegister(input_reg);
if (FLAG_trace_deopt) {
PrintF(
" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s\n",
" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
output_[frame_index]->GetTop() + output_offset,
output_offset,
input_value,
converter.NameOfCPURegister(input_reg));
reinterpret_cast<Object*>(input_value)->ShortPrint();
PrintF("\n");
}
output_[frame_index]->SetFrameSlot(output_offset, input_value);
return;
@ -675,10 +691,12 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
if (FLAG_trace_deopt) {
PrintF(" 0x%08" V8PRIxPTR ": ",
output_[frame_index]->GetTop() + output_offset);
PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d]\n",
PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] ",
output_offset,
input_value,
input_offset);
reinterpret_cast<Object*>(input_value)->ShortPrint();
PrintF("\n");
}
output_[frame_index]->SetFrameSlot(output_offset, input_value);
return;
@ -850,10 +868,12 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
unsigned output_offset =
output->GetOffsetFromSlotIndex(this, output_index);
if (FLAG_trace_osr) {
PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
output_offset,
input_value,
*input_offset);
reinterpret_cast<Object*>(input_value)->ShortPrint();
PrintF("\n");
}
output->SetFrameSlot(output_offset, input_value);
break;
@ -953,7 +973,10 @@ void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
for (uint32_t i = 0; i < table_length; ++i) {
uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
Address pc_after = unoptimized_code->instruction_start() + pc_offset;
PatchStackCheckCodeAt(pc_after, check_code, replacement_code);
PatchStackCheckCodeAt(unoptimized_code,
pc_after,
check_code,
replacement_code);
stack_check_cursor += 2 * kIntSize;
}
}
@ -972,7 +995,10 @@ void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
for (uint32_t i = 0; i < table_length; ++i) {
uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
Address pc_after = unoptimized_code->instruction_start() + pc_offset;
RevertStackCheckCodeAt(pc_after, check_code, replacement_code);
RevertStackCheckCodeAt(unoptimized_code,
pc_after,
check_code,
replacement_code);
stack_check_cursor += 2 * kIntSize;
}
}
@ -1039,7 +1065,7 @@ void Deoptimizer::AddDoubleValue(intptr_t slot_address,
}
LargeObjectChunk* Deoptimizer::CreateCode(BailoutType type) {
MemoryChunk* Deoptimizer::CreateCode(BailoutType type) {
// We cannot run this if the serializer is enabled because this will
// cause us to emit relocation information for the external
// references. This is fine because the deoptimizer's code section
@ -1053,12 +1079,15 @@ LargeObjectChunk* Deoptimizer::CreateCode(BailoutType type) {
masm.GetCode(&desc);
ASSERT(desc.reloc_size == 0);
LargeObjectChunk* chunk = LargeObjectChunk::New(desc.instr_size, EXECUTABLE);
MemoryChunk* chunk =
Isolate::Current()->memory_allocator()->AllocateChunk(desc.instr_size,
EXECUTABLE,
NULL);
if (chunk == NULL) {
V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table");
}
memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size);
CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size);
memcpy(chunk->body(), desc.buffer, desc.instr_size);
CPU::FlushICache(chunk->body(), desc.instr_size);
return chunk;
}

36
deps/v8/src/deoptimizer.h

@ -86,8 +86,8 @@ class DeoptimizerData {
#endif
private:
LargeObjectChunk* eager_deoptimization_entry_code_;
LargeObjectChunk* lazy_deoptimization_entry_code_;
MemoryChunk* eager_deoptimization_entry_code_;
MemoryChunk* lazy_deoptimization_entry_code_;
Deoptimizer* current_;
#ifdef ENABLE_DEBUGGER_SUPPORT
@ -173,7 +173,8 @@ class Deoptimizer : public Malloced {
// Patch stack guard check at instruction before pc_after in
// the unoptimized code to unconditionally call replacement_code.
static void PatchStackCheckCodeAt(Address pc_after,
static void PatchStackCheckCodeAt(Code* unoptimized_code,
Address pc_after,
Code* check_code,
Code* replacement_code);
@ -185,7 +186,8 @@ class Deoptimizer : public Malloced {
// Change all patched stack guard checks in the unoptimized code
// back to a normal stack guard check.
static void RevertStackCheckCodeAt(Address pc_after,
static void RevertStackCheckCodeAt(Code* unoptimized_code,
Address pc_after,
Code* check_code,
Code* replacement_code);
@ -211,6 +213,11 @@ class Deoptimizer : public Malloced {
return OFFSET_OF(Deoptimizer, output_count_);
}
static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
static int frame_alignment_marker_offset() {
return OFFSET_OF(Deoptimizer, frame_alignment_marker_); }
static int has_alignment_padding_offset() {
return OFFSET_OF(Deoptimizer, has_alignment_padding_);
}
static int GetDeoptimizedCodeCount(Isolate* isolate);
@ -285,7 +292,7 @@ class Deoptimizer : public Malloced {
void AddDoubleValue(intptr_t slot_address, double value);
static LargeObjectChunk* CreateCode(BailoutType type);
static MemoryChunk* CreateCode(BailoutType type);
static void GenerateDeoptimizationEntries(
MacroAssembler* masm, int count, BailoutType type);
@ -315,6 +322,10 @@ class Deoptimizer : public Malloced {
// Array of output frame descriptions.
FrameDescription** output_;
// Frames can be dynamically padded on ia32 to align untagged doubles.
Object* frame_alignment_marker_;
intptr_t has_alignment_padding_;
List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
static const int table_entry_size_;
@ -358,7 +369,20 @@ class FrameDescription {
}
double GetDoubleFrameSlot(unsigned offset) {
return *reinterpret_cast<double*>(GetFrameSlotPointer(offset));
intptr_t* ptr = GetFrameSlotPointer(offset);
#if V8_TARGET_ARCH_MIPS
// Prevent gcc from using load-double (mips ldc1) on (possibly)
// non-64-bit aligned double. Uses two lwc1 instructions.
union conversion {
double d;
uint32_t u[2];
} c;
c.u[0] = *reinterpret_cast<uint32_t*>(ptr);
c.u[1] = *(reinterpret_cast<uint32_t*>(ptr) + 1);
return c.d;
#else
return *reinterpret_cast<double*>(ptr);
#endif
}
void SetFrameSlot(unsigned offset, intptr_t value) {

2
deps/v8/src/disassembler.cc

@ -200,7 +200,7 @@ static int DecodeIt(FILE* f,
// Print all the reloc info for this instruction which are not comments.
for (int i = 0; i < pcs.length(); i++) {
// Put together the reloc info
RelocInfo relocinfo(pcs[i], rmodes[i], datas[i]);
RelocInfo relocinfo(pcs[i], rmodes[i], datas[i], NULL);
// Indent the printing of the reloc info.
if (i == 0) {

6
deps/v8/src/double.h

@ -1,4 +1,4 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -34,8 +34,8 @@ namespace v8 {
namespace internal {
// We assume that doubles and uint64_t have the same endianness.
static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
inline uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
inline double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
// Helper functions for doubles.
class Double {

4
deps/v8/src/dtoa.h

@ -1,4 +1,4 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -47,7 +47,7 @@ enum DtoaMode {
// The maximal length of digits a double can have in base 10.
// Note that DoubleToAscii null-terminates its input. So the given buffer should
// be at least kBase10MaximalLength + 1 characters long.
static const int kBase10MaximalLength = 17;
const int kBase10MaximalLength = 17;
// Converts the given double 'v' to ascii.
// The result should be interpreted as buffer * 10^(point-length).

344
deps/v8/src/elements.cc

@ -31,6 +31,30 @@
#include "elements.h"
#include "utils.h"
// Each concrete ElementsAccessor can handle exactly one ElementsKind,
// several abstract ElementsAccessor classes are used to allow sharing
// common code.
//
// Inheritance hierarchy:
// - ElementsAccessorBase (abstract)
// - FastElementsAccessor (abstract)
// - FastObjectElementsAccessor
// - FastDoubleElementsAccessor
// - ExternalElementsAccessor (abstract)
// - ExternalByteElementsAccessor
// - ExternalUnsignedByteElementsAccessor
// - ExternalShortElementsAccessor
// - ExternalUnsignedShortElementsAccessor
// - ExternalIntElementsAccessor
// - ExternalUnsignedIntElementsAccessor
// - ExternalFloatElementsAccessor
// - ExternalDoubleElementsAccessor
// - PixelElementsAccessor
// - DictionaryElementsAccessor
// - NonStrictArgumentsElementsAccessor
namespace v8 {
namespace internal {
@ -38,7 +62,7 @@ namespace internal {
ElementsAccessor** ElementsAccessor::elements_accessors_;
bool HasKey(FixedArray* array, Object* key) {
static bool HasKey(FixedArray* array, Object* key) {
int len0 = array->length();
for (int i = 0; i < len0; i++) {
Object* element = array->get(i);
@ -52,6 +76,14 @@ bool HasKey(FixedArray* array, Object* key) {
}
static Failure* ThrowArrayLengthRangeError(Heap* heap) {
HandleScope scope(heap->isolate());
return heap->isolate()->Throw(
*heap->isolate()->factory()->NewRangeError("invalid_array_length",
HandleVector<Object>(NULL, 0)));
}
// Base class for element handler implementations. Contains the
// the common logic for objects with different ElementsKinds.
// Subclasses must specialize method for which the element
@ -91,6 +123,17 @@ class ElementsAccessorBase : public ElementsAccessor {
return backing_store->GetHeap()->the_hole_value();
}
virtual MaybeObject* SetLength(JSObject* obj,
Object* length) {
ASSERT(obj->IsJSArray());
return ElementsAccessorSubclass::SetLength(
BackingStoreClass::cast(obj->elements()), obj, length);
}
static MaybeObject* SetLength(BackingStoreClass* backing_store,
JSObject* obj,
Object* length);
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
JSReceiver::DeleteMode mode) = 0;
@ -222,12 +265,76 @@ class ElementsAccessorBase : public ElementsAccessor {
};
// Super class for all fast element arrays.
template<typename FastElementsAccessorSubclass,
typename BackingStore,
int ElementSize>
class FastElementsAccessor
: public ElementsAccessorBase<FastElementsAccessor, FixedArray> {
: public ElementsAccessorBase<FastElementsAccessorSubclass, BackingStore> {
protected:
friend class ElementsAccessorBase<FastElementsAccessorSubclass, BackingStore>;
// Adjusts the length of the fast backing store or returns the new length or
// undefined in case conversion to a slow backing store should be performed.
static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store,
JSArray* array,
Object* length_object,
uint32_t length) {
uint32_t old_capacity = backing_store->length();
// Check whether the backing store should be shrunk.
if (length <= old_capacity) {
if (array->HasFastTypeElements()) {
MaybeObject* maybe_obj = array->EnsureWritableFastElements();
if (!maybe_obj->To(&backing_store)) return maybe_obj;
}
if (2 * length <= old_capacity) {
// If more than half the elements won't be used, trim the array.
if (length == 0) {
array->initialize_elements();
} else {
backing_store->set_length(length);
Address filler_start = backing_store->address() +
BackingStore::OffsetOfElementAt(length);
int filler_size = (old_capacity - length) * ElementSize;
array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
}
} else {
// Otherwise, fill the unused tail with holes.
int old_length = FastD2I(array->length()->Number());
for (int i = length; i < old_length; i++) {
backing_store->set_the_hole(i);
}
}
return length_object;
}
// Check whether the backing store should be expanded.
uint32_t min = JSObject::NewElementsCapacity(old_capacity);
uint32_t new_capacity = length > min ? length : min;
if (!array->ShouldConvertToSlowElements(new_capacity)) {
MaybeObject* result = FastElementsAccessorSubclass::
SetFastElementsCapacityAndLength(array, new_capacity, length);
if (result->IsFailure()) return result;
return length_object;
}
// Request conversion to slow elements.
return array->GetHeap()->undefined_value();
}
};
class FastObjectElementsAccessor
: public FastElementsAccessor<FastObjectElementsAccessor,
FixedArray,
kPointerSize> {
public:
static MaybeObject* DeleteCommon(JSObject* obj,
uint32_t key) {
ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements());
ASSERT(obj->HasFastElements() ||
obj->HasFastSmiOnlyElements() ||
obj->HasFastArgumentsElements());
Heap* heap = obj->GetHeap();
FixedArray* backing_store = FixedArray::cast(obj->elements());
if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
@ -270,6 +377,22 @@ class FastElementsAccessor
}
protected:
friend class FastElementsAccessor<FastObjectElementsAccessor,
FixedArray,
kPointerSize>;
static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
uint32_t capacity,
uint32_t length) {
JSObject::SetFastElementsCapacityMode set_capacity_mode =
obj->HasFastSmiOnlyElements()
? JSObject::kAllowSmiOnlyElements
: JSObject::kDontAllowSmiOnlyElements;
return obj->SetFastElementsCapacityAndLength(capacity,
length,
set_capacity_mode);
}
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
JSReceiver::DeleteMode mode) {
@ -279,11 +402,21 @@ class FastElementsAccessor
class FastDoubleElementsAccessor
: public ElementsAccessorBase<FastDoubleElementsAccessor,
FixedDoubleArray> {
: public FastElementsAccessor<FastDoubleElementsAccessor,
FixedDoubleArray,
kDoubleSize> {
protected:
friend class ElementsAccessorBase<FastDoubleElementsAccessor,
FixedDoubleArray>;
friend class FastElementsAccessor<FastDoubleElementsAccessor,
FixedDoubleArray,
kDoubleSize>;
static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
uint32_t capacity,
uint32_t length) {
return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
}
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
@ -327,6 +460,14 @@ class ExternalElementsAccessor
}
}
static MaybeObject* SetLength(ExternalArray* backing_store,
JSObject* obj,
Object* length) {
// External arrays do not support changing their length.
UNREACHABLE();
return obj;
}
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
JSReceiver::DeleteMode mode) {
@ -394,6 +535,63 @@ class DictionaryElementsAccessor
: public ElementsAccessorBase<DictionaryElementsAccessor,
NumberDictionary> {
public:
// Adjusts the length of the dictionary backing store and returns the new
// length according to ES5 section 15.4.5.2 behavior.
static MaybeObject* SetLengthWithoutNormalize(NumberDictionary* dict,
JSArray* array,
Object* length_object,
uint32_t length) {
if (length == 0) {
// If the length of a slow array is reset to zero, we clear
// the array and flush backing storage. This has the added
// benefit that the array returns to fast mode.
Object* obj;
MaybeObject* maybe_obj = array->ResetElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
} else {
uint32_t new_length = length;
uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
if (new_length < old_length) {
// Find last non-deletable element in range of elements to be
// deleted and adjust range accordingly.
Heap* heap = array->GetHeap();
int capacity = dict->Capacity();
for (int i = 0; i < capacity; i++) {
Object* key = dict->KeyAt(i);
if (key->IsNumber()) {
uint32_t number = static_cast<uint32_t>(key->Number());
if (new_length <= number && number < old_length) {
PropertyDetails details = dict->DetailsAt(i);
if (details.IsDontDelete()) new_length = number + 1;
}
}
}
if (new_length != length) {
MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
if (!maybe_object->To(&length_object)) return maybe_object;
}
// Remove elements that should be deleted.
int removed_entries = 0;
Object* the_hole_value = heap->the_hole_value();
for (int i = 0; i < capacity; i++) {
Object* key = dict->KeyAt(i);
if (key->IsNumber()) {
uint32_t number = static_cast<uint32_t>(key->Number());
if (new_length <= number && number < old_length) {
dict->SetEntry(i, the_hole_value, the_hole_value);
removed_entries++;
}
}
}
// Update the number of elements.
dict->ElementsRemoved(removed_entries);
}
}
return length_object;
}
static MaybeObject* DeleteCommon(JSObject* obj,
uint32_t key,
JSReceiver::DeleteMode mode) {
@ -503,9 +701,17 @@ class NonStrictArgumentsElementsAccessor
}
}
static MaybeObject* SetLength(FixedArray* parameter_map,
JSObject* obj,
Object* length) {
// TODO(mstarzinger): This was never implemented but will be used once we
// correctly implement [[DefineOwnProperty]] on arrays.
UNIMPLEMENTED();
return obj;
}
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key
,
uint32_t key,
JSReceiver::DeleteMode mode) {
FixedArray* parameter_map = FixedArray::cast(obj->elements());
Object* probe = GetParameterMapArg(parameter_map, key);
@ -519,7 +725,7 @@ class NonStrictArgumentsElementsAccessor
if (arguments->IsDictionary()) {
return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
} else {
return FastElementsAccessor::DeleteCommon(obj, key);
return FastObjectElementsAccessor::DeleteCommon(obj, key);
}
}
return obj->GetHeap()->true_value();
@ -595,40 +801,108 @@ ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
void ElementsAccessor::InitializeOncePerProcess() {
// First argument in list is the accessor class, the second argument is can
// be any arbitrary unique identifier, in this case chosen to be the
// corresponding enum. Use the fast element handler for smi-only arrays.
// The implementation is currently identical. Note that the order must match
// that of the ElementsKind enum for the |accessor_array[]| below to work.
#define ELEMENTS_LIST(V) \
V(FastObjectElementsAccessor, FAST_SMI_ONLY_ELEMENTS) \
V(FastObjectElementsAccessor, FAST_ELEMENTS) \
V(FastDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS) \
V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS) \
V(NonStrictArgumentsElementsAccessor, NON_STRICT_ARGUMENTS_ELEMENTS) \
V(ExternalByteElementsAccessor, EXTERNAL_BYTE_ELEMENTS) \
V(ExternalUnsignedByteElementsAccessor, EXTERNAL_UNSIGNED_BYTE_ELEMENTS) \
V(ExternalShortElementsAccessor, EXTERNAL_SHORT_ELEMENTS) \
V(ExternalUnsignedShortElementsAccessor, EXTERNAL_UNSIGNED_SHORT_ELEMENTS) \
V(ExternalIntElementsAccessor, EXTERNAL_INT_ELEMENTS) \
V(ExternalUnsignedIntElementsAccessor, EXTERNAL_UNSIGNED_INT_ELEMENTS) \
V(ExternalFloatElementsAccessor, EXTERNAL_FLOAT_ELEMENTS) \
V(ExternalDoubleElementsAccessor, EXTERNAL_DOUBLE_ELEMENTS) \
V(PixelElementsAccessor, EXTERNAL_PIXEL_ELEMENTS)
static struct ConcreteElementsAccessors {
FastElementsAccessor fast_elements_handler;
FastDoubleElementsAccessor fast_double_elements_handler;
DictionaryElementsAccessor dictionary_elements_handler;
NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler;
ExternalByteElementsAccessor byte_elements_handler;
ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler;
ExternalShortElementsAccessor short_elements_handler;
ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler;
ExternalIntElementsAccessor int_elements_handler;
ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler;
ExternalFloatElementsAccessor float_elements_handler;
ExternalDoubleElementsAccessor double_elements_handler;
PixelElementsAccessor pixel_elements_handler;
} element_accessors;
#define ACCESSOR_STRUCT(Class, Name) Class* Name##_handler;
ELEMENTS_LIST(ACCESSOR_STRUCT)
#undef ACCESSOR_STRUCT
} element_accessors = {
#define ACCESSOR_INIT(Class, Name) new Class(),
ELEMENTS_LIST(ACCESSOR_INIT)
#undef ACCESSOR_INIT
};
static ElementsAccessor* accessor_array[] = {
&element_accessors.fast_elements_handler,
&element_accessors.fast_double_elements_handler,
&element_accessors.dictionary_elements_handler,
&element_accessors.non_strict_arguments_elements_handler,
&element_accessors.byte_elements_handler,
&element_accessors.unsigned_byte_elements_handler,
&element_accessors.short_elements_handler,
&element_accessors.unsigned_short_elements_handler,
&element_accessors.int_elements_handler,
&element_accessors.unsigned_int_elements_handler,
&element_accessors.float_elements_handler,
&element_accessors.double_elements_handler,
&element_accessors.pixel_elements_handler
#define ACCESSOR_ARRAY(Class, Name) element_accessors.Name##_handler,
ELEMENTS_LIST(ACCESSOR_ARRAY)
#undef ACCESSOR_ARRAY
};
#undef ELEMENTS_LIST
STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
kElementsKindCount);
elements_accessors_ = accessor_array;
}
template <typename ElementsAccessorSubclass, typename BackingStoreClass>
MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, BackingStoreClass>::
SetLength(BackingStoreClass* backing_store,
JSObject* obj,
Object* length) {
JSArray* array = JSArray::cast(obj);
// Fast case: The new length fits into a Smi.
MaybeObject* maybe_smi_length = length->ToSmi();
Object* smi_length = Smi::FromInt(0);
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
const int value = Smi::cast(smi_length)->value();
if (value >= 0) {
Object* new_length;
MaybeObject* result = ElementsAccessorSubclass::
SetLengthWithoutNormalize(backing_store, array, smi_length, value);
if (!result->ToObject(&new_length)) return result;
ASSERT(new_length->IsSmi() || new_length->IsUndefined());
if (new_length->IsSmi()) {
array->set_length(Smi::cast(new_length));
return array;
}
} else {
return ThrowArrayLengthRangeError(array->GetHeap());
}
}
// Slow case: The new length does not fit into a Smi or conversion
// to slow elements is needed for other reasons.
if (length->IsNumber()) {
uint32_t value;
if (length->ToArrayIndex(&value)) {
NumberDictionary* dictionary;
MaybeObject* maybe_object = array->NormalizeElements();
if (!maybe_object->To(&dictionary)) return maybe_object;
Object* new_length;
MaybeObject* result = DictionaryElementsAccessor::
SetLengthWithoutNormalize(dictionary, array, length, value);
if (!result->ToObject(&new_length)) return result;
ASSERT(new_length->IsNumber());
array->set_length(new_length);
return array;
} else {
return ThrowArrayLengthRangeError(array->GetHeap());
}
}
// Fall-back case: The new length is not a number so make the array
// size one and set only element to length.
FixedArray* new_backing_store;
MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1);
if (!maybe_obj->To(&new_backing_store)) return maybe_obj;
new_backing_store->set(0, length);
array->SetContent(new_backing_store);
return array;
}
} } // namespace v8::internal

5
deps/v8/src/elements.h

@ -44,6 +44,11 @@ class ElementsAccessor {
JSObject* holder,
Object* receiver) = 0;
// Modifies the length data property as specified for JSArrays and resizes
// the underlying backing store accordingly.
virtual MaybeObject* SetLength(JSObject* holder,
Object* new_length) = 0;
virtual MaybeObject* Delete(JSObject* holder,
uint32_t key,
JSReceiver::DeleteMode mode) = 0;

177
deps/v8/src/execution.cc

@ -33,6 +33,7 @@
#include "bootstrapper.h"
#include "codegen.h"
#include "debug.h"
#include "isolate-inl.h"
#include "runtime-profiler.h"
#include "simulator.h"
#include "v8threads.h"
@ -65,13 +66,13 @@ void StackGuard::reset_limits(const ExecutionAccess& lock) {
}
static Handle<Object> Invoke(bool construct,
Handle<JSFunction> func,
static Handle<Object> Invoke(bool is_construct,
Handle<JSFunction> function,
Handle<Object> receiver,
int argc,
Object*** args,
Handle<Object> args[],
bool* has_pending_exception) {
Isolate* isolate = func->GetIsolate();
Isolate* isolate = function->GetIsolate();
// Entering JavaScript.
VMState state(isolate, JS);
@ -79,21 +80,15 @@ static Handle<Object> Invoke(bool construct,
// Placeholder for return value.
MaybeObject* value = reinterpret_cast<Object*>(kZapValue);
typedef Object* (*JSEntryFunction)(
byte* entry,
Object* function,
Object* receiver,
int argc,
Object*** args);
Handle<Code> code;
if (construct) {
JSConstructEntryStub stub;
code = stub.GetCode();
} else {
JSEntryStub stub;
code = stub.GetCode();
}
typedef Object* (*JSEntryFunction)(byte* entry,
Object* function,
Object* receiver,
int argc,
Object*** args);
Handle<Code> code = is_construct
? isolate->factory()->js_construct_entry_code()
: isolate->factory()->js_entry_code();
// Convert calls on global objects to be calls on the global
// receiver instead to avoid having a 'this' pointer which refers
@ -105,21 +100,22 @@ static Handle<Object> Invoke(bool construct,
// Make sure that the global object of the context we're about to
// make the current one is indeed a global object.
ASSERT(func->context()->global()->IsGlobalObject());
ASSERT(function->context()->global()->IsGlobalObject());
{
// Save and restore context around invocation and block the
// allocation of handles without explicit handle scopes.
SaveContext save(isolate);
NoHandleAllocation na;
JSEntryFunction entry = FUNCTION_CAST<JSEntryFunction>(code->entry());
JSEntryFunction stub_entry = FUNCTION_CAST<JSEntryFunction>(code->entry());
// Call the function through the right JS entry stub.
byte* entry_address = func->code()->entry();
JSFunction* function = *func;
Object* receiver_pointer = *receiver;
value = CALL_GENERATED_CODE(entry, entry_address, function,
receiver_pointer, argc, args);
byte* function_entry = function->code()->entry();
JSFunction* func = *function;
Object* recv = *receiver;
Object*** argv = reinterpret_cast<Object***>(args);
value =
CALL_GENERATED_CODE(stub_entry, function_entry, func, recv, argc, argv);
}
#ifdef DEBUG
@ -148,9 +144,11 @@ static Handle<Object> Invoke(bool construct,
Handle<Object> Execution::Call(Handle<Object> callable,
Handle<Object> receiver,
int argc,
Object*** args,
Handle<Object> argv[],
bool* pending_exception,
bool convert_receiver) {
*pending_exception = false;
if (!callable->IsJSFunction()) {
callable = TryGetFunctionDelegate(callable, pending_exception);
if (*pending_exception) return callable;
@ -159,7 +157,7 @@ Handle<Object> Execution::Call(Handle<Object> callable,
// In non-strict mode, convert receiver.
if (convert_receiver && !receiver->IsJSReceiver() &&
!func->shared()->native() && !func->shared()->strict_mode()) {
!func->shared()->native() && func->shared()->is_classic_mode()) {
if (receiver->IsUndefined() || receiver->IsNull()) {
Object* global = func->context()->global()->global_receiver();
// Under some circumstances, 'global' can be the JSBuiltinsObject
@ -172,13 +170,15 @@ Handle<Object> Execution::Call(Handle<Object> callable,
if (*pending_exception) return callable;
}
return Invoke(false, func, receiver, argc, args, pending_exception);
return Invoke(false, func, receiver, argc, argv, pending_exception);
}
Handle<Object> Execution::New(Handle<JSFunction> func, int argc,
Object*** args, bool* pending_exception) {
return Invoke(true, func, Isolate::Current()->global(), argc, args,
Handle<Object> Execution::New(Handle<JSFunction> func,
int argc,
Handle<Object> argv[],
bool* pending_exception) {
return Invoke(true, func, Isolate::Current()->global(), argc, argv,
pending_exception);
}
@ -186,7 +186,7 @@ Handle<Object> Execution::New(Handle<JSFunction> func, int argc,
Handle<Object> Execution::TryCall(Handle<JSFunction> func,
Handle<Object> receiver,
int argc,
Object*** args,
Handle<Object> args[],
bool* caught_exception) {
// Enter a try-block while executing the JavaScript code. To avoid
// duplicate error printing it must be non-verbose. Also, to avoid
@ -195,6 +195,7 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func,
v8::TryCatch catcher;
catcher.SetVerbose(false);
catcher.SetCaptureMessage(false);
*caught_exception = false;
Handle<Object> result = Invoke(false, func, receiver, argc, args,
caught_exception);
@ -377,7 +378,7 @@ void StackGuard::DisableInterrupts() {
bool StackGuard::IsInterrupted() {
ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & INTERRUPT;
return (thread_local_.interrupt_flags_ & INTERRUPT) != 0;
}
@ -403,7 +404,7 @@ void StackGuard::Preempt() {
bool StackGuard::IsTerminateExecution() {
ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & TERMINATE;
return (thread_local_.interrupt_flags_ & TERMINATE) != 0;
}
@ -416,7 +417,7 @@ void StackGuard::TerminateExecution() {
bool StackGuard::IsRuntimeProfilerTick() {
ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & RUNTIME_PROFILER_TICK;
return (thread_local_.interrupt_flags_ & RUNTIME_PROFILER_TICK) != 0;
}
@ -433,6 +434,22 @@ void StackGuard::RequestRuntimeProfilerTick() {
}
bool StackGuard::IsGCRequest() {
ExecutionAccess access(isolate_);
return (thread_local_.interrupt_flags_ & GC_REQUEST) != 0;
}
void StackGuard::RequestGC() {
ExecutionAccess access(isolate_);
thread_local_.interrupt_flags_ |= GC_REQUEST;
if (thread_local_.postpone_interrupts_nesting_ == 0) {
thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit;
isolate_->heap()->SetStackLimits();
}
}
#ifdef ENABLE_DEBUGGER_SUPPORT
bool StackGuard::IsDebugBreak() {
ExecutionAccess access(isolate_);
@ -555,14 +572,15 @@ void StackGuard::InitThread(const ExecutionAccess& lock) {
// --- C a l l s t o n a t i v e s ---
#define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \
do { \
Isolate* isolate = Isolate::Current(); \
Object** args[argc] = argv; \
ASSERT(has_pending_exception != NULL); \
return Call(isolate->name##_fun(), \
isolate->js_builtins_object(), argc, args, \
has_pending_exception); \
#define RETURN_NATIVE_CALL(name, args, has_pending_exception) \
do { \
Isolate* isolate = Isolate::Current(); \
Handle<Object> argv[] = args; \
ASSERT(has_pending_exception != NULL); \
return Call(isolate->name##_fun(), \
isolate->js_builtins_object(), \
ARRAY_SIZE(argv), argv, \
has_pending_exception); \
} while (false)
@ -583,44 +601,44 @@ Handle<Object> Execution::ToBoolean(Handle<Object> obj) {
Handle<Object> Execution::ToNumber(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_number, 1, { obj.location() }, exc);
RETURN_NATIVE_CALL(to_number, { obj }, exc);
}
Handle<Object> Execution::ToString(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_string, 1, { obj.location() }, exc);
RETURN_NATIVE_CALL(to_string, { obj }, exc);
}
Handle<Object> Execution::ToDetailString(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_detail_string, 1, { obj.location() }, exc);
RETURN_NATIVE_CALL(to_detail_string, { obj }, exc);
}
Handle<Object> Execution::ToObject(Handle<Object> obj, bool* exc) {
if (obj->IsSpecObject()) return obj;
RETURN_NATIVE_CALL(to_object, 1, { obj.location() }, exc);
RETURN_NATIVE_CALL(to_object, { obj }, exc);
}
Handle<Object> Execution::ToInteger(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_integer, 1, { obj.location() }, exc);
RETURN_NATIVE_CALL(to_integer, { obj }, exc);
}
Handle<Object> Execution::ToUint32(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_uint32, 1, { obj.location() }, exc);
RETURN_NATIVE_CALL(to_uint32, { obj }, exc);
}
Handle<Object> Execution::ToInt32(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_int32, 1, { obj.location() }, exc);
RETURN_NATIVE_CALL(to_int32, { obj }, exc);
}
Handle<Object> Execution::NewDate(double time, bool* exc) {
Handle<Object> time_obj = FACTORY->NewNumber(time);
RETURN_NATIVE_CALL(create_date, 1, { time_obj.location() }, exc);
RETURN_NATIVE_CALL(create_date, { time_obj }, exc);
}
@ -657,7 +675,7 @@ Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) {
bool caught_exception;
Handle<Object> index_object = factory->NewNumberFromInt(int_index);
Object** index_arg[] = { index_object.location() };
Handle<Object> index_arg[] = { index_object };
Handle<Object> result = TryCall(Handle<JSFunction>::cast(char_at),
string,
ARRAY_SIZE(index_arg),
@ -671,7 +689,8 @@ Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) {
Handle<JSFunction> Execution::InstantiateFunction(
Handle<FunctionTemplateInfo> data, bool* exc) {
Handle<FunctionTemplateInfo> data,
bool* exc) {
Isolate* isolate = data->GetIsolate();
// Fast case: see if the function has already been instantiated
int serial_number = Smi::cast(data->serial_number())->value();
@ -680,10 +699,12 @@ Handle<JSFunction> Execution::InstantiateFunction(
GetElementNoExceptionThrown(serial_number);
if (elm->IsJSFunction()) return Handle<JSFunction>(JSFunction::cast(elm));
// The function has not yet been instantiated in this context; do it.
Object** args[1] = { Handle<Object>::cast(data).location() };
Handle<Object> result =
Call(isolate->instantiate_fun(),
isolate->js_builtins_object(), 1, args, exc);
Handle<Object> args[] = { data };
Handle<Object> result = Call(isolate->instantiate_fun(),
isolate->js_builtins_object(),
ARRAY_SIZE(args),
args,
exc);
if (*exc) return Handle<JSFunction>::null();
return Handle<JSFunction>::cast(result);
}
@ -710,10 +731,12 @@ Handle<JSObject> Execution::InstantiateObject(Handle<ObjectTemplateInfo> data,
ASSERT(!*exc);
return Handle<JSObject>(JSObject::cast(result));
} else {
Object** args[1] = { Handle<Object>::cast(data).location() };
Handle<Object> result =
Call(isolate->instantiate_fun(),
isolate->js_builtins_object(), 1, args, exc);
Handle<Object> args[] = { data };
Handle<Object> result = Call(isolate->instantiate_fun(),
isolate->js_builtins_object(),
ARRAY_SIZE(args),
args,
exc);
if (*exc) return Handle<JSObject>::null();
return Handle<JSObject>::cast(result);
}
@ -724,9 +747,12 @@ void Execution::ConfigureInstance(Handle<Object> instance,
Handle<Object> instance_template,
bool* exc) {
Isolate* isolate = Isolate::Current();
Object** args[2] = { instance.location(), instance_template.location() };
Handle<Object> args[] = { instance, instance_template };
Execution::Call(isolate->configure_instance_fun(),
isolate->js_builtins_object(), 2, args, exc);
isolate->js_builtins_object(),
ARRAY_SIZE(args),
args,
exc);
}
@ -735,16 +761,13 @@ Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
Handle<Object> pos,
Handle<Object> is_global) {
Isolate* isolate = fun->GetIsolate();
const int argc = 4;
Object** args[argc] = { recv.location(),
Handle<Object>::cast(fun).location(),
pos.location(),
is_global.location() };
bool caught_exception = false;
Handle<Object> result =
TryCall(isolate->get_stack_trace_line_fun(),
isolate->js_builtins_object(), argc, args,
&caught_exception);
Handle<Object> args[] = { recv, fun, pos, is_global };
bool caught_exception;
Handle<Object> result = TryCall(isolate->get_stack_trace_line_fun(),
isolate->js_builtins_object(),
ARRAY_SIZE(args),
args,
&caught_exception);
if (caught_exception || !result->IsString()) {
return isolate->factory()->empty_symbol();
}
@ -852,6 +875,12 @@ void Execution::ProcessDebugMesssages(bool debug_command_only) {
MaybeObject* Execution::HandleStackGuardInterrupt() {
Isolate* isolate = Isolate::Current();
StackGuard* stack_guard = isolate->stack_guard();
if (stack_guard->IsGCRequest()) {
isolate->heap()->CollectAllGarbage(false);
stack_guard->Continue(GC_REQUEST);
}
isolate->counters()->stack_interrupts()->Increment();
if (stack_guard->IsRuntimeProfilerTick()) {
isolate->counters()->runtime_profiler_ticks()->Increment();

13
deps/v8/src/execution.h

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -41,7 +41,8 @@ enum InterruptFlag {
DEBUGCOMMAND = 1 << 2,
PREEMPT = 1 << 3,
TERMINATE = 1 << 4,
RUNTIME_PROFILER_TICK = 1 << 5
RUNTIME_PROFILER_TICK = 1 << 5,
GC_REQUEST = 1 << 6
};
class Execution : public AllStatic {
@ -60,7 +61,7 @@ class Execution : public AllStatic {
static Handle<Object> Call(Handle<Object> callable,
Handle<Object> receiver,
int argc,
Object*** args,
Handle<Object> argv[],
bool* pending_exception,
bool convert_receiver = false);
@ -73,7 +74,7 @@ class Execution : public AllStatic {
//
static Handle<Object> New(Handle<JSFunction> func,
int argc,
Object*** args,
Handle<Object> argv[],
bool* pending_exception);
// Call a function, just like Call(), but make sure to silently catch
@ -83,7 +84,7 @@ class Execution : public AllStatic {
static Handle<Object> TryCall(Handle<JSFunction> func,
Handle<Object> receiver,
int argc,
Object*** args,
Handle<Object> argv[],
bool* caught_exception);
// ECMA-262 9.2
@ -196,6 +197,8 @@ class StackGuard {
bool IsDebugCommand();
void DebugCommand();
#endif
bool IsGCRequest();
void RequestGC();
void Continue(InterruptFlag after_what);
// This provides an asynchronous read of the stack limits for the current

12
deps/v8/src/extensions/gc-extension.cc

@ -40,19 +40,15 @@ v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction(
v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) {
bool compact = false;
// All allocation spaces other than NEW_SPACE have the same effect.
if (args.Length() >= 1 && args[0]->IsBoolean()) {
compact = args[0]->BooleanValue();
}
HEAP->CollectAllGarbage(compact);
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
return v8::Undefined();
}
void GCExtension::Register() {
static GCExtension gc_extension;
static v8::DeclareExtension gc_extension_declaration(&gc_extension);
static GCExtension* gc_extension = NULL;
if (gc_extension == NULL) gc_extension = new GCExtension();
static v8::DeclareExtension gc_extension_declaration(gc_extension);
}
} } // namespace v8::internal

192
deps/v8/src/factory.cc

@ -59,13 +59,13 @@ Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size,
}
Handle<FixedArray> Factory::NewFixedDoubleArray(int size,
PretenureFlag pretenure) {
Handle<FixedDoubleArray> Factory::NewFixedDoubleArray(int size,
PretenureFlag pretenure) {
ASSERT(0 <= size);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateUninitializedFixedDoubleArray(size, pretenure),
FixedArray);
FixedDoubleArray);
}
@ -85,6 +85,14 @@ Handle<NumberDictionary> Factory::NewNumberDictionary(int at_least_space_for) {
}
Handle<ObjectHashSet> Factory::NewObjectHashSet(int at_least_space_for) {
ASSERT(0 <= at_least_space_for);
CALL_HEAP_FUNCTION(isolate(),
ObjectHashSet::Allocate(at_least_space_for),
ObjectHashSet);
}
Handle<ObjectHashTable> Factory::NewObjectHashTable(int at_least_space_for) {
ASSERT(0 <= at_least_space_for);
CALL_HEAP_FUNCTION(isolate(),
@ -234,7 +242,7 @@ Handle<String> Factory::NewProperSubString(Handle<String> str,
Handle<String> Factory::NewExternalStringFromAscii(
ExternalAsciiString::Resource* resource) {
const ExternalAsciiString::Resource* resource) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateExternalStringFromAscii(resource),
@ -243,7 +251,7 @@ Handle<String> Factory::NewExternalStringFromAscii(
Handle<String> Factory::NewExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource) {
const ExternalTwoByteString::Resource* resource) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateExternalStringFromTwoByte(resource),
@ -295,7 +303,7 @@ Handle<Context> Factory::NewWithContext(Handle<JSFunction> function,
Handle<Context> Factory::NewBlockContext(
Handle<JSFunction> function,
Handle<Context> previous,
Handle<SerializedScopeInfo> scope_info) {
Handle<ScopeInfo> scope_info) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateBlockContext(*function,
@ -404,10 +412,12 @@ Handle<JSGlobalPropertyCell> Factory::NewJSGlobalPropertyCell(
}
Handle<Map> Factory::NewMap(InstanceType type, int instance_size) {
Handle<Map> Factory::NewMap(InstanceType type,
int instance_size,
ElementsKind elements_kind) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateMap(type, instance_size),
isolate()->heap()->AllocateMap(type, instance_size, elements_kind),
Map);
}
@ -455,23 +465,11 @@ Handle<Map> Factory::CopyMapDropTransitions(Handle<Map> src) {
}
Handle<Map> Factory::GetFastElementsMap(Handle<Map> src) {
CALL_HEAP_FUNCTION(isolate(), src->GetFastElementsMap(), Map);
}
Handle<Map> Factory::GetSlowElementsMap(Handle<Map> src) {
CALL_HEAP_FUNCTION(isolate(), src->GetSlowElementsMap(), Map);
}
Handle<Map> Factory::GetElementsTransitionMap(
Handle<Map> src,
ElementsKind elements_kind,
bool safe_to_add_transition) {
Handle<JSObject> src,
ElementsKind elements_kind) {
CALL_HEAP_FUNCTION(isolate(),
src->GetElementsTransitionMap(elements_kind,
safe_to_add_transition),
src->GetElementsTransitionMap(elements_kind),
Map);
}
@ -481,6 +479,12 @@ Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
}
Handle<FixedDoubleArray> Factory::CopyFixedDoubleArray(
Handle<FixedDoubleArray> array) {
CALL_HEAP_FUNCTION(isolate(), array->Copy(), FixedDoubleArray);
}
Handle<JSFunction> Factory::BaseNewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> function_info,
Handle<Map> function_map,
@ -501,22 +505,26 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
PretenureFlag pretenure) {
Handle<JSFunction> result = BaseNewFunctionFromSharedFunctionInfo(
function_info,
function_info->strict_mode()
? isolate()->strict_mode_function_map()
: isolate()->function_map(),
function_info->is_classic_mode()
? isolate()->function_map()
: isolate()->strict_mode_function_map(),
pretenure);
result->set_context(*context);
int number_of_literals = function_info->num_literals();
Handle<FixedArray> literals = NewFixedArray(number_of_literals, pretenure);
if (number_of_literals > 0) {
// Store the object, regexp and array functions in the literals
// array prefix. These functions will be used when creating
// object, regexp and array literals in this function.
literals->set(JSFunction::kLiteralGlobalContextIndex,
context->global_context());
if (!function_info->bound()) {
int number_of_literals = function_info->num_literals();
Handle<FixedArray> literals = NewFixedArray(number_of_literals, pretenure);
if (number_of_literals > 0) {
// Store the object, regexp and array functions in the literals
// array prefix. These functions will be used when creating
// object, regexp and array literals in this function.
literals->set(JSFunction::kLiteralGlobalContextIndex,
context->global_context());
}
result->set_literals(*literals);
} else {
result->set_function_bindings(isolate()->heap()->empty_fixed_array());
}
result->set_literals(*literals);
result->set_next_function_link(isolate()->heap()->undefined_value());
if (V8::UseCrankshaft() &&
@ -538,17 +546,19 @@ Handle<Object> Factory::NewNumber(double value,
}
Handle<Object> Factory::NewNumberFromInt(int value) {
Handle<Object> Factory::NewNumberFromInt(int32_t value,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->NumberFromInt32(value), Object);
isolate()->heap()->NumberFromInt32(value, pretenure), Object);
}
Handle<Object> Factory::NewNumberFromUint(uint32_t value) {
Handle<Object> Factory::NewNumberFromUint(uint32_t value,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->NumberFromUint32(value), Object);
isolate()->heap()->NumberFromUint32(value, pretenure), Object);
}
@ -641,14 +651,16 @@ Handle<Object> Factory::NewError(const char* maker,
return undefined_value();
Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj);
Handle<Object> type_obj = LookupAsciiSymbol(type);
Object** argv[2] = { type_obj.location(),
Handle<Object>::cast(args).location() };
Handle<Object> argv[] = { type_obj, args };
// Invoke the JavaScript factory method. If an exception is thrown while
// running the factory method, use the exception as the result.
bool caught_exception;
Handle<Object> result = Execution::TryCall(fun,
isolate()->js_builtins_object(), 2, argv, &caught_exception);
isolate()->js_builtins_object(),
ARRAY_SIZE(argv),
argv,
&caught_exception);
return result;
}
@ -664,13 +676,16 @@ Handle<Object> Factory::NewError(const char* constructor,
Handle<JSFunction> fun = Handle<JSFunction>(
JSFunction::cast(isolate()->js_builtins_object()->
GetPropertyNoExceptionThrown(*constr)));
Object** argv[1] = { Handle<Object>::cast(message).location() };
Handle<Object> argv[] = { message };
// Invoke the JavaScript factory method. If an exception is thrown while
// running the factory method, use the exception as the result.
bool caught_exception;
Handle<Object> result = Execution::TryCall(fun,
isolate()->js_builtins_object(), 1, argv, &caught_exception);
isolate()->js_builtins_object(),
ARRAY_SIZE(argv),
argv,
&caught_exception);
return result;
}
@ -722,7 +737,12 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
if (force_initial_map ||
type != JS_OBJECT_TYPE ||
instance_size != JSObject::kHeaderSize) {
Handle<Map> initial_map = NewMap(type, instance_size);
ElementsKind default_elements_kind = FLAG_smi_only_arrays
? FAST_SMI_ONLY_ELEMENTS
: FAST_ELEMENTS;
Handle<Map> initial_map = NewMap(type,
instance_size,
default_elements_kind);
function->set_initial_map(*initial_map);
initial_map->set_constructor(*function);
}
@ -739,7 +759,7 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
Handle<Code> code) {
Handle<JSFunction> function = NewFunctionWithoutPrototype(name,
kNonStrictMode);
CLASSIC_MODE);
function->shared()->set_code(*code);
function->set_code(*code);
ASSERT(!function->has_initial_map());
@ -748,11 +768,11 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
}
Handle<SerializedScopeInfo> Factory::NewSerializedScopeInfo(int length) {
Handle<ScopeInfo> Factory::NewScopeInfo(int length) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateSerializedScopeInfo(length),
SerializedScopeInfo);
isolate()->heap()->AllocateScopeInfo(length),
ScopeInfo);
}
@ -821,10 +841,13 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
// Number of descriptors added to the result so far.
int descriptor_count = 0;
// Ensure that marking will not progress and change color of objects.
DescriptorArray::WhitenessWitness witness(*result);
// Copy the descriptors from the array.
for (int i = 0; i < array->number_of_descriptors(); i++) {
if (array->GetType(i) != NULL_DESCRIPTOR) {
result->CopyFrom(descriptor_count++, *array, i);
if (!array->IsNullDescriptor(i)) {
result->CopyFrom(descriptor_count++, *array, i, witness);
}
}
@ -844,7 +867,7 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
if (result->LinearSearch(*key, descriptor_count) ==
DescriptorArray::kNotFound) {
CallbacksDescriptor desc(*key, *entry, entry->property_attributes());
result->Set(descriptor_count, &desc);
result->Set(descriptor_count, &desc, witness);
descriptor_count++;
} else {
duplicates++;
@ -858,13 +881,13 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
Handle<DescriptorArray> new_result =
NewDescriptorArray(number_of_descriptors);
for (int i = 0; i < number_of_descriptors; i++) {
new_result->CopyFrom(i, *result, i);
new_result->CopyFrom(i, *result, i, witness);
}
result = new_result;
}
// Sort the result before returning.
result->Sort();
result->Sort(witness);
return result;
}
@ -908,11 +931,26 @@ Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArray> elements,
Handle<JSArray> result =
Handle<JSArray>::cast(NewJSObject(isolate()->array_function(),
pretenure));
result->SetContent(*elements);
SetContent(result, elements);
return result;
}
void Factory::SetContent(Handle<JSArray> array,
Handle<FixedArray> elements) {
CALL_HEAP_FUNCTION_VOID(
isolate(),
array->SetContent(*elements));
}
void Factory::EnsureCanContainNonSmiElements(Handle<JSArray> array) {
CALL_HEAP_FUNCTION_VOID(
isolate(),
array->EnsureCanContainNonSmiElements());
}
Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
Handle<Object> prototype) {
CALL_HEAP_FUNCTION(
@ -938,11 +976,18 @@ void Factory::BecomeJSFunction(Handle<JSReceiver> object) {
}
void Factory::SetIdentityHash(Handle<JSObject> object, Object* hash) {
CALL_HEAP_FUNCTION_VOID(
isolate(),
object->SetIdentityHash(hash, ALLOW_CREATION));
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
Handle<String> name,
int number_of_literals,
Handle<Code> code,
Handle<SerializedScopeInfo> scope_info) {
Handle<ScopeInfo> scope_info) {
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo(name);
shared->set_code(*code);
shared->set_scope_info(*scope_info);
@ -990,6 +1035,12 @@ Handle<String> Factory::NumberToString(Handle<Object> number) {
}
Handle<String> Factory::Uint32ToString(uint32_t value) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->Uint32ToString(value), String);
}
Handle<NumberDictionary> Factory::DictionaryAtNumberPut(
Handle<NumberDictionary> dictionary,
uint32_t key,
@ -1022,11 +1073,11 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name,
Handle<JSFunction> Factory::NewFunctionWithoutPrototypeHelper(
Handle<String> name,
StrictModeFlag strict_mode) {
LanguageMode language_mode) {
Handle<SharedFunctionInfo> function_share = NewSharedFunctionInfo(name);
Handle<Map> map = strict_mode == kStrictMode
? isolate()->strict_mode_function_without_prototype_map()
: isolate()->function_without_prototype_map();
Handle<Map> map = (language_mode == CLASSIC_MODE)
? isolate()->function_without_prototype_map()
: isolate()->strict_mode_function_without_prototype_map();
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->AllocateFunction(
*map,
@ -1038,8 +1089,9 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototypeHelper(
Handle<JSFunction> Factory::NewFunctionWithoutPrototype(
Handle<String> name,
StrictModeFlag strict_mode) {
Handle<JSFunction> fun = NewFunctionWithoutPrototypeHelper(name, strict_mode);
LanguageMode language_mode) {
Handle<JSFunction> fun =
NewFunctionWithoutPrototypeHelper(name, language_mode);
fun->set_context(isolate()->context()->global_context());
return fun;
}
@ -1299,4 +1351,20 @@ void Factory::ConfigureInstance(Handle<FunctionTemplateInfo> desc,
}
Handle<Object> Factory::GlobalConstantFor(Handle<String> name) {
Heap* h = isolate()->heap();
if (name->Equals(h->undefined_symbol())) return undefined_value();
if (name->Equals(h->nan_symbol())) return nan_value();
if (name->Equals(h->infinity_symbol())) return infinity_value();
return Handle<Object>::null();
}
Handle<Object> Factory::ToBoolean(bool value) {
return Handle<Object>(value
? isolate()->heap()->true_value()
: isolate()->heap()->false_value());
}
} } // namespace v8::internal

55
deps/v8/src/factory.h

@ -50,7 +50,7 @@ class Factory {
PretenureFlag pretenure = NOT_TENURED);
// Allocate a new uninitialized fixed double array.
Handle<FixedArray> NewFixedDoubleArray(
Handle<FixedDoubleArray> NewFixedDoubleArray(
int size,
PretenureFlag pretenure = NOT_TENURED);
@ -58,6 +58,8 @@ class Factory {
Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
Handle<ObjectHashSet> NewObjectHashSet(int at_least_space_for);
Handle<ObjectHashTable> NewObjectHashTable(int at_least_space_for);
Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
@ -145,9 +147,9 @@ class Factory {
// not make sense to have a UTF-8 factory function for external strings,
// because we cannot change the underlying buffer.
Handle<String> NewExternalStringFromAscii(
ExternalAsciiString::Resource* resource);
const ExternalAsciiString::Resource* resource);
Handle<String> NewExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource);
const ExternalTwoByteString::Resource* resource);
// Create a global (but otherwise uninitialized) context.
Handle<Context> NewGlobalContext();
@ -170,7 +172,7 @@ class Factory {
// Create a 'block' context.
Handle<Context> NewBlockContext(Handle<JSFunction> function,
Handle<Context> previous,
Handle<SerializedScopeInfo> scope_info);
Handle<ScopeInfo> scope_info);
// Return the Symbol matching the passed in string.
Handle<String> SymbolFromString(Handle<String> value);
@ -203,7 +205,9 @@ class Factory {
Handle<JSGlobalPropertyCell> NewJSGlobalPropertyCell(
Handle<Object> value);
Handle<Map> NewMap(InstanceType type, int instance_size);
Handle<Map> NewMap(InstanceType type,
int instance_size,
ElementsKind elements_kind = FAST_ELEMENTS);
Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
@ -215,22 +219,22 @@ class Factory {
Handle<Map> CopyMapDropTransitions(Handle<Map> map);
Handle<Map> GetFastElementsMap(Handle<Map> map);
Handle<Map> GetSlowElementsMap(Handle<Map> map);
Handle<Map> GetElementsTransitionMap(Handle<Map> map,
ElementsKind elements_kind,
bool safe_to_add_transition);
Handle<Map> GetElementsTransitionMap(Handle<JSObject> object,
ElementsKind elements_kind);
Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
Handle<FixedDoubleArray> CopyFixedDoubleArray(
Handle<FixedDoubleArray> array);
// Numbers (eg, literals) are pretenured by the parser.
Handle<Object> NewNumber(double value,
PretenureFlag pretenure = NOT_TENURED);
Handle<Object> NewNumberFromInt(int value);
Handle<Object> NewNumberFromUint(uint32_t value);
Handle<Object> NewNumberFromInt(int32_t value,
PretenureFlag pretenure = NOT_TENURED);
Handle<Object> NewNumberFromUint(uint32_t value,
PretenureFlag pretenure = NOT_TENURED);
// These objects are used by the api to create env-independent data
// structures in the heap.
@ -258,18 +262,24 @@ class Factory {
Handle<FixedArray> elements,
PretenureFlag pretenure = NOT_TENURED);
void SetContent(Handle<JSArray> array, Handle<FixedArray> elements);
void EnsureCanContainNonSmiElements(Handle<JSArray> array);
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
// Change the type of the argument into a JS object/function and reinitialize.
void BecomeJSObject(Handle<JSReceiver> object);
void BecomeJSFunction(Handle<JSReceiver> object);
void SetIdentityHash(Handle<JSObject> object, Object* hash);
Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Object> prototype);
Handle<JSFunction> NewFunctionWithoutPrototype(
Handle<String> name,
StrictModeFlag strict_mode);
LanguageMode language_mode);
Handle<JSFunction> NewFunction(Handle<Object> super, bool is_global);
@ -283,7 +293,7 @@ class Factory {
Handle<Context> context,
PretenureFlag pretenure = TENURED);
Handle<SerializedScopeInfo> NewSerializedScopeInfo(int length);
Handle<ScopeInfo> NewScopeInfo(int length);
Handle<Code> NewCode(const CodeDesc& desc,
Code::Flags flags,
@ -356,6 +366,7 @@ class Factory {
PropertyAttributes attributes);
Handle<String> NumberToString(Handle<Object> number);
Handle<String> Uint32ToString(uint32_t value);
enum ApiInstanceType {
JavaScriptObject,
@ -400,7 +411,7 @@ class Factory {
Handle<String> name,
int number_of_literals,
Handle<Code> code,
Handle<SerializedScopeInfo> scope_info);
Handle<ScopeInfo> scope_info);
Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
Handle<JSMessageObject> NewJSMessageObject(
@ -442,6 +453,14 @@ class Factory {
JSRegExp::Flags flags,
int capture_count);
// Returns the value for a known global constant (a property of the global
// object which is neither configurable nor writable) like 'undefined'.
// Returns a null handle when the given name is unknown.
Handle<Object> GlobalConstantFor(Handle<String> name);
// Converts the given boolean condition to JavaScript boolean value.
Handle<Object> ToBoolean(bool value);
private:
Isolate* isolate() { return reinterpret_cast<Isolate*>(this); }
@ -450,7 +469,7 @@ class Factory {
Handle<JSFunction> NewFunctionWithoutPrototypeHelper(
Handle<String> name,
StrictModeFlag strict_mode);
LanguageMode language_mode);
Handle<DescriptorArray> CopyAppendCallbackDescriptors(
Handle<DescriptorArray> array,

4
deps/v8/src/fast-dtoa.h

@ -1,4 +1,4 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Copyright 2011 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:
@ -43,7 +43,7 @@ enum FastDtoaMode {
// FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not
// include the terminating '\0' character.
static const int kFastDtoaMaximalLength = 17;
const int kFastDtoaMaximalLength = 17;
// Provides a decimal representation of v.
// The result should be interpreted as buffer * 10^(point - length).

60
deps/v8/src/flag-definitions.h

@ -98,20 +98,23 @@ private:
// Flags for experimental language features.
DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof")
DEFINE_bool(harmony_scoping, false, "enable harmony block scoping")
DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps")
DEFINE_bool(harmony_block_scoping, false, "enable harmony block scoping")
DEFINE_bool(harmony_collections, false,
"enable harmony collections (sets, maps, and weak maps)")
DEFINE_bool(harmony, false, "enable all harmony features")
// Flags for experimental implementation features.
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
DEFINE_bool(string_slices, false, "use string slices")
DEFINE_bool(smi_only_arrays, false, "tracks arrays with only smi values")
DEFINE_bool(string_slices, true, "use string slices")
DEFINE_bool(clever_optimizations,
true,
"Optimize object size, Array shift, DOM strings and string +")
// Flags for Crankshaft.
#ifdef V8_TARGET_ARCH_MIPS
DEFINE_bool(crankshaft, false, "use crankshaft")
#else
DEFINE_bool(crankshaft, true, "use crankshaft")
#endif
DEFINE_bool(crankshaft, true, "use crankshaft")
DEFINE_string(hydrogen_filter, "", "hydrogen use/trace filter")
DEFINE_bool(use_hydrogen, true, "use generated hydrogen for compilation")
DEFINE_bool(build_lithium, true, "use lithium chunk builder")
@ -125,6 +128,9 @@ DEFINE_bool(use_inlining, true, "use function inlining")
DEFINE_bool(limit_inlining, true, "limit code size growth from inlining")
DEFINE_bool(eliminate_empty_blocks, true, "eliminate empty blocks")
DEFINE_bool(loop_invariant_code_motion, true, "loop invariant code motion")
DEFINE_bool(collect_megamorphic_maps_from_stub_cache,
true,
"crankshaft harvests type feedback from stub cache")
DEFINE_bool(hydrogen_stats, false, "print statistics for hydrogen")
DEFINE_bool(trace_hydrogen, false, "trace generated hydrogen to file")
DEFINE_bool(trace_inlining, false, "trace inlining decisions")
@ -180,6 +186,8 @@ DEFINE_bool(expose_gc, false, "expose gc extension")
DEFINE_bool(expose_externalize_string, false,
"expose externalize string extension")
DEFINE_int(stack_trace_limit, 10, "number of stack frames to capture")
DEFINE_bool(builtins_in_stack_traces, false,
"show built-in functions in stack traces")
DEFINE_bool(disable_native_files, false, "disable builtin natives files")
// builtins-ia32.cc
@ -253,10 +261,16 @@ DEFINE_bool(print_cumulative_gc_stat, false,
"print cumulative GC statistics in name=value format on exit")
DEFINE_bool(trace_gc_verbose, false,
"print more details following each garbage collection")
DEFINE_bool(trace_fragmentation, false,
"report fragmentation for old pointer and data pages")
DEFINE_bool(collect_maps, true,
"garbage collect maps from which no objects can be reached")
DEFINE_bool(flush_code, true,
"flush code that we expect not to use again before full gc")
DEFINE_bool(incremental_marking, true, "use incremental marking")
DEFINE_bool(incremental_marking_steps, true, "do incremental marking steps")
DEFINE_bool(trace_incremental_marking, false,
"trace progress of the incremental marking")
// v8.cc
DEFINE_bool(use_idle_notification, true,
@ -276,8 +290,13 @@ DEFINE_bool(native_code_counters, false,
// mark-compact.cc
DEFINE_bool(always_compact, false, "Perform compaction on every full GC")
DEFINE_bool(lazy_sweeping, true,
"Use lazy sweeping for old pointer and data spaces")
DEFINE_bool(cleanup_caches_in_maps_at_gc, true,
"Flush code caches in maps during mark compact cycle.")
DEFINE_bool(never_compact, false,
"Never perform compaction on full GC - testing only")
DEFINE_bool(compact_code_space, false, "Compact code space")
DEFINE_bool(cleanup_code_caches_at_gc, true,
"Flush inline caches prior to mark compact collection and "
"flush code caches in maps during mark compact cycle.")
@ -288,9 +307,6 @@ DEFINE_int(random_seed, 0,
DEFINE_bool(canonicalize_object_literal_maps, true,
"Canonicalize maps for object literals.")
DEFINE_bool(use_big_map_space, true,
"Use big map space, but don't compact if it grew too big.")
DEFINE_int(max_map_space_pages, MapSpace::kMaxMapPageIndex - 1,
"Maximum number of pages in map space which still allows to encode "
"forwarding pointers. That's actually a constant, but it's useful "
@ -305,11 +321,11 @@ DEFINE_bool(use_verbose_printer, true, "allows verbose printing")
// parser.cc
DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
DEFINE_bool(strict_mode, true, "allow strict mode directives")
// simulator-arm.cc and simulator-mips.cc
DEFINE_bool(trace_sim, false, "Trace simulator execution")
DEFINE_bool(check_icache, false, "Check icache flushes in ARM simulator")
DEFINE_bool(check_icache, false,
"Check icache flushes in ARM and MIPS simulator")
DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions")
DEFINE_int(sim_stack_alignment, 8,
"Stack alingment in bytes in simulator (4 or 8, 8 is default)")
@ -326,7 +342,6 @@ DEFINE_bool(preemption, false,
// Regexp
DEFINE_bool(regexp_optimization, true, "generate optimized regexp code")
DEFINE_bool(regexp_entry_native, true, "use native code to enter regexp")
// Testing flags test/cctest/test-{flags,api,serialization}.cc
DEFINE_bool(testing_bool_flag, true, "testing_bool_flag")
@ -348,11 +363,15 @@ DEFINE_string(testing_serialization_file, "/tmp/serdes",
DEFINE_bool(help, false, "Print usage message, including flags, on console")
DEFINE_bool(dump_counters, false, "Dump counters on exit")
#ifdef ENABLE_DEBUGGER_SUPPORT
DEFINE_bool(debugger, false, "Enable JavaScript debugger")
DEFINE_bool(remote_debugger, false, "Connect JavaScript debugger to the "
"debugger agent in another process")
DEFINE_bool(debugger_agent, false, "Enable debugger agent")
DEFINE_int(debugger_port, 5858, "Port to use for remote debugging")
#endif // ENABLE_DEBUGGER_SUPPORT
DEFINE_string(map_counters, "", "Map counters to a file")
DEFINE_args(js_arguments, JSArguments(),
"Pass all remaining arguments to the script. Alias for \"--\".")
@ -378,6 +397,15 @@ DEFINE_bool(gdbjit_dump, false, "dump elf objects with debug info to disk")
DEFINE_string(gdbjit_dump_filter, "",
"dump only objects containing this substring")
// mark-compact.cc
DEFINE_bool(force_marking_deque_overflows, false,
"force overflows of marking deque by reducing it's size "
"to 64 words")
DEFINE_bool(stress_compaction, false,
"stress the GC compactor to flush out bugs (implies "
"--force_marking_deque_overflows)")
//
// Debug only flags
//
@ -404,7 +432,6 @@ DEFINE_bool(print_json_ast, false, "print source AST as JSON")
DEFINE_bool(print_builtin_json_ast, false,
"print source AST for builtins as JSON")
DEFINE_string(stop_at, "", "function name where to insert a breakpoint")
DEFINE_bool(verify_stack_height, false, "verify stack height tracing on ia32")
// compiler.cc
DEFINE_bool(print_builtin_scopes, false, "print scopes for builtins")
@ -501,6 +528,9 @@ DEFINE_bool(ll_prof, false, "Enable low-level linux profiler.")
#define FLAG FLAG_READONLY
#endif
// elements.cc
DEFINE_bool(trace_elements_transitions, false, "trace elements transitions")
// code-stubs.cc
DEFINE_bool(print_code_stubs, false, "print code stubs")

88
deps/v8/src/frames-inl.h

@ -68,7 +68,7 @@ inline bool StackHandler::includes(Address address) const {
inline void StackHandler::Iterate(ObjectVisitor* v, Code* holder) const {
v->VisitPointer(context_address());
StackFrame::IteratePc(v, pc_address(), holder);
v->VisitPointer(code_address());
}
@ -77,9 +77,24 @@ inline StackHandler* StackHandler::FromAddress(Address address) {
}
inline StackHandler::State StackHandler::state() const {
inline bool StackHandler::is_entry() const {
return kind() == ENTRY;
}
inline bool StackHandler::is_try_catch() const {
return kind() == TRY_CATCH;
}
inline bool StackHandler::is_try_finally() const {
return kind() == TRY_FINALLY;
}
inline StackHandler::Kind StackHandler::kind() const {
const int offset = StackHandlerConstants::kStateOffset;
return static_cast<State>(Memory::int_at(address() + offset));
return KindField::decode(Memory::unsigned_at(address() + offset));
}
@ -89,9 +104,9 @@ inline Object** StackHandler::context_address() const {
}
inline Address* StackHandler::pc_address() const {
const int offset = StackHandlerConstants::kPCOffset;
return reinterpret_cast<Address*>(address() + offset);
inline Object** StackHandler::code_address() const {
const int offset = StackHandlerConstants::kCodeOffset;
return reinterpret_cast<Object**>(address() + offset);
}
@ -105,8 +120,33 @@ inline StackHandler* StackFrame::top_handler() const {
}
inline Code* StackFrame::LookupCode() const {
return GetContainingCode(isolate(), pc());
}
inline Code* StackFrame::GetContainingCode(Isolate* isolate, Address pc) {
return isolate->pc_to_code_cache()->GetCacheEntry(pc)->code;
return isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code;
}
inline EntryFrame::EntryFrame(StackFrameIterator* iterator)
: StackFrame(iterator) {
}
inline EntryConstructFrame::EntryConstructFrame(StackFrameIterator* iterator)
: EntryFrame(iterator) {
}
inline ExitFrame::ExitFrame(StackFrameIterator* iterator)
: StackFrame(iterator) {
}
inline StandardFrame::StandardFrame(StackFrameIterator* iterator)
: StackFrame(iterator) {
}
@ -155,6 +195,11 @@ inline bool StandardFrame::IsConstructFrame(Address fp) {
}
inline JavaScriptFrame::JavaScriptFrame(StackFrameIterator* iterator)
: StandardFrame(iterator) {
}
Address JavaScriptFrame::GetParameterSlot(int index) const {
int param_count = ComputeParametersCount();
ASSERT(-1 <= index && index < param_count);
@ -190,6 +235,26 @@ inline Object* JavaScriptFrame::function() const {
}
inline OptimizedFrame::OptimizedFrame(StackFrameIterator* iterator)
: JavaScriptFrame(iterator) {
}
inline ArgumentsAdaptorFrame::ArgumentsAdaptorFrame(
StackFrameIterator* iterator) : JavaScriptFrame(iterator) {
}
inline InternalFrame::InternalFrame(StackFrameIterator* iterator)
: StandardFrame(iterator) {
}
inline ConstructFrame::ConstructFrame(StackFrameIterator* iterator)
: InternalFrame(iterator) {
}
template<typename Iterator>
inline JavaScriptFrameIteratorTemp<Iterator>::JavaScriptFrameIteratorTemp(
Isolate* isolate)
@ -197,6 +262,15 @@ inline JavaScriptFrameIteratorTemp<Iterator>::JavaScriptFrameIteratorTemp(
if (!done()) Advance();
}
template<typename Iterator>
inline JavaScriptFrameIteratorTemp<Iterator>::JavaScriptFrameIteratorTemp(
Isolate* isolate, ThreadLocalTop* top)
: iterator_(isolate, top) {
if (!done()) Advance();
}
template<typename Iterator>
inline JavaScriptFrame* JavaScriptFrameIteratorTemp<Iterator>::frame() const {
// TODO(1233797): The frame hierarchy needs to change. It's

211
deps/v8/src/frames.cc

@ -366,16 +366,17 @@ void SafeStackTraceFrameIterator::Advance() {
Code* StackFrame::GetSafepointData(Isolate* isolate,
Address pc,
Address inner_pointer,
SafepointEntry* safepoint_entry,
unsigned* stack_slots) {
PcToCodeCache::PcToCodeCacheEntry* entry =
isolate->pc_to_code_cache()->GetCacheEntry(pc);
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
isolate->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
if (!entry->safepoint_entry.is_valid()) {
entry->safepoint_entry = entry->code->GetSafepointEntry(pc);
entry->safepoint_entry = entry->code->GetSafepointEntry(inner_pointer);
ASSERT(entry->safepoint_entry.is_valid());
} else {
ASSERT(entry->safepoint_entry.Equals(entry->code->GetSafepointEntry(pc)));
ASSERT(entry->safepoint_entry.Equals(
entry->code->GetSafepointEntry(inner_pointer)));
}
// Fill in the results and return the code.
@ -392,11 +393,16 @@ bool StackFrame::HasHandler() const {
}
#ifdef DEBUG
static bool GcSafeCodeContains(HeapObject* object, Address addr);
#endif
void StackFrame::IteratePc(ObjectVisitor* v,
Address* pc_address,
Code* holder) {
Address pc = *pc_address;
ASSERT(holder->contains(pc));
ASSERT(GcSafeCodeContains(holder, pc));
unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
Object* code = holder;
v->VisitPointer(&code);
@ -705,6 +711,69 @@ void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
}
void JavaScriptFrame::PrintTop(FILE* file,
bool print_args,
bool print_line_number) {
// constructor calls
HandleScope scope;
AssertNoAllocation no_allocation;
JavaScriptFrameIterator it;
while (!it.done()) {
if (it.frame()->is_java_script()) {
JavaScriptFrame* frame = it.frame();
if (frame->IsConstructor()) PrintF(file, "new ");
// function name
Object* fun = frame->function();
if (fun->IsJSFunction()) {
SharedFunctionInfo* shared = JSFunction::cast(fun)->shared();
shared->DebugName()->ShortPrint(file);
if (print_line_number) {
Address pc = frame->pc();
Code* code = Code::cast(
v8::internal::Isolate::Current()->heap()->FindCodeObject(pc));
int source_pos = code->SourcePosition(pc);
Object* maybe_script = shared->script();
if (maybe_script->IsScript()) {
Handle<Script> script(Script::cast(maybe_script));
int line = GetScriptLineNumberSafe(script, source_pos) + 1;
Object* script_name_raw = script->name();
if (script_name_raw->IsString()) {
String* script_name = String::cast(script->name());
SmartArrayPointer<char> c_script_name =
script_name->ToCString(DISALLOW_NULLS,
ROBUST_STRING_TRAVERSAL);
PrintF(file, " at %s:%d", *c_script_name, line);
} else {
PrintF(file, "at <unknown>:%d", line);
}
} else {
PrintF(file, " at <unknown>:<unknown>");
}
}
} else {
fun->ShortPrint(file);
}
if (print_args) {
// function arguments
// (we are intentionally only printing the actually
// supplied parameters, not all parameters required)
PrintF(file, "(this=");
frame->receiver()->ShortPrint(file);
const int length = frame->ComputeParametersCount();
for (int i = 0; i < length; i++) {
PrintF(file, ", ");
frame->GetParameter(i)->ShortPrint(file);
}
PrintF(file, ")");
}
break;
}
it.Advance();
}
}
void FrameSummary::Print() {
PrintF("receiver: ");
receiver_->ShortPrint();
@ -819,7 +888,8 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
// back to a slow search in this case to find the original optimized
// code object.
if (!code->contains(pc())) {
code = isolate()->pc_to_code_cache()->GcSafeFindCodeForPc(pc());
code = isolate()->inner_pointer_to_code_cache()->
GcSafeFindCodeForInnerPointer(pc());
}
ASSERT(code != NULL);
ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
@ -881,6 +951,11 @@ void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
}
int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
return Smi::cast(GetExpression(0))->value();
}
Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
return fp() + StandardFrameConstants::kCallerSPOffset;
}
@ -927,11 +1002,15 @@ void JavaScriptFrame::Print(StringStream* accumulator,
if (IsConstructor()) accumulator->Add("new ");
accumulator->PrintFunction(function, receiver, &code);
Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
// Get scope information for nicer output, if possible. If code is NULL, or
// doesn't contain scope info, scope_info will return 0 for the number of
// parameters, stack local variables, context local variables, stack slots,
// or context slots.
Handle<ScopeInfo> scope_info(ScopeInfo::Empty());
if (function->IsJSFunction()) {
Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
scope_info = Handle<SerializedScopeInfo>(shared->scope_info());
scope_info = Handle<ScopeInfo>(shared->scope_info());
Object* script_obj = shared->script();
if (script_obj->IsScript()) {
Handle<Script> script(Script::cast(script_obj));
@ -956,11 +1035,6 @@ void JavaScriptFrame::Print(StringStream* accumulator,
accumulator->Add("(this=%o", receiver);
// Get scope information for nicer output, if possible. If code is
// NULL, or doesn't contain scope info, info will return 0 for the
// number of parameters, stack slots, or context slots.
ScopeInfo<PreallocatedStorage> info(*scope_info);
// Print the parameters.
int parameters_count = ComputeParametersCount();
for (int i = 0; i < parameters_count; i++) {
@ -968,8 +1042,8 @@ void JavaScriptFrame::Print(StringStream* accumulator,
// If we have a name for the parameter we print it. Nameless
// parameters are either because we have more actual parameters
// than formal parameters or because we have no scope information.
if (i < info.number_of_parameters()) {
accumulator->PrintName(*info.parameter_name(i));
if (i < scope_info->ParameterCount()) {
accumulator->PrintName(scope_info->ParameterName(i));
accumulator->Add("=");
}
accumulator->Add("%o", GetParameter(i));
@ -987,8 +1061,8 @@ void JavaScriptFrame::Print(StringStream* accumulator,
accumulator->Add(" {\n");
// Compute the number of locals and expression stack elements.
int stack_locals_count = info.number_of_stack_slots();
int heap_locals_count = info.number_of_context_slots();
int stack_locals_count = scope_info->StackLocalCount();
int heap_locals_count = scope_info->ContextLocalCount();
int expressions_count = ComputeExpressionsCount();
// Print stack-allocated local variables.
@ -997,7 +1071,7 @@ void JavaScriptFrame::Print(StringStream* accumulator,
}
for (int i = 0; i < stack_locals_count; i++) {
accumulator->Add(" var ");
accumulator->PrintName(*info.stack_slot_name(i));
accumulator->PrintName(scope_info->StackLocalName(i));
accumulator->Add(" = ");
if (i < expressions_count) {
accumulator->Add("%o", GetExpression(i));
@ -1014,16 +1088,16 @@ void JavaScriptFrame::Print(StringStream* accumulator,
}
// Print heap-allocated local variables.
if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
if (heap_locals_count > 0) {
accumulator->Add(" // heap-allocated locals\n");
}
for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
for (int i = 0; i < heap_locals_count; i++) {
accumulator->Add(" var ");
accumulator->PrintName(*info.context_slot_name(i));
accumulator->PrintName(scope_info->ContextLocalName(i));
accumulator->Add(" = ");
if (context != NULL) {
if (i < context->length()) {
accumulator->Add("%o", context->get(i));
accumulator->Add("%o", context->get(Context::MIN_CONTEXT_SLOTS + i));
} else {
accumulator->Add(
"// warning: missing context slot - inconsistent frame?");
@ -1155,52 +1229,89 @@ JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
// -------------------------------------------------------------------------
Code* PcToCodeCache::GcSafeCastToCode(HeapObject* object, Address pc) {
static Map* GcSafeMapOfCodeSpaceObject(HeapObject* object) {
MapWord map_word = object->map_word();
return map_word.IsForwardingAddress() ?
map_word.ToForwardingAddress()->map() : map_word.ToMap();
}
static int GcSafeSizeOfCodeSpaceObject(HeapObject* object) {
return object->SizeFromMap(GcSafeMapOfCodeSpaceObject(object));
}
#ifdef DEBUG
static bool GcSafeCodeContains(HeapObject* code, Address addr) {
Map* map = GcSafeMapOfCodeSpaceObject(code);
ASSERT(map == code->GetHeap()->code_map());
Address start = code->address();
Address end = code->address() + code->SizeFromMap(map);
return start <= addr && addr < end;
}
#endif
Code* InnerPointerToCodeCache::GcSafeCastToCode(HeapObject* object,
Address inner_pointer) {
Code* code = reinterpret_cast<Code*>(object);
ASSERT(code != NULL && code->contains(pc));
ASSERT(code != NULL && GcSafeCodeContains(code, inner_pointer));
return code;
}
Code* PcToCodeCache::GcSafeFindCodeForPc(Address pc) {
Code* InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer(
Address inner_pointer) {
Heap* heap = isolate_->heap();
// Check if the pc points into a large object chunk.
LargeObjectChunk* chunk = heap->lo_space()->FindChunkContainingPc(pc);
if (chunk != NULL) return GcSafeCastToCode(chunk->GetObject(), pc);
// Iterate through the 8K page until we reach the end or find an
// object starting after the pc.
Page* page = Page::FromAddress(pc);
HeapObjectIterator iterator(page, heap->GcSafeSizeOfOldObjectFunction());
HeapObject* previous = NULL;
// Check if the inner pointer points into a large object chunk.
LargePage* large_page = heap->lo_space()->FindPageContainingPc(inner_pointer);
if (large_page != NULL) {
return GcSafeCastToCode(large_page->GetObject(), inner_pointer);
}
// Iterate through the page until we reach the end or find an object starting
// after the inner pointer.
Page* page = Page::FromAddress(inner_pointer);
Address addr = page->skip_list()->StartFor(inner_pointer);
Address top = heap->code_space()->top();
Address limit = heap->code_space()->limit();
while (true) {
HeapObject* next = iterator.next();
if (next == NULL || next->address() >= pc) {
return GcSafeCastToCode(previous, pc);
if (addr == top && addr != limit) {
addr = limit;
continue;
}
previous = next;
HeapObject* obj = HeapObject::FromAddress(addr);
int obj_size = GcSafeSizeOfCodeSpaceObject(obj);
Address next_addr = addr + obj_size;
if (next_addr > inner_pointer) return GcSafeCastToCode(obj, inner_pointer);
addr = next_addr;
}
}
PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) {
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
isolate_->counters()->pc_to_code()->Increment();
ASSERT(IsPowerOf2(kPcToCodeCacheSize));
ASSERT(IsPowerOf2(kInnerPointerToCodeCacheSize));
uint32_t hash = ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)));
uint32_t index = hash & (kPcToCodeCacheSize - 1);
PcToCodeCacheEntry* entry = cache(index);
if (entry->pc == pc) {
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)));
uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
InnerPointerToCodeCacheEntry* entry = cache(index);
if (entry->inner_pointer == inner_pointer) {
isolate_->counters()->pc_to_code_cached()->Increment();
ASSERT(entry->code == GcSafeFindCodeForPc(pc));
ASSERT(entry->code == GcSafeFindCodeForInnerPointer(inner_pointer));
} else {
// Because this code may be interrupted by a profiling signal that
// also queries the cache, we cannot update pc before the code has
// been set. Otherwise, we risk trying to use a cache entry before
// also queries the cache, we cannot update inner_pointer before the code
// has been set. Otherwise, we risk trying to use a cache entry before
// the code has been computed.
entry->code = GcSafeFindCodeForPc(pc);
entry->code = GcSafeFindCodeForInnerPointer(inner_pointer);
entry->safepoint_entry.Reset();
entry->pc = pc;
entry->inner_pointer = inner_pointer;
}
return entry;
}

93
deps/v8/src/frames.h

@ -49,47 +49,52 @@ class StackFrameIterator;
class ThreadLocalTop;
class Isolate;
class PcToCodeCache {
class InnerPointerToCodeCache {
public:
struct PcToCodeCacheEntry {
Address pc;
struct InnerPointerToCodeCacheEntry {
Address inner_pointer;
Code* code;
SafepointEntry safepoint_entry;
};
explicit PcToCodeCache(Isolate* isolate) : isolate_(isolate) {
explicit InnerPointerToCodeCache(Isolate* isolate) : isolate_(isolate) {
Flush();
}
Code* GcSafeFindCodeForPc(Address pc);
Code* GcSafeCastToCode(HeapObject* object, Address pc);
Code* GcSafeFindCodeForInnerPointer(Address inner_pointer);
Code* GcSafeCastToCode(HeapObject* object, Address inner_pointer);
void Flush() {
memset(&cache_[0], 0, sizeof(cache_));
}
PcToCodeCacheEntry* GetCacheEntry(Address pc);
InnerPointerToCodeCacheEntry* GetCacheEntry(Address inner_pointer);
private:
PcToCodeCacheEntry* cache(int index) { return &cache_[index]; }
InnerPointerToCodeCacheEntry* cache(int index) { return &cache_[index]; }
Isolate* isolate_;
static const int kPcToCodeCacheSize = 1024;
PcToCodeCacheEntry cache_[kPcToCodeCacheSize];
static const int kInnerPointerToCodeCacheSize = 1024;
InnerPointerToCodeCacheEntry cache_[kInnerPointerToCodeCacheSize];
DISALLOW_COPY_AND_ASSIGN(PcToCodeCache);
DISALLOW_COPY_AND_ASSIGN(InnerPointerToCodeCache);
};
class StackHandler BASE_EMBEDDED {
public:
enum State {
enum Kind {
ENTRY,
TRY_CATCH,
TRY_FINALLY
};
static const int kKindWidth = 2;
static const int kOffsetWidth = 32 - kKindWidth;
class KindField: public BitField<StackHandler::Kind, 0, kKindWidth> {};
class OffsetField: public BitField<unsigned, kKindWidth, kOffsetWidth> {};
// Get the address of this stack handler.
inline Address address() const;
@ -106,16 +111,16 @@ class StackHandler BASE_EMBEDDED {
static inline StackHandler* FromAddress(Address address);
// Testers
bool is_entry() { return state() == ENTRY; }
bool is_try_catch() { return state() == TRY_CATCH; }
bool is_try_finally() { return state() == TRY_FINALLY; }
inline bool is_entry() const;
inline bool is_try_catch() const;
inline bool is_try_finally() const;
private:
// Accessors.
inline State state() const;
inline Kind kind() const;
inline Object** context_address() const;
inline Address* pc_address() const;
inline Object** code_address() const;
DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
};
@ -139,7 +144,10 @@ class StackFrame BASE_EMBEDDED {
enum Type {
NONE = 0,
STACK_FRAME_TYPE_LIST(DECLARE_TYPE)
NUMBER_OF_TYPES
NUMBER_OF_TYPES,
// Used by FrameScope to indicate that the stack frame is constructed
// manually and the FrameScope does not need to emit code.
MANUAL
};
#undef DECLARE_TYPE
@ -215,9 +223,7 @@ class StackFrame BASE_EMBEDDED {
virtual Code* unchecked_code() const = 0;
// Get the code associated with this frame.
Code* LookupCode() const {
return GetContainingCode(isolate(), pc());
}
inline Code* LookupCode() const;
// Get the code object that contains the given pc.
static inline Code* GetContainingCode(Isolate* isolate, Address pc);
@ -299,7 +305,7 @@ class EntryFrame: public StackFrame {
virtual void SetCallerFp(Address caller_fp);
protected:
explicit EntryFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
inline explicit EntryFrame(StackFrameIterator* iterator);
// The caller stack pointer for entry frames is always zero. The
// real information about the caller frame is available through the
@ -326,8 +332,7 @@ class EntryConstructFrame: public EntryFrame {
}
protected:
explicit EntryConstructFrame(StackFrameIterator* iterator)
: EntryFrame(iterator) { }
inline explicit EntryConstructFrame(StackFrameIterator* iterator);
private:
friend class StackFrameIterator;
@ -361,7 +366,7 @@ class ExitFrame: public StackFrame {
static void FillState(Address fp, Address sp, State* state);
protected:
explicit ExitFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
inline explicit ExitFrame(StackFrameIterator* iterator);
virtual Address GetCallerStackPointer() const;
@ -394,8 +399,7 @@ class StandardFrame: public StackFrame {
}
protected:
explicit StandardFrame(StackFrameIterator* iterator)
: StackFrame(iterator) { }
inline explicit StandardFrame(StackFrameIterator* iterator);
virtual void ComputeCallerState(State* state) const;
@ -513,9 +517,10 @@ class JavaScriptFrame: public StandardFrame {
return static_cast<JavaScriptFrame*>(frame);
}
static void PrintTop(FILE* file, bool print_args, bool print_line_number);
protected:
explicit JavaScriptFrame(StackFrameIterator* iterator)
: StandardFrame(iterator) { }
inline explicit JavaScriptFrame(StackFrameIterator* iterator);
virtual Address GetCallerStackPointer() const;
@ -552,8 +557,7 @@ class OptimizedFrame : public JavaScriptFrame {
DeoptimizationInputData* GetDeoptimizationData(int* deopt_index);
protected:
explicit OptimizedFrame(StackFrameIterator* iterator)
: JavaScriptFrame(iterator) { }
inline explicit OptimizedFrame(StackFrameIterator* iterator);
private:
friend class StackFrameIterator;
@ -581,12 +585,9 @@ class ArgumentsAdaptorFrame: public JavaScriptFrame {
int index) const;
protected:
explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
: JavaScriptFrame(iterator) { }
inline explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator);
virtual int GetNumberOfIncomingArguments() const {
return Smi::cast(GetExpression(0))->value();
}
virtual int GetNumberOfIncomingArguments() const;
virtual Address GetCallerStackPointer() const;
@ -611,8 +612,7 @@ class InternalFrame: public StandardFrame {
}
protected:
explicit InternalFrame(StackFrameIterator* iterator)
: StandardFrame(iterator) { }
inline explicit InternalFrame(StackFrameIterator* iterator);
virtual Address GetCallerStackPointer() const;
@ -633,8 +633,7 @@ class ConstructFrame: public InternalFrame {
}
protected:
explicit ConstructFrame(StackFrameIterator* iterator)
: InternalFrame(iterator) { }
inline explicit ConstructFrame(StackFrameIterator* iterator);
private:
friend class StackFrameIterator;
@ -710,20 +709,26 @@ class JavaScriptFrameIteratorTemp BASE_EMBEDDED {
inline explicit JavaScriptFrameIteratorTemp(Isolate* isolate);
inline JavaScriptFrameIteratorTemp(Isolate* isolate, ThreadLocalTop* top);
// Skip frames until the frame with the given id is reached.
explicit JavaScriptFrameIteratorTemp(StackFrame::Id id) { AdvanceToId(id); }
inline JavaScriptFrameIteratorTemp(Isolate* isolate, StackFrame::Id id);
JavaScriptFrameIteratorTemp(Address fp, Address sp,
Address low_bound, Address high_bound) :
JavaScriptFrameIteratorTemp(Address fp,
Address sp,
Address low_bound,
Address high_bound) :
iterator_(fp, sp, low_bound, high_bound) {
if (!done()) Advance();
}
JavaScriptFrameIteratorTemp(Isolate* isolate,
Address fp, Address sp,
Address low_bound, Address high_bound) :
Address fp,
Address sp,
Address low_bound,
Address high_bound) :
iterator_(isolate, fp, sp, low_bound, high_bound) {
if (!done()) Advance();
}

248
deps/v8/src/full-codegen.cc

@ -244,11 +244,6 @@ void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
}
void BreakableStatementChecker::VisitCompareToNull(CompareToNull* expr) {
Visit(expr->expression());
}
void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
Visit(expr->left());
Visit(expr->right());
@ -291,12 +286,16 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
code->set_optimizable(info->IsOptimizable());
cgen.PopulateDeoptimizationData(code);
code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
code->set_handler_table(*cgen.handler_table());
#ifdef ENABLE_DEBUGGER_SUPPORT
code->set_has_debug_break_slots(
info->isolate()->debugger()->IsDebuggerActive());
code->set_compiled_optimizable(info->IsOptimizable());
#endif // ENABLE_DEBUGGER_SUPPORT
code->set_allow_osr_at_loop_nesting_level(0);
code->set_stack_check_table_offset(table_offset);
CodeGenerator::PrintCode(code, info);
info->SetCode(code); // may be an empty handle.
info->SetCode(code); // May be an empty handle.
#ifdef ENABLE_GDB_JIT_INTERFACE
if (FLAG_gdbjit && !code.is_null()) {
GDBJITLineInfo* lineinfo =
@ -363,7 +362,7 @@ void FullCodeGenerator::RecordJSReturnSite(Call* call) {
}
void FullCodeGenerator::PrepareForBailoutForId(int id, State state) {
void FullCodeGenerator::PrepareForBailoutForId(unsigned id, State state) {
// There's no need to prepare this code for bailouts from already optimized
// code or code that can't be optimized.
if (!FLAG_deopt || !info_->HasDeoptimizationSupport()) return;
@ -384,10 +383,11 @@ void FullCodeGenerator::PrepareForBailoutForId(int id, State state) {
}
void FullCodeGenerator::RecordStackCheck(int ast_id) {
void FullCodeGenerator::RecordStackCheck(unsigned ast_id) {
// The pc offset does not need to be encoded and packed together with a
// state.
BailoutEntry entry = { ast_id, masm_->pc_offset() };
ASSERT(masm_->pc_offset() > 0);
BailoutEntry entry = { ast_id, static_cast<unsigned>(masm_->pc_offset()) };
stack_checks_.Add(entry);
}
@ -412,27 +412,24 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
__ push(reg);
codegen()->increment_stack_height();
}
void FullCodeGenerator::TestContext::Plug(Register reg) const {
// For simplicity we always test the accumulator register.
__ Move(result_register(), reg);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
codegen()->DoTest(this);
}
void FullCodeGenerator::EffectContext::PlugTOS() const {
__ Drop(1);
codegen()->decrement_stack_height();
}
void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
__ pop(result_register());
codegen()->decrement_stack_height();
}
@ -443,8 +440,7 @@ void FullCodeGenerator::StackValueContext::PlugTOS() const {
void FullCodeGenerator::TestContext::PlugTOS() const {
// For simplicity we always test the accumulator register.
__ pop(result_register());
codegen()->decrement_stack_height();
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
codegen()->DoTest(this);
}
@ -523,8 +519,8 @@ void FullCodeGenerator::VisitDeclarations(
if (var->IsUnallocated()) {
array->set(j++, *(var->name()));
if (decl->fun() == NULL) {
if (var->mode() == Variable::CONST) {
// In case this is const property use the hole.
if (var->binding_needs_init()) {
// In case this binding needs initialization use the hole.
array->set_the_hole(j++);
} else {
array->set_undefined(j++);
@ -549,11 +545,10 @@ void FullCodeGenerator::VisitDeclarations(
int FullCodeGenerator::DeclareGlobalsFlags() {
int flags = 0;
if (is_eval()) flags |= kDeclareGlobalsEvalFlag;
if (is_strict_mode()) flags |= kDeclareGlobalsStrictModeFlag;
if (is_native()) flags |= kDeclareGlobalsNativeFlag;
return flags;
ASSERT(DeclareGlobalsLanguageMode::is_valid(language_mode()));
return DeclareGlobalsEvalFlag::encode(is_eval()) |
DeclareGlobalsNativeFlag::encode(is_native()) |
DeclareGlobalsLanguageMode::encode(language_mode());
}
@ -659,14 +654,13 @@ FullCodeGenerator::InlineFunctionGenerator
}
void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments();
const Runtime::Function* function = node->function();
void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
const Runtime::Function* function = expr->function();
ASSERT(function != NULL);
ASSERT(function->intrinsic_type == Runtime::INLINE);
InlineFunctionGenerator generator =
FindInlineFunctionGenerator(function->function_id);
((*this).*(generator))(args);
((*this).*(generator))(expr);
}
@ -683,11 +677,25 @@ void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
}
void FullCodeGenerator::VisitInDuplicateContext(Expression* expr) {
if (context()->IsEffect()) {
VisitForEffect(expr);
} else if (context()->IsAccumulatorValue()) {
VisitForAccumulatorValue(expr);
} else if (context()->IsStackValue()) {
VisitForStackValue(expr);
} else if (context()->IsTest()) {
const TestContext* test = TestContext::cast(context());
VisitForControl(expr, test->true_label(), test->false_label(),
test->fall_through());
}
}
void FullCodeGenerator::VisitComma(BinaryOperation* expr) {
Comment cmnt(masm_, "[ Comma");
VisitForEffect(expr->left());
if (context()->IsTest()) ForwardBailoutToChild(expr);
VisitInCurrentContext(expr->right());
VisitInDuplicateContext(expr->right());
}
@ -709,7 +717,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
}
PrepareForBailoutForId(right_id, NO_REGISTERS);
__ bind(&eval_right);
ForwardBailoutToChild(expr);
} else if (context()->IsAccumulatorValue()) {
VisitForAccumulatorValue(left);
@ -717,7 +724,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
// case we need it.
__ push(result_register());
Label discard, restore;
PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
if (is_logical_and) {
DoTest(left, &discard, &restore, &restore);
} else {
@ -736,7 +742,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
// case we need it.
__ push(result_register());
Label discard;
PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
if (is_logical_and) {
DoTest(left, &discard, &done, &discard);
} else {
@ -758,7 +763,7 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
__ bind(&eval_right);
}
VisitInCurrentContext(right);
VisitInDuplicateContext(right);
__ bind(&done);
}
@ -785,34 +790,6 @@ void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
}
void FullCodeGenerator::ForwardBailoutToChild(Expression* expr) {
if (!info_->HasDeoptimizationSupport()) return;
ASSERT(context()->IsTest());
ASSERT(expr == forward_bailout_stack_->expr());
forward_bailout_pending_ = forward_bailout_stack_;
}
void FullCodeGenerator::VisitInCurrentContext(Expression* expr) {
if (context()->IsTest()) {
ForwardBailoutStack stack(expr, forward_bailout_pending_);
ForwardBailoutStack* saved = forward_bailout_stack_;
forward_bailout_pending_ = NULL;
forward_bailout_stack_ = &stack;
Visit(expr);
forward_bailout_stack_ = saved;
} else {
ASSERT(forward_bailout_pending_ == NULL);
Visit(expr);
State state = context()->IsAccumulatorValue() ? TOS_REG : NO_REGISTERS;
PrepareForBailout(expr, state);
// Forwarding bailouts to children is a one shot operation. It should have
// been processed at this point.
ASSERT(forward_bailout_pending_ == NULL);
}
}
void FullCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
NestedBlock nested_block(this, stmt);
@ -823,9 +800,18 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
if (stmt->block_scope() != NULL) {
{ Comment cmnt(masm_, "[ Extend block context");
scope_ = stmt->block_scope();
__ Push(scope_->GetSerializedScopeInfo());
Handle<ScopeInfo> scope_info = scope_->GetScopeInfo();
int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS;
__ Push(scope_info);
PushFunctionArgumentForContextAllocation();
__ CallRuntime(Runtime::kPushBlockContext, 2);
if (heap_slots <= FastNewBlockContextStub::kMaximumSlots) {
FastNewBlockContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kPushBlockContext, 2);
}
// Replace the context stored in the frame.
StoreToFrameField(StandardFrameConstants::kContextOffset,
context_register());
}
@ -972,7 +958,6 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
VisitForStackValue(stmt->expression());
PushFunctionArgumentForContextAllocation();
__ CallRuntime(Runtime::kPushWithContext, 2);
decrement_stack_height();
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
{ WithOrCatch body(this);
@ -1103,20 +1088,17 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
Comment cmnt(masm_, "[ TryCatchStatement");
SetStatementPosition(stmt);
// The try block adds a handler to the exception handler chain
// before entering, and removes it again when exiting normally.
// If an exception is thrown during execution of the try block,
// control is passed to the handler, which also consumes the handler.
// At this point, the exception is in a register, and store it in
// the temporary local variable (prints as ".catch-var") before
// executing the catch block. The catch block has been rewritten
// to introduce a new scope to bind the catch variable and to remove
// that scope again afterwards.
Label try_handler_setup, done;
__ Call(&try_handler_setup);
// Try handler code, exception in result register.
// The try block adds a handler to the exception handler chain before
// entering, and removes it again when exiting normally. If an exception
// is thrown during execution of the try block, the handler is consumed
// and control is passed to the catch block with the exception in the
// result register.
Label try_entry, handler_entry, exit;
__ jmp(&try_entry);
__ bind(&handler_entry);
handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
// Exception handler code, the exception is in the result register.
// Extend the context before executing the catch block.
{ Comment cmnt(masm_, "[ Extend catch context");
__ Push(stmt->variable()->name());
@ -1130,27 +1112,23 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
Scope* saved_scope = scope();
scope_ = stmt->scope();
ASSERT(scope_->declarations()->is_empty());
{ WithOrCatch body(this);
{ WithOrCatch catch_body(this);
Visit(stmt->catch_block());
}
// Restore the context.
LoadContextField(context_register(), Context::PREVIOUS_INDEX);
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
scope_ = saved_scope;
__ jmp(&done);
__ jmp(&exit);
// Try block code. Sets up the exception handler chain.
__ bind(&try_handler_setup);
{
const int delta = StackHandlerConstants::kSize / kPointerSize;
TryCatch try_block(this);
__ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
increment_stack_height(delta);
__ bind(&try_entry);
__ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER, stmt->index());
{ TryCatch try_body(this);
Visit(stmt->try_block());
__ PopTryHandler();
decrement_stack_height(delta);
}
__ bind(&done);
__ PopTryHandler();
__ bind(&exit);
}
@ -1162,12 +1140,12 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
//
// The try-finally construct can enter the finally block in three ways:
// 1. By exiting the try-block normally. This removes the try-handler and
// calls the finally block code before continuing.
// calls the finally block code before continuing.
// 2. By exiting the try-block with a function-local control flow transfer
// (break/continue/return). The site of the, e.g., break removes the
// try handler and calls the finally block code before continuing
// its outward control transfer.
// 3. by exiting the try-block with a thrown exception.
// 3. By exiting the try-block with a thrown exception.
// This can happen in nested function calls. It traverses the try-handler
// chain and consumes the try-handler entry before jumping to the
// handler code. The handler code then calls the finally-block before
@ -1178,49 +1156,39 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
// exception) in the result register (rax/eax/r0), both of which must
// be preserved. The return address isn't GC-safe, so it should be
// cooked before GC.
Label finally_entry;
Label try_handler_setup;
const int original_stack_height = stack_height();
// Setup the try-handler chain. Use a call to
// Jump to try-handler setup and try-block code. Use call to put try-handler
// address on stack.
__ Call(&try_handler_setup);
// Try handler code. Return address of call is pushed on handler stack.
{
// This code is only executed during stack-handler traversal when an
// exception is thrown. The exception is in the result register, which
// is retained by the finally block.
// Call the finally block and then rethrow the exception if it returns.
__ Call(&finally_entry);
__ push(result_register());
__ CallRuntime(Runtime::kReThrow, 1);
}
Label try_entry, handler_entry, finally_entry;
// Jump to try-handler setup and try-block code.
__ jmp(&try_entry);
__ bind(&handler_entry);
handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
// Exception handler code. This code is only executed when an exception
// is thrown. The exception is in the result register, and must be
// preserved by the finally block. Call the finally block and then
// rethrow the exception if it returns.
__ Call(&finally_entry);
__ push(result_register());
__ CallRuntime(Runtime::kReThrow, 1);
// Finally block implementation.
__ bind(&finally_entry);
{
// Finally block implementation.
Finally finally_block(this);
EnterFinallyBlock();
set_stack_height(original_stack_height + Finally::kElementCount);
EnterFinallyBlock();
{ Finally finally_body(this);
Visit(stmt->finally_block());
ExitFinallyBlock(); // Return to the calling code.
}
ExitFinallyBlock(); // Return to the calling code.
__ bind(&try_handler_setup);
{
// Setup try handler (stack pointer registers).
const int delta = StackHandlerConstants::kSize / kPointerSize;
TryFinally try_block(this, &finally_entry);
__ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
set_stack_height(original_stack_height + delta);
// Setup try handler.
__ bind(&try_entry);
__ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER, stmt->index());
{ TryFinally try_body(this, &finally_entry);
Visit(stmt->try_block());
__ PopTryHandler();
set_stack_height(original_stack_height);
}
__ PopTryHandler();
// Execute the finally block on the way out. Clobber the unpredictable
// value in the accumulator with one that's safe for GC. The finally
// block will unconditionally preserve the accumulator on the stack.
// value in the result register with one that's safe for GC because the
// finally block will unconditionally preserve the result register on the
// stack.
ClearAccumulator();
__ Call(&finally_entry);
}
@ -1246,7 +1214,6 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
__ bind(&true_case);
SetExpressionPosition(expr->then_expression(),
expr->then_expression_position());
int start_stack_height = stack_height();
if (context()->IsTest()) {
const TestContext* for_test = TestContext::cast(context());
VisitForControl(expr->then_expression(),
@ -1254,17 +1221,15 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
for_test->false_label(),
NULL);
} else {
VisitInCurrentContext(expr->then_expression());
VisitInDuplicateContext(expr->then_expression());
__ jmp(&done);
}
PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS);
__ bind(&false_case);
set_stack_height(start_stack_height);
if (context()->IsTest()) ForwardBailoutToChild(expr);
SetExpressionPosition(expr->else_expression(),
expr->else_expression_position());
VisitInCurrentContext(expr->else_expression());
VisitInDuplicateContext(expr->else_expression());
// If control flow falls through Visit, merge it with true case here.
if (!context()->IsTest()) {
__ bind(&done);
@ -1301,11 +1266,8 @@ void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
void FullCodeGenerator::VisitThrow(Throw* expr) {
Comment cmnt(masm_, "[ Throw");
// Throw has no effect on the stack height or the current expression context.
// Usually the expression context is null, because throw is a statement.
VisitForStackValue(expr->exception());
__ CallRuntime(Runtime::kThrow, 1);
decrement_stack_height();
// Never returns here.
}
@ -1321,19 +1283,21 @@ FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit(
}
bool FullCodeGenerator::TryLiteralCompare(CompareOperation* compare,
Label* if_true,
Label* if_false,
Label* fall_through) {
Expression *expr;
bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) {
Expression *sub_expr;
Handle<String> check;
if (compare->IsLiteralCompareTypeof(&expr, &check)) {
EmitLiteralCompareTypeof(expr, check, if_true, if_false, fall_through);
if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
EmitLiteralCompareTypeof(expr, sub_expr, check);
return true;
}
if (expr->IsLiteralCompareUndefined(&sub_expr)) {
EmitLiteralCompareNil(expr, sub_expr, kUndefinedValue);
return true;
}
if (compare->IsLiteralCompareUndefined(&expr)) {
EmitLiteralCompareUndefined(expr, if_true, if_false, fall_through);
if (expr->IsLiteralCompareNull(&sub_expr)) {
EmitLiteralCompareNil(expr, sub_expr, kNullValue);
return true;
}

152
deps/v8/src/full-codegen.h

@ -83,12 +83,9 @@ class FullCodeGenerator: public AstVisitor {
scope_(NULL),
nesting_stack_(NULL),
loop_depth_(0),
stack_height_(0),
context_(NULL),
bailout_entries_(0),
stack_checks_(2), // There's always at least one.
forward_bailout_stack_(NULL),
forward_bailout_pending_(NULL) {
stack_checks_(2) { // There's always at least one.
}
static bool MakeCode(CompilationInfo* info);
@ -96,6 +93,8 @@ class FullCodeGenerator: public AstVisitor {
void Generate(CompilationInfo* info);
void PopulateDeoptimizationData(Handle<Code> code);
Handle<FixedArray> handler_table() { return handler_table_; }
class StateField : public BitField<State, 0, 8> { };
class PcField : public BitField<unsigned, 8, 32-8> { };
@ -276,27 +275,8 @@ class FullCodeGenerator: public AstVisitor {
}
};
// The forward bailout stack keeps track of the expressions that can
// bail out to just before the control flow is split in a child
// node. The stack elements are linked together through the parent
// link when visiting expressions in test contexts after requesting
// bailout in child forwarding.
class ForwardBailoutStack BASE_EMBEDDED {
public:
ForwardBailoutStack(Expression* expr, ForwardBailoutStack* parent)
: expr_(expr), parent_(parent) { }
Expression* expr() const { return expr_; }
ForwardBailoutStack* parent() const { return parent_; }
private:
Expression* const expr_;
ForwardBailoutStack* const parent_;
};
// Type of a member function that generates inline code for a native function.
typedef void (FullCodeGenerator::*InlineFunctionGenerator)
(ZoneList<Expression*>*);
typedef void (FullCodeGenerator::*InlineFunctionGenerator)(CallRuntime* expr);
static const InlineFunctionGenerator kInlineFunctionGenerators[];
@ -357,23 +337,22 @@ class FullCodeGenerator: public AstVisitor {
// need the write barrier if location is CONTEXT.
MemOperand VarOperand(Variable* var, Register scratch);
// Forward the bailout responsibility for the given expression to
// the next child visited (which must be in a test context).
void ForwardBailoutToChild(Expression* expr);
void VisitForEffect(Expression* expr) {
EffectContext context(this);
VisitInCurrentContext(expr);
Visit(expr);
PrepareForBailout(expr, NO_REGISTERS);
}
void VisitForAccumulatorValue(Expression* expr) {
AccumulatorValueContext context(this);
VisitInCurrentContext(expr);
Visit(expr);
PrepareForBailout(expr, TOS_REG);
}
void VisitForStackValue(Expression* expr) {
StackValueContext context(this);
VisitInCurrentContext(expr);
Visit(expr);
PrepareForBailout(expr, NO_REGISTERS);
}
void VisitForControl(Expression* expr,
@ -381,9 +360,14 @@ class FullCodeGenerator: public AstVisitor {
Label* if_false,
Label* fall_through) {
TestContext context(this, expr, if_true, if_false, fall_through);
VisitInCurrentContext(expr);
Visit(expr);
// For test contexts, we prepare for bailout before branching, not at
// the end of the entire expression. This happens as part of visiting
// the expression.
}
void VisitInDuplicateContext(Expression* expr);
void VisitDeclarations(ZoneList<Declaration*>* declarations);
void DeclareGlobals(Handle<FixedArray> pairs);
int DeclareGlobalsFlags();
@ -391,29 +375,22 @@ class FullCodeGenerator: public AstVisitor {
// Try to perform a comparison as a fast inlined literal compare if
// the operands allow it. Returns true if the compare operations
// has been matched and all code generated; false otherwise.
bool TryLiteralCompare(CompareOperation* compare,
Label* if_true,
Label* if_false,
Label* fall_through);
bool TryLiteralCompare(CompareOperation* compare);
// Platform-specific code for comparing the type of a value with
// a given literal string.
void EmitLiteralCompareTypeof(Expression* expr,
Handle<String> check,
Label* if_true,
Label* if_false,
Label* fall_through);
// Platform-specific code for strict equality comparison with
// the undefined value.
void EmitLiteralCompareUndefined(Expression* expr,
Label* if_true,
Label* if_false,
Label* fall_through);
Expression* sub_expr,
Handle<String> check);
// Platform-specific code for equality comparison with a nil-like value.
void EmitLiteralCompareNil(CompareOperation* expr,
Expression* sub_expr,
NilValue nil);
// Bailout support.
void PrepareForBailout(Expression* node, State state);
void PrepareForBailoutForId(int id, State state);
void PrepareForBailoutForId(unsigned id, State state);
// Record a call's return site offset, used to rebuild the frame if the
// called function was inlined at the site.
@ -424,7 +401,7 @@ class FullCodeGenerator: public AstVisitor {
// canonical JS true value so we will insert a (dead) test against true at
// the actual bailout target from the optimized code. If not
// should_normalize, the true and false labels are ignored.
void PrepareForBailoutBeforeSplit(State state,
void PrepareForBailoutBeforeSplit(Expression* expr,
bool should_normalize,
Label* if_true,
Label* if_false);
@ -432,7 +409,7 @@ class FullCodeGenerator: public AstVisitor {
// Platform-specific code for a variable, constant, or function
// declaration. Functions have an initial value.
void EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
VariableMode mode,
FunctionLiteral* function,
int* global_count);
@ -440,7 +417,7 @@ class FullCodeGenerator: public AstVisitor {
// a loop.
void EmitStackCheck(IterationStatement* stmt);
// Record the OSR AST id corresponding to a stack check in the code.
void RecordStackCheck(int osr_ast_id);
void RecordStackCheck(unsigned osr_ast_id);
// Emit a table of stack check ids and pcs into the code stream. Return
// the offset of the start of the table.
unsigned EmitStackCheckTable();
@ -459,7 +436,7 @@ class FullCodeGenerator: public AstVisitor {
void EmitInlineRuntimeCall(CallRuntime* expr);
#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
void Emit##name(ZoneList<Expression*>* arguments);
void Emit##name(CallRuntime* expr);
INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
#undef EMIT_INLINE_RUNTIME_CALL
@ -475,13 +452,8 @@ class FullCodeGenerator: public AstVisitor {
Label* done);
void EmitVariableLoad(VariableProxy* proxy);
enum ResolveEvalFlag {
SKIP_CONTEXT_LOOKUP,
PERFORM_CONTEXT_LOOKUP
};
// Expects the arguments and the function already pushed.
void EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, int arg_count);
void EmitResolvePossiblyDirectEval(int arg_count);
// Platform-specific support for allocating a new closure based on
// the given function info.
@ -548,35 +520,6 @@ class FullCodeGenerator: public AstVisitor {
loop_depth_--;
}
#if defined(V8_TARGET_ARCH_IA32)
int stack_height() { return stack_height_; }
void set_stack_height(int depth) { stack_height_ = depth; }
void increment_stack_height() { stack_height_++; }
void increment_stack_height(int delta) { stack_height_ += delta; }
void decrement_stack_height() {
if (FLAG_verify_stack_height) {
ASSERT(stack_height_ > 0);
}
stack_height_--;
}
void decrement_stack_height(int delta) {
stack_height_-= delta;
if (FLAG_verify_stack_height) {
ASSERT(stack_height_ >= 0);
}
}
// Call this function only if FLAG_verify_stack_height is true.
void verify_stack_height(); // Generates a runtime check of esp - ebp.
#else
int stack_height() { return 0; }
void set_stack_height(int depth) {}
void increment_stack_height() {}
void increment_stack_height(int delta) {}
void decrement_stack_height() {}
void decrement_stack_height(int delta) {}
void verify_stack_height() {}
#endif // V8_TARGET_ARCH_IA32
MacroAssembler* masm() { return masm_; }
class ExpressionContext;
@ -586,9 +529,11 @@ class FullCodeGenerator: public AstVisitor {
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
bool is_native() { return info_->is_native(); }
bool is_strict_mode() { return function()->strict_mode(); }
StrictModeFlag strict_mode_flag() {
return is_strict_mode() ? kStrictMode : kNonStrictMode;
bool is_classic_mode() {
return language_mode() == CLASSIC_MODE;
}
LanguageMode language_mode() {
return function()->language_mode();
}
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return scope_; }
@ -618,7 +563,6 @@ class FullCodeGenerator: public AstVisitor {
void VisitComma(BinaryOperation* expr);
void VisitLogicalExpression(BinaryOperation* expr);
void VisitArithmeticExpression(BinaryOperation* expr);
void VisitInCurrentContext(Expression* expr);
void VisitForTypeofValue(Expression* expr);
@ -637,10 +581,6 @@ class FullCodeGenerator: public AstVisitor {
virtual ~ExpressionContext() {
codegen_->set_new_context(old_);
if (FLAG_verify_stack_height) {
ASSERT_EQ(expected_stack_height_, codegen()->stack_height());
codegen()->verify_stack_height();
}
}
Isolate* isolate() const { return codegen_->isolate(); }
@ -694,7 +634,6 @@ class FullCodeGenerator: public AstVisitor {
FullCodeGenerator* codegen() const { return codegen_; }
MacroAssembler* masm() const { return masm_; }
MacroAssembler* masm_;
int expected_stack_height_; // The expected stack height esp - ebp on exit.
private:
const ExpressionContext* old_;
@ -704,9 +643,7 @@ class FullCodeGenerator: public AstVisitor {
class AccumulatorValueContext : public ExpressionContext {
public:
explicit AccumulatorValueContext(FullCodeGenerator* codegen)
: ExpressionContext(codegen) {
expected_stack_height_ = codegen->stack_height();
}
: ExpressionContext(codegen) { }
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
@ -727,9 +664,7 @@ class FullCodeGenerator: public AstVisitor {
class StackValueContext : public ExpressionContext {
public:
explicit StackValueContext(FullCodeGenerator* codegen)
: ExpressionContext(codegen) {
expected_stack_height_ = codegen->stack_height() + 1;
}
: ExpressionContext(codegen) { }
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
@ -758,9 +693,7 @@ class FullCodeGenerator: public AstVisitor {
condition_(condition),
true_label_(true_label),
false_label_(false_label),
fall_through_(fall_through) {
expected_stack_height_ = codegen->stack_height();
}
fall_through_(fall_through) { }
static const TestContext* cast(const ExpressionContext* context) {
ASSERT(context->IsTest());
@ -797,10 +730,7 @@ class FullCodeGenerator: public AstVisitor {
class EffectContext : public ExpressionContext {
public:
explicit EffectContext(FullCodeGenerator* codegen)
: ExpressionContext(codegen) {
expected_stack_height_ = codegen->stack_height();
}
: ExpressionContext(codegen) { }
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
@ -824,12 +754,10 @@ class FullCodeGenerator: public AstVisitor {
Label return_label_;
NestedStatement* nesting_stack_;
int loop_depth_;
int stack_height_;
const ExpressionContext* context_;
ZoneList<BailoutEntry> bailout_entries_;
ZoneList<BailoutEntry> stack_checks_;
ForwardBailoutStack* forward_bailout_stack_;
ForwardBailoutStack* forward_bailout_pending_;
Handle<FixedArray> handler_table_;
friend class NestedStatement;

6
deps/v8/src/gdb-jit.cc

@ -1115,13 +1115,13 @@ class DebugInfoSection : public DebugSection {
int context_slots = scope_info.number_of_context_slots();
// The real slot ID is internal_slots + context_slot_id.
int internal_slots = Context::MIN_CONTEXT_SLOTS;
int locals = scope_info.NumberOfLocals();
int locals = scope_info.LocalCount();
int current_abbreviation = 4;
for (int param = 0; param < params; ++param) {
w->WriteULEB128(current_abbreviation++);
w->WriteString(
*scope_info.parameter_name(param)->ToCString(DISALLOW_NULLS));
*scope_info.ParameterName(param)->ToCString(DISALLOW_NULLS));
w->Write<uint32_t>(ty_offset);
Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>();
uintptr_t block_start = w->position();
@ -1312,7 +1312,7 @@ class DebugAbbrevSection : public DebugSection {
int context_slots = scope_info.number_of_context_slots();
// The real slot ID is internal_slots + context_slot_id.
int internal_slots = Context::MIN_CONTEXT_SLOTS;
int locals = scope_info.NumberOfLocals();
int locals = scope_info.LocalCount();
int total_children =
params + slots + context_slots + internal_slots + locals + 2;

42
deps/v8/src/globals.h

@ -230,6 +230,9 @@ const int kPointerSize = sizeof(void*); // NOLINT
const int kDoubleSizeLog2 = 3;
// Size of the state of a the random number generator.
const int kRandomStateSize = 2 * kIntSize;
#if V8_HOST_ARCH_64_BIT
const int kPointerSizeLog2 = 3;
const intptr_t kIntptrSignBit = V8_INT64_C(0x8000000000000000);
@ -255,6 +258,10 @@ const int kBinary32MinExponent = 0x01;
const int kBinary32MantissaBits = 23;
const int kBinary32ExponentShift = 23;
// Quiet NaNs have bits 51 to 62 set, possibly the sign bit, and no
// other bits set.
const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
// ASCII/UC16 constants
// Code-point values in Unicode 4.0 are 21 bits wide.
typedef uint16_t uc16;
@ -287,7 +294,7 @@ const uint32_t kMaxAsciiCharCodeU = 0x7fu;
// The USE(x) template is used to silence C++ compiler warnings
// issued for (yet) unused variables (typically parameters).
template <typename T>
static inline void USE(T) { }
inline void USE(T) { }
// FUNCTION_ADDR(f) gets the address of a C function f.
@ -351,6 +358,39 @@ F FUNCTION_CAST(Address addr) {
class FreeStoreAllocationPolicy;
template <typename T, class P = FreeStoreAllocationPolicy> class List;
// -----------------------------------------------------------------------------
// Declarations for use in both the preparser and the rest of V8.
// The different language modes that V8 implements. ES5 defines two language
// modes: an unrestricted mode respectively a strict mode which are indicated by
// CLASSIC_MODE respectively STRICT_MODE in the enum. The harmony spec drafts
// for the next ES standard specify a new third mode which is called 'extended
// mode'. The extended mode is only available if the harmony flag is set. It is
// based on the 'strict mode' and adds new functionality to it. This means that
// most of the semantics of these two modes coincide.
//
// In the current draft the term 'base code' is used to refer to code that is
// neither in strict nor extended mode. However, the more distinguishing term
// 'classic mode' is used in V8 instead to avoid mix-ups.
enum LanguageMode {
CLASSIC_MODE,
STRICT_MODE,
EXTENDED_MODE
};
// The Strict Mode (ECMA-262 5th edition, 4.2.2).
//
// This flag is used in the backend to represent the language mode. So far
// there is no semantic difference between the strict and the extended mode in
// the backend, so both modes are represented by the kStrictMode value.
enum StrictModeFlag {
kNonStrictMode,
kStrictMode
};
} } // namespace v8::internal
#endif // V8_GLOBALS_H_

156
deps/v8/src/handles.cc

@ -190,7 +190,11 @@ static int ExpectedNofPropertiesFromEstimate(int estimate) {
// Inobject slack tracking will reclaim redundant inobject space later,
// so we can afford to adjust the estimate generously.
return estimate + 8;
if (FLAG_clever_optimizations) {
return estimate + 8;
} else {
return estimate + 3;
}
}
@ -372,24 +376,6 @@ Handle<Object> GetProperty(Handle<Object> obj,
}
Handle<Object> GetProperty(Handle<JSReceiver> obj,
Handle<String> name,
LookupResult* result) {
PropertyAttributes attributes;
Isolate* isolate = Isolate::Current();
CALL_HEAP_FUNCTION(isolate,
obj->GetProperty(*obj, result, *name, &attributes),
Object);
}
Handle<Object> GetElement(Handle<Object> obj,
uint32_t index) {
Isolate* isolate = Isolate::Current();
CALL_HEAP_FUNCTION(isolate, Runtime::GetElement(obj, index), Object);
}
Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<String> name,
@ -421,17 +407,18 @@ Handle<Object> PreventExtensions(Handle<JSObject> object) {
}
Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
JSObject::HiddenPropertiesFlag flag) {
Handle<Object> SetHiddenProperty(Handle<JSObject> obj,
Handle<String> key,
Handle<Object> value) {
CALL_HEAP_FUNCTION(obj->GetIsolate(),
obj->GetHiddenProperties(flag),
obj->SetHiddenProperty(*key, *value),
Object);
}
int GetIdentityHash(Handle<JSObject> obj) {
int GetIdentityHash(Handle<JSReceiver> obj) {
CALL_AND_RETRY(obj->GetIsolate(),
obj->GetIdentityHash(JSObject::ALLOW_CREATION),
obj->GetIdentityHash(ALLOW_CREATION),
return Smi::cast(__object__)->value(),
return 0);
}
@ -499,6 +486,14 @@ Handle<Object> SetOwnElement(Handle<JSObject> object,
}
Handle<Object> TransitionElementsKind(Handle<JSObject> object,
ElementsKind to_kind) {
CALL_HEAP_FUNCTION(object->GetIsolate(),
object->TransitionElementsKind(to_kind),
Object);
}
Handle<JSObject> Copy(Handle<JSObject> obj) {
Isolate* isolate = obj->GetIsolate();
CALL_HEAP_FUNCTION(isolate,
@ -521,8 +516,9 @@ static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
Handle<Object> cache = Utils::OpenHandle(*handle);
JSValue* wrapper = JSValue::cast(*cache);
Foreign* foreign = Script::cast(wrapper->value())->wrapper();
ASSERT(foreign->address() == reinterpret_cast<Address>(cache.location()));
foreign->set_address(0);
ASSERT(foreign->foreign_address() ==
reinterpret_cast<Address>(cache.location()));
foreign->set_foreign_address(0);
Isolate* isolate = Isolate::Current();
isolate->global_handles()->Destroy(cache.location());
isolate->counters()->script_wrappers()->Decrement();
@ -530,10 +526,10 @@ static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
if (script->wrapper()->address() != NULL) {
if (script->wrapper()->foreign_address() != NULL) {
// Return the script wrapper directly from the cache.
return Handle<JSValue>(
reinterpret_cast<JSValue**>(script->wrapper()->address()));
reinterpret_cast<JSValue**>(script->wrapper()->foreign_address()));
}
Isolate* isolate = Isolate::Current();
// Construct a new script wrapper.
@ -549,7 +545,8 @@ Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
Handle<Object> handle = isolate->global_handles()->Create(*result);
isolate->global_handles()->MakeWeak(handle.location(), NULL,
&ClearWrapperCache);
script->wrapper()->set_address(reinterpret_cast<Address>(handle.location()));
script->wrapper()->set_foreign_address(
reinterpret_cast<Address>(handle.location()));
return result;
}
@ -665,6 +662,19 @@ int GetScriptLineNumber(Handle<Script> script, int code_pos) {
return right + script->line_offset()->value();
}
// Convert code position into column number.
int GetScriptColumnNumber(Handle<Script> script, int code_pos) {
int line_number = GetScriptLineNumber(script, code_pos);
if (line_number == -1) return -1;
AssertNoAllocation no_allocation;
FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
line_number = line_number - script->line_offset()->value();
if (line_number == 0) return code_pos + script->column_offset()->value();
int prev_line_end_pos =
Smi::cast(line_ends_array->get(line_number - 1))->value();
return code_pos - (prev_line_end_pos + 1);
}
int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
AssertNoAllocation no_allocation;
@ -696,7 +706,7 @@ void CustomArguments::IterateInstance(ObjectVisitor* v) {
// Compute the property keys from the interceptor.
v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver,
Handle<JSObject> object) {
Isolate* isolate = receiver->GetIsolate();
Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
@ -718,7 +728,7 @@ v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
// Compute the element keys from the interceptor.
v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver,
Handle<JSObject> object) {
Isolate* isolate = receiver->GetIsolate();
Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
@ -749,8 +759,9 @@ static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
}
Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
KeyCollectionType type) {
Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSReceiver> object,
KeyCollectionType type,
bool* threw) {
USE(ContainsOnlyValidKeys);
Isolate* isolate = object->GetIsolate();
Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
@ -765,6 +776,16 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
for (Handle<Object> p = object;
*p != isolate->heap()->null_value();
p = Handle<Object>(p->GetPrototype(), isolate)) {
if (p->IsJSProxy()) {
Handle<JSProxy> proxy(JSProxy::cast(*p), isolate);
Handle<Object> args[] = { proxy };
Handle<Object> names = Execution::Call(
isolate->proxy_enumerate(), object, ARRAY_SIZE(args), args, threw);
if (*threw) return content;
content = AddKeysFromJSArray(content, Handle<JSArray>::cast(names));
break;
}
Handle<JSObject> current(JSObject::cast(*p), isolate);
// Check access rights if required.
@ -831,11 +852,11 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
}
Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw) {
Isolate* isolate = object->GetIsolate();
isolate->counters()->for_in()->Increment();
Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
INCLUDE_PROTOS);
Handle<FixedArray> elements =
GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, threw);
return isolate->factory()->NewJSArrayWithElements(elements);
}
@ -885,62 +906,29 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
}
Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
Handle<JSObject> key,
Handle<Object> value) {
Handle<ObjectHashSet> ObjectHashSetAdd(Handle<ObjectHashSet> table,
Handle<Object> key) {
CALL_HEAP_FUNCTION(table->GetIsolate(),
table->Put(*key, *value),
ObjectHashTable);
}
bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
ClearExceptionFlag flag) {
return shared->is_compiled() || CompileLazyShared(shared, flag);
}
static bool CompileLazyHelper(CompilationInfo* info,
ClearExceptionFlag flag) {
// Compile the source information to a code object.
ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
ASSERT(!info->isolate()->has_pending_exception());
bool result = Compiler::CompileLazy(info);
ASSERT(result != Isolate::Current()->has_pending_exception());
if (!result && flag == CLEAR_EXCEPTION) {
info->isolate()->clear_pending_exception();
}
return result;
table->Add(*key),
ObjectHashSet);
}
bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
ClearExceptionFlag flag) {
CompilationInfo info(shared);
return CompileLazyHelper(&info, flag);
Handle<ObjectHashSet> ObjectHashSetRemove(Handle<ObjectHashSet> table,
Handle<Object> key) {
CALL_HEAP_FUNCTION(table->GetIsolate(),
table->Remove(*key),
ObjectHashSet);
}
bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) {
bool result = true;
if (function->shared()->is_compiled()) {
function->ReplaceCode(function->shared()->code());
function->shared()->set_code_age(0);
} else {
CompilationInfo info(function);
result = CompileLazyHelper(&info, flag);
ASSERT(!result || function->is_compiled());
}
return result;
Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
Handle<Object> key,
Handle<Object> value) {
CALL_HEAP_FUNCTION(table->GetIsolate(),
table->Put(*key, *value),
ObjectHashTable);
}
bool CompileOptimized(Handle<JSFunction> function,
int osr_ast_id,
ClearExceptionFlag flag) {
CompilationInfo info(function);
info.SetOptimizing(osr_ast_id);
return CompileLazyHelper(&info, flag);
}
} } // namespace v8::internal

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save