Browse Source

v8: upgrade to v3.20.2

v0.11.4-release
Ben Noordhuis 12 years ago
parent
commit
704fd8f374
  1. 1
      deps/v8/.gitignore
  2. 89
      deps/v8/ChangeLog
  3. 5
      deps/v8/DEPS
  4. 16
      deps/v8/Makefile
  5. 1
      deps/v8/OWNERS
  6. 7
      deps/v8/build/android.gypi
  7. 58
      deps/v8/build/common.gypi
  8. 73
      deps/v8/build/shim_headers.gypi
  9. 51
      deps/v8/build/standalone.gypi
  10. 69
      deps/v8/include/v8-profiler.h
  11. 342
      deps/v8/include/v8.h
  12. 3
      deps/v8/preparser/preparser.gyp
  13. 3
      deps/v8/samples/samples.gyp
  14. 627
      deps/v8/src/api.cc
  15. 78
      deps/v8/src/api.h
  16. 14
      deps/v8/src/arguments.cc
  17. 29
      deps/v8/src/arm/assembler-arm-inl.h
  18. 2
      deps/v8/src/arm/assembler-arm.cc
  19. 431
      deps/v8/src/arm/builtins-arm.cc
  20. 353
      deps/v8/src/arm/code-stubs-arm.cc
  21. 1
      deps/v8/src/arm/code-stubs-arm.h
  22. 2
      deps/v8/src/arm/codegen-arm.cc
  23. 2
      deps/v8/src/arm/constants-arm.cc
  24. 2
      deps/v8/src/arm/cpu-arm.cc
  25. 2
      deps/v8/src/arm/debug-arm.cc
  26. 2
      deps/v8/src/arm/disasm-arm.cc
  27. 9
      deps/v8/src/arm/frames-arm.cc
  28. 220
      deps/v8/src/arm/full-codegen-arm.cc
  29. 9
      deps/v8/src/arm/ic-arm.cc
  30. 96
      deps/v8/src/arm/lithium-arm.cc
  31. 92
      deps/v8/src/arm/lithium-arm.h
  32. 491
      deps/v8/src/arm/lithium-codegen-arm.cc
  33. 22
      deps/v8/src/arm/lithium-codegen-arm.h
  34. 51
      deps/v8/src/arm/macro-assembler-arm.cc
  35. 4
      deps/v8/src/arm/macro-assembler-arm.h
  36. 3
      deps/v8/src/arm/regexp-macro-assembler-arm.cc
  37. 67
      deps/v8/src/arm/simulator-arm.cc
  38. 180
      deps/v8/src/arm/stub-cache-arm.cc
  39. 11
      deps/v8/src/arraybuffer.js
  40. 10
      deps/v8/src/assembler.cc
  41. 30
      deps/v8/src/assembler.h
  42. 29
      deps/v8/src/assert-scope.h
  43. 108
      deps/v8/src/ast.cc
  44. 113
      deps/v8/src/ast.h
  45. 10
      deps/v8/src/atomicops.h
  46. 249
      deps/v8/src/atomicops_internals_tsan.h
  47. 88
      deps/v8/src/bootstrapper.cc
  48. 63
      deps/v8/src/builtins.cc
  49. 7
      deps/v8/src/builtins.h
  50. 60
      deps/v8/src/code-stubs-hydrogen.cc
  51. 68
      deps/v8/src/code-stubs.cc
  52. 157
      deps/v8/src/code-stubs.h
  53. 3
      deps/v8/src/codegen.cc
  54. 13
      deps/v8/src/collection.js
  55. 113
      deps/v8/src/compiler.cc
  56. 95
      deps/v8/src/compiler.h
  57. 2
      deps/v8/src/contexts.h
  58. 21
      deps/v8/src/cpu-profiler-inl.h
  59. 364
      deps/v8/src/cpu-profiler.cc
  60. 77
      deps/v8/src/cpu-profiler.h
  61. 6
      deps/v8/src/d8-debug.cc
  62. 15
      deps/v8/src/d8-readline.cc
  63. 11
      deps/v8/src/d8.cc
  64. 3
      deps/v8/src/d8.gyp
  65. 2
      deps/v8/src/d8.js
  66. 2
      deps/v8/src/data-flow.h
  67. 45
      deps/v8/src/debug-debugger.js
  68. 104
      deps/v8/src/debug.cc
  69. 18
      deps/v8/src/debug.h
  70. 369
      deps/v8/src/deoptimizer.cc
  71. 34
      deps/v8/src/deoptimizer.h
  72. 2
      deps/v8/src/execution.h
  73. 331
      deps/v8/src/extensions/i18n/break-iterator.cc
  74. 85
      deps/v8/src/extensions/i18n/break-iterator.h
  75. 197
      deps/v8/src/extensions/i18n/break-iterator.js
  76. 363
      deps/v8/src/extensions/i18n/collator.cc
  77. 68
      deps/v8/src/extensions/i18n/collator.h
  78. 212
      deps/v8/src/extensions/i18n/collator.js
  79. 329
      deps/v8/src/extensions/i18n/date-format.cc
  80. 71
      deps/v8/src/extensions/i18n/date-format.h
  81. 478
      deps/v8/src/extensions/i18n/date-format.js
  82. 40
      deps/v8/src/extensions/i18n/footer.js
  83. 168
      deps/v8/src/extensions/i18n/globals.js
  84. 41
      deps/v8/src/extensions/i18n/header.js
  85. 116
      deps/v8/src/extensions/i18n/i18n-extension.cc
  86. 51
      deps/v8/src/extensions/i18n/i18n-extension.h
  87. 174
      deps/v8/src/extensions/i18n/i18n-utils.cc
  88. 91
      deps/v8/src/extensions/i18n/i18n-utils.h
  89. 541
      deps/v8/src/extensions/i18n/i18n-utils.js
  90. 248
      deps/v8/src/extensions/i18n/locale.cc
  91. 56
      deps/v8/src/extensions/i18n/locale.h
  92. 192
      deps/v8/src/extensions/i18n/locale.js
  93. 418
      deps/v8/src/extensions/i18n/number-format.cc
  94. 69
      deps/v8/src/extensions/i18n/number-format.h
  95. 295
      deps/v8/src/extensions/i18n/number-format.js
  96. 220
      deps/v8/src/extensions/i18n/overrides.js
  97. 6
      deps/v8/src/extensions/statistics-extension.cc
  98. 74
      deps/v8/src/factory.cc
  99. 11
      deps/v8/src/factory.h
  100. 22
      deps/v8/src/flag-definitions.h

1
deps/v8/.gitignore

@ -40,6 +40,7 @@ shell_g
/test/test262/data
/test/test262/test262-*
/test/test262/test262.status2
/test/webkit/webkit.status2
/third_party
/tools/jsfunfuzz
/tools/jsfunfuzz.zip

89
deps/v8/ChangeLog

@ -1,3 +1,92 @@
2013-07-05: Version 3.20.2
Remove deprecated heap profiler methods from V8 public API
Mark i18n functions as native and set proper names
(issue 2745)
Correctly report stack trace when current function is FunctionApply
builtin (Chromium issue 252097)
Enable GDBJIT interface for standalone by default.
Fix debuggersupport=off build. (issue 2754)
Introduce -m64 flag for making x64 when the default gcc compiler is for
X32
Performance and stability improvements on all platforms.
2013-07-02: Version 3.20.1
Implemented WeakMap.prototype.clear function. (issue 2753)
Ensure CheckInitialized is present independent of define.
(Chromium issue 255779)
Performance and stability improvements on all platforms.
2013-06-28: Version 3.20.0
Migrated several tests from blink to V8 repository.
Allowed users of the V8 API to distinguish between unset and undefined
HiddenValues (issue 2746).
Deprecated old style callbacks in the V8 API.
Turned on parallel recompilation.
Performance and stability improvements on all platforms.
2013-06-18: Version 3.19.18
Fixed read-only attribute of Function.length in strict mode.
(issue 2705)
Fixed Runtime_SetProperty to properly handle OOM failures
(Chromium issue 249873)
Emit deprecated check for constant function transitions.
(Chromium issue 250609)
Made MathFloorOfDiv optimization trigger more often
(Issue 2205)
Make more GCs in idle notification handler.
(Chromium issue 241815)
Increased default type info threshold.
(Issue 2730)
Performance and stability improvements on all platforms.
2013-06-14: Version 3.19.16
Performance and stability improvements on all platforms.
2013-06-13: Version 3.19.15
Performance and stability improvements on all platforms.
2013-06-13: Version 3.19.14
Fixed crashes when calling new Array(a) with a single argument that
could result in creating a holey array with a packed elements kind.
(Chromium issue 245480)
Fixed issues in parallel compilation.
(Chromium issue 248076)
Performance and stability improvements on all platforms.
2013-06-11: Version 3.19.13
Performance and stability improvements on all platforms.

5
deps/v8/DEPS

@ -5,7 +5,10 @@
deps = {
# Remember to keep the revision in sync with the Makefile.
"v8/build/gyp":
"http://gyp.googlecode.com/svn/trunk@1501",
"http://gyp.googlecode.com/svn/trunk@1656",
"v8/third_party/icu":
"https://src.chromium.org/chrome/trunk/deps/third_party/icu46@205936",
}
deps_os = {

16
deps/v8/Makefile

@ -35,7 +35,7 @@ GYPFLAGS ?=
TESTFLAGS ?=
ANDROID_NDK_ROOT ?=
ANDROID_TOOLCHAIN ?=
ANDROID_V8 ?= /data/local/v8
ANDROID_V8 ?= /data/local/tmp/v8
NACL_SDK_ROOT ?=
# Special build flags. Use them like this: "make library=shared"
@ -80,10 +80,13 @@ endif
ifeq ($(extrachecks), off)
GYPFLAGS += -Dv8_enable_extra_checks=0
endif
# gdbjit=on
# gdbjit=on/off
ifeq ($(gdbjit), on)
GYPFLAGS += -Dv8_enable_gdbjit=1
endif
ifeq ($(gdbjit), off)
GYPFLAGS += -Dv8_enable_gdbjit=0
endif
# vtunejit=on
ifeq ($(vtunejit), on)
GYPFLAGS += -Dv8_enable_vtunejit=1
@ -116,6 +119,10 @@ endif
ifeq ($(regexp), interpreted)
GYPFLAGS += -Dv8_interpreted_regexp=1
endif
# i18nsupport=on
ifeq ($(i18nsupport), on)
GYPFLAGS += -Dv8_enable_i18n_support=1
endif
# arm specific flags.
# armv7=false/true
ifeq ($(armv7), false)
@ -391,4 +398,7 @@ $(ENVFILE).new:
# Remember to keep these in sync with the DEPS file.
dependencies:
svn checkout --force http://gyp.googlecode.com/svn/trunk build/gyp \
--revision 1501
--revision 1656
svn checkout --force \
https://src.chromium.org/chrome/trunk/deps/third_party/icu46 \
third_party/icu --revision 205936

1
deps/v8/OWNERS

@ -1,3 +1,4 @@
bmeurer@chromium.org
danno@chromium.org
dslomov@chromium.org
hpayer@chromium.org

7
deps/v8/build/android.gypi

@ -75,15 +75,8 @@
],
'configurations': {
'Release': {
'cflags!': [
'-O2',
'-Os',
],
'cflags': [
'-fdata-sections',
'-ffunction-sections',
'-fomit-frame-pointer',
'-O3',
],
}, # Release
}, # configurations

58
deps/v8/build/common.gypi

@ -104,6 +104,10 @@
# Interpreted regexp engine exists as platform-independent alternative
# based where the regular expression is compiled to a bytecode.
'v8_interpreted_regexp%': 0,
# Enable ECMAScript Internationalization API. Enabling this feature will
# add a dependency on the ICU library.
'v8_enable_i18n_support%': 0,
},
'target_defaults': {
'conditions': [
@ -125,6 +129,9 @@
['v8_interpreted_regexp==1', {
'defines': ['V8_INTERPRETED_REGEXP',],
}],
['v8_enable_i18n_support==1', {
'defines': ['V8_I18N_SUPPORT',],
}],
['v8_target_arch=="arm"', {
'defines': [
'V8_TARGET_ARCH_ARM',
@ -452,6 +459,26 @@
}],
],
}],
['(OS=="linux") and (v8_target_arch=="x64")', {
# Check whether the host compiler and target compiler support the
# '-m64' option and set it if so.
'target_conditions': [
['_toolset=="host"', {
'variables': {
'm64flag': '<!((echo | $(echo ${CXX_host:-$(which g++)}) -m64 -E - > /dev/null 2>&1) && echo "-m64" || true)',
},
'cflags': [ '<(m64flag)' ],
'ldflags': [ '<(m64flag)' ],
}],
['_toolset=="target"', {
'variables': {
'm64flag': '<!((echo | $(echo ${CXX_target:-<(CXX)}) -m64 -E - > /dev/null 2>&1) && echo "-m64" || true)',
},
'cflags': [ '<(m64flag)' ],
'ldflags': [ '<(m64flag)' ],
}]
],
}],
['OS=="freebsd" or OS=="openbsd"', {
'cflags': [ '-I/usr/local/include' ],
}],
@ -528,8 +555,35 @@
['v8_enable_extra_checks==1', {
'defines': ['ENABLE_EXTRA_CHECKS',],
}],
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" \
or OS=="android"', {
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', {
'cflags!': [
'-O2',
'-Os',
],
'cflags': [
'-fdata-sections',
'-ffunction-sections',
'-O3',
],
'conditions': [
[ 'gcc_version==44 and clang==0', {
'cflags': [
# Avoid crashes with gcc 4.4 in the v8 test suite.
'-fno-tree-vrp',
],
}],
],
}],
['OS=="android"', {
'cflags!': [
'-O3',
'-Os',
],
'cflags': [
'-fdata-sections',
'-ffunction-sections',
'-O2',
],
'conditions': [
[ 'gcc_version==44 and clang==0', {
'cflags': [

73
deps/v8/build/shim_headers.gypi

@ -0,0 +1,73 @@
# Copyright 2013 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This file is meant to be included into a target to handle shim headers
# in a consistent manner. To use this the following variables need to be
# defined:
# headers_root_path: string: path to directory containing headers
# header_filenames: list: list of header file names
{
'variables': {
'shim_headers_path': '<(SHARED_INTERMEDIATE_DIR)/shim_headers/<(_target_name)/<(_toolset)',
'shim_generator_additional_args%': [],
},
'include_dirs++': [
'<(shim_headers_path)',
],
'all_dependent_settings': {
'include_dirs+++': [
'<(shim_headers_path)',
],
},
'actions': [
{
'variables': {
'generator_path': '<(DEPTH)/tools/generate_shim_headers/generate_shim_headers.py',
'generator_args': [
'--headers-root', '<(headers_root_path)',
'--output-directory', '<(shim_headers_path)',
'<@(shim_generator_additional_args)',
'<@(header_filenames)',
],
},
'action_name': 'generate_<(_target_name)_shim_headers',
'inputs': [
'<(generator_path)',
],
'outputs': [
'<!@pymod_do_main(generate_shim_headers <@(generator_args) --outputs)',
],
'action': ['python',
'<(generator_path)',
'<@(generator_args)',
'--generate',
],
'message': 'Generating <(_target_name) shim headers.',
},
],
}

51
deps/v8/build/standalone.gypi

@ -30,6 +30,7 @@
{
'variables': {
'component%': 'static_library',
'clang%': 0,
'visibility%': 'hidden',
'v8_enable_backtrace%': 0,
'msvs_multi_core_compile%': '1',
@ -65,6 +66,13 @@
'target_arch%': '<(target_arch)',
'v8_target_arch%': '<(v8_target_arch)',
'werror%': '-Werror',
# .gyp files or targets should set v8_code to 1 if they build V8 specific
# code, as opposed to external code. This variable is used to control such
# things as the set of warnings to enable, and whether warnings are treated
# as errors.
'v8_code%': 0,
'conditions': [
['(v8_target_arch=="arm" and host_arch!="arm") or \
(v8_target_arch=="mipsel" and host_arch!="mipsel") or \
@ -74,6 +82,17 @@
}, {
'want_separate_host_toolset': 0,
}],
['OS == "win"', {
'os_posix%': 0,
}, {
'os_posix%': 1,
}],
['(v8_target_arch=="ia32" or v8_target_arch=="x64") and \
(OS=="linux" or OS=="mac")', {
'v8_enable_gdbjit%': 1,
}, {
'v8_enable_gdbjit%': 0,
}],
],
# Default ARM variable settings.
'armv7%': 'default',
@ -83,6 +102,9 @@
'arm_thumb': 'default',
},
'target_defaults': {
'variables': {
'v8_code%': '<(v8_code)',
},
'default_configuration': 'Debug',
'configurations': {
'Debug': {
@ -92,14 +114,37 @@
# Xcode insists on this empty entry.
},
},
'target_conditions': [
['v8_code == 0', {
'conditions': [
['os_posix == 1 and OS != "mac"', {
'cflags!': [
'-Werror',
],
}],
['OS == "mac"', {
'xcode_settings': {
'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO', # -Werror
},
}],
['OS == "win"', {
'msvs_settings': {
'VCCLCompilerTool': {
'WarnAsError': 'false',
},
},
}],
],
}],
],
},
'conditions': [
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \
or OS=="netbsd"', {
'target_defaults': {
'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter',
'-Wnon-virtual-dtor', '-pthread', '-fno-rtti',
'-fno-exceptions', '-pedantic' ],
'-pthread', '-fno-exceptions', '-pedantic' ],
'cflags_cc': [ '-Wnon-virtual-dtor', '-fno-rtti' ],
'ldflags': [ '-pthread', ],
'conditions': [
[ 'OS=="linux"', {
@ -198,6 +243,7 @@
'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES', # -Werror
'GCC_VERSION': 'com.apple.compilers.llvmgcc42',
'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof
'GCC_WARN_NON_VIRTUAL_DESTRUCTOR': 'YES', # -Wnon-virtual-dtor
# MACOSX_DEPLOYMENT_TARGET maps to -mmacosx-version-min
'MACOSX_DEPLOYMENT_TARGET': '<(mac_deployment_target)',
'PREBINDING': 'NO', # No -Wl,-prebind
@ -211,7 +257,6 @@
'-Wendif-labels',
'-W',
'-Wno-unused-parameter',
'-Wnon-virtual-dtor',
],
},
'target_conditions': [

69
deps/v8/include/v8-profiler.h

@ -75,6 +75,9 @@ class V8EXPORT CpuProfileNode {
/** Returns function name (empty string for anonymous functions.) */
Handle<String> GetFunctionName() const;
/** Returns id of the script where function is located. */
int GetScriptId() const;
/** Returns resource name for script from where the function originates. */
Handle<String> GetScriptResourceName() const;
@ -172,18 +175,12 @@ class V8EXPORT CpuProfiler {
* obtaining profiling results.
*/
/** Deprecated. Use GetProfileCount instead. */
V8_DEPRECATED(static int GetProfilesCount());
/**
* Returns the number of profiles collected (doesn't include
* profiles that are being collected at the moment of call.)
*/
int GetProfileCount();
/** Deprecated. Use GetCpuProfile instead. */
V8_DEPRECATED(static const CpuProfile* GetProfile(
int index,
Handle<Value> security_token = Handle<Value>()));
/** Deprecated. Use GetCpuProfile with single parameter. */
V8_DEPRECATED(const CpuProfile* GetCpuProfile(
int index,
@ -191,18 +188,11 @@ class V8EXPORT CpuProfiler {
/** Returns a profile by index. */
const CpuProfile* GetCpuProfile(int index);
/** Deprecated. Use FindProfile instead. */
V8_DEPRECATED(static const CpuProfile* FindProfile(
unsigned uid,
Handle<Value> security_token = Handle<Value>()));
/** Returns a profile by uid. */
V8_DEPRECATED(const CpuProfile* FindCpuProfile(
unsigned uid,
Handle<Value> security_token = Handle<Value>()));
/** Deprecated. Use StartCpuProfiling instead. */
V8_DEPRECATED(static void StartProfiling(Handle<String> title,
bool record_samples = false));
/**
* Starts collecting CPU profile. Title may be an empty string. It
* is allowed to have several profiles being collected at
@ -216,10 +206,6 @@ class V8EXPORT CpuProfiler {
*/
void StartCpuProfiling(Handle<String> title, bool record_samples = false);
/** Deprecated. Use StopCpuProfiling instead. */
V8_DEPRECATED(static const CpuProfile* StopProfiling(
Handle<String> title,
Handle<Value> security_token = Handle<Value>()));
/**
* Deprecated. Use StopCpuProfiling with one parameter instead.
*/
@ -232,8 +218,6 @@ class V8EXPORT CpuProfiler {
*/
const CpuProfile* StopCpuProfiling(Handle<String> title);
/** Deprecated. Use DeleteAllCpuProfiles instead. */
V8_DEPRECATED(static void DeleteAllProfiles());
/**
* Deletes all existing profiles, also cancelling all profiling
* activity. All previously returned pointers to profiles and their
@ -346,16 +330,10 @@ class V8EXPORT HeapGraphNode {
*/
class V8EXPORT HeapSnapshot {
public:
enum Type {
kFull = 0 // Heap snapshot with all instances and references.
};
enum SerializationFormat {
kJSON = 0 // See format description near 'Serialize' method.
};
/** Deprecated. Returns kFull. */
V8_DEPRECATED(Type GetType() const);
/** Returns heap snapshot UID (assigned by the profiler.) */
unsigned GetUid() const;
@ -431,24 +409,12 @@ class V8EXPORT HeapProfiler {
typedef RetainedObjectInfo* (*WrapperInfoCallback)
(uint16_t class_id, Handle<Value> wrapper);
/** Deprecated. Use GetSnapshotCount instead. */
V8_DEPRECATED(static int GetSnapshotsCount());
/** Returns the number of snapshots taken. */
int GetSnapshotCount();
/** Deprecated. Use GetHeapSnapshot instead. */
V8_DEPRECATED(static const HeapSnapshot* GetSnapshot(int index));
/** Returns a snapshot by index. */
const HeapSnapshot* GetHeapSnapshot(int index);
/** Deprecated. Use FindHeapSnapshot instead. */
V8_DEPRECATED(static const HeapSnapshot* FindSnapshot(unsigned uid));
/** Returns a profile by uid. */
V8_DEPRECATED(const HeapSnapshot* FindHeapSnapshot(unsigned uid));
/** Deprecated. Use GetObjectId instead. */
V8_DEPRECATED(static SnapshotObjectId GetSnapshotObjectId(
Handle<Value> value));
/**
* Returns SnapshotObjectId for a heap object referenced by |value| if
* it has been seen by the heap profiler, kUnknownObjectId otherwise.
@ -476,12 +442,6 @@ class V8EXPORT HeapProfiler {
virtual ~ObjectNameResolver() {}
};
/** Deprecated. Use TakeHeapSnapshot instead. */
V8_DEPRECATED(static const HeapSnapshot* TakeSnapshot(
Handle<String> title,
HeapSnapshot::Type type = HeapSnapshot::kFull,
ActivityControl* control = NULL,
ObjectNameResolver* global_object_name_resolver = NULL));
/**
* Takes a heap snapshot and returns it. Title may be an empty string.
*/
@ -490,9 +450,6 @@ class V8EXPORT HeapProfiler {
ActivityControl* control = NULL,
ObjectNameResolver* global_object_name_resolver = NULL);
/** Deprecated. Use StartTrackingHeapObjects instead. */
V8_DEPRECATED(static void StartHeapObjectsTracking());
/**
* Starts tracking of heap objects population statistics. After calling
* this method, all heap objects relocations done by the garbage collector
@ -500,9 +457,6 @@ class V8EXPORT HeapProfiler {
*/
void StartTrackingHeapObjects();
/** Deprecated. Use GetHeapStats instead. */
V8_DEPRECATED(static SnapshotObjectId PushHeapObjectsStats(
OutputStream* stream));
/**
* Adds a new time interval entry to the aggregated statistics array. The
* time interval entry contains information on the current heap objects
@ -517,8 +471,6 @@ class V8EXPORT HeapProfiler {
*/
SnapshotObjectId GetHeapStats(OutputStream* stream);
/** Deprecated. Use StopTrackingHeapObjects instead. */
V8_DEPRECATED(static void StopHeapObjectsTracking());
/**
* Stops tracking of heap objects population statistics, cleans up all
* collected data. StartHeapObjectsTracking must be called again prior to
@ -526,18 +478,12 @@ class V8EXPORT HeapProfiler {
*/
void StopTrackingHeapObjects();
/** Deprecated. Use DeleteAllHeapSnapshots instead. */
V8_DEPRECATED(static void DeleteAllSnapshots());
/**
* Deletes all snapshots taken. All previously returned pointers to
* snapshots and their contents become invalid after this call.
*/
void DeleteAllHeapSnapshots();
/** Deprecated. Use SetWrapperClassInfoProvider instead. */
V8_DEPRECATED(static void DefineWrapperClass(
uint16_t class_id,
WrapperInfoCallback callback));
/** Binds a callback to embedder's class ID. */
void SetWrapperClassInfoProvider(
uint16_t class_id,
@ -550,13 +496,6 @@ class V8EXPORT HeapProfiler {
*/
static const uint16_t kPersistentHandleNoClassId = 0;
/**
* Deprecated. Returns the number of currently existing persistent handles.
*/
V8_DEPRECATED(static int GetPersistentHandleCount());
/** Deprecated. Use GetHeapProfilerMemorySize instead. */
V8_DEPRECATED(static size_t GetMemorySizeUsedByProfiler());
/** Returns memory used for profiler internal data and snapshots. */
size_t GetProfilerMemorySize();
@ -590,7 +529,7 @@ class V8EXPORT HeapProfiler {
* objects for heap snapshots, he can do it in a GC prologue
* handler, and / or by assigning wrapper class ids in the following way:
*
* 1. Bind a callback to class id by calling DefineWrapperClass.
* 1. Bind a callback to class id by calling SetWrapperClassInfoProvider.
* 2. Call SetWrapperClassId on certain persistent handles.
*
* V8 takes ownership of RetainedObjectInfo instances passed to it and

342
deps/v8/include/v8.h

@ -123,7 +123,6 @@ class ImplementationUtilities;
class Int32;
class Integer;
class Isolate;
class LocalContext;
class Number;
class NumberObject;
class Object;
@ -155,6 +154,7 @@ class Isolate;
class DeclaredAccessorDescriptor;
class ObjectOperationDescriptor;
class RawOperationDescriptor;
class CallHandlerHelper;
namespace internal {
class Arguments;
@ -162,8 +162,7 @@ class Heap;
class HeapObject;
class Isolate;
class Object;
template<typename T>
class CustomArguments;
template<typename T> class CustomArguments;
class PropertyCallbackArguments;
class FunctionCallbackArguments;
}
@ -222,8 +221,6 @@ class WeakReferenceCallbacks {
}
#define V8_USE_UNSAFE_HANDLES
/**
* An object reference managed by the v8 garbage collector.
*
@ -365,21 +362,19 @@ template <class T> class Handle {
#endif
private:
friend class Utils;
template<class F> friend class Persistent;
template<class F> friend class Local;
friend class Arguments;
template<class F> friend class FunctionCallbackInfo;
template<class F> friend class PropertyCallbackInfo;
friend class String;
friend class Object;
template<class F> friend class internal::CustomArguments;
friend class AccessorInfo;
friend Handle<Primitive> Undefined(Isolate* isolate);
friend Handle<Primitive> Null(Isolate* isolate);
friend Handle<Boolean> True(Isolate* isolate);
friend Handle<Boolean> False(Isolate* isolate);
friend class Context;
friend class InternalHandleHelper;
friend class LocalContext;
friend class HandleScope;
#ifndef V8_USE_UNSAFE_HANDLES
@ -454,6 +449,7 @@ template <class T> class Local : public Handle<T> {
#endif
private:
friend class Utils;
template<class F> friend class Persistent;
template<class F> friend class Handle;
friend class Arguments;
@ -463,8 +459,7 @@ template <class T> class Local : public Handle<T> {
friend class Object;
friend class AccessorInfo;
friend class Context;
friend class InternalHandleHelper;
friend class LocalContext;
template<class F> friend class internal::CustomArguments;
friend class HandleScope;
V8_INLINE(static Local<T> New(Isolate* isolate, T* that));
@ -496,10 +491,10 @@ template <class T> class Persistent // NOLINT
public:
#ifndef V8_USE_UNSAFE_HANDLES
V8_INLINE(Persistent()) : val_(0) { }
V8_INLINE(~Persistent()) {
// TODO(dcarney): add this back before cutover.
// Dispose();
}
// TODO(dcarney): add this back before cutover.
// V8_INLINE(~Persistent()) {
// Dispose();
// }
V8_INLINE(bool IsEmpty() const) { return val_ == 0; }
// TODO(dcarney): remove somehow before cutover
// The handle should either be 0, or a pointer to a live cell.
@ -511,11 +506,11 @@ template <class T> class Persistent // NOLINT
* to be separately disposed.
*/
template <class S> V8_INLINE(Persistent(Isolate* isolate, Handle<S> that))
: val_(*New(isolate, that)) { }
: val_(New(isolate, *that)) { }
template <class S> V8_INLINE(Persistent(Isolate* isolate,
Persistent<S>& that)) // NOLINT
: val_(*New(isolate, that)) { }
const Persistent<S>& that)) // NOLINT
: val_(New(isolate, *that)) { }
#else
/**
@ -594,15 +589,9 @@ template <class T> class Persistent // NOLINT
}
#endif
#ifdef V8_USE_UNSAFE_HANDLES
V8_DEPRECATED(static Persistent<T> New(Handle<T> that));
/**
* Creates a new persistent handle for an existing local or persistent handle.
*/
// TODO(dcarney): remove before cutover
V8_INLINE(static Persistent<T> New(Isolate* isolate, Handle<T> that));
#ifndef V8_USE_UNSAFE_HANDLES
// TODO(dcarney): remove before cutover
V8_INLINE(static Persistent<T> New(Isolate* isolate, Persistent<T> that));
#endif
@ -652,23 +641,17 @@ template <class T> class Persistent // NOLINT
P* parameters,
typename WeakReferenceCallbacks<T, P>::Revivable callback));
// TODO(dcarney): deprecate
template<typename S, typename P>
V8_INLINE(void MakeWeak(
V8_DEPRECATED(void MakeWeak(
Isolate* isolate,
P* parameters,
typename WeakReferenceCallbacks<S, P>::Revivable callback)) {
MakeWeak<S, P>(parameters, callback);
}
typename WeakReferenceCallbacks<S, P>::Revivable callback));
// TODO(dcarney): deprecate
template<typename P>
V8_INLINE(void MakeWeak(
V8_DEPRECATED(void MakeWeak(
Isolate* isolate,
P* parameters,
typename WeakReferenceCallbacks<T, P>::Revivable callback)) {
MakeWeak<P>(parameters, callback);
}
typename WeakReferenceCallbacks<T, P>::Revivable callback));
V8_INLINE(void ClearWeak());
@ -779,11 +762,7 @@ template <class T> class Persistent // NOLINT
#endif
// TODO(dcarney): remove before cutover
template <class S> V8_INLINE(Persistent(S* that)) : val_(that) { }
// TODO(dcarney): remove before cutover
template <class S> V8_INLINE(Persistent(Persistent<S> that))
: val_(*that) {
TYPE_CHECK(T, S);
}
// TODO(dcarney): remove before cutover
V8_INLINE(T* operator*() const) { return val_; }
@ -794,16 +773,13 @@ template <class T> class Persistent // NOLINT
#endif
private:
friend class Utils;
template<class F> friend class Handle;
template<class F> friend class Local;
template<class F> friend class Persistent;
template<class F> friend class ReturnValue;
friend class ImplementationUtilities;
friend class ObjectTemplate;
friend class Context;
friend class InternalHandleHelper;
friend class LocalContext;
V8_INLINE(static Persistent<T> New(Isolate* isolate, T* that));
V8_INLINE(static T* New(Isolate* isolate, T* that));
#ifndef V8_USE_UNSAFE_HANDLES
T* val_;
@ -1067,9 +1043,15 @@ class V8EXPORT Script {
/**
* Returns the script id value.
* DEPRECATED: Please use GetId().
*/
Local<Value> Id();
/**
* Returns the script id.
*/
int GetId();
/**
* Associate an additional data object with the script. This is mainly used
* with the debugger as this data object is only available through the
@ -1087,6 +1069,8 @@ class V8EXPORT Script {
* -1 will be returned if no information available.
*/
int GetLineNumber(int code_pos);
static const int kNoScriptId = 0;
};
@ -1385,6 +1369,12 @@ class V8EXPORT Value : public Data {
*/
bool IsArrayBuffer() const;
/**
* Returns true if this value is an ArrayBufferView.
* This is an experimental feature.
*/
bool IsArrayBufferView() const;
/**
* Returns true if this value is one of TypedArrays.
* This is an experimental feature.
@ -1445,6 +1435,12 @@ class V8EXPORT Value : public Data {
*/
bool IsFloat64Array() const;
/**
* Returns true if this value is a DataView.
* This is an experimental feature.
*/
bool IsDataView() const;
Local<Boolean> ToBoolean() const;
Local<Number> ToNumber() const;
Local<String> ToString() const;
@ -2078,13 +2074,12 @@ class V8EXPORT Object : public Value {
bool Delete(uint32_t index);
// TODO(dcarney): deprecate
bool SetAccessor(Handle<String> name,
AccessorGetter getter,
AccessorSetter setter = 0,
Handle<Value> data = Handle<Value>(),
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None);
V8_DEPRECATED(bool SetAccessor(Handle<String> name,
AccessorGetter getter,
AccessorSetter setter = 0,
Handle<Value> data = Handle<Value>(),
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None));
bool SetAccessor(Handle<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter = 0,
@ -2360,7 +2355,18 @@ class V8EXPORT Function : public Object {
* kLineOffsetNotFound if no information available.
*/
int GetScriptColumnNumber() const;
/**
* Returns scriptId object.
* DEPRECATED: use ScriptId() instead.
*/
Handle<Value> GetScriptId() const;
/**
* Returns scriptId.
*/
int ScriptId() const;
ScriptOrigin GetScriptOrigin() const;
V8_INLINE(static Function* Cast(Value* obj));
static const int kLineOffsetNotFound;
@ -2484,33 +2490,51 @@ class V8EXPORT ArrayBuffer : public Object {
/**
* A base class for an instance of TypedArray series of constructors
* (ES6 draft 15.13.6).
* A base class for an instance of one of "views" over ArrayBuffer,
* including TypedArrays and DataView (ES6 draft 15.13).
*
* This API is experimental and may change significantly.
*/
class V8EXPORT TypedArray : public Object {
class V8EXPORT ArrayBufferView : public Object {
public:
/**
* Returns underlying ArrayBuffer.
*/
Local<ArrayBuffer> Buffer();
/**
* Byte offset in |Buffer|
* Byte offset in |Buffer|.
*/
size_t ByteOffset();
/**
* Numbe of elements in this typed array.
*/
size_t Length();
/**
* Size of typed array in bytes (e.g. for Int16Array, 2*|Length|).
* Size of a view in bytes.
*/
size_t ByteLength();
/**
* Base address of typed array.
* Base address of a view.
*/
void* BaseAddress();
V8_INLINE(static ArrayBufferView* Cast(Value* obj));
private:
ArrayBufferView();
static void CheckCast(Value* obj);
};
/**
* A base class for an instance of TypedArray series of constructors
* (ES6 draft 15.13.6).
* This API is experimental and may change significantly.
*/
class V8EXPORT TypedArray : public ArrayBufferView {
public:
/**
* Number of elements in this typed array
* (e.g. for Int16Array, |ByteLength|/2).
*/
size_t Length();
V8_INLINE(static TypedArray* Cast(Value* obj));
private:
@ -2662,6 +2686,22 @@ class V8EXPORT Float64Array : public TypedArray {
};
/**
* An instance of DataView constructor (ES6 draft 15.13.7).
* This API is experimental and may change significantly.
*/
class V8EXPORT DataView : public ArrayBufferView {
public:
static Local<DataView> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
V8_INLINE(static DataView* Cast(Value* obj));
private:
DataView();
static void CheckCast(Value* obj);
};
/**
* An instance of the built-in Date constructor (ECMA-262, 15.9).
*/
@ -3220,14 +3260,13 @@ typedef bool (*IndexedSecurityCallback)(Local<Object> host,
class V8EXPORT FunctionTemplate : public Template {
public:
/** Creates a function template.*/
// TODO(dcarney): deprecate
static Local<FunctionTemplate> New(
InvocationCallback callback = 0,
V8_DEPRECATED(static Local<FunctionTemplate> New(
InvocationCallback callback,
Handle<Value> data = Handle<Value>(),
Handle<Signature> signature = Handle<Signature>(),
int length = 0);
int length = 0));
static Local<FunctionTemplate> New(
FunctionCallback callback, // TODO(dcarney): add back default param.
FunctionCallback callback = 0,
Handle<Value> data = Handle<Value>(),
Handle<Signature> signature = Handle<Signature>(),
int length = 0);
@ -3240,9 +3279,8 @@ class V8EXPORT FunctionTemplate : public Template {
* callback is called whenever the function created from this
* FunctionTemplate is called.
*/
// TODO(dcarney): deprecate
void SetCallHandler(InvocationCallback callback,
Handle<Value> data = Handle<Value>());
V8_DEPRECATED(void SetCallHandler(InvocationCallback callback,
Handle<Value> data = Handle<Value>()));
void SetCallHandler(FunctionCallback callback,
Handle<Value> data = Handle<Value>());
@ -3296,6 +3334,9 @@ class V8EXPORT FunctionTemplate : public Template {
private:
FunctionTemplate();
// TODO(dcarney): Remove with SetCallHandler.
friend class v8::CallHandlerHelper;
void SetCallHandlerInternal(InvocationCallback callback, Handle<Value> data);
friend class Context;
friend class ObjectTemplate;
};
@ -3344,15 +3385,14 @@ class V8EXPORT ObjectTemplate : public Template {
* defined by FunctionTemplate::HasInstance()), an implicit TypeError is
* thrown and no callback is invoked.
*/
// TODO(dcarney): deprecate
void SetAccessor(Handle<String> name,
AccessorGetter getter,
AccessorSetter setter = 0,
Handle<Value> data = Handle<Value>(),
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None,
Handle<AccessorSignature> signature =
Handle<AccessorSignature>());
V8_DEPRECATED(void SetAccessor(Handle<String> name,
AccessorGetter getter,
AccessorSetter setter = 0,
Handle<Value> data = Handle<Value>(),
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None,
Handle<AccessorSignature> signature =
Handle<AccessorSignature>()));
void SetAccessor(Handle<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter = 0,
@ -3387,13 +3427,13 @@ class V8EXPORT ObjectTemplate : public Template {
* \param data A piece of data that will be passed to the callbacks
* whenever they are invoked.
*/
// TODO(dcarney): deprecate
void SetNamedPropertyHandler(NamedPropertyGetter getter,
NamedPropertySetter setter = 0,
NamedPropertyQuery query = 0,
NamedPropertyDeleter deleter = 0,
NamedPropertyEnumerator enumerator = 0,
Handle<Value> data = Handle<Value>());
V8_DEPRECATED(void SetNamedPropertyHandler(
NamedPropertyGetter getter,
NamedPropertySetter setter = 0,
NamedPropertyQuery query = 0,
NamedPropertyDeleter deleter = 0,
NamedPropertyEnumerator enumerator = 0,
Handle<Value> data = Handle<Value>()));
void SetNamedPropertyHandler(
NamedPropertyGetterCallback getter,
NamedPropertySetterCallback setter = 0,
@ -3418,13 +3458,13 @@ class V8EXPORT ObjectTemplate : public Template {
* \param data A piece of data that will be passed to the callbacks
* whenever they are invoked.
*/
// TODO(dcarney): deprecate
void SetIndexedPropertyHandler(IndexedPropertyGetter getter,
IndexedPropertySetter setter = 0,
IndexedPropertyQuery query = 0,
IndexedPropertyDeleter deleter = 0,
IndexedPropertyEnumerator enumerator = 0,
Handle<Value> data = Handle<Value>());
V8_DEPRECATED(void SetIndexedPropertyHandler(
IndexedPropertyGetter getter,
IndexedPropertySetter setter = 0,
IndexedPropertyQuery query = 0,
IndexedPropertyDeleter deleter = 0,
IndexedPropertyEnumerator enumerator = 0,
Handle<Value> data = Handle<Value>()));
void SetIndexedPropertyHandler(
IndexedPropertyGetterCallback getter,
IndexedPropertySetterCallback setter = 0,
@ -3439,9 +3479,9 @@ class V8EXPORT ObjectTemplate : public Template {
* behave like normal JavaScript objects that cannot be called as a
* function.
*/
// TODO(dcarney): deprecate
void SetCallAsFunctionHandler(InvocationCallback callback,
Handle<Value> data = Handle<Value>());
V8_DEPRECATED(void SetCallAsFunctionHandler(
InvocationCallback callback,
Handle<Value> data = Handle<Value>()));
void SetCallAsFunctionHandler(FunctionCallback callback,
Handle<Value> data = Handle<Value>());
@ -3953,8 +3993,9 @@ class V8EXPORT Isolate {
HeapProfiler* GetHeapProfiler();
/**
* Returns CPU profiler for this isolate. Will return NULL until the isolate
* is initialized.
* Returns CPU profiler for this isolate. Will return NULL unless the isolate
* is initialized. It is the embedder's responsibility to stop all CPU
* profiling activities if it has started any.
*/
CpuProfiler* GetCpuProfiler();
@ -4436,19 +4477,26 @@ class V8EXPORT V8 {
static void SetReturnAddressLocationResolver(
ReturnAddressLocationResolver return_address_resolver);
/**
* Deprecated, use the variant with the Isolate parameter below instead.
*/
V8_DEPRECATED(static bool SetFunctionEntryHook(FunctionEntryHook entry_hook));
/**
* Allows the host application to provide the address of a function that's
* invoked on entry to every V8-generated function.
* Note that \p entry_hook is invoked at the very start of each
* generated function.
*
* \param isolate the isolate to operate on.
* \param entry_hook a function that will be invoked on entry to every
* V8-generated function.
* \returns true on success on supported platforms, false on failure.
* \note Setting a new entry hook function when one is already active will
* fail.
* \note Setting an entry hook can only be done very early in an isolates
* lifetime, and once set, the entry hook cannot be revoked.
*/
static bool SetFunctionEntryHook(FunctionEntryHook entry_hook);
static bool SetFunctionEntryHook(Isolate* isolate,
FunctionEntryHook entry_hook);
/**
* Allows the host application to provide the address of a function that is
@ -4776,7 +4824,10 @@ class V8EXPORT TryCatch {
v8::internal::Isolate* isolate_;
void* next_;
void* exception_;
void* message_;
void* message_obj_;
void* message_script_;
int message_start_pos_;
int message_end_pos_;
bool is_verbose_ : 1;
bool can_continue_ : 1;
bool capture_message_ : 1;
@ -5320,20 +5371,19 @@ class Internals {
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
static const int kContextHeaderSize = 2 * kApiPointerSize;
static const int kContextEmbedderDataIndex = 64;
static const int kContextEmbedderDataIndex = 65;
static const int kFullStringRepresentationMask = 0x07;
static const int kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;
static const int kExternalAsciiRepresentationTag = 0x06;
static const int kIsolateStateOffset = 0;
static const int kIsolateEmbedderDataOffset = 1 * kApiPointerSize;
static const int kIsolateRootsOffset = 3 * kApiPointerSize;
static const int kUndefinedValueRootIndex = 5;
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
static const int kEmptyStringRootIndex = 130;
static const int kEmptyStringRootIndex = 131;
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
@ -5343,14 +5393,21 @@ class Internals {
static const int kNodeIsIndependentShift = 4;
static const int kNodeIsPartiallyDependentShift = 5;
static const int kJSObjectType = 0xaf;
static const int kJSObjectType = 0xb0;
static const int kFirstNonstringType = 0x80;
static const int kOddballType = 0x83;
static const int kForeignType = 0x87;
static const int kForeignType = 0x88;
static const int kUndefinedOddballKind = 5;
static const int kNullOddballKind = 3;
static void CheckInitializedImpl(v8::Isolate* isolate);
V8_INLINE(static void CheckInitialized(v8::Isolate* isolate)) {
#ifdef V8_ENABLE_CHECKS
CheckInitializedImpl(isolate);
#endif
}
V8_INLINE(static bool HasHeapObjectTag(internal::Object* value)) {
return ((reinterpret_cast<intptr_t>(value) & kHeapObjectTagMask) ==
kHeapObjectTag);
@ -5384,11 +5441,6 @@ class Internals {
return representation == kExternalTwoByteRepresentationTag;
}
V8_INLINE(static bool IsInitialized(v8::Isolate* isolate)) {
uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) + kIsolateStateOffset;
return *reinterpret_cast<int*>(addr) == 1;
}
V8_INLINE(static uint8_t GetNodeFlag(internal::Object** obj, int shift)) {
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
return *addr & (1 << shift);
@ -5510,6 +5562,7 @@ Local<T> Local<T>::New(Isolate* isolate, T* that) {
}
#ifdef V8_USE_UNSAFE_HANDLES
template <class T>
Persistent<T> Persistent<T>::New(Handle<T> that) {
return New(Isolate::GetCurrent(), that.val_);
@ -5521,20 +5574,20 @@ Persistent<T> Persistent<T>::New(Isolate* isolate, Handle<T> that) {
return New(Isolate::GetCurrent(), that.val_);
}
#ifndef V8_USE_UNSAFE_HANDLES
template <class T>
Persistent<T> Persistent<T>::New(Isolate* isolate, Persistent<T> that) {
return New(Isolate::GetCurrent(), that.val_);
}
#endif
template <class T>
Persistent<T> Persistent<T>::New(Isolate* isolate, T* that) {
if (that == NULL) return Persistent<T>();
T* Persistent<T>::New(Isolate* isolate, T* that) {
if (that == NULL) return NULL;
internal::Object** p = reinterpret_cast<internal::Object**>(that);
return Persistent<T>(reinterpret_cast<T*>(
return reinterpret_cast<T*>(
V8::GlobalizeReference(reinterpret_cast<internal::Isolate*>(isolate),
p)));
p));
}
@ -5597,6 +5650,26 @@ void Persistent<T>::MakeWeak(
}
template <class T>
template <typename S, typename P>
void Persistent<T>::MakeWeak(
Isolate* isolate,
P* parameters,
typename WeakReferenceCallbacks<S, P>::Revivable callback) {
MakeWeak<S, P>(parameters, callback);
}
template <class T>
template<typename P>
void Persistent<T>::MakeWeak(
Isolate* isolate,
P* parameters,
typename WeakReferenceCallbacks<T, P>::Revivable callback) {
MakeWeak<P>(parameters, callback);
}
template <class T>
void Persistent<T>::ClearWeak() {
V8::ClearWeak(reinterpret_cast<internal::Object**>(this->val_));
@ -5716,11 +5789,13 @@ void ReturnValue<T>::Set(const Handle<S> handle) {
template<typename T>
void ReturnValue<T>::Set(double i) {
TYPE_CHECK(T, Number);
Set(Number::New(GetIsolate(), i));
}
template<typename T>
void ReturnValue<T>::Set(int32_t i) {
TYPE_CHECK(T, Integer);
typedef internal::Internals I;
if (V8_LIKELY(I::IsValidSmi(i))) {
*value_ = I::IntToSmi(i);
@ -5731,6 +5806,7 @@ void ReturnValue<T>::Set(int32_t i) {
template<typename T>
void ReturnValue<T>::Set(uint32_t i) {
TYPE_CHECK(T, Integer);
typedef internal::Internals I;
// Can't simply use INT32_MAX here for whatever reason.
bool fits_into_int32_t = (i & (1 << 31)) == 0;
@ -5743,6 +5819,7 @@ void ReturnValue<T>::Set(uint32_t i) {
template<typename T>
void ReturnValue<T>::Set(bool value) {
TYPE_CHECK(T, Boolean);
typedef internal::Internals I;
int root_index;
if (value) {
@ -5755,18 +5832,21 @@ void ReturnValue<T>::Set(bool value) {
template<typename T>
void ReturnValue<T>::SetNull() {
TYPE_CHECK(T, Primitive);
typedef internal::Internals I;
*value_ = *I::GetRoot(GetIsolate(), I::kNullValueRootIndex);
}
template<typename T>
void ReturnValue<T>::SetUndefined() {
TYPE_CHECK(T, Primitive);
typedef internal::Internals I;
*value_ = *I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
}
template<typename T>
void ReturnValue<T>::SetEmptyString() {
TYPE_CHECK(T, String);
typedef internal::Internals I;
*value_ = *I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex);
}
@ -5936,7 +6016,7 @@ String* String::Cast(v8::Value* value) {
Local<String> String::Empty(Isolate* isolate) {
typedef internal::Object* S;
typedef internal::Internals I;
if (!I::IsInitialized(isolate)) return Empty();
I::CheckInitialized(isolate);
S* slot = I::GetRoot(isolate, I::kEmptyStringRootIndex);
return Local<String>(reinterpret_cast<String*>(slot));
}
@ -6160,6 +6240,14 @@ ArrayBuffer* ArrayBuffer::Cast(v8::Value* value) {
}
ArrayBufferView* ArrayBufferView::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<ArrayBufferView*>(value);
}
TypedArray* TypedArray::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
@ -6240,6 +6328,14 @@ Uint8ClampedArray* Uint8ClampedArray::Cast(v8::Value* value) {
}
DataView* DataView::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<DataView*>(value);
}
Function* Function::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
@ -6289,7 +6385,7 @@ ReturnValue<T> PropertyCallbackInfo<T>::GetReturnValue() const {
Handle<Primitive> Undefined(Isolate* isolate) {
typedef internal::Object* S;
typedef internal::Internals I;
if (!I::IsInitialized(isolate)) return Undefined();
I::CheckInitialized(isolate);
S* slot = I::GetRoot(isolate, I::kUndefinedValueRootIndex);
return Handle<Primitive>(reinterpret_cast<Primitive*>(slot));
}
@ -6298,7 +6394,7 @@ Handle<Primitive> Undefined(Isolate* isolate) {
Handle<Primitive> Null(Isolate* isolate) {
typedef internal::Object* S;
typedef internal::Internals I;
if (!I::IsInitialized(isolate)) return Null();
I::CheckInitialized(isolate);
S* slot = I::GetRoot(isolate, I::kNullValueRootIndex);
return Handle<Primitive>(reinterpret_cast<Primitive*>(slot));
}
@ -6307,7 +6403,7 @@ Handle<Primitive> Null(Isolate* isolate) {
Handle<Boolean> True(Isolate* isolate) {
typedef internal::Object* S;
typedef internal::Internals I;
if (!I::IsInitialized(isolate)) return True();
I::CheckInitialized(isolate);
S* slot = I::GetRoot(isolate, I::kTrueValueRootIndex);
return Handle<Boolean>(reinterpret_cast<Boolean*>(slot));
}
@ -6316,7 +6412,7 @@ Handle<Boolean> True(Isolate* isolate) {
Handle<Boolean> False(Isolate* isolate) {
typedef internal::Object* S;
typedef internal::Internals I;
if (!I::IsInitialized(isolate)) return False();
I::CheckInitialized(isolate);
S* slot = I::GetRoot(isolate, I::kFalseValueRootIndex);
return Handle<Boolean>(reinterpret_cast<Boolean*>(slot));
}

3
deps/v8/preparser/preparser.gyp

@ -26,6 +26,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'variables': {
'v8_code': 1,
},
'includes': ['../build/common.gypi'],
'targets': [
{

3
deps/v8/samples/samples.gyp

@ -26,6 +26,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'variables': {
'v8_code': 1,
},
'includes': ['../build/common.gypi'],
'target_defaults': {
'type': 'executable',

627
deps/v8/src/api.cc

File diff suppressed because it is too large

78
deps/v8/src/api.h

@ -170,6 +170,7 @@ class RegisteredExtension {
V(Object, JSObject) \
V(Array, JSArray) \
V(ArrayBuffer, JSArrayBuffer) \
V(ArrayBufferView, JSArrayBufferView) \
V(TypedArray, JSTypedArray) \
V(Uint8Array, JSTypedArray) \
V(Uint8ClampedArray, JSTypedArray) \
@ -180,6 +181,7 @@ class RegisteredExtension {
V(Int32Array, JSTypedArray) \
V(Float32Array, JSTypedArray) \
V(Float64Array, JSTypedArray) \
V(DataView, JSDataView) \
V(String, String) \
V(Symbol, Symbol) \
V(Script, Object) \
@ -217,6 +219,10 @@ class Utils {
v8::internal::Handle<v8::internal::JSArray> obj);
static inline Local<ArrayBuffer> ToLocal(
v8::internal::Handle<v8::internal::JSArrayBuffer> obj);
static inline Local<ArrayBufferView> ToLocal(
v8::internal::Handle<v8::internal::JSArrayBufferView> obj);
static inline Local<DataView> ToLocal(
v8::internal::Handle<v8::internal::JSDataView> obj);
static inline Local<TypedArray> ToLocal(
v8::internal::Handle<v8::internal::JSTypedArray> obj);
@ -273,13 +279,31 @@ class Utils {
OPEN_HANDLE_LIST(DECLARE_OPEN_HANDLE)
#undef DECLARE_OPEN_HANDLE
};
template<class From, class To>
static inline Local<To> Convert(v8::internal::Handle<From> obj) {
ASSERT(obj.is_null() || !obj->IsTheHole());
return Local<To>(reinterpret_cast<To*>(obj.location()));
}
template <class T>
inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) {
return reinterpret_cast<T*>(obj.location());
}
template <class T>
static inline v8::internal::Handle<v8::internal::Object> OpenPersistent(
const v8::Persistent<T>& persistent) {
return v8::internal::Handle<v8::internal::Object>(
reinterpret_cast<v8::internal::Object**>(persistent.val_));
}
template <class T>
static inline v8::internal::Handle<v8::internal::Object> OpenPersistent(
v8::Persistent<T>* persistent) {
return OpenPersistent(*persistent);
}
template <class From, class To>
static inline v8::internal::Handle<To> OpenHandle(v8::Local<From> handle) {
return OpenHandle(*handle);
}
};
template <class T>
@ -293,31 +317,31 @@ v8::internal::Handle<T> v8::internal::Handle<T>::EscapeFrom(
}
class InternalHandleHelper {
public:
template<class From, class To>
static inline Local<To> Convert(v8::internal::Handle<From> obj) {
return Local<To>(reinterpret_cast<To*>(obj.location()));
}
};
template <class T>
inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) {
return reinterpret_cast<T*>(obj.location());
}
template <class T>
inline v8::Local<T> ToApiHandle(
v8::internal::Handle<v8::internal::Object> obj) {
return Utils::Convert<v8::internal::Object, T>(obj);
}
// Implementations of ToLocal
#define MAKE_TO_LOCAL(Name, From, To) \
Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \
ASSERT(obj.is_null() || !obj->IsTheHole()); \
return InternalHandleHelper::Convert<v8::internal::From, v8::To>(obj); \
return Convert<v8::internal::From, v8::To>(obj); \
}
#define MAKE_TO_LOCAL_TYPED_ARRAY(TypedArray, typeConst) \
Local<v8::TypedArray> Utils::ToLocal##TypedArray( \
v8::internal::Handle<v8::internal::JSTypedArray> obj) { \
ASSERT(obj.is_null() || !obj->IsTheHole()); \
ASSERT(obj->type() == typeConst); \
return InternalHandleHelper:: \
Convert<v8::internal::JSTypedArray, v8::TypedArray>(obj); \
return Convert<v8::internal::JSTypedArray, v8::TypedArray>(obj); \
}
@ -330,6 +354,8 @@ MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
MAKE_TO_LOCAL(ToLocal, JSObject, Object)
MAKE_TO_LOCAL(ToLocal, JSArray, Array)
MAKE_TO_LOCAL(ToLocal, JSArrayBuffer, ArrayBuffer)
MAKE_TO_LOCAL(ToLocal, JSArrayBufferView, ArrayBufferView)
MAKE_TO_LOCAL(ToLocal, JSDataView, DataView)
MAKE_TO_LOCAL(ToLocal, JSTypedArray, TypedArray)
MAKE_TO_LOCAL_TYPED_ARRAY(Uint8Array, kExternalUnsignedByteArray)
@ -662,6 +688,24 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) {
}
// Interceptor functions called from generated inline caches to notify
// CPU profiler that external callbacks are invoked.
v8::Handle<v8::Value> InvokeAccessorGetter(
v8::Local<v8::String> property,
const v8::AccessorInfo& info,
v8::AccessorGetter getter);
void InvokeAccessorGetterCallback(
v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value>& info,
v8::AccessorGetterCallback getter);
v8::Handle<v8::Value> InvokeInvocationCallback(const v8::Arguments& args,
v8::InvocationCallback callback);
void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
v8::FunctionCallback callback);
class Testing {
public:
static v8::Testing::StressType stress_type() { return stress_type_; }

14
deps/v8/src/arguments.cc

@ -28,6 +28,8 @@
#include "v8.h"
#include "arguments.h"
#include "vm-state-inl.h"
namespace v8 {
namespace internal {
@ -82,7 +84,7 @@ v8::Handle<V> CustomArguments<T>::GetReturnValue(Isolate* isolate) {
Object** handle = &this->end()[kReturnValueOffset];
// Nothing was set, return empty handle as per previous behaviour.
if ((*handle)->IsTheHole()) return v8::Handle<V>();
return v8::Handle<V>(reinterpret_cast<V*>(handle));
return Utils::Convert<Object, V>(Handle<Object>(handle));
}
@ -90,6 +92,8 @@ v8::Handle<v8::Value> FunctionCallbackArguments::Call(InvocationCallback f) {
Isolate* isolate = this->isolate();
void* f_as_void = CallbackTable::FunctionToVoidPtr(f);
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void);
VMState<EXTERNAL> state(isolate);
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f));
if (new_style) {
FunctionCallback c = reinterpret_cast<FunctionCallback>(f);
FunctionCallbackInfo<v8::Value> info(end(),
@ -114,6 +118,8 @@ v8::Handle<ReturnValue> PropertyCallbackArguments::Call(OldFunction f) { \
Isolate* isolate = this->isolate(); \
void* f_as_void = CallbackTable::FunctionToVoidPtr(f); \
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void); \
VMState<EXTERNAL> state(isolate); \
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); \
if (new_style) { \
NewFunction c = reinterpret_cast<NewFunction>(f); \
PropertyCallbackInfo<ReturnValue> info(end()); \
@ -132,6 +138,8 @@ v8::Handle<ReturnValue> PropertyCallbackArguments::Call(OldFunction f, \
Isolate* isolate = this->isolate(); \
void* f_as_void = CallbackTable::FunctionToVoidPtr(f); \
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void); \
VMState<EXTERNAL> state(isolate); \
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); \
if (new_style) { \
NewFunction c = reinterpret_cast<NewFunction>(f); \
PropertyCallbackInfo<ReturnValue> info(end()); \
@ -151,6 +159,8 @@ v8::Handle<ReturnValue> PropertyCallbackArguments::Call(OldFunction f, \
Isolate* isolate = this->isolate(); \
void* f_as_void = CallbackTable::FunctionToVoidPtr(f); \
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void); \
VMState<EXTERNAL> state(isolate); \
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); \
if (new_style) { \
NewFunction c = reinterpret_cast<NewFunction>(f); \
PropertyCallbackInfo<ReturnValue> info(end()); \
@ -170,6 +180,8 @@ void PropertyCallbackArguments::Call(OldFunction f, \
Isolate* isolate = this->isolate(); \
void* f_as_void = CallbackTable::FunctionToVoidPtr(f); \
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void); \
VMState<EXTERNAL> state(isolate); \
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); \
if (new_style) { \
NewFunction c = reinterpret_cast<NewFunction>(f); \
PropertyCallbackInfo<ReturnValue> info(end()); \

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

@ -149,6 +149,7 @@ Object** RelocInfo::target_object_address() {
void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
ASSERT(!target->IsConsString());
Assembler::set_target_pointer_at(pc_, reinterpret_cast<Address>(target));
if (mode == UPDATE_WRITE_BARRIER &&
host() != NULL &&
@ -179,24 +180,22 @@ void RelocInfo::set_target_runtime_entry(Address target,
}
Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() {
ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
Handle<Cell> RelocInfo::target_cell_handle() {
ASSERT(rmode_ == RelocInfo::CELL);
Address address = Memory::Address_at(pc_);
return Handle<JSGlobalPropertyCell>(
reinterpret_cast<JSGlobalPropertyCell**>(address));
return Handle<Cell>(reinterpret_cast<Cell**>(address));
}
JSGlobalPropertyCell* RelocInfo::target_cell() {
ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
return JSGlobalPropertyCell::FromValueAddress(Memory::Address_at(pc_));
Cell* RelocInfo::target_cell() {
ASSERT(rmode_ == RelocInfo::CELL);
return Cell::FromValueAddress(Memory::Address_at(pc_));
}
void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell,
WriteBarrierMode mode) {
ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
Address address = cell->address() + JSGlobalPropertyCell::kValueOffset;
void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) {
ASSERT(rmode_ == RelocInfo::CELL);
Address address = cell->address() + Cell::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
@ -286,8 +285,8 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
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::CELL) {
visitor->VisitCell(this);
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
visitor->VisitExternalReference(this);
} else if (RelocInfo::IsCodeAgeSequence(mode)) {
@ -314,8 +313,8 @@ void RelocInfo::Visit(Heap* heap) {
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::CELL) {
StaticVisitor::VisitCell(heap, this);
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
StaticVisitor::VisitExternalReference(this);
} else if (RelocInfo::IsCodeAgeSequence(mode)) {

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

@ -36,7 +36,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "arm/assembler-arm-inl.h"
#include "serialize.h"

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

@ -27,7 +27,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "codegen.h"
#include "debug.h"
@ -104,360 +104,6 @@ static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
}
// Allocate an empty JSArray. The allocated array is put into the result
// register. An elements backing store is allocated with size initial_capacity
// and filled with the hole values.
static void AllocateEmptyJSArray(MacroAssembler* masm,
Register array_function,
Register result,
Register scratch1,
Register scratch2,
Register scratch3,
Label* gc_required) {
const int initial_capacity = JSArray::kPreallocatedArrayElements;
STATIC_ASSERT(initial_capacity >= 0);
__ LoadInitialArrayMap(array_function, scratch2, scratch1, false);
// Allocate the JSArray object together with space for a fixed array with the
// requested elements.
int size = JSArray::kSize;
if (initial_capacity > 0) {
size += FixedArray::SizeFor(initial_capacity);
}
__ Allocate(size, result, scratch2, scratch3, gc_required, TAG_OBJECT);
// Allocated the JSArray. Now initialize the fields except for the elements
// array.
// result: JSObject
// scratch1: initial map
// scratch2: start of next object
__ str(scratch1, FieldMemOperand(result, JSObject::kMapOffset));
__ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
__ str(scratch1, FieldMemOperand(result, JSArray::kPropertiesOffset));
// Field JSArray::kElementsOffset is initialized later.
__ mov(scratch3, Operand::Zero());
__ str(scratch3, FieldMemOperand(result, JSArray::kLengthOffset));
if (initial_capacity == 0) {
__ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset));
return;
}
// Calculate the location of the elements array and set elements array member
// of the JSArray.
// result: JSObject
// scratch2: start of next object
__ add(scratch1, result, Operand(JSArray::kSize));
__ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset));
// Clear the heap tag on the elements array.
__ sub(scratch1, scratch1, Operand(kHeapObjectTag));
// Initialize the FixedArray and fill it with holes. FixedArray length is
// stored as a smi.
// result: JSObject
// scratch1: elements array (untagged)
// scratch2: start of next object
__ LoadRoot(scratch3, Heap::kFixedArrayMapRootIndex);
STATIC_ASSERT(0 * kPointerSize == FixedArray::kMapOffset);
__ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
__ mov(scratch3, Operand(Smi::FromInt(initial_capacity)));
STATIC_ASSERT(1 * kPointerSize == FixedArray::kLengthOffset);
__ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
// Fill the FixedArray with the hole value. Inline the code if short.
STATIC_ASSERT(2 * kPointerSize == FixedArray::kHeaderSize);
__ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
static const int kLoopUnfoldLimit = 4;
if (initial_capacity <= kLoopUnfoldLimit) {
for (int i = 0; i < initial_capacity; i++) {
__ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
}
} else {
Label loop, entry;
__ add(scratch2, scratch1, Operand(initial_capacity * kPointerSize));
__ b(&entry);
__ bind(&loop);
__ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
__ bind(&entry);
__ cmp(scratch1, scratch2);
__ b(lt, &loop);
}
}
// Allocate a JSArray with the number of elements stored in a register. The
// register array_function holds the built-in Array function and the register
// array_size holds the size of the array as a smi. The allocated array is put
// into the result register and beginning and end of the FixedArray elements
// storage is put into registers elements_array_storage and elements_array_end
// (see below for when that is not the case). If the parameter fill_with_holes
// is true the allocated elements backing store is filled with the hole values
// otherwise it is left uninitialized. When the backing store is filled the
// register elements_array_storage is scratched.
static void AllocateJSArray(MacroAssembler* masm,
Register array_function, // Array function.
Register array_size, // As a smi, cannot be 0.
Register result,
Register elements_array_storage,
Register elements_array_end,
Register scratch1,
Register scratch2,
bool fill_with_hole,
Label* gc_required) {
// Load the initial map from the array function.
__ LoadInitialArrayMap(array_function, scratch2,
elements_array_storage, fill_with_hole);
if (FLAG_debug_code) { // Assert that array size is not zero.
__ tst(array_size, array_size);
__ Assert(ne, "array size is unexpectedly 0");
}
// Allocate the JSArray object together with space for a FixedArray with the
// requested number of elements.
__ mov(elements_array_end,
Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize));
__ add(elements_array_end, elements_array_end, Operand::SmiUntag(array_size));
__ Allocate(elements_array_end,
result,
scratch1,
scratch2,
gc_required,
static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
// Allocated the JSArray. Now initialize the fields except for the elements
// array.
// result: JSObject
// elements_array_storage: initial map
// array_size: size of array (smi)
__ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset));
__ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex);
__ str(elements_array_storage,
FieldMemOperand(result, JSArray::kPropertiesOffset));
// Field JSArray::kElementsOffset is initialized later.
__ str(array_size, FieldMemOperand(result, JSArray::kLengthOffset));
// Calculate the location of the elements array and set elements array member
// of the JSArray.
// result: JSObject
// array_size: size of array (smi)
__ add(elements_array_storage, result, Operand(JSArray::kSize));
__ str(elements_array_storage,
FieldMemOperand(result, JSArray::kElementsOffset));
// Clear the heap tag on the elements array.
__ sub(elements_array_storage,
elements_array_storage,
Operand(kHeapObjectTag));
// Initialize the fixed array and fill it with holes. FixedArray length is
// stored as a smi.
// result: JSObject
// elements_array_storage: elements array (untagged)
// array_size: size of array (smi)
__ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex);
ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
__ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex));
ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
__ str(array_size,
MemOperand(elements_array_storage, kPointerSize, PostIndex));
// Calculate elements array and elements array end.
// result: JSObject
// elements_array_storage: elements array element storage
// array_size: smi-tagged size of elements array
__ add(elements_array_end,
elements_array_storage,
Operand::PointerOffsetFromSmiKey(array_size));
// Fill the allocated FixedArray with the hole value if requested.
// result: JSObject
// elements_array_storage: elements array element storage
// elements_array_end: start of next object
if (fill_with_hole) {
Label loop, entry;
__ LoadRoot(scratch1, Heap::kTheHoleValueRootIndex);
__ jmp(&entry);
__ bind(&loop);
__ str(scratch1,
MemOperand(elements_array_storage, kPointerSize, PostIndex));
__ bind(&entry);
__ cmp(elements_array_storage, elements_array_end);
__ b(lt, &loop);
}
}
// Create a new array for the built-in Array function. This function allocates
// the JSArray object and the FixedArray elements array and initializes these.
// If the Array cannot be constructed in native code the runtime is called. This
// function assumes the following state:
// r0: argc
// r1: constructor (built-in Array function)
// lr: return address
// sp[0]: last argument
// This function is used for both construct and normal calls of Array. The only
// difference between handling a construct call and a normal call is that for a
// construct call the constructor function in r1 needs to be preserved for
// entering the generic code. In both cases argc in r0 needs to be preserved.
// Both registers are preserved by this code so no need to differentiate between
// construct call and normal call.
void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code) {
Counters* counters = masm->isolate()->counters();
Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array,
has_non_smi_element, finish, cant_transition_map, not_double;
// Check for array construction with zero arguments or one.
__ cmp(r0, Operand::Zero());
__ b(ne, &argc_one_or_more);
// Handle construction of an empty array.
__ bind(&empty_array);
AllocateEmptyJSArray(masm,
r1,
r2,
r3,
r4,
r5,
call_generic_code);
__ IncrementCounter(counters->array_function_native(), 1, r3, r4);
// Set up return value, remove receiver from stack and return.
__ mov(r0, r2);
__ add(sp, sp, Operand(kPointerSize));
__ Jump(lr);
// Check for one argument. Bail out if argument is not smi or if it is
// negative.
__ bind(&argc_one_or_more);
__ cmp(r0, Operand(1));
__ b(ne, &argc_two_or_more);
__ ldr(r2, MemOperand(sp)); // Get the argument from the stack.
__ tst(r2, r2);
__ b(ne, &not_empty_array);
__ Drop(1); // Adjust stack.
__ mov(r0, Operand::Zero()); // Treat this as a call with argc of zero.
__ b(&empty_array);
__ bind(&not_empty_array);
STATIC_ASSERT(kSmiTag == 0);
__ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC);
__ b(ne, call_generic_code);
// Handle construction of an empty array of a certain size. Bail out if size
// is too large to actually allocate an elements array.
STATIC_ASSERT(kSmiTag == 0);
__ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize));
__ b(ge, call_generic_code);
// r0: argc
// r1: constructor
// r2: array_size (smi)
// sp[0]: argument
AllocateJSArray(masm,
r1,
r2,
r3,
r4,
r5,
r6,
r7,
true,
call_generic_code);
__ IncrementCounter(counters->array_function_native(), 1, r2, r4);
// Set up return value, remove receiver and argument from stack and return.
__ mov(r0, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
__ Jump(lr);
// Handle construction of an array from a list of arguments.
__ bind(&argc_two_or_more);
__ SmiTag(r2, r0);
// r0: argc
// r1: constructor
// r2: array_size (smi)
// sp[0]: last argument
AllocateJSArray(masm,
r1,
r2,
r3,
r4,
r5,
r6,
r7,
false,
call_generic_code);
__ IncrementCounter(counters->array_function_native(), 1, r2, r6);
// Fill arguments as array elements. Copy from the top of the stack (last
// element) to the array backing store filling it backwards. Note:
// elements_array_end points after the backing store therefore PreIndex is
// used when filling the backing store.
// r0: argc
// r3: JSArray
// r4: elements_array storage start (untagged)
// r5: elements_array_end (untagged)
// sp[0]: last argument
Label loop, entry;
__ mov(r7, sp);
__ jmp(&entry);
__ bind(&loop);
__ ldr(r2, MemOperand(r7, kPointerSize, PostIndex));
if (FLAG_smi_only_arrays) {
__ JumpIfNotSmi(r2, &has_non_smi_element);
}
__ str(r2, MemOperand(r5, -kPointerSize, PreIndex));
__ bind(&entry);
__ cmp(r4, r5);
__ b(lt, &loop);
__ bind(&finish);
__ mov(sp, r7);
// Remove caller arguments and receiver from the stack, setup return value and
// return.
// r0: argc
// r3: JSArray
// sp[0]: receiver
__ add(sp, sp, Operand(kPointerSize));
__ mov(r0, r3);
__ Jump(lr);
__ bind(&has_non_smi_element);
// Double values are handled by the runtime.
__ CheckMap(
r2, r9, Heap::kHeapNumberMapRootIndex, &not_double, DONT_DO_SMI_CHECK);
__ bind(&cant_transition_map);
__ UndoAllocationInNewSpace(r3, r4);
__ b(call_generic_code);
__ bind(&not_double);
// Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS.
// r3: JSArray
__ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
__ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
r2,
r9,
&cant_transition_map);
__ str(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
__ RecordWriteField(r3,
HeapObject::kMapOffset,
r2,
r9,
kLRHasNotBeenSaved,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
Label loop2;
__ sub(r7, r7, Operand(kPointerSize));
__ bind(&loop2);
__ ldr(r2, MemOperand(r7, kPointerSize, PostIndex));
__ str(r2, MemOperand(r5, -kPointerSize, PreIndex));
__ cmp(r4, r5);
__ b(lt, &loop2);
__ b(&finish);
}
void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : number of arguments
@ -480,20 +126,9 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
// Run the native code for the InternalArray function called as a normal
// function.
if (FLAG_optimize_constructed_arrays) {
// tail call a stub
InternalArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
} else {
ArrayNativeCode(masm, &generic_array_code);
// Jump to the generic array code if the specialized code cannot handle the
// construction.
__ bind(&generic_array_code);
Handle<Code> array_code =
masm->isolate()->builtins()->InternalArrayCodeGeneric();
__ Jump(array_code, RelocInfo::CODE_TARGET);
}
// tail call a stub
InternalArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
}
@ -518,56 +153,13 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
}
// Run the native code for the Array function called as a normal function.
if (FLAG_optimize_constructed_arrays) {
// tail call a stub
Handle<Object> undefined_sentinel(
masm->isolate()->heap()->undefined_value(),
masm->isolate());
__ mov(r2, Operand(undefined_sentinel));
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
} else {
ArrayNativeCode(masm, &generic_array_code);
// Jump to the generic array code if the specialized code cannot handle
// the construction.
__ bind(&generic_array_code);
Handle<Code> array_code =
masm->isolate()->builtins()->ArrayCodeGeneric();
__ Jump(array_code, RelocInfo::CODE_TARGET);
}
}
void Builtins::Generate_CommonArrayConstructCode(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : number of arguments
// -- r1 : constructor function
// -- r2 : type info cell
// -- lr : return address
// -- sp[...]: constructor arguments
// -----------------------------------
if (FLAG_debug_code) {
// The array construct code is only set for the builtin and internal
// Array functions which always have a map.
// Initial map for the builtin Array function should be a map.
__ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
__ SmiTst(r3);
__ Assert(ne, "Unexpected initial map for Array function");
__ CompareObjectType(r3, r3, r4, MAP_TYPE);
__ Assert(eq, "Unexpected initial map for Array function");
}
Label generic_constructor;
// Run the native code for the Array function called as a constructor.
ArrayNativeCode(masm, &generic_constructor);
// Jump to the generic construct code in case the specialized code cannot
// handle the construction.
__ bind(&generic_constructor);
Handle<Code> generic_construct_stub =
masm->isolate()->builtins()->JSConstructStubGeneric();
__ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
// tail call a stub
Handle<Object> undefined_sentinel(
masm->isolate()->heap()->undefined_value(),
masm->isolate());
__ mov(r2, Operand(undefined_sentinel));
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
}
@ -1125,6 +717,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// r3: argc
// r4: argv
// r5-r7, cp may be clobbered
ProfileEntryHookStub::MaybeCallEntryHook(masm);
// Clear the context before we push it when entering the internal frame.
__ mov(cp, Operand::Zero());

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

@ -27,7 +27,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "bootstrapper.h"
#include "code-stubs.h"
@ -892,12 +892,17 @@ static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
// Now that we have the types we might as well check for
// internalized-internalized.
// Ensure that no non-strings have the internalized bit set.
STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsInternalizedMask);
Label not_internalized;
STATIC_ASSERT(kInternalizedTag != 0);
__ and_(r2, r2, Operand(r3));
__ tst(r2, Operand(kIsInternalizedMask));
__ b(ne, &return_not_equal);
__ and_(r2, r2, Operand(kIsNotStringMask | kIsInternalizedMask));
__ cmp(r2, Operand(kInternalizedTag | kStringTag));
__ b(ne, &not_internalized); // r2 (rhs) is not an internalized string
__ and_(r3, r3, Operand(kIsNotStringMask | kIsInternalizedMask));
__ cmp(r3, Operand(kInternalizedTag | kStringTag));
__ b(eq, &return_not_equal); // both rhs and lhs are internalized strings
__ bind(&not_internalized);
}
@ -937,7 +942,6 @@ static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
(lhs.is(r1) && rhs.is(r0)));
// r2 is object type of rhs.
// Ensure that no non-strings have the internalized bit set.
Label object_test;
STATIC_ASSERT(kInternalizedTag != 0);
__ tst(r2, Operand(kIsNotStringMask));
@ -2075,7 +2079,7 @@ void BinaryOpStub_GenerateSmiCode(
void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
Label right_arg_changed, call_runtime;
if (op_ == Token::MOD && has_fixed_right_arg_) {
if (op_ == Token::MOD && encoded_right_arg_.has_value) {
// It is guaranteed that the value will fit into a Smi, because if it
// didn't, we wouldn't be here, see BinaryOp_Patch.
__ cmp(r0, Operand(Smi::FromInt(fixed_right_arg_value())));
@ -2252,7 +2256,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
// to type transition.
} else {
if (has_fixed_right_arg_) {
if (encoded_right_arg_.has_value) {
__ Vmov(d8, fixed_right_arg_value(), scratch1);
__ VFPCompareAndSetFlags(d1, d8);
__ b(ne, &transition);
@ -2996,9 +3000,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
if (FLAG_optimize_constructed_arrays) {
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
}
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
}
@ -3075,7 +3077,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ mov(r0, Operand(r4));
__ mov(r1, Operand(r6));
#if defined(V8_HOST_ARCH_ARM)
#if V8_HOST_ARCH_ARM
int frame_alignment = MacroAssembler::ActivationFrameAlignment();
int frame_alignment_mask = frame_alignment - 1;
if (FLAG_debug_code) {
@ -3179,6 +3181,8 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// sp: stack pointer (restored as callee's sp after C call)
// cp: current context (C callee-saved)
ProfileEntryHookStub::MaybeCallEntryHook(masm);
// Result returned in r0 or r0+r1 by default.
// NOTE: Invocations of builtins may return failure objects
@ -3269,6 +3273,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
Label invoke, handler_entry, exit;
ProfileEntryHookStub::MaybeCallEntryHook(masm);
// Called from C, so do not pop argc and args on exit (preserve sp)
// No need to save register-passed args
// Save callee-saved registers (incl. cp and fp), sp, and lr
@ -3504,7 +3510,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Get the map location in scratch and patch it.
__ GetRelocatedValueLocation(inline_site, scratch);
__ ldr(scratch, MemOperand(scratch));
__ str(map, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
__ str(map, FieldMemOperand(scratch, Cell::kValueOffset));
}
// Register mapping: r3 is object map and r4 is function prototype.
@ -4623,52 +4629,12 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
}
static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) {
// Cache the called function in a global property cell. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// r1 : the function to call
// r2 : cache cell for call target
Label done;
ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
masm->isolate()->heap()->undefined_value());
ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
masm->isolate()->heap()->the_hole_value());
// Load the cache state into r3.
__ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
// A monomorphic cache hit or an already megamorphic state: invoke the
// function without changing the state.
__ cmp(r3, r1);
__ b(eq, &done);
__ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
__ b(eq, &done);
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
// megamorphic.
__ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
// MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed.
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex, ne);
__ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset), ne);
// An uninitialized cache is patched with the function.
__ str(r1, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset), eq);
// No need for a write barrier here - cells are rescanned.
__ bind(&done);
}
static void GenerateRecordCallTarget(MacroAssembler* masm) {
// Cache the called function in a global property cell. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// r1 : the function to call
// r2 : cache cell for call target
ASSERT(FLAG_optimize_constructed_arrays);
Label initialize, done, miss, megamorphic, not_array_function;
ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
@ -4677,7 +4643,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
masm->isolate()->heap()->the_hole_value());
// Load the cache state into r3.
__ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
// A monomorphic cache hit or an already megamorphic state: invoke the
// function without changing the state.
@ -4689,12 +4655,15 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// Special handling of the Array() function, which caches not only the
// monomorphic Array function but the initial ElementsKind with special
// sentinels
Handle<Object> terminal_kind_sentinel =
TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
LAST_FAST_ELEMENTS_KIND);
__ JumpIfNotSmi(r3, &miss);
__ cmp(r3, Operand(terminal_kind_sentinel));
__ b(gt, &miss);
if (FLAG_debug_code) {
Handle<Object> terminal_kind_sentinel =
TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
LAST_FAST_ELEMENTS_KIND);
__ cmp(r3, Operand(terminal_kind_sentinel));
__ Assert(le, "Array function sentinel is not an ElementsKind");
}
// Make sure the function is the Array() function
__ LoadArrayFunction(r3);
__ cmp(r1, r3);
@ -4711,7 +4680,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// write-barrier is needed.
__ bind(&megamorphic);
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ str(ip, FieldMemOperand(r2, Cell::kValueOffset));
__ jmp(&done);
// An uninitialized cache is patched with the function or sentinel to
@ -4729,11 +4698,11 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
GetInitialFastElementsKind());
__ mov(r3, Operand(initial_kind_sentinel));
__ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ str(r3, FieldMemOperand(r2, Cell::kValueOffset));
__ b(&done);
__ bind(&not_array_function);
__ str(r1, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ str(r1, FieldMemOperand(r2, Cell::kValueOffset));
// No need for a write barrier here - cells are rescanned.
__ bind(&done);
@ -4772,11 +4741,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ b(ne, &slow);
if (RecordCallTarget()) {
if (FLAG_optimize_constructed_arrays) {
GenerateRecordCallTarget(masm);
} else {
GenerateRecordCallTargetNoArray(masm);
}
GenerateRecordCallTarget(masm);
}
// Fast-case: Invoke the function now.
@ -4809,7 +4774,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
masm->isolate()->heap()->undefined_value());
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ str(ip, FieldMemOperand(r2, Cell::kValueOffset));
}
// Check for function proxy.
__ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
@ -4851,15 +4816,11 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ b(ne, &slow);
if (RecordCallTarget()) {
if (FLAG_optimize_constructed_arrays) {
GenerateRecordCallTarget(masm);
} else {
GenerateRecordCallTargetNoArray(masm);
}
GenerateRecordCallTarget(masm);
}
// Jump to the function-specific construct stub.
Register jmp_reg = FLAG_optimize_constructed_arrays ? r3 : r2;
Register jmp_reg = r3;
__ ldr(jmp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(jmp_reg, FieldMemOperand(jmp_reg,
SharedFunctionInfo::kConstructStubOffset));
@ -6263,9 +6224,14 @@ void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
__ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
__ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
STATIC_ASSERT(kInternalizedTag != 0);
__ and_(tmp1, tmp1, Operand(tmp2));
__ tst(tmp1, Operand(kIsInternalizedMask));
__ b(eq, &miss);
__ and_(tmp1, tmp1, Operand(kIsNotStringMask | kIsInternalizedMask));
__ cmp(tmp1, Operand(kInternalizedTag | kStringTag));
__ b(ne, &miss);
__ and_(tmp2, tmp2, Operand(kIsNotStringMask | kIsInternalizedMask));
__ cmp(tmp2, Operand(kInternalizedTag | kStringTag));
__ b(ne, &miss);
// Internalized strings are compared by identity.
__ cmp(left, right);
@ -6304,19 +6270,8 @@ void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
__ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
__ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
Label succeed1;
__ tst(tmp1, Operand(kIsInternalizedMask));
__ b(ne, &succeed1);
__ cmp(tmp1, Operand(SYMBOL_TYPE));
__ b(ne, &miss);
__ bind(&succeed1);
Label succeed2;
__ tst(tmp2, Operand(kIsInternalizedMask));
__ b(ne, &succeed2);
__ cmp(tmp2, Operand(SYMBOL_TYPE));
__ b(ne, &miss);
__ bind(&succeed2);
__ JumpIfNotUniqueName(tmp1, &miss);
__ JumpIfNotUniqueName(tmp2, &miss);
// Unique names are compared by identity.
__ cmp(left, right);
@ -6371,7 +6326,8 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
// Handle not identical strings.
// Check that both strings are internalized strings. If they are, we're done
// because we already know they are not identical.
// because we already know they are not identical. We know they are both
// strings.
if (equality) {
ASSERT(GetCondition() == eq);
STATIC_ASSERT(kInternalizedTag != 0);
@ -6481,13 +6437,6 @@ void DirectCEntryStub::Generate(MacroAssembler* masm) {
}
void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
ExternalReference function) {
__ mov(r2, Operand(function));
GenerateCall(masm, r2);
}
void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
Register target) {
intptr_t code =
@ -6564,11 +6513,7 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
__ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
__ ldrb(entity_name,
FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
__ tst(entity_name, Operand(kIsInternalizedMask));
__ b(ne, &good);
__ cmp(entity_name, Operand(SYMBOL_TYPE));
__ b(ne, miss);
__ JumpIfNotUniqueName(entity_name, miss);
__ bind(&good);
// Restore the properties.
@ -6735,15 +6680,10 @@ void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
// Check if the entry name is not a unique name.
Label cont;
__ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
__ ldrb(entry_key,
FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
__ tst(entry_key, Operand(kIsInternalizedMask));
__ b(ne, &cont);
__ cmp(entry_key, Operand(SYMBOL_TYPE));
__ b(ne, &maybe_in_dictionary);
__ bind(&cont);
__ JumpIfNotUniqueName(entry_key, &maybe_in_dictionary);
}
}
@ -7062,10 +7002,10 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : element value to store
// -- r1 : array literal
// -- r2 : map of array literal
// -- r3 : element index as smi
// -- r4 : array literal index in function as smi
// -- sp[0] : array literal index in function as smi
// -- sp[4] : array literal
// clobbers r1, r2, r4
// -----------------------------------
Label element_done;
@ -7074,6 +7014,11 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
Label slow_elements;
Label fast_elements;
// Get array literal index, array literal and its map.
__ ldr(r4, MemOperand(sp, 0 * kPointerSize));
__ ldr(r1, MemOperand(sp, 1 * kPointerSize));
__ ldr(r2, FieldMemOperand(r1, JSObject::kMapOffset));
__ CheckFastElements(r2, r5, &double_elements);
// FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS
__ JumpIfSmi(r0, &smi_element);
@ -7133,8 +7078,9 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
if (entry_hook_ != NULL) {
if (masm->isolate()->function_entry_hook() != NULL) {
PredictableCodeSizeScope predictable(masm, 4 * Assembler::kInstrSize);
AllowStubCallsScope allow_stub_calls(masm, true);
ProfileEntryHookStub stub;
__ push(lr);
__ CallStub(&stub);
@ -7148,9 +7094,21 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
const int32_t kReturnAddressDistanceFromFunctionStart =
3 * Assembler::kInstrSize;
// Save live volatile registers.
__ Push(lr, r5, r1);
const int32_t kNumSavedRegs = 3;
// This should contain all kCallerSaved registers.
const RegList kSavedRegs =
1 << 0 | // r0
1 << 1 | // r1
1 << 2 | // r2
1 << 3 | // r3
1 << 5 | // r5
1 << 9; // r9
// We also save lr, so the count here is one higher than the mask indicates.
const int32_t kNumSavedRegs = 7;
ASSERT((kCallerSaved & kSavedRegs) == kCallerSaved);
// Save all caller-save registers as this may be called from anywhere.
__ stm(db_w, sp, kSavedRegs | lr.bit());
// Compute the function's address for the first argument.
__ sub(r0, lr, Operand(kReturnAddressDistanceFromFunctionStart));
@ -7167,15 +7125,14 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
__ and_(sp, sp, Operand(-frame_alignment));
}
#if defined(V8_HOST_ARCH_ARM)
__ mov(ip, Operand(reinterpret_cast<int32_t>(&entry_hook_)));
__ ldr(ip, MemOperand(ip));
#if V8_HOST_ARCH_ARM
int32_t entry_hook =
reinterpret_cast<int32_t>(masm->isolate()->function_entry_hook());
__ mov(ip, Operand(entry_hook));
#else
// Under the simulator we need to indirect the entry hook through a
// trampoline function at a known address.
Address trampoline_address = reinterpret_cast<Address>(
reinterpret_cast<intptr_t>(EntryHookTrampoline));
ApiFunction dispatcher(trampoline_address);
ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
__ mov(ip, Operand(ExternalReference(&dispatcher,
ExternalReference::BUILTIN_CALL,
masm->isolate())));
@ -7187,8 +7144,8 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
__ mov(sp, r5);
}
__ Pop(lr, r5, r1);
__ Ret();
// Also pop pc to get Ret(0).
__ ldm(ia_w, sp, kSavedRegs | pc.bit());
}
@ -7244,6 +7201,10 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
__ cmp(r2, Operand(undefined_sentinel));
__ b(eq, &normal_sequence);
// The type cell may have gone megamorphic, don't overwrite if so
__ ldr(r5, FieldMemOperand(r2, kPointerSize));
__ JumpIfNotSmi(r5, &normal_sequence);
// Save the resulting elements kind in type info
__ SmiTag(r3);
__ str(r3, FieldMemOperand(r2, kPointerSize));
@ -7276,7 +7237,7 @@ static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
T stub(kind);
stub.GetCode(isolate)->set_is_pregenerated(true);
if (AllocationSiteInfo::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
T stub1(kind, true);
T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
stub1.GetCode(isolate)->set_is_pregenerated(true);
}
}
@ -7332,64 +7293,50 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
__ CompareObjectType(r3, r3, r4, MAP_TYPE);
__ Assert(eq, "Unexpected initial map for Array function");
// We should either have undefined in ebx or a valid jsglobalpropertycell
// We should either have undefined in ebx or a valid cell
Label okay_here;
Handle<Map> global_property_cell_map(
masm->isolate()->heap()->global_property_cell_map());
Handle<Map> cell_map = masm->isolate()->factory()->cell_map();
__ cmp(r2, Operand(undefined_sentinel));
__ b(eq, &okay_here);
__ ldr(r3, FieldMemOperand(r2, 0));
__ cmp(r3, Operand(global_property_cell_map));
__ cmp(r3, Operand(cell_map));
__ Assert(eq, "Expected property cell in register ebx");
__ bind(&okay_here);
}
if (FLAG_optimize_constructed_arrays) {
Label no_info, switch_ready;
// Get the elements kind and case on that.
__ cmp(r2, Operand(undefined_sentinel));
__ b(eq, &no_info);
__ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ JumpIfNotSmi(r3, &no_info);
__ SmiUntag(r3);
__ jmp(&switch_ready);
__ bind(&no_info);
__ mov(r3, Operand(GetInitialFastElementsKind()));
__ bind(&switch_ready);
if (argument_count_ == ANY) {
Label not_zero_case, not_one_case;
__ tst(r0, r0);
__ b(ne, &not_zero_case);
CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
__ bind(&not_zero_case);
__ cmp(r0, Operand(1));
__ b(gt, &not_one_case);
CreateArrayDispatchOneArgument(masm);
__ bind(&not_one_case);
CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
} else if (argument_count_ == NONE) {
CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
} else if (argument_count_ == ONE) {
CreateArrayDispatchOneArgument(masm);
} else if (argument_count_ == MORE_THAN_ONE) {
CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
} else {
UNREACHABLE();
}
Label no_info, switch_ready;
// Get the elements kind and case on that.
__ cmp(r2, Operand(undefined_sentinel));
__ b(eq, &no_info);
__ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
__ JumpIfNotSmi(r3, &no_info);
__ SmiUntag(r3);
__ jmp(&switch_ready);
__ bind(&no_info);
__ mov(r3, Operand(GetInitialFastElementsKind()));
__ bind(&switch_ready);
if (argument_count_ == ANY) {
Label not_zero_case, not_one_case;
__ tst(r0, r0);
__ b(ne, &not_zero_case);
CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
__ bind(&not_zero_case);
__ cmp(r0, Operand(1));
__ b(gt, &not_one_case);
CreateArrayDispatchOneArgument(masm);
__ bind(&not_one_case);
CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
} else if (argument_count_ == NONE) {
CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
} else if (argument_count_ == ONE) {
CreateArrayDispatchOneArgument(masm);
} else if (argument_count_ == MORE_THAN_ONE) {
CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
} else {
Label generic_constructor;
// Run the native code for the Array function called as a constructor.
ArrayNativeCode(masm, &generic_constructor);
// Jump to the generic construct code in case the specialized code cannot
// handle the construction.
__ bind(&generic_constructor);
Handle<Code> generic_construct_stub =
masm->isolate()->builtins()->JSConstructStubGeneric();
__ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
UNREACHABLE();
}
}
@ -7451,45 +7398,31 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
__ Assert(eq, "Unexpected initial map for Array function");
}
if (FLAG_optimize_constructed_arrays) {
// Figure out the right elements kind
__ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
// Load the map's "bit field 2" into |result|. We only need the first byte,
// but the following bit field extraction takes care of that anyway.
__ ldr(r3, FieldMemOperand(r3, Map::kBitField2Offset));
// Retrieve elements_kind from bit field 2.
__ Ubfx(r3, r3, Map::kElementsKindShift, Map::kElementsKindBitCount);
if (FLAG_debug_code) {
Label done;
__ cmp(r3, Operand(FAST_ELEMENTS));
__ b(eq, &done);
__ cmp(r3, Operand(FAST_HOLEY_ELEMENTS));
__ Assert(eq,
"Invalid ElementsKind for InternalArray or InternalPackedArray");
__ bind(&done);
}
// Figure out the right elements kind
__ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
// Load the map's "bit field 2" into |result|. We only need the first byte,
// but the following bit field extraction takes care of that anyway.
__ ldr(r3, FieldMemOperand(r3, Map::kBitField2Offset));
// Retrieve elements_kind from bit field 2.
__ Ubfx(r3, r3, Map::kElementsKindShift, Map::kElementsKindBitCount);
Label fast_elements_case;
if (FLAG_debug_code) {
Label done;
__ cmp(r3, Operand(FAST_ELEMENTS));
__ b(eq, &fast_elements_case);
GenerateCase(masm, FAST_HOLEY_ELEMENTS);
__ b(eq, &done);
__ cmp(r3, Operand(FAST_HOLEY_ELEMENTS));
__ Assert(eq,
"Invalid ElementsKind for InternalArray or InternalPackedArray");
__ bind(&done);
}
__ bind(&fast_elements_case);
GenerateCase(masm, FAST_ELEMENTS);
} else {
Label generic_constructor;
// Run the native code for the Array function called as constructor.
ArrayNativeCode(masm, &generic_constructor);
Label fast_elements_case;
__ cmp(r3, Operand(FAST_ELEMENTS));
__ b(eq, &fast_elements_case);
GenerateCase(masm, FAST_HOLEY_ELEMENTS);
// Jump to the generic construct code in case the specialized code cannot
// handle the construction.
__ bind(&generic_constructor);
Handle<Code> generic_construct_stub =
masm->isolate()->builtins()->JSConstructStubGeneric();
__ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
}
__ bind(&fast_elements_case);
GenerateCase(masm, FAST_ELEMENTS);
}

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

@ -585,7 +585,6 @@ class DirectCEntryStub: public PlatformCodeStub {
public:
DirectCEntryStub() {}
void Generate(MacroAssembler* masm);
void GenerateCall(MacroAssembler* masm, ExternalReference function);
void GenerateCall(MacroAssembler* masm, Register target);
private:

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

@ -27,7 +27,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "codegen.h"
#include "macro-assembler.h"

2
deps/v8/src/arm/constants-arm.cc

@ -27,7 +27,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "constants-arm.h"

2
deps/v8/src/arm/cpu-arm.cc

@ -32,7 +32,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "cpu.h"
#include "macro-assembler.h"

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

@ -27,7 +27,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "codegen.h"
#include "debug.h"

2
deps/v8/src/arm/disasm-arm.cc

@ -56,7 +56,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "constants-arm.h"
#include "disasm.h"

9
deps/v8/src/arm/frames-arm.cc

@ -27,12 +27,12 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "assembler.h"
#include "assembler-arm.h"
#include "assembler-arm-inl.h"
#include "frames-inl.h"
#include "frames.h"
#include "macro-assembler.h"
#include "macro-assembler-arm.h"
@ -40,11 +40,6 @@ namespace v8 {
namespace internal {
Address ExitFrame::ComputeStackPointer(Address fp) {
return Memory::Address_at(fp + ExitFrameConstants::kSPOffset);
}
Register JavaScriptFrame::fp_register() { return v8::internal::fp; }
Register JavaScriptFrame::context_register() { return cp; }

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

@ -27,7 +27,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "code-stubs.h"
#include "codegen.h"
@ -129,7 +129,7 @@ void FullCodeGenerator::Generate() {
CompilationInfo* info = info_;
handler_table_ =
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell(
profiling_counter_ = isolate()->factory()->NewCell(
Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
SetFunctionPosition(function());
Comment cmnt(masm_, "[ function compiled by full code generator");
@ -327,9 +327,9 @@ void FullCodeGenerator::ClearAccumulator() {
void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
__ mov(r2, Operand(profiling_counter_));
__ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
__ sub(r3, r3, Operand(Smi::FromInt(delta)), SetCC);
__ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ str(r3, FieldMemOperand(r2, Cell::kValueOffset));
}
@ -345,7 +345,7 @@ void FullCodeGenerator::EmitProfilingCounterReset() {
}
__ mov(r2, Operand(profiling_counter_));
__ mov(r3, Operand(Smi::FromInt(reset_value)));
__ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ str(r3, FieldMemOperand(r2, Cell::kValueOffset));
}
@ -361,7 +361,7 @@ void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
ASSERT(back_edge_target->is_bound());
int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
weight = Min(kMaxBackEdgeWeight,
Max(1, distance / kBackEdgeDistanceUnit));
Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
__ b(pl, &ok);
@ -404,7 +404,7 @@ void FullCodeGenerator::EmitReturnSequence() {
} else if (FLAG_weighted_back_edges) {
int distance = masm_->pc_offset();
weight = Min(kMaxBackEdgeWeight,
Max(1, distance / kBackEdgeDistanceUnit));
Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
Label ok;
@ -1164,15 +1164,13 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
Label non_proxy;
__ bind(&fixed_array);
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(
Handle<Object>(
Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker),
isolate()));
Handle<Cell> cell = isolate()->factory()->NewCell(
Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker),
isolate()));
RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell);
__ LoadHeapObject(r1, cell);
__ mov(r2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker)));
__ str(r2, FieldMemOperand(r1, JSGlobalPropertyCell::kValueOffset));
__ str(r2, FieldMemOperand(r1, Cell::kValueOffset));
__ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check
__ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object
@ -1694,10 +1692,10 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
if (key->handle()->IsInternalizedString()) {
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
__ mov(r2, Operand(key->handle()));
__ mov(r2, Operand(key->value()));
__ ldr(r1, MemOperand(sp));
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
@ -1831,20 +1829,18 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Expression* subexpr = subexprs->at(i);
// If the subexpression is a literal or a simple materialized literal it
// is already set in the cloned array.
if (subexpr->AsLiteral() != NULL ||
CompileTimeValue::IsCompileTimeValue(subexpr)) {
continue;
}
if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
if (!result_saved) {
__ push(r0);
__ Push(Smi::FromInt(expr->literal_index()));
result_saved = true;
}
VisitForAccumulatorValue(subexpr);
if (IsFastObjectElementsKind(constant_elements_kind)) {
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ ldr(r6, MemOperand(sp)); // Copy of array literal.
__ ldr(r6, MemOperand(sp, kPointerSize)); // Copy of array literal.
__ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset));
__ str(result_register(), FieldMemOperand(r1, offset));
// Update the write barrier for the array store.
@ -1852,10 +1848,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
kLRHasBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
} else {
__ ldr(r1, MemOperand(sp)); // Copy of array literal.
__ ldr(r2, FieldMemOperand(r1, JSObject::kMapOffset));
__ mov(r3, Operand(Smi::FromInt(i)));
__ mov(r4, Operand(Smi::FromInt(expr->literal_index())));
StoreArrayLiteralElementStub stub;
__ CallStub(&stub);
}
@ -1864,6 +1857,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
}
if (result_saved) {
__ pop(); // literal index
context()->PlugTOS();
} else {
context()->Plug(r0);
@ -1991,22 +1985,37 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
VisitForStackValue(expr->expression());
switch (expr->yield_kind()) {
case Yield::INITIAL:
case Yield::SUSPEND: {
VisitForStackValue(expr->generator_object());
case Yield::SUSPEND:
// Pop value from top-of-stack slot; box result into result register.
EmitCreateIteratorResult(false);
__ push(result_register());
// Fall through.
case Yield::INITIAL: {
Label suspend, continuation, post_runtime, resume;
__ jmp(&suspend);
__ bind(&continuation);
__ jmp(&resume);
__ bind(&suspend);
VisitForAccumulatorValue(expr->generator_object());
ASSERT(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
__ mov(r1, Operand(Smi::FromInt(continuation.pos())));
__ str(r1, FieldMemOperand(r0, JSGeneratorObject::kContinuationOffset));
__ str(cp, FieldMemOperand(r0, JSGeneratorObject::kContextOffset));
__ mov(r1, cp);
__ RecordWriteField(r0, JSGeneratorObject::kContextOffset, r1, r2,
kLRHasBeenSaved, kDontSaveFPRegs);
__ add(r1, fp, Operand(StandardFrameConstants::kExpressionsOffset));
__ cmp(sp, r1);
__ b(eq, &post_runtime);
__ push(r0); // generator object
__ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
__ ldr(context_register(),
MemOperand(fp, StandardFrameConstants::kContextOffset));
Label resume;
__ CompareRoot(result_register(), Heap::kTheHoleValueRootIndex);
__ b(ne, &resume);
if (expr->yield_kind() == Yield::SUSPEND) {
EmitReturnIteratorResult(false);
} else {
__ pop(result_register());
EmitReturnSequence();
}
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ bind(&post_runtime);
__ pop(result_register());
EmitReturnSequence();
__ bind(&resume);
context()->Plug(result_register());
@ -2018,7 +2027,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
__ mov(r1, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
__ str(r1, FieldMemOperand(result_register(),
JSGeneratorObject::kContinuationOffset));
EmitReturnIteratorResult(true);
// Pop value from top-of-stack slot, box result into result register.
EmitCreateIteratorResult(true);
EmitUnwindBeforeReturn();
EmitReturnSequence();
break;
}
@ -2029,76 +2041,66 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
// [sp + 1 * kPointerSize] iter
// [sp + 0 * kPointerSize] g
Label l_catch, l_try, l_resume, l_next, l_call, l_loop;
Label l_catch, l_try, l_suspend, l_continuation, l_resume;
Label l_next, l_call, l_loop;
// Initial send value is undefined.
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
__ b(&l_next);
// catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; }
// catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
__ bind(&l_catch);
handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
__ LoadRoot(r2, Heap::kthrow_stringRootIndex); // "throw"
__ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter
__ push(r3); // iter
__ push(r0); // exception
__ mov(r0, r3); // iter
__ LoadRoot(r2, Heap::kthrow_stringRootIndex); // "throw"
Handle<Code> throw_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(throw_ic); // iter.throw in r0
__ jmp(&l_call);
// try { received = yield result.value }
// try { received = %yield result }
// Shuffle the received result above a try handler and yield it without
// re-boxing.
__ bind(&l_try);
__ pop(r0); // result.value
__ pop(r0); // result
__ PushTryHandler(StackHandler::CATCH, expr->index());
const int handler_size = StackHandlerConstants::kSize;
__ push(r0); // result.value
__ ldr(r3, MemOperand(sp, (0 + 1) * kPointerSize + handler_size)); // g
__ push(r3); // g
__ push(r0); // result
__ jmp(&l_suspend);
__ bind(&l_continuation);
__ jmp(&l_resume);
__ bind(&l_suspend);
const int generator_object_depth = kPointerSize + handler_size;
__ ldr(r0, MemOperand(sp, generator_object_depth));
__ push(r0); // g
ASSERT(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
__ mov(r1, Operand(Smi::FromInt(l_continuation.pos())));
__ str(r1, FieldMemOperand(r0, JSGeneratorObject::kContinuationOffset));
__ str(cp, FieldMemOperand(r0, JSGeneratorObject::kContextOffset));
__ mov(r1, cp);
__ RecordWriteField(r0, JSGeneratorObject::kContextOffset, r1, r2,
kLRHasBeenSaved, kDontSaveFPRegs);
__ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
__ ldr(context_register(),
MemOperand(fp, StandardFrameConstants::kContextOffset));
__ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
__ b(ne, &l_resume);
EmitReturnIteratorResult(false);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ pop(r0); // result
EmitReturnSequence();
__ bind(&l_resume); // received in r0
__ PopTryHandler();
// receiver = iter; f = iter.next; arg = received;
// receiver = iter; f = 'next'; arg = received;
__ bind(&l_next);
__ LoadRoot(r2, Heap::knext_stringRootIndex); // "next"
__ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter
__ push(r3); // iter
__ push(r0); // received
__ mov(r0, r3); // iter
__ LoadRoot(r2, Heap::knext_stringRootIndex); // "next"
Handle<Code> next_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(next_ic); // iter.next in r0
// result = f.call(receiver, arg);
// result = receiver[f](arg);
__ bind(&l_call);
Label l_call_runtime;
__ JumpIfSmi(r0, &l_call_runtime);
__ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
__ b(ne, &l_call_runtime);
__ mov(r1, r0);
ParameterCount count(1);
__ InvokeFunction(r1, count, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1);
CallIC(ic);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ jmp(&l_loop);
__ bind(&l_call_runtime);
__ push(r0);
__ CallRuntime(Runtime::kCall, 3);
// val = result.value; if (!result.done) goto l_try;
// if (!result.done) goto l_try;
__ bind(&l_loop);
// result.value
__ push(r0); // save result
__ LoadRoot(r2, Heap::kvalue_stringRootIndex); // "value"
Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(value_ic); // result.value in r0
__ pop(r1); // result
__ push(r0); // result.value
__ mov(r0, r1); // result
__ LoadRoot(r2, Heap::kdone_stringRootIndex); // "done"
Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(done_ic); // result.done in r0
@ -2108,7 +2110,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
__ b(eq, &l_try);
// result.value
__ pop(r0); // result.value
__ pop(r0); // result
__ LoadRoot(r2, Heap::kvalue_stringRootIndex); // "value"
Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(value_ic); // result.value in r0
context()->DropAndPlug(2, r0); // drop iter and g
break;
}
@ -2149,7 +2154,7 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
__ LoadRoot(r2, Heap::kTheHoleValueRootIndex);
Label push_argument_holes, push_frame;
__ bind(&push_argument_holes);
__ sub(r3, r3, Operand(1), SetCC);
__ sub(r3, r3, Operand(Smi::FromInt(1)), SetCC);
__ b(mi, &push_frame);
__ push(r2);
__ jmp(&push_argument_holes);
@ -2214,13 +2219,20 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
}
void FullCodeGenerator::EmitReturnIteratorResult(bool done) {
void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
Label gc_required;
Label allocated;
Handle<Map> map(isolate()->native_context()->generator_result_map());
__ Allocate(map->instance_size(), r0, r2, r3, &gc_required, TAG_OBJECT);
__ jmp(&allocated);
__ bind(&gc_required);
__ Push(Smi::FromInt(map->instance_size()));
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
__ ldr(context_register(),
MemOperand(fp, StandardFrameConstants::kContextOffset));
__ bind(&allocated);
__ mov(r1, Operand(map));
@ -2240,33 +2252,13 @@ void FullCodeGenerator::EmitReturnIteratorResult(bool done) {
// root set.
__ RecordWriteField(r0, JSGeneratorObject::kResultValuePropertyOffset,
r2, r3, kLRHasBeenSaved, kDontSaveFPRegs);
if (done) {
// Exit all nested statements.
NestedStatement* current = nesting_stack_;
int stack_depth = 0;
int context_length = 0;
while (current != NULL) {
current = current->Exit(&stack_depth, &context_length);
}
__ Drop(stack_depth);
}
EmitReturnSequence();
__ bind(&gc_required);
__ Push(Smi::FromInt(map->instance_size()));
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
__ ldr(context_register(),
MemOperand(fp, StandardFrameConstants::kContextOffset));
__ jmp(&allocated);
}
void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral();
__ mov(r2, Operand(key->handle()));
__ mov(r2, Operand(key->value()));
// Call load IC. It has arguments receiver and property name r0 and r2.
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
@ -2421,7 +2413,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
VisitForAccumulatorValue(prop->obj());
__ mov(r1, r0);
__ pop(r0); // Restore value.
__ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
__ mov(r2, Operand(prop->key()->AsLiteral()->value()));
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
: isolate()->builtins()->StoreIC_Initialize_Strict();
@ -2550,7 +2542,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
// Record source code position before IC call.
SetSourcePosition(expr->position());
__ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
__ mov(r2, Operand(prop->key()->AsLiteral()->value()));
__ pop(r1);
Handle<Code> ic = is_classic_mode()
@ -2683,8 +2675,7 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
Handle<Object> uninitialized =
TypeFeedbackCells::UninitializedSentinel(isolate());
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized);
RecordTypeFeedbackCell(expr->CallFeedbackId(), cell);
__ mov(r2, Operand(cell));
@ -2825,7 +2816,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
}
if (property->key()->IsPropertyName()) {
EmitCallWithIC(expr,
property->key()->AsLiteral()->handle(),
property->key()->AsLiteral()->value(),
RelocInfo::CODE_TARGET);
} else {
EmitKeyedCallWithIC(expr, property->key());
@ -2879,8 +2870,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// Record call targets in unoptimized code.
Handle<Object> uninitialized =
TypeFeedbackCells::UninitializedSentinel(isolate());
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized);
RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell);
__ mov(r2, Operand(cell));
@ -3434,7 +3424,7 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 2);
ASSERT_NE(NULL, args->at(1)->AsLiteral());
Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->handle()));
Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
VisitForAccumulatorValue(args->at(0)); // Load the object.
@ -3853,7 +3843,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(2, args->length());
ASSERT_NE(NULL, args->at(0)->AsLiteral());
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Handle<FixedArray> jsfunction_result_caches(
isolate()->native_context()->jsfunction_result_caches());
@ -4526,7 +4516,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
break;
case NAMED_PROPERTY: {
__ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
__ mov(r2, Operand(prop->key()->AsLiteral()->value()));
__ pop(r1);
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()

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

@ -27,7 +27,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "assembler-arm.h"
#include "code-stubs.h"
@ -321,7 +321,8 @@ static void GenerateKeyNameCheck(MacroAssembler* masm,
__ tst(hash, Operand(Name::kContainsCachedArrayIndexMask));
__ b(eq, index_string);
// Is the string internalized?
// Is the string internalized? We know it's a string, so a single
// bit test is enough.
// map: key map
__ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
STATIC_ASSERT(kInternalizedTag != 0);
@ -1581,8 +1582,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
}
void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
StrictModeFlag strict_mode) {
void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : receiver

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

@ -41,24 +41,6 @@ namespace internal {
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
#undef DEFINE_COMPILE
LOsrEntry::LOsrEntry() {
for (int i = 0; i < Register::NumAllocatableRegisters(); ++i) {
register_spills_[i] = NULL;
}
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
double_register_spills_[i] = NULL;
}
}
void LOsrEntry::MarkSpilledRegister(int allocation_index,
LOperand* spill_operand) {
ASSERT(spill_operand->IsStackSlot());
ASSERT(register_spills_[allocation_index] == NULL);
register_spills_[allocation_index] = spill_operand;
}
#ifdef DEBUG
void LInstruction::VerifyCall() {
// Call instructions can use only fixed registers as temporaries and
@ -81,14 +63,6 @@ void LInstruction::VerifyCall() {
#endif
void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
LOperand* spill_operand) {
ASSERT(spill_operand->IsDoubleStackSlot());
ASSERT(double_register_spills_[allocation_index] == NULL);
double_register_spills_[allocation_index] = spill_operand;
}
void LInstruction::PrintTo(StringStream* stream) {
stream->Add("%s ", this->Mnemonic());
@ -352,8 +326,7 @@ void LCallNewArray::PrintDataTo(StringStream* stream) {
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
ASSERT(hydrogen()->property_cell()->value()->IsSmi());
ElementsKind kind = static_cast<ElementsKind>(
Smi::cast(hydrogen()->property_cell()->value())->value());
ElementsKind kind = hydrogen()->elements_kind();
stream->Add(" (%s) ", ElementsKindToString(kind));
}
@ -451,7 +424,7 @@ LOperand* LPlatformChunk::GetNextSpillSlot(bool is_double) {
LPlatformChunk* LChunkBuilder::Build() {
ASSERT(is_unused());
chunk_ = new(zone()) LPlatformChunk(info(), graph());
HPhase phase("L_Building chunk", chunk_);
LPhase phase("L_Building chunk", chunk_);
status_ = BUILDING;
const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
for (int i = 0; i < blocks->length(); i++) {
@ -929,7 +902,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
BailoutId ast_id = hydrogen_env->ast_id();
ASSERT(!ast_id.IsNone() ||
hydrogen_env->frame_type() != JS_FUNCTION);
int value_count = hydrogen_env->length();
int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
LEnvironment* result = new(zone()) LEnvironment(
hydrogen_env->closure(),
hydrogen_env->frame_type(),
@ -940,13 +913,15 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
outer,
hydrogen_env->entry(),
zone());
bool needs_arguments_object_materialization = false;
int argument_index = *argument_index_accumulator;
for (int i = 0; i < value_count; ++i) {
for (int i = 0; i < hydrogen_env->length(); ++i) {
if (hydrogen_env->is_special_index(i)) continue;
HValue* value = hydrogen_env->values()->at(i);
LOperand* op = NULL;
if (value->IsArgumentsObject()) {
needs_arguments_object_materialization = true;
op = NULL;
} else if (value->IsPushArgument()) {
op = new(zone()) LArgument(argument_index++);
@ -958,6 +933,21 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
value->CheckFlag(HInstruction::kUint32));
}
if (needs_arguments_object_materialization) {
HArgumentsObject* arguments = hydrogen_env->entry() == NULL
? graph()->GetArgumentsObject()
: hydrogen_env->entry()->arguments_object();
ASSERT(arguments->IsLinked());
for (int i = 1; i < arguments->arguments_count(); ++i) {
HValue* value = arguments->arguments_values()->at(i);
ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument());
LOperand* op = UseAny(value);
result->AddValue(op,
value->representation(),
value->CheckFlag(HInstruction::kUint32));
}
}
if (hydrogen_env->frame_type() == JS_FUNCTION) {
*argument_index_accumulator = argument_index;
}
@ -982,10 +972,13 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
LBranch* result = new(zone()) LBranch(UseRegister(value));
// Tagged values that are not known smis or booleans require a
// deoptimization environment.
// deoptimization environment. If the instruction is generic no
// environment is needed since all cases are handled.
Representation rep = value->representation();
HType type = value->type();
if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean()) {
ToBooleanStub::Types expected = instr->expected_input_types();
if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean() &&
!expected.IsGeneric()) {
return AssignEnvironment(result);
}
return result;
@ -1386,19 +1379,6 @@ bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) {
}
HValue* LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(HValue* dividend) {
// A value with an integer representation does not need to be transformed.
if (dividend->representation().IsInteger32()) {
return dividend;
// A change from an integer32 can be replaced by the integer32 value.
} else if (dividend->IsChange() &&
HChange::cast(dividend)->from().IsInteger32()) {
return HChange::cast(dividend)->value();
}
return NULL;
}
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
if (CpuFeatures::IsSupported(SUDIV)) {
// A value with an integer representation does not need to be transformed.
@ -1456,7 +1436,7 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
instr->CheckFlag(HValue::kBailoutOnMinusZero))
? AssignEnvironment(result)
: result;
} else if (instr->has_fixed_right_arg()) {
} else if (instr->fixed_right_arg().has_value) {
LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
UseRegisterAtStart(right));
return AssignEnvironment(DefineAsRegister(mod));
@ -1816,13 +1796,6 @@ LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
}
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LFixedArrayBaseLength(array));
}
LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
LOperand* map = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LMapEnumLength(map));
@ -2019,7 +1992,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
}
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
return AssignEnvironment(new(zone()) LCheckNonSmi(value));
}
@ -2416,6 +2389,14 @@ LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
}
LInstruction* LChunkBuilder::DoAllocateObject(HAllocateObject* instr) {
info()->MarkAsDeferredCalling();
LAllocateObject* result =
new(zone()) LAllocateObject(TempRegister(), TempRegister());
return AssignPointerMap(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
info()->MarkAsDeferredCalling();
LOperand* size = instr->size()->IsConstant()
@ -2588,8 +2569,9 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
undefined,
instr->inlining_kind(),
instr->undefined_receiver());
if (instr->arguments_var() != NULL) {
inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
// Only replay binding of arguments object if it wasn't removed from graph.
if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
inner->Bind(instr->arguments_var(), instr->arguments_object());
}
inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);

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

@ -49,6 +49,7 @@ class LCodeGen;
#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
V(AccessArgumentsAt) \
V(AddI) \
V(AllocateObject) \
V(Allocate) \
V(ApplyArguments) \
V(ArgumentsElements) \
@ -98,7 +99,6 @@ class LCodeGen;
V(DoubleToSmi) \
V(DummyUse) \
V(ElementsKind) \
V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
@ -489,17 +489,44 @@ class LUnknownOSRValue: public LTemplateInstruction<1, 0, 0> {
template<int I, int T>
class LControlInstruction: public LTemplateInstruction<0, I, T> {
public:
LControlInstruction() : false_label_(NULL), true_label_(NULL) { }
virtual bool IsControl() const { return true; }
int SuccessorCount() { return hydrogen()->SuccessorCount(); }
HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
int true_block_id() { return hydrogen()->SuccessorAt(0)->block_id(); }
int false_block_id() { return hydrogen()->SuccessorAt(1)->block_id(); }
int TrueDestination(LChunk* chunk) {
return chunk->LookupDestination(true_block_id());
}
int FalseDestination(LChunk* chunk) {
return chunk->LookupDestination(false_block_id());
}
Label* TrueLabel(LChunk* chunk) {
if (true_label_ == NULL) {
true_label_ = chunk->GetAssemblyLabel(TrueDestination(chunk));
}
return true_label_;
}
Label* FalseLabel(LChunk* chunk) {
if (false_label_ == NULL) {
false_label_ = chunk->GetAssemblyLabel(FalseDestination(chunk));
}
return false_label_;
}
protected:
int true_block_id() { return SuccessorAt(0)->block_id(); }
int false_block_id() { return SuccessorAt(1)->block_id(); }
private:
HControlInstruction* hydrogen() {
return HControlInstruction::cast(this->hydrogen_value());
}
Label* false_label_;
Label* true_label_;
};
@ -1236,7 +1263,7 @@ class LBranch: public LControlInstruction<1, 0> {
};
class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 1> {
class LCmpMapAndBranch: public LControlInstruction<1, 1> {
public:
LCmpMapAndBranch(LOperand* value, LOperand* temp) {
inputs_[0] = value;
@ -1249,29 +1276,7 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 1> {
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareMap)
virtual bool IsControl() const { return true; }
Handle<Map> map() const { return hydrogen()->map(); }
int true_block_id() const {
return hydrogen()->FirstSuccessor()->block_id();
}
int false_block_id() const {
return hydrogen()->SecondSuccessor()->block_id();
}
};
class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value;
}
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
"fixed-array-base-length")
DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
};
@ -2401,6 +2406,7 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
};
@ -2444,6 +2450,21 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> {
};
class LAllocateObject: public LTemplateInstruction<1, 1, 2> {
public:
LAllocateObject(LOperand* temp, LOperand* temp2) {
temps_[0] = temp;
temps_[1] = temp2;
}
LOperand* temp() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object")
DECLARE_HYDROGEN_ACCESSOR(AllocateObject)
};
class LAllocate: public LTemplateInstruction<1, 2, 2> {
public:
LAllocate(LOperand* size, LOperand* temp1, LOperand* temp2) {
@ -2546,26 +2567,10 @@ class LDeleteProperty: public LTemplateInstruction<1, 2, 0> {
class LOsrEntry: public LTemplateInstruction<0, 0, 0> {
public:
LOsrEntry();
LOsrEntry() {}
virtual bool HasInterestingComment(LCodeGen* gen) const { return false; }
DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
LOperand** SpilledRegisterArray() { return register_spills_; }
LOperand** SpilledDoubleRegisterArray() { return double_register_spills_; }
void MarkSpilledRegister(int allocation_index, LOperand* spill_operand);
void MarkSpilledDoubleRegister(int allocation_index,
LOperand* spill_operand);
private:
// Arrays of spill slot operands for registers with an assigned spill
// slot, i.e., that must also be restored to the spill slot on OSR entry.
// NULL if the register has no assigned spill slot. Indexed by allocation
// index.
LOperand* register_spills_[Register::kMaxNumAllocatableRegisters];
LOperand* double_register_spills_[
DoubleRegister::kMaxNumAllocatableRegisters];
};
@ -2692,7 +2697,6 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* DoRSub(HSub* instr);
static bool HasMagicNumberForDivisor(int32_t divisor);
static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
LInstruction* DoMathFloor(HUnaryMathOperation* instr);

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

@ -62,7 +62,7 @@ class SafepointGenerator : public CallWrapper {
#define __ masm()->
bool LCodeGen::GenerateCode() {
HPhase phase("Z_Code generation", chunk());
LPhase phase("Z_Code generation", chunk());
ASSERT(is_unused());
status_ = GENERATING;
@ -87,20 +87,7 @@ void LCodeGen::FinishCode(Handle<Code> code) {
RegisterDependentCodeForEmbeddedMaps(code);
}
PopulateDeoptimizationData(code);
for (int i = 0 ; i < prototype_maps_.length(); i++) {
prototype_maps_.at(i)->AddDependentCode(
DependentCode::kPrototypeCheckGroup, code);
}
for (int i = 0 ; i < transition_maps_.length(); i++) {
transition_maps_.at(i)->AddDependentCode(
DependentCode::kTransitionGroup, code);
}
if (graph()->depends_on_empty_array_proto_elements()) {
isolate()->initial_object_prototype()->map()->AddDependentCode(
DependentCode::kElementsCantBeAddedGroup, code);
isolate()->initial_array_prototype()->map()->AddDependentCode(
DependentCode::kElementsCantBeAddedGroup, code);
}
info()->CommitDependencies(code);
}
@ -593,27 +580,15 @@ MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
void LCodeGen::WriteTranslation(LEnvironment* environment,
Translation* translation,
int* pushed_arguments_index,
int* pushed_arguments_count) {
Translation* translation) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
int translation_size = environment->values()->length();
int translation_size = environment->translation_size();
// The output frame height does not include the parameters.
int height = translation_size - environment->parameter_count();
// Function parameters are arguments to the outermost environment. The
// arguments index points to the first element of a sequence of tagged
// values on the stack that represent the arguments. This needs to be
// kept in sync with the LArgumentsElements implementation.
*pushed_arguments_index = -environment->parameter_count();
*pushed_arguments_count = environment->parameter_count();
WriteTranslation(environment->outer(),
translation,
pushed_arguments_index,
pushed_arguments_count);
WriteTranslation(environment->outer(), translation);
bool has_closure_id = !info()->closure().is_null() &&
!info()->closure().is_identical_to(environment->closure());
int closure_id = has_closure_id
@ -645,60 +620,29 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
break;
}
// Inlined frames which push their arguments cause the index to be
// bumped and another stack area to be used for materialization,
// otherwise actual argument values are unknown for inlined frames.
bool arguments_known = true;
int arguments_index = *pushed_arguments_index;
int arguments_count = *pushed_arguments_count;
if (environment->entry() != NULL) {
arguments_known = environment->entry()->arguments_pushed();
arguments_index = arguments_index < 0
? GetStackSlotCount() : arguments_index + arguments_count;
arguments_count = environment->entry()->arguments_count() + 1;
if (environment->entry()->arguments_pushed()) {
*pushed_arguments_index = arguments_index;
*pushed_arguments_count = arguments_count;
}
}
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
// both NULL or both set.
if (environment->spilled_registers() != NULL && value != NULL) {
if (value->IsRegister() &&
environment->spilled_registers()[value->index()] != NULL) {
translation->MarkDuplicate();
// TODO(mstarzinger): Introduce marker operands to indicate that this value
// is not present and must be reconstructed from the deoptimizer. Currently
// this is only used for the arguments object.
if (value == NULL) {
int arguments_count = environment->values()->length() - translation_size;
translation->BeginArgumentsObject(arguments_count);
for (int i = 0; i < arguments_count; ++i) {
LOperand* value = environment->values()->at(translation_size + i);
AddToTranslation(translation,
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
environment->HasUint32ValueAt(i),
arguments_known,
arguments_index,
arguments_count);
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL) {
translation->MarkDuplicate();
AddToTranslation(
translation,
environment->spilled_double_registers()[value->index()],
false,
false,
arguments_known,
arguments_index,
arguments_count);
value,
environment->HasTaggedValueAt(translation_size + i),
environment->HasUint32ValueAt(translation_size + i));
}
continue;
}
AddToTranslation(translation,
value,
environment->HasTaggedValueAt(i),
environment->HasUint32ValueAt(i),
arguments_known,
arguments_index,
arguments_count);
environment->HasUint32ValueAt(i));
}
}
@ -706,17 +650,8 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
bool is_uint32,
bool arguments_known,
int arguments_index,
int arguments_count) {
if (op == NULL) {
// TODO(twuerthinger): Introduce marker operands to indicate that this value
// is not present and must be reconstructed from the deoptimizer. Currently
// this is only used for the arguments object.
translation->StoreArgumentsObject(
arguments_known, arguments_index, arguments_count);
} else if (op->IsStackSlot()) {
bool is_uint32) {
if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
} else if (is_uint32) {
@ -823,8 +758,6 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
int frame_count = 0;
int jsframe_count = 0;
int args_index = 0;
int args_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
if (e->frame_type() == JS_FUNCTION) {
@ -832,7 +765,7 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
}
}
Translation translation(&translations_, frame_count, jsframe_count, zone());
WriteTranslation(environment, &translation, &args_index, &args_count);
WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
@ -865,7 +798,7 @@ void LCodeGen::DeoptimizeIf(Condition cc,
return;
}
if (FLAG_trap_on_deopt) {
if (FLAG_trap_on_deopt && info()->IsOptimizing()) {
__ stop("trap_on_deopt", cc);
}
@ -1160,7 +1093,8 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
// Nothing to do.
// Record the address of the first unknown OSR value as the place to enter.
if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
}
@ -1194,12 +1128,12 @@ void LCodeGen::DoModI(LModI* instr) {
__ and_(result_reg, left_reg, Operand(divisor - 1));
__ bind(&done);
} else if (hmod->has_fixed_right_arg()) {
} else if (hmod->fixed_right_arg().has_value) {
Register left_reg = ToRegister(instr->left());
Register right_reg = ToRegister(instr->right());
Register result_reg = ToRegister(instr->result());
int32_t divisor = hmod->fixed_right_arg_value();
int32_t divisor = hmod->fixed_right_arg().value;
ASSERT(IsPowerOf2(divisor));
// Check if our assumption of a fixed right operand still holds.
@ -1912,13 +1846,6 @@ void LCodeGen::DoConstantT(LConstantT* instr) {
}
void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->value());
__ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset));
}
void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
Register result = ToRegister(instr->result());
Register map = ToRegister(instr->value());
@ -1946,10 +1873,12 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
Register map = ToRegister(instr->temp());
Label done;
// If the object is a smi return the object.
__ SmiTst(input);
__ Move(result, input, eq);
__ b(eq, &done);
if (!instr->hydrogen()->value()->IsHeapObject()) {
// If the object is a smi return the object.
__ SmiTst(input);
__ Move(result, input, eq);
__ b(eq, &done);
}
// If the object is not a value type, return the object.
__ CompareObjectType(input, map, map, JS_VALUE_TYPE);
@ -2199,11 +2128,12 @@ int LCodeGen::GetNextEmittedBlock() const {
return -1;
}
template<class InstrType>
void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
int right_block = instr->FalseDestination(chunk_);
int left_block = instr->TrueDestination(chunk_);
void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
int next_block = GetNextEmittedBlock();
right_block = chunk_->LookupDestination(right_block);
left_block = chunk_->LookupDestination(left_block);
if (right_block == left_block) {
EmitGoto(left_block);
@ -2224,22 +2154,19 @@ void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
void LCodeGen::DoBranch(LBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32() || r.IsSmi()) {
ASSERT(!info()->IsStub());
Register reg = ToRegister(instr->value());
__ cmp(reg, Operand::Zero());
EmitBranch(true_block, false_block, ne);
EmitBranch(instr, ne);
} else if (r.IsDouble()) {
ASSERT(!info()->IsStub());
DwVfpRegister reg = ToDoubleRegister(instr->value());
// Test the double value. Zero and NaN are false.
__ VFPCompareAndSetFlags(reg, 0.0);
__ cmp(r0, r0, vs); // If NaN, set the Z flag.
EmitBranch(true_block, false_block, ne);
__ cmp(r0, r0, vs); // If NaN, set the Z flag. (NaN -> false)
EmitBranch(instr, ne);
} else {
ASSERT(r.IsTagged());
Register reg = ToRegister(instr->value());
@ -2247,42 +2174,55 @@ void LCodeGen::DoBranch(LBranch* instr) {
if (type.IsBoolean()) {
ASSERT(!info()->IsStub());
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
EmitBranch(true_block, false_block, eq);
EmitBranch(instr, eq);
} else if (type.IsSmi()) {
ASSERT(!info()->IsStub());
__ cmp(reg, Operand::Zero());
EmitBranch(true_block, false_block, ne);
EmitBranch(instr, ne);
} else if (type.IsJSArray()) {
ASSERT(!info()->IsStub());
EmitBranch(instr, al);
} else if (type.IsHeapNumber()) {
ASSERT(!info()->IsStub());
DwVfpRegister dbl_scratch = double_scratch0();
__ vldr(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
// Test the double value. Zero and NaN are false.
__ VFPCompareAndSetFlags(dbl_scratch, 0.0);
__ cmp(r0, r0, vs); // If NaN, set the Z flag. (NaN)
EmitBranch(instr, ne);
} else if (type.IsString()) {
ASSERT(!info()->IsStub());
__ ldr(ip, FieldMemOperand(reg, String::kLengthOffset));
__ cmp(ip, Operand::Zero());
EmitBranch(instr, ne);
} else {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
// Avoid deopts in the case where we've never executed this path before.
if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
// undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ b(eq, false_label);
__ b(eq, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// Boolean -> its value.
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ b(eq, true_label);
__ b(eq, instr->TrueLabel(chunk_));
__ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ b(eq, false_label);
__ b(eq, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex);
__ b(eq, false_label);
__ b(eq, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SMI)) {
// Smis: 0 -> false, all other -> true.
__ cmp(reg, Operand::Zero());
__ b(eq, false_label);
__ JumpIfSmi(reg, true_label);
__ b(eq, instr->FalseLabel(chunk_));
__ JumpIfSmi(reg, instr->TrueLabel(chunk_));
} else if (expected.NeedsMap()) {
// If we need a map later and have a Smi -> deopt.
__ SmiTst(reg);
@ -2297,14 +2237,14 @@ void LCodeGen::DoBranch(LBranch* instr) {
// Undetectable -> false.
__ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
__ tst(ip, Operand(1 << Map::kIsUndetectable));
__ b(ne, false_label);
__ b(ne, instr->FalseLabel(chunk_));
}
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true.
__ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
__ b(ge, true_label);
__ b(ge, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::STRING)) {
@ -2314,15 +2254,15 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ b(ge, &not_string);
__ ldr(ip, FieldMemOperand(reg, String::kLengthOffset));
__ cmp(ip, Operand::Zero());
__ b(ne, true_label);
__ b(false_label);
__ b(ne, instr->TrueLabel(chunk_));
__ b(instr->FalseLabel(chunk_));
__ bind(&not_string);
}
if (expected.Contains(ToBooleanStub::SYMBOL)) {
// Symbol value -> true.
__ CompareInstanceType(map, ip, SYMBOL_TYPE);
__ b(eq, true_label);
__ b(eq, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@ -2334,13 +2274,16 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ vldr(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
__ VFPCompareAndSetFlags(dbl_scratch, 0.0);
__ cmp(r0, r0, vs); // NaN -> false.
__ b(eq, false_label); // +0, -0 -> false.
__ b(true_label);
__ b(eq, instr->FalseLabel(chunk_)); // +0, -0 -> false.
__ b(instr->TrueLabel(chunk_));
__ bind(&not_heap_number);
}
// We've seen something for the first time -> deopt.
DeoptimizeIf(al, instr->environment());
if (!expected.IsGeneric()) {
// We've seen something for the first time -> deopt.
// This can only happen if we are not generic already.
DeoptimizeIf(al, instr->environment());
}
}
}
}
@ -2348,7 +2291,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
void LCodeGen::EmitGoto(int block) {
if (!IsNextEmittedBlock(block)) {
__ jmp(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block)));
__ jmp(chunk_->GetAssemblyLabel(LookupDestination(block)));
}
}
@ -2389,17 +2332,14 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
int false_block = chunk_->LookupDestination(instr->false_block_id());
int true_block = chunk_->LookupDestination(instr->true_block_id());
Condition cond = TokenToCondition(instr->op(), false);
if (left->IsConstantOperand() && right->IsConstantOperand()) {
// We can statically evaluate the comparison.
double left_val = ToDouble(LConstantOperand::cast(left));
double right_val = ToDouble(LConstantOperand::cast(right));
int next_block =
EvalComparison(instr->op(), left_val, right_val) ? true_block
: false_block;
int next_block = EvalComparison(instr->op(), left_val, right_val) ?
instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
EmitGoto(next_block);
} else {
if (instr->is_double()) {
@ -2408,7 +2348,7 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
__ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right));
// If a NaN is involved, i.e. the result is unordered (V set),
// jump to false block label.
__ b(vs, chunk_->GetAssemblyLabel(false_block));
__ b(vs, instr->FalseLabel(chunk_));
} else {
if (right->IsConstantOperand()) {
int32_t value = ToInteger32(LConstantOperand::cast(right));
@ -2430,7 +2370,7 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
__ cmp(ToRegister(left), ToRegister(right));
}
}
EmitBranch(true_block, false_block, cond);
EmitBranch(instr, cond);
}
}
@ -2438,21 +2378,17 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
Register left = ToRegister(instr->left());
Register right = ToRegister(instr->right());
int false_block = chunk_->LookupDestination(instr->false_block_id());
int true_block = chunk_->LookupDestination(instr->true_block_id());
__ cmp(left, Operand(right));
EmitBranch(true_block, false_block, eq);
EmitBranch(instr, eq);
}
void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
Register left = ToRegister(instr->left());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
__ cmp(left, Operand(instr->hydrogen()->right()));
EmitBranch(true_block, false_block, eq);
EmitBranch(instr, eq);
}
@ -2487,22 +2423,21 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Register reg = ToRegister(instr->value());
Register temp1 = ToRegister(instr->temp());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
Condition true_cond =
EmitIsObject(reg, temp1, false_label, true_label);
EmitIsObject(reg, temp1,
instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
EmitBranch(true_block, false_block, true_cond);
EmitBranch(instr, true_cond);
}
Condition LCodeGen::EmitIsString(Register input,
Register temp1,
Label* is_not_string) {
__ JumpIfSmi(input, is_not_string);
Label* is_not_string,
SmiCheck check_needed = INLINE_SMI_CHECK) {
if (check_needed == INLINE_SMI_CHECK) {
__ JumpIfSmi(input, is_not_string);
}
__ CompareObjectType(input, temp1, temp1, FIRST_NONSTRING_TYPE);
return lt;
@ -2513,24 +2448,20 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
Register reg = ToRegister(instr->value());
Register temp1 = ToRegister(instr->temp());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Label* false_label = chunk_->GetAssemblyLabel(false_block);
SmiCheck check_needed =
instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Condition true_cond =
EmitIsString(reg, temp1, false_label);
EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed);
EmitBranch(true_block, false_block, true_cond);
EmitBranch(instr, true_cond);
}
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Register input_reg = EmitLoadRegister(instr->value(), ip);
__ SmiTst(input_reg);
EmitBranch(true_block, false_block, eq);
EmitBranch(instr, eq);
}
@ -2538,14 +2469,13 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
__ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
if (!instr->hydrogen()->value()->IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset));
__ ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
__ tst(temp, Operand(1 << Map::kIsUndetectable));
EmitBranch(true_block, false_block, ne);
EmitBranch(instr, ne);
}
@ -2571,8 +2501,6 @@ static Condition ComputeCompareCondition(Token::Value op) {
void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
Token::Value op = instr->op();
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
@ -2581,7 +2509,7 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
Condition condition = ComputeCompareCondition(op);
EmitBranch(true_block, false_block, condition);
EmitBranch(instr, condition);
}
@ -2609,15 +2537,12 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Register scratch = scratch0();
Register input = ToRegister(instr->value());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Label* false_label = chunk_->GetAssemblyLabel(false_block);
__ JumpIfSmi(input, false_label);
if (!instr->hydrogen()->value()->IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen()));
EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
EmitBranch(instr, BranchCondition(instr->hydrogen()));
}
@ -2637,13 +2562,10 @@ void LCodeGen::DoHasCachedArrayIndexAndBranch(
Register input = ToRegister(instr->value());
Register scratch = scratch0();
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
__ ldr(scratch,
FieldMemOperand(input, String::kHashFieldOffset));
__ tst(scratch, Operand(String::kContainsCachedArrayIndexMask));
EmitBranch(true_block, false_block, eq);
EmitBranch(instr, eq);
}
@ -2720,27 +2642,20 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
Register temp2 = ToRegister(instr->temp());
Handle<String> class_name = instr->hydrogen()->class_name();
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
class_name, input, temp, temp2);
EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
EmitBranch(true_block, false_block, eq);
EmitBranch(instr, eq);
}
void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
Register reg = ToRegister(instr->value());
Register temp = ToRegister(instr->temp());
int true_block = instr->true_block_id();
int false_block = instr->false_block_id();
__ ldr(temp, FieldMemOperand(reg, HeapObject::kMapOffset));
__ cmp(temp, Operand(instr->map()));
EmitBranch(true_block, false_block, eq);
EmitBranch(instr, eq);
}
@ -2802,10 +2717,9 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
// root array to force relocation to be able to later patch with
// the cached map.
PredictableCodeSizeScope predictable(masm_, 5 * Assembler::kInstrSize);
Handle<JSGlobalPropertyCell> cell =
factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
__ mov(ip, Operand(Handle<Object>(cell)));
__ ldr(ip, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset));
__ ldr(ip, FieldMemOperand(ip, PropertyCell::kValueOffset));
__ cmp(map, Operand(ip));
__ b(ne, &cache_miss);
// We use Factory::the_hole_value() on purpose instead of loading from the
@ -2965,7 +2879,7 @@ void LCodeGen::DoReturn(LReturn* instr) {
void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
Register result = ToRegister(instr->result());
__ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell())));
__ ldr(result, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset));
__ ldr(result, FieldMemOperand(ip, Cell::kValueOffset));
if (instr->hydrogen()->RequiresHoleCheck()) {
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(result, ip);
@ -3000,13 +2914,13 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
if (instr->hydrogen()->RequiresHoleCheck()) {
// We use a temp to check the payload (CompareRoot might clobber ip).
Register payload = ToRegister(instr->temp());
__ ldr(payload, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset));
__ ldr(payload, FieldMemOperand(cell, Cell::kValueOffset));
__ CompareRoot(payload, Heap::kTheHoleValueRootIndex);
DeoptimizeIf(eq, instr->environment());
}
// Store the value.
__ str(value, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset));
__ str(value, FieldMemOperand(cell, Cell::kValueOffset));
// Cells are always rescanned, so no write barrier here.
}
@ -3060,9 +2974,9 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
__ str(value, target);
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ RecordWriteContextSlot(context,
target.offset(),
value,
@ -4193,12 +4107,9 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
__ mov(r0, Operand(instr->arity()));
if (FLAG_optimize_constructed_arrays) {
// No cell in r2 for construct type feedback in optimized code
Handle<Object> undefined_value(isolate()->heap()->undefined_value(),
isolate());
__ mov(r2, Operand(undefined_value));
}
// No cell in r2 for construct type feedback in optimized code
Handle<Object> undefined_value(isolate()->factory()->undefined_value());
__ mov(r2, Operand(undefined_value));
CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
}
@ -4207,22 +4118,42 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
ASSERT(ToRegister(instr->constructor()).is(r1));
ASSERT(ToRegister(instr->result()).is(r0));
ASSERT(FLAG_optimize_constructed_arrays);
__ mov(r0, Operand(instr->arity()));
__ mov(r2, Operand(instr->hydrogen()->property_cell()));
ElementsKind kind = instr->hydrogen()->elements_kind();
bool disable_allocation_sites =
(AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE);
AllocationSiteOverrideMode override_mode =
(AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE)
? DISABLE_ALLOCATION_SITES
: DONT_OVERRIDE;
ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED;
if (instr->arity() == 0) {
ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites);
ArrayNoArgumentConstructorStub stub(kind, context_mode, override_mode);
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
} else if (instr->arity() == 1) {
ArraySingleArgumentConstructorStub stub(kind, disable_allocation_sites);
Label done;
if (IsFastPackedElementsKind(kind)) {
Label packed_case;
// We might need a change here
// look at the first argument
__ ldr(r5, MemOperand(sp, 0));
__ cmp(r5, Operand::Zero());
__ b(eq, &packed_case);
ElementsKind holey_kind = GetHoleyElementsKind(kind);
ArraySingleArgumentConstructorStub stub(holey_kind, context_mode,
override_mode);
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
__ jmp(&done);
__ bind(&packed_case);
}
ArraySingleArgumentConstructorStub stub(kind, context_mode, override_mode);
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
__ bind(&done);
} else {
ArrayNArgumentsConstructorStub stub(kind, disable_allocation_sites);
ArrayNArgumentsConstructorStub stub(kind, context_mode, override_mode);
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
}
}
@ -4267,9 +4198,6 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
}
if (!transition.is_null()) {
if (transition->CanBeDeprecated()) {
transition_maps_.Add(transition, info()->zone());
}
__ mov(scratch, Operand(transition));
__ str(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
@ -4289,9 +4217,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
// Do the store.
Register value = ToRegister(instr->value());
ASSERT(!object.is(value));
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
if (access.IsInobject()) {
__ str(value, FieldMemOperand(object, offset));
if (instr->hydrogen()->NeedsWriteBarrier()) {
@ -4500,9 +4428,9 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
__ str(value, FieldMemOperand(store_base, offset));
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
__ add(key, store_base, Operand(offset - kHeapObjectTag));
__ RecordWrite(elements,
@ -5224,9 +5152,11 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
LOperand* input = instr->value();
__ SmiTst(ToRegister(input));
DeoptimizeIf(eq, instr->environment());
if (!instr->hydrogen()->value()->IsHeapObject()) {
LOperand* input = instr->value();
__ SmiTst(ToRegister(input));
DeoptimizeIf(eq, instr->environment());
}
}
@ -5279,10 +5209,9 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
AllowDeferredHandleDereference smi_check;
if (isolate()->heap()->InNewSpace(*target)) {
Register reg = ToRegister(instr->value());
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(target);
Handle<Cell> cell = isolate()->factory()->NewPropertyCell(target);
__ mov(ip, Operand(Handle<Object>(cell)));
__ ldr(ip, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset));
__ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset));
__ cmp(reg, ip);
} else {
__ cmp(reg, Operand(target));
@ -5382,11 +5311,7 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
ASSERT(prototypes->length() == maps->length());
if (instr->hydrogen()->CanOmitPrototypeChecks()) {
for (int i = 0; i < maps->length(); i++) {
prototype_maps_.Add(maps->at(i), info()->zone());
}
} else {
if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
for (int i = 0; i < prototypes->length(); i++) {
__ LoadHeapObject(prototype_reg, prototypes->at(i));
__ ldr(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
@ -5396,6 +5321,80 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
}
void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
class DeferredAllocateObject: public LDeferredCode {
public:
DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
virtual LInstruction* instr() { return instr_; }
private:
LAllocateObject* instr_;
};
DeferredAllocateObject* deferred =
new(zone()) DeferredAllocateObject(this, instr);
Register result = ToRegister(instr->result());
Register scratch = ToRegister(instr->temp());
Register scratch2 = ToRegister(instr->temp2());
Handle<JSFunction> constructor = instr->hydrogen()->constructor();
Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
int instance_size = initial_map->instance_size();
ASSERT(initial_map->pre_allocated_property_fields() +
initial_map->unused_property_fields() -
initial_map->inobject_properties() == 0);
__ Allocate(instance_size, result, scratch, scratch2, deferred->entry(),
TAG_OBJECT);
__ bind(deferred->exit());
if (FLAG_debug_code) {
Label is_in_new_space;
__ JumpIfInNewSpace(result, scratch, &is_in_new_space);
__ Abort("Allocated object is not in new-space");
__ bind(&is_in_new_space);
}
// Load the initial map.
Register map = scratch;
__ LoadHeapObject(map, constructor);
__ ldr(map, FieldMemOperand(map, JSFunction::kPrototypeOrInitialMapOffset));
// Initialize map and fields of the newly allocated object.
ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
__ str(map, FieldMemOperand(result, JSObject::kMapOffset));
__ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
__ str(scratch, FieldMemOperand(result, JSObject::kElementsOffset));
__ str(scratch, FieldMemOperand(result, JSObject::kPropertiesOffset));
if (initial_map->inobject_properties() != 0) {
__ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
for (int i = 0; i < initial_map->inobject_properties(); i++) {
int property_offset = JSObject::kHeaderSize + i * kPointerSize;
__ str(scratch, FieldMemOperand(result, property_offset));
}
}
}
void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
Register result = ToRegister(instr->result());
Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
int instance_size = initial_map->instance_size();
// TODO(3095996): Get rid of this. For now, we need to make the
// result register contain a valid pointer because it is already
// contained in the register pointer map.
__ mov(result, Operand::Zero());
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ mov(r0, Operand(Smi::FromInt(instance_size)));
__ push(r0);
CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
__ StoreToSafepointRegisterSlot(r0, result);
}
void LCodeGen::DoAllocate(LAllocate* instr) {
class DeferredAllocate: public LDeferredCode {
public:
@ -5554,17 +5553,13 @@ void LCodeGen::DoTypeof(LTypeof* instr) {
void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
Register input = ToRegister(instr->value());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
Condition final_branch_condition = EmitTypeofIs(true_label,
false_label,
Condition final_branch_condition = EmitTypeofIs(instr->TrueLabel(chunk_),
instr->FalseLabel(chunk_),
input,
instr->type_literal());
if (final_branch_condition != kNoCondition) {
EmitBranch(true_block, false_block, final_branch_condition);
EmitBranch(instr, final_branch_condition);
}
}
@ -5649,11 +5644,9 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
Register temp1 = ToRegister(instr->temp());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
EmitIsConstructCall(temp1, scratch0());
EmitBranch(true_block, false_block, eq);
EmitBranch(instr, eq);
}
@ -5809,15 +5802,15 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
// properly registered for deoptimization and records the assembler's PC
// offset.
LEnvironment* environment = instr->environment();
environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
instr->SpilledDoubleRegisterArray());
// If the environment were already registered, we would have no way of
// backpatching it with the spill slot operands.
ASSERT(!environment->HasBeenRegistered());
RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(osr_pc_offset_ == -1);
osr_pc_offset_ = masm()->pc_offset();
// Normally we record the first unknown OSR value as the entrypoint to the OSR
// code, but if there were none, record the entrypoint here.
if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
}

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

@ -56,8 +56,6 @@ class LCodeGen BASE_EMBEDDED {
deoptimizations_(4, info->zone()),
deopt_jump_table_(4, info->zone()),
deoptimization_literals_(8, info->zone()),
prototype_maps_(0, info->zone()),
transition_maps_(0, info->zone()),
inlined_function_count_(0),
scope_(info->scope()),
status_(UNUSED),
@ -81,7 +79,6 @@ class LCodeGen BASE_EMBEDDED {
Heap* heap() const { return isolate()->heap(); }
Zone* zone() const { return zone_; }
// TODO(svenpanne) Use this consistently.
int LookupDestination(int block_id) const {
return chunk()->LookupDestination(block_id);
}
@ -153,6 +150,7 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredRandom(LRandom* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredAllocateObject(LAllocateObject* instr);
void DoDeferredAllocate(LAllocate* instr);
void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
@ -173,10 +171,7 @@ class LCodeGen BASE_EMBEDDED {
int additional_offset);
// Emit frame translation commands for an environment.
void WriteTranslation(LEnvironment* environment,
Translation* translation,
int* arguments_index,
int* arguments_count);
void WriteTranslation(LEnvironment* environment, Translation* translation);
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) void Do##type(L##type* node);
@ -295,10 +290,7 @@ class LCodeGen BASE_EMBEDDED {
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
bool is_uint32,
bool arguments_known,
int arguments_index,
int arguments_count);
bool is_uint32);
void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
@ -327,7 +319,8 @@ class LCodeGen BASE_EMBEDDED {
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block);
void EmitBranch(int left_block, int right_block, Condition cc);
template<class InstrType>
void EmitBranch(InstrType instr, Condition cc);
void EmitNumberUntagD(Register input,
DwVfpRegister result,
bool allow_undefined_as_nan,
@ -356,7 +349,8 @@ class LCodeGen BASE_EMBEDDED {
// true and false label should be made, to optimize fallthrough.
Condition EmitIsString(Register input,
Register temp1,
Label* is_not_string);
Label* is_not_string,
SmiCheck check_needed);
// Emits optimized code for %_IsConstructCall().
// Caller should branch on equal condition.
@ -406,8 +400,6 @@ class LCodeGen BASE_EMBEDDED {
ZoneList<LEnvironment*> deoptimizations_;
ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_;
ZoneList<Handle<Object> > deoptimization_literals_;
ZoneList<Handle<Map> > prototype_maps_;
ZoneList<Handle<Map> > transition_maps_;
int inlined_function_count_;
Scope* const scope_;
Status status_;

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

@ -29,10 +29,11 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "bootstrapper.h"
#include "codegen.h"
#include "cpu-profiler.h"
#include "debug.h"
#include "runtime.h"
@ -400,10 +401,9 @@ void MacroAssembler::LoadHeapObject(Register result,
Handle<HeapObject> object) {
AllowDeferredHandleDereference using_raw_address;
if (isolate()->heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(object);
Handle<Cell> cell = isolate()->factory()->NewCell(object);
mov(result, Operand(cell));
ldr(result, FieldMemOperand(result, JSGlobalPropertyCell::kValueOffset));
ldr(result, FieldMemOperand(result, Cell::kValueOffset));
} else {
mov(result, Operand(object));
}
@ -986,19 +986,19 @@ void MacroAssembler::InitializeNewString(Register string,
int MacroAssembler::ActivationFrameAlignment() {
#if defined(V8_HOST_ARCH_ARM)
#if V8_HOST_ARCH_ARM
// Running on the real platform. Use the alignment as mandated by the local
// environment.
// Note: This will break if we ever start generating snapshots on one ARM
// platform for another ARM platform with a different alignment.
return OS::ActivationFrameAlignment();
#else // defined(V8_HOST_ARCH_ARM)
#else // V8_HOST_ARCH_ARM
// If we are using the simulator then we should always align to the expected
// alignment. As the simulator is used to generate snapshots we do not know
// if the target platform will need alignment, so this is controlled from a
// flag.
return FLAG_sim_stack_alignment;
#endif // defined(V8_HOST_ARCH_ARM)
#endif // V8_HOST_ARCH_ARM
}
@ -2245,6 +2245,9 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
Address function_address,
ExternalReference thunk_ref,
Register thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset) {
@ -2275,11 +2278,31 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
PopSafepointRegisters();
}
ASSERT(!thunk_last_arg.is(r3));
Label profiler_disabled;
Label end_profiler_check;
bool* is_profiling_flag =
isolate()->cpu_profiler()->is_profiling_address();
STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
mov(r3, Operand(reinterpret_cast<int32_t>(is_profiling_flag)));
ldrb(r3, MemOperand(r3, 0));
cmp(r3, Operand(0));
b(eq, &profiler_disabled);
// Additional parameter is the address of the actual callback.
mov(thunk_last_arg, Operand(reinterpret_cast<int32_t>(function_address)));
mov(r3, Operand(thunk_ref));
jmp(&end_profiler_check);
bind(&profiler_disabled);
mov(r3, Operand(function));
bind(&end_profiler_check);
// Native call returns to the DirectCEntry stub which redirects to the
// return address pushed on stack (could have moved after GC).
// DirectCEntry stub itself is generated early and never moves.
DirectCEntryStub stub;
stub.GenerateCall(this, function);
stub.GenerateCall(this, r3);
if (FLAG_log_timer_events) {
FrameScope frame(this, StackFrame::MANUAL);
@ -3067,6 +3090,16 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first,
}
void MacroAssembler::JumpIfNotUniqueName(Register reg,
Label* not_unique_name) {
STATIC_ASSERT(((SYMBOL_TYPE - 1) & kIsInternalizedMask) == kInternalizedTag);
cmp(reg, Operand(kInternalizedTag));
b(lt, not_unique_name);
cmp(reg, Operand(SYMBOL_TYPE));
b(gt, not_unique_name);
}
// Allocates a heap number or jumps to the need_gc label if the young space
// is full and a scavenge is needed.
void MacroAssembler::AllocateHeapNumber(Register result,
@ -3371,7 +3404,7 @@ void MacroAssembler::CallCFunctionHelper(Register function,
// Make sure that the stack is aligned before calling a C function unless
// running in the simulator. The simulator has its own alignment check which
// provides more information.
#if defined(V8_HOST_ARCH_ARM)
#if V8_HOST_ARCH_ARM
if (emit_debug_code()) {
int frame_alignment = OS::ActivationFrameAlignment();
int frame_alignment_mask = frame_alignment - 1;

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

@ -1085,6 +1085,9 @@ class MacroAssembler: public Assembler {
// - 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,
Address function_address,
ExternalReference thunk_ref,
Register thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset_from_fp);
@ -1293,6 +1296,7 @@ class MacroAssembler: public Assembler {
Register scratch,
Label* failure);
void JumpIfNotUniqueName(Register reg, Label* not_unique_name);
// ---------------------------------------------------------------------------
// Patching helpers.

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

@ -27,8 +27,9 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "cpu-profiler.h"
#include "unicode.h"
#include "log.h"
#include "code-stubs.h"

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

@ -30,7 +30,7 @@
#include <cstdarg>
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "disasm.h"
#include "assembler.h"
@ -830,7 +830,10 @@ class Redirection {
Isolate* isolate = Isolate::Current();
Redirection* current = isolate->simulator_redirection();
for (; current != NULL; current = current->next_) {
if (current->external_function_ == external_function) return current;
if (current->external_function_ == external_function) {
ASSERT_EQ(current->type(), type);
return current;
}
}
return new Redirection(external_function, type);
}
@ -1629,12 +1632,19 @@ typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
// (refer to InvocationCallback in v8.h).
typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
typedef void (*SimulatorRuntimeDirectApiCallNew)(int32_t arg0);
typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingApiCall)(
int32_t arg0, int32_t arg1);
typedef void (*SimulatorRuntimeProfilingApiCallNew)(int32_t arg0, int32_t arg1);
// This signature supports direct call to accessor getter callback.
typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0,
int32_t arg1);
typedef void (*SimulatorRuntimeDirectGetterCallNew)(int32_t arg0,
int32_t arg1);
typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingGetterCall)(
int32_t arg0, int32_t arg1, int32_t arg2);
typedef void (*SimulatorRuntimeProfilingGetterCallNew)(
int32_t arg0, int32_t arg1, int32_t arg2);
// Software interrupt instructions are used by the simulator to call into the
// C-based V8 runtime.
@ -1798,6 +1808,31 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
reinterpret_cast<SimulatorRuntimeDirectApiCallNew>(external);
target(arg0);
}
} else if (
redirection->type() == ExternalReference::PROFILING_API_CALL ||
redirection->type() == ExternalReference::PROFILING_API_CALL_NEW) {
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
PrintF("Call to host function at %p args %08x %08x",
reinterpret_cast<void*>(external), arg0, arg1);
if (!stack_aligned) {
PrintF(" with unaligned stack %08x\n", get_register(sp));
}
PrintF("\n");
}
CHECK(stack_aligned);
if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
SimulatorRuntimeProfilingApiCall target =
reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
v8::Handle<v8::Value> result = target(arg0, arg1);
if (::v8::internal::FLAG_trace_sim) {
PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
}
set_register(r0, reinterpret_cast<int32_t>(*result));
} else {
SimulatorRuntimeProfilingApiCallNew target =
reinterpret_cast<SimulatorRuntimeProfilingApiCallNew>(external);
target(arg0, arg1);
}
} else if (
redirection->type() == ExternalReference::DIRECT_GETTER_CALL ||
redirection->type() == ExternalReference::DIRECT_GETTER_CALL_NEW) {
@ -1823,6 +1858,32 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
reinterpret_cast<SimulatorRuntimeDirectGetterCallNew>(external);
target(arg0, arg1);
}
} else if (
redirection->type() == ExternalReference::PROFILING_GETTER_CALL ||
redirection->type() == ExternalReference::PROFILING_GETTER_CALL_NEW) {
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
PrintF("Call to host function at %p args %08x %08x %08x",
reinterpret_cast<void*>(external), arg0, arg1, arg2);
if (!stack_aligned) {
PrintF(" with unaligned stack %08x\n", get_register(sp));
}
PrintF("\n");
}
CHECK(stack_aligned);
if (redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
SimulatorRuntimeProfilingGetterCall target =
reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
v8::Handle<v8::Value> result = target(arg0, arg1, arg2);
if (::v8::internal::FLAG_trace_sim) {
PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
}
set_register(r0, reinterpret_cast<int32_t>(*result));
} else {
SimulatorRuntimeProfilingGetterCallNew target =
reinterpret_cast<SimulatorRuntimeProfilingGetterCallNew>(
external);
target(arg0, arg1, arg2);
}
} else {
// builtin call.
ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
@ -1830,7 +1891,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
reinterpret_cast<SimulatorRuntimeCall>(external);
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
PrintF(
"Call to host function at %p"
"Call to host function at %p "
"args %08x, %08x, %08x, %08x, %08x, %08x",
FUNCTION_ADDR(target),
arg0,

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

@ -27,7 +27,7 @@
#include "v8.h"
#if defined(V8_TARGET_ARCH_ARM)
#if V8_TARGET_ARCH_ARM
#include "ic-inl.h"
#include "codegen.h"
@ -427,12 +427,10 @@ static void GenerateCheckPropertyCell(MacroAssembler* masm,
Handle<Name> name,
Register scratch,
Label* miss) {
Handle<JSGlobalPropertyCell> cell =
GlobalObject::EnsurePropertyCell(global, name);
Handle<Cell> cell = GlobalObject::EnsurePropertyCell(global, name);
ASSERT(cell->value()->IsTheHole());
__ mov(scratch, Operand(cell));
__ ldr(scratch,
FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
__ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(scratch, ip);
__ b(ne, miss);
@ -514,7 +512,13 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
Register storage_reg = name_reg;
if (FLAG_track_fields && representation.IsSmi()) {
if (details.type() == CONSTANT_FUNCTION) {
Handle<HeapObject> constant(
HeapObject::cast(descriptors->GetValue(descriptor)));
__ LoadHeapObject(scratch1, constant);
__ cmp(value_reg, scratch1);
__ b(ne, miss_restore_name);
} else if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_restore_name);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_restore_name);
@ -543,7 +547,8 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
if (object->map()->unused_property_fields() == 0) {
if (details.type() == FIELD &&
object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ push(receiver_reg);
@ -572,6 +577,12 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
if (details.type() == CONSTANT_FUNCTION) {
ASSERT(value_reg.is(r0));
__ Ret();
return;
}
int index = transition->instance_descriptors()->GetFieldIndex(
transition->LastAdded());
@ -958,8 +969,22 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
ExternalReference ref = ExternalReference(&fun,
type,
masm->isolate());
Address thunk_address = returns_handle
? FUNCTION_ADDR(&InvokeInvocationCallback)
: FUNCTION_ADDR(&InvokeFunctionCallback);
ExternalReference::Type thunk_type =
returns_handle ?
ExternalReference::PROFILING_API_CALL :
ExternalReference::PROFILING_API_CALL_NEW;
ApiFunction thunk_fun(thunk_address);
ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
masm->isolate());
AllowExternalCallThatCantCauseGC scope(masm);
__ CallApiFunctionAndReturn(ref,
function_address,
thunk_ref,
r1,
kStackUnwindSpace,
returns_handle,
kFastApiCallArguments + 1);
@ -1456,14 +1481,28 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
Address getter_address = v8::ToCData<Address>(callback->getter());
bool returns_handle =
!CallbackTable::ReturnsVoid(isolate(), getter_address);
ApiFunction fun(getter_address);
ExternalReference::Type type =
returns_handle ?
ExternalReference::DIRECT_GETTER_CALL :
ExternalReference::DIRECT_GETTER_CALL_NEW;
ExternalReference ref = ExternalReference(&fun, type, isolate());
Address thunk_address = returns_handle
? FUNCTION_ADDR(&InvokeAccessorGetter)
: FUNCTION_ADDR(&InvokeAccessorGetterCallback);
ExternalReference::Type thunk_type =
returns_handle ?
ExternalReference::PROFILING_GETTER_CALL :
ExternalReference::PROFILING_GETTER_CALL_NEW;
ApiFunction thunk_fun(thunk_address);
ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
isolate());
__ CallApiFunctionAndReturn(ref,
getter_address,
thunk_ref,
r2,
kStackUnwindSpace,
returns_handle,
5);
@ -1586,12 +1625,12 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
void CallStubCompiler::GenerateLoadFunctionFromCell(
Handle<JSGlobalPropertyCell> cell,
Handle<Cell> cell,
Handle<JSFunction> function,
Label* miss) {
// Get the value from the cell.
__ mov(r3, Operand(cell));
__ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
__ ldr(r1, FieldMemOperand(r3, Cell::kValueOffset));
// Check that the cell contains the same function.
if (heap()->InNewSpace(*function)) {
@ -1659,12 +1698,61 @@ Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
}
Handle<Code> CallStubCompiler::CompileArrayCodeCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<Cell> cell,
Handle<JSFunction> function,
Handle<String> name,
Code::StubType type) {
Label miss;
// Check that function is still array
const int argc = arguments().immediate();
GenerateNameCheck(name, &miss);
Register receiver = r1;
if (cell.is_null()) {
__ ldr(receiver, MemOperand(sp, argc * kPointerSize));
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, &miss);
// Check that the maps haven't changed.
CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, r3, r0,
r4, name, &miss);
} else {
ASSERT(cell->value() == *function);
GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
&miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
}
Handle<Smi> kind(Smi::FromInt(GetInitialFastElementsKind()), isolate());
Handle<Cell> kind_feedback_cell =
isolate()->factory()->NewCell(kind);
__ mov(r0, Operand(argc));
__ mov(r2, Operand(kind_feedback_cell));
__ mov(r1, Operand(function));
ArrayConstructorStub stub(isolate());
__ TailCallStub(&stub);
__ bind(&miss);
GenerateMissBranch();
// Return the generated code.
return GetCode(type, name);
}
Handle<Code> CallStubCompiler::CompileArrayPushCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<Cell> cell,
Handle<JSFunction> function,
Handle<String> name) {
Handle<String> name,
Code::StubType type) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
@ -1908,16 +1996,17 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
GenerateMissBranch();
// Return the generated code.
return GetCode(function);
return GetCode(type, name);
}
Handle<Code> CallStubCompiler::CompileArrayPopCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<Cell> cell,
Handle<JSFunction> function,
Handle<String> name) {
Handle<String> name,
Code::StubType type) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
@ -1990,16 +2079,17 @@ Handle<Code> CallStubCompiler::CompileArrayPopCall(
GenerateMissBranch();
// Return the generated code.
return GetCode(function);
return GetCode(type, name);
}
Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<Cell> cell,
Handle<JSFunction> function,
Handle<String> name) {
Handle<String> name,
Code::StubType type) {
// ----------- S t a t e -------------
// -- r2 : function name
// -- lr : return address
@ -2072,16 +2162,17 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
GenerateMissBranch();
// Return the generated code.
return GetCode(function);
return GetCode(type, name);
}
Handle<Code> CallStubCompiler::CompileStringCharAtCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<Cell> cell,
Handle<JSFunction> function,
Handle<String> name) {
Handle<String> name,
Code::StubType type) {
// ----------- S t a t e -------------
// -- r2 : function name
// -- lr : return address
@ -2155,16 +2246,17 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
GenerateMissBranch();
// Return the generated code.
return GetCode(function);
return GetCode(type, name);
}
Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<Cell> cell,
Handle<JSFunction> function,
Handle<String> name) {
Handle<String> name,
Code::StubType type) {
// ----------- S t a t e -------------
// -- r2 : function name
// -- lr : return address
@ -2227,16 +2319,17 @@ Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
GenerateMissBranch();
// Return the generated code.
return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
return GetCode(type, name);
}
Handle<Code> CallStubCompiler::CompileMathFloorCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<Cell> cell,
Handle<JSFunction> function,
Handle<String> name) {
Handle<String> name,
Code::StubType type) {
// ----------- S t a t e -------------
// -- r2 : function name
// -- lr : return address
@ -2335,16 +2428,17 @@ Handle<Code> CallStubCompiler::CompileMathFloorCall(
GenerateMissBranch();
// Return the generated code.
return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
return GetCode(type, name);
}
Handle<Code> CallStubCompiler::CompileMathAbsCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<Cell> cell,
Handle<JSFunction> function,
Handle<String> name) {
Handle<String> name,
Code::StubType type) {
// ----------- S t a t e -------------
// -- r2 : function name
// -- lr : return address
@ -2433,7 +2527,7 @@ Handle<Code> CallStubCompiler::CompileMathAbsCall(
GenerateMissBranch();
// Return the generated code.
return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
return GetCode(type, name);
}
@ -2441,7 +2535,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
const CallOptimization& optimization,
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<Cell> cell,
Handle<JSFunction> function,
Handle<String> name) {
Counters* counters = isolate()->counters();
@ -2613,8 +2707,9 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
Handle<JSFunction> function) {
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, Handle<String>::cast(name));
Handle<Cell>::null(),
function, Handle<String>::cast(name),
Code::CONSTANT_FUNCTION);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
@ -2671,7 +2766,7 @@ Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
Handle<Code> CallStubCompiler::CompileCallGlobal(
Handle<JSObject> object,
Handle<GlobalObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name) {
// ----------- S t a t e -------------
@ -2680,7 +2775,8 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
// -----------------------------------
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(
object, holder, cell, function, Handle<String>::cast(name));
object, holder, cell, function, Handle<String>::cast(name),
Code::NORMAL);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
@ -2844,7 +2940,7 @@ Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
Handle<Code> StoreStubCompiler::CompileStoreGlobal(
Handle<GlobalObject> object,
Handle<JSGlobalPropertyCell> cell,
Handle<PropertyCell> cell,
Handle<Name> name) {
Label miss;
@ -2859,14 +2955,12 @@ Handle<Code> StoreStubCompiler::CompileStoreGlobal(
// global object. We bail out to the runtime system to do that.
__ mov(scratch1(), Operand(cell));
__ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex);
__ ldr(scratch3(),
FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
__ ldr(scratch3(), FieldMemOperand(scratch1(), Cell::kValueOffset));
__ cmp(scratch3(), scratch2());
__ b(eq, &miss);
// Store the value in the cell.
__ str(value(),
FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
__ str(value(), FieldMemOperand(scratch1(), Cell::kValueOffset));
// Cells are always rescanned, so no write barrier here.
Counters* counters = isolate()->counters();
@ -2990,7 +3084,7 @@ void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<JSObject> object,
Handle<GlobalObject> global,
Handle<JSGlobalPropertyCell> cell,
Handle<PropertyCell> cell,
Handle<Name> name,
bool is_dont_delete) {
Label success, miss;
@ -3002,7 +3096,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
// Get the value from the cell.
__ mov(r3, Operand(cell));
__ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
__ ldr(r4, FieldMemOperand(r3, Cell::kValueOffset));
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {

11
deps/v8/src/arraybuffer.js

@ -31,12 +31,12 @@ var $ArrayBuffer = global.ArrayBuffer;
// -------------------------------------------------------------------
function ArrayBufferConstructor(byteLength) { // length = 1
function ArrayBufferConstructor(length) { // length = 1
if (%_IsConstructCall()) {
var l = TO_POSITIVE_INTEGER(byteLength);
%ArrayBufferInitialize(this, l);
var byteLength = ToPositiveInteger(length, 'invalid_array_buffer_length');
%ArrayBufferInitialize(this, byteLength);
} else {
return new $ArrayBuffer(byteLength);
throw MakeTypeError('constructor_not_function', ["ArrayBuffer"]);
}
}
@ -70,6 +70,9 @@ function ArrayBufferSlice(start, end) {
fin = MathMin(relativeEnd, this.byteLength);
}
if (fin < first) {
fin = first;
}
var newLen = fin - first;
// TODO(dslomov): implement inheritance
var result = new $ArrayBuffer(newLen);

10
deps/v8/src/assembler.cc

@ -724,7 +724,7 @@ bool RelocInfo::RequiresRelocation(const CodeDesc& desc) {
// generation.
int mode_mask = RelocInfo::kCodeTargetMask |
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
RelocInfo::ModeMask(RelocInfo::CELL) |
RelocInfo::kApplyMask;
RelocIterator it(desc, mode_mask);
return !it.done();
@ -754,8 +754,8 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
return "code target";
case RelocInfo::CODE_TARGET_WITH_ID:
return "code target with id";
case RelocInfo::GLOBAL_PROPERTY_CELL:
return "global property cell";
case RelocInfo::CELL:
return "property cell";
case RelocInfo::RUNTIME_ENTRY:
return "runtime entry";
case RelocInfo::JS_RETURN:
@ -830,7 +830,7 @@ void RelocInfo::Verify() {
case EMBEDDED_OBJECT:
Object::VerifyPointer(target_object());
break;
case GLOBAL_PROPERTY_CELL:
case CELL:
Object::VerifyPointer(target_cell());
break;
case DEBUG_BREAK:
@ -1308,7 +1308,7 @@ ExternalReference ExternalReference::address_of_the_hole_nan() {
ExternalReference ExternalReference::re_check_stack_guard_state(
Isolate* isolate) {
Address function;
#ifdef V8_TARGET_ARCH_X64
#if V8_TARGET_ARCH_X64
function = FUNCTION_ADDR(RegExpMacroAssemblerX64::CheckStackGuardState);
#elif V8_TARGET_ARCH_IA32
function = FUNCTION_ADDR(RegExpMacroAssemblerIA32::CheckStackGuardState);

30
deps/v8/src/assembler.h

@ -254,7 +254,7 @@ class RelocInfo BASE_EMBEDDED {
CODE_TARGET_CONTEXT, // Code target used for contextual loads and stores.
DEBUG_BREAK, // Code target for the debugger statement.
EMBEDDED_OBJECT,
GLOBAL_PROPERTY_CELL,
CELL,
// Everything after runtime_entry (inclusive) is not GC'ed.
RUNTIME_ENTRY,
@ -282,7 +282,7 @@ class RelocInfo BASE_EMBEDDED {
FIRST_PSEUDO_RELOC_MODE = CODE_AGE_SEQUENCE,
LAST_PSEUDO_RELOC_MODE = CODE_AGE_SEQUENCE,
LAST_CODE_ENUM = DEBUG_BREAK,
LAST_GCED_ENUM = GLOBAL_PROPERTY_CELL,
LAST_GCED_ENUM = CELL,
// Modes <= LAST_COMPACT_ENUM are guaranteed to have compact encoding.
LAST_COMPACT_ENUM = CODE_TARGET_WITH_ID,
LAST_STANDARD_NONCOMPACT_ENUM = INTERNAL_REFERENCE
@ -386,9 +386,9 @@ class RelocInfo BASE_EMBEDDED {
INLINE(void set_target_runtime_entry(Address target,
WriteBarrierMode mode =
UPDATE_WRITE_BARRIER));
INLINE(JSGlobalPropertyCell* target_cell());
INLINE(Handle<JSGlobalPropertyCell> target_cell_handle());
INLINE(void set_target_cell(JSGlobalPropertyCell* cell,
INLINE(Cell* target_cell());
INLINE(Handle<Cell> target_cell_handle());
INLINE(void set_target_cell(Cell* cell,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER));
INLINE(Code* code_age_stub());
INLINE(void set_code_age_stub(Code* stub));
@ -647,17 +647,35 @@ class ExternalReference BASE_EMBEDDED {
// Handle<Value> f(v8::Arguments&)
DIRECT_API_CALL,
// Call to invocation callback via InvokeInvocationCallback.
// Handle<Value> f(v8::Arguments&, v8::InvocationCallback)
PROFILING_API_CALL,
// Direct call to API function callback.
// void f(v8::Arguments&)
DIRECT_API_CALL_NEW,
// Call to function callback via InvokeFunctionCallback.
// void f(v8::Arguments&, v8::FunctionCallback)
PROFILING_API_CALL_NEW,
// Direct call to accessor getter callback.
// Handle<value> f(Local<String> property, AccessorInfo& info)
DIRECT_GETTER_CALL,
// Call to accessor getter callback via InvokeAccessorGetter.
// Handle<value> f(Local<String> property, AccessorInfo& info,
// AccessorGetter getter)
PROFILING_GETTER_CALL,
// Direct call to accessor getter callback.
// void f(Local<String> property, AccessorInfo& info)
DIRECT_GETTER_CALL_NEW
DIRECT_GETTER_CALL_NEW,
// Call to accessor getter callback via InvokeAccessorGetterCallback.
// void f(Local<String> property, AccessorInfo& info,
// AccessorGetterCallback callback)
PROFILING_GETTER_CALL_NEW
};
static void SetUp();

29
deps/v8/src/assert-scope.h

@ -79,7 +79,11 @@ class PerThreadAssertScopeBase {
protected:
PerThreadAssertScopeBase() {
data_ = AssertData();
data_ = GetAssertData();
if (data_ == NULL) {
data_ = new PerThreadAssertData();
SetThreadLocalData(data_);
}
data_->increment_level();
}
@ -89,22 +93,22 @@ class PerThreadAssertScopeBase {
ASSERT(data_->get(static_cast<PerThreadAssertType>(i)));
}
delete data_;
Thread::SetThreadLocal(thread_local_key, NULL);
SetThreadLocalData(NULL);
}
static PerThreadAssertData* AssertData() {
PerThreadAssertData* data = reinterpret_cast<PerThreadAssertData*>(
Thread::GetThreadLocal(thread_local_key));
if (data == NULL) {
data = new PerThreadAssertData();
Thread::SetThreadLocal(thread_local_key, data);
}
return data;
static PerThreadAssertData* GetAssertData() {
return reinterpret_cast<PerThreadAssertData*>(
Thread::GetThreadLocal(thread_local_key));
}
static Thread::LocalStorageKey thread_local_key;
PerThreadAssertData* data_;
friend class Isolate;
private:
static void SetThreadLocalData(PerThreadAssertData* data) {
Thread::SetThreadLocal(thread_local_key, data);
}
#endif // DEBUG
};
@ -124,7 +128,10 @@ class PerThreadAssertScope : public PerThreadAssertScopeBase {
~PerThreadAssertScope() { data_->set(type, old_state_); }
static bool IsAllowed() { return AssertData()->get(type); }
static bool IsAllowed() {
PerThreadAssertData* data = GetAssertData();
return data == NULL || data->get(type);
}
private:
bool old_state_;

108
deps/v8/src/ast.cc

@ -57,22 +57,22 @@ AST_NODE_LIST(DECL_ACCEPT)
bool Expression::IsSmiLiteral() {
return AsLiteral() != NULL && AsLiteral()->handle()->IsSmi();
return AsLiteral() != NULL && AsLiteral()->value()->IsSmi();
}
bool Expression::IsStringLiteral() {
return AsLiteral() != NULL && AsLiteral()->handle()->IsString();
return AsLiteral() != NULL && AsLiteral()->value()->IsString();
}
bool Expression::IsNullLiteral() {
return AsLiteral() != NULL && AsLiteral()->handle()->IsNull();
return AsLiteral() != NULL && AsLiteral()->value()->IsNull();
}
bool Expression::IsUndefinedLiteral() {
return AsLiteral() != NULL && AsLiteral()->handle()->IsUndefined();
return AsLiteral() != NULL && AsLiteral()->value()->IsUndefined();
}
@ -135,6 +135,7 @@ Assignment::Assignment(Isolate* isolate,
binary_operation_(NULL),
assignment_id_(GetNextId(isolate)),
is_monomorphic_(false),
is_uninitialized_(false),
store_mode_(STANDARD_STORE) { }
@ -188,7 +189,7 @@ ObjectLiteralProperty::ObjectLiteralProperty(Literal* key,
emit_store_ = true;
key_ = key;
value_ = value;
Object* k = *key->handle();
Object* k = *key->value();
if (k->IsInternalizedString() &&
isolate->heap()->proto_string()->Equals(String::cast(k))) {
kind_ = PROTOTYPE;
@ -262,7 +263,7 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) {
for (int i = properties()->length() - 1; i >= 0; i--) {
ObjectLiteral::Property* property = properties()->at(i);
Literal* literal = property->key();
if (literal->handle()->IsNull()) continue;
if (literal->value()->IsNull()) continue;
uint32_t hash = literal->Hash();
// If the key of a computed property is in the table, do not emit
// a store for the property later.
@ -287,6 +288,16 @@ void TargetCollector::AddTarget(Label* target, Zone* zone) {
}
void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
// TODO(olivf) If this Operation is used in a test context, then the
// expression has a ToBoolean stub and we want to collect the type
// information. However the GraphBuilder expects it to be on the instruction
// corresponding to the TestContext, therefore we have to store it here and
// not on the operand.
set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id()));
}
bool UnaryOperation::ResultOverwriteAllowed() {
switch (op_) {
case Token::BIT_NOT:
@ -298,6 +309,16 @@ bool UnaryOperation::ResultOverwriteAllowed() {
}
void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
// TODO(olivf) If this Operation is used in a test context, then the right
// hand side has a ToBoolean stub and we want to collect the type information.
// However the GraphBuilder expects it to be on the instruction corresponding
// to the TestContext, therefore we have to store it here and not on the
// right hand operand.
set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id()));
}
bool BinaryOperation::ResultOverwriteAllowed() {
switch (op_) {
case Token::COMMA:
@ -337,7 +358,7 @@ static bool MatchLiteralCompareTypeof(Expression* left,
Handle<String>* check) {
if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
*expr = left->AsUnaryOperation()->expression();
*check = Handle<String>::cast(right->AsLiteral()->handle());
*check = Handle<String>::cast(right->AsLiteral()->value());
return true;
}
return false;
@ -417,6 +438,10 @@ bool FunctionDeclaration::IsInlineable() const {
// ----------------------------------------------------------------------------
// Recording of type feedback
// TODO(rossberg): all RecordTypeFeedback functions should disappear
// once we use the common type field in the AST consistently.
void ForInStatement::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
for_in_type_ = static_cast<ForInType>(oracle->ForInType(this));
}
@ -444,8 +469,8 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle,
is_function_prototype_ = true;
} else {
Literal* lit_key = key()->AsLiteral();
ASSERT(lit_key != NULL && lit_key->handle()->IsString());
Handle<String> name = Handle<String>::cast(lit_key->handle());
ASSERT(lit_key != NULL && lit_key->value()->IsString());
Handle<String> name = Handle<String>::cast(lit_key->value());
oracle->LoadReceiverTypes(this, name, &receiver_types_);
}
} else if (oracle->LoadIsBuiltin(this, Builtins::kKeyedLoadIC_String)) {
@ -465,12 +490,14 @@ void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle,
Property* prop = target()->AsProperty();
ASSERT(prop != NULL);
TypeFeedbackId id = AssignmentFeedbackId();
is_uninitialized_ = oracle->StoreIsUninitialized(id);
if (is_uninitialized_) return;
is_monomorphic_ = oracle->StoreIsMonomorphicNormal(id);
receiver_types_.Clear();
if (prop->key()->IsPropertyName()) {
Literal* lit_key = prop->key()->AsLiteral();
ASSERT(lit_key != NULL && lit_key->handle()->IsString());
Handle<String> name = Handle<String>::cast(lit_key->handle());
ASSERT(lit_key != NULL && lit_key->value()->IsString());
Handle<String> name = Handle<String>::cast(lit_key->value());
oracle->StoreReceiverTypes(this, name, &receiver_types_);
} else if (is_monomorphic_) {
// Record receiver type for monomorphic keyed stores.
@ -503,19 +530,7 @@ void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle,
void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
TypeInfo info = oracle->SwitchType(this);
if (info.IsUninitialized()) info = TypeInfo::Unknown();
if (info.IsSmi()) {
compare_type_ = SMI_ONLY;
} else if (info.IsInternalizedString()) {
compare_type_ = NAME_ONLY;
} else if (info.IsNonInternalizedString()) {
compare_type_ = STRING_ONLY;
} else if (info.IsNonPrimitive()) {
compare_type_ = OBJECT_ONLY;
} else {
ASSERT(compare_type_ == NONE);
}
compare_type_ = oracle->ClauseType(CompareId());
}
@ -570,11 +585,11 @@ bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
LookupResult* lookup) {
target_ = Handle<JSFunction>::null();
cell_ = Handle<JSGlobalPropertyCell>::null();
cell_ = Handle<Cell>::null();
ASSERT(lookup->IsFound() &&
lookup->type() == NORMAL &&
lookup->holder() == *global);
cell_ = Handle<JSGlobalPropertyCell>(global->GetPropertyCell(lookup));
cell_ = Handle<Cell>(global->GetPropertyCell(lookup));
if (cell_->value()->IsJSFunction()) {
Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
// If the function is in new space we assume it's more likely to
@ -624,8 +639,8 @@ void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
} 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());
ASSERT(key != NULL && key->value()->IsString());
Handle<String> name = Handle<String>::cast(key->value());
receiver_types_.Clear();
oracle->CallReceiverTypes(this, name, call_kind, &receiver_types_);
#ifdef DEBUG
@ -674,31 +689,6 @@ void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
}
void UnaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
type_ = oracle->UnaryType(this);
}
void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
oracle->BinaryType(this, &left_type_, &right_type_, &result_type_,
&has_fixed_right_arg_, &fixed_right_arg_value_);
}
void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
oracle->CompareType(this, &left_type_, &right_type_, &overall_type_);
if (!overall_type_.IsUninitialized() && overall_type_.IsNonPrimitive() &&
(op_ == Token::EQ || op_ == Token::EQ_STRICT)) {
map_ = oracle->GetCompareMap(this);
} else {
// May be a compare to nil.
map_ = oracle->CompareNilMonomorphicReceiverType(this);
if (op_ != Token::EQ_STRICT)
compare_nil_types_ = oracle->CompareNilTypes(this);
}
}
// ----------------------------------------------------------------------------
// Implementation of AstVisitor
@ -1072,7 +1062,7 @@ CaseClause::CaseClause(Isolate* isolate,
: label_(label),
statements_(statements),
position_(pos),
compare_type_(NONE),
compare_type_(Type::None(), isolate),
compare_id_(AstNode::GetNextId(isolate)),
entry_id_(AstNode::GetNextId(isolate)) {
}
@ -1182,18 +1172,18 @@ void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
Handle<String> Literal::ToString() {
if (handle_->IsString()) return Handle<String>::cast(handle_);
if (value_->IsString()) return Handle<String>::cast(value_);
Factory* factory = Isolate::Current()->factory();
ASSERT(handle_->IsNumber());
ASSERT(value_->IsNumber());
char arr[100];
Vector<char> buffer(arr, ARRAY_SIZE(arr));
const char* str;
if (handle_->IsSmi()) {
if (value_->IsSmi()) {
// Optimization only, the heap number case would subsume this.
OS::SNPrintF(buffer, "%d", Smi::cast(*handle_)->value());
OS::SNPrintF(buffer, "%d", Smi::cast(*value_)->value());
str = arr;
} else {
str = DoubleToCString(handle_->Number(), buffer);
str = DoubleToCString(value_->Number(), buffer);
}
return factory->NewStringFromAscii(CStrVector(str));
}

113
deps/v8/src/ast.h

@ -356,8 +356,11 @@ class Expression: public AstNode {
// True iff the expression is the undefined literal.
bool IsUndefinedLiteral();
// Expression type
Handle<Type> type() { return type_; }
// Expression type bounds
Handle<Type> upper_type() { return upper_type_; }
Handle<Type> lower_type() { return lower_type_; }
void set_upper_type(Handle<Type> type) { upper_type_ = type; }
void set_lower_type(Handle<Type> type) { lower_type_ = type; }
// Type feedback information for assignments and properties.
virtual bool IsMonomorphic() {
@ -380,7 +383,7 @@ class Expression: public AstNode {
}
// TODO(rossberg): this should move to its own AST node eventually.
void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
byte to_boolean_types() const { return to_boolean_types_; }
BailoutId id() const { return id_; }
@ -388,12 +391,15 @@ class Expression: public AstNode {
protected:
explicit Expression(Isolate* isolate)
: type_(Type::Any(), isolate),
: upper_type_(Type::Any(), isolate),
lower_type_(Type::None(), isolate),
id_(GetNextId(isolate)),
test_id_(GetNextId(isolate)) {}
void set_to_boolean_types(byte types) { to_boolean_types_ = types; }
private:
Handle<Type> type_;
Handle<Type> upper_type_;
Handle<Type> lower_type_;
byte to_boolean_types_;
const BailoutId id_;
@ -1106,24 +1112,15 @@ class CaseClause: public ZoneObject {
// Type feedback information.
TypeFeedbackId CompareId() { return compare_id_; }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
bool IsSmiCompare() { return compare_type_ == SMI_ONLY; }
bool IsNameCompare() { return compare_type_ == NAME_ONLY; }
bool IsStringCompare() { return compare_type_ == STRING_ONLY; }
bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; }
Handle<Type> compare_type() { return compare_type_; }
private:
Expression* label_;
Label body_target_;
ZoneList<Statement*>* statements_;
int position_;
enum CompareTypeFeedback {
NONE,
SMI_ONLY,
NAME_ONLY,
STRING_ONLY,
OBJECT_ONLY
};
CompareTypeFeedback compare_type_;
Handle<Type> compare_type_;
const TypeFeedbackId compare_id_;
const BailoutId entry_id_;
};
@ -1316,36 +1313,36 @@ class Literal: public Expression {
DECLARE_NODE_TYPE(Literal)
virtual bool IsPropertyName() {
if (handle_->IsInternalizedString()) {
if (value_->IsInternalizedString()) {
uint32_t ignored;
return !String::cast(*handle_)->AsArrayIndex(&ignored);
return !String::cast(*value_)->AsArrayIndex(&ignored);
}
return false;
}
Handle<String> AsPropertyName() {
ASSERT(IsPropertyName());
return Handle<String>::cast(handle_);
return Handle<String>::cast(value_);
}
virtual bool ToBooleanIsTrue() { return handle_->BooleanValue(); }
virtual bool ToBooleanIsFalse() { return !handle_->BooleanValue(); }
virtual bool ToBooleanIsTrue() { return value_->BooleanValue(); }
virtual bool ToBooleanIsFalse() { return !value_->BooleanValue(); }
// Identity testers.
bool IsNull() const {
ASSERT(!handle_.is_null());
return handle_->IsNull();
ASSERT(!value_.is_null());
return value_->IsNull();
}
bool IsTrue() const {
ASSERT(!handle_.is_null());
return handle_->IsTrue();
ASSERT(!value_.is_null());
return value_->IsTrue();
}
bool IsFalse() const {
ASSERT(!handle_.is_null());
return handle_->IsFalse();
ASSERT(!value_.is_null());
return value_->IsFalse();
}
Handle<Object> handle() const { return handle_; }
Handle<Object> value() const { return value_; }
// Support for using Literal as a HashMap key. NOTE: Currently, this works
// only for string and number literals!
@ -1360,14 +1357,14 @@ class Literal: public Expression {
TypeFeedbackId LiteralFeedbackId() const { return reuse(id()); }
protected:
Literal(Isolate* isolate, Handle<Object> handle)
Literal(Isolate* isolate, Handle<Object> value)
: Expression(isolate),
handle_(handle) { }
value_(value) { }
private:
Handle<String> ToString();
Handle<Object> handle_;
Handle<Object> value_;
};
@ -1705,7 +1702,7 @@ class Call: public Expression {
// as the holder!
Handle<JSObject> holder() { return holder_; }
Handle<JSGlobalPropertyCell> cell() { return cell_; }
Handle<Cell> cell() { return cell_; }
bool ComputeTarget(Handle<Map> type, Handle<String> name);
bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupResult* lookup);
@ -1745,7 +1742,7 @@ class Call: public Expression {
SmallMapList receiver_types_;
Handle<JSFunction> target_;
Handle<JSObject> holder_;
Handle<JSGlobalPropertyCell> cell_;
Handle<Cell> cell_;
const BailoutId return_id_;
};
@ -1765,7 +1762,7 @@ class CallNew: public Expression {
virtual bool IsMonomorphic() { return is_monomorphic_; }
Handle<JSFunction> target() const { return target_; }
ElementsKind elements_kind() const { return elements_kind_; }
Handle<JSGlobalPropertyCell> allocation_info_cell() const {
Handle<Cell> allocation_info_cell() const {
return allocation_info_cell_;
}
@ -1792,7 +1789,7 @@ class CallNew: public Expression {
bool is_monomorphic_;
Handle<JSFunction> target_;
ElementsKind elements_kind_;
Handle<JSGlobalPropertyCell> allocation_info_cell_;
Handle<Cell> allocation_info_cell_;
const BailoutId return_id_;
};
@ -1844,8 +1841,8 @@ class UnaryOperation: public Expression {
BailoutId MaterializeFalseId() { return materialize_false_id_; }
TypeFeedbackId UnaryOperationFeedbackId() const { return reuse(id()); }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
TypeInfo type() const { return type_; }
virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
protected:
UnaryOperation(Isolate* isolate,
@ -1866,8 +1863,6 @@ class UnaryOperation: public Expression {
Expression* expression_;
int pos_;
TypeInfo type_;
// For unary not (Token::NOT), the AST ids where true and false will
// actually be materialized, respectively.
const BailoutId materialize_true_id_;
@ -1889,12 +1884,13 @@ class BinaryOperation: public Expression {
BailoutId RightId() const { return right_id_; }
TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
TypeInfo left_type() const { return left_type_; }
TypeInfo right_type() const { return right_type_; }
TypeInfo result_type() const { return result_type_; }
bool has_fixed_right_arg() const { return has_fixed_right_arg_; }
int fixed_right_arg_value() const { return fixed_right_arg_value_; }
// TODO(rossberg): result_type should be subsumed by lower_type.
Handle<Type> result_type() const { return result_type_; }
void set_result_type(Handle<Type> type) { result_type_ = type; }
Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
void set_fixed_right_arg(Maybe<int> arg) { fixed_right_arg_ = arg; }
virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
protected:
BinaryOperation(Isolate* isolate,
@ -1917,11 +1913,10 @@ class BinaryOperation: public Expression {
Expression* right_;
int pos_;
TypeInfo left_type_;
TypeInfo right_type_;
TypeInfo result_type_;
bool has_fixed_right_arg_;
int fixed_right_arg_value_;
Handle<Type> result_type_;
// TODO(rossberg): the fixed arg should probably be represented as a Constant
// type for the RHS.
Maybe<int> fixed_right_arg_;
// The short-circuit logical operations need an AST ID for their
// right-hand subexpression.
@ -2002,12 +1997,8 @@ class CompareOperation: public Expression {
// Type feedback information.
TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
TypeInfo left_type() const { return left_type_; }
TypeInfo right_type() const { return right_type_; }
TypeInfo overall_type() const { return overall_type_; }
byte compare_nil_types() const { return compare_nil_types_; }
Handle<Map> map() const { return map_; }
Handle<Type> combined_type() const { return combined_type_; }
void set_combined_type(Handle<Type> type) { combined_type_ = type; }
// Match special cases.
bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
@ -2034,11 +2025,7 @@ class CompareOperation: public Expression {
Expression* right_;
int pos_;
TypeInfo left_type_;
TypeInfo right_type_;
TypeInfo overall_type_;
byte compare_nil_types_;
Handle<Map> map_;
Handle<Type> combined_type_;
};
@ -2106,6 +2093,7 @@ class Assignment: public Expression {
TypeFeedbackId AssignmentFeedbackId() { return reuse(id()); }
void RecordTypeFeedback(TypeFeedbackOracle* oracle, Zone* zone);
virtual bool IsMonomorphic() { return is_monomorphic_; }
bool IsUninitialized() { return is_uninitialized_; }
virtual SmallMapList* GetReceiverTypes() { return &receiver_types_; }
virtual KeyedAccessStoreMode GetStoreMode() {
return store_mode_;
@ -2136,6 +2124,7 @@ class Assignment: public Expression {
const BailoutId assignment_id_;
bool is_monomorphic_ : 1;
bool is_uninitialized_ : 1;
KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed,
// must have extra bit.
SmallMapList receiver_types_;

10
deps/v8/src/atomicops.h

@ -154,17 +154,17 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
#if defined(THREAD_SANITIZER)
#include "atomicops_internals_tsan.h"
#elif defined(_MSC_VER) && \
(defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64))
(V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
#include "atomicops_internals_x86_msvc.h"
#elif defined(__APPLE__) && \
(defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64))
(V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
#include "atomicops_internals_x86_macosx.h"
#elif defined(__GNUC__) && \
(defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64))
(V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
#include "atomicops_internals_x86_gcc.h"
#elif defined(__GNUC__) && defined(V8_HOST_ARCH_ARM)
#elif defined(__GNUC__) && V8_HOST_ARCH_ARM
#include "atomicops_internals_arm_gcc.h"
#elif defined(__GNUC__) && defined(V8_HOST_ARCH_MIPS)
#elif defined(__GNUC__) && V8_HOST_ARCH_MIPS
#include "atomicops_internals_mips_gcc.h"
#else
#error "Atomic operations are not supported on your platform"

249
deps/v8/src/atomicops_internals_tsan.h

@ -62,97 +62,162 @@ typedef short __tsan_atomic16; // NOLINT
typedef int __tsan_atomic32;
typedef long __tsan_atomic64; // NOLINT
#if defined(__SIZEOF_INT128__) \
|| (__clang_major__ * 100 + __clang_minor__ >= 302)
typedef __int128 __tsan_atomic128;
#define __TSAN_HAS_INT128 1
#else
typedef char __tsan_atomic128;
#define __TSAN_HAS_INT128 0
#endif
typedef enum {
__tsan_memory_order_relaxed = (1 << 0) + 100500,
__tsan_memory_order_consume = (1 << 1) + 100500,
__tsan_memory_order_acquire = (1 << 2) + 100500,
__tsan_memory_order_release = (1 << 3) + 100500,
__tsan_memory_order_acq_rel = (1 << 4) + 100500,
__tsan_memory_order_seq_cst = (1 << 5) + 100500,
__tsan_memory_order_relaxed,
__tsan_memory_order_consume,
__tsan_memory_order_acquire,
__tsan_memory_order_release,
__tsan_memory_order_acq_rel,
__tsan_memory_order_seq_cst,
} __tsan_memory_order;
__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8* a,
__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
__tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
__tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16* a,
__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
__tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32* a,
__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
__tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64* a,
__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a,
__tsan_memory_order mo);
void __tsan_atomic8_store(volatile __tsan_atomic8* a, __tsan_atomic8 v,
void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
__tsan_memory_order mo);
void __tsan_atomic16_store(volatile __tsan_atomic16* a, __tsan_atomic16 v,
void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
__tsan_memory_order mo);
void __tsan_atomic32_store(volatile __tsan_atomic32* a, __tsan_atomic32 v,
void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
__tsan_memory_order mo);
void __tsan_atomic64_store(volatile __tsan_atomic64* a, __tsan_atomic64 v,
void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
__tsan_memory_order mo);
void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v,
__tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8* a,
__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16* a,
__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32* a,
__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64* a,
__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8* a,
__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16* a,
__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32* a,
__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64* a,
__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8* a,
__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16* a,
__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32* a,
__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64* a,
__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8* a,
__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16* a,
__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32* a,
__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64* a,
__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8* a,
__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16* a,
__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32* a,
__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64* a,
__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8* a,
__tsan_atomic8* c, __tsan_atomic8 v, __tsan_memory_order mo);
int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16* a,
__tsan_atomic16* c, __tsan_atomic16 v, __tsan_memory_order mo);
int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32* a,
__tsan_atomic32* c, __tsan_atomic32 v, __tsan_memory_order mo);
int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64* a,
__tsan_atomic64* c, __tsan_atomic64 v, __tsan_memory_order mo);
int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8* a,
__tsan_atomic8* c, __tsan_atomic8 v, __tsan_memory_order mo);
int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16* a,
__tsan_atomic16* c, __tsan_atomic16 v, __tsan_memory_order mo);
int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32* a,
__tsan_atomic32* c, __tsan_atomic32 v, __tsan_memory_order mo);
int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64* a,
__tsan_atomic64* c, __tsan_atomic64 v, __tsan_memory_order mo);
int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
__tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
__tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
void __tsan_atomic_thread_fence(__tsan_memory_order mo);
void __tsan_atomic_signal_fence(__tsan_memory_order mo);
#ifdef __cplusplus
} // extern "C"
@ -160,166 +225,166 @@ void __tsan_atomic_thread_fence(__tsan_memory_order mo);
#endif // #ifndef TSAN_INTERFACE_ATOMIC_H
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
Atomic32 old_value,
Atomic32 new_value) {
Atomic32 cmp = old_value;
__tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_relaxed);
__tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
return cmp;
}
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
Atomic32 new_value) {
return __tsan_atomic32_exchange(ptr, new_value,
__tsan_memory_order_relaxed);
__tsan_memory_order_relaxed);
}
inline Atomic32 Acquire_AtomicExchange(volatile Atomic32* ptr,
inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
Atomic32 new_value) {
return __tsan_atomic32_exchange(ptr, new_value,
__tsan_memory_order_acquire);
__tsan_memory_order_acquire);
}
inline Atomic32 Release_AtomicExchange(volatile Atomic32* ptr,
inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
Atomic32 new_value) {
return __tsan_atomic32_exchange(ptr, new_value,
__tsan_memory_order_release);
__tsan_memory_order_release);
}
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
Atomic32 increment) {
return increment + __tsan_atomic32_fetch_add(ptr, increment,
__tsan_memory_order_relaxed);
__tsan_memory_order_relaxed);
}
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
Atomic32 increment) {
return increment + __tsan_atomic32_fetch_add(ptr, increment,
__tsan_memory_order_acq_rel);
__tsan_memory_order_acq_rel);
}
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
Atomic32 old_value,
Atomic32 new_value) {
Atomic32 cmp = old_value;
__tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_acquire);
__tsan_memory_order_acquire, __tsan_memory_order_acquire);
return cmp;
}
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
Atomic32 old_value,
Atomic32 new_value) {
Atomic32 cmp = old_value;
__tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_release);
__tsan_memory_order_release, __tsan_memory_order_relaxed);
return cmp;
}
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
__tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
}
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
__tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
}
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
__tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
}
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
}
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
}
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
}
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
Atomic64 old_value,
Atomic64 new_value) {
Atomic64 cmp = old_value;
__tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_relaxed);
__tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
return cmp;
}
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
Atomic64 new_value) {
return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed);
}
inline Atomic64 Acquire_AtomicExchange(volatile Atomic64* ptr,
inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
Atomic64 new_value) {
return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire);
}
inline Atomic64 Release_AtomicExchange(volatile Atomic64* ptr,
inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
Atomic64 new_value) {
return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release);
}
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
Atomic64 increment) {
return increment + __tsan_atomic64_fetch_add(ptr, increment,
__tsan_memory_order_relaxed);
__tsan_memory_order_relaxed);
}
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
Atomic64 increment) {
return increment + __tsan_atomic64_fetch_add(ptr, increment,
__tsan_memory_order_acq_rel);
__tsan_memory_order_acq_rel);
}
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
__tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
}
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
__tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
}
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
__tsan_atomic64_store(ptr, value, __tsan_memory_order_release);
}
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
}
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire);
}
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
}
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
Atomic64 old_value,
Atomic64 new_value) {
Atomic64 cmp = old_value;
__tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_acquire);
__tsan_memory_order_acquire, __tsan_memory_order_acquire);
return cmp;
}
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
Atomic64 old_value,
Atomic64 new_value) {
Atomic64 cmp = old_value;
__tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_release);
__tsan_memory_order_release, __tsan_memory_order_relaxed);
return cmp;
}

88
deps/v8/src/bootstrapper.cc

@ -45,6 +45,10 @@
#include "extensions/statistics-extension.h"
#include "code-stubs.h"
#if defined(V8_I18N_SUPPORT)
#include "extensions/i18n/i18n-extension.h"
#endif
namespace v8 {
namespace internal {
@ -102,6 +106,9 @@ void Bootstrapper::InitializeOncePerProcess() {
GCExtension::Register();
ExternalizeStringExtension::Register();
StatisticsExtension::Register();
#if defined(V8_I18N_SUPPORT)
v8_i18n::Extension::Register();
#endif
}
@ -538,31 +545,33 @@ void Genesis::SetStrictFunctionInstanceDescriptor(
if (prototypeMode != DONT_ADD_PROTOTYPE) {
prototype = factory()->NewForeign(&Accessors::FunctionPrototype);
}
PropertyAttributes attribs = static_cast<PropertyAttributes>(
DONT_ENUM | DONT_DELETE);
PropertyAttributes rw_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
PropertyAttributes ro_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
map->set_instance_descriptors(*descriptors);
{ // Add length.
CallbacksDescriptor d(*factory()->length_string(), *length, attribs);
CallbacksDescriptor d(*factory()->length_string(), *length, ro_attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add name.
CallbacksDescriptor d(*factory()->name_string(), *name, attribs);
CallbacksDescriptor d(*factory()->name_string(), *name, rw_attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add arguments.
CallbacksDescriptor d(*factory()->arguments_string(), *arguments, attribs);
CallbacksDescriptor d(*factory()->arguments_string(), *arguments,
rw_attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add caller.
CallbacksDescriptor d(*factory()->caller_string(), *caller, attribs);
CallbacksDescriptor d(*factory()->caller_string(), *caller, rw_attribs);
map->AppendDescriptor(&d, witness);
}
if (prototypeMode != DONT_ADD_PROTOTYPE) {
// Add prototype.
if (prototypeMode != ADD_WRITEABLE_PROTOTYPE) {
attribs = static_cast<PropertyAttributes>(attribs | READ_ONLY);
}
PropertyAttributes attribs =
prototypeMode == ADD_WRITEABLE_PROTOTYPE ? rw_attribs : ro_attribs;
CallbacksDescriptor d(*factory()->prototype_string(), *prototype, attribs);
map->AppendDescriptor(&d, witness);
}
@ -857,12 +866,18 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
isolate->initial_object_prototype(),
Builtins::kArrayCode, true, true);
array_function->shared()->DontAdaptArguments();
array_function->shared()->set_function_data(Smi::FromInt(kArrayCode));
// This seems a bit hackish, but we need to make sure Array.length
// is 1.
array_function->shared()->set_length(1);
Handle<Map> initial_map(array_function->initial_map());
// This assert protects an optimization in
// HGraphBuilder::JSArrayBuilder::EmitMapCode()
ASSERT(initial_map->elements_kind() == GetInitialFastElementsKind());
Handle<DescriptorArray> array_descriptors(
factory->NewDescriptorArray(0, 1));
DescriptorArray::WhitenessWitness witness(*array_descriptors);
@ -883,16 +898,11 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// overwritten by JS code.
native_context()->set_array_function(*array_function);
if (FLAG_optimize_constructed_arrays) {
// Cache the array maps, needed by ArrayConstructorStub
CacheInitialJSArrayMaps(native_context(), initial_map);
ArrayConstructorStub array_constructor_stub(isolate);
Handle<Code> code = array_constructor_stub.GetCode(isolate);
array_function->shared()->set_construct_stub(*code);
} else {
array_function->shared()->set_construct_stub(
isolate->builtins()->builtin(Builtins::kCommonArrayConstructCode));
}
// Cache the array maps, needed by ArrayConstructorStub
CacheInitialJSArrayMaps(native_context(), initial_map);
ArrayConstructorStub array_constructor_stub(isolate);
Handle<Code> code = array_constructor_stub.GetCode(isolate);
array_function->shared()->set_construct_stub(*code);
}
{ // --- N u m b e r ---
@ -1359,6 +1369,14 @@ void Genesis::InitializeExperimentalGlobal() {
Handle<JSFunction> uint8c_fun = InstallTypedArray("Uint8ClampedArray",
EXTERNAL_PIXEL_ELEMENTS);
native_context()->set_uint8c_array_fun(*uint8c_fun);
Handle<JSFunction> data_view_fun =
InstallFunction(
global, "DataView", JS_DATA_VIEW_TYPE,
JSDataView::kSize,
isolate()->initial_object_prototype(),
Builtins::kIllegal, true, true);
native_context()->set_data_view_fun(*data_view_fun);
}
if (FLAG_harmony_generators) {
@ -1612,15 +1630,9 @@ Handle<JSFunction> Genesis::InstallInternalArray(
factory()->NewJSObject(isolate()->object_function(), TENURED);
SetPrototype(array_function, prototype);
if (FLAG_optimize_constructed_arrays) {
InternalArrayConstructorStub internal_array_constructor_stub(isolate());
Handle<Code> code = internal_array_constructor_stub.GetCode(isolate());
array_function->shared()->set_construct_stub(*code);
} else {
array_function->shared()->set_construct_stub(
isolate()->builtins()->builtin(Builtins::kCommonArrayConstructCode));
}
InternalArrayConstructorStub internal_array_constructor_stub(isolate());
Handle<Code> code = internal_array_constructor_stub.GetCode(isolate());
array_function->shared()->set_construct_stub(*code);
array_function->shared()->DontAdaptArguments();
Handle<Map> original_map(array_function->initial_map());
@ -2274,6 +2286,12 @@ bool Genesis::InstallExtensions(Handle<Context> native_context,
InstallExtension(isolate, "v8/statistics", &extension_states);
}
#if defined(V8_I18N_SUPPORT)
if (FLAG_enable_i18n) {
InstallExtension(isolate, "v8/i18n", &extension_states);
}
#endif
if (extensions == NULL) return true;
// Install required extensions
int count = v8::ImplementationUtilities::GetNameCount(extensions);
@ -2499,8 +2517,9 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
Handle<Name> key = Handle<Name>(Name::cast(raw_key));
Handle<Object> value = Handle<Object>(properties->ValueAt(i),
isolate());
if (value->IsJSGlobalPropertyCell()) {
value = Handle<Object>(JSGlobalPropertyCell::cast(*value)->value(),
ASSERT(!value->IsCell());
if (value->IsPropertyCell()) {
value = Handle<Object>(PropertyCell::cast(*value)->value(),
isolate());
}
PropertyDetails details = properties->DetailsAt(i);
@ -2574,7 +2593,14 @@ Genesis::Genesis(Isolate* isolate,
StackLimitCheck check(isolate);
if (check.HasOverflowed()) return;
native_context_ = Snapshot::NewContextFromSnapshot();
// We can only de-serialize a context if the isolate was initialized from
// a snapshot. Otherwise we have to build the context from scratch.
if (isolate->initialized_from_snapshot()) {
native_context_ = Snapshot::NewContextFromSnapshot();
} else {
native_context_ = Handle<Context>();
}
if (!native_context().is_null()) {
AddToWeakNativeContextList(*native_context());
isolate->set_context(*native_context());

63
deps/v8/src/builtins.cc

@ -31,6 +31,7 @@
#include "arguments.h"
#include "bootstrapper.h"
#include "builtins.h"
#include "cpu-profiler.h"
#include "gdb-jit.h"
#include "ic-inl.h"
#include "heap-profiler.h"
@ -209,23 +210,21 @@ static MaybeObject* ArrayCodeGenericCommon(Arguments* args,
MaybeObject* maybe_array = array->Initialize(0);
if (maybe_array->IsFailure()) return maybe_array;
if (FLAG_optimize_constructed_arrays) {
AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(array);
ElementsKind to_kind = array->GetElementsKind();
if (info != NULL && info->GetElementsKindPayload(&to_kind)) {
if (IsMoreGeneralElementsKindTransition(array->GetElementsKind(),
to_kind)) {
// We have advice that we should change the elements kind
if (FLAG_trace_track_allocation_sites) {
PrintF("AllocationSiteInfo: pre-transitioning array %p(%s->%s)\n",
reinterpret_cast<void*>(array),
ElementsKindToString(array->GetElementsKind()),
ElementsKindToString(to_kind));
}
maybe_array = array->TransitionElementsKind(to_kind);
if (maybe_array->IsFailure()) return maybe_array;
AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(array);
ElementsKind to_kind = array->GetElementsKind();
if (info != NULL && info->GetElementsKindPayload(&to_kind)) {
if (IsMoreGeneralElementsKindTransition(array->GetElementsKind(),
to_kind)) {
// We have advice that we should change the elements kind
if (FLAG_trace_track_allocation_sites) {
PrintF("AllocationSiteInfo: pre-transitioning array %p(%s->%s)\n",
reinterpret_cast<void*>(array),
ElementsKindToString(array->GetElementsKind()),
ElementsKindToString(to_kind));
}
maybe_array = array->TransitionElementsKind(to_kind);
if (maybe_array->IsFailure()) return maybe_array;
}
}
@ -1267,14 +1266,7 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
args.length() - 1,
is_construct);
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
ExternalCallbackScope call_scope(isolate,
v8::ToCData<Address>(callback_obj));
value = custom.Call(callback);
}
v8::Handle<v8::Value> value = custom.Call(callback);
if (value.IsEmpty()) {
result = heap->undefined_value();
} else {
@ -1343,14 +1335,7 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
&args[0] - 1,
args.length() - 1,
is_construct_call);
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
ExternalCallbackScope call_scope(isolate,
v8::ToCData<Address>(callback_obj));
value = custom.Call(callback);
}
v8::Handle<v8::Value> value = custom.Call(callback);
if (value.IsEmpty()) {
result = heap->undefined_value();
} else {
@ -1496,12 +1481,12 @@ static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
StoreIC::GenerateRuntimeSetProperty(masm, kNonStrictMode);
}
static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
StoreIC::GenerateGlobalProxy(masm, kStrictMode);
StoreIC::GenerateRuntimeSetProperty(masm, kStrictMode);
}
@ -1510,6 +1495,16 @@ static void Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) {
}
static void Generate_StoreIC_Generic(MacroAssembler* masm) {
StoreIC::GenerateRuntimeSetProperty(masm, kNonStrictMode);
}
static void Generate_StoreIC_Generic_Strict(MacroAssembler* masm) {
StoreIC::GenerateRuntimeSetProperty(masm, kStrictMode);
}
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
}

7
deps/v8/src/builtins.h

@ -166,6 +166,10 @@ enum BuiltinExtraArguments {
Code::kNoExtraICState) \
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC, \
Code::kNoExtraICState) \
V(StoreIC_Generic, STORE_IC, GENERIC, \
Code::kNoExtraICState) \
V(StoreIC_Generic_Strict, STORE_IC, GENERIC, \
kStrictMode) \
V(StoreIC_GlobalProxy, STORE_IC, GENERIC, \
Code::kNoExtraICState) \
V(StoreIC_Initialize_Strict, STORE_IC, UNINITIALIZED, \
@ -204,8 +208,6 @@ enum BuiltinExtraArguments {
V(InternalArrayCode, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(ArrayCode, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(CommonArrayConstructCode, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
\
V(StringConstructCode, BUILTIN, UNINITIALIZED, \
@ -395,7 +397,6 @@ class Builtins {
static void Generate_InternalArrayCode(MacroAssembler* masm);
static void Generate_ArrayCode(MacroAssembler* masm);
static void Generate_CommonArrayConstructCode(MacroAssembler* masm);
static void Generate_StringConstructCode(MacroAssembler* masm);
static void Generate_OnStackReplacement(MacroAssembler* masm);

60
deps/v8/src/code-stubs-hydrogen.cc

@ -106,7 +106,8 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
};
HValue* BuildArrayConstructor(ElementsKind kind,
bool disable_allocation_sites,
ContextCheckMode context_mode,
AllocationSiteOverrideMode override_mode,
ArgumentClass argument_class);
HValue* BuildInternalArrayConstructor(ElementsKind kind,
ArgumentClass argument_class);
@ -144,7 +145,7 @@ bool CodeStubGraphBuilderBase::BuildGraph() {
set_current_block(next_block);
HConstant* undefined_constant = new(zone) HConstant(
isolate()->factory()->undefined_value(), Representation::Tagged());
isolate()->factory()->undefined_value());
AddInstruction(undefined_constant);
graph()->set_undefined_constant(undefined_constant);
@ -196,8 +197,7 @@ bool CodeStubGraphBuilderBase::BuildGraph() {
stack_pop_count->ClearFlag(HValue::kCanOverflow);
} else {
int count = descriptor_->hint_stack_parameter_count_;
stack_pop_count = AddInstruction(new(zone)
HConstant(count, Representation::Integer32()));
stack_pop_count = AddInstruction(new(zone) HConstant(count));
}
}
@ -391,13 +391,11 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
HValue* boilerplate_size =
AddInstruction(new(zone) HInstanceSize(boilerplate));
HValue* size_in_words =
AddInstruction(new(zone) HConstant(size >> kPointerSizeLog2,
Representation::Integer32()));
AddInstruction(new(zone) HConstant(size >> kPointerSizeLog2));
checker.IfCompare(boilerplate_size, size_in_words, Token::EQ);
checker.Then();
HValue* size_in_bytes =
AddInstruction(new(zone) HConstant(size, Representation::Integer32()));
HValue* size_in_bytes = AddInstruction(new(zone) HConstant(size));
HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
if (isolate()->heap()->ShouldGloballyPretenure()) {
flags = static_cast<HAllocate::Flags>(
@ -512,8 +510,7 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
HInstruction* elements = AddLoadElements(js_array);
HInstruction* elements_length =
AddInstruction(new(zone) HFixedArrayBaseLength(elements));
HInstruction* elements_length = AddLoadFixedArrayLength(elements);
HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
context(), to_kind, elements_length);
@ -537,15 +534,19 @@ Handle<Code> TransitionElementsKindStub::GenerateCode() {
}
HValue* CodeStubGraphBuilderBase::BuildArrayConstructor(
ElementsKind kind, bool disable_allocation_sites,
ElementsKind kind,
ContextCheckMode context_mode,
AllocationSiteOverrideMode override_mode,
ArgumentClass argument_class) {
HValue* constructor = GetParameter(ArrayConstructorStubBase::kConstructor);
HValue* property_cell = GetParameter(ArrayConstructorStubBase::kPropertyCell);
HInstruction* array_function = BuildGetArrayFunction(context());
if (context_mode == CONTEXT_CHECK_REQUIRED) {
HInstruction* array_function = BuildGetArrayFunction(context());
ArrayContextChecker checker(this, constructor, array_function);
}
ArrayContextChecker(this, constructor, array_function);
JSArrayBuilder array_builder(this, kind, property_cell,
disable_allocation_sites);
HValue* property_cell = GetParameter(ArrayConstructorStubBase::kPropertyCell);
JSArrayBuilder array_builder(this, kind, property_cell, constructor,
override_mode);
HValue* result = NULL;
switch (argument_class) {
case NONE:
@ -558,6 +559,7 @@ HValue* CodeStubGraphBuilderBase::BuildArrayConstructor(
result = BuildArrayNArgumentsConstructor(&array_builder, kind);
break;
}
return result;
}
@ -602,7 +604,7 @@ HValue* CodeStubGraphBuilderBase::BuildArraySingleArgumentConstructor(
HConstant* initial_capacity_node = new(zone()) HConstant(initial_capacity);
AddInstruction(initial_capacity_node);
HBoundsCheck* checked_arg = AddBoundsCheck(argument, max_alloc_length);
HBoundsCheck* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length);
IfBuilder if_builder(this);
if_builder.IfCompare(checked_arg, constant_zero, Token::EQ);
if_builder.Then();
@ -655,8 +657,9 @@ HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor(
template <>
HValue* CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() {
ElementsKind kind = casted_stub()->elements_kind();
bool disable_allocation_sites = casted_stub()->disable_allocation_sites();
return BuildArrayConstructor(kind, disable_allocation_sites, NONE);
ContextCheckMode context_mode = casted_stub()->context_mode();
AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
return BuildArrayConstructor(kind, context_mode, override_mode, NONE);
}
@ -669,8 +672,9 @@ template <>
HValue* CodeStubGraphBuilder<ArraySingleArgumentConstructorStub>::
BuildCodeStub() {
ElementsKind kind = casted_stub()->elements_kind();
bool disable_allocation_sites = casted_stub()->disable_allocation_sites();
return BuildArrayConstructor(kind, disable_allocation_sites, SINGLE);
ContextCheckMode context_mode = casted_stub()->context_mode();
AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
return BuildArrayConstructor(kind, context_mode, override_mode, SINGLE);
}
@ -682,8 +686,9 @@ Handle<Code> ArraySingleArgumentConstructorStub::GenerateCode() {
template <>
HValue* CodeStubGraphBuilder<ArrayNArgumentsConstructorStub>::BuildCodeStub() {
ElementsKind kind = casted_stub()->elements_kind();
bool disable_allocation_sites = casted_stub()->disable_allocation_sites();
return BuildArrayConstructor(kind, disable_allocation_sites, MULTIPLE);
ContextCheckMode context_mode = casted_stub()->context_mode();
AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
return BuildArrayConstructor(kind, context_mode, override_mode, MULTIPLE);
}
@ -733,12 +738,13 @@ Handle<Code> InternalArrayNArgumentsConstructorStub::GenerateCode() {
template <>
HValue* CodeStubGraphBuilder<CompareNilICStub>::BuildCodeInitializedStub() {
Isolate* isolate = graph()->isolate();
CompareNilICStub* stub = casted_stub();
HIfContinuation continuation;
Handle<Map> sentinel_map(graph()->isolate()->heap()->meta_map());
BuildCompareNil(GetParameter(0),
stub->GetTypes(), sentinel_map,
RelocInfo::kNoPosition, &continuation);
Handle<Map> sentinel_map(isolate->heap()->meta_map());
Handle<Type> type =
CompareNilICStub::StateToType(isolate, stub->GetState(), sentinel_map);
BuildCompareNil(GetParameter(0), type, RelocInfo::kNoPosition, &continuation);
IfBuilder if_nil(this, &continuation);
if_nil.Then();
if (continuation.IsFalseReachable()) {

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

@ -29,6 +29,7 @@
#include "bootstrapper.h"
#include "code-stubs.h"
#include "cpu-profiler.h"
#include "stub-cache.h"
#include "factory.h"
#include "gdb-jit.h"
@ -431,24 +432,24 @@ void ICCompareStub::Generate(MacroAssembler* masm) {
void CompareNilICStub::Record(Handle<Object> object) {
ASSERT(types_ != Types::FullCompare());
ASSERT(state_ != State::Generic());
if (object->IsNull()) {
types_.Add(NULL_TYPE);
state_.Add(NULL_TYPE);
} else if (object->IsUndefined()) {
types_.Add(UNDEFINED);
state_.Add(UNDEFINED);
} else if (object->IsUndetectableObject() ||
object->IsOddball() ||
!object->IsHeapObject()) {
types_ = Types::FullCompare();
state_ = State::Generic();
} else if (IsMonomorphic()) {
types_ = Types::FullCompare();
state_ = State::Generic();
} else {
types_.Add(MONOMORPHIC_MAP);
state_.Add(MONOMORPHIC_MAP);
}
}
void CompareNilICStub::Types::TraceTransition(Types to) const {
void CompareNilICStub::State::TraceTransition(State to) const {
#ifdef DEBUG
if (!FLAG_trace_ic) return;
char buffer[100];
@ -467,13 +468,13 @@ void CompareNilICStub::Types::TraceTransition(Types to) const {
void CompareNilICStub::PrintName(StringStream* stream) {
stream->Add("CompareNilICStub_");
types_.Print(stream);
state_.Print(stream);
stream->Add((nil_value_ == kNullValue) ? "(NullValue|":
"(UndefinedValue|");
}
void CompareNilICStub::Types::Print(StringStream* stream) const {
void CompareNilICStub::State::Print(StringStream* stream) const {
stream->Add("(");
SimpleListPrinter printer(stream);
if (IsEmpty()) printer.Add("None");
@ -481,10 +482,40 @@ void CompareNilICStub::Types::Print(StringStream* stream) const {
if (Contains(NULL_TYPE)) printer.Add("Null");
if (Contains(MONOMORPHIC_MAP)) printer.Add("MonomorphicMap");
if (Contains(UNDETECTABLE)) printer.Add("Undetectable");
if (Contains(GENERIC)) printer.Add("Generic");
stream->Add(")");
}
Handle<Type> CompareNilICStub::StateToType(
Isolate* isolate,
State state,
Handle<Map> map) {
if (state.Contains(CompareNilICStub::GENERIC)) {
return handle(Type::Any(), isolate);
}
Handle<Type> result(Type::None(), isolate);
if (state.Contains(CompareNilICStub::UNDEFINED)) {
result = handle(Type::Union(result, handle(Type::Undefined(), isolate)),
isolate);
}
if (state.Contains(CompareNilICStub::NULL_TYPE)) {
result = handle(Type::Union(result, handle(Type::Null(), isolate)),
isolate);
}
if (state.Contains(CompareNilICStub::UNDETECTABLE)) {
result = handle(Type::Union(result, handle(Type::Undetectable(), isolate)),
isolate);
} else if (state.Contains(CompareNilICStub::MONOMORPHIC_MAP)) {
Type* type = map.is_null() ? Type::Detectable() : Type::Class(map);
result = handle(Type::Union(result, handle(type, isolate)), isolate);
}
return result;
}
void InstanceofStub::PrintName(StringStream* stream) {
const char* args = "";
if (HasArgsInRegisters()) {
@ -727,24 +758,11 @@ void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
}
FunctionEntryHook ProfileEntryHookStub::entry_hook_ = NULL;
void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
intptr_t stack_pointer) {
if (entry_hook_ != NULL)
entry_hook_(function, stack_pointer);
}
bool ProfileEntryHookStub::SetFunctionEntryHook(FunctionEntryHook entry_hook) {
// We don't allow setting a new entry hook over one that's
// already active, as the hooks won't stack.
if (entry_hook != 0 && entry_hook_ != 0)
return false;
entry_hook_ = entry_hook;
return true;
FunctionEntryHook entry_hook = Isolate::Current()->function_entry_hook();
ASSERT(entry_hook != NULL);
entry_hook(function, stack_pointer);
}

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

@ -95,7 +95,7 @@ namespace internal {
V(KeyedLoadField)
// List of code stubs only used on ARM platforms.
#ifdef V8_TARGET_ARCH_ARM
#if V8_TARGET_ARCH_ARM
#define CODE_STUB_LIST_ARM(V) \
V(GetProperty) \
V(SetProperty) \
@ -107,7 +107,7 @@ namespace internal {
#endif
// List of code stubs only used on MIPS platforms.
#ifdef V8_TARGET_ARCH_MIPS
#if V8_TARGET_ARCH_MIPS
#define CODE_STUB_LIST_MIPS(V) \
V(RegExpCEntry) \
V(DirectCEntry)
@ -904,8 +904,7 @@ class BinaryOpStub: public PlatformCodeStub {
left_type_(BinaryOpIC::UNINITIALIZED),
right_type_(BinaryOpIC::UNINITIALIZED),
result_type_(BinaryOpIC::UNINITIALIZED),
has_fixed_right_arg_(false),
encoded_right_arg_(encode_arg_value(1)) {
encoded_right_arg_(false, encode_arg_value(1)) {
Initialize();
ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
}
@ -915,16 +914,15 @@ class BinaryOpStub: public PlatformCodeStub {
BinaryOpIC::TypeInfo left_type,
BinaryOpIC::TypeInfo right_type,
BinaryOpIC::TypeInfo result_type,
bool has_fixed_right_arg,
int32_t fixed_right_arg_value)
Maybe<int32_t> fixed_right_arg)
: op_(OpBits::decode(key)),
mode_(ModeBits::decode(key)),
platform_specific_bit_(PlatformSpecificBits::decode(key)),
left_type_(left_type),
right_type_(right_type),
result_type_(result_type),
has_fixed_right_arg_(has_fixed_right_arg),
encoded_right_arg_(encode_arg_value(fixed_right_arg_value)) { }
encoded_right_arg_(fixed_right_arg.has_value,
encode_arg_value(fixed_right_arg.value)) { }
static void decode_types_from_minor_key(int minor_key,
BinaryOpIC::TypeInfo* left_type,
@ -942,16 +940,14 @@ class BinaryOpStub: public PlatformCodeStub {
return static_cast<Token::Value>(OpBits::decode(minor_key));
}
static bool decode_has_fixed_right_arg_from_minor_key(int minor_key) {
return HasFixedRightArgBits::decode(minor_key);
}
static int decode_fixed_right_arg_value_from_minor_key(int minor_key) {
return decode_arg_value(FixedRightArgValueBits::decode(minor_key));
static Maybe<int> decode_fixed_right_arg_from_minor_key(int minor_key) {
return Maybe<int>(
HasFixedRightArgBits::decode(minor_key),
decode_arg_value(FixedRightArgValueBits::decode(minor_key)));
}
int fixed_right_arg_value() const {
return decode_arg_value(encoded_right_arg_);
return decode_arg_value(encoded_right_arg_.value);
}
static bool can_encode_arg_value(int32_t value) {
@ -975,8 +971,7 @@ class BinaryOpStub: public PlatformCodeStub {
BinaryOpIC::TypeInfo right_type_;
BinaryOpIC::TypeInfo result_type_;
bool has_fixed_right_arg_;
int encoded_right_arg_;
Maybe<int> encoded_right_arg_;
static int encode_arg_value(int32_t value) {
ASSERT(can_encode_arg_value(value));
@ -1009,8 +1004,8 @@ class BinaryOpStub: public PlatformCodeStub {
| LeftTypeBits::encode(left_type_)
| RightTypeBits::encode(right_type_)
| ResultTypeBits::encode(result_type_)
| HasFixedRightArgBits::encode(has_fixed_right_arg_)
| FixedRightArgValueBits::encode(encoded_right_arg_);
| HasFixedRightArgBits::encode(encoded_right_arg_.has_value)
| FixedRightArgValueBits::encode(encoded_right_arg_.value);
}
@ -1124,46 +1119,50 @@ class ICCompareStub: public PlatformCodeStub {
class CompareNilICStub : public HydrogenCodeStub {
public:
enum Type {
enum CompareNilType {
UNDEFINED,
NULL_TYPE,
MONOMORPHIC_MAP,
UNDETECTABLE,
GENERIC,
NUMBER_OF_TYPES
};
class Types : public EnumSet<Type, byte> {
class State : public EnumSet<CompareNilType, byte> {
public:
Types() : EnumSet<Type, byte>(0) { }
explicit Types(byte bits) : EnumSet<Type, byte>(bits) { }
State() : EnumSet<CompareNilType, byte>(0) { }
explicit State(byte bits) : EnumSet<CompareNilType, byte>(bits) { }
static Types FullCompare() {
Types set;
static State Generic() {
State set;
set.Add(UNDEFINED);
set.Add(NULL_TYPE);
set.Add(UNDETECTABLE);
set.Add(GENERIC);
return set;
}
void Print(StringStream* stream) const;
void TraceTransition(Types to) const;
void TraceTransition(State to) const;
};
static Handle<Type> StateToType(
Isolate* isolate, State state, Handle<Map> map = Handle<Map>());
// At most 6 different types can be distinguished, because the Code object
// only has room for a single byte to hold a set and there are two more
// boolean flags we need to store. :-P
STATIC_ASSERT(NUMBER_OF_TYPES <= 6);
CompareNilICStub(NilValue nil, Types types = Types())
: types_(types) {
nil_value_ = nil;
CompareNilICStub(NilValue nil, State state = State())
: nil_value_(nil), state_(state) {
}
CompareNilICStub(Code::ExtraICState ic_state,
InitializationState init_state = INITIALIZED)
: HydrogenCodeStub(init_state) {
nil_value_ = NilValueField::decode(ic_state);
types_ = Types(ExtractTypesFromExtraICState(ic_state));
state_ = State(ExtractTypesFromExtraICState(ic_state));
}
static Handle<Code> GetUninitialized(Isolate* isolate,
@ -1183,9 +1182,9 @@ class CompareNilICStub : public HydrogenCodeStub {
}
virtual InlineCacheState GetICState() {
if (types_ == Types::FullCompare()) {
if (state_ == State::Generic()) {
return MEGAMORPHIC;
} else if (types_.Contains(MONOMORPHIC_MAP)) {
} else if (state_.Contains(MONOMORPHIC_MAP)) {
return MONOMORPHIC;
} else {
return PREMONOMORPHIC;
@ -1198,20 +1197,21 @@ class CompareNilICStub : public HydrogenCodeStub {
// extra ic state = nil_value | type_n-1 | ... | type_0
virtual Code::ExtraICState GetExtraICState() {
return NilValueField::encode(nil_value_) |
types_.ToIntegral();
return NilValueField::encode(nil_value_) | state_.ToIntegral();
}
static byte ExtractTypesFromExtraICState(
Code::ExtraICState state) {
static byte ExtractTypesFromExtraICState(Code::ExtraICState state) {
return state & ((1 << NUMBER_OF_TYPES) - 1);
}
static NilValue ExtractNilValueFromExtraICState(Code::ExtraICState state) {
return NilValueField::decode(state);
}
void Record(Handle<Object> object);
bool IsMonomorphic() const { return types_.Contains(MONOMORPHIC_MAP); }
bool IsMonomorphic() const { return state_.Contains(MONOMORPHIC_MAP); }
NilValue GetNilValue() const { return nil_value_; }
Types GetTypes() const { return types_; }
void ClearTypes() { types_.RemoveAll(); }
State GetState() const { return state_; }
void ClearState() { state_.RemoveAll(); }
virtual void PrintName(StringStream* stream);
@ -1229,7 +1229,7 @@ class CompareNilICStub : public HydrogenCodeStub {
virtual int NotMissMinorKey() { return GetExtraICState(); }
NilValue nil_value_;
Types types_;
State state_;
DISALLOW_COPY_AND_ASSIGN(CompareNilICStub);
};
@ -1733,27 +1733,51 @@ class TransitionElementsKindStub : public HydrogenCodeStub {
};
enum ContextCheckMode {
CONTEXT_CHECK_REQUIRED,
CONTEXT_CHECK_NOT_REQUIRED,
LAST_CONTEXT_CHECK_MODE = CONTEXT_CHECK_NOT_REQUIRED
};
enum AllocationSiteOverrideMode {
DONT_OVERRIDE,
DISABLE_ALLOCATION_SITES,
LAST_ALLOCATION_SITE_OVERRIDE_MODE = DISABLE_ALLOCATION_SITES
};
class ArrayConstructorStubBase : public HydrogenCodeStub {
public:
ArrayConstructorStubBase(ElementsKind kind, bool disable_allocation_sites) {
ArrayConstructorStubBase(ElementsKind kind, ContextCheckMode context_mode,
AllocationSiteOverrideMode override_mode) {
// It only makes sense to override local allocation site behavior
// if there is a difference between the global allocation site policy
// for an ElementsKind and the desired usage of the stub.
ASSERT(!disable_allocation_sites ||
ASSERT(override_mode != DISABLE_ALLOCATION_SITES ||
AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE);
bit_field_ = ElementsKindBits::encode(kind) |
DisableAllocationSitesBits::encode(disable_allocation_sites);
AllocationSiteOverrideModeBits::encode(override_mode) |
ContextCheckModeBits::encode(context_mode);
}
ElementsKind elements_kind() const {
return ElementsKindBits::decode(bit_field_);
}
bool disable_allocation_sites() const {
return DisableAllocationSitesBits::decode(bit_field_);
AllocationSiteOverrideMode override_mode() const {
return AllocationSiteOverrideModeBits::decode(bit_field_);
}
ContextCheckMode context_mode() const {
return ContextCheckModeBits::decode(bit_field_);
}
virtual bool IsPregenerated() {
// We only pre-generate stubs that verify correct context
return context_mode() == CONTEXT_CHECK_REQUIRED;
}
virtual bool IsPregenerated() { return true; }
static void GenerateStubsAheadOfTime(Isolate* isolate);
static void InstallDescriptors(Isolate* isolate);
@ -1764,8 +1788,14 @@ class ArrayConstructorStubBase : public HydrogenCodeStub {
private:
int NotMissMinorKey() { return bit_field_; }
// Ensure data fits within available bits.
STATIC_ASSERT(LAST_ALLOCATION_SITE_OVERRIDE_MODE == 1);
STATIC_ASSERT(LAST_CONTEXT_CHECK_MODE == 1);
class ElementsKindBits: public BitField<ElementsKind, 0, 8> {};
class DisableAllocationSitesBits: public BitField<bool, 8, 1> {};
class AllocationSiteOverrideModeBits: public
BitField<AllocationSiteOverrideMode, 8, 1> {}; // NOLINT
class ContextCheckModeBits: public BitField<ContextCheckMode, 9, 1> {};
uint32_t bit_field_;
DISALLOW_COPY_AND_ASSIGN(ArrayConstructorStubBase);
@ -1776,8 +1806,9 @@ class ArrayNoArgumentConstructorStub : public ArrayConstructorStubBase {
public:
ArrayNoArgumentConstructorStub(
ElementsKind kind,
bool disable_allocation_sites = false)
: ArrayConstructorStubBase(kind, disable_allocation_sites) {
ContextCheckMode context_mode = CONTEXT_CHECK_REQUIRED,
AllocationSiteOverrideMode override_mode = DONT_OVERRIDE)
: ArrayConstructorStubBase(kind, context_mode, override_mode) {
}
virtual Handle<Code> GenerateCode();
@ -1797,8 +1828,9 @@ class ArraySingleArgumentConstructorStub : public ArrayConstructorStubBase {
public:
ArraySingleArgumentConstructorStub(
ElementsKind kind,
bool disable_allocation_sites = false)
: ArrayConstructorStubBase(kind, disable_allocation_sites) {
ContextCheckMode context_mode = CONTEXT_CHECK_REQUIRED,
AllocationSiteOverrideMode override_mode = DONT_OVERRIDE)
: ArrayConstructorStubBase(kind, context_mode, override_mode) {
}
virtual Handle<Code> GenerateCode();
@ -1818,8 +1850,9 @@ class ArrayNArgumentsConstructorStub : public ArrayConstructorStubBase {
public:
ArrayNArgumentsConstructorStub(
ElementsKind kind,
bool disable_allocation_sites = false)
: ArrayConstructorStubBase(kind, disable_allocation_sites) {
ContextCheckMode context_mode = CONTEXT_CHECK_REQUIRED,
AllocationSiteOverrideMode override_mode = DONT_OVERRIDE)
: ArrayConstructorStubBase(kind, context_mode, override_mode) {
}
virtual Handle<Code> GenerateCode();
@ -1971,7 +2004,7 @@ class ToBooleanStub: public HydrogenCodeStub {
class Types : public EnumSet<Type, byte> {
public:
Types() {}
Types() : EnumSet<Type, byte>(0) {}
explicit Types(byte bits) : EnumSet<Type, byte>(bits) {}
byte ToByte() const { return ToIntegral(); }
@ -1980,10 +2013,10 @@ class ToBooleanStub: public HydrogenCodeStub {
bool Record(Handle<Object> object);
bool NeedsMap() const;
bool CanBeUndetectable() const;
};
bool IsGeneric() const { return ToIntegral() == Generic().ToIntegral(); }
static Types no_types() { return Types(); }
static Types all_types() { return Types((1 << NUMBER_OF_TYPES) - 1); }
static Types Generic() { return Types((1 << NUMBER_OF_TYPES) - 1); }
};
explicit ToBooleanStub(Types types = Types())
: types_(types) { }
@ -2135,13 +2168,6 @@ class ProfileEntryHookStub : public PlatformCodeStub {
// Generates a call to the entry hook if it's enabled.
static void MaybeCallEntryHook(MacroAssembler* masm);
// Sets or unsets the entry hook function. Returns true on success,
// false on an attempt to replace a non-NULL entry hook with another
// non-NULL hook.
static bool SetFunctionEntryHook(FunctionEntryHook entry_hook);
static bool HasEntryHook() { return entry_hook_ != NULL; }
private:
static void EntryHookTrampoline(intptr_t function,
intptr_t stack_pointer);
@ -2151,9 +2177,6 @@ class ProfileEntryHookStub : public PlatformCodeStub {
void Generate(MacroAssembler* masm);
// The current function entry hook.
static FunctionEntryHook entry_hook_;
DISALLOW_COPY_AND_ASSIGN(ProfileEntryHookStub);
};

3
deps/v8/src/codegen.cc

@ -30,6 +30,7 @@
#include "bootstrapper.h"
#include "codegen.h"
#include "compiler.h"
#include "cpu-profiler.h"
#include "debug.h"
#include "prettyprinter.h"
#include "rewriter.h"
@ -178,7 +179,7 @@ bool CodeGenerator::ShouldGenerateLog(Expression* type) {
!isolate->cpu_profiler()->is_profiling()) {
return false;
}
Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
Handle<String> name = Handle<String>::cast(type->AsLiteral()->value());
if (FLAG_log_regexp) {
if (name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("regexp")))
return true;

13
deps/v8/src/collection.js

@ -295,6 +295,16 @@ function WeakMapDelete(key) {
}
function WeakMapClear() {
if (!IS_WEAKMAP(this)) {
throw MakeTypeError('incompatible_method_receiver',
['WeakMap.prototype.clear', this]);
}
// Replace the internal table with a new empty table.
%WeakMapInitialize(this);
}
// -------------------------------------------------------------------
function SetUpWeakMap() {
@ -309,7 +319,8 @@ function SetUpWeakMap() {
"get", WeakMapGet,
"set", WeakMapSet,
"has", WeakMapHas,
"delete", WeakMapDelete
"delete", WeakMapDelete,
"clear", WeakMapClear
));
}

113
deps/v8/src/compiler.cc

@ -32,6 +32,7 @@
#include "bootstrapper.h"
#include "codegen.h"
#include "compilation-cache.h"
#include "cpu-profiler.h"
#include "debug.h"
#include "deoptimizer.h"
#include "full-codegen.h"
@ -53,7 +54,8 @@ namespace v8 {
namespace internal {
CompilationInfo::CompilationInfo(Handle<Script> script, Zone* zone)
CompilationInfo::CompilationInfo(Handle<Script> script,
Zone* zone)
: flags_(LanguageModeField::encode(CLASSIC_MODE)),
script_(script),
osr_ast_id_(BailoutId::None()) {
@ -71,7 +73,8 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
}
CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone)
CompilationInfo::CompilationInfo(Handle<JSFunction> closure,
Zone* zone)
: flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
closure_(closure),
shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
@ -83,7 +86,8 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone)
CompilationInfo::CompilationInfo(HydrogenCodeStub* stub,
Isolate* isolate, Zone* zone)
Isolate* isolate,
Zone* zone)
: flags_(LanguageModeField::encode(CLASSIC_MODE) |
IsLazy::encode(true)),
osr_ast_id_(BailoutId::None()) {
@ -92,7 +96,9 @@ CompilationInfo::CompilationInfo(HydrogenCodeStub* stub,
}
void CompilationInfo::Initialize(Isolate* isolate, Mode mode, Zone* zone) {
void CompilationInfo::Initialize(Isolate* isolate,
Mode mode,
Zone* zone) {
isolate_ = isolate;
function_ = NULL;
scope_ = NULL;
@ -106,6 +112,9 @@ void CompilationInfo::Initialize(Isolate* isolate, Mode mode, Zone* zone) {
opt_count_ = shared_info().is_null() ? 0 : shared_info()->opt_count();
no_frame_ranges_ = isolate->cpu_profiler()->is_profiling()
? new List<OffsetRange>(2) : NULL;
for (int i = 0; i < DependentCode::kGroupCount; i++) {
dependencies_[i] = NULL;
}
if (mode == STUB) {
mode_ = STUB;
return;
@ -125,6 +134,47 @@ void CompilationInfo::Initialize(Isolate* isolate, Mode mode, Zone* zone) {
CompilationInfo::~CompilationInfo() {
delete deferred_handles_;
delete no_frame_ranges_;
#ifdef DEBUG
// Check that no dependent maps have been added or added dependent maps have
// been rolled back or committed.
for (int i = 0; i < DependentCode::kGroupCount; i++) {
ASSERT_EQ(NULL, dependencies_[i]);
}
#endif // DEBUG
}
void CompilationInfo::CommitDependencies(Handle<Code> code) {
for (int i = 0; i < DependentCode::kGroupCount; i++) {
ZoneList<Handle<HeapObject> >* group_objects = dependencies_[i];
if (group_objects == NULL) continue;
ASSERT(!object_wrapper_.is_null());
for (int j = 0; j < group_objects->length(); j++) {
DependentCode::DependencyGroup group =
static_cast<DependentCode::DependencyGroup>(i);
DependentCode* dependent_code =
DependentCode::ForObject(group_objects->at(j), group);
dependent_code->UpdateToFinishedCode(group, this, *code);
}
dependencies_[i] = NULL; // Zone-allocated, no need to delete.
}
}
void CompilationInfo::RollbackDependencies() {
// Unregister from all dependent maps if not yet committed.
for (int i = 0; i < DependentCode::kGroupCount; i++) {
ZoneList<Handle<HeapObject> >* group_objects = dependencies_[i];
if (group_objects == NULL) continue;
for (int j = 0; j < group_objects->length(); j++) {
DependentCode::DependencyGroup group =
static_cast<DependentCode::DependencyGroup>(i);
DependentCode* dependent_code =
DependentCode::ForObject(group_objects->at(j), group);
dependent_code->RemoveCompilationInfo(group, this);
}
dependencies_[i] = NULL; // Zone-allocated, no need to delete.
}
}
@ -329,7 +379,10 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
// performance of the hydrogen-based compiler.
bool should_recompile = !info()->shared_info()->has_deoptimization_support();
if (should_recompile || FLAG_hydrogen_stats) {
HPhase phase(HPhase::kFullCodeGen, isolate());
int64_t start_ticks = 0;
if (FLAG_hydrogen_stats) {
start_ticks = OS::Ticks();
}
CompilationInfoWithZone unoptimized(info()->shared_info());
// Note that we use the same AST that we will use for generating the
// optimized code.
@ -346,6 +399,10 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
Compiler::RecordFunctionCompilation(
Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
}
if (FLAG_hydrogen_stats) {
int64_t ticks = OS::Ticks() - start_ticks;
isolate()->GetHStatistics()->IncrementFullCodeGen(ticks);
}
}
// Check that the unoptimized, shared code is ready for
@ -364,7 +421,7 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
}
// Type-check the function.
AstTyper::Type(info());
AstTyper::Run(info());
graph_builder_ = new(info()->zone()) HOptimizedGraphBuilder(info());
@ -490,7 +547,6 @@ static bool DebuggerWantsEagerCompilation(CompilationInfo* info,
static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
Isolate* isolate = info->isolate();
ZoneScope zone_scope(info->zone(), DELETE_ON_EXIT);
PostponeInterruptsScope postpone(isolate);
ASSERT(!isolate->native_context().is_null());
@ -773,7 +829,6 @@ static bool InstallFullCode(CompilationInfo* info) {
// Check the function has compiled code.
ASSERT(shared->is_compiled());
shared->set_code_age(0);
shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize));
shared->set_dont_inline(lit->flags()->Contains(kDontInline));
shared->set_ast_node_count(lit->ast_node_count());
@ -855,8 +910,6 @@ static bool InstallCodeFromOptimizedCodeMap(CompilationInfo* info) {
bool Compiler::CompileLazy(CompilationInfo* info) {
Isolate* isolate = info->isolate();
ZoneScope zone_scope(info->zone(), DELETE_ON_EXIT);
// The VM is in the COMPILER state until exiting this function.
VMState<COMPILER> state(isolate);
@ -982,7 +1035,7 @@ void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
// The function may have already been optimized by OSR. Simply continue.
// Except when OSR already disabled optimization for some reason.
if (info->shared_info()->optimization_disabled()) {
info->SetCode(Handle<Code>(info->shared_info()->code()));
info->AbortOptimization();
InstallFullCode(*info);
if (FLAG_trace_parallel_recompilation) {
PrintF(" ** aborting optimization for ");
@ -1000,9 +1053,14 @@ void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
// If crankshaft succeeded, install the optimized code else install
// the unoptimized code.
OptimizingCompiler::Status status = optimizing_compiler->last_status();
if (status != OptimizingCompiler::SUCCEEDED) {
optimizing_compiler->info()->set_bailout_reason(
"failed/bailed out last time");
if (info->HasAbortedDueToDependencyChange()) {
info->set_bailout_reason("bailed out due to dependent map");
status = optimizing_compiler->AbortOptimization();
} else if (status != OptimizingCompiler::SUCCEEDED) {
info->set_bailout_reason("failed/bailed out last time");
status = optimizing_compiler->AbortOptimization();
} else if (isolate->DebuggerHasBreakPoints()) {
info->set_bailout_reason("debugger is active");
status = optimizing_compiler->AbortOptimization();
} else {
status = optimizing_compiler->GenerateAndInstallCode();
@ -1167,4 +1225,31 @@ void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
info));
}
CompilationPhase::CompilationPhase(const char* name, CompilationInfo* info)
: name_(name), info_(info), zone_(info->isolate()) {
if (FLAG_hydrogen_stats) {
info_zone_start_allocation_size_ = info->zone()->allocation_size();
start_ticks_ = OS::Ticks();
}
}
CompilationPhase::~CompilationPhase() {
if (FLAG_hydrogen_stats) {
unsigned size = zone()->allocation_size();
size += info_->zone()->allocation_size() - info_zone_start_allocation_size_;
int64_t ticks = OS::Ticks() - start_ticks_;
isolate()->GetHStatistics()->SaveTiming(name_, ticks, size);
}
}
bool CompilationPhase::ShouldProduceTraceOutput() const {
// Produce trace output if flag is set so that the first letter of the
// phase name matches the command line parameter FLAG_trace_phase.
return (FLAG_trace_hydrogen &&
OS::StrChr(const_cast<char*>(FLAG_trace_phase), name_[0]) != NULL);
}
} } // namespace v8::internal

95
deps/v8/src/compiler.h

@ -57,12 +57,8 @@ struct OffsetRange {
// is constructed based on the resources available at compile-time.
class CompilationInfo {
public:
CompilationInfo(Handle<Script> script, Zone* zone);
CompilationInfo(Handle<SharedFunctionInfo> shared_info, Zone* zone);
CompilationInfo(Handle<JSFunction> closure, Zone* zone);
CompilationInfo(HydrogenCodeStub* stub, Isolate* isolate, Zone* zone);
~CompilationInfo();
virtual ~CompilationInfo();
Isolate* isolate() {
ASSERT(Isolate::Current() == isolate_);
@ -243,6 +239,18 @@ class CompilationInfo {
deferred_handles_ = deferred_handles;
}
ZoneList<Handle<HeapObject> >* dependencies(
DependentCode::DependencyGroup group) {
if (dependencies_[group] == NULL) {
dependencies_[group] = new(zone_) ZoneList<Handle<HeapObject> >(2, zone_);
}
return dependencies_[group];
}
void CommitDependencies(Handle<Code> code);
void RollbackDependencies();
void SaveHandles() {
SaveHandle(&closure_);
SaveHandle(&shared_info_);
@ -276,6 +284,30 @@ class CompilationInfo {
return result;
}
Handle<Foreign> object_wrapper() {
if (object_wrapper_.is_null()) {
object_wrapper_ =
isolate()->factory()->NewForeign(reinterpret_cast<Address>(this));
}
return object_wrapper_;
}
void AbortDueToDependencyChange() {
mode_ = DEPENDENCY_CHANGE_ABORT;
}
bool HasAbortedDueToDependencyChange() {
return mode_ == DEPENDENCY_CHANGE_ABORT;
}
protected:
CompilationInfo(Handle<Script> script,
Zone* zone);
CompilationInfo(Handle<SharedFunctionInfo> shared_info,
Zone* zone);
CompilationInfo(HydrogenCodeStub* stub,
Isolate* isolate,
Zone* zone);
private:
Isolate* isolate_;
@ -289,7 +321,8 @@ class CompilationInfo {
BASE,
OPTIMIZE,
NONOPT,
STUB
STUB,
DEPENDENCY_CHANGE_ABORT
};
void Initialize(Isolate* isolate, Mode mode, Zone* zone);
@ -369,6 +402,8 @@ class CompilationInfo {
DeferredHandles* deferred_handles_;
ZoneList<Handle<HeapObject> >* dependencies_[DependentCode::kGroupCount];
template<typename T>
void SaveHandle(Handle<T> *object) {
if (!object->is_null()) {
@ -387,6 +422,8 @@ class CompilationInfo {
// during graph optimization.
int opt_count_;
Handle<Foreign> object_wrapper_;
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};
@ -397,24 +434,26 @@ class CompilationInfoWithZone: public CompilationInfo {
public:
explicit CompilationInfoWithZone(Handle<Script> script)
: CompilationInfo(script, &zone_),
zone_(script->GetIsolate()),
zone_scope_(&zone_, DELETE_ON_EXIT) {}
zone_(script->GetIsolate()) {}
explicit CompilationInfoWithZone(Handle<SharedFunctionInfo> shared_info)
: CompilationInfo(shared_info, &zone_),
zone_(shared_info->GetIsolate()),
zone_scope_(&zone_, DELETE_ON_EXIT) {}
zone_(shared_info->GetIsolate()) {}
explicit CompilationInfoWithZone(Handle<JSFunction> closure)
: CompilationInfo(closure, &zone_),
zone_(closure->GetIsolate()),
zone_scope_(&zone_, DELETE_ON_EXIT) {}
explicit CompilationInfoWithZone(HydrogenCodeStub* stub, Isolate* isolate)
zone_(closure->GetIsolate()) {}
CompilationInfoWithZone(HydrogenCodeStub* stub, Isolate* isolate)
: CompilationInfo(stub, isolate, &zone_),
zone_(isolate),
zone_scope_(&zone_, DELETE_ON_EXIT) {}
zone_(isolate) {}
// Virtual destructor because a CompilationInfoWithZone has to exit the
// zone scope and get rid of dependent maps even when the destructor is
// called when cast as a CompilationInfo.
virtual ~CompilationInfoWithZone() {
RollbackDependencies();
}
private:
Zone zone_;
ZoneScope zone_scope_;
};
@ -578,6 +617,30 @@ class Compiler : public AllStatic {
};
class CompilationPhase BASE_EMBEDDED {
public:
CompilationPhase(const char* name, CompilationInfo* info);
~CompilationPhase();
protected:
bool ShouldProduceTraceOutput() const;
const char* name() const { return name_; }
CompilationInfo* info() const { return info_; }
Isolate* isolate() const { return info()->isolate(); }
Zone* zone() { return &zone_; }
private:
const char* name_;
CompilationInfo* info_;
Zone zone_;
unsigned info_zone_start_allocation_size_;
int64_t start_ticks_;
DISALLOW_COPY_AND_ASSIGN(CompilationPhase);
};
} } // namespace v8::internal
#endif // V8_COMPILER_H_

2
deps/v8/src/contexts.h

@ -134,6 +134,7 @@ enum BindingFlags {
V(FLOAT_ARRAY_FUN_INDEX, JSFunction, float_array_fun) \
V(DOUBLE_ARRAY_FUN_INDEX, JSFunction, double_array_fun) \
V(UINT8C_ARRAY_FUN_INDEX, JSFunction, uint8c_array_fun) \
V(DATA_VIEW_FUN_INDEX, JSFunction, data_view_fun) \
V(FUNCTION_MAP_INDEX, Map, function_map) \
V(STRICT_MODE_FUNCTION_MAP_INDEX, Map, strict_mode_function_map) \
V(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, function_without_prototype_map) \
@ -299,6 +300,7 @@ class Context: public FixedArray {
FLOAT_ARRAY_FUN_INDEX,
DOUBLE_ARRAY_FUN_INDEX,
UINT8C_ARRAY_FUN_INDEX,
DATA_VIEW_FUN_INDEX,
MESSAGE_LISTENERS_INDEX,
MAKE_MESSAGE_FUN_INDEX,
GET_STACK_TRACE_LINE_INDEX,

21
deps/v8/src/cpu-profiler-inl.h

@ -56,6 +56,17 @@ void SharedFunctionInfoMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
}
void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) {
CodeEntry* entry = code_map->FindEntry(start);
if (!entry) {
// Code objects for builtins should already have been added to the map but
// some of them have been filtered out by CpuProfiler.
return;
}
entry->SetBuiltinId(builtin_id);
}
TickSample* ProfilerEventsProcessor::TickSampleEvent() {
generator_->Tick();
TickSampleEventRecord* evt =
@ -64,16 +75,6 @@ TickSample* ProfilerEventsProcessor::TickSampleEvent() {
}
bool ProfilerEventsProcessor::FilterOutCodeCreateEvent(
Logger::LogEventsAndTags tag) {
return FLAG_prof_browser_mode
&& (tag != Logger::CALLBACK_TAG
&& tag != Logger::FUNCTION_TAG
&& tag != Logger::LAZY_COMPILE_TAG
&& tag != Logger::REG_EXP_TAG
&& tag != Logger::SCRIPT_TAG);
}
} } // namespace v8::internal
#endif // V8_CPU_PROFILER_INL_H_

364
deps/v8/src/cpu-profiler.cc

@ -45,11 +45,9 @@ static const int kTickSamplesBufferChunksCount = 16;
static const int kProfilerStackSize = 64 * KB;
ProfilerEventsProcessor::ProfilerEventsProcessor(
ProfileGenerator* generator, CpuProfilesCollection* profiles)
ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
: Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
generator_(generator),
profiles_(profiles),
running_(true),
ticks_buffer_(sizeof(TickSampleEventRecord),
kTickSamplesBufferChunkSize,
@ -58,127 +56,15 @@ ProfilerEventsProcessor::ProfilerEventsProcessor(
}
void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
const char* prefix,
Name* name,
Address start) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec;
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->type = CodeEventRecord::CODE_CREATION;
rec->order = ++enqueue_order_;
rec->start = start;
rec->entry = profiles_->NewCodeEntry(tag, prefix, name);
rec->size = 1;
rec->shared = NULL;
events_buffer_.Enqueue(evt_rec);
}
void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
Name* name,
String* resource_name,
int line_number,
Address start,
unsigned size,
Address shared,
CompilationInfo* info) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec;
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->type = CodeEventRecord::CODE_CREATION;
rec->order = ++enqueue_order_;
rec->start = start;
rec->entry = profiles_->NewCodeEntry(tag, name, resource_name, line_number);
if (info) {
rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
}
rec->size = size;
rec->shared = shared;
events_buffer_.Enqueue(evt_rec);
}
void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
const char* name,
Address start,
unsigned size) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec;
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->type = CodeEventRecord::CODE_CREATION;
rec->order = ++enqueue_order_;
rec->start = start;
rec->entry = profiles_->NewCodeEntry(tag, name);
rec->size = size;
rec->shared = NULL;
events_buffer_.Enqueue(evt_rec);
}
void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
int args_count,
Address start,
unsigned size) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec;
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->type = CodeEventRecord::CODE_CREATION;
rec->order = ++enqueue_order_;
rec->start = start;
rec->entry = profiles_->NewCodeEntry(tag, args_count);
rec->size = size;
rec->shared = NULL;
events_buffer_.Enqueue(evt_rec);
}
void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) {
CodeEventsContainer evt_rec;
CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
rec->type = CodeEventRecord::CODE_MOVE;
rec->order = ++enqueue_order_;
rec->from = from;
rec->to = to;
events_buffer_.Enqueue(evt_rec);
void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
event.generic.order = ++enqueue_order_;
events_buffer_.Enqueue(event);
}
void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from,
Address to) {
CodeEventsContainer evt_rec;
SharedFunctionInfoMoveEventRecord* rec =
&evt_rec.SharedFunctionInfoMoveEventRecord_;
rec->type = CodeEventRecord::SHARED_FUNC_MOVE;
rec->order = ++enqueue_order_;
rec->from = from;
rec->to = to;
events_buffer_.Enqueue(evt_rec);
}
void ProfilerEventsProcessor::RegExpCodeCreateEvent(
Logger::LogEventsAndTags tag,
const char* prefix,
String* name,
Address start,
unsigned size) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec;
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->type = CodeEventRecord::CODE_CREATION;
rec->order = ++enqueue_order_;
rec->start = start;
rec->entry = profiles_->NewCodeEntry(tag, prefix, name);
rec->size = size;
events_buffer_.Enqueue(evt_rec);
}
void ProfilerEventsProcessor::AddCurrentStack() {
void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate) {
TickSampleEventRecord record(enqueue_order_);
TickSample* sample = &record.sample;
Isolate* isolate = Isolate::Current();
sample->state = isolate->current_vm_state();
sample->pc = reinterpret_cast<Address>(sample); // Not NULL.
for (StackTraceFrameIterator it(isolate);
@ -191,9 +77,8 @@ void ProfilerEventsProcessor::AddCurrentStack() {
bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) {
if (!events_buffer_.IsEmpty()) {
CodeEventsContainer record;
events_buffer_.Dequeue(&record);
CodeEventsContainer record;
if (events_buffer_.Dequeue(&record)) {
switch (record.generic.type) {
#define PROFILER_TYPE_CASE(type, clss) \
case CodeEventRecord::type: \
@ -306,30 +191,56 @@ bool CpuProfiler::HasDetachedProfiles() {
}
static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag) {
return FLAG_prof_browser_mode
&& (tag != Logger::CALLBACK_TAG
&& tag != Logger::FUNCTION_TAG
&& tag != Logger::LAZY_COMPILE_TAG
&& tag != Logger::REG_EXP_TAG
&& tag != Logger::SCRIPT_TAG);
}
void CpuProfiler::CallbackEvent(Name* name, Address entry_point) {
processor_->CallbackCreateEvent(
Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = entry_point;
rec->entry = profiles_->NewCodeEntry(
Logger::CALLBACK_TAG,
profiles_->GetName(name),
TokenEnumerator::kInheritsSecurityToken);
rec->size = 1;
rec->shared = NULL;
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, const char* comment) {
processor_->CodeCreateEvent(
tag, comment, code->address(), code->ExecutableSize());
Code* code,
const char* name) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
rec->size = code->ExecutableSize();
rec->shared = NULL;
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, Name* name) {
processor_->CodeCreateEvent(
tag,
name,
isolate_->heap()->empty_string(),
v8::CpuProfileNode::kNoLineNumberInfo,
code->address(),
code->ExecutableSize(),
NULL,
NULL);
Code* code,
Name* name) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
rec->size = code->ExecutableSize();
rec->shared = NULL;
processor_->Enqueue(evt_rec);
}
@ -338,15 +249,22 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
SharedFunctionInfo* shared,
CompilationInfo* info,
Name* name) {
processor_->CodeCreateEvent(
tag,
name,
isolate_->heap()->empty_string(),
v8::CpuProfileNode::kNoLineNumberInfo,
code->address(),
code->ExecutableSize(),
shared->address(),
info);
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
if (info) {
rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
}
if (shared->script()->IsScript()) {
ASSERT(Script::cast(shared->script()));
Script* script = Script::cast(shared->script());
rec->entry->set_script_id(script->id()->value());
}
rec->size = code->ExecutableSize();
rec->shared = shared->address();
processor_->Enqueue(evt_rec);
}
@ -355,30 +273,53 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
SharedFunctionInfo* shared,
CompilationInfo* info,
String* source, int line) {
processor_->CodeCreateEvent(
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
tag,
shared->DebugName(),
source,
line,
code->address(),
code->ExecutableSize(),
shared->address(),
info);
profiles_->GetFunctionName(shared->DebugName()),
TokenEnumerator::kNoSecurityToken,
CodeEntry::kEmptyNamePrefix,
profiles_->GetName(source),
line);
if (info) {
rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
}
ASSERT(Script::cast(shared->script()));
Script* script = Script::cast(shared->script());
rec->entry->set_script_id(script->id()->value());
rec->size = code->ExecutableSize();
rec->shared = shared->address();
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, int args_count) {
processor_->CodeCreateEvent(
Code* code,
int args_count) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
tag,
args_count,
code->address(),
code->ExecutableSize());
profiles_->GetName(args_count),
TokenEnumerator::kInheritsSecurityToken,
"args_count: ");
rec->size = code->ExecutableSize();
rec->shared = NULL;
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeMoveEvent(Address from, Address to) {
processor_->CodeMoveEvent(from, to);
CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE);
CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
rec->from = from;
rec->to = to;
processor_->Enqueue(evt_rec);
}
@ -387,29 +328,59 @@ void CpuProfiler::CodeDeleteEvent(Address from) {
void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
processor_->SharedFunctionInfoMoveEvent(from, to);
CodeEventsContainer evt_rec(CodeEventRecord::SHARED_FUNC_MOVE);
SharedFunctionInfoMoveEventRecord* rec =
&evt_rec.SharedFunctionInfoMoveEventRecord_;
rec->from = from;
rec->to = to;
processor_->Enqueue(evt_rec);
}
void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) {
processor_->CallbackCreateEvent(
Logger::CALLBACK_TAG, "get ", name, entry_point);
if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = entry_point;
rec->entry = profiles_->NewCodeEntry(
Logger::CALLBACK_TAG,
profiles_->GetName(name),
TokenEnumerator::kInheritsSecurityToken,
"get ");
rec->size = 1;
rec->shared = NULL;
processor_->Enqueue(evt_rec);
}
void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
processor_->RegExpCodeCreateEvent(
if (FilterOutCodeCreateEvent(Logger::REG_EXP_TAG)) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
Logger::REG_EXP_TAG,
"RegExp: ",
source,
code->address(),
code->ExecutableSize());
profiles_->GetName(source),
TokenEnumerator::kInheritsSecurityToken,
"RegExp: ");
rec->size = code->ExecutableSize();
processor_->Enqueue(evt_rec);
}
void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) {
processor_->CallbackCreateEvent(
Logger::CALLBACK_TAG, "set ", name, entry_point);
if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = entry_point;
rec->entry = profiles_->NewCodeEntry(
Logger::CALLBACK_TAG,
profiles_->GetName(name),
TokenEnumerator::kInheritsSecurityToken,
"set ");
rec->size = 1;
rec->shared = NULL;
processor_->Enqueue(evt_rec);
}
@ -425,7 +396,23 @@ CpuProfiler::CpuProfiler(Isolate* isolate)
}
CpuProfiler::CpuProfiler(Isolate* isolate,
CpuProfilesCollection* test_profiles,
ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor)
: isolate_(isolate),
profiles_(test_profiles),
next_profile_uid_(1),
token_enumerator_(new TokenEnumerator()),
generator_(test_generator),
processor_(test_processor),
need_to_stop_sampler_(false),
is_profiling_(false) {
}
CpuProfiler::~CpuProfiler() {
ASSERT(!is_profiling_);
delete token_enumerator_;
delete profiles_;
}
@ -440,7 +427,7 @@ void CpuProfiler::StartProfiling(const char* title, bool record_samples) {
if (profiles_->StartProfiling(title, next_profile_uid_++, record_samples)) {
StartProcessorIfNotStarted();
}
processor_->AddCurrentStack();
processor_->AddCurrentStack(isolate_);
}
@ -451,23 +438,24 @@ void CpuProfiler::StartProfiling(String* title, bool record_samples) {
void CpuProfiler::StartProcessorIfNotStarted() {
if (processor_ == NULL) {
Logger* logger = isolate_->logger();
// Disable logging when using the new implementation.
saved_logging_nesting_ = isolate_->logger()->logging_nesting_;
isolate_->logger()->logging_nesting_ = 0;
saved_logging_nesting_ = logger->logging_nesting_;
logger->logging_nesting_ = 0;
generator_ = new ProfileGenerator(profiles_);
processor_ = new ProfilerEventsProcessor(generator_, profiles_);
processor_ = new ProfilerEventsProcessor(generator_);
is_profiling_ = true;
processor_->StartSynchronously();
// Enumerate stuff we already have in the heap.
if (isolate_->heap()->HasBeenSetUp()) {
if (!FLAG_prof_browser_mode) {
isolate_->logger()->LogCodeObjects();
}
isolate_->logger()->LogCompiledFunctions();
isolate_->logger()->LogAccessorCallbacks();
ASSERT(isolate_->heap()->HasBeenSetUp());
if (!FLAG_prof_browser_mode) {
logger->LogCodeObjects();
}
logger->LogCompiledFunctions();
logger->LogAccessorCallbacks();
LogBuiltins();
// Enable stack sampling.
Sampler* sampler = isolate_->logger()->sampler();
Sampler* sampler = logger->sampler();
sampler->IncreaseProfilingDepth();
if (!sampler->IsActive()) {
sampler->Start();
@ -526,4 +514,18 @@ void CpuProfiler::StopProcessor() {
}
void CpuProfiler::LogBuiltins() {
Builtins* builtins = isolate_->builtins();
ASSERT(builtins->is_initialized());
for (int i = 0; i < Builtins::builtin_count; i++) {
CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
Builtins::Name id = static_cast<Builtins::Name>(i);
rec->start = builtins->builtin(id)->address();
rec->builtin_id = id;
processor_->Enqueue(evt_rec);
}
}
} } // namespace v8::internal

77
deps/v8/src/cpu-profiler.h

@ -49,7 +49,8 @@ class TokenEnumerator;
#define CODE_EVENTS_TYPE_LIST(V) \
V(CODE_CREATION, CodeCreateEventRecord) \
V(CODE_MOVE, CodeMoveEventRecord) \
V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)
V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord) \
V(REPORT_BUILTIN, ReportBuiltinEventRecord)
class CodeEventRecord {
@ -63,7 +64,7 @@ class CodeEventRecord {
#undef DECLARE_TYPE
Type type;
unsigned order;
mutable unsigned order;
};
@ -96,6 +97,15 @@ class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
};
class ReportBuiltinEventRecord : public CodeEventRecord {
public:
Address start;
Builtins::Name builtin_id;
INLINE(void UpdateCodeMap(CodeMap* code_map));
};
class TickSampleEventRecord {
public:
// The parameterless constructor is used when we dequeue data from
@ -122,43 +132,36 @@ class TickSampleEventRecord {
};
class CodeEventsContainer {
public:
explicit CodeEventsContainer(
CodeEventRecord::Type type = CodeEventRecord::NONE) {
generic.type = type;
}
union {
CodeEventRecord generic;
#define DECLARE_CLASS(ignore, type) type type##_;
CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
#undef DECLARE_TYPE
};
};
// This class implements both the profile events processor thread and
// methods called by event producers: VM and stack sampler threads.
class ProfilerEventsProcessor : public Thread {
public:
ProfilerEventsProcessor(ProfileGenerator* generator,
CpuProfilesCollection* profiles);
explicit ProfilerEventsProcessor(ProfileGenerator* generator);
virtual ~ProfilerEventsProcessor() {}
// Thread control.
virtual void Run();
inline void Stop() { running_ = false; }
INLINE(bool running()) { return running_; }
void Enqueue(const CodeEventsContainer& event);
// Events adding methods. Called by VM threads.
void CallbackCreateEvent(Logger::LogEventsAndTags tag,
const char* prefix, Name* name,
Address start);
void CodeCreateEvent(Logger::LogEventsAndTags tag,
Name* name,
String* resource_name, int line_number,
Address start, unsigned size,
Address shared,
CompilationInfo* info);
void CodeCreateEvent(Logger::LogEventsAndTags tag,
const char* name,
Address start, unsigned size);
void CodeCreateEvent(Logger::LogEventsAndTags tag,
int args_count,
Address start, unsigned size);
void CodeMoveEvent(Address from, Address to);
void CodeDeleteEvent(Address from);
void SharedFunctionInfoMoveEvent(Address from, Address to);
void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
const char* prefix, String* name,
Address start, unsigned size);
// Puts current stack into tick sample events buffer.
void AddCurrentStack();
void AddCurrentStack(Isolate* isolate);
// Tick sample events are filled directly in the buffer of the circular
// queue (because the structure is of fixed width, but usually not all
@ -167,21 +170,11 @@ class ProfilerEventsProcessor : public Thread {
INLINE(TickSample* TickSampleEvent());
private:
union CodeEventsContainer {
CodeEventRecord generic;
#define DECLARE_CLASS(ignore, type) type type##_;
CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
#undef DECLARE_TYPE
};
// Called from events processing thread (Run() method.)
bool ProcessCodeEvent(unsigned* dequeue_order);
bool ProcessTicks(unsigned dequeue_order);
INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
ProfileGenerator* generator_;
CpuProfilesCollection* profiles_;
bool running_;
UnboundQueue<CodeEventsContainer> events_buffer_;
SamplingCircularQueue ticks_buffer_;
@ -204,6 +197,12 @@ class ProfilerEventsProcessor : public Thread {
class CpuProfiler {
public:
explicit CpuProfiler(Isolate* isolate);
CpuProfiler(Isolate* isolate,
CpuProfilesCollection* test_collection,
ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor);
~CpuProfiler();
void StartProfiling(const char* title, bool record_samples = false);
@ -248,12 +247,16 @@ class CpuProfiler {
void SharedFunctionInfoMoveEvent(Address from, Address to);
INLINE(bool is_profiling() const) { return is_profiling_; }
bool* is_profiling_address() {
return &is_profiling_;
}
private:
void StartProcessorIfNotStarted();
void StopProcessorIfLastProfile(const char* title);
void StopProcessor();
void ResetProfiles();
void LogBuiltins();
Isolate* isolate_;
CpuProfilesCollection* profiles_;

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

@ -68,7 +68,7 @@ void HandleDebugEvent(DebugEvent event,
// Get the toJSONProtocol function on the event and get the JSON format.
Local<String> to_json_fun_name = String::New("toJSONProtocol");
Local<Function> to_json_fun =
Function::Cast(*event_data->Get(to_json_fun_name));
Local<Function>::Cast(event_data->Get(to_json_fun_name));
Local<Value> event_json = to_json_fun->Call(event_data, 0, NULL);
if (try_catch.HasCaught()) {
Shell::ReportException(isolate, &try_catch);
@ -91,9 +91,9 @@ void HandleDebugEvent(DebugEvent event,
// Get the debug command processor.
Local<String> fun_name = String::New("debugCommandProcessor");
Local<Function> fun = Function::Cast(*exec_state->Get(fun_name));
Local<Function> fun = Local<Function>::Cast(exec_state->Get(fun_name));
Local<Object> cmd_processor =
Object::Cast(*fun->Call(exec_state, 0, NULL));
Local<Object>::Cast(fun->Call(exec_state, 0, NULL));
if (try_catch.HasCaught()) {
Shell::ReportException(isolate, &try_catch);
return;

15
deps/v8/src/d8-readline.cc

@ -150,18 +150,19 @@ char* ReadLineEditor::CompletionGenerator(const char* text, int state) {
static Persistent<Array> current_completions;
Isolate* isolate = read_line_editor.isolate_;
Locker lock(isolate);
HandleScope scope;
Handle<Array> completions;
if (state == 0) {
HandleScope scope;
Local<String> full_text = String::New(rl_line_buffer, rl_point);
Handle<Array> completions =
Shell::GetCompletions(isolate, String::New(text), full_text);
current_completions = Persistent<Array>::New(isolate, completions);
completions = Shell::GetCompletions(isolate, String::New(text), full_text);
current_completions.Reset(isolate, completions);
current_index = 0;
} else {
completions = Local<Array>::New(isolate, current_completions);
}
if (current_index < current_completions->Length()) {
HandleScope scope;
if (current_index < completions->Length()) {
Handle<Integer> index = Integer::New(current_index);
Handle<Value> str_obj = current_completions->Get(index);
Handle<Value> str_obj = completions->Get(index);
current_index++;
String::Utf8Value str(str_obj);
return strdup(*str);

11
deps/v8/src/d8.cc

@ -1076,14 +1076,15 @@ static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
}
static void ReadBufferWeakCallback(v8::Isolate* isolate,
Persistent<Value>* object,
Persistent<ArrayBuffer>* array_buffer,
uint8_t* data) {
size_t byte_length = ArrayBuffer::Cast(**object)->ByteLength();
size_t byte_length =
Local<ArrayBuffer>::New(isolate, *array_buffer)->ByteLength();
isolate->AdjustAmountOfExternalAllocatedMemory(
-static_cast<intptr_t>(byte_length));
delete[] data;
object->Dispose(isolate);
array_buffer->Dispose();
}
void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
@ -1103,8 +1104,8 @@ void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
Handle<v8::ArrayBuffer> buffer = ArrayBuffer::New(data, length);
v8::Persistent<v8::Value> weak_handle(isolate, buffer);
weak_handle.MakeWeak(isolate, data, ReadBufferWeakCallback);
v8::Persistent<v8::ArrayBuffer> weak_handle(isolate, buffer);
weak_handle.MakeWeak(data, ReadBufferWeakCallback);
weak_handle.MarkIndependent();
isolate->AdjustAmountOfExternalAllocatedMemory(length);

3
deps/v8/src/d8.gyp

@ -26,12 +26,13 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'includes': ['../build/common.gypi'],
'variables': {
'v8_code': 1,
'console%': '',
# Enable support for Intel VTune. Supported on ia32/x64 only
'v8_enable_vtunejit%': 0,
},
'includes': ['../build/common.gypi'],
'targets': [
{
'target_name': 'd8',

2
deps/v8/src/d8.js

@ -1020,7 +1020,7 @@ DebugRequest.prototype.changeBreakpointCommandToJSONRequest_ =
args.substring(nextPos + 1, args.length) : 'all';
if (!arg2) {
arg2 = 'all'; // if unspecified, set for all.
} if (arg2 == 'unc') { // check for short cut.
} else if (arg2 == 'unc') { // check for short cut.
arg2 = 'uncaught';
}
excType = arg2;

2
deps/v8/src/data-flow.h

@ -215,6 +215,8 @@ class GrowableBitVector BASE_EMBEDDED {
};
GrowableBitVector() : bits_(NULL) { }
GrowableBitVector(int length, Zone* zone)
: bits_(new(zone) BitVector(length, zone)) { }
bool Contains(int value) const {
if (!InBitsRange(value)) return false;

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

@ -71,6 +71,13 @@ Debug.ScriptBreakPointType = { ScriptId: 0,
ScriptName: 1,
ScriptRegExp: 2 };
// The different types of breakpoint position alignments.
// Must match BreakPositionAlignment in debug.h.
Debug.BreakPositionAlignment = {
Statement: 0,
BreakPosition: 1
};
function ScriptTypeFlag(type) {
return (1 << type);
}
@ -251,7 +258,7 @@ function IsBreakPointTriggered(break_id, break_point) {
// script name or script id and the break point is represented as line and
// column.
function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
opt_groupId) {
opt_groupId, opt_position_alignment) {
this.type_ = type;
if (type == Debug.ScriptBreakPointType.ScriptId) {
this.script_id_ = script_id_or_name;
@ -265,6 +272,8 @@ function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
this.line_ = opt_line || 0;
this.column_ = opt_column;
this.groupId_ = opt_groupId;
this.position_alignment_ = IS_UNDEFINED(opt_position_alignment)
? Debug.BreakPositionAlignment.Statement : opt_position_alignment;
this.hit_count_ = 0;
this.active_ = true;
this.condition_ = null;
@ -276,7 +285,8 @@ function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
//Creates a clone of script breakpoint that is linked to another script.
ScriptBreakPoint.prototype.cloneForOtherScript = function (other_script) {
var copy = new ScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
other_script.id, this.line_, this.column_, this.groupId_);
other_script.id, this.line_, this.column_, this.groupId_,
this.position_alignment_);
copy.number_ = next_break_point_number++;
script_break_points.push(copy);
@ -443,7 +453,9 @@ ScriptBreakPoint.prototype.set = function (script) {
// Create a break point object and set the break point.
break_point = MakeBreakPoint(position, this);
break_point.setIgnoreCount(this.ignoreCount());
var actual_position = %SetScriptBreakPoint(script, position, break_point);
var actual_position = %SetScriptBreakPoint(script, position,
this.position_alignment_,
break_point);
if (IS_UNDEFINED(actual_position)) {
actual_position = position;
}
@ -509,9 +521,11 @@ Debug.breakExecution = function(f) {
%Break();
};
Debug.breakLocations = function(f) {
Debug.breakLocations = function(f, opt_position_aligment) {
if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
return %GetBreakLocations(f);
var position_aligment = IS_UNDEFINED(opt_position_aligment)
? Debug.BreakPositionAlignment.Statement : opt_position_aligment;
return %GetBreakLocations(f, position_aligment);
};
// Returns a Script object. If the parameter is a function the return value
@ -674,7 +688,8 @@ Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) {
Debug.setBreakPointByScriptIdAndPosition = function(script_id, position,
condition, enabled)
condition, enabled,
opt_position_alignment)
{
break_point = MakeBreakPoint(position);
break_point.setCondition(condition);
@ -682,10 +697,12 @@ Debug.setBreakPointByScriptIdAndPosition = function(script_id, position,
break_point.disable();
}
var scripts = this.scripts();
var position_alignment = IS_UNDEFINED(opt_position_alignment)
? Debug.BreakPositionAlignment.Statement : opt_position_alignment;
for (var i = 0; i < scripts.length; i++) {
if (script_id == scripts[i].id) {
break_point.actual_position = %SetScriptBreakPoint(scripts[i], position,
break_point);
position_alignment, break_point);
break;
}
}
@ -780,11 +797,11 @@ Debug.findScriptBreakPoint = function(break_point_number, remove) {
// specified source line and column within that line.
Debug.setScriptBreakPoint = function(type, script_id_or_name,
opt_line, opt_column, opt_condition,
opt_groupId) {
opt_groupId, opt_position_alignment) {
// Create script break point object.
var script_break_point =
new ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
opt_groupId);
opt_groupId, opt_position_alignment);
// Assign number to the new script break point and add it.
script_break_point.number_ = next_break_point_number++;
@ -806,10 +823,12 @@ Debug.setScriptBreakPoint = function(type, script_id_or_name,
Debug.setScriptBreakPointById = function(script_id,
opt_line, opt_column,
opt_condition, opt_groupId) {
opt_condition, opt_groupId,
opt_position_alignment) {
return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
script_id, opt_line, opt_column,
opt_condition, opt_groupId);
opt_condition, opt_groupId,
opt_position_alignment);
};
@ -893,11 +912,11 @@ Debug.isBreakOnUncaughtException = function() {
return !!%IsBreakOnException(Debug.ExceptionBreak.Uncaught);
};
Debug.showBreakPoints = function(f, full) {
Debug.showBreakPoints = function(f, full, opt_position_alignment) {
if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
var source = full ? this.scriptSource(f) : this.source(f);
var offset = full ? this.sourcePosition(f) : 0;
var locations = this.breakLocations(f);
var locations = this.breakLocations(f, opt_position_alignment);
if (!locations) return source;
locations.sort(function(x, y) { return x - y; });
var result = "";

104
deps/v8/src/debug.cc

@ -235,17 +235,30 @@ void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
// Find the break point closest to the supplied source position.
void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
void BreakLocationIterator::FindBreakLocationFromPosition(int position,
BreakPositionAlignment alignment) {
// Run through all break points to locate the one closest to the source
// position.
int closest_break_point = 0;
int distance = kMaxInt;
while (!Done()) {
int next_position;
switch (alignment) {
case STATEMENT_ALIGNED:
next_position = this->statement_position();
break;
case BREAK_POSITION_ALIGNED:
next_position = this->position();
break;
default:
UNREACHABLE();
next_position = this->statement_position();
}
// Check if this break point is closer that what was previously found.
if (position <= statement_position() &&
statement_position() - position < distance) {
if (position <= next_position && next_position - position < distance) {
closest_break_point = break_point();
distance = statement_position() - position;
distance = next_position - position;
// Check whether we can't get any closer.
if (distance == 0) break;
}
@ -390,6 +403,20 @@ void BreakLocationIterator::ClearDebugBreak() {
}
bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) {
if (RelocInfo::IsConstructCall(rmode())) {
return true;
} else if (RelocInfo::IsCodeTarget(rmode())) {
HandleScope scope(debug_info_->GetIsolate());
Address target = rinfo()->target_address();
Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
return target_code->is_call_stub() || target_code->is_keyed_call_stub();
} else {
return false;
}
}
void BreakLocationIterator::PrepareStepIn(Isolate* isolate) {
HandleScope scope(isolate);
@ -606,7 +633,7 @@ const int Debug::kFrameDropperFrameSize = 4;
void ScriptCache::Add(Handle<Script> script) {
GlobalHandles* global_handles = Isolate::Current()->global_handles();
// Create an entry in the hash map for the script.
int id = Smi::cast(script->id())->value();
int id = script->id()->value();
HashMap::Entry* entry =
HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
if (entry->value != NULL) {
@ -670,11 +697,11 @@ void ScriptCache::HandleWeakScript(v8::Isolate* isolate,
ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
// Find the location of the global handle.
Script** location =
reinterpret_cast<Script**>(Utils::OpenHandle(**obj).location());
reinterpret_cast<Script**>(Utils::OpenPersistent(*obj).location());
ASSERT((*location)->IsScript());
// Remove the entry from the cache.
int id = Smi::cast((*location)->id())->value();
int id = (*location)->id()->value();
script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
script_cache->collected_scripts_.Add(id);
@ -1176,7 +1203,7 @@ void Debug::SetBreakPoint(Handle<JSFunction> function,
// Find the break point and change it.
BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
it.FindBreakLocationFromPosition(*source_position);
it.FindBreakLocationFromPosition(*source_position, STATEMENT_ALIGNED);
it.SetBreakPoint(break_point_object);
*source_position = it.position();
@ -1188,7 +1215,8 @@ void Debug::SetBreakPoint(Handle<JSFunction> function,
bool Debug::SetBreakPointForScript(Handle<Script> script,
Handle<Object> break_point_object,
int* source_position) {
int* source_position,
BreakPositionAlignment alignment) {
HandleScope scope(isolate_);
PrepareForBreakPoints();
@ -1219,7 +1247,7 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
// Find the break point and change it.
BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
it.FindBreakLocationFromPosition(position);
it.FindBreakLocationFromPosition(position, alignment);
it.SetBreakPoint(break_point_object);
*source_position = it.position() + shared->start_position();
@ -1673,7 +1701,8 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
// Simple function for returning the source positions for active break points.
Handle<Object> Debug::GetSourceBreakLocations(
Handle<SharedFunctionInfo> shared) {
Handle<SharedFunctionInfo> shared,
BreakPositionAlignment position_alignment) {
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
if (!HasDebugInfo(shared)) {
@ -1691,7 +1720,20 @@ Handle<Object> Debug::GetSourceBreakLocations(
BreakPointInfo* break_point_info =
BreakPointInfo::cast(debug_info->break_points()->get(i));
if (break_point_info->GetBreakPointCount() > 0) {
locations->set(count++, break_point_info->statement_position());
Smi* position;
switch (position_alignment) {
case STATEMENT_ALIGNED:
position = break_point_info->statement_position();
break;
case BREAK_POSITION_ALIGNED:
position = break_point_info->source_position();
break;
default:
UNREACHABLE();
position = break_point_info->statement_position();
}
locations->set(count++, position);
}
}
}
@ -2046,13 +2088,30 @@ void Debug::PrepareForBreakPoints() {
if (obj->IsJSFunction()) {
JSFunction* function = JSFunction::cast(obj);
SharedFunctionInfo* shared = function->shared();
if (shared->allows_lazy_compilation() &&
shared->script()->IsScript() &&
function->code()->kind() == Code::FUNCTION &&
!function->code()->has_debug_break_slots() &&
shared->code()->gc_metadata() != active_code_marker) {
if (!shared->allows_lazy_compilation()) continue;
if (!shared->script()->IsScript()) continue;
if (shared->code()->gc_metadata() == active_code_marker) continue;
Code::Kind kind = function->code()->kind();
if (kind == Code::FUNCTION &&
!function->code()->has_debug_break_slots()) {
function->set_code(*lazy_compile);
function->shared()->set_code(*lazy_compile);
} else if (kind == Code::BUILTIN &&
(function->IsMarkedForInstallingRecompiledCode() ||
function->IsInRecompileQueue() ||
function->IsMarkedForLazyRecompilation() ||
function->IsMarkedForParallelRecompilation())) {
// Abort in-flight compilation.
Code* shared_code = function->shared()->code();
if (shared_code->kind() == Code::FUNCTION &&
shared_code->has_debug_break_slots()) {
function->set_code(shared_code);
} else {
function->set_code(*lazy_compile);
function->shared()->set_code(*lazy_compile);
}
}
}
}
@ -3066,13 +3125,14 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
v8::Local<v8::String> fun_name =
v8::String::New("debugCommandProcessor");
v8::Local<v8::Function> fun =
v8::Function::Cast(*api_exec_state->Get(fun_name));
v8::Local<v8::Function>::Cast(api_exec_state->Get(fun_name));
v8::Handle<v8::Boolean> running =
auto_continue ? v8::True() : v8::False();
static const int kArgc = 1;
v8::Handle<Value> argv[kArgc] = { running };
cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv));
cmd_processor = v8::Local<v8::Object>::Cast(
fun->Call(api_exec_state, kArgc, argv));
if (try_catch.HasCaught()) {
PrintLn(try_catch.Exception());
return;
@ -3112,7 +3172,7 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
v8::Local<v8::Value> request;
v8::TryCatch try_catch;
fun_name = v8::String::New("processDebugRequest");
fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
fun = v8::Local<v8::Function>::Cast(cmd_processor->Get(fun_name));
request = v8::String::New(command.text().start(),
command.text().length());
@ -3125,7 +3185,7 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
if (!try_catch.HasCaught()) {
// Get response string.
if (!response_val->IsUndefined()) {
response = v8::String::Cast(*response_val);
response = v8::Local<v8::String>::Cast(response_val);
} else {
response = v8::String::New("");
}
@ -3138,7 +3198,7 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
// Get the running state.
fun_name = v8::String::New("isRunning");
fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
fun = v8::Local<v8::Function>::Cast(cmd_processor->Get(fun_name));
static const int kArgc = 1;
v8::Handle<Value> argv[kArgc] = { response };
v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);

18
deps/v8/src/debug.h

@ -79,6 +79,14 @@ enum BreakLocatorType {
};
// The different types of breakpoint position alignments.
// Must match Debug.BreakPositionAlignment in debug-debugger.js
enum BreakPositionAlignment {
STATEMENT_ALIGNED = 0,
BREAK_POSITION_ALIGNED = 1
};
// Class for iterating through the break points in a function and changing
// them.
class BreakLocationIterator {
@ -90,13 +98,15 @@ class BreakLocationIterator {
void Next();
void Next(int count);
void FindBreakLocationFromAddress(Address pc);
void FindBreakLocationFromPosition(int position);
void FindBreakLocationFromPosition(int position,
BreakPositionAlignment alignment);
void Reset();
bool Done() const;
void SetBreakPoint(Handle<Object> break_point_object);
void ClearBreakPoint(Handle<Object> break_point_object);
void SetOneShot();
void ClearOneShot();
bool IsStepInLocation(Isolate* isolate);
void PrepareStepIn(Isolate* isolate);
bool IsExit() const;
bool HasBreakPoint();
@ -240,7 +250,8 @@ class Debug {
int* source_position);
bool SetBreakPointForScript(Handle<Script> script,
Handle<Object> break_point_object,
int* source_position);
int* source_position,
BreakPositionAlignment alignment);
void ClearBreakPoint(Handle<Object> break_point_object);
void ClearAllBreakPoints();
void FloodWithOneShot(Handle<JSFunction> function);
@ -283,7 +294,8 @@ class Debug {
static Handle<Code> FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode);
static Handle<Object> GetSourceBreakLocations(
Handle<SharedFunctionInfo> shared);
Handle<SharedFunctionInfo> shared,
BreakPositionAlignment position_aligment);
// Getter for the debug_context.
inline Handle<Context> debug_context() { return debug_context_; }

369
deps/v8/src/deoptimizer.cc

@ -284,7 +284,7 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
void Deoptimizer::VisitAllOptimizedFunctionsForContext(
Context* context, OptimizedFunctionVisitor* visitor) {
Isolate* isolate = context->GetIsolate();
ZoneScope zone_scope(isolate->runtime_zone(), DELETE_ON_EXIT);
Zone zone(isolate);
DisallowHeapAllocation no_allocation;
ASSERT(context->IsNativeContext());
@ -293,11 +293,11 @@ void Deoptimizer::VisitAllOptimizedFunctionsForContext(
// Create a snapshot of the optimized functions list. This is needed because
// visitors might remove more than one link from the list at once.
ZoneList<JSFunction*> snapshot(1, isolate->runtime_zone());
ZoneList<JSFunction*> snapshot(1, &zone);
Object* element = context->OptimizedFunctionsListHead();
while (!element->IsUndefined()) {
JSFunction* element_function = JSFunction::cast(element);
snapshot.Add(element_function, isolate->runtime_zone());
snapshot.Add(element_function, &zone);
element = element_function->next_function_link();
}
@ -420,11 +420,10 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
Context* context = function->context()->native_context();
Isolate* isolate = context->GetIsolate();
Object* undefined = isolate->heap()->undefined_value();
Zone* zone = isolate->runtime_zone();
ZoneScope zone_scope(zone, DELETE_ON_EXIT);
ZoneList<Code*> codes(1, zone);
Zone zone(isolate);
ZoneList<Code*> codes(1, &zone);
DeoptimizeWithMatchingCodeFilter filter(code);
PartitionOptimizedFunctions(context, &filter, &codes, zone, undefined);
PartitionOptimizedFunctions(context, &filter, &codes, &zone, undefined);
ASSERT_EQ(1, codes.length());
DeoptimizeFunctionWithPreparedFunctionList(
JSFunction::cast(codes.at(0)->deoptimizing_functions()));
@ -437,10 +436,9 @@ void Deoptimizer::DeoptimizeAllFunctionsForContext(
ASSERT(context->IsNativeContext());
Isolate* isolate = context->GetIsolate();
Object* undefined = isolate->heap()->undefined_value();
Zone* zone = isolate->runtime_zone();
ZoneScope zone_scope(zone, DELETE_ON_EXIT);
ZoneList<Code*> codes(1, zone);
PartitionOptimizedFunctions(context, filter, &codes, zone, undefined);
Zone zone(isolate);
ZoneList<Code*> codes(1, &zone);
PartitionOptimizedFunctions(context, filter, &codes, &zone, undefined);
for (int i = 0; i < codes.length(); ++i) {
DeoptimizeFunctionWithPreparedFunctionList(
JSFunction::cast(codes.at(i)->deoptimizing_functions()));
@ -534,8 +532,9 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
output_count_(0),
jsframe_count_(0),
output_(NULL),
deferred_arguments_objects_values_(0),
deferred_arguments_objects_(0),
deferred_objects_tagged_values_(0),
deferred_objects_double_values_(0),
deferred_objects_(0),
deferred_heap_numbers_(0),
trace_(false) {
// For COMPILED_STUBs called from builtins, the function pointer is a SMI
@ -546,6 +545,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
if (function != NULL && function->IsOptimized()) {
function->shared()->increment_deopt_count();
if (bailout_type_ == Deoptimizer::SOFT) {
isolate->counters()->soft_deopts_executed()->Increment();
// Soft deopts shouldn't count against the overall re-optimization count
// that can eventually lead to disabling optimization for a function.
int opt_count = function->shared()->opt_count();
@ -714,6 +714,10 @@ void Deoptimizer::DoComputeOutputFrames() {
// Print some helpful diagnostic information.
int64_t start = OS::Ticks();
if (FLAG_log_timer_events &&
compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
LOG(isolate(), CodeDeoptEvent(compiled_code_));
}
if (trace_) {
PrintF("[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
MessageFor(bailout_type_),
@ -787,7 +791,6 @@ void Deoptimizer::DoComputeOutputFrames() {
case Translation::DOUBLE_STACK_SLOT:
case Translation::LITERAL:
case Translation::ARGUMENTS_OBJECT:
case Translation::DUPLICATE:
default:
UNREACHABLE();
break;
@ -1510,8 +1513,8 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
}
output_frame_offset -= kPointerSize;
value = frame_ptr - (output_frame_size - output_frame_offset) -
StandardFrameConstants::kMarkerOffset + kPointerSize;
value = frame_ptr + StandardFrameConstants::kCallerSPOffset -
(output_frame_size - output_frame_offset) + kPointerSize;
output_frame->SetFrameSlot(output_frame_offset, value);
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
@ -1566,15 +1569,14 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
ASSERT_NE(DEBUGGER, bailout_type_);
// Handlify all argument object values before triggering any allocation.
List<Handle<Object> > values(deferred_arguments_objects_values_.length());
for (int i = 0; i < deferred_arguments_objects_values_.length(); ++i) {
values.Add(Handle<Object>(deferred_arguments_objects_values_[i],
isolate_));
// Handlify all tagged object values before triggering any allocation.
List<Handle<Object> > values(deferred_objects_tagged_values_.length());
for (int i = 0; i < deferred_objects_tagged_values_.length(); ++i) {
values.Add(Handle<Object>(deferred_objects_tagged_values_[i], isolate_));
}
// Play it safe and clear all unhandlified values before we continue.
deferred_arguments_objects_values_.Clear();
deferred_objects_tagged_values_.Clear();
// Materialize all heap numbers before looking at arguments because when the
// output frames are used to materialize arguments objects later on they need
@ -1591,6 +1593,18 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
Memory::Object_at(d.slot_address()) = *num;
}
// Materialize all heap numbers required for arguments objects.
for (int i = 0; i < values.length(); i++) {
if (!values.at(i)->IsTheHole()) continue;
double double_value = deferred_objects_double_values_[i];
Handle<Object> num = isolate_->factory()->NewNumber(double_value);
if (trace_) {
PrintF("Materializing a new heap number %p [%e] for arguments object\n",
reinterpret_cast<void*>(*num), double_value);
}
values.Set(i, num);
}
// Materialize arguments objects one frame at a time.
for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
if (frame_index != 0) it->Advance();
@ -1599,9 +1613,9 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
Handle<JSObject> arguments;
for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
if (frame->GetExpression(i) == isolate_->heap()->arguments_marker()) {
ArgumentsObjectMaterializationDescriptor descriptor =
deferred_arguments_objects_.RemoveLast();
const int length = descriptor.arguments_length();
ObjectMaterializationDescriptor descriptor =
deferred_objects_.RemoveLast();
const int length = descriptor.object_length();
if (arguments.is_null()) {
if (frame->has_adapted_arguments()) {
// Use the arguments adapter frame we just built to materialize the
@ -1695,7 +1709,7 @@ void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
#endif
static const char* TraceValueType(bool is_smi, bool is_native) {
static const char* TraceValueType(bool is_smi, bool is_native = false) {
if (is_native) {
return "native";
} else if (is_smi) {
@ -1706,6 +1720,197 @@ static const char* TraceValueType(bool is_smi, bool is_native) {
}
void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
int object_opcode,
int field_index) {
disasm::NameConverter converter;
Address object_slot = deferred_objects_.last().slot_address();
Translation::Opcode opcode =
static_cast<Translation::Opcode>(iterator->Next());
switch (opcode) {
case Translation::BEGIN:
case Translation::JS_FRAME:
case Translation::ARGUMENTS_ADAPTOR_FRAME:
case Translation::CONSTRUCT_STUB_FRAME:
case Translation::GETTER_STUB_FRAME:
case Translation::SETTER_STUB_FRAME:
case Translation::COMPILED_STUB_FRAME:
case Translation::ARGUMENTS_OBJECT:
UNREACHABLE();
return;
case Translation::REGISTER: {
int input_reg = iterator->Next();
intptr_t input_value = input_->GetRegister(input_reg);
if (trace_) {
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
PrintF("0x%08" V8PRIxPTR " ; %s ", input_value,
converter.NameOfCPURegister(input_reg));
reinterpret_cast<Object*>(input_value)->ShortPrint();
PrintF("\n");
}
AddObjectTaggedValue(input_value);
return;
}
case Translation::INT32_REGISTER: {
int input_reg = iterator->Next();
intptr_t value = input_->GetRegister(input_reg);
bool is_smi = Smi::IsValid(value);
if (trace_) {
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
PrintF("%" V8PRIdPTR " ; %s (%s)\n", value,
converter.NameOfCPURegister(input_reg),
TraceValueType(is_smi));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
AddObjectTaggedValue(tagged_value);
} else {
double double_value = static_cast<double>(static_cast<int32_t>(value));
AddObjectDoubleValue(double_value);
}
return;
}
case Translation::UINT32_REGISTER: {
int input_reg = iterator->Next();
uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
if (trace_) {
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
PrintF("%" V8PRIdPTR " ; uint %s (%s)\n", value,
converter.NameOfCPURegister(input_reg),
TraceValueType(is_smi));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
AddObjectTaggedValue(tagged_value);
} else {
double double_value = static_cast<double>(static_cast<uint32_t>(value));
AddObjectDoubleValue(double_value);
}
return;
}
case Translation::DOUBLE_REGISTER: {
int input_reg = iterator->Next();
double value = input_->GetDoubleRegister(input_reg);
if (trace_) {
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
PrintF("%e ; %s\n", value,
DoubleRegister::AllocationIndexToString(input_reg));
}
AddObjectDoubleValue(value);
return;
}
case Translation::STACK_SLOT: {
int input_slot_index = iterator->Next();
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t input_value = input_->GetFrameSlot(input_offset);
if (trace_) {
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
PrintF("0x%08" V8PRIxPTR " ; [sp + %d] ", input_value, input_offset);
reinterpret_cast<Object*>(input_value)->ShortPrint();
PrintF("\n");
}
AddObjectTaggedValue(input_value);
return;
}
case Translation::INT32_STACK_SLOT: {
int input_slot_index = iterator->Next();
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t value = input_->GetFrameSlot(input_offset);
bool is_smi = Smi::IsValid(value);
if (trace_) {
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
PrintF("%" V8PRIdPTR " ; [sp + %d] (%s)\n",
value, input_offset, TraceValueType(is_smi));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
AddObjectTaggedValue(tagged_value);
} else {
double double_value = static_cast<double>(static_cast<int32_t>(value));
AddObjectDoubleValue(double_value);
}
return;
}
case Translation::UINT32_STACK_SLOT: {
int input_slot_index = iterator->Next();
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
uintptr_t value =
static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
if (trace_) {
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
PrintF("%" V8PRIdPTR " ; [sp + %d] (uint %s)\n",
value, input_offset, TraceValueType(is_smi));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
AddObjectTaggedValue(tagged_value);
} else {
double double_value = static_cast<double>(static_cast<uint32_t>(value));
AddObjectDoubleValue(double_value);
}
return;
}
case Translation::DOUBLE_STACK_SLOT: {
int input_slot_index = iterator->Next();
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
double value = input_->GetDoubleFrameSlot(input_offset);
if (trace_) {
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
PrintF("%e ; [sp + %d]\n", value, input_offset);
}
AddObjectDoubleValue(value);
return;
}
case Translation::LITERAL: {
Object* literal = ComputeLiteral(iterator->Next());
if (trace_) {
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
reinterpret_cast<intptr_t>(object_slot),
field_index);
literal->ShortPrint();
PrintF(" ; literal\n");
}
intptr_t value = reinterpret_cast<intptr_t>(literal);
AddObjectTaggedValue(value);
return;
}
}
}
void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
int frame_index,
unsigned output_offset,
@ -1715,14 +1920,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
bool is_native = value_type == TRANSLATED_VALUE_IS_NATIVE;
// Ignore commands marked as duplicate and act on the first non-duplicate.
Translation::Opcode opcode =
static_cast<Translation::Opcode>(iterator->Next());
while (opcode == Translation::DUPLICATE) {
opcode = static_cast<Translation::Opcode>(iterator->Next());
iterator->Skip(Translation::NumberOfOperandsFor(opcode));
opcode = static_cast<Translation::Opcode>(iterator->Next());
}
switch (opcode) {
case Translation::BEGIN:
@ -1732,7 +1931,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
case Translation::GETTER_STUB_FRAME:
case Translation::SETTER_STUB_FRAME:
case Translation::COMPILED_STUB_FRAME:
case Translation::DUPLICATE:
UNREACHABLE();
return;
@ -1758,7 +1956,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
intptr_t value = input_->GetRegister(input_reg);
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
Smi::IsValid(value);
if (trace_) {
PrintF(
" 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
@ -1836,8 +2033,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
case Translation::STACK_SLOT: {
int input_slot_index = iterator->Next();
unsigned input_offset =
input_->GetOffsetFromSlotIndex(input_slot_index);
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t input_value = input_->GetFrameSlot(input_offset);
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": ",
@ -1855,8 +2051,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
case Translation::INT32_STACK_SLOT: {
int input_slot_index = iterator->Next();
unsigned input_offset =
input_->GetOffsetFromSlotIndex(input_slot_index);
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t value = input_->GetFrameSlot(input_offset);
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
Smi::IsValid(value);
@ -1888,8 +2083,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
case Translation::UINT32_STACK_SLOT: {
int input_slot_index = iterator->Next();
unsigned input_offset =
input_->GetOffsetFromSlotIndex(input_slot_index);
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
uintptr_t value =
static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
@ -1922,8 +2116,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
case Translation::DOUBLE_STACK_SLOT: {
int input_slot_index = iterator->Next();
unsigned input_offset =
input_->GetOffsetFromSlotIndex(input_slot_index);
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
double value = input_->GetDoubleFrameSlot(input_offset);
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
@ -1954,31 +2147,24 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
}
case Translation::ARGUMENTS_OBJECT: {
bool args_known = iterator->Next();
int args_index = iterator->Next() + 1; // Skip receiver.
int args_length = iterator->Next() - 1; // Skip receiver.
int length = iterator->Next();
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
output_[frame_index]->GetTop() + output_offset,
output_offset);
isolate_->heap()->arguments_marker()->ShortPrint();
PrintF(" ; %sarguments object\n", args_known ? "" : "dummy ");
PrintF(" ; arguments object (length = %d)\n", length);
}
// Use the arguments marker value as a sentinel and fill in the arguments
// object after the deoptimized frame is built.
intptr_t value = reinterpret_cast<intptr_t>(
isolate_->heap()->arguments_marker());
AddArgumentsObject(
output_[frame_index]->GetTop() + output_offset, args_length);
AddObjectStart(output_[frame_index]->GetTop() + output_offset, length);
output_[frame_index]->SetFrameSlot(output_offset, value);
// We save the tagged argument values on the side and materialize the
// actual arguments object after the deoptimized frame is built.
for (int i = 0; i < args_length; i++) {
unsigned input_offset = input_->GetOffsetFromSlotIndex(args_index + i);
intptr_t input_value = args_known
? input_->GetFrameSlot(input_offset)
: reinterpret_cast<intptr_t>(isolate_->heap()->the_hole_value());
AddArgumentsObjectValue(input_value);
// We save the argument values on the side and materialize the actual
// arguments object after the deoptimized frame is built.
for (int i = 0; i < length; i++) {
DoTranslateObject(iterator, Translation::ARGUMENTS_OBJECT, i);
}
return;
}
@ -1998,10 +2184,6 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
Translation::Opcode opcode =
static_cast<Translation::Opcode>(iterator->Next());
bool duplicate = (opcode == Translation::DUPLICATE);
if (duplicate) {
opcode = static_cast<Translation::Opcode>(iterator->Next());
}
switch (opcode) {
case Translation::BEGIN:
@ -2011,21 +2193,20 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
case Translation::GETTER_STUB_FRAME:
case Translation::SETTER_STUB_FRAME:
case Translation::COMPILED_STUB_FRAME:
case Translation::DUPLICATE:
UNREACHABLE(); // Malformed input.
return false;
case Translation::REGISTER: {
int output_reg = iterator->Next();
if (FLAG_trace_osr) {
PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
converter.NameOfCPURegister(output_reg),
input_value,
*input_offset);
}
output->SetRegister(output_reg, input_value);
break;
}
return false;
case Translation::REGISTER: {
int output_reg = iterator->Next();
if (FLAG_trace_osr) {
PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
converter.NameOfCPURegister(output_reg),
input_value,
*input_offset);
}
output->SetRegister(output_reg, input_value);
break;
}
case Translation::INT32_REGISTER: {
int32_t int32_value = 0;
@ -2170,7 +2351,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
}
}
if (!duplicate) *input_offset -= kPointerSize;
*input_offset -= kPointerSize;
return true;
}
@ -2231,6 +2412,7 @@ void Deoptimizer::RevertInterruptCode(Code* unoptimized_code,
back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
}
unoptimized_code->set_back_edges_patched_for_osr(false);
unoptimized_code->set_allow_osr_at_loop_nesting_level(0);
#ifdef DEBUG
// Assert that none of the back edges are patched anymore.
Deoptimizer::VerifyInterruptCode(
@ -2324,15 +2506,22 @@ Object* Deoptimizer::ComputeLiteral(int index) const {
}
void Deoptimizer::AddArgumentsObject(intptr_t slot_address, int argc) {
ArgumentsObjectMaterializationDescriptor object_desc(
reinterpret_cast<Address>(slot_address), argc);
deferred_arguments_objects_.Add(object_desc);
void Deoptimizer::AddObjectStart(intptr_t slot_address, int length) {
ObjectMaterializationDescriptor object_desc(
reinterpret_cast<Address>(slot_address), length);
deferred_objects_.Add(object_desc);
}
void Deoptimizer::AddArgumentsObjectValue(intptr_t value) {
deferred_arguments_objects_values_.Add(reinterpret_cast<Object*>(value));
void Deoptimizer::AddObjectTaggedValue(intptr_t value) {
deferred_objects_tagged_values_.Add(reinterpret_cast<Object*>(value));
deferred_objects_double_values_.Add(isolate()->heap()->nan_value()->value());
}
void Deoptimizer::AddObjectDoubleValue(double value) {
deferred_objects_tagged_values_.Add(isolate()->heap()->the_hole_value());
deferred_objects_double_values_.Add(value);
}
@ -2556,6 +2745,12 @@ void Translation::BeginCompiledStubFrame() {
}
void Translation::BeginArgumentsObject(int args_length) {
buffer_->Add(ARGUMENTS_OBJECT, zone());
buffer_->Add(args_length, zone());
}
void Translation::StoreRegister(Register reg) {
buffer_->Add(REGISTER, zone());
buffer_->Add(reg.code(), zone());
@ -2620,17 +2815,11 @@ void Translation::StoreArgumentsObject(bool args_known,
}
void Translation::MarkDuplicate() {
buffer_->Add(DUPLICATE, zone());
}
int Translation::NumberOfOperandsFor(Opcode opcode) {
switch (opcode) {
case DUPLICATE:
return 0;
case GETTER_STUB_FRAME:
case SETTER_STUB_FRAME:
case ARGUMENTS_OBJECT:
case REGISTER:
case INT32_REGISTER:
case UINT32_REGISTER:
@ -2647,7 +2836,6 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
case CONSTRUCT_STUB_FRAME:
return 2;
case JS_FRAME:
case ARGUMENTS_OBJECT:
return 3;
}
UNREACHABLE();
@ -2693,8 +2881,6 @@ const char* Translation::StringFor(Opcode opcode) {
return "LITERAL";
case ARGUMENTS_OBJECT:
return "ARGUMENTS_OBJECT";
case DUPLICATE:
return "DUPLICATE";
}
UNREACHABLE();
return "";
@ -2746,7 +2932,6 @@ SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
case Translation::INT32_REGISTER:
case Translation::UINT32_REGISTER:
case Translation::DOUBLE_REGISTER:
case Translation::DUPLICATE:
// We are at safepoint which corresponds to call. All registers are
// saved by caller so there would be no live registers at this
// point. Thus these translation commands should not be used.

34
deps/v8/src/deoptimizer.h

@ -75,17 +75,17 @@ class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
};
class ArgumentsObjectMaterializationDescriptor BASE_EMBEDDED {
class ObjectMaterializationDescriptor BASE_EMBEDDED {
public:
ArgumentsObjectMaterializationDescriptor(Address slot_address, int argc)
: slot_address_(slot_address), arguments_length_(argc) { }
ObjectMaterializationDescriptor(Address slot_address, int length)
: slot_address_(slot_address), object_length_(length) { }
Address slot_address() const { return slot_address_; }
int arguments_length() const { return arguments_length_; }
int object_length() const { return object_length_; }
private:
Address slot_address_;
int arguments_length_;
int object_length_;
};
@ -369,6 +369,10 @@ class Deoptimizer : public Malloced {
void DoComputeCompiledStubFrame(TranslationIterator* iterator,
int frame_index);
void DoTranslateObject(TranslationIterator* iterator,
int object_opcode,
int field_index);
enum DeoptimizerTranslatedValueType {
TRANSLATED_VALUE_IS_NATIVE,
TRANSLATED_VALUE_IS_TAGGED
@ -394,8 +398,9 @@ class Deoptimizer : public Malloced {
Object* ComputeLiteral(int index) const;
void AddArgumentsObject(intptr_t slot_address, int argc);
void AddArgumentsObjectValue(intptr_t value);
void AddObjectStart(intptr_t slot_address, int argc);
void AddObjectTaggedValue(intptr_t value);
void AddObjectDoubleValue(double value);
void AddDoubleValue(intptr_t slot_address, double value);
static void GenerateDeoptimizationEntries(
@ -446,8 +451,9 @@ class Deoptimizer : public Malloced {
// Array of output frame descriptions.
FrameDescription** output_;
List<Object*> deferred_arguments_objects_values_;
List<ArgumentsObjectMaterializationDescriptor> deferred_arguments_objects_;
List<Object*> deferred_objects_tagged_values_;
List<double> deferred_objects_double_values_;
List<ObjectMaterializationDescriptor> deferred_objects_;
List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
#ifdef DEBUG
DisallowHeapAllocation* disallow_heap_allocation_;
@ -698,6 +704,7 @@ class Translation BASE_EMBEDDED {
SETTER_STUB_FRAME,
ARGUMENTS_ADAPTOR_FRAME,
COMPILED_STUB_FRAME,
ARGUMENTS_OBJECT,
REGISTER,
INT32_REGISTER,
UINT32_REGISTER,
@ -706,12 +713,7 @@ class Translation BASE_EMBEDDED {
INT32_STACK_SLOT,
UINT32_STACK_SLOT,
DOUBLE_STACK_SLOT,
LITERAL,
ARGUMENTS_OBJECT,
// A prefix indicating that the next command is a duplicate of the one
// that follows it.
DUPLICATE
LITERAL
};
Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
@ -733,6 +735,7 @@ class Translation BASE_EMBEDDED {
void BeginConstructStubFrame(int literal_id, unsigned height);
void BeginGetterStubFrame(int literal_id);
void BeginSetterStubFrame(int literal_id);
void BeginArgumentsObject(int args_length);
void StoreRegister(Register reg);
void StoreInt32Register(Register reg);
void StoreUint32Register(Register reg);
@ -743,7 +746,6 @@ class Translation BASE_EMBEDDED {
void StoreDoubleStackSlot(int index);
void StoreLiteral(int literal_id);
void StoreArgumentsObject(bool args_known, int args_index, int args_length);
void MarkDuplicate();
Zone* zone() const { return zone_; }

2
deps/v8/src/execution.h

@ -253,7 +253,7 @@ class StackGuard {
void EnableInterrupts();
void DisableInterrupts();
#ifdef V8_TARGET_ARCH_X64
#if V8_TARGET_ARCH_X64
static const uintptr_t kInterruptLimit = V8_UINT64_C(0xfffffffffffffffe);
static const uintptr_t kIllegalLimit = V8_UINT64_C(0xfffffffffffffff8);
#else

331
deps/v8/src/extensions/i18n/break-iterator.cc

@ -0,0 +1,331 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "break-iterator.h"
#include <string.h>
#include "i18n-utils.h"
#include "unicode/brkiter.h"
#include "unicode/locid.h"
#include "unicode/rbbi.h"
namespace v8_i18n {
static v8::Handle<v8::Value> ThrowUnexpectedObjectError();
static icu::UnicodeString* ResetAdoptedText(v8::Handle<v8::Object>,
v8::Handle<v8::Value>);
static icu::BreakIterator* InitializeBreakIterator(v8::Handle<v8::String>,
v8::Handle<v8::Object>,
v8::Handle<v8::Object>);
static icu::BreakIterator* CreateICUBreakIterator(const icu::Locale&,
v8::Handle<v8::Object>);
static void SetResolvedSettings(const icu::Locale&,
icu::BreakIterator*,
v8::Handle<v8::Object>);
icu::BreakIterator* BreakIterator::UnpackBreakIterator(
v8::Handle<v8::Object> obj) {
v8::HandleScope handle_scope;
// v8::ObjectTemplate doesn't have HasInstance method so we can't check
// if obj is an instance of BreakIterator class. We'll check for a property
// that has to be in the object. The same applies to other services, like
// Collator and DateTimeFormat.
if (obj->HasOwnProperty(v8::String::New("breakIterator"))) {
return static_cast<icu::BreakIterator*>(
obj->GetAlignedPointerFromInternalField(0));
}
return NULL;
}
void BreakIterator::DeleteBreakIterator(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
void* param) {
// First delete the hidden C++ object.
// Unpacking should never return NULL here. That would only happen if
// this method is used as the weak callback for persistent handles not
// pointing to a break iterator.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Object> handle = v8::Local<v8::Object>::New(isolate, *object);
delete UnpackBreakIterator(handle);
delete static_cast<icu::UnicodeString*>(
handle->GetAlignedPointerFromInternalField(1));
// Then dispose of the persistent handle to JS object.
object->Dispose(isolate);
}
// Throws a JavaScript exception.
static v8::Handle<v8::Value> ThrowUnexpectedObjectError() {
// Returns undefined, and schedules an exception to be thrown.
return v8::ThrowException(v8::Exception::Error(
v8::String::New("BreakIterator method called on an object "
"that is not a BreakIterator.")));
}
// Deletes the old value and sets the adopted text in corresponding
// JavaScript object.
icu::UnicodeString* ResetAdoptedText(
v8::Handle<v8::Object> obj, v8::Handle<v8::Value> value) {
// Get the previous value from the internal field.
icu::UnicodeString* text = static_cast<icu::UnicodeString*>(
obj->GetAlignedPointerFromInternalField(1));
delete text;
// Assign new value to the internal pointer.
v8::String::Value text_value(value);
text = new icu::UnicodeString(
reinterpret_cast<const UChar*>(*text_value), text_value.length());
obj->SetAlignedPointerInInternalField(1, text);
// Return new unicode string pointer.
return text;
}
void BreakIterator::JSInternalBreakIteratorAdoptText(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsString()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New(
"Internal error. Iterator and text have to be specified.")));
return;
}
icu::BreakIterator* break_iterator = UnpackBreakIterator(args[0]->ToObject());
if (!break_iterator) {
ThrowUnexpectedObjectError();
return;
}
break_iterator->setText(*ResetAdoptedText(args[0]->ToObject(), args[1]));
}
void BreakIterator::JSInternalBreakIteratorFirst(
const v8::FunctionCallbackInfo<v8::Value>& args) {
icu::BreakIterator* break_iterator = UnpackBreakIterator(args[0]->ToObject());
if (!break_iterator) {
ThrowUnexpectedObjectError();
return;
}
args.GetReturnValue().Set(static_cast<int32_t>(break_iterator->first()));
}
void BreakIterator::JSInternalBreakIteratorNext(
const v8::FunctionCallbackInfo<v8::Value>& args) {
icu::BreakIterator* break_iterator = UnpackBreakIterator(args[0]->ToObject());
if (!break_iterator) {
ThrowUnexpectedObjectError();
return;
}
args.GetReturnValue().Set(static_cast<int32_t>(break_iterator->next()));
}
void BreakIterator::JSInternalBreakIteratorCurrent(
const v8::FunctionCallbackInfo<v8::Value>& args) {
icu::BreakIterator* break_iterator = UnpackBreakIterator(args[0]->ToObject());
if (!break_iterator) {
ThrowUnexpectedObjectError();
return;
}
args.GetReturnValue().Set(static_cast<int32_t>(break_iterator->current()));
}
void BreakIterator::JSInternalBreakIteratorBreakType(
const v8::FunctionCallbackInfo<v8::Value>& args) {
icu::BreakIterator* break_iterator = UnpackBreakIterator(args[0]->ToObject());
if (!break_iterator) {
ThrowUnexpectedObjectError();
return;
}
// TODO(cira): Remove cast once ICU fixes base BreakIterator class.
icu::RuleBasedBreakIterator* rule_based_iterator =
static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
int32_t status = rule_based_iterator->getRuleStatus();
// Keep return values in sync with JavaScript BreakType enum.
v8::Handle<v8::String> result;
if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
result = v8::String::New("none");
} else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
result = v8::String::New("number");
} else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
result = v8::String::New("letter");
} else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
result = v8::String::New("kana");
} else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
result = v8::String::New("ideo");
} else {
result = v8::String::New("unknown");
}
args.GetReturnValue().Set(result);
}
void BreakIterator::JSCreateBreakIterator(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 3 || !args[0]->IsString() || !args[1]->IsObject() ||
!args[2]->IsObject()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Internal error, wrong parameters.")));
return;
}
v8::Isolate* isolate = args.GetIsolate();
v8::Local<v8::ObjectTemplate> break_iterator_template =
Utils::GetTemplate2(isolate);
// Create an empty object wrapper.
v8::Local<v8::Object> local_object = break_iterator_template->NewInstance();
// But the handle shouldn't be empty.
// That can happen if there was a stack overflow when creating the object.
if (local_object.IsEmpty()) {
args.GetReturnValue().Set(local_object);
return;
}
// Set break iterator as internal field of the resulting JS object.
icu::BreakIterator* break_iterator = InitializeBreakIterator(
args[0]->ToString(), args[1]->ToObject(), args[2]->ToObject());
if (!break_iterator) {
v8::ThrowException(v8::Exception::Error(v8::String::New(
"Internal error. Couldn't create ICU break iterator.")));
return;
} else {
local_object->SetAlignedPointerInInternalField(0, break_iterator);
// Make sure that the pointer to adopted text is NULL.
local_object->SetAlignedPointerInInternalField(1, NULL);
v8::TryCatch try_catch;
local_object->Set(v8::String::New("breakIterator"),
v8::String::New("valid"));
if (try_catch.HasCaught()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Internal error, couldn't set property.")));
return;
}
}
v8::Persistent<v8::Object> wrapper(isolate, local_object);
// Make object handle weak so we can delete iterator once GC kicks in.
wrapper.MakeWeak<void>(NULL, &DeleteBreakIterator);
args.GetReturnValue().Set(wrapper);
wrapper.ClearAndLeak();
}
static icu::BreakIterator* InitializeBreakIterator(
v8::Handle<v8::String> locale,
v8::Handle<v8::Object> options,
v8::Handle<v8::Object> resolved) {
// Convert BCP47 into ICU locale format.
UErrorCode status = U_ZERO_ERROR;
icu::Locale icu_locale;
char icu_result[ULOC_FULLNAME_CAPACITY];
int icu_length = 0;
v8::String::AsciiValue bcp47_locale(locale);
if (bcp47_locale.length() != 0) {
uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
&icu_length, &status);
if (U_FAILURE(status) || icu_length == 0) {
return NULL;
}
icu_locale = icu::Locale(icu_result);
}
icu::BreakIterator* break_iterator =
CreateICUBreakIterator(icu_locale, options);
if (!break_iterator) {
// Remove extensions and try again.
icu::Locale no_extension_locale(icu_locale.getBaseName());
break_iterator = CreateICUBreakIterator(no_extension_locale, options);
// Set resolved settings (locale).
SetResolvedSettings(no_extension_locale, break_iterator, resolved);
} else {
SetResolvedSettings(icu_locale, break_iterator, resolved);
}
return break_iterator;
}
static icu::BreakIterator* CreateICUBreakIterator(
const icu::Locale& icu_locale, v8::Handle<v8::Object> options) {
UErrorCode status = U_ZERO_ERROR;
icu::BreakIterator* break_iterator = NULL;
icu::UnicodeString type;
if (!Utils::ExtractStringSetting(options, "type", &type)) {
// Type had to be in the options. This would be an internal error.
return NULL;
}
if (type == UNICODE_STRING_SIMPLE("character")) {
break_iterator =
icu::BreakIterator::createCharacterInstance(icu_locale, status);
} else if (type == UNICODE_STRING_SIMPLE("sentence")) {
break_iterator =
icu::BreakIterator::createSentenceInstance(icu_locale, status);
} else if (type == UNICODE_STRING_SIMPLE("line")) {
break_iterator =
icu::BreakIterator::createLineInstance(icu_locale, status);
} else {
// Defualt is word iterator.
break_iterator =
icu::BreakIterator::createWordInstance(icu_locale, status);
}
if (U_FAILURE(status)) {
delete break_iterator;
return NULL;
}
return break_iterator;
}
static void SetResolvedSettings(const icu::Locale& icu_locale,
icu::BreakIterator* date_format,
v8::Handle<v8::Object> resolved) {
UErrorCode status = U_ZERO_ERROR;
// Set the locale
char result[ULOC_FULLNAME_CAPACITY];
status = U_ZERO_ERROR;
uloc_toLanguageTag(
icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
if (U_SUCCESS(status)) {
resolved->Set(v8::String::New("locale"), v8::String::New(result));
} else {
// This would never happen, since we got the locale from ICU.
resolved->Set(v8::String::New("locale"), v8::String::New("und"));
}
}
} // namespace v8_i18n

85
deps/v8/src/extensions/i18n/break-iterator.h

@ -0,0 +1,85 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#ifndef V8_EXTENSIONS_I18N_BREAK_ITERATOR_H_
#define V8_EXTENSIONS_I18N_BREAK_ITERATOR_H_
#include "unicode/uversion.h"
#include "v8.h"
namespace U_ICU_NAMESPACE {
class BreakIterator;
class UnicodeString;
}
namespace v8_i18n {
class BreakIterator {
public:
static void JSCreateBreakIterator(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Helper methods for various bindings.
// Unpacks iterator object from corresponding JavaScript object.
static icu::BreakIterator* UnpackBreakIterator(v8::Handle<v8::Object> obj);
// Release memory we allocated for the BreakIterator once the JS object that
// holds the pointer gets garbage collected.
static void DeleteBreakIterator(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
void* param);
// Assigns new text to the iterator.
static void JSInternalBreakIteratorAdoptText(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Moves iterator to the beginning of the string and returns new position.
static void JSInternalBreakIteratorFirst(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Moves iterator to the next position and returns it.
static void JSInternalBreakIteratorNext(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Returns current iterator's current position.
static void JSInternalBreakIteratorCurrent(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Returns type of the item from current position.
// This call is only valid for word break iterators. Others just return 0.
static void JSInternalBreakIteratorBreakType(
const v8::FunctionCallbackInfo<v8::Value>& args);
private:
BreakIterator() {}
};
} // namespace v8_i18n
#endif // V8_EXTENSIONS_I18N_BREAK_ITERATOR_H_

197
deps/v8/src/extensions/i18n/break-iterator.js

@ -0,0 +1,197 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
// ECMAScript 402 API implementation is broken into separate files for
// each service. The build system combines them together into one
// Intl namespace.
/**
* Initializes the given object so it's a valid BreakIterator instance.
* Useful for subclassing.
*/
function initializeBreakIterator(iterator, locales, options) {
native function NativeJSCreateBreakIterator();
if (iterator.hasOwnProperty('__initializedIntlObject')) {
throw new TypeError('Trying to re-initialize v8BreakIterator object.');
}
if (options === undefined) {
options = {};
}
var getOption = getGetOption(options, 'breakiterator');
var internalOptions = {};
defineWEProperty(internalOptions, 'type', getOption(
'type', 'string', ['character', 'word', 'sentence', 'line'], 'word'));
var locale = resolveLocale('breakiterator', locales, options);
var resolved = Object.defineProperties({}, {
requestedLocale: {value: locale.locale, writable: true},
type: {value: internalOptions.type, writable: true},
locale: {writable: true}
});
var internalIterator = NativeJSCreateBreakIterator(locale.locale,
internalOptions,
resolved);
Object.defineProperty(iterator, 'iterator', {value: internalIterator});
Object.defineProperty(iterator, 'resolved', {value: resolved});
Object.defineProperty(iterator, '__initializedIntlObject',
{value: 'breakiterator'});
return iterator;
}
/**
* Constructs Intl.v8BreakIterator object given optional locales and options
* parameters.
*
* @constructor
*/
%SetProperty(Intl, 'v8BreakIterator', function() {
var locales = arguments[0];
var options = arguments[1];
if (!this || this === Intl) {
// Constructor is called as a function.
return new Intl.v8BreakIterator(locales, options);
}
return initializeBreakIterator(toObject(this), locales, options);
},
ATTRIBUTES.DONT_ENUM
);
/**
* BreakIterator resolvedOptions method.
*/
%SetProperty(Intl.v8BreakIterator.prototype, 'resolvedOptions', function() {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject !== 'breakiterator') {
throw new TypeError('resolvedOptions method called on a non-object or ' +
'on a object that is not Intl.v8BreakIterator.');
}
var segmenter = this;
var locale = getOptimalLanguageTag(segmenter.resolved.requestedLocale,
segmenter.resolved.locale);
return {
locale: locale,
type: segmenter.resolved.type
};
},
ATTRIBUTES.DONT_ENUM
);
%FunctionSetName(Intl.v8BreakIterator.prototype.resolvedOptions,
'resolvedOptions');
%FunctionRemovePrototype(Intl.v8BreakIterator.prototype.resolvedOptions);
%SetNativeFlag(Intl.v8BreakIterator.prototype.resolvedOptions);
/**
* Returns the subset of the given locale list for which this locale list
* has a matching (possibly fallback) locale. Locales appear in the same
* order in the returned list as in the input list.
* Options are optional parameter.
*/
%SetProperty(Intl.v8BreakIterator, 'supportedLocalesOf', function(locales) {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
return supportedLocalesOf('breakiterator', locales, arguments[1]);
},
ATTRIBUTES.DONT_ENUM
);
%FunctionSetName(Intl.v8BreakIterator.supportedLocalesOf, 'supportedLocalesOf');
%FunctionRemovePrototype(Intl.v8BreakIterator.supportedLocalesOf);
%SetNativeFlag(Intl.v8BreakIterator.supportedLocalesOf);
/**
* Adopts text to segment using the iterator. Old text, if present,
* gets discarded.
*/
function adoptText(iterator, text) {
native function NativeJSBreakIteratorAdoptText();
NativeJSBreakIteratorAdoptText(iterator.iterator, String(text));
}
/**
* Returns index of the first break in the string and moves current pointer.
*/
function first(iterator) {
native function NativeJSBreakIteratorFirst();
return NativeJSBreakIteratorFirst(iterator.iterator);
}
/**
* Returns the index of the next break and moves the pointer.
*/
function next(iterator) {
native function NativeJSBreakIteratorNext();
return NativeJSBreakIteratorNext(iterator.iterator);
}
/**
* Returns index of the current break.
*/
function current(iterator) {
native function NativeJSBreakIteratorCurrent();
return NativeJSBreakIteratorCurrent(iterator.iterator);
}
/**
* Returns type of the current break.
*/
function breakType(iterator) {
native function NativeJSBreakIteratorBreakType();
return NativeJSBreakIteratorBreakType(iterator.iterator);
}
addBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1);
addBoundMethod(Intl.v8BreakIterator, 'first', first, 0);
addBoundMethod(Intl.v8BreakIterator, 'next', next, 0);
addBoundMethod(Intl.v8BreakIterator, 'current', current, 0);
addBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0);

363
deps/v8/src/extensions/i18n/collator.cc

@ -0,0 +1,363 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#include "collator.h"
#include "i18n-utils.h"
#include "unicode/coll.h"
#include "unicode/locid.h"
#include "unicode/ucol.h"
namespace v8_i18n {
static icu::Collator* InitializeCollator(
v8::Handle<v8::String>, v8::Handle<v8::Object>, v8::Handle<v8::Object>);
static icu::Collator* CreateICUCollator(
const icu::Locale&, v8::Handle<v8::Object>);
static bool SetBooleanAttribute(
UColAttribute, const char*, v8::Handle<v8::Object>, icu::Collator*);
static void SetResolvedSettings(
const icu::Locale&, icu::Collator*, v8::Handle<v8::Object>);
static void SetBooleanSetting(
UColAttribute, icu::Collator*, const char*, v8::Handle<v8::Object>);
icu::Collator* Collator::UnpackCollator(v8::Handle<v8::Object> obj) {
v8::HandleScope handle_scope;
if (obj->HasOwnProperty(v8::String::New("collator"))) {
return static_cast<icu::Collator*>(
obj->GetAlignedPointerFromInternalField(0));
}
return NULL;
}
void Collator::DeleteCollator(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
void* param) {
// First delete the hidden C++ object.
// Unpacking should never return NULL here. That would only happen if
// this method is used as the weak callback for persistent handles not
// pointing to a collator.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Object> handle = v8::Local<v8::Object>::New(isolate, *object);
delete UnpackCollator(handle);
// Then dispose of the persistent handle to JS object.
object->Dispose(isolate);
}
// Throws a JavaScript exception.
static v8::Handle<v8::Value> ThrowUnexpectedObjectError() {
// Returns undefined, and schedules an exception to be thrown.
return v8::ThrowException(v8::Exception::Error(
v8::String::New("Collator method called on an object "
"that is not a Collator.")));
}
// When there's an ICU error, throw a JavaScript error with |message|.
static v8::Handle<v8::Value> ThrowExceptionForICUError(const char* message) {
return v8::ThrowException(v8::Exception::Error(v8::String::New(message)));
}
// static
void Collator::JSInternalCompare(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 3 || !args[0]->IsObject() ||
!args[1]->IsString() || !args[2]->IsString()) {
v8::ThrowException(v8::Exception::SyntaxError(
v8::String::New("Collator and two string arguments are required.")));
return;
}
icu::Collator* collator = UnpackCollator(args[0]->ToObject());
if (!collator) {
ThrowUnexpectedObjectError();
return;
}
v8::String::Value string_value1(args[1]);
v8::String::Value string_value2(args[2]);
const UChar* string1 = reinterpret_cast<const UChar*>(*string_value1);
const UChar* string2 = reinterpret_cast<const UChar*>(*string_value2);
UErrorCode status = U_ZERO_ERROR;
UCollationResult result = collator->compare(
string1, string_value1.length(), string2, string_value2.length(), status);
if (U_FAILURE(status)) {
ThrowExceptionForICUError(
"Internal error. Unexpected failure in Collator.compare.");
return;
}
args.GetReturnValue().Set(result);
}
void Collator::JSCreateCollator(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 3 || !args[0]->IsString() || !args[1]->IsObject() ||
!args[2]->IsObject()) {
v8::ThrowException(v8::Exception::SyntaxError(
v8::String::New("Internal error, wrong parameters.")));
return;
}
v8::Isolate* isolate = args.GetIsolate();
v8::Local<v8::ObjectTemplate> intl_collator_template =
Utils::GetTemplate(isolate);
// Create an empty object wrapper.
v8::Local<v8::Object> local_object = intl_collator_template->NewInstance();
// But the handle shouldn't be empty.
// That can happen if there was a stack overflow when creating the object.
if (local_object.IsEmpty()) {
args.GetReturnValue().Set(local_object);
return;
}
// Set collator as internal field of the resulting JS object.
icu::Collator* collator = InitializeCollator(
args[0]->ToString(), args[1]->ToObject(), args[2]->ToObject());
if (!collator) {
v8::ThrowException(v8::Exception::Error(v8::String::New(
"Internal error. Couldn't create ICU collator.")));
return;
} else {
local_object->SetAlignedPointerInInternalField(0, collator);
// Make it safer to unpack later on.
v8::TryCatch try_catch;
local_object->Set(v8::String::New("collator"), v8::String::New("valid"));
if (try_catch.HasCaught()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Internal error, couldn't set property.")));
return;
}
}
v8::Persistent<v8::Object> wrapper(isolate, local_object);
// Make object handle weak so we can delete iterator once GC kicks in.
wrapper.MakeWeak<void>(NULL, &DeleteCollator);
args.GetReturnValue().Set(wrapper);
wrapper.ClearAndLeak();
}
static icu::Collator* InitializeCollator(v8::Handle<v8::String> locale,
v8::Handle<v8::Object> options,
v8::Handle<v8::Object> resolved) {
// Convert BCP47 into ICU locale format.
UErrorCode status = U_ZERO_ERROR;
icu::Locale icu_locale;
char icu_result[ULOC_FULLNAME_CAPACITY];
int icu_length = 0;
v8::String::AsciiValue bcp47_locale(locale);
if (bcp47_locale.length() != 0) {
uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
&icu_length, &status);
if (U_FAILURE(status) || icu_length == 0) {
return NULL;
}
icu_locale = icu::Locale(icu_result);
}
icu::Collator* collator = CreateICUCollator(icu_locale, options);
if (!collator) {
// Remove extensions and try again.
icu::Locale no_extension_locale(icu_locale.getBaseName());
collator = CreateICUCollator(no_extension_locale, options);
// Set resolved settings (pattern, numbering system).
SetResolvedSettings(no_extension_locale, collator, resolved);
} else {
SetResolvedSettings(icu_locale, collator, resolved);
}
return collator;
}
static icu::Collator* CreateICUCollator(
const icu::Locale& icu_locale, v8::Handle<v8::Object> options) {
// Make collator from options.
icu::Collator* collator = NULL;
UErrorCode status = U_ZERO_ERROR;
collator = icu::Collator::createInstance(icu_locale, status);
if (U_FAILURE(status)) {
delete collator;
return NULL;
}
// Set flags first, and then override them with sensitivity if necessary.
SetBooleanAttribute(UCOL_NUMERIC_COLLATION, "numeric", options, collator);
// Normalization is always on, by the spec. We are free to optimize
// if the strings are already normalized (but we don't have a way to tell
// that right now).
collator->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
icu::UnicodeString case_first;
if (Utils::ExtractStringSetting(options, "caseFirst", &case_first)) {
if (case_first == UNICODE_STRING_SIMPLE("upper")) {
collator->setAttribute(UCOL_CASE_FIRST, UCOL_UPPER_FIRST, status);
} else if (case_first == UNICODE_STRING_SIMPLE("lower")) {
collator->setAttribute(UCOL_CASE_FIRST, UCOL_LOWER_FIRST, status);
} else {
// Default (false/off).
collator->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
}
}
icu::UnicodeString sensitivity;
if (Utils::ExtractStringSetting(options, "sensitivity", &sensitivity)) {
if (sensitivity == UNICODE_STRING_SIMPLE("base")) {
collator->setStrength(icu::Collator::PRIMARY);
} else if (sensitivity == UNICODE_STRING_SIMPLE("accent")) {
collator->setStrength(icu::Collator::SECONDARY);
} else if (sensitivity == UNICODE_STRING_SIMPLE("case")) {
collator->setStrength(icu::Collator::PRIMARY);
collator->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status);
} else {
// variant (default)
collator->setStrength(icu::Collator::TERTIARY);
}
}
bool ignore;
if (Utils::ExtractBooleanSetting(options, "ignorePunctuation", &ignore)) {
if (ignore) {
collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status);
}
}
return collator;
}
static bool SetBooleanAttribute(UColAttribute attribute,
const char* name,
v8::Handle<v8::Object> options,
icu::Collator* collator) {
UErrorCode status = U_ZERO_ERROR;
bool result;
if (Utils::ExtractBooleanSetting(options, name, &result)) {
collator->setAttribute(attribute, result ? UCOL_ON : UCOL_OFF, status);
if (U_FAILURE(status)) {
return false;
}
}
return true;
}
static void SetResolvedSettings(const icu::Locale& icu_locale,
icu::Collator* collator,
v8::Handle<v8::Object> resolved) {
SetBooleanSetting(UCOL_NUMERIC_COLLATION, collator, "numeric", resolved);
UErrorCode status = U_ZERO_ERROR;
switch (collator->getAttribute(UCOL_CASE_FIRST, status)) {
case UCOL_LOWER_FIRST:
resolved->Set(v8::String::New("caseFirst"), v8::String::New("lower"));
break;
case UCOL_UPPER_FIRST:
resolved->Set(v8::String::New("caseFirst"), v8::String::New("upper"));
break;
default:
resolved->Set(v8::String::New("caseFirst"), v8::String::New("false"));
}
switch (collator->getAttribute(UCOL_STRENGTH, status)) {
case UCOL_PRIMARY: {
resolved->Set(v8::String::New("strength"), v8::String::New("primary"));
// case level: true + s1 -> case, s1 -> base.
if (UCOL_ON == collator->getAttribute(UCOL_CASE_LEVEL, status)) {
resolved->Set(v8::String::New("sensitivity"), v8::String::New("case"));
} else {
resolved->Set(v8::String::New("sensitivity"), v8::String::New("base"));
}
break;
}
case UCOL_SECONDARY:
resolved->Set(v8::String::New("strength"), v8::String::New("secondary"));
resolved->Set(v8::String::New("sensitivity"), v8::String::New("accent"));
break;
case UCOL_TERTIARY:
resolved->Set(v8::String::New("strength"), v8::String::New("tertiary"));
resolved->Set(v8::String::New("sensitivity"), v8::String::New("variant"));
break;
case UCOL_QUATERNARY:
// We shouldn't get quaternary and identical from ICU, but if we do
// put them into variant.
resolved->Set(v8::String::New("strength"), v8::String::New("quaternary"));
resolved->Set(v8::String::New("sensitivity"), v8::String::New("variant"));
break;
default:
resolved->Set(v8::String::New("strength"), v8::String::New("identical"));
resolved->Set(v8::String::New("sensitivity"), v8::String::New("variant"));
}
if (UCOL_SHIFTED == collator->getAttribute(UCOL_ALTERNATE_HANDLING, status)) {
resolved->Set(v8::String::New("ignorePunctuation"),
v8::Boolean::New(true));
} else {
resolved->Set(v8::String::New("ignorePunctuation"),
v8::Boolean::New(false));
}
// Set the locale
char result[ULOC_FULLNAME_CAPACITY];
status = U_ZERO_ERROR;
uloc_toLanguageTag(
icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
if (U_SUCCESS(status)) {
resolved->Set(v8::String::New("locale"), v8::String::New(result));
} else {
// This would never happen, since we got the locale from ICU.
resolved->Set(v8::String::New("locale"), v8::String::New("und"));
}
}
static void SetBooleanSetting(UColAttribute attribute,
icu::Collator* collator,
const char* property,
v8::Handle<v8::Object> resolved) {
UErrorCode status = U_ZERO_ERROR;
if (UCOL_ON == collator->getAttribute(attribute, status)) {
resolved->Set(v8::String::New(property), v8::Boolean::New(true));
} else {
resolved->Set(v8::String::New(property), v8::Boolean::New(false));
}
}
} // namespace v8_i18n

68
deps/v8/src/extensions/i18n/collator.h

@ -0,0 +1,68 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#ifndef V8_EXTENSIONS_I18N_COLLATOR_H_
#define V8_EXTENSIONS_I18N_COLLATOR_H_
#include "unicode/uversion.h"
#include "v8.h"
namespace U_ICU_NAMESPACE {
class Collator;
class UnicodeString;
}
namespace v8_i18n {
class Collator {
public:
static void JSCreateCollator(const v8::FunctionCallbackInfo<v8::Value>& args);
// Helper methods for various bindings.
// Unpacks collator object from corresponding JavaScript object.
static icu::Collator* UnpackCollator(v8::Handle<v8::Object> obj);
// Release memory we allocated for the Collator once the JS object that
// holds the pointer gets garbage collected.
static void DeleteCollator(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
void* param);
// Compare two strings and returns -1, 0 and 1 depending on
// whether string1 is smaller than, equal to or larger than string2.
static void JSInternalCompare(
const v8::FunctionCallbackInfo<v8::Value>& args);
private:
Collator() {}
};
} // namespace v8_i18n
#endif // V8_EXTENSIONS_I18N_COLLATOR_H_

212
deps/v8/src/extensions/i18n/collator.js

@ -0,0 +1,212 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
// ECMAScript 402 API implementation is broken into separate files for
// each service. The build system combines them together into one
// Intl namespace.
/**
* Initializes the given object so it's a valid Collator instance.
* Useful for subclassing.
*/
function initializeCollator(collator, locales, options) {
native function NativeJSCreateCollator();
if (collator.hasOwnProperty('__initializedIntlObject')) {
throw new TypeError('Trying to re-initialize Collator object.');
}
if (options === undefined) {
options = {};
}
var getOption = getGetOption(options, 'collator');
var internalOptions = {};
defineWEProperty(internalOptions, 'usage', getOption(
'usage', 'string', ['sort', 'search'], 'sort'));
var sensitivity = getOption('sensitivity', 'string',
['base', 'accent', 'case', 'variant']);
if (sensitivity === undefined && internalOptions.usage === 'sort') {
sensitivity = 'variant';
}
defineWEProperty(internalOptions, 'sensitivity', sensitivity);
defineWEProperty(internalOptions, 'ignorePunctuation', getOption(
'ignorePunctuation', 'boolean', undefined, false));
var locale = resolveLocale('collator', locales, options);
// ICU can't take kb, kc... parameters through localeID, so we need to pass
// them as options.
// One exception is -co- which has to be part of the extension, but only for
// usage: sort, and its value can't be 'standard' or 'search'.
var extensionMap = parseExtension(locale.extension);
setOptions(
options, extensionMap, COLLATOR_KEY_MAP, getOption, internalOptions);
var collation = 'default';
var extension = '';
if (extensionMap.hasOwnProperty('co') && internalOptions.usage === 'sort') {
if (ALLOWED_CO_VALUES.indexOf(extensionMap.co) !== -1) {
extension = '-u-co-' + extensionMap.co;
// ICU can't tell us what the collation is, so save user's input.
collation = extensionMap.co;
}
} else if (internalOptions.usage === 'search') {
extension = '-u-co-search';
}
defineWEProperty(internalOptions, 'collation', collation);
var requestedLocale = locale.locale + extension;
// We define all properties C++ code may produce, to prevent security
// problems. If malicious user decides to redefine Object.prototype.locale
// we can't just use plain x.locale = 'us' or in C++ Set("locale", "us").
// Object.defineProperties will either succeed defining or throw an error.
var resolved = Object.defineProperties({}, {
caseFirst: {writable: true},
collation: {value: internalOptions.collation, writable: true},
ignorePunctuation: {writable: true},
locale: {writable: true},
numeric: {writable: true},
requestedLocale: {value: requestedLocale, writable: true},
sensitivity: {writable: true},
strength: {writable: true},
usage: {value: internalOptions.usage, writable: true}
});
var internalCollator = NativeJSCreateCollator(requestedLocale,
internalOptions,
resolved);
// Writable, configurable and enumerable are set to false by default.
Object.defineProperty(collator, 'collator', {value: internalCollator});
Object.defineProperty(collator, '__initializedIntlObject',
{value: 'collator'});
Object.defineProperty(collator, 'resolved', {value: resolved});
return collator;
}
/**
* Constructs Intl.Collator object given optional locales and options
* parameters.
*
* @constructor
*/
%SetProperty(Intl, 'Collator', function() {
var locales = arguments[0];
var options = arguments[1];
if (!this || this === Intl) {
// Constructor is called as a function.
return new Intl.Collator(locales, options);
}
return initializeCollator(toObject(this), locales, options);
},
ATTRIBUTES.DONT_ENUM
);
/**
* Collator resolvedOptions method.
*/
%SetProperty(Intl.Collator.prototype, 'resolvedOptions', function() {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject !== 'collator') {
throw new TypeError('resolvedOptions method called on a non-object ' +
'or on a object that is not Intl.Collator.');
}
var coll = this;
var locale = getOptimalLanguageTag(coll.resolved.requestedLocale,
coll.resolved.locale);
return {
locale: locale,
usage: coll.resolved.usage,
sensitivity: coll.resolved.sensitivity,
ignorePunctuation: coll.resolved.ignorePunctuation,
numeric: coll.resolved.numeric,
caseFirst: coll.resolved.caseFirst,
collation: coll.resolved.collation
};
},
ATTRIBUTES.DONT_ENUM
);
%FunctionSetName(Intl.Collator.prototype.resolvedOptions, 'resolvedOptions');
%FunctionRemovePrototype(Intl.Collator.prototype.resolvedOptions);
%SetNativeFlag(Intl.Collator.prototype.resolvedOptions);
/**
* Returns the subset of the given locale list for which this locale list
* has a matching (possibly fallback) locale. Locales appear in the same
* order in the returned list as in the input list.
* Options are optional parameter.
*/
%SetProperty(Intl.Collator, 'supportedLocalesOf', function(locales) {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
return supportedLocalesOf('collator', locales, arguments[1]);
},
ATTRIBUTES.DONT_ENUM
);
%FunctionSetName(Intl.Collator.supportedLocalesOf, 'supportedLocalesOf');
%FunctionRemovePrototype(Intl.Collator.supportedLocalesOf);
%SetNativeFlag(Intl.Collator.supportedLocalesOf);
/**
* When the compare method is called with two arguments x and y, it returns a
* Number other than NaN that represents the result of a locale-sensitive
* String comparison of x with y.
* The result is intended to order String values in the sort order specified
* by the effective locale and collation options computed during construction
* of this Collator object, and will be negative, zero, or positive, depending
* on whether x comes before y in the sort order, the Strings are equal under
* the sort order, or x comes after y in the sort order, respectively.
*/
function compare(collator, x, y) {
native function NativeJSInternalCompare();
return NativeJSInternalCompare(collator.collator, String(x), String(y));
};
addBoundMethod(Intl.Collator, 'compare', compare, 2);

329
deps/v8/src/extensions/i18n/date-format.cc

@ -0,0 +1,329 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#include "date-format.h"
#include <string.h>
#include "i18n-utils.h"
#include "unicode/calendar.h"
#include "unicode/dtfmtsym.h"
#include "unicode/dtptngen.h"
#include "unicode/locid.h"
#include "unicode/numsys.h"
#include "unicode/smpdtfmt.h"
#include "unicode/timezone.h"
namespace v8_i18n {
static icu::SimpleDateFormat* InitializeDateTimeFormat(v8::Handle<v8::String>,
v8::Handle<v8::Object>,
v8::Handle<v8::Object>);
static icu::SimpleDateFormat* CreateICUDateFormat(const icu::Locale&,
v8::Handle<v8::Object>);
static void SetResolvedSettings(const icu::Locale&,
icu::SimpleDateFormat*,
v8::Handle<v8::Object>);
icu::SimpleDateFormat* DateFormat::UnpackDateFormat(
v8::Handle<v8::Object> obj) {
v8::HandleScope handle_scope;
if (obj->HasOwnProperty(v8::String::New("dateFormat"))) {
return static_cast<icu::SimpleDateFormat*>(
obj->GetAlignedPointerFromInternalField(0));
}
return NULL;
}
void DateFormat::DeleteDateFormat(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
void* param) {
// First delete the hidden C++ object.
// Unpacking should never return NULL here. That would only happen if
// this method is used as the weak callback for persistent handles not
// pointing to a date time formatter.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Object> handle = v8::Local<v8::Object>::New(isolate, *object);
delete UnpackDateFormat(handle);
// Then dispose of the persistent handle to JS object.
object->Dispose(isolate);
}
void DateFormat::JSInternalFormat(
const v8::FunctionCallbackInfo<v8::Value>& args) {
double millis = 0.0;
if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsDate()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New(
"Internal error. Formatter and date value have to be specified.")));
return;
} else {
millis = v8::Date::Cast(*args[1])->NumberValue();
}
icu::SimpleDateFormat* date_format = UnpackDateFormat(args[0]->ToObject());
if (!date_format) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("DateTimeFormat method called on an object "
"that is not a DateTimeFormat.")));
return;
}
icu::UnicodeString result;
date_format->format(millis, result);
args.GetReturnValue().Set(v8::String::New(
reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()));
}
void DateFormat::JSInternalParse(
const v8::FunctionCallbackInfo<v8::Value>& args) {
icu::UnicodeString string_date;
if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsString()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New(
"Internal error. Formatter and string have to be specified.")));
return;
} else {
if (!Utils::V8StringToUnicodeString(args[1], &string_date)) {
string_date = "";
}
}
icu::SimpleDateFormat* date_format = UnpackDateFormat(args[0]->ToObject());
if (!date_format) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("DateTimeFormat method called on an object "
"that is not a DateTimeFormat.")));
return;
}
UErrorCode status = U_ZERO_ERROR;
UDate date = date_format->parse(string_date, status);
if (U_FAILURE(status)) {
return;
}
args.GetReturnValue().Set(v8::Date::New(static_cast<double>(date)));
}
void DateFormat::JSCreateDateTimeFormat(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 3 ||
!args[0]->IsString() ||
!args[1]->IsObject() ||
!args[2]->IsObject()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Internal error, wrong parameters.")));
return;
}
v8::Isolate* isolate = args.GetIsolate();
v8::Local<v8::ObjectTemplate> date_format_template =
Utils::GetTemplate(isolate);
// Create an empty object wrapper.
v8::Local<v8::Object> local_object = date_format_template->NewInstance();
// But the handle shouldn't be empty.
// That can happen if there was a stack overflow when creating the object.
if (local_object.IsEmpty()) {
args.GetReturnValue().Set(local_object);
return;
}
// Set date time formatter as internal field of the resulting JS object.
icu::SimpleDateFormat* date_format = InitializeDateTimeFormat(
args[0]->ToString(), args[1]->ToObject(), args[2]->ToObject());
if (!date_format) {
v8::ThrowException(v8::Exception::Error(v8::String::New(
"Internal error. Couldn't create ICU date time formatter.")));
return;
} else {
local_object->SetAlignedPointerInInternalField(0, date_format);
v8::TryCatch try_catch;
local_object->Set(v8::String::New("dateFormat"), v8::String::New("valid"));
if (try_catch.HasCaught()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Internal error, couldn't set property.")));
return;
}
}
v8::Persistent<v8::Object> wrapper(isolate, local_object);
// Make object handle weak so we can delete iterator once GC kicks in.
wrapper.MakeWeak<void>(NULL, &DeleteDateFormat);
args.GetReturnValue().Set(wrapper);
wrapper.ClearAndLeak();
}
static icu::SimpleDateFormat* InitializeDateTimeFormat(
v8::Handle<v8::String> locale,
v8::Handle<v8::Object> options,
v8::Handle<v8::Object> resolved) {
// Convert BCP47 into ICU locale format.
UErrorCode status = U_ZERO_ERROR;
icu::Locale icu_locale;
char icu_result[ULOC_FULLNAME_CAPACITY];
int icu_length = 0;
v8::String::AsciiValue bcp47_locale(locale);
if (bcp47_locale.length() != 0) {
uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
&icu_length, &status);
if (U_FAILURE(status) || icu_length == 0) {
return NULL;
}
icu_locale = icu::Locale(icu_result);
}
icu::SimpleDateFormat* date_format = CreateICUDateFormat(icu_locale, options);
if (!date_format) {
// Remove extensions and try again.
icu::Locale no_extension_locale(icu_locale.getBaseName());
date_format = CreateICUDateFormat(no_extension_locale, options);
// Set resolved settings (pattern, numbering system, calendar).
SetResolvedSettings(no_extension_locale, date_format, resolved);
} else {
SetResolvedSettings(icu_locale, date_format, resolved);
}
return date_format;
}
static icu::SimpleDateFormat* CreateICUDateFormat(
const icu::Locale& icu_locale, v8::Handle<v8::Object> options) {
// Create time zone as specified by the user. We have to re-create time zone
// since calendar takes ownership.
icu::TimeZone* tz = NULL;
icu::UnicodeString timezone;
if (Utils::ExtractStringSetting(options, "timeZone", &timezone)) {
tz = icu::TimeZone::createTimeZone(timezone);
} else {
tz = icu::TimeZone::createDefault();
}
// Create a calendar using locale, and apply time zone to it.
UErrorCode status = U_ZERO_ERROR;
icu::Calendar* calendar =
icu::Calendar::createInstance(tz, icu_locale, status);
// Make formatter from skeleton. Calendar and numbering system are added
// to the locale as Unicode extension (if they were specified at all).
icu::SimpleDateFormat* date_format = NULL;
icu::UnicodeString skeleton;
if (Utils::ExtractStringSetting(options, "skeleton", &skeleton)) {
icu::DateTimePatternGenerator* generator =
icu::DateTimePatternGenerator::createInstance(icu_locale, status);
icu::UnicodeString pattern;
if (U_SUCCESS(status)) {
pattern = generator->getBestPattern(skeleton, status);
delete generator;
}
date_format = new icu::SimpleDateFormat(pattern, icu_locale, status);
if (U_SUCCESS(status)) {
date_format->adoptCalendar(calendar);
}
}
if (U_FAILURE(status)) {
delete calendar;
delete date_format;
date_format = NULL;
}
return date_format;
}
static void SetResolvedSettings(const icu::Locale& icu_locale,
icu::SimpleDateFormat* date_format,
v8::Handle<v8::Object> resolved) {
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString pattern;
date_format->toPattern(pattern);
resolved->Set(v8::String::New("pattern"),
v8::String::New(reinterpret_cast<const uint16_t*>(
pattern.getBuffer()), pattern.length()));
// Set time zone and calendar.
if (date_format) {
const icu::Calendar* calendar = date_format->getCalendar();
const char* calendar_name = calendar->getType();
resolved->Set(v8::String::New("calendar"), v8::String::New(calendar_name));
const icu::TimeZone& tz = calendar->getTimeZone();
icu::UnicodeString time_zone;
tz.getID(time_zone);
icu::UnicodeString canonical_time_zone;
icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status);
if (U_SUCCESS(status)) {
if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) {
resolved->Set(v8::String::New("timeZone"), v8::String::New("UTC"));
} else {
resolved->Set(v8::String::New("timeZone"),
v8::String::New(reinterpret_cast<const uint16_t*>(
canonical_time_zone.getBuffer()),
canonical_time_zone.length()));
}
}
}
// Ugly hack. ICU doesn't expose numbering system in any way, so we have
// to assume that for given locale NumberingSystem constructor produces the
// same digits as NumberFormat/Calendar would.
status = U_ZERO_ERROR;
icu::NumberingSystem* numbering_system =
icu::NumberingSystem::createInstance(icu_locale, status);
if (U_SUCCESS(status)) {
const char* ns = numbering_system->getName();
resolved->Set(v8::String::New("numberingSystem"), v8::String::New(ns));
} else {
resolved->Set(v8::String::New("numberingSystem"), v8::Undefined());
}
delete numbering_system;
// Set the locale
char result[ULOC_FULLNAME_CAPACITY];
status = U_ZERO_ERROR;
uloc_toLanguageTag(
icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
if (U_SUCCESS(status)) {
resolved->Set(v8::String::New("locale"), v8::String::New(result));
} else {
// This would never happen, since we got the locale from ICU.
resolved->Set(v8::String::New("locale"), v8::String::New("und"));
}
}
} // namespace v8_i18n

71
deps/v8/src/extensions/i18n/date-format.h

@ -0,0 +1,71 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#ifndef V8_EXTENSIONS_I18N_DATE_FORMAT_H_
#define V8_EXTENSIONS_I18N_DATE_FORMAT_H_
#include "unicode/uversion.h"
#include "v8.h"
namespace U_ICU_NAMESPACE {
class SimpleDateFormat;
}
namespace v8_i18n {
class DateFormat {
public:
static void JSCreateDateTimeFormat(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Helper methods for various bindings.
// Unpacks date format object from corresponding JavaScript object.
static icu::SimpleDateFormat* UnpackDateFormat(
v8::Handle<v8::Object> obj);
// Release memory we allocated for the DateFormat once the JS object that
// holds the pointer gets garbage collected.
static void DeleteDateFormat(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
void* param);
// Formats date and returns corresponding string.
static void JSInternalFormat(const v8::FunctionCallbackInfo<v8::Value>& args);
// Parses date and returns corresponding Date object or undefined if parse
// failed.
static void JSInternalParse(const v8::FunctionCallbackInfo<v8::Value>& args);
private:
DateFormat();
};
} // namespace v8_i18n
#endif // V8_EXTENSIONS_I18N_DATE_FORMAT_H_

478
deps/v8/src/extensions/i18n/date-format.js

@ -0,0 +1,478 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
// ECMAScript 402 API implementation is broken into separate files for
// each service. The build system combines them together into one
// Intl namespace.
/**
* Returns a string that matches LDML representation of the options object.
*/
function toLDMLString(options) {
var getOption = getGetOption(options, 'dateformat');
var ldmlString = '';
var option = getOption('weekday', 'string', ['narrow', 'short', 'long']);
ldmlString += appendToLDMLString(
option, {narrow: 'EEEEE', short: 'EEE', long: 'EEEE'});
option = getOption('era', 'string', ['narrow', 'short', 'long']);
ldmlString += appendToLDMLString(
option, {narrow: 'GGGGG', short: 'GGG', long: 'GGGG'});
option = getOption('year', 'string', ['2-digit', 'numeric']);
ldmlString += appendToLDMLString(option, {'2-digit': 'yy', 'numeric': 'y'});
option = getOption('month', 'string',
['2-digit', 'numeric', 'narrow', 'short', 'long']);
ldmlString += appendToLDMLString(option, {'2-digit': 'MM', 'numeric': 'M',
'narrow': 'MMMMM', 'short': 'MMM', 'long': 'MMMM'});
option = getOption('day', 'string', ['2-digit', 'numeric']);
ldmlString += appendToLDMLString(
option, {'2-digit': 'dd', 'numeric': 'd'});
var hr12 = getOption('hour12', 'boolean');
option = getOption('hour', 'string', ['2-digit', 'numeric']);
if (hr12 === undefined) {
ldmlString += appendToLDMLString(option, {'2-digit': 'jj', 'numeric': 'j'});
} else if (hr12 === true) {
ldmlString += appendToLDMLString(option, {'2-digit': 'hh', 'numeric': 'h'});
} else {
ldmlString += appendToLDMLString(option, {'2-digit': 'HH', 'numeric': 'H'});
}
option = getOption('minute', 'string', ['2-digit', 'numeric']);
ldmlString += appendToLDMLString(option, {'2-digit': 'mm', 'numeric': 'm'});
option = getOption('second', 'string', ['2-digit', 'numeric']);
ldmlString += appendToLDMLString(option, {'2-digit': 'ss', 'numeric': 's'});
option = getOption('timeZoneName', 'string', ['short', 'long']);
ldmlString += appendToLDMLString(option, {short: 'v', long: 'vv'});
return ldmlString;
}
/**
* Returns either LDML equivalent of the current option or empty string.
*/
function appendToLDMLString(option, pairs) {
if (option !== undefined) {
return pairs[option];
} else {
return '';
}
}
/**
* Returns object that matches LDML representation of the date.
*/
function fromLDMLString(ldmlString) {
// First remove '' quoted text, so we lose 'Uhr' strings.
ldmlString = ldmlString.replace(QUOTED_STRING_RE, '');
var options = {};
var match = ldmlString.match(/E{3,5}/g);
options = appendToDateTimeObject(
options, 'weekday', match, {EEEEE: 'narrow', EEE: 'short', EEEE: 'long'});
match = ldmlString.match(/G{3,5}/g);
options = appendToDateTimeObject(
options, 'era', match, {GGGGG: 'narrow', GGG: 'short', GGGG: 'long'});
match = ldmlString.match(/y{1,2}/g);
options = appendToDateTimeObject(
options, 'year', match, {y: 'numeric', yy: '2-digit'});
match = ldmlString.match(/M{1,5}/g);
options = appendToDateTimeObject(options, 'month', match, {MM: '2-digit',
M: 'numeric', MMMMM: 'narrow', MMM: 'short', MMMM: 'long'});
// Sometimes we get L instead of M for month - standalone name.
match = ldmlString.match(/L{1,5}/g);
options = appendToDateTimeObject(options, 'month', match, {LL: '2-digit',
L: 'numeric', LLLLL: 'narrow', LLL: 'short', LLLL: 'long'});
match = ldmlString.match(/d{1,2}/g);
options = appendToDateTimeObject(
options, 'day', match, {d: 'numeric', dd: '2-digit'});
match = ldmlString.match(/h{1,2}/g);
if (match !== null) {
options['hour12'] = true;
}
options = appendToDateTimeObject(
options, 'hour', match, {h: 'numeric', hh: '2-digit'});
match = ldmlString.match(/H{1,2}/g);
if (match !== null) {
options['hour12'] = false;
}
options = appendToDateTimeObject(
options, 'hour', match, {H: 'numeric', HH: '2-digit'});
match = ldmlString.match(/m{1,2}/g);
options = appendToDateTimeObject(
options, 'minute', match, {m: 'numeric', mm: '2-digit'});
match = ldmlString.match(/s{1,2}/g);
options = appendToDateTimeObject(
options, 'second', match, {s: 'numeric', ss: '2-digit'});
match = ldmlString.match(/v{1,2}/g);
options = appendToDateTimeObject(
options, 'timeZoneName', match, {v: 'short', vv: 'long'});
return options;
}
function appendToDateTimeObject(options, option, match, pairs) {
if (match === null) {
if (!options.hasOwnProperty(option)) {
defineWEProperty(options, option, undefined);
}
return options;
}
var property = match[0];
defineWEProperty(options, option, pairs[property]);
return options;
}
/**
* Returns options with at least default values in it.
*/
function toDateTimeOptions(options, required, defaults) {
if (options === undefined) {
options = null;
} else {
options = toObject(options);
}
options = Object.apply(this, [options]);
var needsDefault = true;
if ((required === 'date' || required === 'any') &&
(options.weekday !== undefined || options.year !== undefined ||
options.month !== undefined || options.day !== undefined)) {
needsDefault = false;
}
if ((required === 'time' || required === 'any') &&
(options.hour !== undefined || options.minute !== undefined ||
options.second !== undefined)) {
needsDefault = false;
}
if (needsDefault && (defaults === 'date' || defaults === 'all')) {
Object.defineProperty(options, 'year', {value: 'numeric',
writable: true,
enumerable: true,
configurable: true});
Object.defineProperty(options, 'month', {value: 'numeric',
writable: true,
enumerable: true,
configurable: true});
Object.defineProperty(options, 'day', {value: 'numeric',
writable: true,
enumerable: true,
configurable: true});
}
if (needsDefault && (defaults === 'time' || defaults === 'all')) {
Object.defineProperty(options, 'hour', {value: 'numeric',
writable: true,
enumerable: true,
configurable: true});
Object.defineProperty(options, 'minute', {value: 'numeric',
writable: true,
enumerable: true,
configurable: true});
Object.defineProperty(options, 'second', {value: 'numeric',
writable: true,
enumerable: true,
configurable: true});
}
return options;
}
/**
* Initializes the given object so it's a valid DateTimeFormat instance.
* Useful for subclassing.
*/
function initializeDateTimeFormat(dateFormat, locales, options) {
native function NativeJSCreateDateTimeFormat();
if (dateFormat.hasOwnProperty('__initializedIntlObject')) {
throw new TypeError('Trying to re-initialize DateTimeFormat object.');
}
if (options === undefined) {
options = {};
}
var locale = resolveLocale('dateformat', locales, options);
options = toDateTimeOptions(options, 'any', 'date');
var getOption = getGetOption(options, 'dateformat');
// We implement only best fit algorithm, but still need to check
// if the formatMatcher values are in range.
var matcher = getOption('formatMatcher', 'string',
['basic', 'best fit'], 'best fit');
// Build LDML string for the skeleton that we pass to the formatter.
var ldmlString = toLDMLString(options);
// Filter out supported extension keys so we know what to put in resolved
// section later on.
// We need to pass calendar and number system to the method.
var tz = canonicalizeTimeZoneID(options.timeZone);
// ICU prefers options to be passed using -u- extension key/values, so
// we need to build that.
var internalOptions = {};
var extensionMap = parseExtension(locale.extension);
var extension = setOptions(options, extensionMap, DATETIME_FORMAT_KEY_MAP,
getOption, internalOptions);
var requestedLocale = locale.locale + extension;
var resolved = Object.defineProperties({}, {
calendar: {writable: true},
day: {writable: true},
era: {writable: true},
hour12: {writable: true},
hour: {writable: true},
locale: {writable: true},
minute: {writable: true},
month: {writable: true},
numberingSystem: {writable: true},
pattern: {writable: true},
requestedLocale: {value: requestedLocale, writable: true},
second: {writable: true},
timeZone: {writable: true},
timeZoneName: {writable: true},
tz: {value: tz, writable: true},
weekday: {writable: true},
year: {writable: true}
});
var formatter = NativeJSCreateDateTimeFormat(
requestedLocale, {skeleton: ldmlString, timeZone: tz}, resolved);
if (tz !== undefined && tz !== resolved.timeZone) {
throw new RangeError('Unsupported time zone specified ' + tz);
}
Object.defineProperty(dateFormat, 'formatter', {value: formatter});
Object.defineProperty(dateFormat, 'resolved', {value: resolved});
Object.defineProperty(dateFormat, '__initializedIntlObject',
{value: 'dateformat'});
return dateFormat;
}
/**
* Constructs Intl.DateTimeFormat object given optional locales and options
* parameters.
*
* @constructor
*/
%SetProperty(Intl, 'DateTimeFormat', function() {
var locales = arguments[0];
var options = arguments[1];
if (!this || this === Intl) {
// Constructor is called as a function.
return new Intl.DateTimeFormat(locales, options);
}
return initializeDateTimeFormat(toObject(this), locales, options);
},
ATTRIBUTES.DONT_ENUM
);
/**
* DateTimeFormat resolvedOptions method.
*/
%SetProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject !== 'dateformat') {
throw new TypeError('resolvedOptions method called on a non-object or ' +
'on a object that is not Intl.DateTimeFormat.');
}
var format = this;
var fromPattern = fromLDMLString(format.resolved.pattern);
var userCalendar = ICU_CALENDAR_MAP[format.resolved.calendar];
if (userCalendar === undefined) {
// Use ICU name if we don't have a match. It shouldn't happen, but
// it would be too strict to throw for this.
userCalendar = format.resolved.calendar;
}
var locale = getOptimalLanguageTag(format.resolved.requestedLocale,
format.resolved.locale);
var result = {
locale: locale,
numberingSystem: format.resolved.numberingSystem,
calendar: userCalendar,
timeZone: format.resolved.timeZone
};
addWECPropertyIfDefined(result, 'timeZoneName', fromPattern.timeZoneName);
addWECPropertyIfDefined(result, 'era', fromPattern.era);
addWECPropertyIfDefined(result, 'year', fromPattern.year);
addWECPropertyIfDefined(result, 'month', fromPattern.month);
addWECPropertyIfDefined(result, 'day', fromPattern.day);
addWECPropertyIfDefined(result, 'weekday', fromPattern.weekday);
addWECPropertyIfDefined(result, 'hour12', fromPattern.hour12);
addWECPropertyIfDefined(result, 'hour', fromPattern.hour);
addWECPropertyIfDefined(result, 'minute', fromPattern.minute);
addWECPropertyIfDefined(result, 'second', fromPattern.second);
return result;
},
ATTRIBUTES.DONT_ENUM
);
%FunctionSetName(Intl.DateTimeFormat.prototype.resolvedOptions,
'resolvedOptions');
%FunctionRemovePrototype(Intl.DateTimeFormat.prototype.resolvedOptions);
%SetNativeFlag(Intl.DateTimeFormat.prototype.resolvedOptions);
/**
* Returns the subset of the given locale list for which this locale list
* has a matching (possibly fallback) locale. Locales appear in the same
* order in the returned list as in the input list.
* Options are optional parameter.
*/
%SetProperty(Intl.DateTimeFormat, 'supportedLocalesOf', function(locales) {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
return supportedLocalesOf('dateformat', locales, arguments[1]);
},
ATTRIBUTES.DONT_ENUM
);
%FunctionSetName(Intl.DateTimeFormat.supportedLocalesOf, 'supportedLocalesOf');
%FunctionRemovePrototype(Intl.DateTimeFormat.supportedLocalesOf);
%SetNativeFlag(Intl.DateTimeFormat.supportedLocalesOf);
/**
* Returns a String value representing the result of calling ToNumber(date)
* according to the effective locale and the formatting options of this
* DateTimeFormat.
*/
function formatDate(formatter, dateValue) {
native function NativeJSInternalDateFormat();
var dateMs;
if (dateValue === undefined) {
dateMs = Date.now();
} else {
dateMs = Number(dateValue);
}
if (!isFinite(dateMs)) {
throw new RangeError('Provided date is not in valid range.');
}
return NativeJSInternalDateFormat(formatter.formatter, new Date(dateMs));
}
/**
* Returns a Date object representing the result of calling ToString(value)
* according to the effective locale and the formatting options of this
* DateTimeFormat.
* Returns undefined if date string cannot be parsed.
*/
function parseDate(formatter, value) {
native function NativeJSInternalDateParse();
return NativeJSInternalDateParse(formatter.formatter, String(value));
}
// 0 because date is optional argument.
addBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0);
addBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1);
/**
* Returns canonical Area/Location name, or throws an exception if the zone
* name is invalid IANA name.
*/
function canonicalizeTimeZoneID(tzID) {
// Skip undefined zones.
if (tzID === undefined) {
return tzID;
}
// Special case handling (UTC, GMT).
var upperID = tzID.toUpperCase();
if (upperID === 'UTC' || upperID === 'GMT' ||
upperID === 'ETC/UTC' || upperID === 'ETC/GMT') {
return 'UTC';
}
// We expect only _ and / beside ASCII letters.
// All inputs should conform to Area/Location from now on.
var match = TIMEZONE_NAME_CHECK_RE.exec(tzID);
if (match === null) {
throw new RangeError('Expected Area/Location for time zone, got ' + tzID);
}
var result = toTitleCaseWord(match[1]) + '/' + toTitleCaseWord(match[2]);
var i = 3;
while (match[i] !== undefined && i < match.length) {
result = result + '_' + toTitleCaseWord(match[i]);
i++;
}
return result;
}

40
deps/v8/src/extensions/i18n/footer.js

@ -0,0 +1,40 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
// ECMAScript 402 API implementation is broken into separate files for
// each service. The build system combines them together into one
// Intl namespace.
// Fix RegExp global state so we don't fail WebKit layout test:
// fast/js/regexp-caching.html
// It seems that 'g' or test() operations leave state changed.
var CLEANUP_RE = new RegExp('');
CLEANUP_RE.test('');
return Intl;
}());

168
deps/v8/src/extensions/i18n/globals.js

@ -0,0 +1,168 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
/**
* List of available services.
*/
var AVAILABLE_SERVICES = ['collator',
'numberformat',
'dateformat',
'breakiterator'];
/**
* Caches available locales for each service.
*/
var AVAILABLE_LOCALES = {
'collator': undefined,
'numberformat': undefined,
'dateformat': undefined,
'breakiterator': undefined
};
/**
* Caches default ICU locale.
*/
var DEFAULT_ICU_LOCALE = undefined;
/**
* Unicode extension regular expression.
*/
var UNICODE_EXTENSION_RE = new RegExp('-u(-[a-z0-9]{2,8})+', 'g');
/**
* Matches any Unicode extension.
*/
var ANY_EXTENSION_RE = new RegExp('-[a-z0-9]{1}-.*', 'g');
/**
* Replace quoted text (single quote, anything but the quote and quote again).
*/
var QUOTED_STRING_RE = new RegExp("'[^']+'", 'g');
/**
* Matches valid service name.
*/
var SERVICE_RE =
new RegExp('^(collator|numberformat|dateformat|breakiterator)$');
/**
* Validates a language tag against bcp47 spec.
* Actual value is assigned on first run.
*/
var LANGUAGE_TAG_RE = undefined;
/**
* Helps find duplicate variants in the language tag.
*/
var LANGUAGE_VARIANT_RE = undefined;
/**
* Helps find duplicate singletons in the language tag.
*/
var LANGUAGE_SINGLETON_RE = undefined;
/**
* Matches valid IANA time zone names.
*/
var TIMEZONE_NAME_CHECK_RE =
new RegExp('^([A-Za-z]+)/([A-Za-z]+)(?:_([A-Za-z]+))*$');
/**
* Maps ICU calendar names into LDML type.
*/
var ICU_CALENDAR_MAP = {
'gregorian': 'gregory',
'japanese': 'japanese',
'buddhist': 'buddhist',
'roc': 'roc',
'persian': 'persian',
'islamic-civil': 'islamicc',
'islamic': 'islamic',
'hebrew': 'hebrew',
'chinese': 'chinese',
'indian': 'indian',
'coptic': 'coptic',
'ethiopic': 'ethiopic',
'ethiopic-amete-alem': 'ethioaa'
};
/**
* Map of Unicode extensions to option properties, and their values and types,
* for a collator.
*/
var COLLATOR_KEY_MAP = {
'kn': {'property': 'numeric', 'type': 'boolean'},
'kf': {'property': 'caseFirst', 'type': 'string',
'values': ['false', 'lower', 'upper']}
};
/**
* Map of Unicode extensions to option properties, and their values and types,
* for a number format.
*/
var NUMBER_FORMAT_KEY_MAP = {
'nu': {'property': undefined, 'type': 'string'}
};
/**
* Map of Unicode extensions to option properties, and their values and types,
* for a date/time format.
*/
var DATETIME_FORMAT_KEY_MAP = {
'ca': {'property': undefined, 'type': 'string'},
'nu': {'property': undefined, 'type': 'string'}
};
/**
* Allowed -u-co- values. List taken from:
* http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml
*/
var ALLOWED_CO_VALUES = [
'big5han', 'dict', 'direct', 'ducet', 'gb2312', 'phonebk', 'phonetic',
'pinyin', 'reformed', 'searchjl', 'stroke', 'trad', 'unihan', 'zhuyin'
];
/**
* Object attributes (configurable, writable, enumerable).
* To combine attributes, OR them.
* Values/names are copied from v8/include/v8.h:PropertyAttribute
*/
var ATTRIBUTES = {
'NONE': 0,
'READ_ONLY': 1,
'DONT_ENUM': 2,
'DONT_DELETE': 4
};
/**
* Error message for when function object is created with new and it's not
* a constructor.
*/
var ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR =
'Function object that\'s not a constructor was created with new';

41
deps/v8/src/extensions/i18n/header.js

@ -0,0 +1,41 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
// ECMAScript 402 API implementation is broken into separate files for
// each service. The build system combines them together into one
// Intl namespace.
/**
* Intl object is a single object that has some named properties,
* all of which are constructors.
*/
var Intl = (function() {
'use strict';
var Intl = {};

116
deps/v8/src/extensions/i18n/i18n-extension.cc

@ -0,0 +1,116 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#include "i18n-extension.h"
#include "break-iterator.h"
#include "collator.h"
#include "date-format.h"
#include "locale.h"
#include "natives.h"
#include "number-format.h"
using v8::internal::I18NNatives;
namespace v8_i18n {
Extension::Extension()
: v8::Extension("v8/i18n",
reinterpret_cast<const char*>(
I18NNatives::GetScriptsSource().start()),
0,
0,
I18NNatives::GetScriptsSource().length()) {}
v8::Handle<v8::FunctionTemplate> Extension::GetNativeFunction(
v8::Handle<v8::String> name) {
// Standalone, helper methods.
if (name->Equals(v8::String::New("NativeJSCanonicalizeLanguageTag"))) {
return v8::FunctionTemplate::New(JSCanonicalizeLanguageTag);
} else if (name->Equals(v8::String::New("NativeJSAvailableLocalesOf"))) {
return v8::FunctionTemplate::New(JSAvailableLocalesOf);
} else if (name->Equals(v8::String::New("NativeJSGetDefaultICULocale"))) {
return v8::FunctionTemplate::New(JSGetDefaultICULocale);
} else if (name->Equals(v8::String::New("NativeJSGetLanguageTagVariants"))) {
return v8::FunctionTemplate::New(JSGetLanguageTagVariants);
}
// Date format and parse.
if (name->Equals(v8::String::New("NativeJSCreateDateTimeFormat"))) {
return v8::FunctionTemplate::New(DateFormat::JSCreateDateTimeFormat);
} else if (name->Equals(v8::String::New("NativeJSInternalDateFormat"))) {
return v8::FunctionTemplate::New(DateFormat::JSInternalFormat);
} else if (name->Equals(v8::String::New("NativeJSInternalDateParse"))) {
return v8::FunctionTemplate::New(DateFormat::JSInternalParse);
}
// Number format and parse.
if (name->Equals(v8::String::New("NativeJSCreateNumberFormat"))) {
return v8::FunctionTemplate::New(NumberFormat::JSCreateNumberFormat);
} else if (name->Equals(v8::String::New("NativeJSInternalNumberFormat"))) {
return v8::FunctionTemplate::New(NumberFormat::JSInternalFormat);
} else if (name->Equals(v8::String::New("NativeJSInternalNumberParse"))) {
return v8::FunctionTemplate::New(NumberFormat::JSInternalParse);
}
// Collator.
if (name->Equals(v8::String::New("NativeJSCreateCollator"))) {
return v8::FunctionTemplate::New(Collator::JSCreateCollator);
} else if (name->Equals(v8::String::New("NativeJSInternalCompare"))) {
return v8::FunctionTemplate::New(Collator::JSInternalCompare);
}
// Break iterator.
if (name->Equals(v8::String::New("NativeJSCreateBreakIterator"))) {
return v8::FunctionTemplate::New(BreakIterator::JSCreateBreakIterator);
} else if (name->Equals(v8::String::New("NativeJSBreakIteratorAdoptText"))) {
return v8::FunctionTemplate::New(
BreakIterator::JSInternalBreakIteratorAdoptText);
} else if (name->Equals(v8::String::New("NativeJSBreakIteratorFirst"))) {
return v8::FunctionTemplate::New(
BreakIterator::JSInternalBreakIteratorFirst);
} else if (name->Equals(v8::String::New("NativeJSBreakIteratorNext"))) {
return v8::FunctionTemplate::New(
BreakIterator::JSInternalBreakIteratorNext);
} else if (name->Equals(v8::String::New("NativeJSBreakIteratorCurrent"))) {
return v8::FunctionTemplate::New(
BreakIterator::JSInternalBreakIteratorCurrent);
} else if (name->Equals(v8::String::New("NativeJSBreakIteratorBreakType"))) {
return v8::FunctionTemplate::New(
BreakIterator::JSInternalBreakIteratorBreakType);
}
return v8::Handle<v8::FunctionTemplate>();
}
void Extension::Register() {
static Extension i18n_extension;
static v8::DeclareExtension extension_declaration(&i18n_extension);
}
} // namespace v8_i18n

51
deps/v8/src/extensions/i18n/i18n-extension.h

@ -0,0 +1,51 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#ifndef V8_EXTENSIONS_I18N_I18N_EXTENSION_H_
#define V8_EXTENSIONS_I18N_I18N_EXTENSION_H_
#include "v8.h"
namespace v8_i18n {
class Extension : public v8::Extension {
public:
Extension();
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
v8::Handle<v8::String> name);
static void Register();
private:
static Extension* extension_;
};
} // namespace v8_i18n
#endif // V8_EXTENSIONS_I18N_I18N_EXTENSION_H_

174
deps/v8/src/extensions/i18n/i18n-utils.cc

@ -0,0 +1,174 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#include "i18n-utils.h"
#include <string.h>
#include "unicode/unistr.h"
namespace v8_i18n {
// static
void Utils::StrNCopy(char* dest, int length, const char* src) {
if (!dest || !src) return;
strncpy(dest, src, length);
dest[length - 1] = '\0';
}
// static
bool Utils::V8StringToUnicodeString(const v8::Handle<v8::Value>& input,
icu::UnicodeString* output) {
v8::String::Utf8Value utf8_value(input);
if (*utf8_value == NULL) return false;
output->setTo(icu::UnicodeString::fromUTF8(*utf8_value));
return true;
}
// static
bool Utils::ExtractStringSetting(const v8::Handle<v8::Object>& settings,
const char* setting,
icu::UnicodeString* result) {
if (!setting || !result) return false;
v8::HandleScope handle_scope;
v8::TryCatch try_catch;
v8::Handle<v8::Value> value = settings->Get(v8::String::New(setting));
if (try_catch.HasCaught()) {
return false;
}
// No need to check if |value| is empty because it's taken care of
// by TryCatch above.
if (!value->IsUndefined() && !value->IsNull() && value->IsString()) {
return V8StringToUnicodeString(value, result);
}
return false;
}
// static
bool Utils::ExtractIntegerSetting(const v8::Handle<v8::Object>& settings,
const char* setting,
int32_t* result) {
if (!setting || !result) return false;
v8::HandleScope handle_scope;
v8::TryCatch try_catch;
v8::Handle<v8::Value> value = settings->Get(v8::String::New(setting));
if (try_catch.HasCaught()) {
return false;
}
// No need to check if |value| is empty because it's taken care of
// by TryCatch above.
if (!value->IsUndefined() && !value->IsNull() && value->IsNumber()) {
*result = static_cast<int32_t>(value->Int32Value());
return true;
}
return false;
}
// static
bool Utils::ExtractBooleanSetting(const v8::Handle<v8::Object>& settings,
const char* setting,
bool* result) {
if (!setting || !result) return false;
v8::HandleScope handle_scope;
v8::TryCatch try_catch;
v8::Handle<v8::Value> value = settings->Get(v8::String::New(setting));
if (try_catch.HasCaught()) {
return false;
}
// No need to check if |value| is empty because it's taken care of
// by TryCatch above.
if (!value->IsUndefined() && !value->IsNull() && value->IsBoolean()) {
*result = static_cast<bool>(value->BooleanValue());
return true;
}
return false;
}
// static
void Utils::AsciiToUChar(const char* source,
int32_t source_length,
UChar* target,
int32_t target_length) {
int32_t length =
source_length < target_length ? source_length : target_length;
if (length <= 0) {
return;
}
for (int32_t i = 0; i < length - 1; ++i) {
target[i] = static_cast<UChar>(source[i]);
}
target[length - 1] = 0x0u;
}
// static
// Chrome Linux doesn't like static initializers in class, so we create
// template on demand.
v8::Local<v8::ObjectTemplate> Utils::GetTemplate(v8::Isolate* isolate) {
static v8::Persistent<v8::ObjectTemplate> icu_template;
if (icu_template.IsEmpty()) {
v8::Local<v8::ObjectTemplate> raw_template(v8::ObjectTemplate::New());
// Set aside internal field for ICU class.
raw_template->SetInternalFieldCount(1);
icu_template.Reset(isolate, raw_template);
}
return v8::Local<v8::ObjectTemplate>::New(isolate, icu_template);
}
// static
// Chrome Linux doesn't like static initializers in class, so we create
// template on demand. This one has 2 internal fields.
v8::Local<v8::ObjectTemplate> Utils::GetTemplate2(v8::Isolate* isolate) {
static v8::Persistent<v8::ObjectTemplate> icu_template_2;
if (icu_template_2.IsEmpty()) {
v8::Local<v8::ObjectTemplate> raw_template(v8::ObjectTemplate::New());
// Set aside internal field for ICU class and additional data.
raw_template->SetInternalFieldCount(2);
icu_template_2.Reset(isolate, raw_template);
}
return v8::Local<v8::ObjectTemplate>::New(isolate, icu_template_2);
}
} // namespace v8_i18n

91
deps/v8/src/extensions/i18n/i18n-utils.h

@ -0,0 +1,91 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#ifndef V8_EXTENSIONS_I18N_SRC_UTILS_H_
#define V8_EXTENSIONS_I18N_SRC_UTILS_H_
#include "unicode/uversion.h"
#include "v8.h"
namespace U_ICU_NAMESPACE {
class UnicodeString;
}
namespace v8_i18n {
class Utils {
public:
// Safe string copy. Null terminates the destination. Copies at most
// (length - 1) bytes.
// We can't use snprintf since it's not supported on all relevant platforms.
// We can't use OS::SNPrintF, it's only for internal code.
static void StrNCopy(char* dest, int length, const char* src);
// Converts v8::String into UnicodeString. Returns false if input
// can't be converted into utf8.
static bool V8StringToUnicodeString(const v8::Handle<v8::Value>& input,
icu::UnicodeString* output);
// Extract a String setting named in |settings| and set it to |result|.
// Return true if it's specified. Otherwise, return false.
static bool ExtractStringSetting(const v8::Handle<v8::Object>& settings,
const char* setting,
icu::UnicodeString* result);
// Extract a Integer setting named in |settings| and set it to |result|.
// Return true if it's specified. Otherwise, return false.
static bool ExtractIntegerSetting(const v8::Handle<v8::Object>& settings,
const char* setting,
int32_t* result);
// Extract a Boolean setting named in |settings| and set it to |result|.
// Return true if it's specified. Otherwise, return false.
static bool ExtractBooleanSetting(const v8::Handle<v8::Object>& settings,
const char* setting,
bool* result);
// Converts ASCII array into UChar array.
// Target is always \0 terminated.
static void AsciiToUChar(const char* source,
int32_t source_length,
UChar* target,
int32_t target_length);
// Creates an ObjectTemplate with one internal field.
static v8::Local<v8::ObjectTemplate> GetTemplate(v8::Isolate* isolate);
// Creates an ObjectTemplate with two internal fields.
static v8::Local<v8::ObjectTemplate> GetTemplate2(v8::Isolate* isolate);
private:
Utils() {}
};
} // namespace v8_i18n
#endif // V8_EXTENSIONS_I18N_UTILS_H_

541
deps/v8/src/extensions/i18n/i18n-utils.js

@ -0,0 +1,541 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
// ECMAScript 402 API implementation is broken into separate files for
// each service. The build system combines them together into one
// Intl namespace.
/**
* Adds bound method to the prototype of the given object.
*/
function addBoundMethod(obj, methodName, implementation, length) {
function getter() {
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject === undefined) {
throw new TypeError('Method ' + methodName + ' called on a ' +
'non-object or on a wrong type of object.');
}
var internalName = '__bound' + methodName + '__';
if (this[internalName] === undefined) {
var that = this;
var boundMethod;
if (length === undefined || length === 2) {
boundMethod = function(x, y) {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
return implementation(that, x, y);
}
} else if (length === 1) {
boundMethod = function(x) {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
return implementation(that, x);
}
} else {
boundMethod = function() {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
// DateTimeFormat.format needs to be 0 arg method, but can stil
// receive optional dateValue param. If one was provided, pass it
// along.
if (arguments.length > 0) {
return implementation(that, arguments[0]);
} else {
return implementation(that);
}
}
}
%FunctionSetName(boundMethod, internalName);
%FunctionRemovePrototype(boundMethod);
%SetNativeFlag(boundMethod);
this[internalName] = boundMethod;
}
return this[internalName];
}
%FunctionSetName(getter, methodName);
%FunctionRemovePrototype(getter);
%SetNativeFlag(getter);
Object.defineProperty(obj.prototype, methodName, {
get: getter,
enumerable: false,
configurable: true
});
}
/**
* Returns an intersection of locales and service supported locales.
* Parameter locales is treated as a priority list.
*/
function supportedLocalesOf(service, locales, options) {
if (service.match(SERVICE_RE) === null) {
throw new Error('Internal error, wrong service type: ' + service);
}
// Provide defaults if matcher was not specified.
if (options === undefined) {
options = {};
} else {
options = toObject(options);
}
var matcher = options.localeMatcher;
if (matcher !== undefined) {
matcher = String(matcher);
if (matcher !== 'lookup' && matcher !== 'best fit') {
throw new RangeError('Illegal value for localeMatcher:' + matcher);
}
} else {
matcher = 'best fit';
}
var requestedLocales = initializeLocaleList(locales);
// Cache these, they don't ever change per service.
if (AVAILABLE_LOCALES[service] === undefined) {
AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service);
}
// Use either best fit or lookup algorithm to match locales.
if (matcher === 'best fit') {
return initializeLocaleList(bestFitSupportedLocalesOf(
requestedLocales, AVAILABLE_LOCALES[service]));
}
return initializeLocaleList(lookupSupportedLocalesOf(
requestedLocales, AVAILABLE_LOCALES[service]));
}
/**
* Returns the subset of the provided BCP 47 language priority list for which
* this service has a matching locale when using the BCP 47 Lookup algorithm.
* Locales appear in the same order in the returned list as in the input list.
*/
function lookupSupportedLocalesOf(requestedLocales, availableLocales) {
var matchedLocales = [];
for (var i = 0; i < requestedLocales.length; ++i) {
// Remove -u- extension.
var locale = requestedLocales[i].replace(UNICODE_EXTENSION_RE, '');
do {
if (availableLocales[locale] !== undefined) {
// Push requested locale not the resolved one.
matchedLocales.push(requestedLocales[i]);
break;
}
// Truncate locale if possible, if not break.
var pos = locale.lastIndexOf('-');
if (pos === -1) {
break;
}
locale = locale.substring(0, pos);
} while (true);
}
return matchedLocales;
}
/**
* Returns the subset of the provided BCP 47 language priority list for which
* this service has a matching locale when using the implementation
* dependent algorithm.
* Locales appear in the same order in the returned list as in the input list.
*/
function bestFitSupportedLocalesOf(requestedLocales, availableLocales) {
// TODO(cira): implement better best fit algorithm.
return lookupSupportedLocalesOf(requestedLocales, availableLocales);
}
/**
* Returns a getOption function that extracts property value for given
* options object. If property is missing it returns defaultValue. If value
* is out of range for that property it throws RangeError.
*/
function getGetOption(options, caller) {
if (options === undefined) {
throw new Error('Internal ' + caller + ' error. ' +
'Default options are missing.');
}
var getOption = function getOption(property, type, values, defaultValue) {
if (options[property] !== undefined) {
var value = options[property];
switch (type) {
case 'boolean':
value = Boolean(value);
break;
case 'string':
value = String(value);
break;
case 'number':
value = Number(value);
break;
default:
throw new Error('Internal error. Wrong value type.');
}
if (values !== undefined && values.indexOf(value) === -1) {
throw new RangeError('Value ' + value + ' out of range for ' + caller +
' options property ' + property);
}
return value;
}
return defaultValue;
}
return getOption;
}
/**
* Compares a BCP 47 language priority list requestedLocales against the locales
* in availableLocales and determines the best available language to meet the
* request. Two algorithms are available to match the locales: the Lookup
* algorithm described in RFC 4647 section 3.4, and an implementation dependent
* best-fit algorithm. Independent of the locale matching algorithm, options
* specified through Unicode locale extension sequences are negotiated
* separately, taking the caller's relevant extension keys and locale data as
* well as client-provided options into consideration. Returns an object with
* a locale property whose value is the language tag of the selected locale,
* and properties for each key in relevantExtensionKeys providing the selected
* value for that key.
*/
function resolveLocale(service, requestedLocales, options) {
requestedLocales = initializeLocaleList(requestedLocales);
var getOption = getGetOption(options, service);
var matcher = getOption('localeMatcher', 'string',
['lookup', 'best fit'], 'best fit');
var resolved;
if (matcher === 'lookup') {
resolved = lookupMatcher(service, requestedLocales);
} else {
resolved = bestFitMatcher(service, requestedLocales);
}
return resolved;
}
/**
* Returns best matched supported locale and extension info using basic
* lookup algorithm.
*/
function lookupMatcher(service, requestedLocales) {
native function NativeJSGetDefaultICULocale();
if (service.match(SERVICE_RE) === null) {
throw new Error('Internal error, wrong service type: ' + service);
}
// Cache these, they don't ever change per service.
if (AVAILABLE_LOCALES[service] === undefined) {
AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service);
}
for (var i = 0; i < requestedLocales.length; ++i) {
// Remove all extensions.
var locale = requestedLocales[i].replace(ANY_EXTENSION_RE, '');
do {
if (AVAILABLE_LOCALES[service][locale] !== undefined) {
// Return the resolved locale and extension.
var extensionMatch = requestedLocales[i].match(UNICODE_EXTENSION_RE);
var extension = (extensionMatch === null) ? '' : extensionMatch[0];
return {'locale': locale, 'extension': extension, 'position': i};
}
// Truncate locale if possible.
var pos = locale.lastIndexOf('-');
if (pos === -1) {
break;
}
locale = locale.substring(0, pos);
} while (true);
}
// Didn't find a match, return default.
if (DEFAULT_ICU_LOCALE === undefined) {
DEFAULT_ICU_LOCALE = NativeJSGetDefaultICULocale();
}
return {'locale': DEFAULT_ICU_LOCALE, 'extension': '', 'position': -1};
}
/**
* Returns best matched supported locale and extension info using
* implementation dependend algorithm.
*/
function bestFitMatcher(service, requestedLocales) {
// TODO(cira): implement better best fit algorithm.
return lookupMatcher(service, requestedLocales);
}
/**
* Parses Unicode extension into key - value map.
* Returns empty object if the extension string is invalid.
* We are not concerned with the validity of the values at this point.
*/
function parseExtension(extension) {
var extensionSplit = extension.split('-');
// Assume ['', 'u', ...] input, but don't throw.
if (extensionSplit.length <= 2 ||
(extensionSplit[0] !== '' && extensionSplit[1] !== 'u')) {
return {};
}
// Key is {2}alphanum, value is {3,8}alphanum.
// Some keys may not have explicit values (booleans).
var extensionMap = {};
var previousKey = undefined;
for (var i = 2; i < extensionSplit.length; ++i) {
var length = extensionSplit[i].length;
var element = extensionSplit[i];
if (length === 2) {
extensionMap[element] = undefined;
previousKey = element;
} else if (length >= 3 && length <=8 && previousKey !== undefined) {
extensionMap[previousKey] = element;
previousKey = undefined;
} else {
// There is a value that's too long, or that doesn't have a key.
return {};
}
}
return extensionMap;
}
/**
* Converts parameter to an Object if possible.
*/
function toObject(value) {
if (value === undefined || value === null) {
throw new TypeError('Value cannot be converted to an Object.');
}
return Object(value);
}
/**
* Populates internalOptions object with boolean key-value pairs
* from extensionMap and options.
* Returns filtered extension (number and date format constructors use
* Unicode extensions for passing parameters to ICU).
* It's used for extension-option pairs only, e.g. kn-normalization, but not
* for 'sensitivity' since it doesn't have extension equivalent.
* Extensions like nu and ca don't have options equivalent, so we place
* undefined in the map.property to denote that.
*/
function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
var extension = '';
var updateExtension = function updateExtension(key, value) {
return '-' + key + '-' + String(value);
}
var updateProperty = function updateProperty(property, type, value) {
if (type === 'boolean' && (typeof value === 'string')) {
value = (value === 'true') ? true : false;
}
if (property !== undefined) {
defineWEProperty(outOptions, property, value);
}
}
for (var key in keyValues) {
if (keyValues.hasOwnProperty(key)) {
var value = undefined;
var map = keyValues[key];
if (map.property !== undefined) {
// This may return true if user specifies numeric: 'false', since
// Boolean('nonempty') === true.
value = getOption(map.property, map.type, map.values);
}
if (value !== undefined) {
updateProperty(map.property, map.type, value);
extension += updateExtension(key, value);
continue;
}
// User options didn't have it, check Unicode extension.
// Here we want to convert strings 'true', 'false' into proper Boolean
// values (not a user error).
if (extensionMap.hasOwnProperty(key)) {
value = extensionMap[key];
if (value !== undefined) {
updateProperty(map.property, map.type, value);
extension += updateExtension(key, value);
} else if (map.type === 'boolean') {
// Boolean keys are allowed not to have values in Unicode extension.
// Those default to true.
updateProperty(map.property, map.type, true);
extension += updateExtension(key, true);
}
}
}
}
return extension === ''? '' : '-u' + extension;
}
/**
* Converts all OwnProperties into
* configurable: false, writable: false, enumerable: true.
*/
function freezeArray(array) {
array.forEach(function(element, index) {
Object.defineProperty(array, index, {value: element,
configurable: false,
writable: false,
enumerable: true});
});
Object.defineProperty(array, 'length', {value: array.length,
writable: false});
return array;
}
/**
* It's sometimes desireable to leave user requested locale instead of ICU
* supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter
* one, if that was what user requested).
* This function returns user specified tag if its maximized form matches ICU
* resolved locale. If not we return ICU result.
*/
function getOptimalLanguageTag(original, resolved) {
// Returns Array<Object>, where each object has maximized and base properties.
// Maximized: zh -> zh-Hans-CN
// Base: zh-CN-u-ca-gregory -> zh-CN
native function NativeJSGetLanguageTagVariants();
// Take care of grandfathered or simple cases.
if (original === resolved) {
return original;
}
var locales = NativeJSGetLanguageTagVariants([original, resolved]);
if (locales[0].maximized !== locales[1].maximized) {
return resolved;
}
// Preserve extensions of resolved locale, but swap base tags with original.
var resolvedBase = new RegExp('^' + locales[1].base);
return resolved.replace(resolvedBase, locales[0].base);
}
/**
* Returns an Object that contains all of supported locales for a given
* service.
* In addition to the supported locales we add xx-ZZ locale for each xx-Yyyy-ZZ
* that is supported. This is required by the spec.
*/
function getAvailableLocalesOf(service) {
native function NativeJSAvailableLocalesOf();
var available = NativeJSAvailableLocalesOf(service);
for (var i in available) {
if (available.hasOwnProperty(i)) {
var parts = i.match(/^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/);
if (parts !== null) {
// Build xx-ZZ. We don't care about the actual value,
// as long it's not undefined.
available[parts[1] + '-' + parts[3]] = null;
}
}
}
return available;
}
/**
* Defines a property and sets writable and enumerable to true.
* Configurable is false by default.
*/
function defineWEProperty(object, property, value) {
Object.defineProperty(object, property,
{value: value, writable: true, enumerable: true});
}
/**
* Adds property to an object if the value is not undefined.
* Sets configurable descriptor to false.
*/
function addWEPropertyIfDefined(object, property, value) {
if (value !== undefined) {
defineWEProperty(object, property, value);
}
}
/**
* Defines a property and sets writable, enumerable and configurable to true.
*/
function defineWECProperty(object, property, value) {
Object.defineProperty(object, property,
{value: value,
writable: true,
enumerable: true,
configurable: true});
}
/**
* Adds property to an object if the value is not undefined.
* Sets all descriptors to true.
*/
function addWECPropertyIfDefined(object, property, value) {
if (value !== undefined) {
defineWECProperty(object, property, value);
}
}
/**
* Returns titlecased word, aMeRricA -> America.
*/
function toTitleCaseWord(word) {
return word.substr(0, 1).toUpperCase() + word.substr(1).toLowerCase();
}

248
deps/v8/src/extensions/i18n/locale.cc

@ -0,0 +1,248 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#include "locale.h"
#include <string.h>
#include "unicode/brkiter.h"
#include "unicode/coll.h"
#include "unicode/datefmt.h"
#include "unicode/numfmt.h"
#include "unicode/uloc.h"
#include "unicode/uversion.h"
namespace v8_i18n {
void JSCanonicalizeLanguageTag(
const v8::FunctionCallbackInfo<v8::Value>& args) {
// Expect locale id which is a string.
if (args.Length() != 1 || !args[0]->IsString()) {
v8::ThrowException(v8::Exception::SyntaxError(
v8::String::New("Locale identifier, as a string, is required.")));
return;
}
UErrorCode error = U_ZERO_ERROR;
char icu_result[ULOC_FULLNAME_CAPACITY];
int icu_length = 0;
// Return value which denotes invalid language tag.
const char* const kInvalidTag = "invalid-tag";
v8::String::AsciiValue locale_id(args[0]->ToString());
if (*locale_id == NULL) {
args.GetReturnValue().Set(v8::String::New(kInvalidTag));
return;
}
uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
&icu_length, &error);
if (U_FAILURE(error) || icu_length == 0) {
args.GetReturnValue().Set(v8::String::New(kInvalidTag));
return;
}
char result[ULOC_FULLNAME_CAPACITY];
// Force strict BCP47 rules.
uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
if (U_FAILURE(error)) {
args.GetReturnValue().Set(v8::String::New(kInvalidTag));
return;
}
args.GetReturnValue().Set(v8::String::New(result));
}
void JSAvailableLocalesOf(const v8::FunctionCallbackInfo<v8::Value>& args) {
// Expect service name which is a string.
if (args.Length() != 1 || !args[0]->IsString()) {
v8::ThrowException(v8::Exception::SyntaxError(
v8::String::New("Service identifier, as a string, is required.")));
return;
}
const icu::Locale* available_locales = NULL;
int32_t count = 0;
v8::String::AsciiValue service(args[0]->ToString());
if (strcmp(*service, "collator") == 0) {
available_locales = icu::Collator::getAvailableLocales(count);
} else if (strcmp(*service, "numberformat") == 0) {
available_locales = icu::NumberFormat::getAvailableLocales(count);
} else if (strcmp(*service, "dateformat") == 0) {
available_locales = icu::DateFormat::getAvailableLocales(count);
} else if (strcmp(*service, "breakiterator") == 0) {
available_locales = icu::BreakIterator::getAvailableLocales(count);
}
v8::TryCatch try_catch;
UErrorCode error = U_ZERO_ERROR;
char result[ULOC_FULLNAME_CAPACITY];
v8::Handle<v8::Object> locales = v8::Object::New();
for (int32_t i = 0; i < count; ++i) {
const char* icu_name = available_locales[i].getName();
error = U_ZERO_ERROR;
// No need to force strict BCP47 rules.
uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
if (U_FAILURE(error)) {
// This shouldn't happen, but lets not break the user.
continue;
}
// Index is just a dummy value for the property value.
locales->Set(v8::String::New(result), v8::Integer::New(i));
if (try_catch.HasCaught()) {
// Ignore error, but stop processing and return.
break;
}
}
args.GetReturnValue().Set(locales);
}
void JSGetDefaultICULocale(const v8::FunctionCallbackInfo<v8::Value>& args) {
icu::Locale default_locale;
// Set the locale
char result[ULOC_FULLNAME_CAPACITY];
UErrorCode status = U_ZERO_ERROR;
uloc_toLanguageTag(
default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
if (U_SUCCESS(status)) {
args.GetReturnValue().Set(v8::String::New(result));
return;
}
args.GetReturnValue().Set(v8::String::New("und"));
}
void JSGetLanguageTagVariants(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::TryCatch try_catch;
// Expect an array of strings.
if (args.Length() != 1 || !args[0]->IsArray()) {
v8::ThrowException(v8::Exception::SyntaxError(
v8::String::New("Internal error. Expected Array<String>.")));
return;
}
v8::Local<v8::Array> input = v8::Local<v8::Array>::Cast(args[0]);
v8::Handle<v8::Array> output = v8::Array::New(input->Length());
for (unsigned int i = 0; i < input->Length(); ++i) {
v8::Local<v8::Value> locale_id = input->Get(i);
if (try_catch.HasCaught()) {
break;
}
if (!locale_id->IsString()) {
v8::ThrowException(v8::Exception::SyntaxError(
v8::String::New("Internal error. Array element is missing "
"or it isn't a string.")));
return;
}
v8::String::AsciiValue ascii_locale_id(locale_id);
if (*ascii_locale_id == NULL) {
v8::ThrowException(v8::Exception::SyntaxError(
v8::String::New("Internal error. Non-ASCII locale identifier.")));
return;
}
UErrorCode error = U_ZERO_ERROR;
// Convert from BCP47 to ICU format.
// de-DE-u-co-phonebk -> de_DE@collation=phonebook
char icu_locale[ULOC_FULLNAME_CAPACITY];
int icu_locale_length = 0;
uloc_forLanguageTag(*ascii_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
&icu_locale_length, &error);
if (U_FAILURE(error) || icu_locale_length == 0) {
v8::ThrowException(v8::Exception::SyntaxError(
v8::String::New("Internal error. Failed to convert locale to ICU.")));
return;
}
// Maximize the locale.
// de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
char icu_max_locale[ULOC_FULLNAME_CAPACITY];
uloc_addLikelySubtags(
icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error);
// Remove extensions from maximized locale.
// de_Latn_DE@collation=phonebook -> de_Latn_DE
char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
uloc_getBaseName(
icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error);
// Get original name without extensions.
// de_DE@collation=phonebook -> de_DE
char icu_base_locale[ULOC_FULLNAME_CAPACITY];
uloc_getBaseName(
icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error);
// Convert from ICU locale format to BCP47 format.
// de_Latn_DE -> de-Latn-DE
char base_max_locale[ULOC_FULLNAME_CAPACITY];
uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
ULOC_FULLNAME_CAPACITY, FALSE, &error);
// de_DE -> de-DE
char base_locale[ULOC_FULLNAME_CAPACITY];
uloc_toLanguageTag(
icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error);
if (U_FAILURE(error)) {
v8::ThrowException(v8::Exception::SyntaxError(
v8::String::New("Internal error. Couldn't generate maximized "
"or base locale.")));
return;
}
v8::Handle<v8::Object> result = v8::Object::New();
result->Set(v8::String::New("maximized"), v8::String::New(base_max_locale));
result->Set(v8::String::New("base"), v8::String::New(base_locale));
if (try_catch.HasCaught()) {
break;
}
output->Set(i, result);
if (try_catch.HasCaught()) {
break;
}
}
args.GetReturnValue().Set(output);
}
} // namespace v8_i18n

56
deps/v8/src/extensions/i18n/locale.h

@ -0,0 +1,56 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#ifndef V8_EXTENSIONS_I18N_SRC_LOCALE_H_
#define V8_EXTENSIONS_I18N_SRC_LOCALE_H_
#include "unicode/uversion.h"
#include "v8.h"
namespace v8_i18n {
// Canonicalizes the BCP47 language tag using BCP47 rules.
// Returns 'invalid-tag' in case input was not well formed.
void JSCanonicalizeLanguageTag(const v8::FunctionCallbackInfo<v8::Value>& args);
// Returns a list of available locales for collator, date or number formatter.
void JSAvailableLocalesOf(const v8::FunctionCallbackInfo<v8::Value>& args);
// Returns default ICU locale.
void JSGetDefaultICULocale(const v8::FunctionCallbackInfo<v8::Value>& args);
// Returns an array of objects, that have maximized and base names of inputs.
// Unicode extensions are dropped from both.
// Input: ['zh-TW-u-nu-thai', 'sr']
// Output: [{maximized: 'zh-Hant-TW', base: 'zh-TW'},
// {maximized: 'sr-Cyrl-RS', base: 'sr'}]
void JSGetLanguageTagVariants(const v8::FunctionCallbackInfo<v8::Value>& args);
} // namespace v8_i18n
#endif // V8_EXTENSIONS_I18N_LOCALE_H_

192
deps/v8/src/extensions/i18n/locale.js

@ -0,0 +1,192 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
// ECMAScript 402 API implementation is broken into separate files for
// each service. The build system combines them together into one
// Intl namespace.
/**
* Canonicalizes the language tag, or throws in case the tag is invalid.
*/
function canonicalizeLanguageTag(localeID) {
native function NativeJSCanonicalizeLanguageTag();
// null is typeof 'object' so we have to do extra check.
if (typeof localeID !== 'string' && typeof localeID !== 'object' ||
localeID === null) {
throw new TypeError('Language ID should be string or object.');
}
var localeString = String(localeID);
if (isValidLanguageTag(localeString) === false) {
throw new RangeError('Invalid language tag: ' + localeString);
}
// This call will strip -kn but not -kn-true extensions.
// ICU bug filled - http://bugs.icu-project.org/trac/ticket/9265.
// TODO(cira): check if -u-kn-true-kc-true-kh-true still throws after
// upgrade to ICU 4.9.
var tag = NativeJSCanonicalizeLanguageTag(localeString);
if (tag === 'invalid-tag') {
throw new RangeError('Invalid language tag: ' + localeString);
}
return tag;
}
/**
* Returns an array where all locales are canonicalized and duplicates removed.
* Throws on locales that are not well formed BCP47 tags.
*/
function initializeLocaleList(locales) {
var seen = [];
if (locales === undefined) {
// Constructor is called without arguments.
seen = [];
} else {
// We allow single string localeID.
if (typeof locales === 'string') {
seen.push(canonicalizeLanguageTag(locales));
return freezeArray(seen);
}
var o = toObject(locales);
// Converts it to UInt32 (>>> is shr on 32bit integers).
var len = o.length >>> 0;
for (var k = 0; k < len; k++) {
if (k in o) {
var value = o[k];
var tag = canonicalizeLanguageTag(value);
if (seen.indexOf(tag) === -1) {
seen.push(tag);
}
}
}
}
return freezeArray(seen);
}
/**
* Validates the language tag. Section 2.2.9 of the bcp47 spec
* defines a valid tag.
*
* ICU is too permissible and lets invalid tags, like
* hant-cmn-cn, through.
*
* Returns false if the language tag is invalid.
*/
function isValidLanguageTag(locale) {
// Check if it's well-formed, including grandfadered tags.
if (LANGUAGE_TAG_RE.test(locale) === false) {
return false;
}
// Just return if it's a x- form. It's all private.
if (locale.indexOf('x-') === 0) {
return true;
}
// Check if there are any duplicate variants or singletons (extensions).
// Remove private use section.
locale = locale.split(/-x-/)[0];
// Skip language since it can match variant regex, so we start from 1.
// We are matching i-klingon here, but that's ok, since i-klingon-klingon
// is not valid and would fail LANGUAGE_TAG_RE test.
var variants = [];
var extensions = [];
var parts = locale.split(/-/);
for (var i = 1; i < parts.length; i++) {
var value = parts[i];
if (LANGUAGE_VARIANT_RE.test(value) === true && extensions.length === 0) {
if (variants.indexOf(value) === -1) {
variants.push(value);
} else {
return false;
}
}
if (LANGUAGE_SINGLETON_RE.test(value) === true) {
if (extensions.indexOf(value) === -1) {
extensions.push(value);
} else {
return false;
}
}
}
return true;
}
/**
* Builds a regular expresion that validates the language tag
* against bcp47 spec.
* Uses http://tools.ietf.org/html/bcp47, section 2.1, ABNF.
* Runs on load and initializes the global REs.
*/
(function() {
var alpha = '[a-zA-Z]';
var digit = '[0-9]';
var alphanum = '(' + alpha + '|' + digit + ')';
var regular = '(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|' +
'zh-min|zh-min-nan|zh-xiang)';
var irregular = '(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|' +
'i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|' +
'i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)';
var grandfathered = '(' + irregular + '|' + regular + ')';
var privateUse = '(x(-' + alphanum + '{1,8})+)';
var singleton = '(' + digit + '|[A-WY-Za-wy-z])';
LANGUAGE_SINGLETON_RE = new RegExp('^' + singleton + '$', 'i');
var extension = '(' + singleton + '(-' + alphanum + '{2,8})+)';
var variant = '(' + alphanum + '{5,8}|(' + digit + alphanum + '{3}))';
LANGUAGE_VARIANT_RE = new RegExp('^' + variant + '$', 'i');
var region = '(' + alpha + '{2}|' + digit + '{3})';
var script = '(' + alpha + '{4})';
var extLang = '(' + alpha + '{3}(-' + alpha + '{3}){0,2})';
var language = '(' + alpha + '{2,3}(-' + extLang + ')?|' + alpha + '{4}|' +
alpha + '{5,8})';
var langTag = language + '(-' + script + ')?(-' + region + ')?(-' +
variant + ')*(-' + extension + ')*(-' + privateUse + ')?';
var languageTag =
'^(' + langTag + '|' + privateUse + '|' + grandfathered + ')$';
LANGUAGE_TAG_RE = new RegExp(languageTag, 'i');
})();

418
deps/v8/src/extensions/i18n/number-format.cc

@ -0,0 +1,418 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#include "number-format.h"
#include <string.h>
#include "i18n-utils.h"
#include "unicode/curramt.h"
#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
#include "unicode/locid.h"
#include "unicode/numfmt.h"
#include "unicode/numsys.h"
#include "unicode/uchar.h"
#include "unicode/ucurr.h"
#include "unicode/unum.h"
#include "unicode/uversion.h"
namespace v8_i18n {
static icu::DecimalFormat* InitializeNumberFormat(v8::Handle<v8::String>,
v8::Handle<v8::Object>,
v8::Handle<v8::Object>);
static icu::DecimalFormat* CreateICUNumberFormat(const icu::Locale&,
v8::Handle<v8::Object>);
static void SetResolvedSettings(const icu::Locale&,
icu::DecimalFormat*,
v8::Handle<v8::Object>);
icu::DecimalFormat* NumberFormat::UnpackNumberFormat(
v8::Handle<v8::Object> obj) {
v8::HandleScope handle_scope;
// v8::ObjectTemplate doesn't have HasInstance method so we can't check
// if obj is an instance of NumberFormat class. We'll check for a property
// that has to be in the object. The same applies to other services, like
// Collator and DateTimeFormat.
if (obj->HasOwnProperty(v8::String::New("numberFormat"))) {
return static_cast<icu::DecimalFormat*>(
obj->GetAlignedPointerFromInternalField(0));
}
return NULL;
}
void NumberFormat::DeleteNumberFormat(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
void* param) {
// First delete the hidden C++ object.
// Unpacking should never return NULL here. That would only happen if
// this method is used as the weak callback for persistent handles not
// pointing to a date time formatter.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Object> handle = v8::Local<v8::Object>::New(isolate, *object);
delete UnpackNumberFormat(handle);
// Then dispose of the persistent handle to JS object.
object->Dispose(isolate);
}
void NumberFormat::JSInternalFormat(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsNumber()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Formatter and numeric value have to be specified.")));
return;
}
icu::DecimalFormat* number_format = UnpackNumberFormat(args[0]->ToObject());
if (!number_format) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("NumberFormat method called on an object "
"that is not a NumberFormat.")));
return;
}
// ICU will handle actual NaN value properly and return NaN string.
icu::UnicodeString result;
number_format->format(args[1]->NumberValue(), result);
args.GetReturnValue().Set(v8::String::New(
reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()));
}
void NumberFormat::JSInternalParse(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsString()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Formatter and string have to be specified.")));
return;
}
icu::DecimalFormat* number_format = UnpackNumberFormat(args[0]->ToObject());
if (!number_format) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("NumberFormat method called on an object "
"that is not a NumberFormat.")));
return;
}
// ICU will handle actual NaN value properly and return NaN string.
icu::UnicodeString string_number;
if (!Utils::V8StringToUnicodeString(args[1]->ToString(), &string_number)) {
string_number = "";
}
UErrorCode status = U_ZERO_ERROR;
icu::Formattable result;
// ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
// to be part of Chrome.
// TODO(cira): Include currency parsing code using parseCurrency call.
// We need to check if the formatter parses all currencies or only the
// one it was constructed with (it will impact the API - how to return ISO
// code and the value).
number_format->parse(string_number, result, status);
if (U_FAILURE(status)) {
return;
}
switch (result.getType()) {
case icu::Formattable::kDouble:
args.GetReturnValue().Set(result.getDouble());
return;
case icu::Formattable::kLong:
args.GetReturnValue().Set(v8::Number::New(result.getLong()));
return;
case icu::Formattable::kInt64:
args.GetReturnValue().Set(v8::Number::New(result.getInt64()));
return;
default:
return;
}
}
void NumberFormat::JSCreateNumberFormat(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 3 ||
!args[0]->IsString() ||
!args[1]->IsObject() ||
!args[2]->IsObject()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Internal error, wrong parameters.")));
return;
}
v8::Isolate* isolate = args.GetIsolate();
v8::Local<v8::ObjectTemplate> number_format_template =
Utils::GetTemplate(isolate);
// Create an empty object wrapper.
v8::Local<v8::Object> local_object = number_format_template->NewInstance();
// But the handle shouldn't be empty.
// That can happen if there was a stack overflow when creating the object.
if (local_object.IsEmpty()) {
args.GetReturnValue().Set(local_object);
return;
}
// Set number formatter as internal field of the resulting JS object.
icu::DecimalFormat* number_format = InitializeNumberFormat(
args[0]->ToString(), args[1]->ToObject(), args[2]->ToObject());
if (!number_format) {
v8::ThrowException(v8::Exception::Error(v8::String::New(
"Internal error. Couldn't create ICU number formatter.")));
return;
} else {
local_object->SetAlignedPointerInInternalField(0, number_format);
v8::TryCatch try_catch;
local_object->Set(v8::String::New("numberFormat"),
v8::String::New("valid"));
if (try_catch.HasCaught()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Internal error, couldn't set property.")));
return;
}
}
v8::Persistent<v8::Object> wrapper(isolate, local_object);
// Make object handle weak so we can delete iterator once GC kicks in.
wrapper.MakeWeak<void>(NULL, &DeleteNumberFormat);
args.GetReturnValue().Set(wrapper);
wrapper.ClearAndLeak();
}
static icu::DecimalFormat* InitializeNumberFormat(
v8::Handle<v8::String> locale,
v8::Handle<v8::Object> options,
v8::Handle<v8::Object> resolved) {
// Convert BCP47 into ICU locale format.
UErrorCode status = U_ZERO_ERROR;
icu::Locale icu_locale;
char icu_result[ULOC_FULLNAME_CAPACITY];
int icu_length = 0;
v8::String::AsciiValue bcp47_locale(locale);
if (bcp47_locale.length() != 0) {
uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
&icu_length, &status);
if (U_FAILURE(status) || icu_length == 0) {
return NULL;
}
icu_locale = icu::Locale(icu_result);
}
icu::DecimalFormat* number_format =
CreateICUNumberFormat(icu_locale, options);
if (!number_format) {
// Remove extensions and try again.
icu::Locale no_extension_locale(icu_locale.getBaseName());
number_format = CreateICUNumberFormat(no_extension_locale, options);
// Set resolved settings (pattern, numbering system).
SetResolvedSettings(no_extension_locale, number_format, resolved);
} else {
SetResolvedSettings(icu_locale, number_format, resolved);
}
return number_format;
}
static icu::DecimalFormat* CreateICUNumberFormat(
const icu::Locale& icu_locale, v8::Handle<v8::Object> options) {
// Make formatter from options. Numbering system is added
// to the locale as Unicode extension (if it was specified at all).
UErrorCode status = U_ZERO_ERROR;
icu::DecimalFormat* number_format = NULL;
icu::UnicodeString style;
icu::UnicodeString currency;
if (Utils::ExtractStringSetting(options, "style", &style)) {
if (style == UNICODE_STRING_SIMPLE("currency")) {
Utils::ExtractStringSetting(options, "currency", &currency);
icu::UnicodeString display;
Utils::ExtractStringSetting(options, "currencyDisplay", &display);
#if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6)
icu::NumberFormat::EStyles style;
if (display == UNICODE_STRING_SIMPLE("code")) {
style = icu::NumberFormat::kIsoCurrencyStyle;
} else if (display == UNICODE_STRING_SIMPLE("name")) {
style = icu::NumberFormat::kPluralCurrencyStyle;
} else {
style = icu::NumberFormat::kCurrencyStyle;
}
#else // ICU version is 4.8 or above (we ignore versions below 4.0).
UNumberFormatStyle style;
if (display == UNICODE_STRING_SIMPLE("code")) {
style = UNUM_CURRENCY_ISO;
} else if (display == UNICODE_STRING_SIMPLE("name")) {
style = UNUM_CURRENCY_PLURAL;
} else {
style = UNUM_CURRENCY;
}
#endif
number_format = static_cast<icu::DecimalFormat*>(
icu::NumberFormat::createInstance(icu_locale, style, status));
} else if (style == UNICODE_STRING_SIMPLE("percent")) {
number_format = static_cast<icu::DecimalFormat*>(
icu::NumberFormat::createPercentInstance(icu_locale, status));
if (U_FAILURE(status)) {
delete number_format;
return NULL;
}
// Make sure 1.1% doesn't go into 2%.
number_format->setMinimumFractionDigits(1);
} else {
// Make a decimal instance by default.
number_format = static_cast<icu::DecimalFormat*>(
icu::NumberFormat::createInstance(icu_locale, status));
}
}
if (U_FAILURE(status)) {
delete number_format;
return NULL;
}
// Set all options.
if (!currency.isEmpty()) {
number_format->setCurrency(currency.getBuffer(), status);
}
int32_t digits;
if (Utils::ExtractIntegerSetting(
options, "minimumIntegerDigits", &digits)) {
number_format->setMinimumIntegerDigits(digits);
}
if (Utils::ExtractIntegerSetting(
options, "minimumFractionDigits", &digits)) {
number_format->setMinimumFractionDigits(digits);
}
if (Utils::ExtractIntegerSetting(
options, "maximumFractionDigits", &digits)) {
number_format->setMaximumFractionDigits(digits);
}
bool significant_digits_used = false;
if (Utils::ExtractIntegerSetting(
options, "minimumSignificantDigits", &digits)) {
number_format->setMinimumSignificantDigits(digits);
significant_digits_used = true;
}
if (Utils::ExtractIntegerSetting(
options, "maximumSignificantDigits", &digits)) {
number_format->setMaximumSignificantDigits(digits);
significant_digits_used = true;
}
number_format->setSignificantDigitsUsed(significant_digits_used);
bool grouping;
if (Utils::ExtractBooleanSetting(options, "useGrouping", &grouping)) {
number_format->setGroupingUsed(grouping);
}
// Set rounding mode.
number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp);
return number_format;
}
static void SetResolvedSettings(const icu::Locale& icu_locale,
icu::DecimalFormat* number_format,
v8::Handle<v8::Object> resolved) {
icu::UnicodeString pattern;
number_format->toPattern(pattern);
resolved->Set(v8::String::New("pattern"),
v8::String::New(reinterpret_cast<const uint16_t*>(
pattern.getBuffer()), pattern.length()));
// Set resolved currency code in options.currency if not empty.
icu::UnicodeString currency(number_format->getCurrency());
if (!currency.isEmpty()) {
resolved->Set(v8::String::New("currency"),
v8::String::New(reinterpret_cast<const uint16_t*>(
currency.getBuffer()), currency.length()));
}
// Ugly hack. ICU doesn't expose numbering system in any way, so we have
// to assume that for given locale NumberingSystem constructor produces the
// same digits as NumberFormat would.
UErrorCode status = U_ZERO_ERROR;
icu::NumberingSystem* numbering_system =
icu::NumberingSystem::createInstance(icu_locale, status);
if (U_SUCCESS(status)) {
const char* ns = numbering_system->getName();
resolved->Set(v8::String::New("numberingSystem"), v8::String::New(ns));
} else {
resolved->Set(v8::String::New("numberingSystem"), v8::Undefined());
}
delete numbering_system;
resolved->Set(v8::String::New("useGrouping"),
v8::Boolean::New(number_format->isGroupingUsed()));
resolved->Set(v8::String::New("minimumIntegerDigits"),
v8::Integer::New(number_format->getMinimumIntegerDigits()));
resolved->Set(v8::String::New("minimumFractionDigits"),
v8::Integer::New(number_format->getMinimumFractionDigits()));
resolved->Set(v8::String::New("maximumFractionDigits"),
v8::Integer::New(number_format->getMaximumFractionDigits()));
if (resolved->HasOwnProperty(v8::String::New("minimumSignificantDigits"))) {
resolved->Set(v8::String::New("minimumSignificantDigits"), v8::Integer::New(
number_format->getMinimumSignificantDigits()));
}
if (resolved->HasOwnProperty(v8::String::New("maximumSignificantDigits"))) {
resolved->Set(v8::String::New("maximumSignificantDigits"), v8::Integer::New(
number_format->getMaximumSignificantDigits()));
}
// Set the locale
char result[ULOC_FULLNAME_CAPACITY];
status = U_ZERO_ERROR;
uloc_toLanguageTag(
icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
if (U_SUCCESS(status)) {
resolved->Set(v8::String::New("locale"), v8::String::New(result));
} else {
// This would never happen, since we got the locale from ICU.
resolved->Set(v8::String::New("locale"), v8::String::New("und"));
}
}
} // namespace v8_i18n

69
deps/v8/src/extensions/i18n/number-format.h

@ -0,0 +1,69 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#ifndef V8_EXTENSIONS_I18N_NUMBER_FORMAT_H_
#define V8_EXTENSIONS_I18N_NUMBER_FORMAT_H_
#include "unicode/uversion.h"
#include "v8.h"
namespace U_ICU_NAMESPACE {
class DecimalFormat;
}
namespace v8_i18n {
class NumberFormat {
public:
static void JSCreateNumberFormat(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Helper methods for various bindings.
// Unpacks date format object from corresponding JavaScript object.
static icu::DecimalFormat* UnpackNumberFormat(v8::Handle<v8::Object> obj);
// Release memory we allocated for the NumberFormat once the JS object that
// holds the pointer gets garbage collected.
static void DeleteNumberFormat(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
void* param);
// Formats number and returns corresponding string.
static void JSInternalFormat(const v8::FunctionCallbackInfo<v8::Value>& args);
// Parses a string and returns a number.
static void JSInternalParse(const v8::FunctionCallbackInfo<v8::Value>& args);
private:
NumberFormat();
};
} // namespace v8_i18n
#endif // V8_EXTENSIONS_I18N_NUMBER_FORMAT_H_

295
deps/v8/src/extensions/i18n/number-format.js

@ -0,0 +1,295 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
// ECMAScript 402 API implementation is broken into separate files for
// each service. The build system combines them together into one
// Intl namespace.
/**
* Verifies that the input is a well-formed ISO 4217 currency code.
* Don't uppercase to test. It could convert invalid code into a valid one.
* For example \u00DFP (Eszett+P) becomes SSP.
*/
function isWellFormedCurrencyCode(currency) {
return typeof currency == "string" &&
currency.length == 3 &&
currency.match(/[^A-Za-z]/) == null;
}
/**
* Returns the valid digit count for a property, or throws RangeError on
* a value out of the range.
*/
function getNumberOption(options, property, min, max, fallback) {
var value = options[property];
if (value !== undefined) {
value = Number(value);
if (isNaN(value) || value < min || value > max) {
throw new RangeError(property + ' value is out of range.');
}
return Math.floor(value);
}
return fallback;
}
/**
* Initializes the given object so it's a valid NumberFormat instance.
* Useful for subclassing.
*/
function initializeNumberFormat(numberFormat, locales, options) {
native function NativeJSCreateNumberFormat();
if (numberFormat.hasOwnProperty('__initializedIntlObject')) {
throw new TypeError('Trying to re-initialize NumberFormat object.');
}
if (options === undefined) {
options = {};
}
var getOption = getGetOption(options, 'numberformat');
var locale = resolveLocale('numberformat', locales, options);
var internalOptions = {};
defineWEProperty(internalOptions, 'style', getOption(
'style', 'string', ['decimal', 'percent', 'currency'], 'decimal'));
var currency = getOption('currency', 'string');
if (currency !== undefined && !isWellFormedCurrencyCode(currency)) {
throw new RangeError('Invalid currency code: ' + currency);
}
if (internalOptions.style === 'currency' && currency === undefined) {
throw new TypeError('Currency code is required with currency style.');
}
var currencyDisplay = getOption(
'currencyDisplay', 'string', ['code', 'symbol', 'name'], 'symbol');
if (internalOptions.style === 'currency') {
defineWEProperty(internalOptions, 'currency', currency.toUpperCase());
defineWEProperty(internalOptions, 'currencyDisplay', currencyDisplay);
}
// Digit ranges.
var mnid = getNumberOption(options, 'minimumIntegerDigits', 1, 21, 1);
defineWEProperty(internalOptions, 'minimumIntegerDigits', mnid);
var mnfd = getNumberOption(options, 'minimumFractionDigits', 0, 20, 0);
defineWEProperty(internalOptions, 'minimumFractionDigits', mnfd);
var mxfd = getNumberOption(options, 'maximumFractionDigits', mnfd, 20, 3);
defineWEProperty(internalOptions, 'maximumFractionDigits', mxfd);
var mnsd = options['minimumSignificantDigits'];
var mxsd = options['maximumSignificantDigits'];
if (mnsd !== undefined || mxsd !== undefined) {
mnsd = getNumberOption(options, 'minimumSignificantDigits', 1, 21, 0);
defineWEProperty(internalOptions, 'minimumSignificantDigits', mnsd);
mxsd = getNumberOption(options, 'maximumSignificantDigits', mnsd, 21, 21);
defineWEProperty(internalOptions, 'maximumSignificantDigits', mxsd);
}
// Grouping.
defineWEProperty(internalOptions, 'useGrouping', getOption(
'useGrouping', 'boolean', undefined, true));
// ICU prefers options to be passed using -u- extension key/values for
// number format, so we need to build that.
var extensionMap = parseExtension(locale.extension);
var extension = setOptions(options, extensionMap, NUMBER_FORMAT_KEY_MAP,
getOption, internalOptions);
var requestedLocale = locale.locale + extension;
var resolved = Object.defineProperties({}, {
currency: {writable: true},
currencyDisplay: {writable: true},
locale: {writable: true},
maximumFractionDigits: {writable: true},
minimumFractionDigits: {writable: true},
minimumIntegerDigits: {writable: true},
numberingSystem: {writable: true},
requestedLocale: {value: requestedLocale, writable: true},
style: {value: internalOptions.style, writable: true},
useGrouping: {writable: true}
});
if (internalOptions.hasOwnProperty('minimumSignificantDigits')) {
defineWEProperty(resolved, 'minimumSignificantDigits', undefined);
}
if (internalOptions.hasOwnProperty('maximumSignificantDigits')) {
defineWEProperty(resolved, 'maximumSignificantDigits', undefined);
}
var formatter = NativeJSCreateNumberFormat(requestedLocale,
internalOptions,
resolved);
// We can't get information about number or currency style from ICU, so we
// assume user request was fulfilled.
if (internalOptions.style === 'currency') {
Object.defineProperty(resolved, 'currencyDisplay', {value: currencyDisplay,
writable: true});
}
Object.defineProperty(numberFormat, 'formatter', {value: formatter});
Object.defineProperty(numberFormat, 'resolved', {value: resolved});
Object.defineProperty(numberFormat, '__initializedIntlObject',
{value: 'numberformat'});
return numberFormat;
}
/**
* Constructs Intl.NumberFormat object given optional locales and options
* parameters.
*
* @constructor
*/
%SetProperty(Intl, 'NumberFormat', function() {
var locales = arguments[0];
var options = arguments[1];
if (!this || this === Intl) {
// Constructor is called as a function.
return new Intl.NumberFormat(locales, options);
}
return initializeNumberFormat(toObject(this), locales, options);
},
ATTRIBUTES.DONT_ENUM
);
/**
* NumberFormat resolvedOptions method.
*/
%SetProperty(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject !== 'numberformat') {
throw new TypeError('resolvedOptions method called on a non-object' +
' or on a object that is not Intl.NumberFormat.');
}
var format = this;
var locale = getOptimalLanguageTag(format.resolved.requestedLocale,
format.resolved.locale);
var result = {
locale: locale,
numberingSystem: format.resolved.numberingSystem,
style: format.resolved.style,
useGrouping: format.resolved.useGrouping,
minimumIntegerDigits: format.resolved.minimumIntegerDigits,
minimumFractionDigits: format.resolved.minimumFractionDigits,
maximumFractionDigits: format.resolved.maximumFractionDigits,
};
if (result.style === 'currency') {
defineWECProperty(result, 'currency', format.resolved.currency);
defineWECProperty(result, 'currencyDisplay',
format.resolved.currencyDisplay);
}
if (format.resolved.hasOwnProperty('minimumSignificantDigits')) {
defineWECProperty(result, 'minimumSignificantDigits',
format.resolved.minimumSignificantDigits);
}
if (format.resolved.hasOwnProperty('maximumSignificantDigits')) {
defineWECProperty(result, 'maximumSignificantDigits',
format.resolved.maximumSignificantDigits);
}
return result;
},
ATTRIBUTES.DONT_ENUM
);
%FunctionSetName(Intl.NumberFormat.prototype.resolvedOptions,
'resolvedOptions');
%FunctionRemovePrototype(Intl.NumberFormat.prototype.resolvedOptions);
%SetNativeFlag(Intl.NumberFormat.prototype.resolvedOptions);
/**
* Returns the subset of the given locale list for which this locale list
* has a matching (possibly fallback) locale. Locales appear in the same
* order in the returned list as in the input list.
* Options are optional parameter.
*/
%SetProperty(Intl.NumberFormat, 'supportedLocalesOf', function(locales) {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
return supportedLocalesOf('numberformat', locales, arguments[1]);
},
ATTRIBUTES.DONT_ENUM
);
%FunctionSetName(Intl.NumberFormat.supportedLocalesOf, 'supportedLocalesOf');
%FunctionRemovePrototype(Intl.NumberFormat.supportedLocalesOf);
%SetNativeFlag(Intl.NumberFormat.supportedLocalesOf);
/**
* Returns a String value representing the result of calling ToNumber(value)
* according to the effective locale and the formatting options of this
* NumberFormat.
*/
function formatNumber(formatter, value) {
native function NativeJSInternalNumberFormat();
// Spec treats -0 and +0 as 0.
var number = Number(value);
if (number === -0) {
number = 0;
}
return NativeJSInternalNumberFormat(formatter.formatter, number);
}
/**
* Returns a Number that represents string value that was passed in.
*/
function parseNumber(formatter, value) {
native function NativeJSInternalNumberParse();
return NativeJSInternalNumberParse(formatter.formatter, String(value));
}
addBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1);
addBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1);

220
deps/v8/src/extensions/i18n/overrides.js

@ -0,0 +1,220 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
// ECMAScript 402 API implementation is broken into separate files for
// each service. The build system combines them together into one
// Intl namespace.
// Save references to Intl objects and methods we use, for added security.
var savedObjects = {
'collator': Intl.Collator,
'numberformat': Intl.NumberFormat,
'dateformatall': Intl.DateTimeFormat,
'dateformatdate': Intl.DateTimeFormat,
'dateformattime': Intl.DateTimeFormat
};
// Default (created with undefined locales and options parameters) collator,
// number and date format instances. They'll be created as needed.
var defaultObjects = {
'collator': undefined,
'numberformat': undefined,
'dateformatall': undefined,
'dateformatdate': undefined,
'dateformattime': undefined,
};
/**
* Returns cached or newly created instance of a given service.
* We cache only default instances (where no locales or options are provided).
*/
function cachedOrNewService(service, locales, options, defaults) {
var useOptions = (defaults === undefined) ? options : defaults;
if (locales === undefined && options === undefined) {
if (defaultObjects[service] === undefined) {
defaultObjects[service] = new savedObjects[service](locales, useOptions);
}
return defaultObjects[service];
}
return new savedObjects[service](locales, useOptions);
}
/**
* Compares this and that, and returns less than 0, 0 or greater than 0 value.
* Overrides the built-in method.
*/
Object.defineProperty(String.prototype, 'localeCompare', {
value: function(that) {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (this === undefined || this === null) {
throw new TypeError('Method invoked on undefined or null value.');
}
var locales = arguments[1];
var options = arguments[2];
var collator = cachedOrNewService('collator', locales, options);
return compare(collator, this, that);
},
writable: true,
configurable: true,
enumerable: false
});
%FunctionSetName(String.prototype.localeCompare, 'localeCompare');
%FunctionRemovePrototype(String.prototype.localeCompare);
%SetNativeFlag(String.prototype.localeCompare);
/**
* Formats a Number object (this) using locale and options values.
* If locale or options are omitted, defaults are used.
*/
Object.defineProperty(Number.prototype, 'toLocaleString', {
value: function() {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (!(this instanceof Number) && typeof(this) !== 'number') {
throw new TypeError('Method invoked on an object that is not Number.');
}
var locales = arguments[0];
var options = arguments[1];
var numberFormat = cachedOrNewService('numberformat', locales, options);
return formatNumber(numberFormat, this);
},
writable: true,
configurable: true,
enumerable: false
});
%FunctionSetName(Number.prototype.toLocaleString, 'toLocaleString');
%FunctionRemovePrototype(Number.prototype.toLocaleString);
%SetNativeFlag(Number.prototype.toLocaleString);
/**
* Returns actual formatted date or fails if date parameter is invalid.
*/
function toLocaleDateTime(date, locales, options, required, defaults, service) {
if (!(date instanceof Date)) {
throw new TypeError('Method invoked on an object that is not Date.');
}
if (isNaN(date)) {
return 'Invalid Date';
}
var internalOptions = toDateTimeOptions(options, required, defaults);
var dateFormat =
cachedOrNewService(service, locales, options, internalOptions);
return formatDate(dateFormat, date);
}
/**
* Formats a Date object (this) using locale and options values.
* If locale or options are omitted, defaults are used - both date and time are
* present in the output.
*/
Object.defineProperty(Date.prototype, 'toLocaleString', {
value: function() {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
var locales = arguments[0];
var options = arguments[1];
return toLocaleDateTime(
this, locales, options, 'any', 'all', 'dateformatall');
},
writable: true,
configurable: true,
enumerable: false
});
%FunctionSetName(Date.prototype.toLocaleString, 'toLocaleString');
%FunctionRemovePrototype(Date.prototype.toLocaleString);
%SetNativeFlag(Date.prototype.toLocaleString);
/**
* Formats a Date object (this) using locale and options values.
* If locale or options are omitted, defaults are used - only date is present
* in the output.
*/
Object.defineProperty(Date.prototype, 'toLocaleDateString', {
value: function() {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
var locales = arguments[0];
var options = arguments[1];
return toLocaleDateTime(
this, locales, options, 'date', 'date', 'dateformatdate');
},
writable: true,
configurable: true,
enumerable: false
});
%FunctionSetName(Date.prototype.toLocaleDateString, 'toLocaleDateString');
%FunctionRemovePrototype(Date.prototype.toLocaleDateString);
%SetNativeFlag(Date.prototype.toLocaleDateString);
/**
* Formats a Date object (this) using locale and options values.
* If locale or options are omitted, defaults are used - only time is present
* in the output.
*/
Object.defineProperty(Date.prototype, 'toLocaleTimeString', {
value: function() {
if (%_IsConstructCall()) {
throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
var locales = arguments[0];
var options = arguments[1];
return toLocaleDateTime(
this, locales, options, 'time', 'time', 'dateformattime');
},
writable: true,
configurable: true,
enumerable: false
});
%FunctionSetName(Date.prototype.toLocaleTimeString, 'toLocaleTimeString');
%FunctionRemovePrototype(Date.prototype.toLocaleTimeString);
%SetNativeFlag(Date.prototype.toLocaleTimeString);

6
deps/v8/src/extensions/statistics-extension.cc

@ -133,6 +133,12 @@ void StatisticsExtension::GetCounters(
"cell_space_available_bytes");
AddNumber(result, heap->cell_space()->CommittedMemory(),
"cell_space_commited_bytes");
AddNumber(result, heap->property_cell_space()->Size(),
"property_cell_space_live_bytes");
AddNumber(result, heap->property_cell_space()->Available(),
"property_cell_space_available_bytes");
AddNumber(result, heap->property_cell_space()->CommittedMemory(),
"property_cell_space_commited_bytes");
AddNumber(result, heap->lo_space()->Size(),
"lo_space_live_bytes");
AddNumber(result, heap->lo_space()->Available(),

74
deps/v8/src/factory.cc

@ -31,6 +31,7 @@
#include "debug.h"
#include "execution.h"
#include "factory.h"
#include "isolate-inl.h"
#include "macro-assembler.h"
#include "objects.h"
#include "objects-visiting.h"
@ -259,6 +260,32 @@ Handle<String> Factory::NewConsString(Handle<String> first,
}
template<typename SinkChar, typename StringType>
Handle<String> ConcatStringContent(Handle<StringType> result,
Handle<String> first,
Handle<String> second) {
DisallowHeapAllocation pointer_stays_valid;
SinkChar* sink = result->GetChars();
String::WriteToFlat(*first, sink, 0, first->length());
String::WriteToFlat(*second, sink + first->length(), 0, second->length());
return result;
}
Handle<String> Factory::NewFlatConcatString(Handle<String> first,
Handle<String> second) {
int total_length = first->length() + second->length();
if (first->IsOneByteRepresentationUnderneath() &&
second->IsOneByteRepresentationUnderneath()) {
return ConcatStringContent<uint8_t>(
NewRawOneByteString(total_length), first, second);
} else {
return ConcatStringContent<uc16>(
NewRawTwoByteString(total_length), first, second);
}
}
Handle<String> Factory::NewSubString(Handle<String> str,
int begin,
int end) {
@ -408,27 +435,17 @@ Handle<ExecutableAccessorInfo> Factory::NewExecutableAccessorInfo() {
Handle<Script> Factory::NewScript(Handle<String> source) {
// Generate id for this script.
int id;
Heap* heap = isolate()->heap();
if (heap->last_script_id()->IsUndefined()) {
// Script ids start from one.
id = 1;
} else {
// Increment id, wrap when positive smi is exhausted.
id = Smi::cast(heap->last_script_id())->value();
id++;
if (!Smi::IsValid(id)) {
id = 0;
}
}
heap->SetLastScriptId(Smi::FromInt(id));
int id = heap->last_script_id()->value() + 1;
if (!Smi::IsValid(id) || id < 0) id = 1;
heap->set_last_script_id(Smi::FromInt(id));
// Create and initialize script object.
Handle<Foreign> wrapper = NewForeign(0, TENURED);
Handle<Script> script = Handle<Script>::cast(NewStruct(SCRIPT_TYPE));
script->set_source(*source);
script->set_name(heap->undefined_value());
script->set_id(heap->last_script_id());
script->set_id(Smi::FromInt(id));
script->set_line_offset(Smi::FromInt(0));
script->set_column_offset(Smi::FromInt(0));
script->set_data(heap->undefined_value());
@ -482,13 +499,21 @@ Handle<ExternalArray> Factory::NewExternalArray(int length,
}
Handle<JSGlobalPropertyCell> Factory::NewJSGlobalPropertyCell(
Handle<Object> value) {
Handle<Cell> Factory::NewCell(Handle<Object> value) {
AllowDeferredHandleDereference convert_to_cell;
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateCell(*value),
Cell);
}
Handle<PropertyCell> Factory::NewPropertyCell(Handle<Object> value) {
AllowDeferredHandleDereference convert_to_cell;
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSGlobalPropertyCell(*value),
JSGlobalPropertyCell);
isolate()->heap()->AllocatePropertyCell(*value),
PropertyCell);
}
@ -636,7 +661,8 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
result->is_compiled() &&
!function_info->is_toplevel() &&
function_info->allows_lazy_compilation() &&
!function_info->optimization_disabled()) {
!function_info->optimization_disabled() &&
!isolate()->DebuggerHasBreakPoints()) {
result->MarkForLazyRecompilation();
}
return result;
@ -1072,6 +1098,16 @@ Handle<JSArrayBuffer> Factory::NewJSArrayBuffer() {
}
Handle<JSDataView> Factory::NewJSDataView() {
JSFunction* data_view_fun =
isolate()->context()->native_context()->data_view_fun();
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObject(data_view_fun),
JSDataView);
}
Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type) {
JSFunction* typed_array_fun;
Context* native_context = isolate()->context()->native_context();

11
deps/v8/src/factory.h

@ -152,6 +152,10 @@ class Factory {
Handle<String> NewConsString(Handle<String> first,
Handle<String> second);
// Create a new sequential string containing the concatenation of the inputs.
Handle<String> NewFlatConcatString(Handle<String> first,
Handle<String> second);
// Create a new string object which holds a substring of a string.
Handle<String> NewSubString(Handle<String> str,
int begin,
@ -235,8 +239,9 @@ class Factory {
void* external_pointer,
PretenureFlag pretenure = NOT_TENURED);
Handle<JSGlobalPropertyCell> NewJSGlobalPropertyCell(
Handle<Object> value);
Handle<Cell> NewCell(Handle<Object> value);
Handle<PropertyCell> NewPropertyCell(Handle<Object> value);
Handle<Map> NewMap(
InstanceType type,
@ -327,6 +332,8 @@ class Factory {
Handle<JSTypedArray> NewJSTypedArray(ExternalArrayType type);
Handle<JSDataView> NewJSDataView();
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
// Change the type of the argument into a JS object/function and reinitialize.

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

@ -178,8 +178,7 @@ DEFINE_implication(harmony, harmony_symbols)
DEFINE_implication(harmony, harmony_proxies)
DEFINE_implication(harmony, harmony_collections)
DEFINE_implication(harmony, harmony_observation)
// TODO(wingo): Re-enable when GC bug that appeared in r15060 is gone.
// DEFINE_implication(harmony, harmony_generators)
DEFINE_implication(harmony, harmony_generators)
DEFINE_implication(harmony, harmony_iteration)
DEFINE_implication(harmony_modules, harmony_scoping)
DEFINE_implication(harmony_observation, harmony_collections)
@ -196,9 +195,6 @@ DEFINE_bool(clever_optimizations,
true,
"Optimize object size, Array shift, DOM strings and string +")
DEFINE_bool(pretenuring, true, "allocate objects in old space")
// TODO(hpayer): We will remove this flag as soon as we have pretenuring
// support for specific allocation sites.
DEFINE_bool(pretenuring_call_new, false, "pretenure call new")
DEFINE_bool(track_fields, true, "track fields with only smi values")
DEFINE_bool(track_double_fields, true, "track fields with double values")
DEFINE_bool(track_heap_object_fields, true, "track fields with heap values")
@ -218,6 +214,7 @@ DEFINE_bool(use_range, true, "use hydrogen range analysis")
DEFINE_bool(use_gvn, true, "use hydrogen global value numbering")
DEFINE_bool(use_canonicalizing, true, "use hydrogen instruction canonicalizing")
DEFINE_bool(use_inlining, true, "use function inlining")
DEFINE_bool(use_escape_analysis, false, "use hydrogen escape analysis")
DEFINE_int(max_inlined_source_size, 600,
"maximum source size in bytes considered for a single inlining")
DEFINE_int(max_inlined_nodes, 196,
@ -238,6 +235,7 @@ DEFINE_bool(trace_all_uses, false, "trace all use positions")
DEFINE_bool(trace_range, false, "trace range analysis")
DEFINE_bool(trace_gvn, false, "trace global value numbering")
DEFINE_bool(trace_representation, false, "trace representation types")
DEFINE_bool(trace_escape_analysis, false, "trace hydrogen escape analysis")
DEFINE_bool(trace_track_allocation_sites, false,
"trace the tracking of allocation sites")
DEFINE_bool(trace_migration, false, "trace object migration")
@ -268,8 +266,6 @@ DEFINE_bool(unreachable_code_elimination, false,
"eliminate unreachable code (hidden behind soft deopts)")
DEFINE_bool(track_allocation_sites, true,
"Use allocation site info to reduce transitions")
DEFINE_bool(optimize_constructed_arrays, true,
"Use allocation site info on constructed arrays")
DEFINE_bool(trace_osr, false, "trace on-stack replacement")
DEFINE_int(stress_runs, 0, "number of stress runs")
DEFINE_bool(optimize_closures, true, "optimize closures")
@ -291,10 +287,10 @@ DEFINE_bool(opt_safe_uint32_operations, true,
"allow uint32 values on optimize frames if they are used only in "
"safe operations")
DEFINE_bool(parallel_recompilation, false,
DEFINE_bool(parallel_recompilation, true,
"optimizing hot functions asynchronously on a separate thread")
DEFINE_bool(trace_parallel_recompilation, false, "track parallel recompilation")
DEFINE_int(parallel_recompilation_queue_length, 3,
DEFINE_int(parallel_recompilation_queue_length, 8,
"the length of the parallel compilation queue")
DEFINE_int(parallel_recompilation_delay, 0,
"artificial compilation delay in ms")
@ -318,7 +314,7 @@ DEFINE_bool(weighted_back_edges, false,
// 0x1700 fits in the immediate field of an ARM instruction.
DEFINE_int(interrupt_budget, 0x1700,
"execution budget before interrupt is triggered")
DEFINE_int(type_info_threshold, 15,
DEFINE_int(type_info_threshold, 25,
"percentage of ICs that must have type info to allow optimization")
DEFINE_int(self_opt_count, 130, "call count before self-optimization")
@ -365,6 +361,7 @@ DEFINE_bool(enable_vldr_imm, false,
"enable use of constant pools for double immediate (ARM only)")
// bootstrapper.cc
DEFINE_bool(enable_i18n, true, "enable i18n extension")
DEFINE_string(expose_natives_as, NULL, "expose natives in global object")
DEFINE_string(expose_debug_as, NULL, "expose debug in global object")
DEFINE_bool(expose_gc, false, "expose gc extension")
@ -400,6 +397,7 @@ DEFINE_bool(trace_opt, false, "trace lazy optimization")
DEFINE_bool(trace_opt_stats, false, "trace lazy optimization statistics")
DEFINE_bool(opt, true, "use adaptive optimizations")
DEFINE_bool(always_opt, false, "always try to optimize functions")
DEFINE_bool(always_osr, false, "always try to OSR functions")
DEFINE_bool(prepare_always_opt, false, "prepare for turning on always opt")
DEFINE_bool(trace_deopt, false, "trace optimize function deoptimization")
DEFINE_bool(trace_stub_failures, false,
@ -472,7 +470,7 @@ DEFINE_bool(trace_external_memory, false,
"it is adjusted.")
DEFINE_bool(collect_maps, true,
"garbage collect maps from which no objects can be reached")
DEFINE_bool(weak_embedded_maps_in_optimized_code, false,
DEFINE_bool(weak_embedded_maps_in_optimized_code, true,
"make maps embedded in optimized code weak")
DEFINE_bool(flush_code, true,
"flush code that we expect not to use again (during full gc)")
@ -481,7 +479,7 @@ DEFINE_bool(flush_code_incrementally, true,
DEFINE_bool(trace_code_flushing, false, "trace code flushing progress")
DEFINE_bool(age_code, true,
"track un-executed functions to age code and flush only "
"old code")
"old code (required for code flushing)")
DEFINE_bool(incremental_marking, true, "use incremental marking")
DEFINE_bool(incremental_marking_steps, true, "do incremental marking steps")
DEFINE_bool(trace_incremental_marking, false,

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

Loading…
Cancel
Save