Browse Source

Upgrade V8 to 3.4.9

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
6054dcc130
  1. 1
      deps/v8/AUTHORS
  2. 15
      deps/v8/ChangeLog
  3. 39
      deps/v8/SConstruct
  4. 46
      deps/v8/include/v8.h
  5. 9
      deps/v8/samples/shell.cc
  6. 33
      deps/v8/src/api.cc
  7. 10
      deps/v8/src/arm/assembler-arm.h
  8. 3
      deps/v8/src/arm/builtins-arm.cc
  9. 26
      deps/v8/src/arm/code-stubs-arm.cc
  10. 16
      deps/v8/src/arm/code-stubs-arm.h
  11. 30
      deps/v8/src/arm/deoptimizer-arm.cc
  12. 191
      deps/v8/src/arm/full-codegen-arm.cc
  13. 3
      deps/v8/src/arm/ic-arm.cc
  14. 197
      deps/v8/src/arm/lithium-arm.cc
  15. 188
      deps/v8/src/arm/lithium-arm.h
  16. 236
      deps/v8/src/arm/lithium-codegen-arm.cc
  17. 109
      deps/v8/src/arm/macro-assembler-arm.cc
  18. 22
      deps/v8/src/arm/macro-assembler-arm.h
  19. 15
      deps/v8/src/array.js
  20. 14
      deps/v8/src/ast.h
  21. 49
      deps/v8/src/compilation-cache.cc
  22. 10
      deps/v8/src/compilation-cache.h
  23. 14
      deps/v8/src/compiler.cc
  24. 2
      deps/v8/src/contexts.h
  25. 13
      deps/v8/src/date.js
  26. 281
      deps/v8/src/dateparser-inl.h
  27. 38
      deps/v8/src/dateparser.cc
  28. 198
      deps/v8/src/dateparser.h
  29. 15
      deps/v8/src/debug-debugger.js
  30. 188
      deps/v8/src/deoptimizer.cc
  31. 96
      deps/v8/src/deoptimizer.h
  32. 3
      deps/v8/src/flag-definitions.h
  33. 37
      deps/v8/src/frames.cc
  34. 8
      deps/v8/src/frames.h
  35. 8
      deps/v8/src/full-codegen.cc
  36. 16
      deps/v8/src/full-codegen.h
  37. 690
      deps/v8/src/gdb-jit.cc
  38. 8
      deps/v8/src/gdb-jit.h
  39. 7
      deps/v8/src/handles.cc
  40. 2
      deps/v8/src/handles.h
  41. 4
      deps/v8/src/heap.cc
  42. 41
      deps/v8/src/hydrogen-instructions.cc
  43. 287
      deps/v8/src/hydrogen-instructions.h
  44. 405
      deps/v8/src/hydrogen.cc
  45. 17
      deps/v8/src/hydrogen.h
  46. 6
      deps/v8/src/ia32/assembler-ia32.h
  47. 11
      deps/v8/src/ia32/code-stubs-ia32.cc
  48. 14
      deps/v8/src/ia32/code-stubs-ia32.h
  49. 29
      deps/v8/src/ia32/deoptimizer-ia32.cc
  50. 200
      deps/v8/src/ia32/full-codegen-ia32.cc
  51. 2
      deps/v8/src/ia32/ic-ia32.cc
  52. 257
      deps/v8/src/ia32/lithium-codegen-ia32.cc
  53. 220
      deps/v8/src/ia32/lithium-ia32.cc
  54. 187
      deps/v8/src/ia32/lithium-ia32.h
  55. 11
      deps/v8/src/ia32/macro-assembler-ia32.cc
  56. 61
      deps/v8/src/ic.cc
  57. 6
      deps/v8/src/ic.h
  58. 5
      deps/v8/src/isolate.cc
  59. 4
      deps/v8/src/isolate.h
  60. 24
      deps/v8/src/log.cc
  61. 6
      deps/v8/src/log.h
  62. 57
      deps/v8/src/mark-compact.cc
  63. 4
      deps/v8/src/mark-compact.h
  64. 13
      deps/v8/src/mips/code-stubs-mips.cc
  65. 16
      deps/v8/src/mips/code-stubs-mips.h
  66. 5
      deps/v8/src/mips/deoptimizer-mips.cc
  67. 229
      deps/v8/src/mips/full-codegen-mips.cc
  68. 17
      deps/v8/src/mips/macro-assembler-mips.cc
  69. 4
      deps/v8/src/mips/macro-assembler-mips.h
  70. 35
      deps/v8/src/mirror-debugger.js
  71. 50
      deps/v8/src/objects.cc
  72. 9
      deps/v8/src/objects.h
  73. 124
      deps/v8/src/parser.cc
  74. 6
      deps/v8/src/parser.h
  75. 230
      deps/v8/src/platform-solaris.cc
  76. 9
      deps/v8/src/prettyprinter.cc
  77. 108
      deps/v8/src/profile-generator.cc
  78. 2
      deps/v8/src/profile-generator.h
  79. 2
      deps/v8/src/rewriter.cc
  80. 139
      deps/v8/src/runtime-profiler.cc
  81. 23
      deps/v8/src/runtime-profiler.h
  82. 166
      deps/v8/src/runtime.cc
  83. 25
      deps/v8/src/runtime.h
  84. 138
      deps/v8/src/scopes.cc
  85. 31
      deps/v8/src/scopes.h
  86. 11
      deps/v8/src/string.js
  87. 4
      deps/v8/src/stub-cache.cc
  88. 1
      deps/v8/src/type-info.cc
  89. 4
      deps/v8/src/v8-counters.h
  90. 44
      deps/v8/src/v8.cc
  91. 2
      deps/v8/src/version.cc
  92. 6
      deps/v8/src/x64/assembler-x64.h
  93. 13
      deps/v8/src/x64/code-stubs-x64.cc
  94. 16
      deps/v8/src/x64/code-stubs-x64.h
  95. 32
      deps/v8/src/x64/deoptimizer-x64.cc
  96. 191
      deps/v8/src/x64/full-codegen-x64.cc
  97. 2
      deps/v8/src/x64/ic-x64.cc
  98. 260
      deps/v8/src/x64/lithium-codegen-x64.cc
  99. 197
      deps/v8/src/x64/lithium-x64.cc
  100. 190
      deps/v8/src/x64/lithium-x64.h

1
deps/v8/AUTHORS

@ -36,6 +36,7 @@ Patrick Gansterer <paroga@paroga.com>
Peter Varga <pvarga@inf.u-szeged.hu> Peter Varga <pvarga@inf.u-szeged.hu>
Rafal Krypa <rafal@krypa.net> Rafal Krypa <rafal@krypa.net>
Rene Rebe <rene@exactcode.de> Rene Rebe <rene@exactcode.de>
Robert Mustacchi <rm@fingolfin.org>
Rodolph Perfetta <rodolph.perfetta@arm.com> Rodolph Perfetta <rodolph.perfetta@arm.com>
Ryan Dahl <coldredlemur@gmail.com> Ryan Dahl <coldredlemur@gmail.com>
Sanjoy Das <sanjoy@playingwithpointers.com> Sanjoy Das <sanjoy@playingwithpointers.com>

15
deps/v8/ChangeLog

@ -1,3 +1,18 @@
2011-07-04: Version 3.4.9
Added support for debugger inspection of locals in optimized frames
(issue 1140).
Fixed SConstruct to pass correct defines to samples/preparser when
building with library=shared.
Made date parser handle ES5 Date Time Strings correctly (issue 1498).
Fixed a bug in Object.defineProperty on the arguments object.
Performance improvements on all platforms.
2011-06-29: Version 3.4.8 2011-06-29: Version 3.4.8
Ensure 16-byte stack alignment on Solaris (issue 1505). Ensure 16-byte stack alignment on Solaris (issue 1505).

39
deps/v8/SConstruct

@ -89,7 +89,7 @@ LIBRARY_FLAGS = {
'gcc': { 'gcc': {
'all': { 'all': {
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'], 'CXXFLAGS': ['-fno-rtti', '-fno-exceptions'],
}, },
'visibility:hidden': { 'visibility:hidden': {
# Use visibility=default to disable this. # Use visibility=default to disable this.
@ -230,7 +230,7 @@ LIBRARY_FLAGS = {
'msvc': { 'msvc': {
'all': { 'all': {
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CXXFLAGS': ['$CCFLAGS', '/GR-', '/Gy'], 'CXXFLAGS': ['/GR-', '/Gy'],
'CPPDEFINES': ['WIN32'], 'CPPDEFINES': ['WIN32'],
'LINKFLAGS': ['/INCREMENTAL:NO', '/NXCOMPAT', '/IGNORE:4221'], 'LINKFLAGS': ['/INCREMENTAL:NO', '/NXCOMPAT', '/IGNORE:4221'],
'CCPDBFLAGS': ['/Zi'] 'CCPDBFLAGS': ['/Zi']
@ -400,12 +400,15 @@ DTOA_EXTRA_FLAGS = {
CCTEST_EXTRA_FLAGS = { CCTEST_EXTRA_FLAGS = {
'all': { 'all': {
'CPPPATH': [join(root_dir, 'src')], 'CPPPATH': [join(root_dir, 'src')],
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
},
}, },
'gcc': { 'gcc': {
'all': { 'all': {
'LIBPATH': [abspath('.')], 'LIBPATH': [abspath('.')],
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'], 'CXXFLAGS': ['-fno-rtti', '-fno-exceptions'],
'LINKFLAGS': ['$CCFLAGS'], 'LINKFLAGS': ['$CCFLAGS'],
}, },
'os:linux': { 'os:linux': {
@ -436,9 +439,6 @@ CCTEST_EXTRA_FLAGS = {
'CPPDEFINES': ['_HAS_EXCEPTIONS=0'], 'CPPDEFINES': ['_HAS_EXCEPTIONS=0'],
'LIBS': ['winmm', 'ws2_32'] 'LIBS': ['winmm', 'ws2_32']
}, },
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
},
'arch:ia32': { 'arch:ia32': {
'CPPDEFINES': ['V8_TARGET_ARCH_IA32'] 'CPPDEFINES': ['V8_TARGET_ARCH_IA32']
}, },
@ -453,12 +453,15 @@ CCTEST_EXTRA_FLAGS = {
SAMPLE_FLAGS = { SAMPLE_FLAGS = {
'all': { 'all': {
'CPPPATH': [join(abspath('.'), 'include')], 'CPPPATH': [join(abspath('.'), 'include')],
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
},
}, },
'gcc': { 'gcc': {
'all': { 'all': {
'LIBPATH': ['.'], 'LIBPATH': ['.'],
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'], 'CXXFLAGS': ['-fno-rtti', '-fno-exceptions'],
'LINKFLAGS': ['$CCFLAGS'], 'LINKFLAGS': ['$CCFLAGS'],
}, },
'os:linux': { 'os:linux': {
@ -472,6 +475,9 @@ SAMPLE_FLAGS = {
'LIBS': ['execinfo', 'pthread'] 'LIBS': ['execinfo', 'pthread']
}, },
'os:solaris': { 'os:solaris': {
# On Solaris, to get isinf, INFINITY, fpclassify and other macros one
# needs to define __C99FEATURES__.
'CPPDEFINES': ['__C99FEATURES__'],
'LIBPATH' : ['/usr/local/lib'], 'LIBPATH' : ['/usr/local/lib'],
'LIBS': ['m', 'pthread', 'socket', 'nsl', 'rt'], 'LIBS': ['m', 'pthread', 'socket', 'nsl', 'rt'],
'LINKFLAGS': ['-mt'] 'LINKFLAGS': ['-mt']
@ -572,9 +578,6 @@ SAMPLE_FLAGS = {
'verbose:on': { 'verbose:on': {
'LINKFLAGS': ['/VERBOSE'] 'LINKFLAGS': ['/VERBOSE']
}, },
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
},
'prof:on': { 'prof:on': {
'LINKFLAGS': ['/MAP'] 'LINKFLAGS': ['/MAP']
}, },
@ -625,13 +628,16 @@ SAMPLE_FLAGS = {
PREPARSER_FLAGS = { PREPARSER_FLAGS = {
'all': { 'all': {
'CPPPATH': [join(abspath('.'), 'include'), join(abspath('.'), 'src')] 'CPPPATH': [join(abspath('.'), 'include'), join(abspath('.'), 'src')],
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
},
}, },
'gcc': { 'gcc': {
'all': { 'all': {
'LIBPATH': ['.'], 'LIBPATH': ['.'],
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'], 'CXXFLAGS': ['-fno-rtti', '-fno-exceptions'],
'LINKFLAGS': ['$CCFLAGS'], 'LINKFLAGS': ['$CCFLAGS'],
}, },
'os:win32': { 'os:win32': {
@ -727,9 +733,6 @@ PREPARSER_FLAGS = {
'verbose:on': { 'verbose:on': {
'LINKFLAGS': ['/VERBOSE'] 'LINKFLAGS': ['/VERBOSE']
}, },
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
},
'prof:on': { 'prof:on': {
'LINKFLAGS': ['/MAP'] 'LINKFLAGS': ['/MAP']
}, },
@ -782,7 +785,7 @@ D8_FLAGS = {
'gcc': { 'gcc': {
'all': { 'all': {
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'], 'CXXFLAGS': ['-fno-rtti', '-fno-exceptions'],
'LINKFLAGS': ['$CCFLAGS'], 'LINKFLAGS': ['$CCFLAGS'],
}, },
'console:readline': { 'console:readline': {
@ -1155,8 +1158,8 @@ def VerifyOptions(env):
return False return False
if env['os'] == 'win32' and env['library'] == 'shared' and env['prof'] == 'on': if env['os'] == 'win32' and env['library'] == 'shared' and env['prof'] == 'on':
Abort("Profiling on windows only supported for static library.") Abort("Profiling on windows only supported for static library.")
if env['gdbjit'] == 'on' and (env['os'] != 'linux' or (env['arch'] != 'ia32' and env['arch'] != 'x64' and env['arch'] != 'arm')): if env['gdbjit'] == 'on' and ((env['os'] != 'linux' and env['os'] != 'macos') or (env['arch'] != 'ia32' and env['arch'] != 'x64' and env['arch'] != 'arm')):
Abort("GDBJIT interface is supported only for Intel-compatible (ia32 or x64) Linux target.") Abort("GDBJIT interface is supported only for Intel-compatible (ia32 or x64) Linux/OSX target.")
if env['os'] == 'win32' and env['soname'] == 'on': if env['os'] == 'win32' and env['soname'] == 'on':
Abort("Shared Object soname not applicable for Windows.") Abort("Shared Object soname not applicable for Windows.")
if env['soname'] == 'on' and env['library'] == 'static': if env['soname'] == 'on' and env['library'] == 'static':

46
deps/v8/include/v8.h

@ -2557,18 +2557,6 @@ typedef void (*GCEpilogueCallback)(GCType type, GCCallbackFlags flags);
typedef void (*GCCallback)(); typedef void (*GCCallback)();
/**
* Profiler modules.
*
* In V8, profiler consists of several modules. Each can be turned on / off
* independently.
*/
enum ProfilerModules {
PROFILER_MODULE_NONE = 0,
PROFILER_MODULE_CPU = 1
};
/** /**
* Collection of V8 heap information. * Collection of V8 heap information.
* *
@ -2995,40 +2983,6 @@ class V8EXPORT V8 {
*/ */
static bool IsProfilerPaused(); static bool IsProfilerPaused();
/**
* Resumes specified profiler modules. Can be called several times to
* mark the opening of a profiler events block with the given tag.
*
* "ResumeProfiler" is equivalent to "ResumeProfilerEx(PROFILER_MODULE_CPU)".
* See ProfilerModules enum.
*
* \param flags Flags specifying profiler modules.
* \param tag Profile tag.
*/
static void ResumeProfilerEx(int flags, int tag = 0);
/**
* Pauses specified profiler modules. Each call to "PauseProfilerEx" closes
* a block of profiler events opened by a call to "ResumeProfilerEx" with the
* same tag value. There is no need for blocks to be properly nested.
* The profiler is paused when the last opened block is closed.
*
* "PauseProfiler" is equivalent to "PauseProfilerEx(PROFILER_MODULE_CPU)".
* See ProfilerModules enum.
*
* \param flags Flags specifying profiler modules.
* \param tag Profile tag.
*/
static void PauseProfilerEx(int flags, int tag = 0);
/**
* Returns active (resumed) profiler modules.
* See ProfilerModules enum.
*
* \returns active profiler modules.
*/
static int GetActiveProfilerModules();
/** /**
* If logging is performed into a memory buffer (via --logfile=*), allows to * If logging is performed into a memory buffer (via --logfile=*), allows to
* retrieve previously written messages. This can be used for retrieving * retrieve previously written messages. This can be used for retrieving

9
deps/v8/samples/shell.cc

@ -498,12 +498,15 @@ void ExternalArrayWeakCallback(v8::Persistent<v8::Value> object, void* data) {
v8::Handle<v8::Value> CreateExternalArray(const v8::Arguments& args, v8::Handle<v8::Value> CreateExternalArray(const v8::Arguments& args,
v8::ExternalArrayType type, v8::ExternalArrayType type,
size_t element_size) { size_t element_size) {
ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || assert(element_size == 1 ||
element_size == 2 ||
element_size == 4 ||
element_size == 8); element_size == 8);
if (args.Length() != 1) { if (args.Length() != 1) {
return v8::ThrowException( return v8::ThrowException(
v8::String::New("Array constructor needs one parameter.")); v8::String::New("Array constructor needs one parameter."));
} }
static const int kMaxLength = 0x3fffffff;
size_t length = 0; size_t length = 0;
if (args[0]->IsUint32()) { if (args[0]->IsUint32()) {
length = args[0]->Uint32Value(); length = args[0]->Uint32Value();
@ -513,7 +516,7 @@ v8::Handle<v8::Value> CreateExternalArray(const v8::Arguments& args,
return v8::ThrowException( return v8::ThrowException(
v8::String::New("Array length must not be negative.")); v8::String::New("Array length must not be negative."));
} }
if (raw_length > v8::internal::ExternalArray::kMaxLength) { if (raw_length > kMaxLength) {
return v8::ThrowException( return v8::ThrowException(
v8::String::New("Array length exceeds maximum length.")); v8::String::New("Array length exceeds maximum length."));
} }
@ -522,7 +525,7 @@ v8::Handle<v8::Value> CreateExternalArray(const v8::Arguments& args,
return v8::ThrowException( return v8::ThrowException(
v8::String::New("Array length must be a number.")); v8::String::New("Array length must be a number."));
} }
if (length > static_cast<size_t>(v8::internal::ExternalArray::kMaxLength)) { if (length > static_cast<size_t>(kMaxLength)) {
return v8::ThrowException( return v8::ThrowException(
v8::String::New("Array length exceeds maximum length.")); v8::String::New("Array length exceeds maximum length."));
} }

33
deps/v8/src/api.cc

@ -4831,47 +4831,26 @@ void V8::RemoveMemoryAllocationCallback(MemoryAllocationCallback callback) {
void V8::PauseProfiler() { void V8::PauseProfiler() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
PauseProfilerEx(PROFILER_MODULE_CPU); i::Isolate* isolate = i::Isolate::Current();
isolate->logger()->PauseProfiler();
#endif #endif
} }
void V8::ResumeProfiler() { void V8::ResumeProfiler() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
ResumeProfilerEx(PROFILER_MODULE_CPU); i::Isolate* isolate = i::Isolate::Current();
isolate->logger()->ResumeProfiler();
#endif #endif
} }
bool V8::IsProfilerPaused() { bool V8::IsProfilerPaused() {
#ifdef ENABLE_LOGGING_AND_PROFILING
return LOGGER->GetActiveProfilerModules() & PROFILER_MODULE_CPU;
#else
return true;
#endif
}
void V8::ResumeProfilerEx(int flags, int tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
i::Isolate* isolate = i::Isolate::Current(); i::Isolate* isolate = i::Isolate::Current();
isolate->logger()->ResumeProfiler(flags, tag); return isolate->logger()->IsProfilerPaused();
#endif
}
void V8::PauseProfilerEx(int flags, int tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
LOGGER->PauseProfiler(flags, tag);
#endif
}
int V8::GetActiveProfilerModules() {
#ifdef ENABLE_LOGGING_AND_PROFILING
return LOGGER->GetActiveProfilerModules();
#else #else
return PROFILER_MODULE_NONE; return true;
#endif #endif
} }

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

@ -378,7 +378,6 @@ class Operand BASE_EMBEDDED {
INLINE(explicit Operand(int32_t immediate, INLINE(explicit Operand(int32_t immediate,
RelocInfo::Mode rmode = RelocInfo::NONE)); RelocInfo::Mode rmode = RelocInfo::NONE));
INLINE(explicit Operand(const ExternalReference& f)); INLINE(explicit Operand(const ExternalReference& f));
INLINE(explicit Operand(const char* s));
explicit Operand(Handle<Object> handle); explicit Operand(Handle<Object> handle);
INLINE(explicit Operand(Smi* value)); INLINE(explicit Operand(Smi* value));
@ -1141,8 +1140,13 @@ class Assembler : public AssemblerBase {
void jmp(Label* L) { b(L, al); } void jmp(Label* L) { b(L, al); }
// Check the code size generated from label to here. // Check the code size generated from label to here.
int InstructionsGeneratedSince(Label* l) { int SizeOfCodeGeneratedSince(Label* label) {
return (pc_offset() - l->pos()) / kInstrSize; return pc_offset() - label->pos();
}
// Check the number of instructions generated from label to here.
int InstructionsGeneratedSince(Label* label) {
return SizeOfCodeGeneratedSince(label) / kInstrSize;
} }
// Check whether an immediate fits an addressing mode 1 instruction. // Check whether an immediate fits an addressing mode 1 instruction.

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

@ -1044,8 +1044,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// Invoke the code and pass argc as r0. // Invoke the code and pass argc as r0.
__ mov(r0, Operand(r3)); __ mov(r0, Operand(r3));
if (is_construct) { if (is_construct) {
__ Call(masm->isolate()->builtins()->JSConstructCall(), __ Call(masm->isolate()->builtins()->JSConstructCall());
RelocInfo::CODE_TARGET);
} else { } else {
ParameterCount actual(r0); ParameterCount actual(r0);
__ InvokeFunction(r1, actual, CALL_FUNCTION, __ InvokeFunction(r1, actual, CALL_FUNCTION,

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

@ -392,11 +392,11 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
__ mov(scratch1, Operand(r0)); __ mov(scratch1, Operand(r0));
ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2); ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2);
__ push(lr); __ push(lr);
__ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); __ Call(stub1.GetCode());
// Write Smi from r1 to r1 and r0 in double format. // Write Smi from r1 to r1 and r0 in double format.
__ mov(scratch1, Operand(r1)); __ mov(scratch1, Operand(r1));
ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2); ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2);
__ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); __ Call(stub2.GetCode());
__ pop(lr); __ pop(lr);
} }
} }
@ -473,7 +473,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
__ mov(scratch1, Operand(object)); __ mov(scratch1, Operand(object));
ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
__ push(lr); __ push(lr);
__ Call(stub.GetCode(), RelocInfo::CODE_TARGET); __ Call(stub.GetCode());
__ pop(lr); __ pop(lr);
} }
@ -1058,7 +1058,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
// Convert lhs to a double in r2, r3. // Convert lhs to a double in r2, r3.
__ mov(r7, Operand(lhs)); __ mov(r7, Operand(lhs));
ConvertToDoubleStub stub1(r3, r2, r7, r6); ConvertToDoubleStub stub1(r3, r2, r7, r6);
__ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); __ Call(stub1.GetCode());
// Load rhs to a double in r0, r1. // Load rhs to a double in r0, r1.
__ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset)); __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset));
__ pop(lr); __ pop(lr);
@ -1100,7 +1100,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
// Convert rhs to a double in r0, r1. // Convert rhs to a double in r0, r1.
__ mov(r7, Operand(rhs)); __ mov(r7, Operand(rhs));
ConvertToDoubleStub stub2(r1, r0, r7, r6); ConvertToDoubleStub stub2(r1, r0, r7, r6);
__ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); __ Call(stub2.GetCode());
__ pop(lr); __ pop(lr);
} }
// Fall through to both_loaded_as_doubles. // Fall through to both_loaded_as_doubles.
@ -1731,22 +1731,14 @@ void UnaryOpStub::Generate(MacroAssembler* masm) {
void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
// Prepare to push argument. __ mov(r3, Operand(r0)); // the operand
__ mov(r3, Operand(r0)); __ mov(r2, Operand(Smi::FromInt(op_)));
__ mov(r1, Operand(Smi::FromInt(mode_)));
// Push this stub's key. Although the operation and the type info are
// encoded into the key, the encoding is opaque, so push them too.
__ mov(r2, Operand(Smi::FromInt(MinorKey())));
__ mov(r1, Operand(Smi::FromInt(op_)));
__ mov(r0, Operand(Smi::FromInt(operand_type_))); __ mov(r0, Operand(Smi::FromInt(operand_type_)));
__ Push(r3, r2, r1, r0); __ Push(r3, r2, r1, r0);
__ TailCallExternalReference( __ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kUnaryOp_Patch), ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
masm->isolate()),
4,
1);
} }

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

@ -60,18 +60,11 @@ class TranscendentalCacheStub: public CodeStub {
class UnaryOpStub: public CodeStub { class UnaryOpStub: public CodeStub {
public: public:
UnaryOpStub(Token::Value op, UnaryOverwriteMode mode) UnaryOpStub(Token::Value op,
UnaryOverwriteMode mode,
UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
: op_(op), : op_(op),
mode_(mode), mode_(mode),
operand_type_(UnaryOpIC::UNINITIALIZED),
name_(NULL) {
}
UnaryOpStub(
int key,
UnaryOpIC::TypeInfo operand_type)
: op_(OpBits::decode(key)),
mode_(ModeBits::decode(key)),
operand_type_(operand_type), operand_type_(operand_type),
name_(NULL) { name_(NULL) {
} }
@ -89,8 +82,7 @@ class UnaryOpStub: public CodeStub {
#ifdef DEBUG #ifdef DEBUG
void Print() { void Print() {
PrintF("UnaryOpStub %d (op %s), " PrintF("UnaryOpStub %d (op %s), (mode %d, runtime_type_info %s)\n",
"(mode %d, runtime_type_info %s)\n",
MinorKey(), MinorKey(),
Token::String(op_), Token::String(op_),
static_cast<int>(mode_), static_cast<int>(mode_),

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

@ -267,6 +267,9 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
output_ = new FrameDescription*[1]; output_ = new FrameDescription*[1];
output_[0] = new(output_frame_size) FrameDescription( output_[0] = new(output_frame_size) FrameDescription(
output_frame_size, function_); output_frame_size, function_);
#ifdef DEBUG
output_[0]->SetKind(Code::OPTIMIZED_FUNCTION);
#endif
// Clear the incoming parameters in the optimized frame to avoid // Clear the incoming parameters in the optimized frame to avoid
// confusing the garbage collector. // confusing the garbage collector.
@ -382,6 +385,9 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
// Allocate and store the output frame description. // Allocate and store the output frame description.
FrameDescription* output_frame = FrameDescription* output_frame =
new(output_frame_size) FrameDescription(output_frame_size, function); new(output_frame_size) FrameDescription(output_frame_size, function);
#ifdef DEBUG
output_frame->SetKind(Code::FUNCTION);
#endif
bool is_bottommost = (0 == frame_index); bool is_bottommost = (0 == frame_index);
bool is_topmost = (output_count_ - 1 == frame_index); bool is_topmost = (output_count_ - 1 == frame_index);
@ -516,7 +522,7 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
// Set the continuation for the topmost frame. // Set the continuation for the topmost frame.
if (is_topmost) { if (is_topmost && bailout_type_ != DEBUGGER) {
Builtins* builtins = isolate_->builtins(); Builtins* builtins = isolate_->builtins();
Code* continuation = (bailout_type_ == EAGER) Code* continuation = (bailout_type_ == EAGER)
? builtins->builtin(Builtins::kNotifyDeoptimized) ? builtins->builtin(Builtins::kNotifyDeoptimized)
@ -529,8 +535,28 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
} }
#define __ masm()-> void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
// Set the register values. The values are not important as there are no
// callee saved registers in JavaScript frames, so all registers are
// spilled. Registers fp and sp are set to the correct values though.
for (int i = 0; i < Register::kNumRegisters; i++) {
input_->SetRegister(i, i * 4);
}
input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp()));
input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) {
input_->SetDoubleRegister(i, 0.0);
}
// Fill the frame content from the actual data on the frame.
for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
input_->SetFrameSlot(i, Memory::uint32_at(tos + i));
}
}
#define __ masm()->
// This code tries to be close to ia32 code so that any changes can be // This code tries to be close to ia32 code so that any changes can be
// easily ported. // easily ported.

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

@ -92,6 +92,7 @@ class JumpPatchSite BASE_EMBEDDED {
} }
void EmitPatchInfo() { void EmitPatchInfo() {
if (patch_site_.is_bound()) {
int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
Register reg; Register reg;
reg.set_code(delta_to_patch_site / kOff12Mask); reg.set_code(delta_to_patch_site / kOff12Mask);
@ -99,9 +100,10 @@ class JumpPatchSite BASE_EMBEDDED {
#ifdef DEBUG #ifdef DEBUG
info_emitted_ = true; info_emitted_ = true;
#endif #endif
} else {
__ nop(); // Signals no inlined code.
}
} }
bool is_bound() const { return patch_site_.is_bound(); }
private: private:
MacroAssembler* masm_; MacroAssembler* masm_;
@ -129,6 +131,7 @@ class JumpPatchSite BASE_EMBEDDED {
void FullCodeGenerator::Generate(CompilationInfo* info) { void FullCodeGenerator::Generate(CompilationInfo* info) {
ASSERT(info_ == NULL); ASSERT(info_ == NULL);
info_ = info; info_ = info;
scope_ = info->scope();
SetFunctionPosition(function()); SetFunctionPosition(function());
Comment cmnt(masm_, "[ function compiled by full code generator"); Comment cmnt(masm_, "[ function compiled by full code generator");
@ -147,13 +150,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
Label ok; Label ok;
__ cmp(r5, Operand(0)); __ cmp(r5, Operand(0));
__ b(eq, &ok); __ b(eq, &ok);
int receiver_offset = scope()->num_parameters() * kPointerSize; int receiver_offset = info->scope()->num_parameters() * kPointerSize;
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex); __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ str(r2, MemOperand(sp, receiver_offset)); __ str(r2, MemOperand(sp, receiver_offset));
__ bind(&ok); __ bind(&ok);
} }
int locals_count = scope()->num_stack_slots(); int locals_count = info->scope()->num_stack_slots();
__ Push(lr, fp, cp, r1); __ Push(lr, fp, cp, r1);
if (locals_count > 0) { if (locals_count > 0) {
@ -173,7 +176,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
bool function_in_register = true; bool function_in_register = true;
// Possibly allocate a local context. // Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
if (heap_slots > 0) { if (heap_slots > 0) {
Comment cmnt(masm_, "[ Allocate local context"); Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is in r1. // Argument to NewContext is the function, which is in r1.
@ -189,7 +192,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// passed to us. It's saved in the stack and kept live in cp. // passed to us. It's saved in the stack and kept live in cp.
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Copy any necessary parameters into the context. // Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters(); int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot(); Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (slot != NULL && slot->type() == Slot::CONTEXT) {
@ -220,10 +223,11 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ mov(r3, r1); __ mov(r3, r1);
} }
// Receiver is just before the parameters on the caller's stack. // Receiver is just before the parameters on the caller's stack.
int offset = scope()->num_parameters() * kPointerSize; int num_parameters = info->scope()->num_parameters();
int offset = num_parameters * kPointerSize;
__ add(r2, fp, __ add(r2, fp,
Operand(StandardFrameConstants::kCallerSPOffset + offset)); Operand(StandardFrameConstants::kCallerSPOffset + offset));
__ mov(r1, Operand(Smi::FromInt(scope()->num_parameters()))); __ mov(r1, Operand(Smi::FromInt(num_parameters)));
__ Push(r3, r2, r1); __ Push(r3, r2, r1);
// Arguments to ArgumentsAccessStub: // Arguments to ArgumentsAccessStub:
@ -345,7 +349,7 @@ void FullCodeGenerator::EmitReturnSequence() {
{ Assembler::BlockConstPoolScope block_const_pool(masm_); { Assembler::BlockConstPoolScope block_const_pool(masm_);
// Here we use masm_-> instead of the __ macro to avoid the code coverage // Here we use masm_-> instead of the __ macro to avoid the code coverage
// tool from instrumenting as we rely on the code size here. // tool from instrumenting as we rely on the code size here.
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize; int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
__ RecordJSReturn(); __ RecordJSReturn();
masm_->mov(sp, fp); masm_->mov(sp, fp);
@ -786,7 +790,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ Call(ic);
// Value in r0 is ignored (declarations are statements). // Value in r0 is ignored (declarations are statements).
} }
} }
@ -860,7 +864,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// Record position before stub call for type feedback. // Record position before stub call for type feedback.
SetSourcePosition(clause->position()); SetSourcePosition(clause->position());
Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
EmitCallIC(ic, &patch_site, clause->CompareId()); __ Call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
patch_site.EmitPatchInfo();
__ cmp(r0, Operand(0)); __ cmp(r0, Operand(0));
__ b(ne, &next_test); __ b(ne, &next_test);
@ -1167,7 +1172,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
? RelocInfo::CODE_TARGET ? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT; : RelocInfo::CODE_TARGET_CONTEXT;
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, mode, AstNode::kNoNumber); __ Call(ic, mode);
} }
@ -1248,7 +1253,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
__ mov(r0, Operand(key_literal->handle())); __ mov(r0, Operand(key_literal->handle()));
Handle<Code> ic = Handle<Code> ic =
isolate()->builtins()->KeyedLoadIC_Initialize(); isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
__ jmp(done); __ jmp(done);
} }
} }
@ -1270,7 +1275,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
__ ldr(r0, GlobalObjectOperand()); __ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(var->name())); __ mov(r2, Operand(var->name()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(r0); context()->Plug(r0);
} else if (slot->type() == Slot::LOOKUP) { } else if (slot->type() == Slot::LOOKUP) {
@ -1414,7 +1419,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id()); __ Call(ic, RelocInfo::CODE_TARGET, key->id());
PrepareForBailoutForId(key->id(), NO_REGISTERS); PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else { } else {
VisitForEffect(value); VisitForEffect(value);
@ -1654,7 +1659,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
__ mov(r2, Operand(key->handle())); __ mov(r2, Operand(key->handle()));
// Call load IC. It has arguments receiver and property name r0 and r2. // Call load IC. It has arguments receiver and property name r0 and r2.
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
} }
@ -1662,7 +1667,7 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position()); SetSourcePosition(prop->position());
// Call keyed load IC. It has arguments key and receiver in r0 and r1. // Call keyed load IC. It has arguments key and receiver in r0 and r1.
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
} }
@ -1689,7 +1694,8 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
__ bind(&stub_call); __ bind(&stub_call);
BinaryOpStub stub(op, mode); BinaryOpStub stub(op, mode);
EmitCallIC(stub.GetCode(), &patch_site, expr->id()); __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
__ jmp(&done); __ jmp(&done);
__ bind(&smi_case); __ bind(&smi_case);
@ -1770,7 +1776,9 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
OverwriteMode mode) { OverwriteMode mode) {
__ pop(r1); __ pop(r1);
BinaryOpStub stub(op, mode); BinaryOpStub stub(op, mode);
EmitCallIC(stub.GetCode(), NULL, expr->id()); JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
__ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
context()->Plug(r0); context()->Plug(r0);
} }
@ -1810,7 +1818,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ Call(ic);
break; break;
} }
case KEYED_PROPERTY: { case KEYED_PROPERTY: {
@ -1823,7 +1831,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ Call(ic);
break; break;
} }
} }
@ -1847,7 +1855,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) { } else if (op == Token::INIT_CONST) {
// Like var declarations, const declarations are hoisted to function // Like var declarations, const declarations are hoisted to function
@ -1945,7 +1953,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
// If the assignment ends an initialization block, revert to fast case. // If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) { if (expr->ends_initialization_block()) {
@ -1991,7 +1999,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
// If the assignment ends an initialization block, revert to fast case. // If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) { if (expr->ends_initialization_block()) {
@ -2043,7 +2051,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = Handle<Code> ic =
isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
EmitCallIC(ic, mode, expr->id()); __ Call(ic, mode, expr->id());
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@ -2077,7 +2085,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Handle<Code> ic = Handle<Code> ic =
isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
__ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@ -2117,7 +2125,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
__ push(r1); __ push(r1);
// Push the receiver of the enclosing function and do runtime call. // Push the receiver of the enclosing function and do runtime call.
__ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize)); int receiver_offset = 2 + info_->scope()->num_parameters();
__ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize));
__ push(r1); __ push(r1);
// Push the strict mode flag. // Push the strict mode flag.
__ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
@ -2260,7 +2269,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else { } else {
// Call to a keyed property. // Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call, // For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed EmitCallIC. // for a regular property use EmitKeyedCallWithIC.
if (prop->is_synthetic()) { if (prop->is_synthetic()) {
// Do not visit the object and key subexpressions (they are shared // Do not visit the object and key subexpressions (they are shared
// by all occurrences of the same rewritten parameter). // by all occurrences of the same rewritten parameter).
@ -2278,7 +2287,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
SetSourcePosition(prop->position()); SetSourcePosition(prop->position());
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
__ ldr(r1, GlobalObjectOperand()); __ ldr(r1, GlobalObjectOperand());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
__ Push(r0, r1); // Function, receiver. __ Push(r0, r1); // Function, receiver.
@ -2669,7 +2678,7 @@ void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
// parameter count in r0. // parameter count in r0.
VisitForAccumulatorValue(args->at(0)); VisitForAccumulatorValue(args->at(0));
__ mov(r1, r0); __ mov(r1, r0);
__ mov(r0, Operand(Smi::FromInt(scope()->num_parameters()))); __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
__ CallStub(&stub); __ CallStub(&stub);
context()->Plug(r0); context()->Plug(r0);
@ -2681,7 +2690,7 @@ void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
Label exit; Label exit;
// Get the number of formal parameters. // Get the number of formal parameters.
__ mov(r0, Operand(Smi::FromInt(scope()->num_parameters()))); __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
// Check if the calling frame is an arguments adaptor frame. // Check if the calling frame is an arguments adaptor frame.
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
@ -3568,6 +3577,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
} }
void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
// Load the function into r0.
VisitForAccumulatorValue(args->at(0));
// Prepare for the test.
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
context()->PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Test for strict mode function.
__ ldr(r1, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCompilerHintsOffset));
__ tst(r1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
kSmiTagSize)));
__ b(ne, if_true);
// Test for native function.
__ tst(r1, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
__ b(ne, if_true);
// Not native or strict-mode function.
__ b(if_false);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
context()->Plug(if_true, if_false);
}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name(); Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') { if (name->length() > 0 && name->Get(0) == '_') {
@ -3600,7 +3642,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
isolate()->stub_cache()->ComputeCallInitialize(arg_count, isolate()->stub_cache()->ComputeCallInitialize(arg_count,
NOT_IN_LOOP, NOT_IN_LOOP,
mode); mode);
EmitCallIC(ic, mode, expr->id()); __ Call(ic, mode, expr->id());
// Restore context register. // Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
} else { } else {
@ -3742,7 +3784,7 @@ void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
// accumulator register r0. // accumulator register r0.
VisitForAccumulatorValue(expr->expression()); VisitForAccumulatorValue(expr->expression());
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
EmitCallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
context()->Plug(r0); context()->Plug(r0);
} }
@ -3853,7 +3895,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
BinaryOpStub stub(Token::ADD, NO_OVERWRITE); BinaryOpStub stub(Token::ADD, NO_OVERWRITE);
EmitCallIC(stub.GetCode(), &patch_site, expr->CountId()); __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
patch_site.EmitPatchInfo();
__ bind(&done); __ bind(&done);
// Store the value returned in r0. // Store the value returned in r0.
@ -3884,7 +3927,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
@ -3901,7 +3944,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
@ -3927,7 +3970,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference // Use a regular load, not a contextual load, to avoid a reference
// error. // error.
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ Call(ic);
PrepareForBailout(expr, TOS_REG); PrepareForBailout(expr, TOS_REG);
context()->Plug(r0); context()->Plug(r0);
} else if (proxy != NULL && } else if (proxy != NULL &&
@ -4126,7 +4169,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
// Record position and call the compare IC. // Record position and call the compare IC.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
Handle<Code> ic = CompareIC::GetUninitialized(op); Handle<Code> ic = CompareIC::GetUninitialized(op);
EmitCallIC(ic, &patch_site, expr->id()); __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
__ cmp(r0, Operand(0)); __ cmp(r0, Operand(0));
Split(cond, if_true, if_false, fall_through); Split(cond, if_true, if_false, fall_through);
@ -4187,70 +4231,6 @@ Register FullCodeGenerator::context_register() {
} }
void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
RelocInfo::Mode mode,
unsigned ast_id) {
ASSERT(mode == RelocInfo::CODE_TARGET ||
mode == RelocInfo::CODE_TARGET_CONTEXT);
Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
__ IncrementCounter(counters->named_load_full(), 1, r1, r2);
break;
case Code::KEYED_LOAD_IC:
__ IncrementCounter(counters->keyed_load_full(), 1, r1, r2);
break;
case Code::STORE_IC:
__ IncrementCounter(counters->named_store_full(), 1, r1, r2);
break;
case Code::KEYED_STORE_IC:
__ IncrementCounter(counters->keyed_store_full(), 1, r1, r2);
default:
break;
}
if (ast_id == kNoASTId || mode == RelocInfo::CODE_TARGET_CONTEXT) {
__ Call(ic, mode);
} else {
ASSERT(mode == RelocInfo::CODE_TARGET);
mode = RelocInfo::CODE_TARGET_WITH_ID;
__ CallWithAstId(ic, mode, ast_id);
}
}
void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
JumpPatchSite* patch_site,
unsigned ast_id) {
Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
__ IncrementCounter(counters->named_load_full(), 1, r1, r2);
break;
case Code::KEYED_LOAD_IC:
__ IncrementCounter(counters->keyed_load_full(), 1, r1, r2);
break;
case Code::STORE_IC:
__ IncrementCounter(counters->named_store_full(), 1, r1, r2);
break;
case Code::KEYED_STORE_IC:
__ IncrementCounter(counters->keyed_store_full(), 1, r1, r2);
default:
break;
}
if (ast_id == kNoASTId) {
__ Call(ic, RelocInfo::CODE_TARGET);
} else {
__ CallWithAstId(ic, RelocInfo::CODE_TARGET_WITH_ID, ast_id);
}
if (patch_site != NULL && patch_site->is_bound()) {
patch_site->EmitPatchInfo();
} else {
__ nop(); // Signals no inlined code.
}
}
void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
__ str(value, MemOperand(fp, frame_offset)); __ str(value, MemOperand(fp, frame_offset));
@ -4263,19 +4243,20 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
if (scope()->is_global_scope()) { Scope* declaration_scope = scope()->DeclarationScope();
if (declaration_scope->is_global_scope()) {
// Contexts nested in the global context have a canonical empty function // Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global // as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty // code. Pass a smi sentinel and let the runtime look up the empty
// function. // function.
__ mov(ip, Operand(Smi::FromInt(0))); __ mov(ip, Operand(Smi::FromInt(0)));
} else if (scope()->is_eval_scope()) { } else if (declaration_scope->is_eval_scope()) {
// Contexts created by a call to eval have the same closure as the // Contexts created by a call to eval have the same closure as the
// context calling eval, not the anonymous closure containing the eval // context calling eval, not the anonymous closure containing the eval
// code. Fetch it from the context. // code. Fetch it from the context.
__ ldr(ip, ContextOperand(cp, Context::CLOSURE_INDEX)); __ ldr(ip, ContextOperand(cp, Context::CLOSURE_INDEX));
} else { } else {
ASSERT(scope()->is_function_scope()); ASSERT(declaration_scope->is_function_scope());
__ ldr(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ ldr(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
} }
__ push(ip); __ push(ip);

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

@ -952,6 +952,9 @@ static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
Register backing_store = parameter_map; Register backing_store = parameter_map;
__ ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset)); __ ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
__ CheckMap(backing_store, scratch, fixed_array_map, slow_case,
DONT_DO_SMI_CHECK);
__ ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset)); __ ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
__ cmp(key, Operand(scratch)); __ cmp(key, Operand(scratch));
__ b(cs, slow_case); __ b(cs, slow_case);

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

@ -265,12 +265,6 @@ void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
} }
void LTypeofIs::PrintDataTo(StringStream* stream) {
InputAt(0)->PrintTo(stream);
stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
}
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if typeof "); stream->Add("if typeof ");
InputAt(0)->PrintTo(stream); InputAt(0)->PrintTo(stream);
@ -340,13 +334,6 @@ void LCallNew::PrintDataTo(StringStream* stream) {
} }
void LClassOfTest::PrintDataTo(StringStream* stream) {
stream->Add("= class_of_test(");
InputAt(0)->PrintTo(stream);
stream->Add(", \"%o\")", *hydrogen()->class_name());
}
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
arguments()->PrintTo(stream); arguments()->PrintTo(stream);
@ -990,18 +977,7 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
if (FLAG_stress_environments && !instr->HasEnvironment()) { if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr); instr = AssignEnvironment(instr);
} }
if (current->IsTest() && !instr->IsGoto()) {
ASSERT(instr->IsControl());
HTest* test = HTest::cast(current);
instr->set_hydrogen_value(test->value());
HBasicBlock* first = test->FirstSuccessor();
HBasicBlock* second = test->SecondSuccessor();
ASSERT(first != NULL && second != NULL);
instr->SetBranchTargets(first->block_id(), second->block_id());
} else {
instr->set_hydrogen_value(current); instr->set_hydrogen_value(current);
}
chunk_->AddInstruction(instr, current_block_); chunk_->AddInstruction(instr, current_block_);
} }
current_instruction_ = old_current; current_instruction_ = old_current;
@ -1046,80 +1022,15 @@ LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
} }
LInstruction* LChunkBuilder::DoTest(HTest* instr) { LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* v = instr->value(); HValue* v = instr->value();
if (!v->EmitAtUses()) return new LBranch(UseRegisterAtStart(v)); if (v->EmitAtUses()) {
ASSERT(!v->HasSideEffects());
if (v->IsClassOfTest()) {
HClassOfTest* compare = HClassOfTest::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
TempRegister());
} else if (v->IsCompare()) {
HCompare* compare = HCompare::cast(v);
HValue* left = compare->left();
HValue* right = compare->right();
Representation r = compare->GetInputRepresentation();
if (r.IsInteger32()) {
ASSERT(left->representation().IsInteger32());
ASSERT(right->representation().IsInteger32());
return new LCmpIDAndBranch(UseRegisterAtStart(left),
UseRegisterAtStart(right));
} else {
ASSERT(r.IsDouble());
ASSERT(left->representation().IsDouble());
ASSERT(right->representation().IsDouble());
return new LCmpIDAndBranch(UseRegisterAtStart(left),
UseRegisterAtStart(right));
}
} else if (v->IsIsSmi()) {
HIsSmi* compare = HIsSmi::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LIsSmiAndBranch(Use(compare->value()));
} else if (v->IsIsUndetectable()) {
HIsUndetectable* compare = HIsUndetectable::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()),
TempRegister());
} else if (v->IsHasInstanceType()) {
HHasInstanceType* compare = HHasInstanceType::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsHasCachedArrayIndex()) {
HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LHasCachedArrayIndexAndBranch(
UseRegisterAtStart(compare->value()));
} else if (v->IsIsNull()) {
HIsNull* compare = HIsNull::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LIsNullAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsIsObject()) {
HIsObject* compare = HIsObject::cast(v);
ASSERT(compare->value()->representation().IsTagged());
LOperand* temp = TempRegister();
return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()), temp);
} else if (v->IsCompareObjectEq()) {
HCompareObjectEq* compare = HCompareObjectEq::cast(v);
return new LCmpObjectEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
} else if (v->IsCompareConstantEq()) {
HCompareConstantEq* compare = HCompareConstantEq::cast(v);
return new LCmpConstantEqAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
} else if (v->IsIsConstructCall()) {
return new LIsConstructCallAndBranch(TempRegister());
} else if (v->IsConstant()) {
HBasicBlock* successor = HConstant::cast(v)->ToBoolean() HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
? instr->FirstSuccessor() ? instr->FirstSuccessor()
: instr->SecondSuccessor(); : instr->SecondSuccessor();
return new LGoto(successor->block_id()); return new LGoto(successor->block_id());
} else {
Abort("Undefined compare before branch");
return NULL;
} }
return new LBranch(UseRegisterAtStart(v));
} }
@ -1477,85 +1388,84 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
} }
LInstruction* LChunkBuilder::DoCompare(HCompare* instr) { LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
Token::Value op = instr->token(); Token::Value op = instr->token();
Representation r = instr->GetInputRepresentation(); Representation r = instr->GetInputRepresentation();
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
bool reversed = (op == Token::GT || op == Token::LTE);
LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1);
LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0);
LCmpT* result = new LCmpT(left, right);
return MarkAsCall(DefineFixed(result, r0), instr);
}
LInstruction* LChunkBuilder::DoCompareIDAndBranch(
HCompareIDAndBranch* instr) {
Representation r = instr->GetInputRepresentation();
if (r.IsInteger32()) { if (r.IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32());
LOperand* left = UseRegisterAtStart(instr->left()); LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right()); LOperand* right = UseRegisterAtStart(instr->right());
return DefineAsRegister(new LCmpID(left, right)); return new LCmpIDAndBranch(left, right);
} else if (r.IsDouble()) { } else {
ASSERT(r.IsDouble());
ASSERT(instr->left()->representation().IsDouble()); ASSERT(instr->left()->representation().IsDouble());
ASSERT(instr->right()->representation().IsDouble()); ASSERT(instr->right()->representation().IsDouble());
LOperand* left = UseRegisterAtStart(instr->left()); LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right()); LOperand* right = UseRegisterAtStart(instr->right());
return DefineAsRegister(new LCmpID(left, right)); return new LCmpIDAndBranch(left, right);
} else {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
bool reversed = (op == Token::GT || op == Token::LTE);
LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1);
LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0);
LCmpT* result = new LCmpT(left, right);
return MarkAsCall(DefineFixed(result, r0), instr);
} }
} }
LInstruction* LChunkBuilder::DoCompareObjectEq(HCompareObjectEq* instr) { LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
HCompareObjectEqAndBranch* instr) {
LOperand* left = UseRegisterAtStart(instr->left()); LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right()); LOperand* right = UseRegisterAtStart(instr->right());
LCmpObjectEq* result = new LCmpObjectEq(left, right); return new LCmpObjectEqAndBranch(left, right);
return DefineAsRegister(result);
} }
LInstruction* LChunkBuilder::DoCompareConstantEq( LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch(
HCompareConstantEq* instr) { HCompareConstantEqAndBranch* instr) {
LOperand* left = UseRegisterAtStart(instr->value()); return new LCmpConstantEqAndBranch(UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LCmpConstantEq(left));
} }
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) { LInstruction* LChunkBuilder::DoIsNullAndBranch(HIsNullAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value()); return new LIsNullAndBranch(UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LIsNull(value));
} }
LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) { LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value()); LOperand* temp = TempRegister();
return new LIsObjectAndBranch(UseRegisterAtStart(instr->value()), temp);
return DefineAsRegister(new LIsObject(value));
} }
LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseAtStart(instr->value()); return new LIsSmiAndBranch(Use(instr->value()));
return DefineAsRegister(new LIsSmi(value));
} }
LInstruction* LChunkBuilder::DoIsUndetectable(HIsUndetectable* instr) { LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
HIsUndetectableAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value()); return new LIsUndetectableAndBranch(UseRegisterAtStart(instr->value()),
TempRegister());
return DefineAsRegister(new LIsUndetectable(value));
} }
LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) { LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
HHasInstanceTypeAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value()); return new LHasInstanceTypeAndBranch(UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LHasInstanceType(value));
} }
@ -1568,19 +1478,19 @@ LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
} }
LInstruction* LChunkBuilder::DoHasCachedArrayIndex( LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
HHasCachedArrayIndex* instr) { HHasCachedArrayIndexAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegister(instr->value()); return new LHasCachedArrayIndexAndBranch(
UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LHasCachedArrayIndex(value));
} }
LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) { LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
HClassOfTestAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseTempRegister(instr->value()); return new LClassOfTestAndBranch(UseTempRegister(instr->value()),
return DefineSameAsFirst(new LClassOfTest(value)); TempRegister());
} }
@ -2169,13 +2079,14 @@ LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
} }
LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) { LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value()))); return new LTypeofIsAndBranch(UseTempRegister(instr->value()));
} }
LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) { LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
return DefineAsRegister(new LIsConstructCall()); HIsConstructCallAndBranch* instr) {
return new LIsConstructCallAndBranch(TempRegister());
} }

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

@ -77,13 +77,9 @@ class LCodeGen;
V(ClampDToUint8) \ V(ClampDToUint8) \
V(ClampIToUint8) \ V(ClampIToUint8) \
V(ClampTToUint8) \ V(ClampTToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \ V(ClassOfTestAndBranch) \
V(CmpConstantEq) \
V(CmpConstantEqAndBranch) \ V(CmpConstantEqAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \ V(CmpIDAndBranch) \
V(CmpObjectEq) \
V(CmpObjectEqAndBranch) \ V(CmpObjectEqAndBranch) \
V(CmpMapAndBranch) \ V(CmpMapAndBranch) \
V(CmpT) \ V(CmpT) \
@ -103,9 +99,7 @@ class LCodeGen;
V(GlobalObject) \ V(GlobalObject) \
V(GlobalReceiver) \ V(GlobalReceiver) \
V(Goto) \ V(Goto) \
V(HasCachedArrayIndex) \
V(HasCachedArrayIndexAndBranch) \ V(HasCachedArrayIndexAndBranch) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \ V(HasInstanceTypeAndBranch) \
V(In) \ V(In) \
V(InstanceOf) \ V(InstanceOf) \
@ -113,15 +107,10 @@ class LCodeGen;
V(InstructionGap) \ V(InstructionGap) \
V(Integer32ToDouble) \ V(Integer32ToDouble) \
V(InvokeFunction) \ V(InvokeFunction) \
V(IsConstructCall) \
V(IsConstructCallAndBranch) \ V(IsConstructCallAndBranch) \
V(IsNull) \
V(IsNullAndBranch) \ V(IsNullAndBranch) \
V(IsObject) \
V(IsObjectAndBranch) \ V(IsObjectAndBranch) \
V(IsSmi) \
V(IsSmiAndBranch) \ V(IsSmiAndBranch) \
V(IsUndetectable) \
V(IsUndetectableAndBranch) \ V(IsUndetectableAndBranch) \
V(JSArrayLength) \ V(JSArrayLength) \
V(Label) \ V(Label) \
@ -173,7 +162,6 @@ class LCodeGen;
V(Throw) \ V(Throw) \
V(ToFastProperties) \ V(ToFastProperties) \
V(Typeof) \ V(Typeof) \
V(TypeofIs) \
V(TypeofIsAndBranch) \ V(TypeofIsAndBranch) \
V(UnaryMathOperation) \ V(UnaryMathOperation) \
V(UnknownOSRValue) \ V(UnknownOSRValue) \
@ -232,7 +220,6 @@ class LInstruction: public ZoneObject {
virtual bool IsGap() const { return false; } virtual bool IsGap() const { return false; }
virtual bool IsControl() const { return false; } virtual bool IsControl() const { return false; }
virtual void SetBranchTargets(int true_block_id, int false_block_id) { }
void set_environment(LEnvironment* env) { environment_ = env; } void set_environment(LEnvironment* env) { environment_ = env; }
LEnvironment* environment() const { return environment_; } LEnvironment* environment() const { return environment_; }
@ -456,16 +443,15 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> {
public: public:
virtual bool IsControl() const { return true; } virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; } int SuccessorCount() { return hydrogen()->SuccessorCount(); }
int false_block_id() const { return false_block_id_; } HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
void SetBranchTargets(int true_block_id, int false_block_id) { int true_block_id() { return hydrogen()->SuccessorAt(0)->block_id(); }
true_block_id_ = true_block_id; int false_block_id() { return hydrogen()->SuccessorAt(1)->block_id(); }
false_block_id_ = false_block_id;
}
private: private:
int true_block_id_; HControlInstruction* hydrogen() {
int false_block_id_; return HControlInstruction::cast(this->hydrogen_value());
}
}; };
@ -581,23 +567,6 @@ class LMulI: public LTemplateInstruction<1, 2, 1> {
}; };
class LCmpID: public LTemplateInstruction<1, 2, 0> {
public:
LCmpID(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
DECLARE_CONCRETE_INSTRUCTION(CmpID, "cmp-id")
DECLARE_HYDROGEN_ACCESSOR(Compare)
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const {
return hydrogen()->GetInputRepresentation().IsDouble();
}
};
class LCmpIDAndBranch: public LControlInstruction<2, 0> { class LCmpIDAndBranch: public LControlInstruction<2, 0> {
public: public:
LCmpIDAndBranch(LOperand* left, LOperand* right) { LCmpIDAndBranch(LOperand* left, LOperand* right) {
@ -606,7 +575,7 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch") DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
DECLARE_HYDROGEN_ACCESSOR(Compare) DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch)
Token::Value op() const { return hydrogen()->token(); } Token::Value op() const { return hydrogen()->token(); }
bool is_double() const { bool is_double() const {
@ -632,17 +601,6 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> {
}; };
class LCmpObjectEq: public LTemplateInstruction<1, 2, 0> {
public:
LCmpObjectEq(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
DECLARE_CONCRETE_INSTRUCTION(CmpObjectEq, "cmp-object-eq")
};
class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
public: public:
LCmpObjectEqAndBranch(LOperand* left, LOperand* right) { LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
@ -652,17 +610,7 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch,
"cmp-object-eq-and-branch") "cmp-object-eq-and-branch")
}; DECLARE_HYDROGEN_ACCESSOR(CompareObjectEqAndBranch)
class LCmpConstantEq: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCmpConstantEq(LOperand* left) {
inputs_[0] = left;
}
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEq, "cmp-constant-eq")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
}; };
@ -674,22 +622,10 @@ class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch, DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
"cmp-constant-eq-and-branch") "cmp-constant-eq-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq) DECLARE_HYDROGEN_ACCESSOR(CompareConstantEqAndBranch)
}; };
class LIsNull: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsNull(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsNull, "is-null")
DECLARE_HYDROGEN_ACCESSOR(IsNull)
bool is_strict() const { return hydrogen()->is_strict(); }
};
class LIsNullAndBranch: public LControlInstruction<1, 0> { class LIsNullAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LIsNullAndBranch(LOperand* value) { explicit LIsNullAndBranch(LOperand* value) {
@ -697,7 +633,7 @@ class LIsNullAndBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsNull) DECLARE_HYDROGEN_ACCESSOR(IsNullAndBranch)
bool is_strict() const { return hydrogen()->is_strict(); } bool is_strict() const { return hydrogen()->is_strict(); }
@ -705,16 +641,6 @@ class LIsNullAndBranch: public LControlInstruction<1, 0> {
}; };
class LIsObject: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsObject(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object")
};
class LIsObjectAndBranch: public LControlInstruction<1, 1> { class LIsObjectAndBranch: public LControlInstruction<1, 1> {
public: public:
LIsObjectAndBranch(LOperand* value, LOperand* temp) { LIsObjectAndBranch(LOperand* value, LOperand* temp) {
@ -723,22 +649,12 @@ class LIsObjectAndBranch: public LControlInstruction<1, 1> {
} }
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
class LIsSmi: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsSmi(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is-smi")
DECLARE_HYDROGEN_ACCESSOR(IsSmi)
};
class LIsSmiAndBranch: public LControlInstruction<1, 0> { class LIsSmiAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LIsSmiAndBranch(LOperand* value) { explicit LIsSmiAndBranch(LOperand* value) {
@ -746,22 +662,12 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
class LIsUndetectable: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsUndetectable(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsUndetectable, "is-undetectable")
DECLARE_HYDROGEN_ACCESSOR(IsUndetectable)
};
class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { class LIsUndetectableAndBranch: public LControlInstruction<1, 1> {
public: public:
explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) { explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) {
@ -771,22 +677,12 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> {
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch,
"is-undetectable-and-branch") "is-undetectable-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
class LHasInstanceType: public LTemplateInstruction<1, 1, 0> {
public:
explicit LHasInstanceType(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(HasInstanceType, "has-instance-type")
DECLARE_HYDROGEN_ACCESSOR(HasInstanceType)
};
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> { class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LHasInstanceTypeAndBranch(LOperand* value) { explicit LHasInstanceTypeAndBranch(LOperand* value) {
@ -795,7 +691,7 @@ class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch, DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
"has-instance-type-and-branch") "has-instance-type-and-branch")
DECLARE_HYDROGEN_ACCESSOR(HasInstanceType) DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -812,17 +708,6 @@ class LGetCachedArrayIndex: public LTemplateInstruction<1, 1, 0> {
}; };
class LHasCachedArrayIndex: public LTemplateInstruction<1, 1, 0> {
public:
explicit LHasCachedArrayIndex(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has-cached-array-index")
DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndex)
};
class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> { class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LHasCachedArrayIndexAndBranch(LOperand* value) { explicit LHasCachedArrayIndexAndBranch(LOperand* value) {
@ -831,18 +716,7 @@ class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> {
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch, DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
"has-cached-array-index-and-branch") "has-cached-array-index-and-branch")
virtual void PrintDataTo(StringStream* stream); DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
};
class LClassOfTest: public LTemplateInstruction<1, 1, 0> {
public:
explicit LClassOfTest(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTest)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -857,7 +731,7 @@ class LClassOfTestAndBranch: public LControlInstruction<1, 1> {
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch,
"class-of-test-and-branch") "class-of-test-and-branch")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTest) DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -871,7 +745,7 @@ class LCmpT: public LTemplateInstruction<1, 2, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t") DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
DECLARE_HYDROGEN_ACCESSOR(Compare) DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
Token::Value op() const { return hydrogen()->token(); } Token::Value op() const { return hydrogen()->token(); }
}; };
@ -1000,7 +874,7 @@ class LBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
DECLARE_HYDROGEN_ACCESSOR(Value) DECLARE_HYDROGEN_ACCESSOR(Branch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -1979,21 +1853,6 @@ class LTypeof: public LTemplateInstruction<1, 1, 0> {
}; };
class LTypeofIs: public LTemplateInstruction<1, 1, 0> {
public:
explicit LTypeofIs(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(TypeofIs, "typeof-is")
DECLARE_HYDROGEN_ACCESSOR(TypeofIs)
Handle<String> type_literal() { return hydrogen()->type_literal(); }
virtual void PrintDataTo(StringStream* stream);
};
class LTypeofIsAndBranch: public LControlInstruction<1, 0> { class LTypeofIsAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LTypeofIsAndBranch(LOperand* value) { explicit LTypeofIsAndBranch(LOperand* value) {
@ -2001,7 +1860,7 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch") DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch")
DECLARE_HYDROGEN_ACCESSOR(TypeofIs) DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch)
Handle<String> type_literal() { return hydrogen()->type_literal(); } Handle<String> type_literal() { return hydrogen()->type_literal(); }
@ -2009,13 +1868,6 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> {
}; };
class LIsConstructCall: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(IsConstructCall, "is-construct-call")
DECLARE_HYDROGEN_ACCESSOR(IsConstructCall)
};
class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { class LIsConstructCallAndBranch: public LControlInstruction<0, 1> {
public: public:
explicit LIsConstructCallAndBranch(LOperand* temp) { explicit LIsConstructCallAndBranch(LOperand* temp) {

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

@ -1531,7 +1531,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id());
Representation r = instr->hydrogen()->representation(); Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32()) { if (r.IsInteger32()) {
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
__ cmp(reg, Operand(0)); __ cmp(reg, Operand(0));
@ -1547,7 +1547,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
} else { } else {
ASSERT(r.IsTagged()); ASSERT(r.IsTagged());
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
if (instr->hydrogen()->type().IsBoolean()) { if (instr->hydrogen()->value()->type().IsBoolean()) {
__ LoadRoot(ip, Heap::kTrueValueRootIndex); __ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(reg, ip); __ cmp(reg, ip);
EmitBranch(true_block, false_block, eq); EmitBranch(true_block, false_block, eq);
@ -1645,34 +1645,6 @@ void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
} }
void LCodeGen::DoCmpID(LCmpID* instr) {
LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1);
LOperand* result = instr->result();
Register scratch = scratch0();
Label unordered, done;
if (instr->is_double()) {
// Compare left and right as doubles and load the
// resulting flags into the normal status register.
__ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right));
// If a NaN is involved, i.e. the result is unordered (V set),
// jump to unordered to return false.
__ b(vs, &unordered);
} else {
EmitCmpI(left, right);
}
Condition cc = TokenToCondition(instr->op(), instr->is_double());
__ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex);
__ b(cc, &done);
__ bind(&unordered);
__ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
LOperand* left = instr->InputAt(0); LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1); LOperand* right = instr->InputAt(1);
@ -1695,17 +1667,6 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
} }
void LCodeGen::DoCmpObjectEq(LCmpObjectEq* instr) {
Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1));
Register result = ToRegister(instr->result());
__ cmp(left, Operand(right));
__ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
__ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
}
void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
Register left = ToRegister(instr->InputAt(0)); Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1)); Register right = ToRegister(instr->InputAt(1));
@ -1717,17 +1678,6 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
} }
void LCodeGen::DoCmpConstantEq(LCmpConstantEq* instr) {
Register left = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label done;
__ cmp(left, Operand(instr->hydrogen()->right()));
__ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
__ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
}
void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
Register left = ToRegister(instr->InputAt(0)); Register left = ToRegister(instr->InputAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
@ -1738,39 +1688,6 @@ void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
} }
void LCodeGen::DoIsNull(LIsNull* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
__ LoadRoot(ip, Heap::kNullValueRootIndex);
__ cmp(reg, ip);
if (instr->is_strict()) {
__ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
__ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
} else {
Label true_value, false_value, done;
__ b(eq, &true_value);
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(ip, reg);
__ b(eq, &true_value);
__ JumpIfSmi(reg, &false_value);
// Check for undetectable objects by looking in the bit field in
// the map. The object has already been smi checked.
Register scratch = result;
__ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
__ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
__ tst(scratch, Operand(1 << Map::kIsUndetectable));
__ b(ne, &true_value);
__ bind(&false_value);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ jmp(&done);
__ bind(&true_value);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
}
void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
Register scratch = scratch0(); Register scratch = scratch0();
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
@ -1830,25 +1747,6 @@ Condition LCodeGen::EmitIsObject(Register input,
} }
void LCodeGen::DoIsObject(LIsObject* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label is_false, is_true, done;
Condition true_cond = EmitIsObject(reg, result, &is_false, &is_true);
__ b(true_cond, &is_true);
__ bind(&is_false);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ b(&done);
__ bind(&is_true);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
Register temp1 = ToRegister(instr->TempAt(0)); Register temp1 = ToRegister(instr->TempAt(0));
@ -1866,18 +1764,6 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
} }
void LCodeGen::DoIsSmi(LIsSmi* instr) {
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
Register result = ToRegister(instr->result());
Register input_reg = EmitLoadRegister(instr->InputAt(0), ip);
Label done;
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ JumpIfSmi(input_reg, &done);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id());
@ -1888,25 +1774,6 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
} }
void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
Label false_label, done;
__ JumpIfSmi(input, &false_label);
__ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset));
__ ldrb(result, FieldMemOperand(result, Map::kBitFieldOffset));
__ tst(result, Operand(1 << Map::kIsUndetectable));
__ b(eq, &false_label);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ jmp(&done);
__ bind(&false_label);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0)); Register temp = ToRegister(instr->TempAt(0));
@ -1922,7 +1789,7 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
} }
static InstanceType TestType(HHasInstanceType* instr) { static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from(); InstanceType from = instr->from();
InstanceType to = instr->to(); InstanceType to = instr->to();
if (from == FIRST_TYPE) return to; if (from == FIRST_TYPE) return to;
@ -1931,7 +1798,7 @@ static InstanceType TestType(HHasInstanceType* instr) {
} }
static Condition BranchCondition(HHasInstanceType* instr) { static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from(); InstanceType from = instr->from();
InstanceType to = instr->to(); InstanceType to = instr->to();
if (from == to) return eq; if (from == to) return eq;
@ -1942,23 +1809,6 @@ static Condition BranchCondition(HHasInstanceType* instr) {
} }
void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
Label done;
__ tst(input, Operand(kSmiTagMask));
__ LoadRoot(result, Heap::kFalseValueRootIndex, eq);
__ b(eq, &done);
__ CompareObjectType(input, result, result, TestType(instr->hydrogen()));
Condition cond = BranchCondition(instr->hydrogen());
__ LoadRoot(result, Heap::kTrueValueRootIndex, cond);
__ LoadRoot(result, Heap::kFalseValueRootIndex, NegateCondition(cond));
__ bind(&done);
}
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Register scratch = scratch0(); Register scratch = scratch0();
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
@ -1988,20 +1838,6 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
} }
void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Register scratch = scratch0();
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
__ ldr(scratch,
FieldMemOperand(input, String::kHashFieldOffset));
__ tst(scratch, Operand(String::kContainsCachedArrayIndexMask));
__ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
__ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
}
void LCodeGen::DoHasCachedArrayIndexAndBranch( void LCodeGen::DoHasCachedArrayIndexAndBranch(
LHasCachedArrayIndexAndBranch* instr) { LHasCachedArrayIndexAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
@ -2074,27 +1910,6 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
} }
void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(input.is(result));
Handle<String> class_name = instr->hydrogen()->class_name();
Label done, is_true, is_false;
EmitClassOfTest(&is_true, &is_false, class_name, input, scratch0(), input);
__ b(ne, &is_false);
__ bind(&is_true);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ jmp(&done);
__ bind(&is_false);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
Register temp = scratch0(); Register temp = scratch0();
@ -4349,29 +4164,6 @@ void LCodeGen::DoTypeof(LTypeof* instr) {
} }
void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label true_label;
Label false_label;
Label done;
Condition final_branch_condition = EmitTypeofIs(&true_label,
&false_label,
input,
instr->type_literal());
__ b(final_branch_condition, &true_label);
__ bind(&false_label);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ b(&done);
__ bind(&true_label);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
@ -4455,26 +4247,6 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
} }
void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
Register result = ToRegister(instr->result());
Label true_label;
Label false_label;
Label done;
EmitIsConstructCall(result, scratch0());
__ b(eq, &true_label);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ b(&done);
__ bind(&true_label);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
Register temp1 = ToRegister(instr->TempAt(0)); Register temp1 = ToRegister(instr->TempAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());

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

@ -91,7 +91,7 @@ void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
} }
void MacroAssembler::Jump(byte* target, RelocInfo::Mode rmode, void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode,
Condition cond) { Condition cond) {
ASSERT(!RelocInfo::IsCodeTarget(rmode)); ASSERT(!RelocInfo::IsCodeTarget(rmode));
Jump(reinterpret_cast<intptr_t>(target), rmode, cond); Jump(reinterpret_cast<intptr_t>(target), rmode, cond);
@ -118,10 +118,8 @@ int MacroAssembler::CallSize(Register target, Condition cond) {
void MacroAssembler::Call(Register target, Condition cond) { void MacroAssembler::Call(Register target, Condition cond) {
// Block constant pool for the call instruction sequence. // Block constant pool for the call instruction sequence.
BlockConstPoolScope block_const_pool(this); BlockConstPoolScope block_const_pool(this);
#ifdef DEBUG Label start;
int pre_position = pc_offset(); bind(&start);
#endif
#if USE_BLX #if USE_BLX
blx(target, cond); blx(target, cond);
#else #else
@ -129,34 +127,29 @@ void MacroAssembler::Call(Register target, Condition cond) {
mov(lr, Operand(pc), LeaveCC, cond); mov(lr, Operand(pc), LeaveCC, cond);
mov(pc, Operand(target), LeaveCC, cond); mov(pc, Operand(target), LeaveCC, cond);
#endif #endif
ASSERT_EQ(CallSize(target, cond), SizeOfCodeGeneratedSince(&start));
#ifdef DEBUG
int post_position = pc_offset();
CHECK_EQ(pre_position + CallSize(target, cond), post_position);
#endif
} }
int MacroAssembler::CallSize( int MacroAssembler::CallSize(
intptr_t target, RelocInfo::Mode rmode, Condition cond) { Address target, RelocInfo::Mode rmode, Condition cond) {
int size = 2 * kInstrSize; int size = 2 * kInstrSize;
Instr mov_instr = cond | MOV | LeaveCC; Instr mov_instr = cond | MOV | LeaveCC;
if (!Operand(target, rmode).is_single_instruction(mov_instr)) { intptr_t immediate = reinterpret_cast<intptr_t>(target);
if (!Operand(immediate, rmode).is_single_instruction(mov_instr)) {
size += kInstrSize; size += kInstrSize;
} }
return size; return size;
} }
void MacroAssembler::Call(intptr_t target, void MacroAssembler::Call(Address target,
RelocInfo::Mode rmode, RelocInfo::Mode rmode,
Condition cond) { Condition cond) {
// Block constant pool for the call instruction sequence. // Block constant pool for the call instruction sequence.
BlockConstPoolScope block_const_pool(this); BlockConstPoolScope block_const_pool(this);
#ifdef DEBUG Label start;
int pre_position = pc_offset(); bind(&start);
#endif
#if USE_BLX #if USE_BLX
// On ARMv5 and after the recommended call sequence is: // On ARMv5 and after the recommended call sequence is:
// ldr ip, [pc, #...] // ldr ip, [pc, #...]
@ -168,7 +161,7 @@ void MacroAssembler::Call(intptr_t target,
// we have to do it explicitly. // we have to do it explicitly.
positions_recorder()->WriteRecordedPositions(); positions_recorder()->WriteRecordedPositions();
mov(ip, Operand(target, rmode)); mov(ip, Operand(reinterpret_cast<int32_t>(target), rmode));
blx(ip, cond); blx(ip, cond);
ASSERT(kCallTargetAddressOffset == 2 * kInstrSize); ASSERT(kCallTargetAddressOffset == 2 * kInstrSize);
@ -176,82 +169,36 @@ void MacroAssembler::Call(intptr_t target,
// Set lr for return at current pc + 8. // Set lr for return at current pc + 8.
mov(lr, Operand(pc), LeaveCC, cond); mov(lr, Operand(pc), LeaveCC, cond);
// Emit a ldr<cond> pc, [pc + offset of target in constant pool]. // Emit a ldr<cond> pc, [pc + offset of target in constant pool].
mov(pc, Operand(target, rmode), LeaveCC, cond); mov(pc, Operand(reinterpret_cast<int32_t>(target), rmode), LeaveCC, cond);
ASSERT(kCallTargetAddressOffset == kInstrSize); ASSERT(kCallTargetAddressOffset == kInstrSize);
#endif #endif
ASSERT_EQ(CallSize(target, rmode, cond), SizeOfCodeGeneratedSince(&start));
#ifdef DEBUG
int post_position = pc_offset();
CHECK_EQ(pre_position + CallSize(target, rmode, cond), post_position);
#endif
}
int MacroAssembler::CallSize(
byte* target, RelocInfo::Mode rmode, Condition cond) {
return CallSize(reinterpret_cast<intptr_t>(target), rmode);
}
void MacroAssembler::Call(
byte* target, RelocInfo::Mode rmode, Condition cond) {
#ifdef DEBUG
int pre_position = pc_offset();
#endif
ASSERT(!RelocInfo::IsCodeTarget(rmode));
Call(reinterpret_cast<intptr_t>(target), rmode, cond);
#ifdef DEBUG
int post_position = pc_offset();
CHECK_EQ(pre_position + CallSize(target, rmode, cond), post_position);
#endif
} }
int MacroAssembler::CallSize( int MacroAssembler::CallSize(Handle<Code> code,
Handle<Code> code, RelocInfo::Mode rmode, Condition cond) {
return CallSize(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
}
void MacroAssembler::CallWithAstId(Handle<Code> code,
RelocInfo::Mode rmode, RelocInfo::Mode rmode,
unsigned ast_id, unsigned ast_id,
Condition cond) { Condition cond) {
#ifdef DEBUG return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond);
int pre_position = pc_offset();
#endif
ASSERT(rmode == RelocInfo::CODE_TARGET_WITH_ID);
ASSERT(ast_id != kNoASTId);
ASSERT(ast_id_for_reloc_info_ == kNoASTId);
ast_id_for_reloc_info_ = ast_id;
// 'code' is always generated ARM code, never THUMB code
Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
#ifdef DEBUG
int post_position = pc_offset();
CHECK_EQ(pre_position + CallSize(code, rmode, cond), post_position);
#endif
} }
void MacroAssembler::Call(Handle<Code> code, void MacroAssembler::Call(Handle<Code> code,
RelocInfo::Mode rmode, RelocInfo::Mode rmode,
unsigned ast_id,
Condition cond) { Condition cond) {
#ifdef DEBUG Label start;
int pre_position = pc_offset(); bind(&start);
#endif
ASSERT(RelocInfo::IsCodeTarget(rmode)); ASSERT(RelocInfo::IsCodeTarget(rmode));
if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) {
ASSERT(ast_id_for_reloc_info_ == kNoASTId);
ast_id_for_reloc_info_ = ast_id;
rmode = RelocInfo::CODE_TARGET_WITH_ID;
}
// 'code' is always generated ARM code, never THUMB code // 'code' is always generated ARM code, never THUMB code
Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond); Call(reinterpret_cast<Address>(code.location()), rmode, cond);
ASSERT_EQ(CallSize(code, rmode, cond), SizeOfCodeGeneratedSince(&start));
#ifdef DEBUG
int post_position = pc_offset();
CHECK_EQ(pre_position + CallSize(code, rmode, cond), post_position);
#endif
} }
@ -994,9 +941,9 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Handle<Code> adaptor = Handle<Code> adaptor =
isolate()->builtins()->ArgumentsAdaptorTrampoline(); isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (flag == CALL_FUNCTION) { if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET)); call_wrapper.BeforeCall(CallSize(adaptor));
SetCallKind(r5, call_kind); SetCallKind(r5, call_kind);
Call(adaptor, RelocInfo::CODE_TARGET); Call(adaptor);
call_wrapper.AfterCall(); call_wrapper.AfterCall();
b(done); b(done);
} else { } else {
@ -1719,7 +1666,7 @@ void MacroAssembler::CheckFastElements(Register map,
Register scratch, Register scratch,
Label* fail) { Label* fail) {
STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue)); cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue));
b(hi, fail); b(hi, fail);
} }

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

@ -90,19 +90,19 @@ class MacroAssembler: public Assembler {
// Jump, Call, and Ret pseudo instructions implementing inter-working. // Jump, Call, and Ret pseudo instructions implementing inter-working.
void Jump(Register target, Condition cond = al); void Jump(Register target, Condition cond = al);
void Jump(byte* target, RelocInfo::Mode rmode, Condition cond = al); void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al); void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
int CallSize(Register target, Condition cond = al); int CallSize(Register target, Condition cond = al);
void Call(Register target, Condition cond = al); void Call(Register target, Condition cond = al);
int CallSize(byte* target, RelocInfo::Mode rmode, Condition cond = al); int CallSize(Address target, RelocInfo::Mode rmode, Condition cond = al);
void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al); void Call(Address target, RelocInfo::Mode rmode, Condition cond = al);
int CallSize(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al); int CallSize(Handle<Code> code,
void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
RelocInfo::Mode rmode, unsigned ast_id = kNoASTId,
Condition cond = al); Condition cond = al);
void CallWithAstId(Handle<Code> code, void Call(Handle<Code> code,
RelocInfo::Mode rmode, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
unsigned ast_id, unsigned ast_id = kNoASTId,
Condition cond = al); Condition cond = al);
void Ret(Condition cond = al); void Ret(Condition cond = al);
@ -1036,10 +1036,6 @@ class MacroAssembler: public Assembler {
int num_double_arguments); int num_double_arguments);
void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al); void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
int CallSize(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
void Call(intptr_t target,
RelocInfo::Mode rmode,
Condition cond = al);
// Helper functions for generating invokes. // Helper functions for generating invokes.
void InvokePrologue(const ParameterCount& expected, void InvokePrologue(const ParameterCount& expected,

15
deps/v8/src/array.js

@ -742,14 +742,15 @@ function ArraySort(comparefn) {
else return x < y ? -1 : 1; else return x < y ? -1 : 1;
}; };
} }
var global_receiver = %GetGlobalReceiver(); var receiver =
%_IsNativeOrStrictMode(comparefn) ? void 0 : %GetGlobalReceiver();
function InsertionSort(a, from, to) { function InsertionSort(a, from, to) {
for (var i = from + 1; i < to; i++) { for (var i = from + 1; i < to; i++) {
var element = a[i]; var element = a[i];
for (var j = i - 1; j >= from; j--) { for (var j = i - 1; j >= from; j--) {
var tmp = a[j]; var tmp = a[j];
var order = %_CallFunction(global_receiver, tmp, element, comparefn); var order = %_CallFunction(receiver, tmp, element, comparefn);
if (order > 0) { if (order > 0) {
a[j + 1] = tmp; a[j + 1] = tmp;
} else { } else {
@ -771,14 +772,14 @@ function ArraySort(comparefn) {
var v1 = a[to - 1]; var v1 = a[to - 1];
var middle_index = from + ((to - from) >> 1); var middle_index = from + ((to - from) >> 1);
var v2 = a[middle_index]; var v2 = a[middle_index];
var c01 = %_CallFunction(global_receiver, v0, v1, comparefn); var c01 = %_CallFunction(receiver, v0, v1, comparefn);
if (c01 > 0) { if (c01 > 0) {
// v1 < v0, so swap them. // v1 < v0, so swap them.
var tmp = v0; var tmp = v0;
v0 = v1; v0 = v1;
v1 = tmp; v1 = tmp;
} // v0 <= v1. } // v0 <= v1.
var c02 = %_CallFunction(global_receiver, v0, v2, comparefn); var c02 = %_CallFunction(receiver, v0, v2, comparefn);
if (c02 >= 0) { if (c02 >= 0) {
// v2 <= v0 <= v1. // v2 <= v0 <= v1.
var tmp = v0; var tmp = v0;
@ -787,7 +788,7 @@ function ArraySort(comparefn) {
v1 = tmp; v1 = tmp;
} else { } else {
// v0 <= v1 && v0 < v2 // v0 <= v1 && v0 < v2
var c12 = %_CallFunction(global_receiver, v1, v2, comparefn); var c12 = %_CallFunction(receiver, v1, v2, comparefn);
if (c12 > 0) { if (c12 > 0) {
// v0 <= v2 < v1 // v0 <= v2 < v1
var tmp = v1; var tmp = v1;
@ -808,7 +809,7 @@ function ArraySort(comparefn) {
// From i to high_start are elements that haven't been compared yet. // From i to high_start are elements that haven't been compared yet.
partition: for (var i = low_end + 1; i < high_start; i++) { partition: for (var i = low_end + 1; i < high_start; i++) {
var element = a[i]; var element = a[i];
var order = %_CallFunction(global_receiver, element, pivot, comparefn); var order = %_CallFunction(receiver, element, pivot, comparefn);
if (order < 0) { if (order < 0) {
%_SwapElements(a, i, low_end); %_SwapElements(a, i, low_end);
low_end++; low_end++;
@ -817,7 +818,7 @@ function ArraySort(comparefn) {
high_start--; high_start--;
if (high_start == i) break partition; if (high_start == i) break partition;
var top_elem = a[high_start]; var top_elem = a[high_start];
order = %_CallFunction(global_receiver, top_elem, pivot, comparefn); order = %_CallFunction(receiver, top_elem, pivot, comparefn);
} while (order > 0); } while (order > 0);
%_SwapElements(a, i, high_start); %_SwapElements(a, i, high_start);
if (order < 0) { if (order < 0) {

14
deps/v8/src/ast.h

@ -772,20 +772,26 @@ class TryStatement: public Statement {
class TryCatchStatement: public TryStatement { class TryCatchStatement: public TryStatement {
public: public:
TryCatchStatement(Block* try_block, Handle<String> name, Block* catch_block) TryCatchStatement(Block* try_block,
Scope* scope,
Variable* variable,
Block* catch_block)
: TryStatement(try_block), : TryStatement(try_block),
name_(name), scope_(scope),
variable_(variable),
catch_block_(catch_block) { catch_block_(catch_block) {
} }
DECLARE_NODE_TYPE(TryCatchStatement) DECLARE_NODE_TYPE(TryCatchStatement)
Scope* scope() { return scope_; }
Variable* variable() { return variable_; }
Block* catch_block() const { return catch_block_; } Block* catch_block() const { return catch_block_; }
Handle<String> name() const { return name_; }
virtual bool IsInlineable() const; virtual bool IsInlineable() const;
private: private:
Handle<String> name_; Scope* scope_;
Variable* variable_;
Block* catch_block_; Block* catch_block_;
}; };

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

@ -52,8 +52,7 @@ CompilationCache::CompilationCache(Isolate* isolate)
eval_global_(isolate, kEvalGlobalGenerations), eval_global_(isolate, kEvalGlobalGenerations),
eval_contextual_(isolate, kEvalContextualGenerations), eval_contextual_(isolate, kEvalContextualGenerations),
reg_exp_(isolate, kRegExpGenerations), reg_exp_(isolate, kRegExpGenerations),
enabled_(true), enabled_(true) {
eager_optimizing_set_(NULL) {
CompilationSubCache* subcaches[kSubCacheCount] = CompilationSubCache* subcaches[kSubCacheCount] =
{&script_, &eval_global_, &eval_contextual_, &reg_exp_}; {&script_, &eval_global_, &eval_contextual_, &reg_exp_};
for (int i = 0; i < kSubCacheCount; ++i) { for (int i = 0; i < kSubCacheCount; ++i) {
@ -62,10 +61,7 @@ CompilationCache::CompilationCache(Isolate* isolate)
} }
CompilationCache::~CompilationCache() { CompilationCache::~CompilationCache() {}
delete eager_optimizing_set_;
eager_optimizing_set_ = NULL;
}
static Handle<CompilationCacheTable> AllocateTable(Isolate* isolate, int size) { static Handle<CompilationCacheTable> AllocateTable(Isolate* isolate, int size) {
@ -457,47 +453,6 @@ void CompilationCache::PutRegExp(Handle<String> source,
} }
static bool SourceHashCompare(void* key1, void* key2) {
return key1 == key2;
}
HashMap* CompilationCache::EagerOptimizingSet() {
if (eager_optimizing_set_ == NULL) {
eager_optimizing_set_ = new HashMap(&SourceHashCompare);
}
return eager_optimizing_set_;
}
bool CompilationCache::ShouldOptimizeEagerly(Handle<JSFunction> function) {
if (FLAG_opt_eagerly) return true;
uint32_t hash = function->SourceHash();
void* key = reinterpret_cast<void*>(hash);
return EagerOptimizingSet()->Lookup(key, hash, false) != NULL;
}
void CompilationCache::MarkForEagerOptimizing(Handle<JSFunction> function) {
uint32_t hash = function->SourceHash();
void* key = reinterpret_cast<void*>(hash);
EagerOptimizingSet()->Lookup(key, hash, true);
}
void CompilationCache::MarkForLazyOptimizing(Handle<JSFunction> function) {
uint32_t hash = function->SourceHash();
void* key = reinterpret_cast<void*>(hash);
EagerOptimizingSet()->Remove(key, hash);
}
void CompilationCache::ResetEagerOptimizingData() {
HashMap* set = EagerOptimizingSet();
if (set->occupancy() > 0) set->Clear();
}
void CompilationCache::Clear() { void CompilationCache::Clear() {
for (int i = 0; i < kSubCacheCount; i++) { for (int i = 0; i < kSubCacheCount; i++) {
subcaches_[i]->Clear(); subcaches_[i]->Clear();

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

@ -223,14 +223,6 @@ class CompilationCache {
JSRegExp::Flags flags, JSRegExp::Flags flags,
Handle<FixedArray> data); Handle<FixedArray> data);
// Support for eager optimization tracking.
bool ShouldOptimizeEagerly(Handle<JSFunction> function);
void MarkForEagerOptimizing(Handle<JSFunction> function);
void MarkForLazyOptimizing(Handle<JSFunction> function);
// Reset the eager optimization tracking data.
void ResetEagerOptimizingData();
// Clear the cache - also used to initialize the cache at startup. // Clear the cache - also used to initialize the cache at startup.
void Clear(); void Clear();
@ -274,8 +266,6 @@ class CompilationCache {
// Current enable state of the compilation cache. // Current enable state of the compilation cache.
bool enabled_; bool enabled_;
HashMap* eager_optimizing_set_;
friend class Isolate; friend class Isolate;
DISALLOW_COPY_AND_ASSIGN(CompilationCache); DISALLOW_COPY_AND_ASSIGN(CompilationCache);

14
deps/v8/src/compiler.cc

@ -109,8 +109,6 @@ void CompilationInfo::DisableOptimization() {
void CompilationInfo::AbortOptimization() { void CompilationInfo::AbortOptimization() {
Handle<Code> code(shared_info()->code()); Handle<Code> code(shared_info()->code());
SetCode(code); SetCode(code);
Isolate* isolate = code->GetIsolate();
isolate->compilation_cache()->MarkForLazyOptimizing(closure());
} }
@ -413,7 +411,8 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
String::cast(script->name()))); String::cast(script->name())));
GDBJIT(AddCode(Handle<String>(String::cast(script->name())), GDBJIT(AddCode(Handle<String>(String::cast(script->name())),
script, script,
info->code())); info->code(),
info));
} else { } else {
PROFILE(isolate, CodeCreateEvent( PROFILE(isolate, CodeCreateEvent(
info->is_eval() info->is_eval()
@ -422,7 +421,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
*info->code(), *info->code(),
*result, *result,
isolate->heap()->empty_string())); isolate->heap()->empty_string()));
GDBJIT(AddCode(Handle<String>(), script, info->code())); GDBJIT(AddCode(Handle<String>(), script, info->code(), info));
} }
// Hint to the runtime system used when allocating space for initial // Hint to the runtime system used when allocating space for initial
@ -618,6 +617,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared); RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
if (info->IsOptimizing()) { if (info->IsOptimizing()) {
ASSERT(shared->scope_info() != SerializedScopeInfo::Empty());
function->ReplaceCode(*code); function->ReplaceCode(*code);
} else { } else {
// Update the shared function info with the compiled code and the // Update the shared function info with the compiled code and the
@ -659,9 +659,6 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
CompilationInfo optimized(function); CompilationInfo optimized(function);
optimized.SetOptimizing(AstNode::kNoNumber); optimized.SetOptimizing(AstNode::kNoNumber);
return CompileLazy(&optimized); return CompileLazy(&optimized);
} else if (isolate->compilation_cache()->ShouldOptimizeEagerly(
function)) {
isolate->runtime_profiler()->OptimizeSoon(*function);
} }
} }
} }
@ -788,7 +785,8 @@ void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
GDBJIT(AddCode(Handle<String>(shared->DebugName()), GDBJIT(AddCode(Handle<String>(shared->DebugName()),
Handle<Script>(info->script()), Handle<Script>(info->script()),
Handle<Code>(info->code()))); Handle<Code>(info->code()),
info));
} }
} } // namespace v8::internal } } // namespace v8::internal

2
deps/v8/src/contexts.h

@ -225,7 +225,6 @@ class Context: public FixedArray {
OPAQUE_REFERENCE_FUNCTION_INDEX, OPAQUE_REFERENCE_FUNCTION_INDEX,
CONTEXT_EXTENSION_FUNCTION_INDEX, CONTEXT_EXTENSION_FUNCTION_INDEX,
OUT_OF_MEMORY_INDEX, OUT_OF_MEMORY_INDEX,
MAP_CACHE_INDEX,
CONTEXT_DATA_INDEX, CONTEXT_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX, ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
DERIVED_GET_TRAP_INDEX, DERIVED_GET_TRAP_INDEX,
@ -234,6 +233,7 @@ class Context: public FixedArray {
// Properties from here are treated as weak references by the full GC. // Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references. // Scavenge treats them as strong references.
OPTIMIZED_FUNCTIONS_LIST, // Weak. OPTIMIZED_FUNCTIONS_LIST, // Weak.
MAP_CACHE_INDEX, // Weak.
NEXT_CONTEXT_LINK, // Weak. NEXT_CONTEXT_LINK, // Weak.
// Total number of slots. // Total number of slots.

13
deps/v8/src/date.js

@ -981,7 +981,18 @@ function PadInt(n, digits) {
function DateToISOString() { function DateToISOString() {
var t = DATE_VALUE(this); var t = DATE_VALUE(this);
if (NUMBER_IS_NAN(t)) return kInvalidDate; if (NUMBER_IS_NAN(t)) return kInvalidDate;
return this.getUTCFullYear() + var year = this.getUTCFullYear();
var year_string;
if (year >= 0 && year <= 9999) {
year_string = PadInt(year, 4);
} else {
if (year < 0) {
year_string = "-" + PadInt(-year, 6);
} else {
year_string = "+" + PadInt(year, 6);
}
}
return year_string +
'-' + PadInt(this.getUTCMonth() + 1, 2) + '-' + PadInt(this.getUTCMonth() + 1, 2) +
'-' + PadInt(this.getUTCDate(), 2) + '-' + PadInt(this.getUTCDate(), 2) +
'T' + PadInt(this.getUTCHours(), 2) + 'T' + PadInt(this.getUTCHours(), 2) +

281
deps/v8/src/dateparser-inl.h

@ -39,16 +39,71 @@ bool DateParser::Parse(Vector<Char> str,
UnicodeCache* unicode_cache) { UnicodeCache* unicode_cache) {
ASSERT(out->length() >= OUTPUT_SIZE); ASSERT(out->length() >= OUTPUT_SIZE);
InputReader<Char> in(unicode_cache, str); InputReader<Char> in(unicode_cache, str);
DateStringTokenizer<Char> scanner(&in);
TimeZoneComposer tz; TimeZoneComposer tz;
TimeComposer time; TimeComposer time;
DayComposer day; DayComposer day;
while (!in.IsEnd()) { // Specification:
if (in.IsAsciiDigit()) { // Accept ES5 ISO 8601 date-time-strings or legacy dates compatible
// Parse a number (possibly with 1 or 2 trailing colons). // with Safari.
int n = in.ReadUnsignedNumber(); // ES5 ISO 8601 dates:
if (in.Skip(':')) { // [('-'|'+')yy]yyyy[-MM[-DD]][THH:mm[:ss[.sss]][Z|(+|-)hh:mm]]
if (in.Skip(':')) { // where yyyy is in the range 0000..9999 and
// +/-yyyyyy is in the range -999999..+999999 -
// but -000000 is invalid (year zero must be positive),
// MM is in the range 01..12,
// DD is in the range 01..31,
// MM and DD defaults to 01 if missing,,
// HH is generally in the range 00..23, but can be 24 if mm, ss
// and sss are zero (or missing), representing midnight at the
// end of a day,
// mm and ss are in the range 00..59,
// sss is in the range 000..999,
// hh is in the range 00..23,
// mm, ss, and sss default to 00 if missing, and
// timezone defaults to Z if missing.
// Extensions:
// We also allow sss to have more or less than three digits (but at
// least one).
// We allow hh:mm to be specified as hhmm.
// Legacy dates:
// Any unrecognized word before the first number is ignored.
// Parenthesized text is ignored.
// An unsigned number followed by ':' is a time value, and is
// added to the TimeComposer. A number followed by '::' adds a second
// zero as well. A number followed by '.' is also a time and must be
// followed by milliseconds.
// Any other number is a date component and is added to DayComposer.
// A month name (or really: any word having the same first three letters
// as a month name) is recorded as a named month in the Day composer.
// A word recognizable as a time-zone is recorded as such, as is
// '(+|-)(hhmm|hh:)'.
// Legacy dates don't allow extra signs ('+' or '-') or umatched ')'
// after a number has been read (before the first number, any garbage
// is allowed).
// Intersection of the two:
// A string that matches both formats (e.g. 1970-01-01) will be
// parsed as an ES5 date-time string - which means it will default
// to UTC time-zone. That's unavoidable if following the ES5
// specification.
// After a valid "T" has been read while scanning an ES5 datetime string,
// the input can no longer be a valid legacy date, since the "T" is a
// garbage string after a number has been read.
// First try getting as far as possible with as ES5 Date Time String.
DateToken next_unhandled_token = ParseES5DateTime(&scanner, &day, &time, &tz);
if (next_unhandled_token.IsInvalid()) return false;
bool has_read_number = !day.IsEmpty();
// If there's anything left, continue with the legacy parser.
for (DateToken token = next_unhandled_token;
!token.IsEndOfInput();
token = scanner.Next()) {
if (token.IsNumber()) {
has_read_number = true;
int n = token.number();
if (scanner.SkipSymbol(':')) {
if (scanner.SkipSymbol(':')) {
// n + "::" // n + "::"
if (!time.IsEmpty()) return false; if (!time.IsEmpty()) return false;
time.Add(n); time.Add(n);
@ -56,12 +111,13 @@ bool DateParser::Parse(Vector<Char> str,
} else { } else {
// n + ":" // n + ":"
if (!time.Add(n)) return false; if (!time.Add(n)) return false;
in.Skip('.'); if (scanner.Peek().IsSymbol('.')) scanner.Next();
} }
} else if (in.Skip('.') && time.IsExpecting(n)) { } else if (scanner.SkipSymbol('.') && time.IsExpecting(n)) {
time.Add(n); time.Add(n);
if (!in.IsAsciiDigit()) return false; if (!scanner.Peek().IsNumber()) return false;
int n = in.ReadMilliseconds(); int n = ReadMilliseconds(scanner.Next());
if (n < 0) return false;
time.AddFinal(n); time.AddFinal(n);
} else if (tz.IsExpecting(n)) { } else if (tz.IsExpecting(n)) {
tz.SetAbsoluteMinute(n); tz.SetAbsoluteMinute(n);
@ -69,59 +125,206 @@ bool DateParser::Parse(Vector<Char> str,
time.AddFinal(n); time.AddFinal(n);
// Require end, white space, "Z", "+" or "-" immediately after // Require end, white space, "Z", "+" or "-" immediately after
// finalizing time. // finalizing time.
if (!in.IsEnd() && !in.SkipWhiteSpace() && !in.Is('Z') && DateToken peek = scanner.Peek();
!in.IsAsciiSign()) return false; if (!peek.IsEndOfInput() &&
!peek.IsWhiteSpace() &&
!peek.IsKeywordZ() &&
!peek.IsAsciiSign()) return false;
} else { } else {
if (!day.Add(n)) return false; if (!day.Add(n)) return false;
in.Skip('-'); // Ignore suffix '-' for year, month, or day. scanner.SkipSymbol('-');
// Skip trailing 'T' for ECMAScript 5 date string format but make
// sure that it is followed by a digit (for the time).
if (in.Skip('T') && !in.IsAsciiDigit()) return false;
} }
} else if (in.IsAsciiAlphaOrAbove()) { } else if (token.IsKeyword()) {
// Parse a "word" (sequence of chars. >= 'A'). // Parse a "word" (sequence of chars. >= 'A').
uint32_t pre[KeywordTable::kPrefixLength]; KeywordType type = token.keyword_type();
int len = in.ReadWord(pre, KeywordTable::kPrefixLength); int value = token.keyword_value();
int index = KeywordTable::Lookup(pre, len);
KeywordType type = KeywordTable::GetType(index);
if (type == AM_PM && !time.IsEmpty()) { if (type == AM_PM && !time.IsEmpty()) {
time.SetHourOffset(KeywordTable::GetValue(index)); time.SetHourOffset(value);
} else if (type == MONTH_NAME) { } else if (type == MONTH_NAME) {
day.SetNamedMonth(KeywordTable::GetValue(index)); day.SetNamedMonth(value);
in.Skip('-'); // Ignore suffix '-' for month names scanner.SkipSymbol('-');
} else if (type == TIME_ZONE_NAME && in.HasReadNumber()) { } else if (type == TIME_ZONE_NAME && has_read_number) {
tz.Set(KeywordTable::GetValue(index)); tz.Set(value);
} else { } else {
// Garbage words are illegal if a number has been read. // Garbage words are illegal if a number has been read.
if (in.HasReadNumber()) return false; if (has_read_number) return false;
} }
} else if (in.IsAsciiSign() && (tz.IsUTC() || !time.IsEmpty())) { } else if (token.IsAsciiSign() && (tz.IsUTC() || !time.IsEmpty())) {
// Parse UTC offset (only after UTC or time). // Parse UTC offset (only after UTC or time).
tz.SetSign(in.GetAsciiSignValue()); tz.SetSign(token.ascii_sign());
in.Next(); // The following number may be empty.
int n = in.ReadUnsignedNumber(); int n = 0;
if (in.Skip(':')) { if (scanner.Peek().IsNumber()) {
n = scanner.Next().number();
}
has_read_number = true;
if (scanner.Peek().IsSymbol(':')) {
tz.SetAbsoluteHour(n); tz.SetAbsoluteHour(n);
tz.SetAbsoluteMinute(kNone); tz.SetAbsoluteMinute(kNone);
} else { } else {
tz.SetAbsoluteHour(n / 100); tz.SetAbsoluteHour(n / 100);
tz.SetAbsoluteMinute(n % 100); tz.SetAbsoluteMinute(n % 100);
} }
} else if (in.Is('(')) { } else if ((token.IsAsciiSign() || token.IsSymbol(')')) &&
// Ignore anything from '(' to a matching ')' or end of string. has_read_number) {
in.SkipParentheses();
} else if ((in.IsAsciiSign() || in.Is(')')) && in.HasReadNumber()) {
// Extra sign or ')' is illegal if a number has been read. // Extra sign or ')' is illegal if a number has been read.
return false; return false;
} else { } else {
// Ignore other characters. // Ignore other characters and whitespace.
in.Next();
} }
} }
return day.Write(out) && time.Write(out) && tz.Write(out); return day.Write(out) && time.Write(out) && tz.Write(out);
} }
template<typename CharType>
DateParser::DateToken DateParser::DateStringTokenizer<CharType>::Scan() {
int pre_pos = in_->position();
if (in_->IsEnd()) return DateToken::EndOfInput();
if (in_->IsAsciiDigit()) {
int n = in_->ReadUnsignedNumeral();
int length = in_->position() - pre_pos;
return DateToken::Number(n, length);
}
if (in_->Skip(':')) return DateToken::Symbol(':');
if (in_->Skip('-')) return DateToken::Symbol('-');
if (in_->Skip('+')) return DateToken::Symbol('+');
if (in_->Skip('.')) return DateToken::Symbol('.');
if (in_->Skip(')')) return DateToken::Symbol(')');
if (in_->IsAsciiAlphaOrAbove()) {
ASSERT(KeywordTable::kPrefixLength == 3);
uint32_t buffer[3] = {0, 0, 0};
int length = in_->ReadWord(buffer, 3);
int index = KeywordTable::Lookup(buffer, length);
return DateToken::Keyword(KeywordTable::GetType(index),
KeywordTable::GetValue(index),
length);
}
if (in_->SkipWhiteSpace()) {
return DateToken::WhiteSpace(in_->position() - pre_pos);
}
if (in_->SkipParentheses()) {
return DateToken::Unknown();
}
in_->Next();
return DateToken::Unknown();
}
template <typename Char>
DateParser::DateToken DateParser::ParseES5DateTime(
DateStringTokenizer<Char>* scanner,
DayComposer* day,
TimeComposer* time,
TimeZoneComposer* tz) {
ASSERT(day->IsEmpty());
ASSERT(time->IsEmpty());
ASSERT(tz->IsEmpty());
// Parse mandatory date string: [('-'|'+')yy]yyyy[':'MM[':'DD]]
if (scanner->Peek().IsAsciiSign()) {
// Keep the sign token, so we can pass it back to the legacy
// parser if we don't use it.
DateToken sign_token = scanner->Next();
if (!scanner->Peek().IsFixedLengthNumber(6)) return sign_token;
int sign = sign_token.ascii_sign();
int year = scanner->Next().number();
if (sign < 0 && year == 0) return sign_token;
day->Add(sign * year);
} else if (scanner->Peek().IsFixedLengthNumber(4)) {
day->Add(scanner->Next().number());
} else {
return scanner->Next();
}
if (scanner->SkipSymbol('-')) {
if (!scanner->Peek().IsFixedLengthNumber(2) ||
!DayComposer::IsMonth(scanner->Peek().number())) return scanner->Next();
day->Add(scanner->Next().number());
if (scanner->SkipSymbol('-')) {
if (!scanner->Peek().IsFixedLengthNumber(2) ||
!DayComposer::IsDay(scanner->Peek().number())) return scanner->Next();
day->Add(scanner->Next().number());
}
}
// Check for optional time string: 'T'HH':'mm[':'ss['.'sss]]Z
if (!scanner->Peek().IsKeywordType(TIME_SEPARATOR)) {
if (!scanner->Peek().IsEndOfInput()) return scanner->Next();
} else {
// ES5 Date Time String time part is present.
scanner->Next();
if (!scanner->Peek().IsFixedLengthNumber(2) ||
!Between(scanner->Peek().number(), 0, 24)) {
return DateToken::Invalid();
}
// Allow 24:00[:00[.000]], but no other time starting with 24.
bool hour_is_24 = (scanner->Peek().number() == 24);
time->Add(scanner->Next().number());
if (!scanner->SkipSymbol(':')) return DateToken::Invalid();
if (!scanner->Peek().IsFixedLengthNumber(2) ||
!TimeComposer::IsMinute(scanner->Peek().number()) ||
(hour_is_24 && scanner->Peek().number() > 0)) {
return DateToken::Invalid();
}
time->Add(scanner->Next().number());
if (scanner->SkipSymbol(':')) {
if (!scanner->Peek().IsFixedLengthNumber(2) ||
!TimeComposer::IsSecond(scanner->Peek().number()) ||
(hour_is_24 && scanner->Peek().number() > 0)) {
return DateToken::Invalid();
}
time->Add(scanner->Next().number());
if (scanner->SkipSymbol('.')) {
if (!scanner->Peek().IsNumber() ||
(hour_is_24 && scanner->Peek().number() > 0)) {
return DateToken::Invalid();
}
// Allow more or less than the mandated three digits.
time->Add(ReadMilliseconds(scanner->Next()));
}
}
// Check for optional timezone designation: 'Z' | ('+'|'-')hh':'mm
if (scanner->Peek().IsKeywordZ()) {
scanner->Next();
tz->Set(0);
} else if (scanner->Peek().IsSymbol('+') ||
scanner->Peek().IsSymbol('-')) {
tz->SetSign(scanner->Next().symbol() == '+' ? 1 : -1);
if (scanner->Peek().IsFixedLengthNumber(4)) {
// hhmm extension syntax.
int hourmin = scanner->Next().number();
int hour = hourmin / 100;
int min = hourmin % 100;
if (!TimeComposer::IsHour(hour) || !TimeComposer::IsMinute(min)) {
return DateToken::Invalid();
}
tz->SetAbsoluteHour(hour);
tz->SetAbsoluteMinute(min);
} else {
// hh:mm standard syntax.
if (!scanner->Peek().IsFixedLengthNumber(2) ||
!TimeComposer::IsHour(scanner->Peek().number())) {
return DateToken::Invalid();
}
tz->SetAbsoluteHour(scanner->Next().number());
if (!scanner->SkipSymbol(':')) return DateToken::Invalid();
if (!scanner->Peek().IsFixedLengthNumber(2) ||
!TimeComposer::IsMinute(scanner->Peek().number())) {
return DateToken::Invalid();
}
tz->SetAbsoluteMinute(scanner->Next().number());
}
}
if (!scanner->Peek().IsEndOfInput()) return DateToken::Invalid();
}
// Successfully parsed ES5 Date Time String. Default to UTC if no TZ given.
if (tz->IsEmpty()) tz->Set(0);
day->set_iso_date();
return DateToken::EndOfInput();
}
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_DATEPARSER_INL_H_ #endif // V8_DATEPARSER_INL_H_

38
deps/v8/src/dateparser.cc

@ -1,4 +1,4 @@
// Copyright 2008 the V8 project authors. All rights reserved. // Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -44,7 +44,7 @@ bool DateParser::DayComposer::Write(FixedArray* output) {
int day = kNone; int day = kNone;
if (named_month_ == kNone) { if (named_month_ == kNone) {
if (index_ == 3 && !IsDay(comp_[0])) { if (is_iso_date_ || (index_ == 3 && !IsDay(comp_[0]))) {
// YMD // YMD
year = comp_[0]; year = comp_[0];
month = comp_[1]; month = comp_[1];
@ -71,8 +71,10 @@ bool DateParser::DayComposer::Write(FixedArray* output) {
} }
} }
if (!is_iso_date_) {
if (Between(year, 0, 49)) year += 2000; if (Between(year, 0, 49)) year += 2000;
else if (Between(year, 50, 99)) year += 1900; else if (Between(year, 50, 99)) year += 1900;
}
if (!Smi::IsValid(year) || !IsMonth(month) || !IsDay(day)) return false; if (!Smi::IsValid(year) || !IsMonth(month) || !IsDay(day)) return false;
@ -151,6 +153,7 @@ const int8_t DateParser::KeywordTable::
{'m', 's', 't', DateParser::TIME_ZONE_NAME, -7}, {'m', 's', 't', DateParser::TIME_ZONE_NAME, -7},
{'p', 'd', 't', DateParser::TIME_ZONE_NAME, -7}, {'p', 'd', 't', DateParser::TIME_ZONE_NAME, -7},
{'p', 's', 't', DateParser::TIME_ZONE_NAME, -8}, {'p', 's', 't', DateParser::TIME_ZONE_NAME, -8},
{'t', '\0', '\0', DateParser::TIME_SEPARATOR, 0},
{'\0', '\0', '\0', DateParser::INVALID, 0}, {'\0', '\0', '\0', DateParser::INVALID, 0},
}; };
@ -175,4 +178,35 @@ int DateParser::KeywordTable::Lookup(const uint32_t* pre, int len) {
} }
int DateParser::ReadMilliseconds(DateToken token) {
// Read first three significant digits of the original numeral,
// as inferred from the value and the number of digits.
// I.e., use the number of digits to see if there were
// leading zeros.
int number = token.number();
int length = token.length();
if (length < 3) {
// Less than three digits. Multiply to put most significant digit
// in hundreds position.
if (length == 1) {
number *= 100;
} else if (length == 2) {
number *= 10;
}
} else if (length > 3) {
if (length > kMaxSignificantDigits) length = kMaxSignificantDigits;
// More than three digits. Divide by 10^(length - 3) to get three
// most significant digits.
int factor = 1;
do {
ASSERT(factor <= 100000000); // factor won't overflow.
factor *= 10;
length--;
} while (length > 3);
number /= factor;
}
return number;
}
} } // namespace v8::internal } } // namespace v8::internal

198
deps/v8/src/dateparser.h

@ -61,9 +61,14 @@ class DateParser : public AllStatic {
static inline bool Between(int x, int lo, int hi) { static inline bool Between(int x, int lo, int hi) {
return static_cast<unsigned>(x - lo) <= static_cast<unsigned>(hi - lo); return static_cast<unsigned>(x - lo) <= static_cast<unsigned>(hi - lo);
} }
// Indicates a missing value. // Indicates a missing value.
static const int kNone = kMaxInt; static const int kNone = kMaxInt;
// Maximal number of digits used to build the value of a numeral.
// Remaining digits are ignored.
static const int kMaxSignificantDigits = 9;
// InputReader provides basic string parsing and character classification. // InputReader provides basic string parsing and character classification.
template <typename Char> template <typename Char>
class InputReader BASE_EMBEDDED { class InputReader BASE_EMBEDDED {
@ -71,32 +76,28 @@ class DateParser : public AllStatic {
InputReader(UnicodeCache* unicode_cache, Vector<Char> s) InputReader(UnicodeCache* unicode_cache, Vector<Char> s)
: index_(0), : index_(0),
buffer_(s), buffer_(s),
has_read_number_(false),
unicode_cache_(unicode_cache) { unicode_cache_(unicode_cache) {
Next(); Next();
} }
// Advance to the next character of the string. int position() { return index_; }
void Next() { ch_ = (index_ < buffer_.length()) ? buffer_[index_++] : 0; }
// Read a string of digits as an unsigned number (cap just below kMaxInt). // Advance to the next character of the string.
int ReadUnsignedNumber() { void Next() {
has_read_number_ = true; ch_ = (index_ < buffer_.length()) ? buffer_[index_] : 0;
int n; index_++;
for (n = 0; IsAsciiDigit() && n < kMaxInt / 10 - 1; Next()) {
n = n * 10 + ch_ - '0';
}
return n;
} }
// Read a string of digits, take the first three or fewer as an unsigned // Read a string of digits as an unsigned number. Cap value at
// number of milliseconds, and ignore any digits after the first three. // kMaxSignificantDigits, but skip remaining digits if the numeral
int ReadMilliseconds() { // is longer.
has_read_number_ = true; int ReadUnsignedNumeral() {
int n = 0; int n = 0;
int power; int i = 0;
for (power = 100; IsAsciiDigit(); Next(), power = power / 10) { while (IsAsciiDigit()) {
n = n + power * (ch_ - '0'); if (i < kMaxSignificantDigits) n = n * 10 + ch_ - '0';
i++;
Next();
} }
return n; return n;
} }
@ -151,18 +152,138 @@ class DateParser : public AllStatic {
// Return 1 for '+' and -1 for '-'. // Return 1 for '+' and -1 for '-'.
int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); } int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); }
// Indicates whether any (possibly empty!) numbers have been read.
bool HasReadNumber() const { return has_read_number_; }
private: private:
int index_; int index_;
Vector<Char> buffer_; Vector<Char> buffer_;
bool has_read_number_;
uint32_t ch_; uint32_t ch_;
UnicodeCache* unicode_cache_; UnicodeCache* unicode_cache_;
}; };
enum KeywordType { INVALID, MONTH_NAME, TIME_ZONE_NAME, AM_PM }; enum KeywordType {
INVALID, MONTH_NAME, TIME_ZONE_NAME, TIME_SEPARATOR, AM_PM
};
struct DateToken {
public:
bool IsInvalid() { return tag_ == kInvalidTokenTag; }
bool IsUnknown() { return tag_ == kUnknownTokenTag; }
bool IsNumber() { return tag_ == kNumberTag; }
bool IsSymbol() { return tag_ == kSymbolTag; }
bool IsWhiteSpace() { return tag_ == kWhiteSpaceTag; }
bool IsEndOfInput() { return tag_ == kEndOfInputTag; }
bool IsKeyword() { return tag_ >= kKeywordTagStart; }
int length() { return length_; }
int number() {
ASSERT(IsNumber());
return value_;
}
KeywordType keyword_type() {
ASSERT(IsKeyword());
return static_cast<KeywordType>(tag_);
}
int keyword_value() {
ASSERT(IsKeyword());
return value_;
}
char symbol() {
ASSERT(IsSymbol());
return static_cast<char>(value_);
}
bool IsSymbol(char symbol) {
return IsSymbol() && this->symbol() == symbol;
}
bool IsKeywordType(KeywordType tag) {
return tag_ == tag;
}
bool IsFixedLengthNumber(int length) {
return IsNumber() && length_ == length;
}
bool IsAsciiSign() {
return tag_ == kSymbolTag && (value_ == '-' || value_ == '+');
}
int ascii_sign() {
ASSERT(IsAsciiSign());
return 44 - value_;
}
bool IsKeywordZ() {
return IsKeywordType(TIME_ZONE_NAME) && length_ == 1 && value_ == 0;
}
bool IsUnknown(int character) {
return IsUnknown() && value_ == character;
}
// Factory functions.
static DateToken Keyword(KeywordType tag, int value, int length) {
return DateToken(tag, length, value);
}
static DateToken Number(int value, int length) {
return DateToken(kNumberTag, length, value);
}
static DateToken Symbol(char symbol) {
return DateToken(kSymbolTag, 1, symbol);
}
static DateToken EndOfInput() {
return DateToken(kEndOfInputTag, 0, -1);
}
static DateToken WhiteSpace(int length) {
return DateToken(kWhiteSpaceTag, length, -1);
}
static DateToken Unknown() {
return DateToken(kUnknownTokenTag, 1, -1);
}
static DateToken Invalid() {
return DateToken(kInvalidTokenTag, 0, -1);
}
private:
enum TagType {
kInvalidTokenTag = -6,
kUnknownTokenTag = -5,
kWhiteSpaceTag = -4,
kNumberTag = -3,
kSymbolTag = -2,
kEndOfInputTag = -1,
kKeywordTagStart = 0
};
DateToken(int tag, int length, int value)
: tag_(tag),
length_(length),
value_(value) { }
int tag_;
int length_; // Number of characters.
int value_;
};
template <typename Char>
class DateStringTokenizer {
public:
explicit DateStringTokenizer(InputReader<Char>* in)
: in_(in), next_(Scan()) { }
DateToken Next() {
DateToken result = next_;
next_ = Scan();
return result;
}
DateToken Peek() {
return next_;
}
bool SkipSymbol(char symbol) {
if (next_.IsSymbol(symbol)) {
next_ = Scan();
return true;
}
return false;
}
private:
DateToken Scan();
InputReader<Char>* in_;
DateToken next_;
};
static int ReadMilliseconds(DateToken number);
// KeywordTable maps names of months, time zones, am/pm to numbers. // KeywordTable maps names of months, time zones, am/pm to numbers.
class KeywordTable : public AllStatic { class KeywordTable : public AllStatic {
@ -201,6 +322,7 @@ class DateParser : public AllStatic {
} }
bool IsUTC() const { return hour_ == 0 && minute_ == 0; } bool IsUTC() const { return hour_ == 0 && minute_ == 0; }
bool Write(FixedArray* output); bool Write(FixedArray* output);
bool IsEmpty() { return hour_ == kNone; }
private: private:
int sign_; int sign_;
int hour_; int hour_;
@ -228,10 +350,10 @@ class DateParser : public AllStatic {
bool Write(FixedArray* output); bool Write(FixedArray* output);
static bool IsMinute(int x) { return Between(x, 0, 59); } static bool IsMinute(int x) { return Between(x, 0, 59); }
private:
static bool IsHour(int x) { return Between(x, 0, 23); } static bool IsHour(int x) { return Between(x, 0, 23); }
static bool IsHour12(int x) { return Between(x, 0, 12); }
static bool IsSecond(int x) { return Between(x, 0, 59); } static bool IsSecond(int x) { return Between(x, 0, 59); }
private:
static bool IsHour12(int x) { return Between(x, 0, 12); }
static bool IsMillisecond(int x) { return Between(x, 0, 999); } static bool IsMillisecond(int x) { return Between(x, 0, 999); }
static const int kSize = 4; static const int kSize = 4;
@ -242,22 +364,42 @@ class DateParser : public AllStatic {
class DayComposer BASE_EMBEDDED { class DayComposer BASE_EMBEDDED {
public: public:
DayComposer() : index_(0), named_month_(kNone) {} DayComposer() : index_(0), named_month_(kNone), is_iso_date_(false) {}
bool IsEmpty() const { return index_ == 0; } bool IsEmpty() const { return index_ == 0; }
bool Add(int n) { bool Add(int n) {
return index_ < kSize ? (comp_[index_++] = n, true) : false; if (index_ < kSize) {
comp_[index_] = n;
index_++;
return true;
}
return false;
} }
void SetNamedMonth(int n) { named_month_ = n; } void SetNamedMonth(int n) { named_month_ = n; }
bool Write(FixedArray* output); bool Write(FixedArray* output);
private: void set_iso_date() { is_iso_date_ = true; }
static bool IsMonth(int x) { return Between(x, 1, 12); } static bool IsMonth(int x) { return Between(x, 1, 12); }
static bool IsDay(int x) { return Between(x, 1, 31); } static bool IsDay(int x) { return Between(x, 1, 31); }
private:
static const int kSize = 3; static const int kSize = 3;
int comp_[kSize]; int comp_[kSize];
int index_; int index_;
int named_month_; int named_month_;
// If set, ensures that data is always parsed in year-month-date order.
bool is_iso_date_;
}; };
// Tries to parse an ES5 Date Time String. Returns the next token
// to continue with in the legacy date string parser. If parsing is
// complete, returns DateToken::EndOfInput(). If terminally unsuccessful,
// returns DateToken::Invalid(). Otherwise parsing continues in the
// legacy parser.
template <typename Char>
static DateParser::DateToken ParseES5DateTime(
DateStringTokenizer<Char>* scanner,
DayComposer* day,
TimeComposer* time,
TimeZoneComposer* tz);
}; };

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

@ -2311,21 +2311,10 @@ DebugCommandProcessor.prototype.versionRequest_ = function(request, response) {
DebugCommandProcessor.prototype.profileRequest_ = function(request, response) { DebugCommandProcessor.prototype.profileRequest_ = function(request, response) {
if (!request.arguments) {
return response.failed('Missing arguments');
}
var modules = parseInt(request.arguments.modules);
if (isNaN(modules)) {
return response.failed('Modules is not an integer');
}
var tag = parseInt(request.arguments.tag);
if (isNaN(tag)) {
tag = 0;
}
if (request.arguments.command == 'resume') { if (request.arguments.command == 'resume') {
%ProfilerResume(modules, tag); %ProfilerResume();
} else if (request.arguments.command == 'pause') { } else if (request.arguments.command == 'pause') {
%ProfilerPause(modules, tag); %ProfilerPause();
} else { } else {
return response.failed('Unknown command'); return response.failed('Unknown command');
} }

188
deps/v8/src/deoptimizer.cc

@ -44,6 +44,9 @@ DeoptimizerData::DeoptimizerData() {
lazy_deoptimization_entry_code_ = NULL; lazy_deoptimization_entry_code_ = NULL;
current_ = NULL; current_ = NULL;
deoptimizing_code_list_ = NULL; deoptimizing_code_list_ = NULL;
#ifdef ENABLE_DEBUGGER_SUPPORT
deoptimized_frame_info_ = NULL;
#endif
} }
@ -58,6 +61,16 @@ DeoptimizerData::~DeoptimizerData() {
} }
} }
#ifdef ENABLE_DEBUGGER_SUPPORT
void DeoptimizerData::Iterate(ObjectVisitor* v) {
if (deoptimized_frame_info_ != NULL) {
deoptimized_frame_info_->Iterate(v);
}
}
#endif
Deoptimizer* Deoptimizer::New(JSFunction* function, Deoptimizer* Deoptimizer::New(JSFunction* function,
BailoutType type, BailoutType type,
unsigned bailout_id, unsigned bailout_id,
@ -70,7 +83,8 @@ Deoptimizer* Deoptimizer::New(JSFunction* function,
type, type,
bailout_id, bailout_id,
from, from,
fp_to_sp_delta); fp_to_sp_delta,
NULL);
ASSERT(isolate->deoptimizer_data()->current_ == NULL); ASSERT(isolate->deoptimizer_data()->current_ == NULL);
isolate->deoptimizer_data()->current_ = deoptimizer; isolate->deoptimizer_data()->current_ = deoptimizer;
return deoptimizer; return deoptimizer;
@ -86,6 +100,92 @@ Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
return result; return result;
} }
#ifdef ENABLE_DEBUGGER_SUPPORT
DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
JavaScriptFrame* frame,
int frame_index,
Isolate* isolate) {
ASSERT(isolate == Isolate::Current());
ASSERT(frame->is_optimized());
ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
// Get the function and code from the frame.
JSFunction* function = JSFunction::cast(frame->function());
Code* code = frame->LookupCode();
Address code_start_address = code->instruction_start();
// Locate the deoptimization point in the code. As we are at a call the
// return address must be at a place in the code with deoptimization support.
int deoptimization_index = Safepoint::kNoDeoptimizationIndex;
// Scope this as the safe point constructor will disallow allocation.
{
SafepointTable table(code);
for (unsigned i = 0; i < table.length(); ++i) {
Address address = code_start_address + table.GetPcOffset(i);
if (address == frame->pc()) {
SafepointEntry safepoint_entry = table.GetEntry(i);
ASSERT(safepoint_entry.deoptimization_index() !=
Safepoint::kNoDeoptimizationIndex);
deoptimization_index = safepoint_entry.deoptimization_index();
break;
}
}
}
ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
// Always use the actual stack slots when calculating the fp to sp
// delta adding two for the function and context.
unsigned stack_slots = code->stack_slots();
unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize);
Deoptimizer* deoptimizer = new Deoptimizer(isolate,
function,
Deoptimizer::DEBUGGER,
deoptimization_index,
frame->pc(),
fp_to_sp_delta,
code);
Address tos = frame->fp() - fp_to_sp_delta;
deoptimizer->FillInputFrame(tos, frame);
// Calculate the output frames.
Deoptimizer::ComputeOutputFrames(deoptimizer);
// Create the GC safe output frame information and register it for GC
// handling.
ASSERT_LT(frame_index, deoptimizer->output_count());
DeoptimizedFrameInfo* info =
new DeoptimizedFrameInfo(deoptimizer, frame_index);
isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
// Get the "simulated" top and size for the requested frame.
Address top =
reinterpret_cast<Address>(deoptimizer->output_[frame_index]->GetTop());
unsigned size =
deoptimizer->output_[frame_index]->GetFrameSize() / kPointerSize;
// Done with the GC-unsafe frame descriptions. This re-enables allocation.
deoptimizer->DeleteFrameDescriptions();
// Allocate a heap number for the doubles belonging to this frame.
deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
top, size, info);
// Finished using the deoptimizer instance.
delete deoptimizer;
return info;
}
void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
Isolate* isolate) {
ASSERT(isolate == Isolate::Current());
ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info);
delete info;
isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
}
#endif
void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
int count, int count,
@ -209,18 +309,24 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
BailoutType type, BailoutType type,
unsigned bailout_id, unsigned bailout_id,
Address from, Address from,
int fp_to_sp_delta) int fp_to_sp_delta,
Code* optimized_code)
: isolate_(isolate), : isolate_(isolate),
function_(function), function_(function),
bailout_id_(bailout_id), bailout_id_(bailout_id),
bailout_type_(type), bailout_type_(type),
from_(from), from_(from),
fp_to_sp_delta_(fp_to_sp_delta), fp_to_sp_delta_(fp_to_sp_delta),
input_(NULL),
output_count_(0), output_count_(0),
output_(NULL), output_(NULL),
deferred_heap_numbers_(0) { deferred_heap_numbers_(0) {
if (FLAG_trace_deopt && type != OSR) { if (FLAG_trace_deopt && type != OSR) {
if (type == DEBUGGER) {
PrintF("**** DEOPT FOR DEBUGGER: ");
} else {
PrintF("**** DEOPT: "); PrintF("**** DEOPT: ");
}
function->PrintName(); function->PrintName();
PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n", PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
bailout_id, bailout_id,
@ -248,10 +354,16 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
optimized_code_ = function_->code(); optimized_code_ = function_->code();
ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION); ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
ASSERT(!optimized_code_->contains(from)); ASSERT(!optimized_code_->contains(from));
} else if (type == DEBUGGER) {
optimized_code_ = optimized_code;
ASSERT(optimized_code_->contains(from));
} }
ASSERT(HEAP->allow_allocation(false)); ASSERT(HEAP->allow_allocation(false));
unsigned size = ComputeInputFrameSize(); unsigned size = ComputeInputFrameSize();
input_ = new(size) FrameDescription(size, function); input_ = new(size) FrameDescription(size, function);
#ifdef DEBUG
input_->SetKind(Code::OPTIMIZED_FUNCTION);
#endif
} }
@ -417,6 +529,7 @@ void Deoptimizer::DoComputeOutputFrames() {
void Deoptimizer::MaterializeHeapNumbers() { void Deoptimizer::MaterializeHeapNumbers() {
ASSERT_NE(DEBUGGER, bailout_type_);
for (int i = 0; i < deferred_heap_numbers_.length(); i++) { for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i]; HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
Handle<Object> num = isolate_->factory()->NewNumber(d.value()); Handle<Object> num = isolate_->factory()->NewNumber(d.value());
@ -432,6 +545,35 @@ void Deoptimizer::MaterializeHeapNumbers() {
} }
#ifdef ENABLE_DEBUGGER_SUPPORT
void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
Address top, intptr_t size, DeoptimizedFrameInfo* info) {
ASSERT_EQ(DEBUGGER, bailout_type_);
for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
// Check of the heap number to materialize actually belong to the frame
// being extracted.
Address slot = d.slot_address();
if (top <= slot && slot < top + size) {
Handle<Object> num = isolate_->factory()->NewNumber(d.value());
int expression_index = static_cast<int>(
info->expression_count_ - (slot - top) / kPointerSize - 1);
if (FLAG_trace_deopt) {
PrintF("Materializing a new heap number %p [%e] in slot %p"
"for expression stack index %d\n",
reinterpret_cast<void*>(*num),
d.value(),
d.slot_address(),
expression_index);
}
info->SetExpression(expression_index, *num);
}
}
}
#endif
void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
int frame_index, int frame_index,
unsigned output_offset) { unsigned output_offset) {
@ -972,18 +1114,32 @@ unsigned FrameDescription::GetOffsetFromSlotIndex(Deoptimizer* deoptimizer,
if (slot_index >= 0) { if (slot_index >= 0) {
// Local or spill slots. Skip the fixed part of the frame // Local or spill slots. Skip the fixed part of the frame
// including all arguments. // including all arguments.
unsigned base = static_cast<unsigned>( unsigned base =
GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction())); GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction());
return base - ((slot_index + 1) * kPointerSize); return base - ((slot_index + 1) * kPointerSize);
} else { } else {
// Incoming parameter. // Incoming parameter.
unsigned base = static_cast<unsigned>(GetFrameSize() - unsigned base = GetFrameSize() -
deoptimizer->ComputeIncomingArgumentSize(GetFunction())); deoptimizer->ComputeIncomingArgumentSize(GetFunction());
return base - ((slot_index + 1) * kPointerSize); return base - ((slot_index + 1) * kPointerSize);
} }
} }
unsigned FrameDescription::GetExpressionCount(Deoptimizer* deoptimizer) {
ASSERT_EQ(Code::FUNCTION, kind_);
unsigned size = GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction());
return size / kPointerSize;
}
Object* FrameDescription::GetExpression(Deoptimizer* deoptimizer, int index) {
ASSERT_EQ(Code::FUNCTION, kind_);
unsigned offset = GetOffsetFromSlotIndex(deoptimizer, index);
return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
}
void TranslationBuffer::Add(int32_t value) { void TranslationBuffer::Add(int32_t value) {
// Encode the sign bit in the least significant bit. // Encode the sign bit in the least significant bit.
bool is_negative = (value < 0); bool is_negative = (value < 0);
@ -1256,4 +1412,24 @@ void SlotRef::ComputeSlotMappingForArguments(JavaScriptFrame* frame,
} }
DeoptimizedFrameInfo::DeoptimizedFrameInfo(
Deoptimizer* deoptimizer, int frame_index) {
FrameDescription* output_frame = deoptimizer->output_[frame_index];
expression_count_ = output_frame->GetExpressionCount(deoptimizer);
expression_stack_ = new Object*[expression_count_];
for (int i = 0; i < expression_count_; i++) {
SetExpression(i, output_frame->GetExpression(deoptimizer, i));
}
}
DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
delete expression_stack_;
}
void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
}
} } // namespace v8::internal } } // namespace v8::internal

96
deps/v8/src/deoptimizer.h

@ -41,7 +41,7 @@ namespace internal {
class FrameDescription; class FrameDescription;
class TranslationIterator; class TranslationIterator;
class DeoptimizingCodeListNode; class DeoptimizingCodeListNode;
class DeoptimizedFrameInfo;
class HeapNumberMaterializationDescriptor BASE_EMBEDDED { class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
public: public:
@ -81,11 +81,19 @@ class DeoptimizerData {
DeoptimizerData(); DeoptimizerData();
~DeoptimizerData(); ~DeoptimizerData();
#ifdef ENABLE_DEBUGGER_SUPPORT
void Iterate(ObjectVisitor* v);
#endif
private: private:
LargeObjectChunk* eager_deoptimization_entry_code_; LargeObjectChunk* eager_deoptimization_entry_code_;
LargeObjectChunk* lazy_deoptimization_entry_code_; LargeObjectChunk* lazy_deoptimization_entry_code_;
Deoptimizer* current_; Deoptimizer* current_;
#ifdef ENABLE_DEBUGGER_SUPPORT
DeoptimizedFrameInfo* deoptimized_frame_info_;
#endif
// List of deoptimized code which still have references from active stack // List of deoptimized code which still have references from active stack
// frames. These code objects are needed by the deoptimizer when deoptimizing // frames. These code objects are needed by the deoptimizer when deoptimizing
// a frame for which the code object for the function function has been // a frame for which the code object for the function function has been
@ -103,7 +111,10 @@ class Deoptimizer : public Malloced {
enum BailoutType { enum BailoutType {
EAGER, EAGER,
LAZY, LAZY,
OSR OSR,
// This last bailout type is not really a bailout, but used by the
// debugger to deoptimize stack frames to allow inspection.
DEBUGGER
}; };
int output_count() const { return output_count_; } int output_count() const { return output_count_; }
@ -116,6 +127,16 @@ class Deoptimizer : public Malloced {
Isolate* isolate); Isolate* isolate);
static Deoptimizer* Grab(Isolate* isolate); static Deoptimizer* Grab(Isolate* isolate);
#ifdef ENABLE_DEBUGGER_SUPPORT
// The returned object with information on the optimized frame needs to be
// freed before another one can be generated.
static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
int frame_index,
Isolate* isolate);
static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
Isolate* isolate);
#endif
// Makes sure that there is enough room in the relocation // Makes sure that there is enough room in the relocation
// information of a code object to perform lazy deoptimization // information of a code object to perform lazy deoptimization
// patching. If there is not enough room a new relocation // patching. If there is not enough room a new relocation
@ -171,6 +192,10 @@ class Deoptimizer : public Malloced {
~Deoptimizer(); ~Deoptimizer();
void MaterializeHeapNumbers(); void MaterializeHeapNumbers();
#ifdef ENABLE_DEBUGGER_SUPPORT
void MaterializeHeapNumbersForDebuggerInspectableFrame(
Address top, intptr_t size, DeoptimizedFrameInfo* info);
#endif
static void ComputeOutputFrames(Deoptimizer* deoptimizer); static void ComputeOutputFrames(Deoptimizer* deoptimizer);
@ -233,7 +258,8 @@ class Deoptimizer : public Malloced {
BailoutType type, BailoutType type,
unsigned bailout_id, unsigned bailout_id,
Address from, Address from,
int fp_to_sp_delta); int fp_to_sp_delta,
Code* optimized_code);
void DeleteFrameDescriptions(); void DeleteFrameDescriptions();
void DoComputeOutputFrames(); void DoComputeOutputFrames();
@ -269,6 +295,11 @@ class Deoptimizer : public Malloced {
static Code* FindDeoptimizingCodeFromAddress(Address addr); static Code* FindDeoptimizingCodeFromAddress(Address addr);
static void RemoveDeoptimizingCode(Code* code); static void RemoveDeoptimizingCode(Code* code);
// Fill the input from from a JavaScript frame. This is used when
// the debugger needs to inspect an optimized frame. For normal
// deoptimizations the input frame is filled in generated code.
void FillInputFrame(Address tos, JavaScriptFrame* frame);
Isolate* isolate_; Isolate* isolate_;
JSFunction* function_; JSFunction* function_;
Code* optimized_code_; Code* optimized_code_;
@ -290,6 +321,7 @@ class Deoptimizer : public Malloced {
friend class FrameDescription; friend class FrameDescription;
friend class DeoptimizingCodeListNode; friend class DeoptimizingCodeListNode;
friend class DeoptimizedFrameInfo;
}; };
@ -308,7 +340,10 @@ class FrameDescription {
free(description); free(description);
} }
intptr_t GetFrameSize() const { return frame_size_; } uint32_t GetFrameSize() const {
ASSERT(static_cast<uint32_t>(frame_size_) == frame_size_);
return static_cast<uint32_t>(frame_size_);
}
JSFunction* GetFunction() const { return function_; } JSFunction* GetFunction() const { return function_; }
@ -360,6 +395,17 @@ class FrameDescription {
void SetContinuation(intptr_t pc) { continuation_ = pc; } void SetContinuation(intptr_t pc) { continuation_ = pc; }
#ifdef DEBUG
Code::Kind GetKind() const { return kind_; }
void SetKind(Code::Kind kind) { kind_ = kind; }
#endif
// Get the expression stack height for a unoptimized frame.
unsigned GetExpressionCount(Deoptimizer* deoptimizer);
// Get the expression stack value for an unoptimized frame.
Object* GetExpression(Deoptimizer* deoptimizer, int index);
static int registers_offset() { static int registers_offset() {
return OFFSET_OF(FrameDescription, registers_); return OFFSET_OF(FrameDescription, registers_);
} }
@ -391,6 +437,9 @@ class FrameDescription {
private: private:
static const uint32_t kZapUint32 = 0xbeeddead; static const uint32_t kZapUint32 = 0xbeeddead;
// Frame_size_ must hold a uint32_t value. It is only a uintptr_t to
// keep the variable-size array frame_content_ of type intptr_t at
// the end of the structure aligned.
uintptr_t frame_size_; // Number of bytes. uintptr_t frame_size_; // Number of bytes.
JSFunction* function_; JSFunction* function_;
intptr_t registers_[Register::kNumRegisters]; intptr_t registers_[Register::kNumRegisters];
@ -399,6 +448,9 @@ class FrameDescription {
intptr_t pc_; intptr_t pc_;
intptr_t fp_; intptr_t fp_;
Smi* state_; Smi* state_;
#ifdef DEBUG
Code::Kind kind_;
#endif
// Continuation is the PC where the execution continues after // Continuation is the PC where the execution continues after
// deoptimizing. // deoptimizing.
@ -597,6 +649,42 @@ class SlotRef BASE_EMBEDDED {
}; };
#ifdef ENABLE_DEBUGGER_SUPPORT
// Class used to represent an unoptimized frame when the debugger
// needs to inspect a frame that is part of an optimized frame. The
// internally used FrameDescription objects are not GC safe so for use
// by the debugger frame information is copied to an object of this type.
class DeoptimizedFrameInfo : public Malloced {
public:
DeoptimizedFrameInfo(Deoptimizer* deoptimizer, int frame_index);
virtual ~DeoptimizedFrameInfo();
// GC support.
void Iterate(ObjectVisitor* v);
// Return the height of the expression stack.
int expression_count() { return expression_count_; }
// Get an expression from the expression stack.
Object* GetExpression(int index) {
ASSERT(0 <= index && index < expression_count());
return expression_stack_[index];
}
private:
// Set an expression on the expression stack.
void SetExpression(int index, Object* obj) {
ASSERT(0 <= index && index < expression_count());
expression_stack_[index] = obj;
}
int expression_count_;
Object** expression_stack_;
friend class Deoptimizer;
};
#endif
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_DEOPTIMIZER_H_ #endif // V8_DEOPTIMIZER_H_

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

@ -203,7 +203,6 @@ DEFINE_bool(deopt, true, "support deoptimization")
DEFINE_bool(trace_deopt, false, "trace deoptimization") DEFINE_bool(trace_deopt, false, "trace deoptimization")
// compiler.cc // compiler.cc
DEFINE_bool(strict, false, "strict error checking")
DEFINE_int(min_preparse_length, 1024, DEFINE_int(min_preparse_length, 1024,
"minimum length for automatic enable preparsing") "minimum length for automatic enable preparsing")
DEFINE_bool(always_full_compiler, false, DEFINE_bool(always_full_compiler, false,
@ -372,6 +371,8 @@ DEFINE_bool(debug_script_collected_events, true,
DEFINE_bool(gdbjit, false, "enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit, false, "enable GDBJIT interface (disables compacting GC)")
DEFINE_bool(gdbjit_full, false, "enable GDBJIT interface for all code objects") DEFINE_bool(gdbjit_full, false, "enable GDBJIT interface for all code objects")
DEFINE_bool(gdbjit_dump, false, "dump elf objects with debug info to disk") DEFINE_bool(gdbjit_dump, false, "dump elf objects with debug info to disk")
DEFINE_string(gdbjit_dump_filter, "",
"dump only objects containing this substring")
// //
// Debug only flags // Debug only flags

37
deps/v8/src/frames.cc

@ -528,6 +528,17 @@ Address StandardFrame::GetExpressionAddress(int n) const {
} }
Object* StandardFrame::GetExpression(Address fp, int index) {
return Memory::Object_at(GetExpressionAddress(fp, index));
}
Address StandardFrame::GetExpressionAddress(Address fp, int n) {
const int offset = StandardFrameConstants::kExpressionsOffset;
return fp + offset - n * kPointerSize;
}
int StandardFrame::ComputeExpressionsCount() const { int StandardFrame::ComputeExpressionsCount() const {
const int offset = const int offset =
StandardFrameConstants::kExpressionsOffset + kPointerSize; StandardFrameConstants::kExpressionsOffset + kPointerSize;
@ -646,6 +657,16 @@ bool JavaScriptFrame::IsConstructor() const {
} }
int JavaScriptFrame::GetArgumentsLength() const {
// If there is an arguments adaptor frame get the arguments length from it.
if (has_adapted_arguments()) {
return Smi::cast(GetExpression(caller_fp(), 0))->value();
} else {
return GetNumberOfIncomingArguments();
}
}
Code* JavaScriptFrame::unchecked_code() const { Code* JavaScriptFrame::unchecked_code() const {
JSFunction* function = JSFunction::cast(this->function()); JSFunction* function = JSFunction::cast(this->function());
return function->unchecked_code(); return function->unchecked_code();
@ -812,6 +833,22 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
} }
int OptimizedFrame::GetInlineCount() {
ASSERT(is_optimized());
int deopt_index = Safepoint::kNoDeoptimizationIndex;
DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
TranslationIterator it(data->TranslationByteArray(),
data->TranslationIndex(deopt_index)->value());
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
ASSERT(opcode == Translation::BEGIN);
USE(opcode);
int frame_count = it.Next();
return frame_count;
}
void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) { void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
ASSERT(functions->length() == 0); ASSERT(functions->length() == 0);
ASSERT(is_optimized()); ASSERT(is_optimized());

8
deps/v8/src/frames.h

@ -383,6 +383,7 @@ class StandardFrame: public StackFrame {
inline Object* GetExpression(int index) const; inline Object* GetExpression(int index) const;
inline void SetExpression(int index, Object* value); inline void SetExpression(int index, Object* value);
int ComputeExpressionsCount() const; int ComputeExpressionsCount() const;
static Object* GetExpression(Address fp, int index);
virtual void SetCallerFp(Address caller_fp); virtual void SetCallerFp(Address caller_fp);
@ -411,6 +412,7 @@ class StandardFrame: public StackFrame {
// Returns the address of the n'th expression stack element. // Returns the address of the n'th expression stack element.
Address GetExpressionAddress(int n) const; Address GetExpressionAddress(int n) const;
static Address GetExpressionAddress(Address fp, int n);
// Determines if the n'th expression stack element is in a stack // Determines if the n'th expression stack element is in a stack
// handler or not. Requires traversing all handlers in this frame. // handler or not. Requires traversing all handlers in this frame.
@ -483,6 +485,7 @@ class JavaScriptFrame: public StandardFrame {
// actual passed arguments are available in an arguments adaptor // actual passed arguments are available in an arguments adaptor
// frame below it on the stack. // frame below it on the stack.
inline bool has_adapted_arguments() const; inline bool has_adapted_arguments() const;
int GetArgumentsLength() const;
// Garbage collection support. // Garbage collection support.
virtual void Iterate(ObjectVisitor* v) const; virtual void Iterate(ObjectVisitor* v) const;
@ -495,6 +498,9 @@ class JavaScriptFrame: public StandardFrame {
// Determine the code for the frame. // Determine the code for the frame.
virtual Code* unchecked_code() const; virtual Code* unchecked_code() const;
// Returns the levels of inlining for this frame.
virtual int GetInlineCount() { return 1; }
// Return a list with JSFunctions of this frame. // Return a list with JSFunctions of this frame.
virtual void GetFunctions(List<JSFunction*>* functions); virtual void GetFunctions(List<JSFunction*>* functions);
@ -533,6 +539,8 @@ class OptimizedFrame : public JavaScriptFrame {
// GC support. // GC support.
virtual void Iterate(ObjectVisitor* v) const; virtual void Iterate(ObjectVisitor* v) const;
virtual int GetInlineCount();
// Return a list with JSFunctions of this frame. // Return a list with JSFunctions of this frame.
// The functions are ordered bottom-to-top (i.e. functions.last() // The functions are ordered bottom-to-top (i.e. functions.last()
// is the top-most activation) // is the top-most activation)

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

@ -401,7 +401,7 @@ int FullCodeGenerator::SlotOffset(Slot* slot) {
// Adjust by a (parameter or local) base offset. // Adjust by a (parameter or local) base offset.
switch (slot->type()) { switch (slot->type()) {
case Slot::PARAMETER: case Slot::PARAMETER:
offset += (scope()->num_parameters() + 1) * kPointerSize; offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
break; break;
case Slot::LOCAL: case Slot::LOCAL:
offset += JavaScriptFrameConstants::kLocal0Offset; offset += JavaScriptFrameConstants::kLocal0Offset;
@ -1106,7 +1106,7 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
// Extend the context before executing the catch block. // Extend the context before executing the catch block.
{ Comment cmnt(masm_, "[ Extend catch context"); { Comment cmnt(masm_, "[ Extend catch context");
__ Push(stmt->name()); __ Push(stmt->variable()->name());
__ push(result_register()); __ push(result_register());
PushFunctionArgumentForContextAllocation(); PushFunctionArgumentForContextAllocation();
__ CallRuntime(Runtime::kPushCatchContext, 3); __ CallRuntime(Runtime::kPushCatchContext, 3);
@ -1114,7 +1114,11 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
context_register()); context_register());
} }
Scope* saved_scope = scope();
scope_ = stmt->scope();
ASSERT(scope_->declarations()->is_empty());
Visit(stmt->catch_block()); Visit(stmt->catch_block());
scope_ = saved_scope;
__ jmp(&done); __ jmp(&done);
// Try block code. Sets up the exception handler chain. // Try block code. Sets up the exception handler chain.

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

@ -80,6 +80,7 @@ class FullCodeGenerator: public AstVisitor {
explicit FullCodeGenerator(MacroAssembler* masm) explicit FullCodeGenerator(MacroAssembler* masm)
: masm_(masm), : masm_(masm),
info_(NULL), info_(NULL),
scope_(NULL),
nesting_stack_(NULL), nesting_stack_(NULL),
loop_depth_(0), loop_depth_(0),
context_(NULL), context_(NULL),
@ -531,23 +532,11 @@ class FullCodeGenerator: public AstVisitor {
return is_strict_mode() ? kStrictMode : kNonStrictMode; return is_strict_mode() ? kStrictMode : kNonStrictMode;
} }
FunctionLiteral* function() { return info_->function(); } FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return info_->scope(); } Scope* scope() { return scope_; }
static Register result_register(); static Register result_register();
static Register context_register(); static Register context_register();
// Helper for calling an IC stub.
void EmitCallIC(Handle<Code> ic,
RelocInfo::Mode mode,
unsigned ast_id);
// Calling an IC stub with a patch site. Passing NULL for patch_site
// or non NULL patch_site which is not activated indicates no inlined smi code
// and emits a nop after the IC call.
void EmitCallIC(Handle<Code> ic,
JumpPatchSite* patch_site,
unsigned ast_id);
// Set fields in the stack frame. Offsets are the frame pointer relative // Set fields in the stack frame. Offsets are the frame pointer relative
// offsets defined in, e.g., StandardFrameConstants. // offsets defined in, e.g., StandardFrameConstants.
void StoreToFrameField(int frame_offset, Register value); void StoreToFrameField(int frame_offset, Register value);
@ -758,6 +747,7 @@ class FullCodeGenerator: public AstVisitor {
MacroAssembler* masm_; MacroAssembler* masm_;
CompilationInfo* info_; CompilationInfo* info_;
Scope* scope_;
Label return_label_; Label return_label_;
NestedStatement* nesting_stack_; NestedStatement* nesting_stack_;
int loop_depth_; int loop_depth_;

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

@ -34,16 +34,29 @@
#include "global-handles.h" #include "global-handles.h"
#include "messages.h" #include "messages.h"
#include "natives.h" #include "natives.h"
#include "scopeinfo.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#ifdef __APPLE__
#define __MACH_O
class MachO;
class MachOSection;
typedef MachO DebugObject;
typedef MachOSection DebugSection;
#else
#define __ELF
class ELF; class ELF;
class ELFSection;
typedef ELF DebugObject;
typedef ELFSection DebugSection;
#endif
class Writer BASE_EMBEDDED { class Writer BASE_EMBEDDED {
public: public:
explicit Writer(ELF* elf) explicit Writer(DebugObject* debug_object)
: elf_(elf), : debug_object_(debug_object),
position_(0), position_(0),
capacity_(1024), capacity_(1024),
buffer_(reinterpret_cast<byte*>(malloc(capacity_))) { buffer_(reinterpret_cast<byte*>(malloc(capacity_))) {
@ -112,7 +125,7 @@ class Writer BASE_EMBEDDED {
} }
} }
ELF* elf() { return elf_; } DebugObject* debug_object() { return debug_object_; }
byte* buffer() { return buffer_; } byte* buffer() { return buffer_; }
@ -165,7 +178,7 @@ class Writer BASE_EMBEDDED {
return reinterpret_cast<T*>(&buffer_[offset]); return reinterpret_cast<T*>(&buffer_[offset]);
} }
ELF* elf_; DebugObject* debug_object_;
uintptr_t position_; uintptr_t position_;
uintptr_t capacity_; uintptr_t capacity_;
byte* buffer_; byte* buffer_;
@ -173,9 +186,104 @@ class Writer BASE_EMBEDDED {
class StringTable; class StringTable;
class ELFSection : public ZoneObject { template<typename THeader>
class DebugSectionBase : public ZoneObject {
public: public:
struct Header { virtual ~DebugSectionBase() { }
virtual void WriteBody(Writer::Slot<THeader> header, Writer* writer) {
uintptr_t start = writer->position();
if (WriteBody(writer)) {
uintptr_t end = writer->position();
header->offset = start;
#if defined(__MACH_O)
header->addr = 0;
#endif
header->size = end - start;
}
}
virtual bool WriteBody(Writer* writer) {
return false;
}
typedef THeader Header;
};
struct MachOSectionHeader {
char sectname[16];
char segname[16];
#if defined(V8_TARGET_ARCH_IA32)
uint32_t addr;
uint32_t size;
#else
uint64_t addr;
uint64_t size;
#endif
uint32_t offset;
uint32_t align;
uint32_t reloff;
uint32_t nreloc;
uint32_t flags;
uint32_t reserved1;
uint32_t reserved2;
};
class MachOSection : public DebugSectionBase<MachOSectionHeader> {
public:
enum Type {
S_REGULAR = 0x0u,
S_ATTR_COALESCED = 0xbu,
S_ATTR_SOME_INSTRUCTIONS = 0x400u,
S_ATTR_DEBUG = 0x02000000u,
S_ATTR_PURE_INSTRUCTIONS = 0x80000000u
};
MachOSection(const char* name,
const char* segment,
uintptr_t align,
uint32_t flags)
: name_(name),
segment_(segment),
align_(align),
flags_(flags) {
ASSERT(IsPowerOf2(align));
if (align_ != 0) {
align_ = WhichPowerOf2(align_);
}
}
virtual ~MachOSection() { }
virtual void PopulateHeader(Writer::Slot<Header> header) {
header->addr = 0;
header->size = 0;
header->offset = 0;
header->align = align_;
header->reloff = 0;
header->nreloc = 0;
header->flags = flags_;
header->reserved1 = 0;
header->reserved2 = 0;
memset(header->sectname, 0, sizeof(header->sectname));
memset(header->segname, 0, sizeof(header->segname));
ASSERT(strlen(name_) < sizeof(header->sectname));
ASSERT(strlen(segment_) < sizeof(header->segname));
strncpy(header->sectname, name_, sizeof(header->sectname));
strncpy(header->segname, segment_, sizeof(header->segname));
}
private:
const char* name_;
const char* segment_;
uintptr_t align_;
uint32_t flags_;
};
struct ELFSectionHeader {
uint32_t name; uint32_t name;
uint32_t type; uint32_t type;
uintptr_t flags; uintptr_t flags;
@ -186,8 +294,12 @@ class ELFSection : public ZoneObject {
uint32_t info; uint32_t info;
uintptr_t alignment; uintptr_t alignment;
uintptr_t entry_size; uintptr_t entry_size;
}; };
#if defined(__ELF)
class ELFSection : public DebugSectionBase<ELFSectionHeader> {
public:
enum Type { enum Type {
TYPE_NULL = 0, TYPE_NULL = 0,
TYPE_PROGBITS = 1, TYPE_PROGBITS = 1,
@ -252,15 +364,45 @@ class ELFSection : public ZoneObject {
header->entry_size = 0; header->entry_size = 0;
} }
private: private:
const char* name_; const char* name_;
Type type_; Type type_;
uintptr_t align_; uintptr_t align_;
uint16_t index_; uint16_t index_;
}; };
#endif // defined(__ELF)
#if defined(__MACH_O)
class MachOTextSection : public MachOSection {
public:
MachOTextSection(uintptr_t align,
uintptr_t addr,
uintptr_t size)
: MachOSection("__text",
"__TEXT",
align,
MachOSection::S_REGULAR |
MachOSection::S_ATTR_SOME_INSTRUCTIONS |
MachOSection::S_ATTR_PURE_INSTRUCTIONS),
addr_(addr),
size_(size) { }
protected:
virtual void PopulateHeader(Writer::Slot<Header> header) {
MachOSection::PopulateHeader(header);
header->addr = addr_;
header->size = size_;
}
private:
uintptr_t addr_;
uintptr_t size_;
};
#endif // defined(__MACH_O)
#if defined(__ELF)
class FullHeaderELFSection : public ELFSection { class FullHeaderELFSection : public ELFSection {
public: public:
FullHeaderELFSection(const char* name, FullHeaderELFSection(const char* name,
@ -349,8 +491,139 @@ void ELFSection::PopulateHeader(Writer::Slot<ELFSection::Header> header,
header->alignment = align_; header->alignment = align_;
PopulateHeader(header); PopulateHeader(header);
} }
#endif // defined(__ELF)
#if defined(__MACH_O)
class MachO BASE_EMBEDDED {
public:
MachO() : sections_(6) { }
uint32_t AddSection(MachOSection* section) {
sections_.Add(section);
return sections_.length() - 1;
}
void Write(Writer* w, uintptr_t code_start, uintptr_t code_size) {
Writer::Slot<MachOHeader> header = WriteHeader(w);
uintptr_t load_command_start = w->position();
Writer::Slot<MachOSegmentCommand> cmd = WriteSegmentCommand(w,
code_start,
code_size);
WriteSections(w, cmd, header, load_command_start);
}
private:
struct MachOHeader {
uint32_t magic;
uint32_t cputype;
uint32_t cpusubtype;
uint32_t filetype;
uint32_t ncmds;
uint32_t sizeofcmds;
uint32_t flags;
#if defined(V8_TARGET_ARCH_X64)
uint32_t reserved;
#endif
};
struct MachOSegmentCommand {
uint32_t cmd;
uint32_t cmdsize;
char segname[16];
#if defined(V8_TARGET_ARCH_IA32)
uint32_t vmaddr;
uint32_t vmsize;
uint32_t fileoff;
uint32_t filesize;
#else
uint64_t vmaddr;
uint64_t vmsize;
uint64_t fileoff;
uint64_t filesize;
#endif
uint32_t maxprot;
uint32_t initprot;
uint32_t nsects;
uint32_t flags;
};
enum MachOLoadCommandCmd {
LC_SEGMENT_32 = 0x00000001u,
LC_SEGMENT_64 = 0x00000019u
};
Writer::Slot<MachOHeader> WriteHeader(Writer* w) {
ASSERT(w->position() == 0);
Writer::Slot<MachOHeader> header = w->CreateSlotHere<MachOHeader>();
#if defined(V8_TARGET_ARCH_IA32)
header->magic = 0xFEEDFACEu;
header->cputype = 7; // i386
header->cpusubtype = 3; // CPU_SUBTYPE_I386_ALL
#elif defined(V8_TARGET_ARCH_X64)
header->magic = 0xFEEDFACFu;
header->cputype = 7 | 0x01000000; // i386 | 64-bit ABI
header->cpusubtype = 3; // CPU_SUBTYPE_I386_ALL
header->reserved = 0;
#else
#error Unsupported target architecture.
#endif
header->filetype = 0x1; // MH_OBJECT
header->ncmds = 1;
header->sizeofcmds = 0;
header->flags = 0;
return header;
}
Writer::Slot<MachOSegmentCommand> WriteSegmentCommand(Writer* w,
uintptr_t code_start,
uintptr_t code_size) {
Writer::Slot<MachOSegmentCommand> cmd =
w->CreateSlotHere<MachOSegmentCommand>();
#if defined(V8_TARGET_ARCH_IA32)
cmd->cmd = LC_SEGMENT_32;
#else
cmd->cmd = LC_SEGMENT_64;
#endif
cmd->vmaddr = code_start;
cmd->vmsize = code_size;
cmd->fileoff = 0;
cmd->filesize = 0;
cmd->maxprot = 7;
cmd->initprot = 7;
cmd->flags = 0;
cmd->nsects = sections_.length();
memset(cmd->segname, 0, 16);
cmd->cmdsize = sizeof(MachOSegmentCommand) + sizeof(MachOSection::Header) *
cmd->nsects;
return cmd;
}
void WriteSections(Writer* w,
Writer::Slot<MachOSegmentCommand> cmd,
Writer::Slot<MachOHeader> header,
uintptr_t load_command_start) {
Writer::Slot<MachOSection::Header> headers =
w->CreateSlotsHere<MachOSection::Header>(sections_.length());
cmd->fileoff = w->position();
header->sizeofcmds = w->position() - load_command_start;
for (int section = 0; section < sections_.length(); ++section) {
sections_[section]->PopulateHeader(headers.at(section));
sections_[section]->WriteBody(headers.at(section), w);
}
cmd->filesize = w->position() - (uintptr_t)cmd->fileoff;
}
ZoneList<MachOSection*> sections_;
};
#endif // defined(__MACH_O)
#if defined(__ELF)
class ELF BASE_EMBEDDED { class ELF BASE_EMBEDDED {
public: public:
ELF() : sections_(6) { ELF() : sections_(6) {
@ -596,7 +869,7 @@ class ELFSymbolTable : public ELFSection {
// String table for this symbol table should follow it in the section table. // String table for this symbol table should follow it in the section table.
StringTable* strtab = StringTable* strtab =
static_cast<StringTable*>(w->elf()->SectionAt(index() + 1)); static_cast<StringTable*>(w->debug_object()->SectionAt(index() + 1));
strtab->AttachWriter(w); strtab->AttachWriter(w);
symbols.at(0).set(ELFSymbol::SerializedLayout(0, symbols.at(0).set(ELFSymbol::SerializedLayout(0,
0, 0,
@ -640,6 +913,7 @@ class ELFSymbolTable : public ELFSection {
ZoneList<ELFSymbol> locals_; ZoneList<ELFSymbol> locals_;
ZoneList<ELFSymbol> globals_; ZoneList<ELFSymbol> globals_;
}; };
#endif // defined(__ELF)
class CodeDescription BASE_EMBEDDED { class CodeDescription BASE_EMBEDDED {
@ -657,12 +931,14 @@ class CodeDescription BASE_EMBEDDED {
Code* code, Code* code,
Handle<Script> script, Handle<Script> script,
GDBJITLineInfo* lineinfo, GDBJITLineInfo* lineinfo,
GDBJITInterface::CodeTag tag) GDBJITInterface::CodeTag tag,
CompilationInfo* info)
: name_(name), : name_(name),
code_(code), code_(code),
script_(script), script_(script),
lineinfo_(lineinfo), lineinfo_(lineinfo),
tag_(tag) { tag_(tag),
info_(info) {
} }
const char* name() const { const char* name() const {
@ -677,6 +953,14 @@ class CodeDescription BASE_EMBEDDED {
return tag_; return tag_;
} }
CompilationInfo* info() const {
return info_;
}
bool IsInfoAvailable() const {
return info_ != NULL;
}
uintptr_t CodeStart() const { uintptr_t CodeStart() const {
return reinterpret_cast<uintptr_t>(code_->instruction_start()); return reinterpret_cast<uintptr_t>(code_->instruction_start());
} }
@ -724,12 +1008,13 @@ class CodeDescription BASE_EMBEDDED {
Handle<Script> script_; Handle<Script> script_;
GDBJITLineInfo* lineinfo_; GDBJITLineInfo* lineinfo_;
GDBJITInterface::CodeTag tag_; GDBJITInterface::CodeTag tag_;
CompilationInfo* info_;
#ifdef V8_TARGET_ARCH_X64 #ifdef V8_TARGET_ARCH_X64
uintptr_t stack_state_start_addresses_[STACK_STATE_MAX]; uintptr_t stack_state_start_addresses_[STACK_STATE_MAX];
#endif #endif
}; };
#if defined(__ELF)
static void CreateSymbolsTable(CodeDescription* desc, static void CreateSymbolsTable(CodeDescription* desc,
ELF* elf, ELF* elf,
int text_section_index) { int text_section_index) {
@ -754,14 +1039,42 @@ static void CreateSymbolsTable(CodeDescription* desc,
ELFSymbol::TYPE_FUNC, ELFSymbol::TYPE_FUNC,
text_section_index)); text_section_index));
} }
#endif // defined(__ELF)
class DebugInfoSection : public ELFSection { class DebugInfoSection : public DebugSection {
public: public:
explicit DebugInfoSection(CodeDescription* desc) explicit DebugInfoSection(CodeDescription* desc)
: ELFSection(".debug_info", TYPE_PROGBITS, 1), desc_(desc) { } #if defined(__ELF)
: ELFSection(".debug_info", TYPE_PROGBITS, 1),
#else
: MachOSection("__debug_info",
"__DWARF",
1,
MachOSection::S_REGULAR | MachOSection::S_ATTR_DEBUG),
#endif
desc_(desc) { }
// DWARF2 standard
enum DWARF2LocationOp {
DW_OP_reg0 = 0x50,
DW_OP_reg1 = 0x51,
DW_OP_reg2 = 0x52,
DW_OP_reg3 = 0x53,
DW_OP_reg4 = 0x54,
DW_OP_reg5 = 0x55,
DW_OP_reg6 = 0x56,
DW_OP_reg7 = 0x57,
DW_OP_fbreg = 0x91 // 1 param: SLEB128 offset
};
enum DWARF2Encoding {
DW_ATE_ADDRESS = 0x1,
DW_ATE_SIGNED = 0x5
};
bool WriteBody(Writer* w) { bool WriteBody(Writer* w) {
uintptr_t cu_start = w->position();
Writer::Slot<uint32_t> size = w->CreateSlotHere<uint32_t>(); Writer::Slot<uint32_t> size = w->CreateSlotHere<uint32_t>();
uintptr_t start = w->position(); uintptr_t start = w->position();
w->Write<uint16_t>(2); // DWARF version. w->Write<uint16_t>(2); // DWARF version.
@ -773,6 +1086,123 @@ class DebugInfoSection : public ELFSection {
w->Write<intptr_t>(desc_->CodeStart()); w->Write<intptr_t>(desc_->CodeStart());
w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize()); w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize());
w->Write<uint32_t>(0); w->Write<uint32_t>(0);
uint32_t ty_offset = static_cast<uint32_t>(w->position() - cu_start);
w->WriteULEB128(3);
w->Write<uint8_t>(kPointerSize);
w->WriteString("v8value");
if (desc_->IsInfoAvailable()) {
CompilationInfo* info = desc_->info();
ScopeInfo<FreeStoreAllocationPolicy> scope_info(info->scope());
w->WriteULEB128(2);
w->WriteString(desc_->name());
w->Write<intptr_t>(desc_->CodeStart());
w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize());
Writer::Slot<uint32_t> fb_block_size = w->CreateSlotHere<uint32_t>();
uintptr_t fb_block_start = w->position();
#if defined(V8_TARGET_ARCH_IA32)
w->Write<uint8_t>(DW_OP_reg5); // The frame pointer's here on ia32
#elif defined(V8_TARGET_ARCH_X64)
w->Write<uint8_t>(DW_OP_reg6); // and here on x64.
#else
#error Unsupported target architecture.
#endif
fb_block_size.set(static_cast<uint32_t>(w->position() - fb_block_start));
int params = scope_info.number_of_parameters();
int slots = scope_info.number_of_stack_slots();
int context_slots = scope_info.number_of_context_slots();
// The real slot ID is internal_slots + context_slot_id.
int internal_slots = Context::MIN_CONTEXT_SLOTS;
int locals = scope_info.NumberOfLocals();
int current_abbreviation = 4;
for (int param = 0; param < params; ++param) {
w->WriteULEB128(current_abbreviation++);
w->WriteString(
*scope_info.parameter_name(param)->ToCString(DISALLOW_NULLS));
w->Write<uint32_t>(ty_offset);
Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>();
uintptr_t block_start = w->position();
w->Write<uint8_t>(DW_OP_fbreg);
w->WriteSLEB128(
JavaScriptFrameConstants::kLastParameterOffset +
kPointerSize * (params - param - 1));
block_size.set(static_cast<uint32_t>(w->position() - block_start));
}
EmbeddedVector<char, 256> buffer;
StringBuilder builder(buffer.start(), buffer.length());
for (int slot = 0; slot < slots; ++slot) {
w->WriteULEB128(current_abbreviation++);
builder.Reset();
builder.AddFormatted("slot%d", slot);
w->WriteString(builder.Finalize());
}
// See contexts.h for more information.
ASSERT(Context::MIN_CONTEXT_SLOTS == 4);
ASSERT(Context::CLOSURE_INDEX == 0);
ASSERT(Context::PREVIOUS_INDEX == 1);
ASSERT(Context::EXTENSION_INDEX == 2);
ASSERT(Context::GLOBAL_INDEX == 3);
w->WriteULEB128(current_abbreviation++);
w->WriteString(".closure");
w->WriteULEB128(current_abbreviation++);
w->WriteString(".previous");
w->WriteULEB128(current_abbreviation++);
w->WriteString(".extension");
w->WriteULEB128(current_abbreviation++);
w->WriteString(".global");
for (int context_slot = 0;
context_slot < context_slots;
++context_slot) {
w->WriteULEB128(current_abbreviation++);
builder.Reset();
builder.AddFormatted("context_slot%d", context_slot + internal_slots);
w->WriteString(builder.Finalize());
}
for (int local = 0; local < locals; ++local) {
w->WriteULEB128(current_abbreviation++);
w->WriteString(
*scope_info.LocalName(local)->ToCString(DISALLOW_NULLS));
w->Write<uint32_t>(ty_offset);
Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>();
uintptr_t block_start = w->position();
w->Write<uint8_t>(DW_OP_fbreg);
w->WriteSLEB128(
JavaScriptFrameConstants::kLocal0Offset -
kPointerSize * local);
block_size.set(static_cast<uint32_t>(w->position() - block_start));
}
{
w->WriteULEB128(current_abbreviation++);
w->WriteString("__function");
w->Write<uint32_t>(ty_offset);
Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>();
uintptr_t block_start = w->position();
w->Write<uint8_t>(DW_OP_fbreg);
w->WriteSLEB128(JavaScriptFrameConstants::kFunctionOffset);
block_size.set(static_cast<uint32_t>(w->position() - block_start));
}
{
w->WriteULEB128(current_abbreviation++);
w->WriteString("__context");
w->Write<uint32_t>(ty_offset);
Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>();
uintptr_t block_start = w->position();
w->Write<uint8_t>(DW_OP_fbreg);
w->WriteSLEB128(StandardFrameConstants::kContextOffset);
block_size.set(static_cast<uint32_t>(w->position() - block_start));
}
}
size.set(static_cast<uint32_t>(w->position() - start)); size.set(static_cast<uint32_t>(w->position() - start));
return true; return true;
} }
@ -782,13 +1212,28 @@ class DebugInfoSection : public ELFSection {
}; };
class DebugAbbrevSection : public ELFSection { class DebugAbbrevSection : public DebugSection {
public: public:
DebugAbbrevSection() : ELFSection(".debug_abbrev", TYPE_PROGBITS, 1) { } explicit DebugAbbrevSection(CodeDescription* desc)
#ifdef __ELF
: ELFSection(".debug_abbrev", TYPE_PROGBITS, 1),
#else
: MachOSection("__debug_abbrev",
"__DWARF",
1,
MachOSection::S_REGULAR | MachOSection::S_ATTR_DEBUG),
#endif
desc_(desc) { }
// DWARF2 standard, figure 14. // DWARF2 standard, figure 14.
enum DWARF2Tags { enum DWARF2Tags {
DW_TAG_COMPILE_UNIT = 0x11 DW_TAG_FORMAL_PARAMETER = 0x05,
DW_TAG_POINTER_TYPE = 0xf,
DW_TAG_COMPILE_UNIT = 0x11,
DW_TAG_STRUCTURE_TYPE = 0x13,
DW_TAG_BASE_TYPE = 0x24,
DW_TAG_SUBPROGRAM = 0x2e,
DW_TAG_VARIABLE = 0x34
}; };
// DWARF2 standard, figure 16. // DWARF2 standard, figure 16.
@ -799,23 +1244,55 @@ class DebugAbbrevSection : public ELFSection {
// DWARF standard, figure 17. // DWARF standard, figure 17.
enum DWARF2Attribute { enum DWARF2Attribute {
DW_AT_LOCATION = 0x2,
DW_AT_NAME = 0x3, DW_AT_NAME = 0x3,
DW_AT_BYTE_SIZE = 0xb,
DW_AT_STMT_LIST = 0x10, DW_AT_STMT_LIST = 0x10,
DW_AT_LOW_PC = 0x11, DW_AT_LOW_PC = 0x11,
DW_AT_HIGH_PC = 0x12 DW_AT_HIGH_PC = 0x12,
DW_AT_ENCODING = 0x3e,
DW_AT_FRAME_BASE = 0x40,
DW_AT_TYPE = 0x49
}; };
// DWARF2 standard, figure 19. // DWARF2 standard, figure 19.
enum DWARF2AttributeForm { enum DWARF2AttributeForm {
DW_FORM_ADDR = 0x1, DW_FORM_ADDR = 0x1,
DW_FORM_BLOCK4 = 0x4,
DW_FORM_STRING = 0x8, DW_FORM_STRING = 0x8,
DW_FORM_DATA4 = 0x6 DW_FORM_DATA4 = 0x6,
DW_FORM_BLOCK = 0x9,
DW_FORM_DATA1 = 0xb,
DW_FORM_FLAG = 0xc,
DW_FORM_REF4 = 0x13
}; };
void WriteVariableAbbreviation(Writer* w,
int abbreviation_code,
bool has_value,
bool is_parameter) {
w->WriteULEB128(abbreviation_code);
w->WriteULEB128(is_parameter ? DW_TAG_FORMAL_PARAMETER : DW_TAG_VARIABLE);
w->Write<uint8_t>(DW_CHILDREN_NO);
w->WriteULEB128(DW_AT_NAME);
w->WriteULEB128(DW_FORM_STRING);
if (has_value) {
w->WriteULEB128(DW_AT_TYPE);
w->WriteULEB128(DW_FORM_REF4);
w->WriteULEB128(DW_AT_LOCATION);
w->WriteULEB128(DW_FORM_BLOCK4);
}
w->WriteULEB128(0);
w->WriteULEB128(0);
}
bool WriteBody(Writer* w) { bool WriteBody(Writer* w) {
w->WriteULEB128(1); int current_abbreviation = 1;
bool extra_info = desc_->IsInfoAvailable();
ASSERT(desc_->IsLineInfoAvailable());
w->WriteULEB128(current_abbreviation++);
w->WriteULEB128(DW_TAG_COMPILE_UNIT); w->WriteULEB128(DW_TAG_COMPILE_UNIT);
w->Write<uint8_t>(DW_CHILDREN_NO); w->Write<uint8_t>(extra_info ? DW_CHILDREN_YES : DW_CHILDREN_NO);
w->WriteULEB128(DW_AT_NAME); w->WriteULEB128(DW_AT_NAME);
w->WriteULEB128(DW_FORM_STRING); w->WriteULEB128(DW_FORM_STRING);
w->WriteULEB128(DW_AT_LOW_PC); w->WriteULEB128(DW_AT_LOW_PC);
@ -826,16 +1303,101 @@ class DebugAbbrevSection : public ELFSection {
w->WriteULEB128(DW_FORM_DATA4); w->WriteULEB128(DW_FORM_DATA4);
w->WriteULEB128(0); w->WriteULEB128(0);
w->WriteULEB128(0); w->WriteULEB128(0);
if (extra_info) {
CompilationInfo* info = desc_->info();
ScopeInfo<FreeStoreAllocationPolicy> scope_info(info->scope());
int params = scope_info.number_of_parameters();
int slots = scope_info.number_of_stack_slots();
int context_slots = scope_info.number_of_context_slots();
// The real slot ID is internal_slots + context_slot_id.
int internal_slots = Context::MIN_CONTEXT_SLOTS;
int locals = scope_info.NumberOfLocals();
int total_children =
params + slots + context_slots + internal_slots + locals + 2;
// The extra duplication below seems to be necessary to keep
// gdb from getting upset on OSX.
w->WriteULEB128(current_abbreviation++); // Abbreviation code.
w->WriteULEB128(DW_TAG_SUBPROGRAM);
w->Write<uint8_t>(
total_children != 0 ? DW_CHILDREN_YES : DW_CHILDREN_NO);
w->WriteULEB128(DW_AT_NAME);
w->WriteULEB128(DW_FORM_STRING);
w->WriteULEB128(DW_AT_LOW_PC);
w->WriteULEB128(DW_FORM_ADDR);
w->WriteULEB128(DW_AT_HIGH_PC);
w->WriteULEB128(DW_FORM_ADDR);
w->WriteULEB128(DW_AT_FRAME_BASE);
w->WriteULEB128(DW_FORM_BLOCK4);
w->WriteULEB128(0);
w->WriteULEB128(0);
w->WriteULEB128(current_abbreviation++);
w->WriteULEB128(DW_TAG_STRUCTURE_TYPE);
w->Write<uint8_t>(DW_CHILDREN_NO);
w->WriteULEB128(DW_AT_BYTE_SIZE);
w->WriteULEB128(DW_FORM_DATA1);
w->WriteULEB128(DW_AT_NAME);
w->WriteULEB128(DW_FORM_STRING);
w->WriteULEB128(0); w->WriteULEB128(0);
w->WriteULEB128(0);
for (int param = 0; param < params; ++param) {
WriteVariableAbbreviation(w, current_abbreviation++, true, true);
}
for (int slot = 0; slot < slots; ++slot) {
WriteVariableAbbreviation(w, current_abbreviation++, false, false);
}
for (int internal_slot = 0;
internal_slot < internal_slots;
++internal_slot) {
WriteVariableAbbreviation(w, current_abbreviation++, false, false);
}
for (int context_slot = 0;
context_slot < context_slots;
++context_slot) {
WriteVariableAbbreviation(w, current_abbreviation++, false, false);
}
for (int local = 0; local < locals; ++local) {
WriteVariableAbbreviation(w, current_abbreviation++, true, false);
}
// The function.
WriteVariableAbbreviation(w, current_abbreviation++, true, false);
// The context.
WriteVariableAbbreviation(w, current_abbreviation++, true, false);
if (total_children != 0) {
w->WriteULEB128(0); // Terminate the sibling list.
}
}
w->WriteULEB128(0); // Terminate the table.
return true; return true;
} }
private:
CodeDescription* desc_;
}; };
class DebugLineSection : public ELFSection { class DebugLineSection : public DebugSection {
public: public:
explicit DebugLineSection(CodeDescription* desc) explicit DebugLineSection(CodeDescription* desc)
#ifdef __ELF
: ELFSection(".debug_line", TYPE_PROGBITS, 1), : ELFSection(".debug_line", TYPE_PROGBITS, 1),
#else
: MachOSection("__debug_line",
"__DWARF",
1,
MachOSection::S_REGULAR | MachOSection::S_ATTR_DEBUG),
#endif
desc_(desc) { } desc_(desc) { }
// DWARF2 standard, figure 34. // DWARF2 standard, figure 34.
@ -992,8 +1554,7 @@ class DebugLineSection : public ELFSection {
#ifdef V8_TARGET_ARCH_X64 #ifdef V8_TARGET_ARCH_X64
class UnwindInfoSection : public DebugSection {
class UnwindInfoSection : public ELFSection {
public: public:
explicit UnwindInfoSection(CodeDescription *desc); explicit UnwindInfoSection(CodeDescription *desc);
virtual bool WriteBody(Writer *w); virtual bool WriteBody(Writer *w);
@ -1079,8 +1640,13 @@ void UnwindInfoSection::WriteLength(Writer *w,
UnwindInfoSection::UnwindInfoSection(CodeDescription *desc) UnwindInfoSection::UnwindInfoSection(CodeDescription *desc)
: ELFSection(".eh_frame", TYPE_X86_64_UNWIND, 1), desc_(desc) #ifdef __ELF
{ } : ELFSection(".eh_frame", TYPE_X86_64_UNWIND, 1),
#else
: MachOSection("__eh_frame", "__TEXT", sizeof(uintptr_t),
MachOSection::S_REGULAR),
#endif
desc_(desc) { }
int UnwindInfoSection::WriteCIE(Writer *w) { int UnwindInfoSection::WriteCIE(Writer *w) {
Writer::Slot<uint32_t> cie_length_slot = w->CreateSlotHere<uint32_t>(); Writer::Slot<uint32_t> cie_length_slot = w->CreateSlotHere<uint32_t>();
@ -1212,15 +1778,14 @@ bool UnwindInfoSection::WriteBody(Writer *w) {
#endif // V8_TARGET_ARCH_X64 #endif // V8_TARGET_ARCH_X64
static void CreateDWARFSections(CodeDescription* desc, DebugObject* obj) {
static void CreateDWARFSections(CodeDescription* desc, ELF* elf) {
if (desc->IsLineInfoAvailable()) { if (desc->IsLineInfoAvailable()) {
elf->AddSection(new DebugInfoSection(desc)); obj->AddSection(new DebugInfoSection(desc));
elf->AddSection(new DebugAbbrevSection); obj->AddSection(new DebugAbbrevSection(desc));
elf->AddSection(new DebugLineSection(desc)); obj->AddSection(new DebugLineSection(desc));
} }
#ifdef V8_TARGET_ARCH_X64 #ifdef V8_TARGET_ARCH_X64
elf->AddSection(new UnwindInfoSection(desc)); obj->AddSection(new UnwindInfoSection(desc));
#endif #endif
} }
@ -1260,6 +1825,13 @@ extern "C" {
// Static initialization is necessary to prevent GDB from seeing // Static initialization is necessary to prevent GDB from seeing
// uninitialized descriptor. // uninitialized descriptor.
JITDescriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; JITDescriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
#ifdef OBJECT_PRINT
void __gdb_print_v8_object(MaybeObject* object) {
object->Print();
fprintf(stdout, "\n");
}
#endif
} }
@ -1283,17 +1855,23 @@ static void DestroyCodeEntry(JITCodeEntry* entry) {
} }
static void RegisterCodeEntry(JITCodeEntry* entry) { static void RegisterCodeEntry(JITCodeEntry* entry,
bool dump_if_enabled,
const char* name_hint) {
#if defined(DEBUG) && !defined(WIN32) #if defined(DEBUG) && !defined(WIN32)
static int file_num = 0; static int file_num = 0;
if (FLAG_gdbjit_dump) { if (FLAG_gdbjit_dump && dump_if_enabled) {
static const int kMaxFileNameSize = 64; static const int kMaxFileNameSize = 64;
static const char* kElfFilePrefix = "/tmp/elfdump"; static const char* kElfFilePrefix = "/tmp/elfdump";
static const char* kObjFileExt = ".o"; static const char* kObjFileExt = ".o";
char file_name[64]; char file_name[64];
OS::SNPrintF(Vector<char>(file_name, kMaxFileNameSize), "%s%d%s", OS::SNPrintF(Vector<char>(file_name, kMaxFileNameSize),
kElfFilePrefix, file_num++, kObjFileExt); "%s%s%d%s",
kElfFilePrefix,
(name_hint != NULL) ? name_hint : "",
file_num++,
kObjFileExt);
WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_); WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_);
} }
#endif #endif
@ -1327,7 +1905,18 @@ static void UnregisterCodeEntry(JITCodeEntry* entry) {
static JITCodeEntry* CreateELFObject(CodeDescription* desc) { static JITCodeEntry* CreateELFObject(CodeDescription* desc) {
ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT); ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT);
#ifdef __MACH_O
MachO mach_o;
Writer w(&mach_o);
mach_o.AddSection(new MachOTextSection(kCodeAlignment,
desc->CodeStart(),
desc->CodeSize()));
CreateDWARFSections(desc, &mach_o);
mach_o.Write(&w, desc->CodeStart(), desc->CodeSize());
#else
ELF elf; ELF elf;
Writer w(&elf); Writer w(&elf);
@ -1345,6 +1934,7 @@ static JITCodeEntry* CreateELFObject(CodeDescription* desc) {
CreateDWARFSections(desc, &elf); CreateDWARFSections(desc, &elf);
elf.Write(&w); elf.Write(&w);
#endif
return CreateCodeEntry(w.buffer(), w.position()); return CreateCodeEntry(w.buffer(), w.position());
} }
@ -1393,7 +1983,8 @@ static GDBJITLineInfo* UntagLineInfo(void* ptr) {
void GDBJITInterface::AddCode(Handle<String> name, void GDBJITInterface::AddCode(Handle<String> name,
Handle<Script> script, Handle<Script> script,
Handle<Code> code) { Handle<Code> code,
CompilationInfo* info) {
if (!FLAG_gdbjit) return; if (!FLAG_gdbjit) return;
// Force initialization of line_ends array. // Force initialization of line_ends array.
@ -1401,9 +1992,9 @@ void GDBJITInterface::AddCode(Handle<String> name,
if (!name.is_null()) { if (!name.is_null()) {
SmartPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS); SmartPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS);
AddCode(*name_cstring, *code, GDBJITInterface::FUNCTION, *script); AddCode(*name_cstring, *code, GDBJITInterface::FUNCTION, *script, info);
} else { } else {
AddCode("", *code, GDBJITInterface::FUNCTION, *script); AddCode("", *code, GDBJITInterface::FUNCTION, *script, info);
} }
} }
@ -1450,7 +2041,8 @@ Mutex* GDBJITInterface::mutex_ = OS::CreateMutex();
void GDBJITInterface::AddCode(const char* name, void GDBJITInterface::AddCode(const char* name,
Code* code, Code* code,
GDBJITInterface::CodeTag tag, GDBJITInterface::CodeTag tag,
Script* script) { Script* script,
CompilationInfo* info) {
if (!FLAG_gdbjit) return; if (!FLAG_gdbjit) return;
ScopedLock lock(mutex_); ScopedLock lock(mutex_);
@ -1465,7 +2057,8 @@ void GDBJITInterface::AddCode(const char* name,
script != NULL ? Handle<Script>(script) script != NULL ? Handle<Script>(script)
: Handle<Script>(), : Handle<Script>(),
lineinfo, lineinfo,
tag); tag,
info);
if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) { if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) {
delete lineinfo; delete lineinfo;
@ -1480,7 +2073,18 @@ void GDBJITInterface::AddCode(const char* name,
delete lineinfo; delete lineinfo;
e->value = entry; e->value = entry;
RegisterCodeEntry(entry); const char* name_hint = NULL;
bool should_dump = false;
if (FLAG_gdbjit_dump) {
if (strlen(FLAG_gdbjit_dump_filter) == 0) {
name_hint = name;
should_dump = true;
} else if (name != NULL) {
name_hint = strstr(name, FLAG_gdbjit_dump_filter);
should_dump = (name_hint != NULL);
}
}
RegisterCodeEntry(entry, should_dump, name_hint);
} }
@ -1500,7 +2104,7 @@ void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag,
builder.AddFormatted(": code object %p", static_cast<void*>(code)); builder.AddFormatted(": code object %p", static_cast<void*>(code));
} }
AddCode(builder.Finalize(), code, tag); AddCode(builder.Finalize(), code, tag, NULL, NULL);
} }

8
deps/v8/src/gdb-jit.h

@ -43,6 +43,8 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class CompilationInfo;
#define CODE_TAGS_LIST(V) \ #define CODE_TAGS_LIST(V) \
V(LOAD_IC) \ V(LOAD_IC) \
V(KEYED_LOAD_IC) \ V(KEYED_LOAD_IC) \
@ -113,11 +115,13 @@ class GDBJITInterface: public AllStatic {
static void AddCode(const char* name, static void AddCode(const char* name,
Code* code, Code* code,
CodeTag tag, CodeTag tag,
Script* script = NULL); Script* script,
CompilationInfo* info);
static void AddCode(Handle<String> name, static void AddCode(Handle<String> name,
Handle<Script> script, Handle<Script> script,
Handle<Code> code); Handle<Code> code,
CompilationInfo* info);
static void AddCode(CodeTag tag, String* name, Code* code); static void AddCode(CodeTag tag, String* name, Code* code);

7
deps/v8/src/handles.cc

@ -214,9 +214,10 @@ void NormalizeProperties(Handle<JSObject> object,
} }
void NormalizeElements(Handle<JSObject> object) { Handle<NumberDictionary> NormalizeElements(Handle<JSObject> object) {
CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), CALL_HEAP_FUNCTION(object->GetIsolate(),
object->NormalizeElements()); object->NormalizeElements(),
NumberDictionary);
} }

2
deps/v8/src/handles.h

@ -170,7 +170,7 @@ class HandleScope {
void NormalizeProperties(Handle<JSObject> object, void NormalizeProperties(Handle<JSObject> object,
PropertyNormalizationMode mode, PropertyNormalizationMode mode,
int expected_additional_properties); int expected_additional_properties);
void NormalizeElements(Handle<JSObject> object); Handle<NumberDictionary> NormalizeElements(Handle<JSObject> object);
void TransformToFastProperties(Handle<JSObject> object, void TransformToFastProperties(Handle<JSObject> object,
int unused_property_fields); int unused_property_fields);
MUST_USE_RESULT Handle<NumberDictionary> NumberDictionarySet( MUST_USE_RESULT Handle<NumberDictionary> NumberDictionarySet(

4
deps/v8/src/heap.cc

@ -33,6 +33,7 @@
#include "codegen.h" #include "codegen.h"
#include "compilation-cache.h" #include "compilation-cache.h"
#include "debug.h" #include "debug.h"
#include "deoptimizer.h"
#include "global-handles.h" #include "global-handles.h"
#include "heap-profiler.h" #include "heap-profiler.h"
#include "liveobjectlist-inl.h" #include "liveobjectlist-inl.h"
@ -4664,6 +4665,9 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
isolate_->debug()->Iterate(v); isolate_->debug()->Iterate(v);
if (isolate_->deoptimizer_data() != NULL) {
isolate_->deoptimizer_data()->Iterate(v);
}
#endif #endif
v->Synchronize("debug"); v->Synchronize("debug");
isolate_->compilation_cache()->Iterate(v); isolate_->compilation_cache()->Iterate(v);

41
deps/v8/src/hydrogen-instructions.cc

@ -669,7 +669,7 @@ void HCallRuntime::PrintDataTo(StringStream* stream) {
} }
void HClassOfTest::PrintDataTo(StringStream* stream) { void HClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("class_of_test("); stream->Add("class_of_test(");
value()->PrintNameTo(stream); value()->PrintNameTo(stream);
stream->Add(", \"%o\")", *class_name()); stream->Add(", \"%o\")", *class_name());
@ -747,7 +747,7 @@ void HUnaryOperation::PrintDataTo(StringStream* stream) {
} }
void HHasInstanceType::PrintDataTo(StringStream* stream) { void HHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream); value()->PrintNameTo(stream);
switch (from_) { switch (from_) {
case FIRST_JS_RECEIVER_TYPE: case FIRST_JS_RECEIVER_TYPE:
@ -768,7 +768,7 @@ void HHasInstanceType::PrintDataTo(StringStream* stream) {
} }
void HTypeofIs::PrintDataTo(StringStream* stream) { void HTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream); value()->PrintNameTo(stream);
stream->Add(" == "); stream->Add(" == ");
stream->Add(type_literal_->ToAsciiVector()); stream->Add(type_literal_->ToAsciiVector());
@ -1231,25 +1231,28 @@ Range* HShl::InferRange() {
void HCompare::PrintDataTo(StringStream* stream) { void HCompareGeneric::PrintDataTo(StringStream* stream) {
stream->Add(Token::Name(token())); stream->Add(Token::Name(token()));
stream->Add(" "); stream->Add(" ");
HBinaryOperation::PrintDataTo(stream); HBinaryOperation::PrintDataTo(stream);
} }
void HCompare::SetInputRepresentation(Representation r) { void HCompareIDAndBranch::PrintDataTo(StringStream* stream) {
stream->Add(Token::Name(token()));
stream->Add(" ");
left()->PrintNameTo(stream);
stream->Add(" ");
right()->PrintNameTo(stream);
}
void HCompareIDAndBranch::SetInputRepresentation(Representation r) {
input_representation_ = r; input_representation_ = r;
if (r.IsTagged()) { if (r.IsDouble()) {
SetAllSideEffects();
ClearFlag(kUseGVN);
} else if (r.IsDouble()) {
SetFlag(kDeoptimizeOnUndefined); SetFlag(kDeoptimizeOnUndefined);
ClearAllSideEffects();
SetFlag(kUseGVN);
} else { } else {
ClearAllSideEffects(); ASSERT(r.IsInteger32());
SetFlag(kUseGVN);
} }
} }
@ -1566,17 +1569,7 @@ HType HConstant::CalculateInferredType() {
} }
HType HCompare::CalculateInferredType() { HType HCompareGeneric::CalculateInferredType() {
return HType::Boolean();
}
HType HCompareObjectEq::CalculateInferredType() {
return HType::Boolean();
}
HType HUnaryPredicate::CalculateInferredType() {
return HType::Boolean(); return HType::Boolean();
} }

287
deps/v8/src/hydrogen-instructions.h

@ -72,6 +72,7 @@ class LChunkBuilder;
V(BitXor) \ V(BitXor) \
V(BlockEntry) \ V(BlockEntry) \
V(BoundsCheck) \ V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \ V(CallConstantFunction) \
V(CallFunction) \ V(CallFunction) \
V(CallGlobal) \ V(CallGlobal) \
@ -89,11 +90,12 @@ class LChunkBuilder;
V(CheckPrototypeMaps) \ V(CheckPrototypeMaps) \
V(CheckSmi) \ V(CheckSmi) \
V(ClampToUint8) \ V(ClampToUint8) \
V(ClassOfTest) \ V(ClassOfTestAndBranch) \
V(Compare) \ V(CompareIDAndBranch) \
V(CompareObjectEq) \ V(CompareGeneric) \
V(CompareObjectEqAndBranch) \
V(CompareMap) \ V(CompareMap) \
V(CompareConstantEq) \ V(CompareConstantEqAndBranch) \
V(Constant) \ V(Constant) \
V(Context) \ V(Context) \
V(DeleteProperty) \ V(DeleteProperty) \
@ -109,17 +111,17 @@ class LChunkBuilder;
V(GlobalObject) \ V(GlobalObject) \
V(GlobalReceiver) \ V(GlobalReceiver) \
V(Goto) \ V(Goto) \
V(HasCachedArrayIndex) \ V(HasCachedArrayIndexAndBranch) \
V(HasInstanceType) \ V(HasInstanceTypeAndBranch) \
V(In) \ V(In) \
V(InstanceOf) \ V(InstanceOf) \
V(InstanceOfKnownGlobal) \ V(InstanceOfKnownGlobal) \
V(InvokeFunction) \ V(InvokeFunction) \
V(IsConstructCall) \ V(IsConstructCallAndBranch) \
V(IsNull) \ V(IsNullAndBranch) \
V(IsObject) \ V(IsObjectAndBranch) \
V(IsSmi) \ V(IsSmiAndBranch) \
V(IsUndetectable) \ V(IsUndetectableAndBranch) \
V(JSArrayLength) \ V(JSArrayLength) \
V(LeaveInlined) \ V(LeaveInlined) \
V(LoadContextSlot) \ V(LoadContextSlot) \
@ -163,13 +165,12 @@ class LChunkBuilder;
V(StringCharFromCode) \ V(StringCharFromCode) \
V(StringLength) \ V(StringLength) \
V(Sub) \ V(Sub) \
V(Test) \
V(ThisFunction) \ V(ThisFunction) \
V(Throw) \ V(Throw) \
V(ToFastProperties) \ V(ToFastProperties) \
V(ToInt32) \ V(ToInt32) \
V(Typeof) \ V(Typeof) \
V(TypeofIs) \ V(TypeofIsAndBranch) \
V(UnaryMathOperation) \ V(UnaryMathOperation) \
V(UnknownOSRValue) \ V(UnknownOSRValue) \
V(UseConst) \ V(UseConst) \
@ -781,6 +782,7 @@ class HControlInstruction: public HInstruction {
public: public:
virtual HBasicBlock* SuccessorAt(int i) = 0; virtual HBasicBlock* SuccessorAt(int i) = 0;
virtual int SuccessorCount() = 0; virtual int SuccessorCount() = 0;
virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
@ -815,12 +817,13 @@ class HTemplateControlInstruction: public HControlInstruction {
public: public:
int SuccessorCount() { return S; } int SuccessorCount() { return S; }
HBasicBlock* SuccessorAt(int i) { return successors_[i]; } HBasicBlock* SuccessorAt(int i) { return successors_[i]; }
void SetSuccessorAt(int i, HBasicBlock* block) { successors_[i] = block; }
int OperandCount() { return V; } int OperandCount() { return V; }
HValue* OperandAt(int i) { return inputs_[i]; } HValue* OperandAt(int i) { return inputs_[i]; }
protected: protected:
void SetSuccessorAt(int i, HBasicBlock* block) { successors_[i] = block; }
void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; } void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; }
private: private:
@ -869,6 +872,9 @@ class HDeoptimize: public HControlInstruction {
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
} }
virtual void SetSuccessorAt(int i, HBasicBlock* block) {
UNREACHABLE();
}
void AddEnvironmentValue(HValue* value) { void AddEnvironmentValue(HValue* value) {
values_.Add(NULL); values_.Add(NULL);
@ -922,18 +928,21 @@ class HUnaryControlInstruction: public HTemplateControlInstruction<2, 1> {
}; };
class HTest: public HUnaryControlInstruction { class HBranch: public HUnaryControlInstruction {
public: public:
HTest(HValue* value, HBasicBlock* true_target, HBasicBlock* false_target) HBranch(HValue* value, HBasicBlock* true_target, HBasicBlock* false_target)
: HUnaryControlInstruction(value, true_target, false_target) { : HUnaryControlInstruction(value, true_target, false_target) {
ASSERT(true_target != NULL && false_target != NULL); ASSERT(true_target != NULL && false_target != NULL);
} }
explicit HBranch(HValue* value)
: HUnaryControlInstruction(value, NULL, NULL) { }
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
return Representation::None(); return Representation::None();
} }
DECLARE_CONCRETE_INSTRUCTION(Test) DECLARE_CONCRETE_INSTRUCTION(Branch)
}; };
@ -2520,43 +2529,58 @@ class HArithmeticBinaryOperation: public HBinaryOperation {
}; };
class HCompare: public HBinaryOperation { class HCompareGeneric: public HBinaryOperation {
public: public:
HCompare(HValue* left, HValue* right, Token::Value token) HCompareGeneric(HValue* left, HValue* right, Token::Value token)
: HBinaryOperation(left, right), token_(token) { : HBinaryOperation(left, right), token_(token) {
ASSERT(Token::IsCompareOp(token)); ASSERT(Token::IsCompareOp(token));
set_representation(Representation::Tagged()); set_representation(Representation::Tagged());
SetAllSideEffects(); SetAllSideEffects();
} }
void SetInputRepresentation(Representation r);
virtual bool EmitAtUses() {
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
return input_representation_; return Representation::Tagged();
} }
Representation GetInputRepresentation() const { Representation GetInputRepresentation() const {
return input_representation_; return Representation::Tagged();
} }
Token::Value token() const { return token_; } Token::Value token() const { return token_; }
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType(); virtual HType CalculateInferredType();
virtual intptr_t Hashcode() { DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
return HValue::Hashcode() * 7 + token_;
private:
Token::Value token_;
};
class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> {
public:
HCompareIDAndBranch(HValue* left, HValue* right, Token::Value token)
: token_(token) {
ASSERT(Token::IsCompareOp(token));
SetOperandAt(0, left);
SetOperandAt(1, right);
} }
DECLARE_CONCRETE_INSTRUCTION(Compare) HValue* left() { return OperandAt(0); }
HValue* right() { return OperandAt(1); }
Token::Value token() const { return token_; }
protected: void SetInputRepresentation(Representation r);
virtual bool DataEquals(HValue* other) { Representation GetInputRepresentation() const {
HCompare* comp = HCompare::cast(other); return input_representation_;
return token_ == comp->token(); }
virtual Representation RequiredInputRepresentation(int index) const {
return input_representation_;
} }
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(CompareIDAndBranch)
private: private:
Representation input_representation_; Representation input_representation_;
@ -2564,61 +2588,39 @@ class HCompare: public HBinaryOperation {
}; };
class HCompareObjectEq: public HBinaryOperation { class HCompareObjectEqAndBranch: public HTemplateControlInstruction<2, 2> {
public: public:
HCompareObjectEq(HValue* left, HValue* right) HCompareObjectEqAndBranch(HValue* left, HValue* right) {
: HBinaryOperation(left, right) { SetOperandAt(0, left);
set_representation(Representation::Tagged()); SetOperandAt(1, right);
SetFlag(kUseGVN);
SetFlag(kDependsOnMaps);
} }
virtual bool EmitAtUses() { HValue* left() { return OperandAt(0); }
return !HasSideEffects() && !HasMultipleUses(); HValue* right() { return OperandAt(1); }
}
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged(); return Representation::Tagged();
} }
virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(CompareObjectEq) DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
protected:
virtual bool DataEquals(HValue* other) { return true; }
}; };
class HCompareConstantEq: public HUnaryOperation { class HCompareConstantEqAndBranch: public HUnaryControlInstruction {
public: public:
HCompareConstantEq(HValue* left, int right, Token::Value op) HCompareConstantEqAndBranch(HValue* left, int right, Token::Value op)
: HUnaryOperation(left), op_(op), right_(right) { : HUnaryControlInstruction(left, NULL, NULL), op_(op), right_(right) {
ASSERT(op == Token::EQ_STRICT); ASSERT(op == Token::EQ_STRICT);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
} }
Token::Value op() const { return op_; } Token::Value op() const { return op_; }
int right() const { return right_; } int right() const { return right_; }
virtual bool EmitAtUses() {
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Integer32(); return Representation::Integer32();
} }
virtual HType CalculateInferredType() { return HType::Boolean(); } DECLARE_CONCRETE_INSTRUCTION(CompareConstantEqAndBranch);
DECLARE_CONCRETE_INSTRUCTION(CompareConstantEq);
protected:
virtual bool DataEquals(HValue* other) {
HCompareConstantEq* other_instr = HCompareConstantEq::cast(other);
return (op_ == other_instr->op_ &&
right_ == other_instr->right_);
}
private: private:
const Token::Value op_; const Token::Value op_;
@ -2626,139 +2628,112 @@ class HCompareConstantEq: public HUnaryOperation {
}; };
class HUnaryPredicate: public HUnaryOperation { class HIsNullAndBranch: public HUnaryControlInstruction {
public: public:
explicit HUnaryPredicate(HValue* value) : HUnaryOperation(value) { HIsNullAndBranch(HValue* value, bool is_strict)
set_representation(Representation::Tagged()); : HUnaryControlInstruction(value, NULL, NULL), is_strict_(is_strict) { }
SetFlag(kUseGVN);
}
virtual bool EmitAtUses() { bool is_strict() const { return is_strict_; }
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged(); return Representation::Tagged();
} }
virtual HType CalculateInferredType();
};
class HIsNull: public HUnaryPredicate {
public:
HIsNull(HValue* value, bool is_strict)
: HUnaryPredicate(value), is_strict_(is_strict) { }
bool is_strict() const { return is_strict_; }
DECLARE_CONCRETE_INSTRUCTION(IsNull)
protected: DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch)
virtual bool DataEquals(HValue* other) {
HIsNull* b = HIsNull::cast(other);
return is_strict_ == b->is_strict();
}
private: private:
bool is_strict_; bool is_strict_;
}; };
class HIsObject: public HUnaryPredicate { class HIsObjectAndBranch: public HUnaryControlInstruction {
public: public:
explicit HIsObject(HValue* value) : HUnaryPredicate(value) { } explicit HIsObjectAndBranch(HValue* value)
: HUnaryControlInstruction(value, NULL, NULL) { }
DECLARE_CONCRETE_INSTRUCTION(IsObject) virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
protected: DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
virtual bool DataEquals(HValue* other) { return true; }
}; };
class HIsSmi: public HUnaryPredicate { class HIsSmiAndBranch: public HUnaryControlInstruction {
public: public:
explicit HIsSmi(HValue* value) : HUnaryPredicate(value) { } explicit HIsSmiAndBranch(HValue* value)
: HUnaryControlInstruction(value, NULL, NULL) { }
DECLARE_CONCRETE_INSTRUCTION(IsSmi) DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
protected: protected:
virtual bool DataEquals(HValue* other) { return true; } virtual bool DataEquals(HValue* other) { return true; }
}; };
class HIsUndetectable: public HUnaryPredicate { class HIsUndetectableAndBranch: public HUnaryControlInstruction {
public: public:
explicit HIsUndetectable(HValue* value) : HUnaryPredicate(value) { } explicit HIsUndetectableAndBranch(HValue* value)
: HUnaryControlInstruction(value, NULL, NULL) { }
DECLARE_CONCRETE_INSTRUCTION(IsUndetectable) virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
protected: DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
virtual bool DataEquals(HValue* other) { return true; }
}; };
class HIsConstructCall: public HTemplateInstruction<0> { class HIsConstructCallAndBranch: public HTemplateControlInstruction<2, 0> {
public: public:
HIsConstructCall() {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
virtual bool EmitAtUses() {
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
return Representation::None(); return Representation::None();
} }
DECLARE_CONCRETE_INSTRUCTION(IsConstructCall) DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
protected:
virtual bool DataEquals(HValue* other) { return true; }
}; };
class HHasInstanceType: public HUnaryPredicate { class HHasInstanceTypeAndBranch: public HUnaryControlInstruction {
public: public:
HHasInstanceType(HValue* value, InstanceType type) HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
: HUnaryPredicate(value), from_(type), to_(type) { } : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
HHasInstanceType(HValue* value, InstanceType from, InstanceType to) HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
: HUnaryPredicate(value), from_(from), to_(to) { : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
ASSERT(to == LAST_TYPE); // Others not implemented yet in backend. ASSERT(to == LAST_TYPE); // Others not implemented yet in backend.
} }
InstanceType from() { return from_; } InstanceType from() { return from_; }
InstanceType to() { return to_; } InstanceType to() { return to_; }
virtual bool EmitAtUses() {
return !HasSideEffects() && !HasMultipleUses();
}
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(HasInstanceType) virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
protected:
virtual bool DataEquals(HValue* other) {
HHasInstanceType* b = HHasInstanceType::cast(other);
return (from_ == b->from()) && (to_ == b->to());
} }
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
private: private:
InstanceType from_; InstanceType from_;
InstanceType to_; // Inclusive range, not all combinations work. InstanceType to_; // Inclusive range, not all combinations work.
}; };
class HHasCachedArrayIndex: public HUnaryPredicate { class HHasCachedArrayIndexAndBranch: public HUnaryControlInstruction {
public: public:
explicit HHasCachedArrayIndex(HValue* value) : HUnaryPredicate(value) { } explicit HHasCachedArrayIndexAndBranch(HValue* value)
: HUnaryControlInstruction(value, NULL, NULL) { }
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex) virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
protected: DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
virtual bool DataEquals(HValue* other) { return true; }
}; };
@ -2780,42 +2755,40 @@ class HGetCachedArrayIndex: public HUnaryOperation {
}; };
class HClassOfTest: public HUnaryPredicate { class HClassOfTestAndBranch: public HUnaryControlInstruction {
public: public:
HClassOfTest(HValue* value, Handle<String> class_name) HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
: HUnaryPredicate(value), class_name_(class_name) { } : HUnaryControlInstruction(value, NULL, NULL),
class_name_(class_name) { }
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
DECLARE_CONCRETE_INSTRUCTION(ClassOfTest) virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
Handle<String> class_name() const { return class_name_; } Handle<String> class_name() const { return class_name_; }
protected:
virtual bool DataEquals(HValue* other) {
HClassOfTest* b = HClassOfTest::cast(other);
return class_name_.is_identical_to(b->class_name_);
}
private: private:
Handle<String> class_name_; Handle<String> class_name_;
}; };
class HTypeofIs: public HUnaryPredicate { class HTypeofIsAndBranch: public HUnaryControlInstruction {
public: public:
HTypeofIs(HValue* value, Handle<String> type_literal) HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
: HUnaryPredicate(value), type_literal_(type_literal) { } : HUnaryControlInstruction(value, NULL, NULL),
type_literal_(type_literal) { }
Handle<String> type_literal() { return type_literal_; } Handle<String> type_literal() { return type_literal_; }
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(TypeofIs) DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
protected: virtual Representation RequiredInputRepresentation(int index) const {
virtual bool DataEquals(HValue* other) { return Representation::Tagged();
HTypeofIs* b = HTypeofIs::cast(other);
return type_literal_.is_identical_to(b->type_literal_);
} }
private: private:

405
deps/v8/src/hydrogen.cc

File diff suppressed because it is too large

17
deps/v8/src/hydrogen.h

@ -498,6 +498,12 @@ class AstContext {
// the instruction as value. // the instruction as value.
virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0; virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
// Finishes the current basic block and materialize a boolean for
// value context, nothing for effect, generate a branch for test context.
// Call this function in tail position in the Visit functions for
// expressions.
virtual void ReturnControl(HControlInstruction* instr, int ast_id) = 0;
void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; } void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
bool is_for_typeof() { return for_typeof_; } bool is_for_typeof() { return for_typeof_; }
@ -532,6 +538,7 @@ class EffectContext: public AstContext {
virtual void ReturnValue(HValue* value); virtual void ReturnValue(HValue* value);
virtual void ReturnInstruction(HInstruction* instr, int ast_id); virtual void ReturnInstruction(HInstruction* instr, int ast_id);
virtual void ReturnControl(HControlInstruction* instr, int ast_id);
}; };
@ -544,6 +551,7 @@ class ValueContext: public AstContext {
virtual void ReturnValue(HValue* value); virtual void ReturnValue(HValue* value);
virtual void ReturnInstruction(HInstruction* instr, int ast_id); virtual void ReturnInstruction(HInstruction* instr, int ast_id);
virtual void ReturnControl(HControlInstruction* instr, int ast_id);
bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; } bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
@ -566,6 +574,7 @@ class TestContext: public AstContext {
virtual void ReturnValue(HValue* value); virtual void ReturnValue(HValue* value);
virtual void ReturnInstruction(HInstruction* instr, int ast_id); virtual void ReturnInstruction(HInstruction* instr, int ast_id);
virtual void ReturnControl(HControlInstruction* instr, int ast_id);
static TestContext* cast(AstContext* context) { static TestContext* cast(AstContext* context) {
ASSERT(context->IsTest()); ASSERT(context->IsTest());
@ -706,6 +715,10 @@ class HGraphBuilder: public AstVisitor {
void Bailout(const char* reason); void Bailout(const char* reason);
HBasicBlock* CreateJoin(HBasicBlock* first,
HBasicBlock* second,
int join_id);
private: private:
// Type of a member function that generates inline code for a native function. // Type of a member function that generates inline code for a native function.
typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call); typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
@ -779,10 +792,6 @@ class HGraphBuilder: public AstVisitor {
HBasicBlock* loop_entry, HBasicBlock* loop_entry,
BreakAndContinueInfo* break_info); BreakAndContinueInfo* break_info);
HBasicBlock* CreateJoin(HBasicBlock* first,
HBasicBlock* second,
int join_id);
// Create a back edge in the flow graph. body_exit is the predecessor // Create a back edge in the flow graph. body_exit is the predecessor
// block and loop_entry is the successor block. loop_successor is the // block and loop_entry is the successor block. loop_successor is the
// block where control flow exits the loop normally (e.g., via failure of // block where control flow exits the loop normally (e.g., via failure of

6
deps/v8/src/ia32/assembler-ia32.h

@ -835,7 +835,7 @@ class Assembler : public AssemblerBase {
void call(const Operand& adr); void call(const Operand& adr);
int CallSize(Handle<Code> code, RelocInfo::Mode mode); int CallSize(Handle<Code> code, RelocInfo::Mode mode);
void call(Handle<Code> code, void call(Handle<Code> code,
RelocInfo::Mode rmode, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
unsigned ast_id = kNoASTId); unsigned ast_id = kNoASTId);
// Jumps // Jumps
@ -990,7 +990,9 @@ class Assembler : public AssemblerBase {
void Print(); void Print();
// Check the code size generated from label to here. // Check the code size generated from label to here.
int SizeOfCodeGeneratedSince(Label* l) { return pc_offset() - l->pos(); } int SizeOfCodeGeneratedSince(Label* label) {
return pc_offset() - label->pos();
}
// Mark address of the ExitJSFrame code. // Mark address of the ExitJSFrame code.
void RecordJSReturn(); void RecordJSReturn();

11
deps/v8/src/ia32/code-stubs-ia32.cc

@ -554,12 +554,10 @@ void UnaryOpStub::Generate(MacroAssembler* masm) {
void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
__ pop(ecx); // Save return address. __ pop(ecx); // Save return address.
__ push(eax);
// the argument is now on top. __ push(eax); // the operand
// Push this stub's key. Although the operation and the type info are
// encoded into the key, the encoding is opaque, so push them too.
__ push(Immediate(Smi::FromInt(MinorKey())));
__ push(Immediate(Smi::FromInt(op_))); __ push(Immediate(Smi::FromInt(op_)));
__ push(Immediate(Smi::FromInt(mode_)));
__ push(Immediate(Smi::FromInt(operand_type_))); __ push(Immediate(Smi::FromInt(operand_type_)));
__ push(ecx); // Push return address. __ push(ecx); // Push return address.
@ -567,8 +565,7 @@ void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
// Patch the caller to an appropriate specialized stub and return the // Patch the caller to an appropriate specialized stub and return the
// operation result to the caller of the stub. // operation result to the caller of the stub.
__ TailCallExternalReference( __ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kUnaryOp_Patch), ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
masm->isolate()), 4, 1);
} }

14
deps/v8/src/ia32/code-stubs-ia32.h

@ -62,16 +62,11 @@ class TranscendentalCacheStub: public CodeStub {
class UnaryOpStub: public CodeStub { class UnaryOpStub: public CodeStub {
public: public:
UnaryOpStub(Token::Value op, UnaryOverwriteMode mode) UnaryOpStub(Token::Value op,
UnaryOverwriteMode mode,
UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
: op_(op), : op_(op),
mode_(mode), mode_(mode),
operand_type_(UnaryOpIC::UNINITIALIZED),
name_(NULL) {
}
UnaryOpStub(int key, UnaryOpIC::TypeInfo operand_type)
: op_(OpBits::decode(key)),
mode_(ModeBits::decode(key)),
operand_type_(operand_type), operand_type_(operand_type),
name_(NULL) { name_(NULL) {
} }
@ -89,8 +84,7 @@ class UnaryOpStub: public CodeStub {
#ifdef DEBUG #ifdef DEBUG
void Print() { void Print() {
PrintF("TypeRecordingUnaryOpStub %d (op %s), " PrintF("UnaryOpStub %d (op %s), (mode %d, runtime_type_info %s)\n",
"(mode %d, runtime_type_info %s)\n",
MinorKey(), MinorKey(),
Token::String(op_), Token::String(op_),
static_cast<int>(mode_), static_cast<int>(mode_),

29
deps/v8/src/ia32/deoptimizer-ia32.cc

@ -348,6 +348,9 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
output_ = new FrameDescription*[1]; output_ = new FrameDescription*[1];
output_[0] = new(output_frame_size) FrameDescription( output_[0] = new(output_frame_size) FrameDescription(
output_frame_size, function_); output_frame_size, function_);
#ifdef DEBUG
output_[0]->SetKind(Code::OPTIMIZED_FUNCTION);
#endif
// Clear the incoming parameters in the optimized frame to avoid // Clear the incoming parameters in the optimized frame to avoid
// confusing the garbage collector. // confusing the garbage collector.
@ -461,6 +464,9 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
// Allocate and store the output frame description. // Allocate and store the output frame description.
FrameDescription* output_frame = FrameDescription* output_frame =
new(output_frame_size) FrameDescription(output_frame_size, function); new(output_frame_size) FrameDescription(output_frame_size, function);
#ifdef DEBUG
output_frame->SetKind(Code::FUNCTION);
#endif
bool is_bottommost = (0 == frame_index); bool is_bottommost = (0 == frame_index);
bool is_topmost = (output_count_ - 1 == frame_index); bool is_topmost = (output_count_ - 1 == frame_index);
@ -587,7 +593,7 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
output_frame->SetState(Smi::FromInt(state)); output_frame->SetState(Smi::FromInt(state));
// Set the continuation for the topmost frame. // Set the continuation for the topmost frame.
if (is_topmost) { if (is_topmost && bailout_type_ != DEBUGGER) {
Builtins* builtins = isolate_->builtins(); Builtins* builtins = isolate_->builtins();
Code* continuation = (bailout_type_ == EAGER) Code* continuation = (bailout_type_ == EAGER)
? builtins->builtin(Builtins::kNotifyDeoptimized) ? builtins->builtin(Builtins::kNotifyDeoptimized)
@ -600,6 +606,27 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
} }
void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
// Set the register values. The values are not important as there are no
// callee saved registers in JavaScript frames, so all registers are
// spilled. Registers ebp and esp are set to the correct values though.
for (int i = 0; i < Register::kNumRegisters; i++) {
input_->SetRegister(i, i * 4);
}
input_->SetRegister(esp.code(), reinterpret_cast<intptr_t>(frame->sp()));
input_->SetRegister(ebp.code(), reinterpret_cast<intptr_t>(frame->fp()));
for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) {
input_->SetDoubleRegister(i, 0.0);
}
// Fill the frame content from the actual data on the frame.
for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
input_->SetFrameSlot(i, Memory::uint32_at(tos + i));
}
}
#define __ masm()-> #define __ masm()->
void Deoptimizer::EntryGenerator::Generate() { void Deoptimizer::EntryGenerator::Generate() {

200
deps/v8/src/ia32/full-codegen-ia32.cc

@ -78,15 +78,17 @@ class JumpPatchSite BASE_EMBEDDED {
} }
void EmitPatchInfo() { void EmitPatchInfo() {
if (patch_site_.is_bound()) {
int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
ASSERT(is_int8(delta_to_patch_site)); ASSERT(is_int8(delta_to_patch_site));
__ test(eax, Immediate(delta_to_patch_site)); __ test(eax, Immediate(delta_to_patch_site));
#ifdef DEBUG #ifdef DEBUG
info_emitted_ = true; info_emitted_ = true;
#endif #endif
} else {
__ nop(); // Signals no inlined code.
}
} }
bool is_bound() const { return patch_site_.is_bound(); }
private: private:
// jc will be patched with jz, jnc will become jnz. // jc will be patched with jz, jnc will become jnz.
@ -121,6 +123,7 @@ class JumpPatchSite BASE_EMBEDDED {
void FullCodeGenerator::Generate(CompilationInfo* info) { void FullCodeGenerator::Generate(CompilationInfo* info) {
ASSERT(info_ == NULL); ASSERT(info_ == NULL);
info_ = info; info_ = info;
scope_ = info->scope();
SetFunctionPosition(function()); SetFunctionPosition(function());
Comment cmnt(masm_, "[ function compiled by full code generator"); Comment cmnt(masm_, "[ function compiled by full code generator");
@ -140,7 +143,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ test(ecx, Operand(ecx)); __ test(ecx, Operand(ecx));
__ j(zero, &ok, Label::kNear); __ j(zero, &ok, Label::kNear);
// +1 for return address. // +1 for return address.
int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
__ mov(Operand(esp, receiver_offset), __ mov(Operand(esp, receiver_offset),
Immediate(isolate()->factory()->undefined_value())); Immediate(isolate()->factory()->undefined_value()));
__ bind(&ok); __ bind(&ok);
@ -152,7 +155,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ push(edi); // Callee's JS Function. __ push(edi); // Callee's JS Function.
{ Comment cmnt(masm_, "[ Allocate locals"); { Comment cmnt(masm_, "[ Allocate locals");
int locals_count = scope()->num_stack_slots(); int locals_count = info->scope()->num_stack_slots();
if (locals_count == 1) { if (locals_count == 1) {
__ push(Immediate(isolate()->factory()->undefined_value())); __ push(Immediate(isolate()->factory()->undefined_value()));
} else if (locals_count > 1) { } else if (locals_count > 1) {
@ -166,7 +169,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
bool function_in_register = true; bool function_in_register = true;
// Possibly allocate a local context. // Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
if (heap_slots > 0) { if (heap_slots > 0) {
Comment cmnt(masm_, "[ Allocate local context"); Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in edi. // Argument to NewContext is the function, which is still in edi.
@ -183,7 +186,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
// Copy parameters into context if necessary. // Copy parameters into context if necessary.
int num_parameters = scope()->num_parameters(); int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot(); Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (slot != NULL && slot->type() == Slot::CONTEXT) {
@ -213,11 +216,12 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
} }
// Receiver is just before the parameters on the caller's stack. // Receiver is just before the parameters on the caller's stack.
int offset = scope()->num_parameters() * kPointerSize; int num_parameters = info->scope()->num_parameters();
int offset = num_parameters * kPointerSize;
__ lea(edx, __ lea(edx,
Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
__ push(edx); __ push(edx);
__ SafePush(Immediate(Smi::FromInt(scope()->num_parameters()))); __ SafePush(Immediate(Smi::FromInt(num_parameters)));
// Arguments to ArgumentsAccessStub and/or New...: // Arguments to ArgumentsAccessStub and/or New...:
// function, receiver address, parameter count. // function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous // The stub will rewrite receiver and parameter count if the previous
@ -342,7 +346,7 @@ void FullCodeGenerator::EmitReturnSequence() {
__ mov(esp, ebp); __ mov(esp, ebp);
__ pop(ebp); __ pop(ebp);
int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize; int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
__ Ret(arguments_bytes, ecx); __ Ret(arguments_bytes, ecx);
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
// Check that the size of the code used for returning is large enough // Check that the size of the code used for returning is large enough
@ -754,7 +758,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ call(ic);
} }
} }
} }
@ -827,7 +831,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// Record position before stub call for type feedback. // Record position before stub call for type feedback.
SetSourcePosition(clause->position()); SetSourcePosition(clause->position());
Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
EmitCallIC(ic, &patch_site, clause->CompareId()); __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
patch_site.EmitPatchInfo();
__ test(eax, Operand(eax)); __ test(eax, Operand(eax));
__ j(not_equal, &next_test); __ j(not_equal, &next_test);
__ Drop(1); // Switch value is no longer needed. __ Drop(1); // Switch value is no longer needed.
@ -1120,7 +1125,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET ? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT; : RelocInfo::CODE_TARGET_CONTEXT;
EmitCallIC(ic, mode, AstNode::kNoNumber); __ call(ic, mode);
} }
@ -1200,7 +1205,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
__ SafeSet(eax, Immediate(key_literal->handle())); __ SafeSet(eax, Immediate(key_literal->handle()));
Handle<Code> ic = Handle<Code> ic =
isolate()->builtins()->KeyedLoadIC_Initialize(); isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
__ jmp(done); __ jmp(done);
} }
} }
@ -1222,7 +1227,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
__ mov(eax, GlobalObjectOperand()); __ mov(eax, GlobalObjectOperand());
__ mov(ecx, var->name()); __ mov(ecx, var->name());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(eax); context()->Plug(eax);
} else if (slot->type() == Slot::LOOKUP) { } else if (slot->type() == Slot::LOOKUP) {
@ -1368,7 +1373,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id()); __ call(ic, RelocInfo::CODE_TARGET, key->id());
PrepareForBailoutForId(key->id(), NO_REGISTERS); PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else { } else {
VisitForEffect(value); VisitForEffect(value);
@ -1601,14 +1606,14 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
ASSERT(!key->handle()->IsSmi()); ASSERT(!key->handle()->IsSmi());
__ mov(ecx, Immediate(key->handle())); __ mov(ecx, Immediate(key->handle()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
} }
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position()); SetSourcePosition(prop->position());
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
} }
@ -1629,7 +1634,8 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
__ bind(&stub_call); __ bind(&stub_call);
__ mov(eax, ecx); __ mov(eax, ecx);
BinaryOpStub stub(op, mode); BinaryOpStub stub(op, mode);
EmitCallIC(stub.GetCode(), &patch_site, expr->id()); __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
__ jmp(&done, Label::kNear); __ jmp(&done, Label::kNear);
// Smi case. // Smi case.
@ -1712,8 +1718,9 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
OverwriteMode mode) { OverwriteMode mode) {
__ pop(edx); __ pop(edx);
BinaryOpStub stub(op, mode); BinaryOpStub stub(op, mode);
// NULL signals no inlined smi code. JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
EmitCallIC(stub.GetCode(), NULL, expr->id()); __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
context()->Plug(eax); context()->Plug(eax);
} }
@ -1753,7 +1760,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ call(ic);
break; break;
} }
case KEYED_PROPERTY: { case KEYED_PROPERTY: {
@ -1776,7 +1783,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ call(ic);
break; break;
} }
} }
@ -1800,7 +1807,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) { } else if (op == Token::INIT_CONST) {
// Like var declarations, const declarations are hoisted to function // Like var declarations, const declarations are hoisted to function
@ -1893,7 +1900,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
// If the assignment ends an initialization block, revert to fast case. // If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) { if (expr->ends_initialization_block()) {
@ -1933,7 +1940,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
// If the assignment ends an initialization block, revert to fast case. // If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) { if (expr->ends_initialization_block()) {
@ -1984,7 +1991,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = Handle<Code> ic =
isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
EmitCallIC(ic, mode, expr->id()); __ call(ic, mode, expr->id());
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@ -2017,7 +2024,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize( Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
arg_count, in_loop); arg_count, in_loop);
__ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@ -2056,7 +2063,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
} }
// Push the receiver of the enclosing function. // Push the receiver of the enclosing function.
__ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
// Push the strict mode flag. // Push the strict mode flag.
__ push(Immediate(Smi::FromInt(strict_mode_flag()))); __ push(Immediate(Smi::FromInt(strict_mode_flag())));
@ -2193,7 +2200,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else { } else {
// Call to a keyed property. // Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call, // For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed EmitCallIC. // for a regular property use EmitKeyedCallWithIC.
if (prop->is_synthetic()) { if (prop->is_synthetic()) {
// Do not visit the object and key subexpressions (they are shared // Do not visit the object and key subexpressions (they are shared
// by all occurrences of the same rewritten parameter). // by all occurrences of the same rewritten parameter).
@ -2211,7 +2218,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
SetSourcePosition(prop->position()); SetSourcePosition(prop->position());
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
// Push result (function). // Push result (function).
__ push(eax); __ push(eax);
// Push Global receiver. // Push Global receiver.
@ -2599,7 +2606,7 @@ void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
// parameter count in eax. // parameter count in eax.
VisitForAccumulatorValue(args->at(0)); VisitForAccumulatorValue(args->at(0));
__ mov(edx, eax); __ mov(edx, eax);
__ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
__ CallStub(&stub); __ CallStub(&stub);
context()->Plug(eax); context()->Plug(eax);
@ -2611,7 +2618,7 @@ void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
Label exit; Label exit;
// Get the number of formal parameters. // Get the number of formal parameters.
__ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
// Check if the calling frame is an arguments adaptor frame. // Check if the calling frame is an arguments adaptor frame.
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
@ -3527,6 +3534,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
} }
void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
// Load the function into eax.
VisitForAccumulatorValue(args->at(0));
// Prepare for the test.
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
context()->PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Test for strict mode function.
__ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
__ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
1 << SharedFunctionInfo::kStrictModeBitWithinByte);
__ j(not_equal, if_true);
// Test for native function.
__ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
1 << SharedFunctionInfo::kNativeBitWithinByte);
__ j(not_equal, if_true);
// Not native or strict-mode function.
__ jmp(if_false);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
context()->Plug(if_true, if_false);
}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name(); Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') { if (name->length() > 0 && name->Get(0) == '_') {
@ -3557,7 +3597,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
RelocInfo::Mode mode = RelocInfo::CODE_TARGET; RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize( Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
arg_count, in_loop, mode); arg_count, in_loop, mode);
EmitCallIC(ic, mode, expr->id()); __ call(ic, mode, expr->id());
// Restore context register. // Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
} else { } else {
@ -3696,7 +3736,7 @@ void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
// accumulator register eax. // accumulator register eax.
VisitForAccumulatorValue(expr->expression()); VisitForAccumulatorValue(expr->expression());
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
EmitCallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
context()->Plug(eax); context()->Plug(eax);
} }
@ -3816,7 +3856,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ mov(edx, eax); __ mov(edx, eax);
__ mov(eax, Immediate(Smi::FromInt(1))); __ mov(eax, Immediate(Smi::FromInt(1)));
BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE);
EmitCallIC(stub.GetCode(), &patch_site, expr->CountId()); __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
patch_site.EmitPatchInfo();
__ bind(&done); __ bind(&done);
// Store the value returned in eax. // Store the value returned in eax.
@ -3849,7 +3890,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
@ -3866,7 +3907,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
// Result is on the stack // Result is on the stack
@ -3894,7 +3935,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference // Use a regular load, not a contextual load, to avoid a reference
// error. // error.
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ call(ic);
PrepareForBailout(expr, TOS_REG); PrepareForBailout(expr, TOS_REG);
context()->Plug(eax); context()->Plug(eax);
} else if (proxy != NULL && } else if (proxy != NULL &&
@ -4089,7 +4130,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
// Record position and call the compare IC. // Record position and call the compare IC.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
Handle<Code> ic = CompareIC::GetUninitialized(op); Handle<Code> ic = CompareIC::GetUninitialized(op);
EmitCallIC(ic, &patch_site, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
__ test(eax, Operand(eax)); __ test(eax, Operand(eax));
@ -4148,58 +4190,6 @@ Register FullCodeGenerator::context_register() {
} }
void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
RelocInfo::Mode mode,
unsigned ast_id) {
ASSERT(mode == RelocInfo::CODE_TARGET ||
mode == RelocInfo::CODE_TARGET_CONTEXT);
switch (ic->kind()) {
case Code::LOAD_IC:
__ IncrementCounter(isolate()->counters()->named_load_full(), 1);
break;
case Code::KEYED_LOAD_IC:
__ IncrementCounter(isolate()->counters()->keyed_load_full(), 1);
break;
case Code::STORE_IC:
__ IncrementCounter(isolate()->counters()->named_store_full(), 1);
break;
case Code::KEYED_STORE_IC:
__ IncrementCounter(isolate()->counters()->keyed_store_full(), 1);
default:
break;
}
__ call(ic, mode, ast_id);
}
void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
JumpPatchSite* patch_site,
unsigned ast_id) {
Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
__ IncrementCounter(counters->named_load_full(), 1);
break;
case Code::KEYED_LOAD_IC:
__ IncrementCounter(counters->keyed_load_full(), 1);
break;
case Code::STORE_IC:
__ IncrementCounter(counters->named_store_full(), 1);
break;
case Code::KEYED_STORE_IC:
__ IncrementCounter(counters->keyed_store_full(), 1);
default:
break;
}
__ call(ic, RelocInfo::CODE_TARGET, ast_id);
if (patch_site != NULL && patch_site->is_bound()) {
patch_site->EmitPatchInfo();
} else {
__ nop(); // Signals no inlined code.
}
}
void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
__ mov(Operand(ebp, frame_offset), value); __ mov(Operand(ebp, frame_offset), value);
@ -4212,19 +4202,20 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
if (scope()->is_global_scope()) { Scope* declaration_scope = scope()->DeclarationScope();
if (declaration_scope->is_global_scope()) {
// Contexts nested in the global context have a canonical empty function // Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global // as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty // code. Pass a smi sentinel and let the runtime look up the empty
// function. // function.
__ push(Immediate(Smi::FromInt(0))); __ push(Immediate(Smi::FromInt(0)));
} else if (scope()->is_eval_scope()) { } else if (declaration_scope->is_eval_scope()) {
// Contexts created by a call to eval have the same closure as the // Contexts nested inside eval code have the same closure as the context
// context calling eval, not the anonymous closure containing the eval // calling eval, not the anonymous closure containing the eval code.
// code. Fetch it from the context. // Fetch it from the context.
__ push(ContextOperand(esi, Context::CLOSURE_INDEX)); __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
} else { } else {
ASSERT(scope()->is_function_scope()); ASSERT(declaration_scope->is_function_scope());
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
} }
} }
@ -4236,12 +4227,12 @@ void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
void FullCodeGenerator::EnterFinallyBlock() { void FullCodeGenerator::EnterFinallyBlock() {
// Cook return address on top of stack (smi encoded Code* delta) // Cook return address on top of stack (smi encoded Code* delta)
ASSERT(!result_register().is(edx)); ASSERT(!result_register().is(edx));
__ mov(edx, Operand(esp, 0)); __ pop(edx);
__ sub(Operand(edx), Immediate(masm_->CodeObject())); __ sub(Operand(edx), Immediate(masm_->CodeObject()));
ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
ASSERT_EQ(0, kSmiTag); ASSERT_EQ(0, kSmiTag);
__ add(edx, Operand(edx)); // Convert to smi. __ SmiTag(edx);
__ mov(Operand(esp, 0), edx); __ push(edx);
// Store result register while executing finally block. // Store result register while executing finally block.
__ push(result_register()); __ push(result_register());
} }
@ -4249,15 +4240,12 @@ void FullCodeGenerator::EnterFinallyBlock() {
void FullCodeGenerator::ExitFinallyBlock() { void FullCodeGenerator::ExitFinallyBlock() {
ASSERT(!result_register().is(edx)); ASSERT(!result_register().is(edx));
// Restore result register from stack.
__ pop(result_register()); __ pop(result_register());
// Uncook return address. // Uncook return address.
__ mov(edx, Operand(esp, 0)); __ pop(edx);
__ sar(edx, 1); // Convert smi to int. __ SmiUntag(edx);
__ add(Operand(edx), Immediate(masm_->CodeObject())); __ add(Operand(edx), Immediate(masm_->CodeObject()));
__ mov(Operand(esp, 0), edx); __ jmp(Operand(edx));
// And return.
__ ret(0);
} }

2
deps/v8/src/ia32/ic-ia32.cc

@ -528,6 +528,8 @@ static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
Register backing_store = parameter_map; Register backing_store = parameter_map;
__ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset)); __ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
__ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
__ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset)); __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
__ cmp(key, Operand(scratch)); __ cmp(key, Operand(scratch));
__ j(greater_equal, slow_case); __ j(greater_equal, slow_case);

257
deps/v8/src/ia32/lithium-codegen-ia32.cc

@ -1367,7 +1367,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id());
Representation r = instr->hydrogen()->representation(); Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32()) { if (r.IsInteger32()) {
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
__ test(reg, Operand(reg)); __ test(reg, Operand(reg));
@ -1380,7 +1380,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
} else { } else {
ASSERT(r.IsTagged()); ASSERT(r.IsTagged());
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
if (instr->hydrogen()->type().IsBoolean()) { if (instr->hydrogen()->value()->type().IsBoolean()) {
__ cmp(reg, factory()->true_value()); __ cmp(reg, factory()->true_value());
EmitBranch(true_block, false_block, equal); EmitBranch(true_block, false_block, equal);
} else { } else {
@ -1474,32 +1474,6 @@ void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
} }
void LCodeGen::DoCmpID(LCmpID* instr) {
LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1);
LOperand* result = instr->result();
Label unordered;
if (instr->is_double()) {
// Don't base result on EFLAGS when a NaN is involved. Instead
// jump to the unordered case, which produces a false value.
__ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
__ j(parity_even, &unordered, Label::kNear);
} else {
EmitCmpI(left, right);
}
Label done;
Condition cc = TokenToCondition(instr->op(), instr->is_double());
__ mov(ToRegister(result), factory()->true_value());
__ j(cc, &done, Label::kNear);
__ bind(&unordered);
__ mov(ToRegister(result), factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
LOperand* left = instr->InputAt(0); LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1); LOperand* right = instr->InputAt(1);
@ -1520,23 +1494,9 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
} }
void LCodeGen::DoCmpObjectEq(LCmpObjectEq* instr) {
Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1));
Register result = ToRegister(instr->result());
__ cmp(left, Operand(right));
__ mov(result, factory()->true_value());
Label done;
__ j(equal, &done, Label::kNear);
__ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
Register left = ToRegister(instr->InputAt(0)); Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1)); Operand right = ToOperand(instr->InputAt(1));
int false_block = chunk_->LookupDestination(instr->false_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id());
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
@ -1545,19 +1505,6 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
} }
void LCodeGen::DoCmpConstantEq(LCmpConstantEq* instr) {
Register left = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label done;
__ cmp(left, instr->hydrogen()->right());
__ mov(result, factory()->true_value());
__ j(equal, &done, Label::kNear);
__ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
Register left = ToRegister(instr->InputAt(0)); Register left = ToRegister(instr->InputAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
@ -1568,43 +1515,6 @@ void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
} }
void LCodeGen::DoIsNull(LIsNull* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
// TODO(fsc): If the expression is known to be a smi, then it's
// definitely not null. Materialize false.
__ cmp(reg, factory()->null_value());
if (instr->is_strict()) {
__ mov(result, factory()->true_value());
Label done;
__ j(equal, &done, Label::kNear);
__ mov(result, factory()->false_value());
__ bind(&done);
} else {
Label true_value, false_value, done;
__ j(equal, &true_value, Label::kNear);
__ cmp(reg, factory()->undefined_value());
__ j(equal, &true_value, Label::kNear);
__ JumpIfSmi(reg, &false_value, Label::kNear);
// Check for undetectable objects by looking in the bit field in
// the map. The object has already been smi checked.
Register scratch = result;
__ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
__ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
__ test(scratch, Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, &true_value, Label::kNear);
__ bind(&false_value);
__ mov(result, factory()->false_value());
__ jmp(&done, Label::kNear);
__ bind(&true_value);
__ mov(result, factory()->true_value());
__ bind(&done);
}
}
void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
@ -1658,25 +1568,6 @@ Condition LCodeGen::EmitIsObject(Register input,
} }
void LCodeGen::DoIsObject(LIsObject* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label is_false, is_true, done;
Condition true_cond = EmitIsObject(reg, result, &is_false, &is_true);
__ j(true_cond, &is_true);
__ bind(&is_false);
__ mov(result, factory()->false_value());
__ jmp(&done);
__ bind(&is_true);
__ mov(result, factory()->true_value());
__ bind(&done);
}
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0)); Register temp = ToRegister(instr->TempAt(0));
@ -1692,19 +1583,6 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
} }
void LCodeGen::DoIsSmi(LIsSmi* instr) {
Operand input = ToOperand(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
Label done;
__ mov(result, factory()->true_value());
__ JumpIfSmi(input, &done, Label::kNear);
__ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
Operand input = ToOperand(instr->InputAt(0)); Operand input = ToOperand(instr->InputAt(0));
@ -1716,26 +1594,6 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
} }
void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
Label false_label, done;
STATIC_ASSERT(kSmiTag == 0);
__ JumpIfSmi(input, &false_label, Label::kNear);
__ mov(result, FieldOperand(input, HeapObject::kMapOffset));
__ test_b(FieldOperand(result, Map::kBitFieldOffset),
1 << Map::kIsUndetectable);
__ j(zero, &false_label, Label::kNear);
__ mov(result, factory()->true_value());
__ jmp(&done);
__ bind(&false_label);
__ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0)); Register temp = ToRegister(instr->TempAt(0));
@ -1752,7 +1610,7 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
} }
static InstanceType TestType(HHasInstanceType* instr) { static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from(); InstanceType from = instr->from();
InstanceType to = instr->to(); InstanceType to = instr->to();
if (from == FIRST_TYPE) return to; if (from == FIRST_TYPE) return to;
@ -1761,7 +1619,7 @@ static InstanceType TestType(HHasInstanceType* instr) {
} }
static Condition BranchCondition(HHasInstanceType* instr) { static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from(); InstanceType from = instr->from();
InstanceType to = instr->to(); InstanceType to = instr->to();
if (from == to) return equal; if (from == to) return equal;
@ -1772,24 +1630,6 @@ static Condition BranchCondition(HHasInstanceType* instr) {
} }
void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
Label done, is_false;
__ JumpIfSmi(input, &is_false, Label::kNear);
__ CmpObjectType(input, TestType(instr->hydrogen()), result);
__ j(NegateCondition(BranchCondition(instr->hydrogen())),
&is_false, Label::kNear);
__ mov(result, factory()->true_value());
__ jmp(&done, Label::kNear);
__ bind(&is_false);
__ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0)); Register temp = ToRegister(instr->TempAt(0));
@ -1819,21 +1659,6 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
} }
void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
__ mov(result, factory()->true_value());
__ test(FieldOperand(input, String::kHashFieldOffset),
Immediate(String::kContainsCachedArrayIndexMask));
Label done;
__ j(zero, &done, Label::kNear);
__ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoHasCachedArrayIndexAndBranch( void LCodeGen::DoHasCachedArrayIndexAndBranch(
LHasCachedArrayIndexAndBranch* instr) { LHasCachedArrayIndexAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
@ -1904,29 +1729,6 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
} }
void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(input.is(result));
Register temp = ToRegister(instr->TempAt(0));
Handle<String> class_name = instr->hydrogen()->class_name();
Label done;
Label is_true, is_false;
EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input);
__ j(not_equal, &is_false, Label::kNear);
__ bind(&is_true);
__ mov(result, factory()->true_value());
__ jmp(&done, Label::kNear);
__ bind(&is_false);
__ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0)); Register temp = ToRegister(instr->TempAt(0));
@ -3882,14 +3684,14 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
void LCodeGen::DoCheckSmi(LCheckSmi* instr) { void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
LOperand* input = instr->InputAt(0); LOperand* input = instr->InputAt(0);
__ test(ToRegister(input), Immediate(kSmiTagMask)); __ test(ToOperand(input), Immediate(kSmiTagMask));
DeoptimizeIf(not_zero, instr->environment()); DeoptimizeIf(not_zero, instr->environment());
} }
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
LOperand* input = instr->InputAt(0); LOperand* input = instr->InputAt(0);
__ test(ToRegister(input), Immediate(kSmiTagMask)); __ test(ToOperand(input), Immediate(kSmiTagMask));
DeoptimizeIf(zero, instr->environment()); DeoptimizeIf(zero, instr->environment());
} }
@ -3941,8 +3743,8 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
void LCodeGen::DoCheckFunction(LCheckFunction* instr) { void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
ASSERT(instr->InputAt(0)->IsRegister()); ASSERT(instr->InputAt(0)->IsRegister());
Register reg = ToRegister(instr->InputAt(0)); Operand operand = ToOperand(instr->InputAt(0));
__ cmp(reg, instr->hydrogen()->target()); __ cmp(operand, instr->hydrogen()->target());
DeoptimizeIf(not_equal, instr->environment()); DeoptimizeIf(not_equal, instr->environment());
} }
@ -4189,29 +3991,6 @@ void LCodeGen::DoTypeof(LTypeof* instr) {
} }
void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label true_label;
Label false_label;
Label done;
Condition final_branch_condition = EmitTypeofIs(&true_label,
&false_label,
input,
instr->type_literal());
__ j(final_branch_condition, &true_label, Label::kNear);
__ bind(&false_label);
__ mov(result, factory()->false_value());
__ jmp(&done, Label::kNear);
__ bind(&true_label);
__ mov(result, factory()->true_value());
__ bind(&done);
}
void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
@ -4292,24 +4071,6 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
} }
void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
Register result = ToRegister(instr->result());
Label true_label;
Label done;
EmitIsConstructCall(result);
__ j(equal, &true_label, Label::kNear);
__ mov(result, factory()->false_value());
__ jmp(&done, Label::kNear);
__ bind(&true_label);
__ mov(result, factory()->true_value());
__ bind(&done);
}
void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
Register temp = ToRegister(instr->TempAt(0)); Register temp = ToRegister(instr->TempAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());

220
deps/v8/src/ia32/lithium-ia32.cc

@ -267,12 +267,6 @@ void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
} }
void LTypeofIs::PrintDataTo(StringStream* stream) {
InputAt(0)->PrintTo(stream);
stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
}
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if typeof "); stream->Add("if typeof ");
InputAt(0)->PrintTo(stream); InputAt(0)->PrintTo(stream);
@ -344,13 +338,6 @@ void LCallNew::PrintDataTo(StringStream* stream) {
} }
void LClassOfTest::PrintDataTo(StringStream* stream) {
stream->Add("= class_of_test(");
InputAt(0)->PrintTo(stream);
stream->Add(", \"%o\")", *hydrogen()->class_name());
}
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
arguments()->PrintTo(stream); arguments()->PrintTo(stream);
@ -985,18 +972,7 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
if (FLAG_stress_environments && !instr->HasEnvironment()) { if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr); instr = AssignEnvironment(instr);
} }
if (current->IsTest() && !instr->IsGoto()) {
ASSERT(instr->IsControl());
HTest* test = HTest::cast(current);
instr->set_hydrogen_value(test->value());
HBasicBlock* first = test->FirstSuccessor();
HBasicBlock* second = test->SecondSuccessor();
ASSERT(first != NULL && second != NULL);
instr->SetBranchTargets(first->block_id(), second->block_id());
} else {
instr->set_hydrogen_value(current); instr->set_hydrogen_value(current);
}
chunk_->AddInstruction(instr, current_block_); chunk_->AddInstruction(instr, current_block_);
} }
current_instruction_ = old_current; current_instruction_ = old_current;
@ -1041,84 +1017,17 @@ LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
} }
LInstruction* LChunkBuilder::DoTest(HTest* instr) { LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* v = instr->value(); HValue* v = instr->value();
if (!v->EmitAtUses()) return new LBranch(UseRegisterAtStart(v)); if (v->EmitAtUses()) {
ASSERT(!v->HasSideEffects()); ASSERT(v->IsConstant());
if (v->IsClassOfTest()) { ASSERT(!v->representation().IsDouble());
HClassOfTest* compare = HClassOfTest::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
TempRegister(),
TempRegister());
} else if (v->IsCompare()) {
HCompare* compare = HCompare::cast(v);
HValue* left = compare->left();
HValue* right = compare->right();
Representation r = compare->GetInputRepresentation();
if (r.IsInteger32()) {
ASSERT(left->representation().IsInteger32());
ASSERT(right->representation().IsInteger32());
return new LCmpIDAndBranch(UseRegisterAtStart(left),
UseOrConstantAtStart(right));
} else {
ASSERT(r.IsDouble());
ASSERT(left->representation().IsDouble());
ASSERT(right->representation().IsDouble());
return new LCmpIDAndBranch(UseRegisterAtStart(left),
UseRegisterAtStart(right));
}
} else if (v->IsIsSmi()) {
HIsSmi* compare = HIsSmi::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LIsSmiAndBranch(Use(compare->value()));
} else if (v->IsIsUndetectable()) {
HIsUndetectable* compare = HIsUndetectable::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()),
TempRegister());
} else if (v->IsHasInstanceType()) {
HHasInstanceType* compare = HHasInstanceType::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()),
TempRegister());
} else if (v->IsHasCachedArrayIndex()) {
HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LHasCachedArrayIndexAndBranch(
UseRegisterAtStart(compare->value()));
} else if (v->IsIsNull()) {
HIsNull* compare = HIsNull::cast(v);
ASSERT(compare->value()->representation().IsTagged());
// We only need a temp register for non-strict compare.
LOperand* temp = compare->is_strict() ? NULL : TempRegister();
return new LIsNullAndBranch(UseRegisterAtStart(compare->value()), temp);
} else if (v->IsIsObject()) {
HIsObject* compare = HIsObject::cast(v);
ASSERT(compare->value()->representation().IsTagged());
LOperand* temp = TempRegister();
return new LIsObjectAndBranch(UseRegister(compare->value()), temp);
} else if (v->IsCompareObjectEq()) {
HCompareObjectEq* compare = HCompareObjectEq::cast(v);
return new LCmpObjectEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
} else if (v->IsCompareConstantEq()) {
HCompareConstantEq* compare = HCompareConstantEq::cast(v);
return new LCmpConstantEqAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
} else if (v->IsIsConstructCall()) {
return new LIsConstructCallAndBranch(TempRegister());
} else if (v->IsConstant()) {
HBasicBlock* successor = HConstant::cast(v)->ToBoolean() HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
? instr->FirstSuccessor() ? instr->FirstSuccessor()
: instr->SecondSuccessor(); : instr->SecondSuccessor();
return new LGoto(successor->block_id()); return new LGoto(successor->block_id());
} else {
Abort("Undefined compare before branch");
return NULL;
} }
return new LBranch(UseRegisterAtStart(v));
} }
@ -1489,85 +1398,85 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
} }
LInstruction* LChunkBuilder::DoCompare(HCompare* instr) { LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
Token::Value op = instr->token(); Token::Value op = instr->token();
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
bool reversed = (op == Token::GT || op == Token::LTE);
LOperand* left = UseFixed(instr->left(), reversed ? eax : edx);
LOperand* right = UseFixed(instr->right(), reversed ? edx : eax);
LCmpT* result = new LCmpT(left, right);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoCompareIDAndBranch(
HCompareIDAndBranch* instr) {
Representation r = instr->GetInputRepresentation(); Representation r = instr->GetInputRepresentation();
if (r.IsInteger32()) { if (r.IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32());
LOperand* left = UseRegisterAtStart(instr->left()); LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right()); LOperand* right = UseOrConstantAtStart(instr->right());
return DefineAsRegister(new LCmpID(left, right)); return new LCmpIDAndBranch(left, right);
} else if (r.IsDouble()) { } else {
ASSERT(r.IsDouble());
ASSERT(instr->left()->representation().IsDouble()); ASSERT(instr->left()->representation().IsDouble());
ASSERT(instr->right()->representation().IsDouble()); ASSERT(instr->right()->representation().IsDouble());
LOperand* left = UseRegisterAtStart(instr->left()); LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right()); LOperand* right = UseRegisterAtStart(instr->right());
return DefineAsRegister(new LCmpID(left, right)); return new LCmpIDAndBranch(left, right);
} else {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
bool reversed = (op == Token::GT || op == Token::LTE);
LOperand* left = UseFixed(instr->left(), reversed ? eax : edx);
LOperand* right = UseFixed(instr->right(), reversed ? edx : eax);
LCmpT* result = new LCmpT(left, right);
return MarkAsCall(DefineFixed(result, eax), instr);
} }
} }
LInstruction* LChunkBuilder::DoCompareObjectEq(HCompareObjectEq* instr) { LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
HCompareObjectEqAndBranch* instr) {
LOperand* left = UseRegisterAtStart(instr->left()); LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right()); LOperand* right = UseAtStart(instr->right());
LCmpObjectEq* result = new LCmpObjectEq(left, right); return new LCmpObjectEqAndBranch(left, right);
return DefineAsRegister(result);
} }
LInstruction* LChunkBuilder::DoCompareConstantEq( LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch(
HCompareConstantEq* instr) { HCompareConstantEqAndBranch* instr) {
LOperand* left = UseRegisterAtStart(instr->value()); return new LCmpConstantEqAndBranch(UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LCmpConstantEq(left));
} }
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) { LInstruction* LChunkBuilder::DoIsNullAndBranch(HIsNullAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); // We only need a temp register for non-strict compare.
LOperand* value = UseRegisterAtStart(instr->value()); LOperand* temp = instr->is_strict() ? NULL : TempRegister();
return new LIsNullAndBranch(UseRegisterAtStart(instr->value()), temp);
return DefineAsRegister(new LIsNull(value));
} }
LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) { LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegister(instr->value()); LOperand* temp = TempRegister();
return new LIsObjectAndBranch(UseRegister(instr->value()), temp);
return DefineAsRegister(new LIsObject(value));
} }
LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseAtStart(instr->value()); return new LIsSmiAndBranch(Use(instr->value()));
return DefineAsRegister(new LIsSmi(value));
} }
LInstruction* LChunkBuilder::DoIsUndetectable(HIsUndetectable* instr) { LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
ASSERT(instr->value()->representation().IsTagged()); HIsUndetectableAndBranch* instr) {
LOperand* value = UseRegisterAtStart(instr->value()); ASSERT(instr ->value()->representation().IsTagged());
return new LIsUndetectableAndBranch(UseRegisterAtStart(instr->value()),
return DefineAsRegister(new LIsUndetectable(value)); TempRegister());
} }
LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) { LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
HHasInstanceTypeAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value()); return new LHasInstanceTypeAndBranch(UseRegisterAtStart(instr->value()),
TempRegister());
return DefineAsRegister(new LHasInstanceType(value));
} }
@ -1580,20 +1489,20 @@ LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
} }
LInstruction* LChunkBuilder::DoHasCachedArrayIndex( LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
HHasCachedArrayIndex* instr) { HHasCachedArrayIndexAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegister(instr->value()); return new LHasCachedArrayIndexAndBranch(
UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LHasCachedArrayIndex(value));
} }
LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) { LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
HClassOfTestAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseTempRegister(instr->value()); return new LClassOfTestAndBranch(UseTempRegister(instr->value()),
TempRegister(),
return DefineSameAsFirst(new LClassOfTest(value, TempRegister())); TempRegister());
} }
@ -1631,7 +1540,7 @@ LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()), return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
Use(instr->length()))); UseAtStart(instr->length())));
} }
@ -1724,7 +1633,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) { LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value()); LOperand* value = UseAtStart(instr->value());
return AssignEnvironment(new LCheckNonSmi(value)); return AssignEnvironment(new LCheckNonSmi(value));
} }
@ -1745,13 +1654,13 @@ LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) { LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value()); LOperand* value = UseAtStart(instr->value());
return AssignEnvironment(new LCheckSmi(value)); return AssignEnvironment(new LCheckSmi(value));
} }
LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
LOperand* value = UseRegisterAtStart(instr->value()); LOperand* value = UseAtStart(instr->value());
return AssignEnvironment(new LCheckFunction(value)); return AssignEnvironment(new LCheckFunction(value));
} }
@ -2207,13 +2116,14 @@ LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
} }
LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) { LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value()))); return new LTypeofIsAndBranch(UseTempRegister(instr->value()));
} }
LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) { LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
return DefineAsRegister(new LIsConstructCall); HIsConstructCallAndBranch* instr) {
return new LIsConstructCallAndBranch(TempRegister());
} }

187
deps/v8/src/ia32/lithium-ia32.h

@ -71,15 +71,11 @@ class LCodeGen;
V(ClampDToUint8) \ V(ClampDToUint8) \
V(ClampIToUint8) \ V(ClampIToUint8) \
V(ClampTToUint8) \ V(ClampTToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \ V(ClassOfTestAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \ V(CmpIDAndBranch) \
V(CmpObjectEq) \
V(CmpObjectEqAndBranch) \ V(CmpObjectEqAndBranch) \
V(CmpMapAndBranch) \ V(CmpMapAndBranch) \
V(CmpT) \ V(CmpT) \
V(CmpConstantEq) \
V(CmpConstantEqAndBranch) \ V(CmpConstantEqAndBranch) \
V(ConstantD) \ V(ConstantD) \
V(ConstantI) \ V(ConstantI) \
@ -97,9 +93,7 @@ class LCodeGen;
V(GlobalObject) \ V(GlobalObject) \
V(GlobalReceiver) \ V(GlobalReceiver) \
V(Goto) \ V(Goto) \
V(HasCachedArrayIndex) \
V(HasCachedArrayIndexAndBranch) \ V(HasCachedArrayIndexAndBranch) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \ V(HasInstanceTypeAndBranch) \
V(In) \ V(In) \
V(InstanceOf) \ V(InstanceOf) \
@ -107,15 +101,10 @@ class LCodeGen;
V(InstructionGap) \ V(InstructionGap) \
V(Integer32ToDouble) \ V(Integer32ToDouble) \
V(InvokeFunction) \ V(InvokeFunction) \
V(IsConstructCall) \
V(IsConstructCallAndBranch) \ V(IsConstructCallAndBranch) \
V(IsNull) \
V(IsNullAndBranch) \ V(IsNullAndBranch) \
V(IsObject) \
V(IsObjectAndBranch) \ V(IsObjectAndBranch) \
V(IsSmi) \
V(IsSmiAndBranch) \ V(IsSmiAndBranch) \
V(IsUndetectable) \
V(IsUndetectableAndBranch) \ V(IsUndetectableAndBranch) \
V(JSArrayLength) \ V(JSArrayLength) \
V(Label) \ V(Label) \
@ -167,7 +156,6 @@ class LCodeGen;
V(Throw) \ V(Throw) \
V(ToFastProperties) \ V(ToFastProperties) \
V(Typeof) \ V(Typeof) \
V(TypeofIs) \
V(TypeofIsAndBranch) \ V(TypeofIsAndBranch) \
V(UnaryMathOperation) \ V(UnaryMathOperation) \
V(UnknownOSRValue) \ V(UnknownOSRValue) \
@ -226,7 +214,6 @@ class LInstruction: public ZoneObject {
virtual bool IsGap() const { return false; } virtual bool IsGap() const { return false; }
virtual bool IsControl() const { return false; } virtual bool IsControl() const { return false; }
virtual void SetBranchTargets(int true_block_id, int false_block_id) { }
void set_environment(LEnvironment* env) { environment_ = env; } void set_environment(LEnvironment* env) { environment_ = env; }
LEnvironment* environment() const { return environment_; } LEnvironment* environment() const { return environment_; }
@ -456,16 +443,15 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> {
public: public:
virtual bool IsControl() const { return true; } virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; } int SuccessorCount() { return hydrogen()->SuccessorCount(); }
int false_block_id() const { return false_block_id_; } HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
void SetBranchTargets(int true_block_id, int false_block_id) { int true_block_id() { return hydrogen()->SuccessorAt(0)->block_id(); }
true_block_id_ = true_block_id; int false_block_id() { return hydrogen()->SuccessorAt(1)->block_id(); }
false_block_id_ = false_block_id;
}
private: private:
int true_block_id_; HControlInstruction* hydrogen() {
int false_block_id_; return HControlInstruction::cast(this->hydrogen_value());
}
}; };
@ -567,23 +553,6 @@ class LMulI: public LTemplateInstruction<1, 2, 1> {
}; };
class LCmpID: public LTemplateInstruction<1, 2, 0> {
public:
LCmpID(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
DECLARE_CONCRETE_INSTRUCTION(CmpID, "cmp-id")
DECLARE_HYDROGEN_ACCESSOR(Compare)
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const {
return hydrogen()->GetInputRepresentation().IsDouble();
}
};
class LCmpIDAndBranch: public LControlInstruction<2, 0> { class LCmpIDAndBranch: public LControlInstruction<2, 0> {
public: public:
LCmpIDAndBranch(LOperand* left, LOperand* right) { LCmpIDAndBranch(LOperand* left, LOperand* right) {
@ -592,7 +561,7 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch") DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
DECLARE_HYDROGEN_ACCESSOR(Compare) DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch)
Token::Value op() const { return hydrogen()->token(); } Token::Value op() const { return hydrogen()->token(); }
bool is_double() const { bool is_double() const {
@ -617,17 +586,6 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 0> {
}; };
class LCmpObjectEq: public LTemplateInstruction<1, 2, 0> {
public:
LCmpObjectEq(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
DECLARE_CONCRETE_INSTRUCTION(CmpObjectEq, "cmp-object-eq")
};
class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
public: public:
LCmpObjectEqAndBranch(LOperand* left, LOperand* right) { LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
@ -640,17 +598,6 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
}; };
class LCmpConstantEq: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCmpConstantEq(LOperand* left) {
inputs_[0] = left;
}
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEq, "cmp-constant-eq")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
};
class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> { class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LCmpConstantEqAndBranch(LOperand* left) { explicit LCmpConstantEqAndBranch(LOperand* left) {
@ -659,20 +606,7 @@ class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch, DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
"cmp-constant-eq-and-branch") "cmp-constant-eq-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq) DECLARE_HYDROGEN_ACCESSOR(CompareConstantEqAndBranch)
};
class LIsNull: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsNull(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsNull, "is-null")
DECLARE_HYDROGEN_ACCESSOR(IsNull)
bool is_strict() const { return hydrogen()->is_strict(); }
}; };
@ -684,7 +618,7 @@ class LIsNullAndBranch: public LControlInstruction<1, 1> {
} }
DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsNull) DECLARE_HYDROGEN_ACCESSOR(IsNullAndBranch)
bool is_strict() const { return hydrogen()->is_strict(); } bool is_strict() const { return hydrogen()->is_strict(); }
@ -692,16 +626,6 @@ class LIsNullAndBranch: public LControlInstruction<1, 1> {
}; };
class LIsObject: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsObject(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object")
};
class LIsObjectAndBranch: public LControlInstruction<1, 1> { class LIsObjectAndBranch: public LControlInstruction<1, 1> {
public: public:
LIsObjectAndBranch(LOperand* value, LOperand* temp) { LIsObjectAndBranch(LOperand* value, LOperand* temp) {
@ -715,17 +639,6 @@ class LIsObjectAndBranch: public LControlInstruction<1, 1> {
}; };
class LIsSmi: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsSmi(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is-smi")
DECLARE_HYDROGEN_ACCESSOR(IsSmi)
};
class LIsSmiAndBranch: public LControlInstruction<1, 0> { class LIsSmiAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LIsSmiAndBranch(LOperand* value) { explicit LIsSmiAndBranch(LOperand* value) {
@ -733,22 +646,12 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
class LIsUndetectable: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsUndetectable(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsUndetectable, "is-undetectable")
DECLARE_HYDROGEN_ACCESSOR(IsUndetectable)
};
class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { class LIsUndetectableAndBranch: public LControlInstruction<1, 1> {
public: public:
explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) { explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) {
@ -763,17 +666,6 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> {
}; };
class LHasInstanceType: public LTemplateInstruction<1, 1, 0> {
public:
explicit LHasInstanceType(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(HasInstanceType, "has-instance-type")
DECLARE_HYDROGEN_ACCESSOR(HasInstanceType)
};
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 1> { class LHasInstanceTypeAndBranch: public LControlInstruction<1, 1> {
public: public:
LHasInstanceTypeAndBranch(LOperand* value, LOperand* temp) { LHasInstanceTypeAndBranch(LOperand* value, LOperand* temp) {
@ -783,7 +675,7 @@ class LHasInstanceTypeAndBranch: public LControlInstruction<1, 1> {
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch, DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
"has-instance-type-and-branch") "has-instance-type-and-branch")
DECLARE_HYDROGEN_ACCESSOR(HasInstanceType) DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -800,17 +692,6 @@ class LGetCachedArrayIndex: public LTemplateInstruction<1, 1, 0> {
}; };
class LHasCachedArrayIndex: public LTemplateInstruction<1, 1, 0> {
public:
explicit LHasCachedArrayIndex(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has-cached-array-index")
DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndex)
};
class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> { class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LHasCachedArrayIndexAndBranch(LOperand* value) { explicit LHasCachedArrayIndexAndBranch(LOperand* value) {
@ -823,13 +704,6 @@ class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> {
}; };
class LIsConstructCall: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(IsConstructCall, "is-construct-call")
DECLARE_HYDROGEN_ACCESSOR(IsConstructCall)
};
class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { class LIsConstructCallAndBranch: public LControlInstruction<0, 1> {
public: public:
explicit LIsConstructCallAndBranch(LOperand* temp) { explicit LIsConstructCallAndBranch(LOperand* temp) {
@ -841,20 +715,6 @@ class LIsConstructCallAndBranch: public LControlInstruction<0, 1> {
}; };
class LClassOfTest: public LTemplateInstruction<1, 1, 1> {
public:
LClassOfTest(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTest)
virtual void PrintDataTo(StringStream* stream);
};
class LClassOfTestAndBranch: public LControlInstruction<1, 2> { class LClassOfTestAndBranch: public LControlInstruction<1, 2> {
public: public:
LClassOfTestAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { LClassOfTestAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) {
@ -865,7 +725,7 @@ class LClassOfTestAndBranch: public LControlInstruction<1, 2> {
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch,
"class-of-test-and-branch") "class-of-test-and-branch")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTest) DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -879,7 +739,7 @@ class LCmpT: public LTemplateInstruction<1, 2, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t") DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
DECLARE_HYDROGEN_ACCESSOR(Compare) DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
Token::Value op() const { return hydrogen()->token(); } Token::Value op() const { return hydrogen()->token(); }
}; };
@ -1015,7 +875,7 @@ class LBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
DECLARE_HYDROGEN_ACCESSOR(Value) DECLARE_HYDROGEN_ACCESSOR(Branch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -2034,21 +1894,6 @@ class LTypeof: public LTemplateInstruction<1, 1, 0> {
}; };
class LTypeofIs: public LTemplateInstruction<1, 1, 0> {
public:
explicit LTypeofIs(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(TypeofIs, "typeof-is")
DECLARE_HYDROGEN_ACCESSOR(TypeofIs)
Handle<String> type_literal() { return hydrogen()->type_literal(); }
virtual void PrintDataTo(StringStream* stream);
};
class LTypeofIsAndBranch: public LControlInstruction<1, 0> { class LTypeofIsAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LTypeofIsAndBranch(LOperand* value) { explicit LTypeofIsAndBranch(LOperand* value) {
@ -2056,7 +1901,7 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch") DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch")
DECLARE_HYDROGEN_ACCESSOR(TypeofIs) DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch)
Handle<String> type_literal() { return hydrogen()->type_literal(); } Handle<String> type_literal() { return hydrogen()->type_literal(); }

11
deps/v8/src/ia32/macro-assembler-ia32.cc

@ -1766,17 +1766,14 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
mov(dst, esi); mov(dst, esi);
} }
// We should not have found a with or catch context by walking the context // We should not have found a with context by walking the context chain
// chain (i.e., the static scope chain and runtime context chain do not // (i.e., the static scope chain and runtime context chain do not agree).
// agree). A variable occurring in such a scope should have slot type // A variable occurring in such a scope should have slot type LOOKUP and
// LOOKUP and not CONTEXT. // not CONTEXT.
if (emit_debug_code()) { if (emit_debug_code()) {
cmp(FieldOperand(dst, HeapObject::kMapOffset), cmp(FieldOperand(dst, HeapObject::kMapOffset),
isolate()->factory()->with_context_map()); isolate()->factory()->with_context_map());
Check(not_equal, "Variable resolved to with context."); Check(not_equal, "Variable resolved to with context.");
cmp(FieldOperand(dst, HeapObject::kMapOffset),
isolate()->factory()->with_context_map());
Check(not_equal, "Variable resolved to catch context.");
} }
} }

61
deps/v8/src/ic.cc

@ -956,7 +956,7 @@ MaybeObject* LoadIC::Load(State state,
// If we did not find a property, check if we need to throw an exception. // If we did not find a property, check if we need to throw an exception.
if (!lookup.IsProperty()) { if (!lookup.IsProperty()) {
if (FLAG_strict || IsContextual(object)) { if (IsContextual(object)) {
return ReferenceError("not_defined", name); return ReferenceError("not_defined", name);
} }
LOG(isolate(), SuspectReadEvent(*name, *object)); LOG(isolate(), SuspectReadEvent(*name, *object));
@ -1097,16 +1097,6 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
} }
String* KeyedLoadIC::GetStubNameForCache(IC::State ic_state) {
if (ic_state == MONOMORPHIC) {
return isolate()->heap()->KeyedLoadElementMonomorphic_symbol();
} else {
ASSERT(ic_state == MEGAMORPHIC);
return isolate()->heap()->KeyedLoadElementPolymorphic_symbol();
}
}
MaybeObject* KeyedLoadIC::GetFastElementStubWithoutMapCheck( MaybeObject* KeyedLoadIC::GetFastElementStubWithoutMapCheck(
bool is_js_array) { bool is_js_array) {
return KeyedLoadFastElementStub().TryGetCode(); return KeyedLoadFastElementStub().TryGetCode();
@ -1230,11 +1220,9 @@ MaybeObject* KeyedLoadIC::Load(State state,
LookupForRead(*object, *name, &lookup); LookupForRead(*object, *name, &lookup);
// If we did not find a property, check if we need to throw an exception. // If we did not find a property, check if we need to throw an exception.
if (!lookup.IsProperty()) { if (!lookup.IsProperty() && IsContextual(object)) {
if (FLAG_strict || IsContextual(object)) {
return ReferenceError("not_defined", name); return ReferenceError("not_defined", name);
} }
}
if (FLAG_use_ic) { if (FLAG_use_ic) {
UpdateCaches(&lookup, state, object, name); UpdateCaches(&lookup, state, object, name);
@ -1636,18 +1624,14 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
Code* generic_stub) { Code* generic_stub) {
State ic_state = target()->ic_state(); State ic_state = target()->ic_state();
if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
Code* monomorphic_stub; Code* monomorphic_stub;
// Always compute the MONOMORPHIC stub, even if the MEGAMORPHIC stub ends up
// being used. This is necessary because the megamorphic stub needs to have
// access to more information than what is stored in the receiver map in some
// cases (external arrays need the array type from the MONOMORPHIC stub).
MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver, MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
is_store, is_store,
strict_mode, strict_mode,
generic_stub); generic_stub);
if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub; if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
return monomorphic_stub; return monomorphic_stub;
} }
ASSERT(target() != generic_stub); ASSERT(target() != generic_stub);
@ -1698,7 +1682,7 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
} }
// Build the MEGAMORPHIC stub. // Build the MEGAMORPHIC stub.
Code* stub; Code* stub;
maybe_stub = ConstructMegamorphicStub(&target_receiver_maps, MaybeObject* maybe_stub = ConstructMegamorphicStub(&target_receiver_maps,
&handler_ics, &handler_ics,
strict_mode); strict_mode);
if (!maybe_stub->To(&stub)) return maybe_stub; if (!maybe_stub->To(&stub)) return maybe_stub;
@ -1716,22 +1700,7 @@ MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
ASSERT(string_stub() != NULL); ASSERT(string_stub() != NULL);
return string_stub(); return string_stub();
} else if (receiver_map->has_external_array_elements()) { } else if (receiver_map->has_external_array_elements()) {
// Determine the array type from the default MONOMORPHIC already generated return GetExternalArrayStubWithoutMapCheck(receiver_map->elements_kind());
// stub. There is no other way to determine the type of the external array
// directly from the receiver type.
Code::Kind kind = this->kind();
Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
NORMAL,
strict_mode);
String* monomorphic_name = GetStubNameForCache(MONOMORPHIC);
Object* maybe_default_stub = receiver_map->FindInCodeCache(monomorphic_name,
flags);
if (maybe_default_stub->IsUndefined()) {
return generic_stub;
}
Code* default_stub = Code::cast(maybe_default_stub);
Map* first_map = default_stub->FindFirstMap();
return GetExternalArrayStubWithoutMapCheck(first_map->elements_kind());
} else if (receiver_map->has_fast_elements()) { } else if (receiver_map->has_fast_elements()) {
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
return GetFastElementStubWithoutMapCheck(is_js_array); return GetFastElementStubWithoutMapCheck(is_js_array);
@ -1747,7 +1716,8 @@ MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
Code* generic_stub) { Code* generic_stub) {
Code* result = NULL; Code* result = NULL;
if (receiver->HasFastElements() || if (receiver->HasFastElements() ||
receiver->HasExternalArrayElements()) { receiver->HasExternalArrayElements() ||
receiver->HasDictionaryElements()) {
MaybeObject* maybe_stub = MaybeObject* maybe_stub =
isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement( isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
receiver, is_store, strict_mode); receiver, is_store, strict_mode);
@ -1759,16 +1729,6 @@ MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
} }
String* KeyedStoreIC::GetStubNameForCache(IC::State ic_state) {
if (ic_state == MONOMORPHIC) {
return isolate()->heap()->KeyedStoreElementMonomorphic_symbol();
} else {
ASSERT(ic_state == MEGAMORPHIC);
return isolate()->heap()->KeyedStoreElementPolymorphic_symbol();
}
}
MaybeObject* KeyedStoreIC::GetFastElementStubWithoutMapCheck( MaybeObject* KeyedStoreIC::GetFastElementStubWithoutMapCheck(
bool is_js_array) { bool is_js_array) {
return KeyedStoreFastElementStub(is_js_array).TryGetCode(); return KeyedStoreFastElementStub(is_js_array).TryGetCode();
@ -1856,6 +1816,7 @@ MaybeObject* KeyedStoreIC::Store(State state,
stub = non_strict_arguments_stub(); stub = non_strict_arguments_stub();
} else if (!force_generic) { } else if (!force_generic) {
if (key->IsSmi() && (target() != non_strict_arguments_stub())) { if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
HandleScope scope(isolate());
MaybeObject* maybe_stub = ComputeStub(receiver, MaybeObject* maybe_stub = ComputeStub(receiver,
true, true,
strict_mode, strict_mode,
@ -2333,15 +2294,15 @@ RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) {
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<Object> operand = args.at<Object>(0); Handle<Object> operand = args.at<Object>(0);
int key = args.smi_at(1); Token::Value op = static_cast<Token::Value>(args.smi_at(1));
Token::Value op = static_cast<Token::Value>(args.smi_at(2)); UnaryOverwriteMode mode = static_cast<UnaryOverwriteMode>(args.smi_at(2));
UnaryOpIC::TypeInfo previous_type = UnaryOpIC::TypeInfo previous_type =
static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3)); static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3));
UnaryOpIC::TypeInfo type = UnaryOpIC::GetTypeInfo(operand); UnaryOpIC::TypeInfo type = UnaryOpIC::GetTypeInfo(operand);
type = UnaryOpIC::ComputeNewType(type, previous_type); type = UnaryOpIC::ComputeNewType(type, previous_type);
UnaryOpStub stub(key, type); UnaryOpStub stub(op, mode, type);
Handle<Code> code = stub.GetCode(); Handle<Code> code = stub.GetCode();
if (!code.is_null()) { if (!code.is_null()) {
if (FLAG_trace_ic) { if (FLAG_trace_ic) {

6
deps/v8/src/ic.h

@ -358,8 +358,6 @@ class KeyedIC: public IC {
virtual Code::Kind kind() const = 0; virtual Code::Kind kind() const = 0;
virtual String* GetStubNameForCache(IC::State ic_state) = 0;
MaybeObject* ComputeStub(JSObject* receiver, MaybeObject* ComputeStub(JSObject* receiver,
bool is_store, bool is_store,
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
@ -426,8 +424,6 @@ class KeyedLoadIC: public KeyedIC {
protected: protected:
virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; } virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
virtual String* GetStubNameForCache(IC::State ic_state);
virtual MaybeObject* ConstructMegamorphicStub( virtual MaybeObject* ConstructMegamorphicStub(
MapList* receiver_maps, MapList* receiver_maps,
CodeList* targets, CodeList* targets,
@ -581,8 +577,6 @@ class KeyedStoreIC: public KeyedIC {
protected: protected:
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; } virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
virtual String* GetStubNameForCache(IC::State ic_state);
virtual MaybeObject* ConstructMegamorphicStub( virtual MaybeObject* ConstructMegamorphicStub(
MapList* receiver_maps, MapList* receiver_maps,
CodeList* targets, CodeList* targets,

5
deps/v8/src/isolate.cc

@ -1855,11 +1855,6 @@ void Isolate::Exit() {
} }
void Isolate::ResetEagerOptimizingData() {
compilation_cache_->ResetEagerOptimizingData();
}
#ifdef DEBUG #ifdef DEBUG
#define ISOLATE_FIELD_OFFSET(type, name, ignored) \ #define ISOLATE_FIELD_OFFSET(type, name, ignored) \
const intptr_t Isolate::name##_debug_offset_ = OFFSET_OF(Isolate, name##_); const intptr_t Isolate::name##_debug_offset_ = OFFSET_OF(Isolate, name##_);

4
deps/v8/src/isolate.h

@ -332,6 +332,8 @@ class HashMap;
V(int, bad_char_shift_table, kUC16AlphabetSize) \ V(int, bad_char_shift_table, kUC16AlphabetSize) \
V(int, good_suffix_shift_table, (kBMMaxShift + 1)) \ V(int, good_suffix_shift_table, (kBMMaxShift + 1)) \
V(int, suffix_table, (kBMMaxShift + 1)) \ V(int, suffix_table, (kBMMaxShift + 1)) \
V(uint32_t, random_seed, 2) \
V(uint32_t, private_random_seed, 2) \
ISOLATE_INIT_DEBUG_ARRAY_LIST(V) ISOLATE_INIT_DEBUG_ARRAY_LIST(V)
typedef List<HeapObject*, PreallocatedStorage> DebugObjectCache; typedef List<HeapObject*, PreallocatedStorage> DebugObjectCache;
@ -978,8 +980,6 @@ class Isolate {
} }
#endif #endif
void ResetEagerOptimizingData();
void SetData(void* data) { embedder_data_ = data; } void SetData(void* data) { embedder_data_ = data; }
void* GetData() { return embedder_data_; } void* GetData() { return embedder_data_; }

24
deps/v8/src/log.cc

@ -1362,18 +1362,14 @@ void Logger::TickEvent(TickSample* sample, bool overflow) {
} }
int Logger::GetActiveProfilerModules() { bool Logger::IsProfilerPaused() {
int result = PROFILER_MODULE_NONE; return profiler_ == NULL || profiler_->paused();
if (profiler_ != NULL && !profiler_->paused()) {
result |= PROFILER_MODULE_CPU;
}
return result;
} }
void Logger::PauseProfiler(int flags, int tag) { void Logger::PauseProfiler() {
if (!log_->IsEnabled()) return; if (!log_->IsEnabled()) return;
if (profiler_ != NULL && (flags & PROFILER_MODULE_CPU)) { if (profiler_ != NULL) {
// It is OK to have negative nesting. // It is OK to have negative nesting.
if (--cpu_profiler_nesting_ == 0) { if (--cpu_profiler_nesting_ == 0) {
profiler_->pause(); profiler_->pause();
@ -1388,18 +1384,12 @@ void Logger::PauseProfiler(int flags, int tag) {
--logging_nesting_; --logging_nesting_;
} }
} }
if (tag != 0) {
UncheckedIntEvent("close-tag", tag);
}
} }
void Logger::ResumeProfiler(int flags, int tag) { void Logger::ResumeProfiler() {
if (!log_->IsEnabled()) return; if (!log_->IsEnabled()) return;
if (tag != 0) { if (profiler_ != NULL) {
UncheckedIntEvent("open-tag", tag);
}
if (profiler_ != NULL && (flags & PROFILER_MODULE_CPU)) {
if (cpu_profiler_nesting_++ == 0) { if (cpu_profiler_nesting_++ == 0) {
++logging_nesting_; ++logging_nesting_;
if (FLAG_prof_lazy) { if (FLAG_prof_lazy) {
@ -1421,7 +1411,7 @@ void Logger::ResumeProfiler(int flags, int tag) {
// This function can be called when Log's mutex is acquired, // This function can be called when Log's mutex is acquired,
// either from main or Profiler's thread. // either from main or Profiler's thread.
void Logger::LogFailure() { void Logger::LogFailure() {
PauseProfiler(PROFILER_MODULE_CPU, 0); PauseProfiler();
} }

6
deps/v8/src/log.h

@ -280,9 +280,9 @@ class Logger {
// Pause/Resume collection of profiling data. // Pause/Resume collection of profiling data.
// When data collection is paused, CPU Tick events are discarded until // When data collection is paused, CPU Tick events are discarded until
// data collection is Resumed. // data collection is Resumed.
void PauseProfiler(int flags, int tag); void PauseProfiler();
void ResumeProfiler(int flags, int tag); void ResumeProfiler();
int GetActiveProfilerModules(); bool IsProfilerPaused();
// If logging is performed into a memory buffer, allows to // If logging is performed into a memory buffer, allows to
// retrieve previously written messages. See v8.h. // retrieve previously written messages. See v8.h.

57
deps/v8/src/mark-compact.cc

@ -1424,6 +1424,12 @@ void MarkCompactCollector::MarkLiveObjects() {
// reachable from the weak roots. // reachable from the weak roots.
ProcessExternalMarking(); ProcessExternalMarking();
// Object literal map caches reference symbols (cache keys) and maps
// (cache values). At this point still useful maps have already been
// marked. Mark the keys for the alive values before we process the
// symbol table.
ProcessMapCaches();
// Prune the symbol table removing all symbols only pointed to by the // Prune the symbol table removing all symbols only pointed to by the
// symbol table. Cannot use symbol_table() here because the symbol // symbol table. Cannot use symbol_table() here because the symbol
// table is marked. // table is marked.
@ -1452,6 +1458,57 @@ void MarkCompactCollector::MarkLiveObjects() {
} }
void MarkCompactCollector::ProcessMapCaches() {
Object* raw_context = heap()->global_contexts_list_;
while (raw_context != heap()->undefined_value()) {
Context* context = reinterpret_cast<Context*>(raw_context);
if (context->IsMarked()) {
HeapObject* raw_map_cache =
HeapObject::cast(context->get(Context::MAP_CACHE_INDEX));
// A map cache may be reachable from the stack. In this case
// it's already transitively marked and it's too late to clean
// up its parts.
if (!raw_map_cache->IsMarked() &&
raw_map_cache != heap()->undefined_value()) {
MapCache* map_cache = reinterpret_cast<MapCache*>(raw_map_cache);
int existing_elements = map_cache->NumberOfElements();
int used_elements = 0;
for (int i = MapCache::kElementsStartIndex;
i < map_cache->length();
i += MapCache::kEntrySize) {
Object* raw_key = map_cache->get(i);
if (raw_key == heap()->undefined_value() ||
raw_key == heap()->null_value()) continue;
STATIC_ASSERT(MapCache::kEntrySize == 2);
Object* raw_map = map_cache->get(i + 1);
if (raw_map->IsHeapObject() &&
HeapObject::cast(raw_map)->IsMarked()) {
++used_elements;
} else {
// Delete useless entries with unmarked maps.
ASSERT(raw_map->IsMap());
map_cache->set_null_unchecked(heap(), i);
map_cache->set_null_unchecked(heap(), i + 1);
}
}
if (used_elements == 0) {
context->set(Context::MAP_CACHE_INDEX, heap()->undefined_value());
} else {
// Note: we don't actually shrink the cache here to avoid
// extra complexity during GC. We rely on subsequent cache
// usages (EnsureCapacity) to do this.
map_cache->ElementsRemoved(existing_elements - used_elements);
MarkObject(map_cache);
}
}
}
// Move to next element in the list.
raw_context = context->get(Context::NEXT_CONTEXT_LINK);
}
ProcessMarkingStack();
}
#ifdef DEBUG #ifdef DEBUG
void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) { void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
live_bytes_ += obj->Size(); live_bytes_ += obj->Size();

4
deps/v8/src/mark-compact.h

@ -306,6 +306,10 @@ class MarkCompactCollector {
// flag on the marking stack. // flag on the marking stack.
void RefillMarkingStack(); void RefillMarkingStack();
// After reachable maps have been marked process per context object
// literal map caches removing unmarked entries.
void ProcessMapCaches();
// Callback function for telling whether the object *p is an unmarked // Callback function for telling whether the object *p is an unmarked
// heap object. // heap object.
static bool IsUnmarkedHeapObject(Object** p); static bool IsUnmarkedHeapObject(Object** p);

13
deps/v8/src/mips/code-stubs-mips.cc

@ -166,7 +166,6 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
// Setup the fixed slots. // Setup the fixed slots.
__ li(a1, Operand(Smi::FromInt(0))); __ li(a1, Operand(Smi::FromInt(0)));
__ sw(a3, MemOperand(v0, Context::SlotOffset(Context::CLOSURE_INDEX))); __ sw(a3, MemOperand(v0, Context::SlotOffset(Context::CLOSURE_INDEX)));
__ sw(v0, MemOperand(v0, Context::SlotOffset(Context::FCONTEXT_INDEX)));
__ sw(cp, MemOperand(v0, Context::SlotOffset(Context::PREVIOUS_INDEX))); __ sw(cp, MemOperand(v0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
__ sw(a1, MemOperand(v0, Context::SlotOffset(Context::EXTENSION_INDEX))); __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::EXTENSION_INDEX)));
@ -1847,19 +1846,13 @@ void UnaryOpStub::Generate(MacroAssembler* masm) {
void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
// Argument is in a0 and v0 at this point, so we can overwrite a0. // Argument is in a0 and v0 at this point, so we can overwrite a0.
// Push this stub's key. Although the operation and the type info are __ li(a2, Operand(Smi::FromInt(op_)));
// encoded into the key, the encoding is opaque, so push them too. __ li(a1, Operand(Smi::FromInt(mode_)));
__ li(a2, Operand(Smi::FromInt(MinorKey())));
__ li(a1, Operand(Smi::FromInt(op_)));
__ li(a0, Operand(Smi::FromInt(operand_type_))); __ li(a0, Operand(Smi::FromInt(operand_type_)));
__ Push(v0, a2, a1, a0); __ Push(v0, a2, a1, a0);
__ TailCallExternalReference( __ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kUnaryOp_Patch), ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
masm->isolate()),
4,
1);
} }

16
deps/v8/src/mips/code-stubs-mips.h

@ -61,18 +61,11 @@ class TranscendentalCacheStub: public CodeStub {
class UnaryOpStub: public CodeStub { class UnaryOpStub: public CodeStub {
public: public:
UnaryOpStub(Token::Value op, UnaryOverwriteMode mode) UnaryOpStub(Token::Value op,
UnaryOverwriteMode mode,
UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
: op_(op), : op_(op),
mode_(mode), mode_(mode),
operand_type_(UnaryOpIC::UNINITIALIZED),
name_(NULL) {
}
UnaryOpStub(
int key,
UnaryOpIC::TypeInfo operand_type)
: op_(OpBits::decode(key)),
mode_(ModeBits::decode(key)),
operand_type_(operand_type), operand_type_(operand_type),
name_(NULL) { name_(NULL) {
} }
@ -90,8 +83,7 @@ class UnaryOpStub: public CodeStub {
#ifdef DEBUG #ifdef DEBUG
void Print() { void Print() {
PrintF("UnaryOpStub %d (op %s), " PrintF("UnaryOpStub %d (op %s), (mode %d, runtime_type_info %s)\n",
"(mode %d, runtime_type_info %s)\n",
MinorKey(), MinorKey(),
Token::String(op_), Token::String(op_),
static_cast<int>(mode_), static_cast<int>(mode_),

5
deps/v8/src/mips/deoptimizer-mips.cc

@ -78,6 +78,11 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
} }
void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
UNIMPLEMENTED();
}
void Deoptimizer::EntryGenerator::Generate() { void Deoptimizer::EntryGenerator::Generate() {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }

229
deps/v8/src/mips/full-codegen-mips.cc

@ -101,15 +101,17 @@ class JumpPatchSite BASE_EMBEDDED {
} }
void EmitPatchInfo() { void EmitPatchInfo() {
if (patch_site_.is_bound()) {
int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
Register reg = Register::from_code(delta_to_patch_site / kImm16Mask); Register reg = Register::from_code(delta_to_patch_site / kImm16Mask);
__ andi(at, reg, delta_to_patch_site % kImm16Mask); __ andi(at, reg, delta_to_patch_site % kImm16Mask);
#ifdef DEBUG #ifdef DEBUG
info_emitted_ = true; info_emitted_ = true;
#endif #endif
} else {
__ nop(); // Signals no inlined code.
}
} }
bool is_bound() const { return patch_site_.is_bound(); }
private: private:
MacroAssembler* masm_; MacroAssembler* masm_;
@ -137,6 +139,7 @@ class JumpPatchSite BASE_EMBEDDED {
void FullCodeGenerator::Generate(CompilationInfo* info) { void FullCodeGenerator::Generate(CompilationInfo* info) {
ASSERT(info_ == NULL); ASSERT(info_ == NULL);
info_ = info; info_ = info;
scope_ = info->scope();
SetFunctionPosition(function()); SetFunctionPosition(function());
Comment cmnt(masm_, "[ function compiled by full code generator"); Comment cmnt(masm_, "[ function compiled by full code generator");
@ -154,13 +157,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
if (info->is_strict_mode() || info->is_native()) { if (info->is_strict_mode() || info->is_native()) {
Label ok; Label ok;
__ Branch(&ok, eq, t1, Operand(zero_reg)); __ Branch(&ok, eq, t1, Operand(zero_reg));
int receiver_offset = scope()->num_parameters() * kPointerSize; int receiver_offset = info->scope()->num_parameters() * kPointerSize;
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex); __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ sw(a2, MemOperand(sp, receiver_offset)); __ sw(a2, MemOperand(sp, receiver_offset));
__ bind(&ok); __ bind(&ok);
} }
int locals_count = scope()->num_stack_slots(); int locals_count = info->scope()->num_stack_slots();
__ Push(ra, fp, cp, a1); __ Push(ra, fp, cp, a1);
if (locals_count > 0) { if (locals_count > 0) {
@ -180,7 +183,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
bool function_in_register = true; bool function_in_register = true;
// Possibly allocate a local context. // Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
if (heap_slots > 0) { if (heap_slots > 0) {
Comment cmnt(masm_, "[ Allocate local context"); Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is in a1. // Argument to NewContext is the function, which is in a1.
@ -196,7 +199,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// passed to us. It's saved in the stack and kept live in cp. // passed to us. It's saved in the stack and kept live in cp.
__ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Copy any necessary parameters into the context. // Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters(); int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot(); Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (slot != NULL && slot->type() == Slot::CONTEXT) {
@ -228,10 +231,11 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ mov(a3, a1); __ mov(a3, a1);
} }
// Receiver is just before the parameters on the caller's stack. // Receiver is just before the parameters on the caller's stack.
int offset = scope()->num_parameters() * kPointerSize; int num_parameters = info->scope()->num_parameters();
int offset = num_parameters * kPointerSize;
__ Addu(a2, fp, __ Addu(a2, fp,
Operand(StandardFrameConstants::kCallerSPOffset + offset)); Operand(StandardFrameConstants::kCallerSPOffset + offset));
__ li(a1, Operand(Smi::FromInt(scope()->num_parameters()))); __ li(a1, Operand(Smi::FromInt(num_parameters)));
__ Push(a3, a2, a1); __ Push(a3, a2, a1);
// Arguments to ArgumentsAccessStub: // Arguments to ArgumentsAccessStub:
@ -348,7 +352,7 @@ void FullCodeGenerator::EmitReturnSequence() {
{ Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
// Here we use masm_-> instead of the __ macro to avoid the code coverage // Here we use masm_-> instead of the __ macro to avoid the code coverage
// tool from instrumenting as we rely on the code size here. // tool from instrumenting as we rely on the code size here.
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize; int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
__ RecordJSReturn(); __ RecordJSReturn();
masm_->mov(sp, fp); masm_->mov(sp, fp);
@ -716,10 +720,14 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// context. // context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
if (FLAG_debug_code) { if (FLAG_debug_code) {
// Check that we're not inside a 'with'. // Check that we're not inside a with or catch context.
__ lw(a1, ContextOperand(cp, Context::FCONTEXT_INDEX)); __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
__ Check(eq, "Unexpected declaration in current context.", __ LoadRoot(t0, Heap::kWithContextMapRootIndex);
a1, Operand(cp)); __ Check(ne, "Declaration in with context.",
a1, Operand(t0));
__ LoadRoot(t0, Heap::kCatchContextMapRootIndex);
__ Check(ne, "Declaration in catch context.",
a1, Operand(t0));
} }
if (mode == Variable::CONST) { if (mode == Variable::CONST) {
__ LoadRoot(at, Heap::kTheHoleValueRootIndex); __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
@ -790,7 +798,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ CallWithAstId(ic);
// Value in v0 is ignored (declarations are statements). // Value in v0 is ignored (declarations are statements).
} }
} }
@ -865,7 +873,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// Record position before stub call for type feedback. // Record position before stub call for type feedback.
SetSourcePosition(clause->position()); SetSourcePosition(clause->position());
Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
EmitCallIC(ic, &patch_site, clause->CompareId()); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, clause->CompareId());
patch_site.EmitPatchInfo();
__ Branch(&next_test, ne, v0, Operand(zero_reg)); __ Branch(&next_test, ne, v0, Operand(zero_reg));
__ Drop(1); // Switch value is no longer needed. __ Drop(1); // Switch value is no longer needed.
@ -1164,7 +1173,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
? RelocInfo::CODE_TARGET ? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT; : RelocInfo::CODE_TARGET_CONTEXT;
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, mode, AstNode::kNoNumber); __ CallWithAstId(ic, mode);
} }
@ -1244,7 +1253,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
__ li(a0, Operand(key_literal->handle())); __ li(a0, Operand(key_literal->handle()));
Handle<Code> ic = Handle<Code> ic =
isolate()->builtins()->KeyedLoadIC_Initialize(); isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
__ Branch(done); __ Branch(done);
} }
} }
@ -1266,7 +1275,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
__ lw(a0, GlobalObjectOperand()); __ lw(a0, GlobalObjectOperand());
__ li(a2, Operand(var->name())); __ li(a2, Operand(var->name()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); __ CallWithAstId(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(v0); context()->Plug(v0);
} else if (slot->type() == Slot::LOOKUP) { } else if (slot->type() == Slot::LOOKUP) {
@ -1412,7 +1421,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id()); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, key->id());
PrepareForBailoutForId(key->id(), NO_REGISTERS); PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else { } else {
VisitForEffect(value); VisitForEffect(value);
@ -1656,7 +1665,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
__ li(a2, Operand(key->handle())); __ li(a2, Operand(key->handle()));
// Call load IC. It has arguments receiver and property name a0 and a2. // Call load IC. It has arguments receiver and property name a0 and a2.
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
} }
@ -1665,7 +1674,7 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
__ mov(a0, result_register()); __ mov(a0, result_register());
// Call keyed load IC. It has arguments key and receiver in a0 and a1. // Call keyed load IC. It has arguments key and receiver in a0 and a1.
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
} }
@ -1693,7 +1702,8 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
__ bind(&stub_call); __ bind(&stub_call);
BinaryOpStub stub(op, mode); BinaryOpStub stub(op, mode);
EmitCallIC(stub.GetCode(), &patch_site, expr->id()); __ CallWithAstId(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
__ jmp(&done); __ jmp(&done);
__ bind(&smi_case); __ bind(&smi_case);
@ -1774,7 +1784,9 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
__ mov(a0, result_register()); __ mov(a0, result_register());
__ pop(a1); __ pop(a1);
BinaryOpStub stub(op, mode); BinaryOpStub stub(op, mode);
EmitCallIC(stub.GetCode(), NULL, expr->id()); JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
__ CallWithAstId(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
context()->Plug(v0); context()->Plug(v0);
} }
@ -1814,7 +1826,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ CallWithAstId(ic);
break; break;
} }
case KEYED_PROPERTY: { case KEYED_PROPERTY: {
@ -1827,7 +1839,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ CallWithAstId(ic);
break; break;
} }
} }
@ -1852,7 +1864,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); __ CallWithAstId(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) { } else if (op == Token::INIT_CONST) {
// Like var declarations, const declarations are hoisted to function // Like var declarations, const declarations are hoisted to function
@ -1873,17 +1885,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Branch(&skip, ne, a1, Operand(t0)); __ Branch(&skip, ne, a1, Operand(t0));
__ sw(result_register(), MemOperand(fp, SlotOffset(slot))); __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
break; break;
case Slot::CONTEXT: { case Slot::CONTEXT:
__ lw(a1, ContextOperand(cp, Context::FCONTEXT_INDEX));
__ lw(a2, ContextOperand(a1, slot->index()));
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
__ Branch(&skip, ne, a2, Operand(t0));
__ sw(result_register(), ContextOperand(a1, slot->index()));
int offset = Context::SlotOffset(slot->index());
__ mov(a3, result_register()); // Preserve the stored value in v0.
__ RecordWrite(a1, Operand(offset), a3, a2);
break;
}
case Slot::LOOKUP: case Slot::LOOKUP:
__ push(result_register()); __ push(result_register());
__ li(a0, Operand(slot->var()->name())); __ li(a0, Operand(slot->var()->name()));
@ -1960,7 +1962,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, expr->id());
// If the assignment ends an initialization block, revert to fast case. // If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) { if (expr->ends_initialization_block()) {
@ -2012,7 +2014,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, expr->id());
// If the assignment ends an initialization block, revert to fast case. // If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) { if (expr->ends_initialization_block()) {
@ -2065,7 +2067,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = Handle<Code> ic =
isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
EmitCallIC(ic, mode, expr->id()); __ CallWithAstId(ic, mode, expr->id());
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@ -2099,7 +2101,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Handle<Code> ic = Handle<Code> ic =
isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
__ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. __ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@ -2139,7 +2141,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
__ push(a1); __ push(a1);
// Push the receiver of the enclosing function and do runtime call. // Push the receiver of the enclosing function and do runtime call.
__ lw(a1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize)); int receiver_offset = 2 + info_->scope()->num_parameters();
__ lw(a1, MemOperand(fp, receiver_offset * kPointerSize));
__ push(a1); __ push(a1);
// Push the strict mode flag. // Push the strict mode flag.
__ li(a1, Operand(Smi::FromInt(strict_mode_flag()))); __ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
@ -2280,7 +2283,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else { } else {
// Call to a keyed property. // Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call, // For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed EmitCallIC. // for a regular property use EmitKeyedCallWithIC.
if (prop->is_synthetic()) { if (prop->is_synthetic()) {
// Do not visit the object and key subexpressions (they are shared // Do not visit the object and key subexpressions (they are shared
// by all occurrences of the same rewritten parameter). // by all occurrences of the same rewritten parameter).
@ -2298,7 +2301,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
SetSourcePosition(prop->position()); SetSourcePosition(prop->position());
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
__ lw(a1, GlobalObjectOperand()); __ lw(a1, GlobalObjectOperand());
__ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset)); __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
__ Push(v0, a1); // Function, receiver. __ Push(v0, a1); // Function, receiver.
@ -2685,7 +2688,7 @@ void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
// parameter count in a0. // parameter count in a0.
VisitForAccumulatorValue(args->at(0)); VisitForAccumulatorValue(args->at(0));
__ mov(a1, v0); __ mov(a1, v0);
__ li(a0, Operand(Smi::FromInt(scope()->num_parameters()))); __ li(a0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
__ CallStub(&stub); __ CallStub(&stub);
context()->Plug(v0); context()->Plug(v0);
@ -2697,7 +2700,7 @@ void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
Label exit; Label exit;
// Get the number of formal parameters. // Get the number of formal parameters.
__ li(v0, Operand(Smi::FromInt(scope()->num_parameters()))); __ li(v0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
// Check if the calling frame is an arguments adaptor frame. // Check if the calling frame is an arguments adaptor frame.
__ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
@ -3596,6 +3599,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
} }
void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
// Load the function into v0.
VisitForAccumulatorValue(args->at(0));
// Prepare for the test.
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
context()->PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Test for strict mode function.
__ lw(a1, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset));
__ lw(a1, FieldMemOperand(a1, SharedFunctionInfo::kCompilerHintsOffset));
__ And(at, a1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
kSmiTagSize)));
__ Branch(if_true, ne, at, Operand(zero_reg));
// Test for native function.
__ And(at, a1, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
__ Branch(if_true, ne, at, Operand(zero_reg));
// Not native or strict-mode function.
__ Branch(if_false);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
context()->Plug(if_true, if_false);
}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name(); Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') { if (name->length() > 0 && name->Get(0) == '_') {
@ -3628,7 +3664,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
isolate()->stub_cache()->ComputeCallInitialize(arg_count, isolate()->stub_cache()->ComputeCallInitialize(arg_count,
NOT_IN_LOOP, NOT_IN_LOOP,
mode); mode);
EmitCallIC(ic, mode, expr->id()); __ CallWithAstId(ic, mode, expr->id());
// Restore context register. // Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
} else { } else {
@ -3771,7 +3807,7 @@ void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
VisitForAccumulatorValue(expr->expression()); VisitForAccumulatorValue(expr->expression());
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
__ mov(a0, result_register()); __ mov(a0, result_register());
EmitCallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); __ CallWithAstId(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
context()->Plug(v0); context()->Plug(v0);
} }
@ -3882,7 +3918,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
BinaryOpStub stub(Token::ADD, NO_OVERWRITE); BinaryOpStub stub(Token::ADD, NO_OVERWRITE);
EmitCallIC(stub.GetCode(), &patch_site, expr->CountId()); __ CallWithAstId(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
patch_site.EmitPatchInfo();
__ bind(&done); __ bind(&done);
// Store the value returned in v0. // Store the value returned in v0.
@ -3914,7 +3951,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, expr->id());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
@ -3932,7 +3969,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, expr->id());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
@ -3956,7 +3993,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference // Use a regular load, not a contextual load, to avoid a reference
// error. // error.
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ CallWithAstId(ic);
PrepareForBailout(expr, TOS_REG); PrepareForBailout(expr, TOS_REG);
context()->Plug(v0); context()->Plug(v0);
} else if (proxy != NULL && } else if (proxy != NULL &&
@ -4153,7 +4190,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
// Record position and call the compare IC. // Record position and call the compare IC.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
Handle<Code> ic = CompareIC::GetUninitialized(op); Handle<Code> ic = CompareIC::GetUninitialized(op);
EmitCallIC(ic, &patch_site, expr->id()); __ CallWithAstId(ic, RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through); Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through);
} }
@ -4212,70 +4250,6 @@ Register FullCodeGenerator::context_register() {
} }
void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
RelocInfo::Mode mode,
unsigned ast_id) {
ASSERT(mode == RelocInfo::CODE_TARGET ||
mode == RelocInfo::CODE_TARGET_CONTEXT);
Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
__ IncrementCounter(counters->named_load_full(), 1, a1, a2);
break;
case Code::KEYED_LOAD_IC:
__ IncrementCounter(counters->keyed_load_full(), 1, a1, a2);
break;
case Code::STORE_IC:
__ IncrementCounter(counters->named_store_full(), 1, a1, a2);
break;
case Code::KEYED_STORE_IC:
__ IncrementCounter(counters->keyed_store_full(), 1, a1, a2);
default:
break;
}
if (ast_id == kNoASTId || mode == RelocInfo::CODE_TARGET_CONTEXT) {
__ Call(ic, mode);
} else {
ASSERT(mode == RelocInfo::CODE_TARGET);
mode = RelocInfo::CODE_TARGET_WITH_ID;
__ CallWithAstId(ic, mode, ast_id);
}
}
void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
JumpPatchSite* patch_site,
unsigned ast_id) {
Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
__ IncrementCounter(counters->named_load_full(), 1, a1, a2);
break;
case Code::KEYED_LOAD_IC:
__ IncrementCounter(counters->keyed_load_full(), 1, a1, a2);
break;
case Code::STORE_IC:
__ IncrementCounter(counters->named_store_full(), 1, a1, a2);
break;
case Code::KEYED_STORE_IC:
__ IncrementCounter(counters->keyed_store_full(), 1, a1, a2);
default:
break;
}
if (ast_id == kNoASTId) {
__ Call(ic, RelocInfo::CODE_TARGET);
} else {
__ CallWithAstId(ic, RelocInfo::CODE_TARGET_WITH_ID, ast_id);
}
if (patch_site != NULL && patch_site->is_bound()) {
patch_site->EmitPatchInfo();
} else {
__ nop(); // Signals no inlined code.
}
}
void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
__ sw(value, MemOperand(fp, frame_offset)); __ sw(value, MemOperand(fp, frame_offset));
@ -4287,6 +4261,27 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
} }
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
Scope* declaration_scope = scope()->DeclarationScope();
if (declaration_scope->is_global_scope()) {
// Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty
// function.
__ li(at, Operand(Smi::FromInt(0)));
} else if (declaration_scope->is_eval_scope()) {
// Contexts created by a call to eval have the same closure as the
// context calling eval, not the anonymous closure containing the eval
// code. Fetch it from the context.
__ lw(at, ContextOperand(cp, Context::CLOSURE_INDEX));
} else {
ASSERT(declaration_scope->is_function_scope());
__ lw(at, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
}
__ push(at);
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Non-local control flow support. // Non-local control flow support.

17
deps/v8/src/mips/macro-assembler-mips.cc

@ -2088,10 +2088,12 @@ void MacroAssembler::CallWithAstId(Handle<Code> code,
Condition cond, Condition cond,
Register r1, Register r1,
const Operand& r2) { const Operand& r2) {
ASSERT(rmode == RelocInfo::CODE_TARGET_WITH_ID); ASSERT(RelocInfo::IsCodeTarget(rmode));
ASSERT(ast_id != kNoASTId); if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) {
ASSERT(ast_id_for_reloc_info_ == kNoASTId); ASSERT(ast_id_for_reloc_info_ == kNoASTId);
ast_id_for_reloc_info_ = ast_id; ast_id_for_reloc_info_ = ast_id;
rmode = RelocInfo::CODE_TARGET_WITH_ID;
}
Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond, r1, r2); Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond, r1, r2);
} }
@ -3715,17 +3717,6 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
// cannot be allowed to destroy the context in esi). // cannot be allowed to destroy the context in esi).
Move(dst, cp); Move(dst, cp);
} }
// We should not have found a 'with' context by walking the context chain
// (i.e., the static scope chain and runtime context chain do not agree).
// A variable occurring in such a scope should have slot type LOOKUP and
// not CONTEXT.
if (emit_debug_code()) {
lw(t9, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
Check(eq, "Yo dawg, I heard you liked function contexts "
"so I put function contexts in all your contexts",
dst, Operand(t9));
}
} }

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

@ -181,8 +181,8 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
#undef DECLARE_BRANCH_PROTOTYPES #undef DECLARE_BRANCH_PROTOTYPES
void CallWithAstId(Handle<Code> code, void CallWithAstId(Handle<Code> code,
RelocInfo::Mode rmode, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
unsigned ast_id, unsigned ast_id = kNoASTId,
Condition cond = al, Condition cond = al,
Register r1 = zero_reg, Register r1 = zero_reg,
const Operand& r2 = Operand(zero_reg)); const Operand& r2 = Operand(zero_reg));

35
deps/v8/src/mirror-debugger.js

@ -1243,13 +1243,17 @@ const kFrameDetailsLocalCountIndex = 4;
const kFrameDetailsSourcePositionIndex = 5; const kFrameDetailsSourcePositionIndex = 5;
const kFrameDetailsConstructCallIndex = 6; const kFrameDetailsConstructCallIndex = 6;
const kFrameDetailsAtReturnIndex = 7; const kFrameDetailsAtReturnIndex = 7;
const kFrameDetailsDebuggerFrameIndex = 8; const kFrameDetailsFlagsIndex = 8;
const kFrameDetailsFirstDynamicIndex = 9; const kFrameDetailsFirstDynamicIndex = 9;
const kFrameDetailsNameIndex = 0; const kFrameDetailsNameIndex = 0;
const kFrameDetailsValueIndex = 1; const kFrameDetailsValueIndex = 1;
const kFrameDetailsNameValueSize = 2; const kFrameDetailsNameValueSize = 2;
const kFrameDetailsFlagDebuggerFrame = 1;
const kFrameDetailsFlagOptimizedFrame = 2;
const kFrameDetailsFlagInlinedFrame = 4;
/** /**
* Wrapper for the frame details information retreived from the VM. The frame * Wrapper for the frame details information retreived from the VM. The frame
* details from the VM is an array with the following content. See runtime.cc * details from the VM is an array with the following content. See runtime.cc
@ -1262,7 +1266,7 @@ const kFrameDetailsNameValueSize = 2;
* 5: Source position * 5: Source position
* 6: Construct call * 6: Construct call
* 7: Is at return * 7: Is at return
* 8: Debugger frame * 8: Flags (debugger frame, optimized frame, inlined frame)
* Arguments name, value * Arguments name, value
* Locals name, value * Locals name, value
* Return value if any * Return value if any
@ -1308,7 +1312,22 @@ FrameDetails.prototype.isAtReturn = function() {
FrameDetails.prototype.isDebuggerFrame = function() { FrameDetails.prototype.isDebuggerFrame = function() {
%CheckExecutionState(this.break_id_); %CheckExecutionState(this.break_id_);
return this.details_[kFrameDetailsDebuggerFrameIndex]; var f = kFrameDetailsFlagDebuggerFrame;
return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
}
FrameDetails.prototype.isOptimizedFrame = function() {
%CheckExecutionState(this.break_id_);
var f = kFrameDetailsFlagOptimizedFrame;
return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
}
FrameDetails.prototype.isInlinedFrame = function() {
%CheckExecutionState(this.break_id_);
var f = kFrameDetailsFlagInlinedFrame;
return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
} }
@ -1447,6 +1466,16 @@ FrameMirror.prototype.isDebuggerFrame = function() {
}; };
FrameMirror.prototype.isOptimizedFrame = function() {
return this.details_.isOptimizedFrame();
};
FrameMirror.prototype.isInlinedFrame = function() {
return this.details_.isInlinedFrame();
};
FrameMirror.prototype.argumentCount = function() { FrameMirror.prototype.argumentCount = function() {
return this.details_.argumentCount(); return this.details_.argumentCount();
}; };

50
deps/v8/src/objects.cc

@ -3031,11 +3031,33 @@ MaybeObject* JSObject::DeleteFastElement(uint32_t index) {
if (!maybe->ToObject(&writable)) return maybe; if (!maybe->ToObject(&writable)) return maybe;
backing_store = FixedArray::cast(writable); backing_store = FixedArray::cast(writable);
} }
int length = IsJSArray() uint32_t length = static_cast<uint32_t>(
IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value() ? Smi::cast(JSArray::cast(this)->length())->value()
: backing_store->length(); : backing_store->length());
if (index < static_cast<uint32_t>(length)) { if (index < length) {
backing_store->set_the_hole(index); backing_store->set_the_hole(index);
// If an old space backing store is larger than a certain size and
// has too few used values, normalize it.
// To avoid doing the check on every delete we require at least
// one adjacent hole to the value being deleted.
Object* hole = heap->the_hole_value();
const int kMinLengthForSparsenessCheck = 64;
if (backing_store->length() >= kMinLengthForSparsenessCheck &&
!heap->InNewSpace(backing_store) &&
((index > 0 && backing_store->get(index - 1) == hole) ||
(index + 1 < length && backing_store->get(index + 1) == hole))) {
int num_used = 0;
for (int i = 0; i < backing_store->length(); ++i) {
if (backing_store->get(i) != hole) ++num_used;
// Bail out early if more than 1/4 is used.
if (4 * num_used > backing_store->length()) break;
}
if (4 * num_used <= backing_store->length()) {
MaybeObject* result = NormalizeElements();
if (result->IsFailure()) return result;
}
}
} }
return heap->true_value(); return heap->true_value();
} }
@ -6287,19 +6309,6 @@ void JSFunction::MarkForLazyRecompilation() {
} }
uint32_t JSFunction::SourceHash() {
uint32_t hash = 0;
Object* script = shared()->script();
if (!script->IsUndefined()) {
Object* source = Script::cast(script)->source();
if (source->IsUndefined()) hash = String::cast(source)->Hash();
}
hash ^= ComputeIntegerHash(shared()->start_position_and_type());
hash += ComputeIntegerHash(shared()->end_position());
return hash;
}
bool JSFunction::IsInlineable() { bool JSFunction::IsInlineable() {
if (IsBuiltin()) return false; if (IsBuiltin()) return false;
SharedFunctionInfo* shared_info = shared(); SharedFunctionInfo* shared_info = shared();
@ -6950,7 +6959,7 @@ Map* Code::FindFirstMap() {
} }
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) #ifdef ENABLE_DISASSEMBLER
void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
disasm::NameConverter converter; disasm::NameConverter converter;
@ -7098,10 +7107,6 @@ void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
} }
} }
#endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
#ifdef ENABLE_DISASSEMBLER
// Identify kind of code. // Identify kind of code.
const char* Code::Kind2String(Kind kind) { const char* Code::Kind2String(Kind kind) {
@ -7192,6 +7197,9 @@ void Code::Disassemble(const char* name, FILE* out) {
if (ic_state() == MONOMORPHIC) { if (ic_state() == MONOMORPHIC) {
PrintF(out, "type = %s\n", PropertyType2String(type())); PrintF(out, "type = %s\n", PropertyType2String(type()));
} }
if (is_call_stub() || is_keyed_call_stub()) {
PrintF(out, "argc = %d\n", arguments_count());
}
} }
if ((name != NULL) && (name[0] != '\0')) { if ((name != NULL) && (name[0] != '\0')) {
PrintF(out, "name = %s\n", name); PrintF(out, "name = %s\n", name);

9
deps/v8/src/objects.h

@ -3418,7 +3418,7 @@ class DeoptimizationInputData: public FixedArray {
// Casting. // Casting.
static inline DeoptimizationInputData* cast(Object* obj); static inline DeoptimizationInputData* cast(Object* obj);
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) #ifdef ENABLE_DISASSEMBLER
void DeoptimizationInputDataPrint(FILE* out); void DeoptimizationInputDataPrint(FILE* out);
#endif #endif
@ -3946,6 +3946,10 @@ class Map: public HeapObject {
kind <= JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND; kind <= JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND;
} }
inline bool has_dictionary_elements() {
return elements_kind() == JSObject::DICTIONARY_ELEMENTS;
}
// Tells whether the map is attached to SharedFunctionInfo // Tells whether the map is attached to SharedFunctionInfo
// (for inobject slack tracking). // (for inobject slack tracking).
inline void set_attached_to_shared_function_info(bool value); inline void set_attached_to_shared_function_info(bool value);
@ -4924,9 +4928,6 @@ class JSFunction: public JSObject {
// recompilation. // recompilation.
inline bool IsMarkedForLazyRecompilation(); inline bool IsMarkedForLazyRecompilation();
// Compute a hash code for the source code of this function.
uint32_t SourceHash();
// Check whether or not this function is inlineable. // Check whether or not this function is inlineable.
bool IsInlineable(); bool IsInlineable();

124
deps/v8/src/parser.cc

@ -411,6 +411,7 @@ Scope* Parser::NewScope(Scope* parent, Scope::Type type, bool inside_with) {
return result; return result;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Target is a support class to facilitate manipulation of the // Target is a support class to facilitate manipulation of the
// Parser's target_stack_ (the stack of potential 'break' and // Parser's target_stack_ (the stack of potential 'break' and
@ -1301,13 +1302,14 @@ VariableProxy* Parser::Declare(Handle<String> name,
// to the calling function context. // to the calling function context.
// Similarly, strict mode eval scope does not leak variable declarations to // Similarly, strict mode eval scope does not leak variable declarations to
// the caller's scope so we declare all locals, too. // the caller's scope so we declare all locals, too.
if (top_scope_->is_function_scope() || Scope* declaration_scope = top_scope_->DeclarationScope();
top_scope_->is_strict_mode_eval_scope()) { if (declaration_scope->is_function_scope() ||
declaration_scope->is_strict_mode_eval_scope()) {
// Declare the variable in the function scope. // Declare the variable in the function scope.
var = top_scope_->LocalLookup(name); var = declaration_scope->LocalLookup(name);
if (var == NULL) { if (var == NULL) {
// Declare the name. // Declare the name.
var = top_scope_->DeclareLocal(name, mode); var = declaration_scope->DeclareLocal(name, mode);
} else { } else {
// The name was declared before; check for conflicting // The name was declared before; check for conflicting
// re-declarations. If the previous declaration was a const or the // re-declarations. If the previous declaration was a const or the
@ -1323,7 +1325,7 @@ VariableProxy* Parser::Declare(Handle<String> name,
Expression* expression = Expression* expression =
NewThrowTypeError(isolate()->factory()->redeclaration_symbol(), NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
type_string, name); type_string, name);
top_scope_->SetIllegalRedeclaration(expression); declaration_scope->SetIllegalRedeclaration(expression);
} }
} }
} }
@ -1344,14 +1346,18 @@ VariableProxy* Parser::Declare(Handle<String> name,
// semantic issue as long as we keep the source order, but it may be // semantic issue as long as we keep the source order, but it may be
// a performance issue since it may lead to repeated // a performance issue since it may lead to repeated
// Runtime::DeclareContextSlot() calls. // Runtime::DeclareContextSlot() calls.
VariableProxy* proxy = top_scope_->NewUnresolved(name, inside_with()); VariableProxy* proxy = declaration_scope->NewUnresolved(name, false);
top_scope_->AddDeclaration(new(zone()) Declaration(proxy, mode, fun)); declaration_scope->AddDeclaration(new(zone()) Declaration(proxy, mode, fun));
// For global const variables we bind the proxy to a variable. // For global const variables we bind the proxy to a variable.
if (mode == Variable::CONST && top_scope_->is_global_scope()) { if (mode == Variable::CONST && declaration_scope->is_global_scope()) {
ASSERT(resolve); // should be set by all callers ASSERT(resolve); // should be set by all callers
Variable::Kind kind = Variable::NORMAL; Variable::Kind kind = Variable::NORMAL;
var = new(zone()) Variable(top_scope_, name, Variable::CONST, true, kind); var = new(zone()) Variable(declaration_scope,
name,
Variable::CONST,
true,
kind);
} }
// If requested and we have a local variable, bind the proxy to the variable // If requested and we have a local variable, bind the proxy to the variable
@ -1407,7 +1413,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
// isn't lazily compiled. The extension structures are only // isn't lazily compiled. The extension structures are only
// accessible while parsing the first time not when reparsing // accessible while parsing the first time not when reparsing
// because of lazy compilation. // because of lazy compilation.
top_scope_->ForceEagerCompilation(); top_scope_->DeclarationScope()->ForceEagerCompilation();
// Compute the function template for the native function. // Compute the function template for the native function.
v8::Handle<v8::FunctionTemplate> fun_template = v8::Handle<v8::FunctionTemplate> fun_template =
@ -1485,8 +1491,8 @@ Block* Parser::ParseVariableStatement(bool* ok) {
// VariableStatement :: // VariableStatement ::
// VariableDeclarations ';' // VariableDeclarations ';'
Expression* dummy; // to satisfy the ParseVariableDeclarations() signature Handle<String> ignore;
Block* result = ParseVariableDeclarations(true, &dummy, CHECK_OK); Block* result = ParseVariableDeclarations(true, &ignore, CHECK_OK);
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return result; return result;
} }
@ -1504,18 +1510,19 @@ bool Parser::IsEvalOrArguments(Handle<String> string) {
// to initialize it properly. This mechanism is used for the parsing // to initialize it properly. This mechanism is used for the parsing
// of 'for-in' loops. // of 'for-in' loops.
Block* Parser::ParseVariableDeclarations(bool accept_IN, Block* Parser::ParseVariableDeclarations(bool accept_IN,
Expression** var, Handle<String>* out,
bool* ok) { bool* ok) {
// VariableDeclarations :: // VariableDeclarations ::
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
Variable::Mode mode = Variable::VAR; Variable::Mode mode = Variable::VAR;
bool is_const = false; bool is_const = false;
Scope* declaration_scope = top_scope_->DeclarationScope();
if (peek() == Token::VAR) { if (peek() == Token::VAR) {
Consume(Token::VAR); Consume(Token::VAR);
} else if (peek() == Token::CONST) { } else if (peek() == Token::CONST) {
Consume(Token::CONST); Consume(Token::CONST);
if (top_scope_->is_strict_mode()) { if (declaration_scope->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty()); ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false; *ok = false;
return NULL; return NULL;
@ -1540,18 +1547,18 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// //
// Create new block with one expected declaration. // Create new block with one expected declaration.
Block* block = new(zone()) Block(NULL, 1, true); Block* block = new(zone()) Block(NULL, 1, true);
VariableProxy* last_var = NULL; // the last variable declared
int nvars = 0; // the number of variables declared int nvars = 0; // the number of variables declared
Handle<String> name;
do { do {
if (fni_ != NULL) fni_->Enter(); if (fni_ != NULL) fni_->Enter();
// Parse variable name. // Parse variable name.
if (nvars > 0) Consume(Token::COMMA); if (nvars > 0) Consume(Token::COMMA);
Handle<String> name = ParseIdentifier(CHECK_OK); name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name); if (fni_ != NULL) fni_->PushVariableName(name);
// Strict mode variables may not be named eval or arguments // Strict mode variables may not be named eval or arguments
if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) { if (declaration_scope->is_strict_mode() && IsEvalOrArguments(name)) {
ReportMessage("strict_var_name", Vector<const char*>::empty()); ReportMessage("strict_var_name", Vector<const char*>::empty());
*ok = false; *ok = false;
return NULL; return NULL;
@ -1569,11 +1576,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// If we have a const declaration, in an inner scope, the proxy is always // If we have a const declaration, in an inner scope, the proxy is always
// bound to the declared variable (independent of possibly surrounding with // bound to the declared variable (independent of possibly surrounding with
// statements). // statements).
last_var = Declare(name, mode, NULL, Declare(name, mode, NULL, is_const /* always bound for CONST! */,
is_const /* always bound for CONST! */,
CHECK_OK); CHECK_OK);
nvars++; nvars++;
if (top_scope_->num_var_or_const() > kMaxNumFunctionLocals) { if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
ReportMessageAt(scanner().location(), "too_many_variables", ReportMessageAt(scanner().location(), "too_many_variables",
Vector<const char*>::empty()); Vector<const char*>::empty());
*ok = false; *ok = false;
@ -1589,10 +1595,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// //
// var v; v = x; // var v; v = x;
// //
// In particular, we need to re-lookup 'v' as it may be a // In particular, we need to re-lookup 'v' (in top_scope_, not
// different 'v' than the 'v' in the declaration (if we are inside // declaration_scope) as it may be a different 'v' than the 'v' in the
// a 'with' statement that makes a object property with name 'v' // declaration (e.g., if we are inside a 'with' statement or 'catch'
// visible). // block).
// //
// However, note that const declarations are different! A const // However, note that const declarations are different! A const
// declaration of the form: // declaration of the form:
@ -1607,6 +1613,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// one - there is no re-lookup (see the last parameter of the // one - there is no re-lookup (see the last parameter of the
// Declare() call above). // Declare() call above).
Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
Expression* value = NULL; Expression* value = NULL;
int position = -1; int position = -1;
if (peek() == Token::ASSIGN) { if (peek() == Token::ASSIGN) {
@ -1647,7 +1654,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// browsers where the global object (window) has lots of // browsers where the global object (window) has lots of
// properties defined in prototype objects. // properties defined in prototype objects.
if (top_scope_->is_global_scope()) { if (initialization_scope->is_global_scope()) {
// Compute the arguments for the runtime call. // Compute the arguments for the runtime call.
ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3); ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
// We have at least 1 parameter. // We have at least 1 parameter.
@ -1670,8 +1677,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
} else { } else {
// Add strict mode. // Add strict mode.
// We may want to pass singleton to avoid Literal allocations. // We may want to pass singleton to avoid Literal allocations.
arguments->Add(NewNumberLiteral( StrictModeFlag flag = initialization_scope->is_strict_mode()
top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode)); ? kStrictMode
: kNonStrictMode;
arguments->Add(NewNumberLiteral(flag));
// Be careful not to assign a value to the global variable if // Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not // we're in a with. The initialization value should not
@ -1708,8 +1717,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// the top context for variables). Sigh... // the top context for variables). Sigh...
if (value != NULL) { if (value != NULL) {
Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR); Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR);
bool in_with = is_const ? false : inside_with();
VariableProxy* proxy =
initialization_scope->NewUnresolved(name, in_with);
Assignment* assignment = Assignment* assignment =
new(zone()) Assignment(op, last_var, value, position); new(zone()) Assignment(op, proxy, value, position);
if (block) { if (block) {
block->AddStatement(new(zone()) ExpressionStatement(assignment)); block->AddStatement(new(zone()) ExpressionStatement(assignment));
} }
@ -1718,10 +1730,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
if (fni_ != NULL) fni_->Leave(); if (fni_ != NULL) fni_->Leave();
} while (peek() == Token::COMMA); } while (peek() == Token::COMMA);
if (!is_const && nvars == 1) { // If there was a single non-const declaration, return it in the output
// We have a single, non-const variable. // parameter for possible use by for/in.
ASSERT(last_var != NULL); if (nvars == 1 && !is_const) {
*var = last_var; *out = name;
} }
return block; return block;
@ -1895,7 +1907,9 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// function. See ECMA-262, section 12.9, page 67. // function. See ECMA-262, section 12.9, page 67.
// //
// To be consistent with KJS we report the syntax error at runtime. // To be consistent with KJS we report the syntax error at runtime.
if (!top_scope_->is_function_scope()) { Scope* declaration_scope = top_scope_->DeclarationScope();
if (declaration_scope->is_global_scope() ||
declaration_scope->is_eval_scope()) {
Handle<String> type = isolate()->factory()->illegal_return_symbol(); Handle<String> type = isolate()->factory()->illegal_return_symbol();
Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null()); Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
return new(zone()) ExpressionStatement(throw_error); return new(zone()) ExpressionStatement(throw_error);
@ -1922,7 +1936,7 @@ Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
Statement* stat; Statement* stat;
{ Target target(&this->target_stack_, &collector); { Target target(&this->target_stack_, &collector);
with_nesting_level_++; with_nesting_level_++;
top_scope_->RecordWithStatement(); top_scope_->DeclarationScope()->RecordWithStatement();
stat = ParseStatement(labels, CHECK_OK); stat = ParseStatement(labels, CHECK_OK);
with_nesting_level_--; with_nesting_level_--;
} }
@ -2082,6 +2096,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
// block. Since we don't know yet if there will be a finally block, we // block. Since we don't know yet if there will be a finally block, we
// always collect the targets. // always collect the targets.
TargetCollector catch_collector; TargetCollector catch_collector;
Scope* catch_scope = NULL;
Variable* catch_variable = NULL;
Block* catch_block = NULL; Block* catch_block = NULL;
Handle<String> name; Handle<String> name;
if (tok == Token::CATCH) { if (tok == Token::CATCH) {
@ -2108,10 +2124,16 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
TargetCollector inner_collector; TargetCollector inner_collector;
{ Target target(&this->target_stack_, &catch_collector); { Target target(&this->target_stack_, &catch_collector);
{ Target target(&this->target_stack_, &inner_collector); { Target target(&this->target_stack_, &inner_collector);
++with_nesting_level_; catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
top_scope_->RecordWithStatement(); if (top_scope_->is_strict_mode()) {
catch_scope->EnableStrictMode();
}
catch_variable = catch_scope->DeclareLocal(name, Variable::VAR);
Scope* saved_scope = top_scope_;
top_scope_ = catch_scope;
inner_body = ParseBlock(NULL, CHECK_OK); inner_body = ParseBlock(NULL, CHECK_OK);
--with_nesting_level_; top_scope_ = saved_scope;
} }
} }
@ -2145,19 +2167,28 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
// 'try { try B0 catch B1 } finally B2' // 'try { try B0 catch B1 } finally B2'
if (catch_block != NULL && finally_block != NULL) { if (catch_block != NULL && finally_block != NULL) {
// If we have both, create an inner try/catch.
ASSERT(catch_scope != NULL && catch_variable != NULL);
TryCatchStatement* statement = TryCatchStatement* statement =
new(zone()) TryCatchStatement(try_block, name, catch_block); new(zone()) TryCatchStatement(try_block,
catch_scope,
catch_variable,
catch_block);
statement->set_escaping_targets(try_collector.targets()); statement->set_escaping_targets(try_collector.targets());
try_block = new(zone()) Block(NULL, 1, false); try_block = new(zone()) Block(NULL, 1, false);
try_block->AddStatement(statement); try_block->AddStatement(statement);
catch_block = NULL; catch_block = NULL; // Clear to indicate it's been handled.
} }
TryStatement* result = NULL; TryStatement* result = NULL;
if (catch_block != NULL) { if (catch_block != NULL) {
ASSERT(finally_block == NULL); ASSERT(finally_block == NULL);
ASSERT(catch_scope != NULL && catch_variable != NULL);
result = result =
new(zone()) TryCatchStatement(try_block, name, catch_block); new(zone()) TryCatchStatement(try_block,
catch_scope,
catch_variable,
catch_block);
} else { } else {
ASSERT(finally_block != NULL); ASSERT(finally_block != NULL);
result = new(zone()) TryFinallyStatement(try_block, finally_block); result = new(zone()) TryFinallyStatement(try_block, finally_block);
@ -2230,10 +2261,12 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
if (peek() != Token::SEMICOLON) { if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST) { if (peek() == Token::VAR || peek() == Token::CONST) {
Expression* each = NULL; Handle<String> name;
Block* variable_statement = Block* variable_statement =
ParseVariableDeclarations(false, &each, CHECK_OK); ParseVariableDeclarations(false, &name, CHECK_OK);
if (peek() == Token::IN && each != NULL) {
if (peek() == Token::IN && !name.is_null()) {
VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
ForInStatement* loop = new(zone()) ForInStatement(labels); ForInStatement* loop = new(zone()) ForInStatement(labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
@ -2901,8 +2934,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
switch (peek()) { switch (peek()) {
case Token::THIS: { case Token::THIS: {
Consume(Token::THIS); Consume(Token::THIS);
VariableProxy* recv = top_scope_->receiver(); result = new(zone()) VariableProxy(top_scope_->receiver());
result = recv;
break; break;
} }
@ -3762,7 +3794,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
if (extension_ != NULL) { if (extension_ != NULL) {
// The extension structures are only accessible while parsing the // The extension structures are only accessible while parsing the
// very first time not when reparsing because of lazy compilation. // very first time not when reparsing because of lazy compilation.
top_scope_->ForceEagerCompilation(); top_scope_->DeclarationScope()->ForceEagerCompilation();
} }
const Runtime::Function* function = Runtime::FunctionForSymbol(name); const Runtime::Function* function = Runtime::FunctionForSymbol(name);

6
deps/v8/src/parser.h

@ -436,7 +436,7 @@ class Parser {
const char* message, const char* message,
Vector<Handle<String> > args); Vector<Handle<String> > args);
protected: private:
// Limit on number of function parameters is chosen arbitrarily. // Limit on number of function parameters is chosen arbitrarily.
// Code::Flags uses only the low 17 bits of num-parameters to // Code::Flags uses only the low 17 bits of num-parameters to
// construct a hashable id, so if more than 2^17 are allowed, this // construct a hashable id, so if more than 2^17 are allowed, this
@ -484,7 +484,9 @@ class Parser {
Statement* ParseNativeDeclaration(bool* ok); Statement* ParseNativeDeclaration(bool* ok);
Block* ParseBlock(ZoneStringList* labels, bool* ok); Block* ParseBlock(ZoneStringList* labels, bool* ok);
Block* ParseVariableStatement(bool* ok); Block* ParseVariableStatement(bool* ok);
Block* ParseVariableDeclarations(bool accept_IN, Expression** var, bool* ok); Block* ParseVariableDeclarations(bool accept_IN,
Handle<String>* out,
bool* ok);
Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels, Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels,
bool* ok); bool* ok);
IfStatement* ParseIfStatement(ZoneStringList* labels, bool* ok); IfStatement* ParseIfStatement(ZoneStringList* labels, bool* ok);

230
deps/v8/src/platform-solaris.cc

@ -88,6 +88,7 @@ double ceiling(double x) {
} }
static Mutex* limit_mutex = NULL;
void OS::Setup() { void OS::Setup() {
// Seed the random number generator. // Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it // Convert the current time to a 64-bit integer first, before converting it
@ -96,6 +97,7 @@ void OS::Setup() {
// call this setup code within the same millisecond. // call this setup code within the same millisecond.
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed)); srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
} }
@ -145,6 +147,9 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
static void UpdateAllocatedSpaceLimits(void* address, int size) { static void UpdateAllocatedSpaceLimits(void* address, int size) {
ASSERT(limit_mutex != NULL);
ScopedLock lock(limit_mutex);
lowest_ever_allocated = Min(lowest_ever_allocated, address); lowest_ever_allocated = Min(lowest_ever_allocated, address);
highest_ever_allocated = highest_ever_allocated =
Max(highest_ever_allocated, Max(highest_ever_allocated,
@ -407,7 +412,6 @@ static void* ThreadEntry(void* arg) {
// one) so we initialize it here too. // one) so we initialize it here too.
thread->data()->thread_ = pthread_self(); thread->data()->thread_ = pthread_self();
ASSERT(thread->data()->thread_ != kNoThread); ASSERT(thread->data()->thread_ != kNoThread);
Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
thread->Run(); thread->Run();
return NULL; return NULL;
} }
@ -587,78 +591,172 @@ Semaphore* OS::CreateSemaphore(int count) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
static Sampler* active_sampler_ = NULL;
static pthread_t vm_tid_ = 0;
static pthread_t GetThreadID() { static pthread_t GetThreadID() {
return pthread_self(); return pthread_self();
} }
static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
USE(info); USE(info);
if (signal != SIGPROF) return; if (signal != SIGPROF) return;
if (active_sampler_ == NULL || !active_sampler_->IsActive()) return; Isolate* isolate = Isolate::UncheckedCurrent();
if (vm_tid_ != GetThreadID()) return; if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
// We require a fully initialized and entered isolate.
return;
}
if (v8::Locker::IsActive() &&
!isolate->thread_manager()->IsLockedByCurrentThread()) {
return;
}
Sampler* sampler = isolate->logger()->sampler();
if (sampler == NULL || !sampler->IsActive()) return;
TickSample sample_obj; TickSample sample_obj;
TickSample* sample = CpuProfiler::TickSampleEvent(); TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
if (sample == NULL) sample = &sample_obj; if (sample == NULL) sample = &sample_obj;
// Extracting the sample from the context is extremely machine dependent. // Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
mcontext_t& mcontext = ucontext->uc_mcontext; mcontext_t& mcontext = ucontext->uc_mcontext;
sample->state = Top::current_vm_state(); sample->state = isolate->current_vm_state();
sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
active_sampler_->SampleStack(sample); sampler->SampleStack(sample);
active_sampler_->Tick(sample); sampler->Tick(sample);
} }
class Sampler::PlatformData : public Malloced { class Sampler::PlatformData : public Malloced {
public:
PlatformData() : vm_tid_(GetThreadID()) {}
pthread_t vm_tid() const { return vm_tid_; }
private:
pthread_t vm_tid_;
};
class SignalSender : public Thread {
public: public:
enum SleepInterval { enum SleepInterval {
FULL_INTERVAL, HALF_INTERVAL,
HALF_INTERVAL FULL_INTERVAL
}; };
explicit PlatformData(Sampler* sampler) explicit SignalSender(int interval)
: sampler_(sampler), : Thread("SignalSender"),
signal_handler_installed_(false), interval_(interval) {}
vm_tgid_(getpid()),
signal_sender_launched_(false) { static void InstallSignalHandler() {
struct sigaction sa;
sa.sa_sigaction = ProfilerSignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
signal_handler_installed_ =
(sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
}
static void RestoreSignalHandler() {
if (signal_handler_installed_) {
sigaction(SIGPROF, &old_signal_handler_, 0);
signal_handler_installed_ = false;
}
}
static void AddActiveSampler(Sampler* sampler) {
ScopedLock lock(mutex_);
SamplerRegistry::AddActiveSampler(sampler);
if (instance_ == NULL) {
// Start a thread that will send SIGPROF signal to VM threads,
// when CPU profiling will be enabled.
instance_ = new SignalSender(sampler->interval());
instance_->Start();
} else {
ASSERT(instance_->interval_ == sampler->interval());
}
}
static void RemoveActiveSampler(Sampler* sampler) {
ScopedLock lock(mutex_);
SamplerRegistry::RemoveActiveSampler(sampler);
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown();
instance_->Join();
delete instance_;
instance_ = NULL;
RestoreSignalHandler();
}
}
// Implement Thread::Run().
virtual void Run() {
SamplerRegistry::State state;
while ((state = SamplerRegistry::GetState()) !=
SamplerRegistry::HAS_NO_SAMPLERS) {
bool cpu_profiling_enabled =
(state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
if (cpu_profiling_enabled && !signal_handler_installed_) {
InstallSignalHandler();
} else if (!cpu_profiling_enabled && signal_handler_installed_) {
RestoreSignalHandler();
} }
void SignalSender() { // When CPU profiling is enabled both JavaScript and C++ code is
while (sampler_->IsActive()) { // profiled. We must not suspend.
if (!cpu_profiling_enabled) {
if (rate_limiter_.SuspendIfNecessary()) continue; if (rate_limiter_.SuspendIfNecessary()) continue;
if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { }
SendProfilingSignal(); if (cpu_profiling_enabled && runtime_profiler_enabled) {
if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
return;
}
Sleep(HALF_INTERVAL); Sleep(HALF_INTERVAL);
RuntimeProfiler::NotifyTick(); if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
return;
}
Sleep(HALF_INTERVAL); Sleep(HALF_INTERVAL);
} else { } else {
if (sampler_->IsProfiling()) SendProfilingSignal(); if (cpu_profiling_enabled) {
if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
this)) {
return;
}
}
if (runtime_profiler_enabled) {
if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
NULL)) {
return;
}
}
Sleep(FULL_INTERVAL); Sleep(FULL_INTERVAL);
} }
} }
} }
void SendProfilingSignal() { static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
if (!sampler->IsProfiling()) return;
SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
}
static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
if (!sampler->isolate()->IsInitialized()) return;
sampler->isolate()->runtime_profiler()->NotifyTick();
}
void SendProfilingSignal(pthread_t tid) {
if (!signal_handler_installed_) return; if (!signal_handler_installed_) return;
pthread_kill(vm_tid_, SIGPROF); pthread_kill(tid, SIGPROF);
} }
void Sleep(SleepInterval full_or_half) { void Sleep(SleepInterval full_or_half) {
// Convert ms to us and subtract 100 us to compensate delays // Convert ms to us and subtract 100 us to compensate delays
// occuring during signal delivery. // occuring during signal delivery.
useconds_t interval = sampler_->interval_ * 1000 - 100; useconds_t interval = interval_ * 1000 - 100;
if (full_or_half == HALF_INTERVAL) interval /= 2; if (full_or_half == HALF_INTERVAL) interval /= 2;
int result = usleep(interval); int result = usleep(interval);
#ifdef DEBUG #ifdef DEBUG
@ -673,22 +771,22 @@ class Sampler::PlatformData : public Malloced {
USE(result); USE(result);
} }
Sampler* sampler_; const int interval_;
bool signal_handler_installed_;
struct sigaction old_signal_handler_;
int vm_tgid_;
bool signal_sender_launched_;
pthread_t signal_sender_thread_;
RuntimeProfilerRateLimiter rate_limiter_; RuntimeProfilerRateLimiter rate_limiter_;
};
// Protects the process wide state below.
static Mutex* mutex_;
static SignalSender* instance_;
static bool signal_handler_installed_;
static struct sigaction old_signal_handler_;
static void* SenderEntry(void* arg) { DISALLOW_COPY_AND_ASSIGN(SignalSender);
Sampler::PlatformData* data = };
reinterpret_cast<Sampler::PlatformData*>(arg);
data->SignalSender(); Mutex* SignalSender::mutex_ = OS::CreateMutex();
return 0; SignalSender* SignalSender::instance_ = NULL;
} struct sigaction SignalSender::old_signal_handler_;
bool SignalSender::signal_handler_installed_ = false;
Sampler::Sampler(Isolate* isolate, int interval) Sampler::Sampler(Isolate* isolate, int interval)
@ -697,63 +795,27 @@ Sampler::Sampler(Isolate* isolate, int interval)
profiling_(false), profiling_(false),
active_(false), active_(false),
samples_taken_(0) { samples_taken_(0) {
data_ = new PlatformData(this); data_ = new PlatformData;
} }
Sampler::~Sampler() { Sampler::~Sampler() {
ASSERT(!data_->signal_sender_launched_); ASSERT(!IsActive());
delete data_; delete data_;
} }
void Sampler::Start() { void Sampler::Start() {
// There can only be one active sampler at the time on POSIX
// platforms.
ASSERT(!IsActive()); ASSERT(!IsActive());
vm_tid_ = GetThreadID();
// Request profiling signals.
struct sigaction sa;
sa.sa_sigaction = ProfilerSignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
data_->signal_handler_installed_ =
sigaction(SIGPROF, &sa, &data_->old_signal_handler_) == 0;
// Start a thread that sends SIGPROF signal to VM thread.
// Sending the signal ourselves instead of relying on itimer provides
// much better accuracy.
SetActive(true); SetActive(true);
if (pthread_create( SignalSender::AddActiveSampler(this);
&data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
data_->signal_sender_launched_ = true;
}
// Set this sampler as the active sampler.
active_sampler_ = this;
} }
void Sampler::Stop() { void Sampler::Stop() {
ASSERT(IsActive());
SignalSender::RemoveActiveSampler(this);
SetActive(false); SetActive(false);
// Wait for signal sender termination (it will exit after setting
// active_ to false).
if (data_->signal_sender_launched_) {
Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
pthread_join(data_->signal_sender_thread_, NULL);
data_->signal_sender_launched_ = false;
}
// Restore old signal handler
if (data_->signal_handler_installed_) {
sigaction(SIGPROF, &data_->old_signal_handler_, 0);
data_->signal_handler_installed_ = false;
}
// This sampler is no longer the active sampler.
active_sampler_ = NULL;
} }
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING

9
deps/v8/src/prettyprinter.cc

@ -203,7 +203,7 @@ void PrettyPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
Visit(node->try_block()); Visit(node->try_block());
Print(" catch ("); Print(" catch (");
const bool quote = false; const bool quote = false;
PrintLiteral(node->name(), quote); PrintLiteral(node->variable()->name(), quote);
Print(") "); Print(") ");
Visit(node->catch_block()); Visit(node->catch_block());
} }
@ -856,8 +856,9 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) {
void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
IndentedScope indent(this, "TRY CATCH"); IndentedScope indent(this, "TRY CATCH");
PrintIndentedVisit("TRY", node->try_block()); PrintIndentedVisit("TRY", node->try_block());
const bool quote = false; PrintLiteralWithModeIndented("CATCHVAR",
PrintLiteralIndented("CATCHVAR", node->name(), quote); node->variable(),
node->variable()->name());
PrintIndentedVisit("CATCH", node->catch_block()); PrintIndentedVisit("CATCH", node->catch_block());
} }
@ -1244,7 +1245,7 @@ void JsonAstBuilder::VisitForInStatement(ForInStatement* stmt) {
void JsonAstBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { void JsonAstBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
TagScope tag(this, "TryCatchStatement"); TagScope tag(this, "TryCatchStatement");
{ AttributesScope attributes(this); { AttributesScope attributes(this);
AddAttribute("variable", stmt->name()); AddAttribute("variable", stmt->variable()->name());
} }
Visit(stmt->try_block()); Visit(stmt->try_block());
Visit(stmt->catch_block()); Visit(stmt->catch_block());

108
deps/v8/src/profile-generator.cc

@ -1635,7 +1635,8 @@ HeapObject *const V8HeapExplorer::kGcRootsObject =
V8HeapExplorer::V8HeapExplorer( V8HeapExplorer::V8HeapExplorer(
HeapSnapshot* snapshot, HeapSnapshot* snapshot,
SnapshottingProgressReportingInterface* progress) SnapshottingProgressReportingInterface* progress)
: snapshot_(snapshot), : heap_(Isolate::Current()->heap()),
snapshot_(snapshot),
collection_(snapshot_->collection()), collection_(snapshot_->collection()),
progress_(progress), progress_(progress),
filler_(NULL) { filler_(NULL) {
@ -1725,10 +1726,14 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
: "", : "",
children_count, children_count,
retainers_count); retainers_count);
} else if (object->IsFixedArray() || object->IsByteArray()) { } else if (object->IsFixedArray() ||
object->IsFixedDoubleArray() ||
object->IsByteArray() ||
object->IsExternalArray()) {
const char* tag = objects_tags_.GetTag(object);
return AddEntry(object, return AddEntry(object,
HeapEntry::kArray, HeapEntry::kArray,
"", tag != NULL ? tag : "",
children_count, children_count,
retainers_count); retainers_count);
} else if (object->IsHeapNumber()) { } else if (object->IsHeapNumber()) {
@ -1836,15 +1841,13 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
HeapEntry* entry = GetEntry(obj); HeapEntry* entry = GetEntry(obj);
if (entry == NULL) return; // No interest in this object. if (entry == NULL) return; // No interest in this object.
bool extract_indexed_refs = true;
if (obj->IsJSGlobalProxy()) { if (obj->IsJSGlobalProxy()) {
// We need to reference JS global objects from snapshot's root. // We need to reference JS global objects from snapshot's root.
// We use JSGlobalProxy because this is what embedder (e.g. browser) // We use JSGlobalProxy because this is what embedder (e.g. browser)
// uses for the global object. // uses for the global object.
JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
SetRootShortcutReference(proxy->map()->prototype()); SetRootShortcutReference(proxy->map()->prototype());
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
IndexedReferencesExtractor refs_extractor(this, obj, entry);
obj->Iterate(&refs_extractor);
} else if (obj->IsJSObject()) { } else if (obj->IsJSObject()) {
JSObject* js_obj = JSObject::cast(obj); JSObject* js_obj = JSObject::cast(obj);
ExtractClosureReferences(js_obj, entry); ExtractClosureReferences(js_obj, entry);
@ -1852,7 +1855,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
ExtractElementReferences(js_obj, entry); ExtractElementReferences(js_obj, entry);
ExtractInternalReferences(js_obj, entry); ExtractInternalReferences(js_obj, entry);
SetPropertyReference( SetPropertyReference(
obj, entry, HEAP->Proto_symbol(), js_obj->GetPrototype()); obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype());
if (obj->IsJSFunction()) { if (obj->IsJSFunction()) {
JSFunction* js_fun = JSFunction::cast(js_obj); JSFunction* js_fun = JSFunction::cast(js_obj);
Object* proto_or_map = js_fun->prototype_or_initial_map(); Object* proto_or_map = js_fun->prototype_or_initial_map();
@ -1860,39 +1863,49 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
if (!proto_or_map->IsMap()) { if (!proto_or_map->IsMap()) {
SetPropertyReference( SetPropertyReference(
obj, entry, obj, entry,
HEAP->prototype_symbol(), proto_or_map, heap_->prototype_symbol(), proto_or_map,
JSFunction::kPrototypeOrInitialMapOffset); JSFunction::kPrototypeOrInitialMapOffset);
} else { } else {
SetPropertyReference( SetPropertyReference(
obj, entry, obj, entry,
HEAP->prototype_symbol(), js_fun->prototype()); heap_->prototype_symbol(), js_fun->prototype());
} }
} }
SetInternalReference(js_fun, entry, SetInternalReference(js_fun, entry,
"shared", js_fun->shared(), "shared", js_fun->shared(),
JSFunction::kSharedFunctionInfoOffset); JSFunction::kSharedFunctionInfoOffset);
TagObject(js_fun->unchecked_context(), "(context)");
SetInternalReference(js_fun, entry, SetInternalReference(js_fun, entry,
"context", js_fun->unchecked_context(), "context", js_fun->unchecked_context(),
JSFunction::kContextOffset); JSFunction::kContextOffset);
TagObject(js_fun->literals(), "(function literals)");
SetInternalReference(js_fun, entry, SetInternalReference(js_fun, entry,
"literals", js_fun->literals(), "literals", js_fun->literals(),
JSFunction::kLiteralsOffset); JSFunction::kLiteralsOffset);
} }
TagObject(js_obj->properties(), "(object properties)");
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
"properties", js_obj->properties(), "properties", js_obj->properties(),
JSObject::kPropertiesOffset); JSObject::kPropertiesOffset);
TagObject(js_obj->elements(), "(object elements)");
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
"elements", js_obj->elements(), "elements", js_obj->elements(),
JSObject::kElementsOffset); JSObject::kElementsOffset);
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
IndexedReferencesExtractor refs_extractor(this, obj, entry);
obj->Iterate(&refs_extractor);
} else if (obj->IsString()) { } else if (obj->IsString()) {
if (obj->IsConsString()) { if (obj->IsConsString()) {
ConsString* cs = ConsString::cast(obj); ConsString* cs = ConsString::cast(obj);
SetInternalReference(obj, entry, 1, cs->first()); SetInternalReference(obj, entry, 1, cs->first());
SetInternalReference(obj, entry, 2, cs->second()); SetInternalReference(obj, entry, 2, cs->second());
} }
extract_indexed_refs = false;
} else if (obj->IsGlobalContext()) {
Context* context = Context::cast(obj);
TagObject(context->jsfunction_result_caches(),
"(context func. result caches)");
TagObject(context->normalized_map_cache(), "(context norm. map cache)");
TagObject(context->runtime_context(), "(runtime context)");
TagObject(context->map_cache(), "(context map cache)");
TagObject(context->data(), "(context data)");
} else if (obj->IsMap()) { } else if (obj->IsMap()) {
Map* map = Map::cast(obj); Map* map = Map::cast(obj);
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
@ -1901,6 +1914,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
"constructor", map->constructor(), "constructor", map->constructor(),
Map::kConstructorOffset); Map::kConstructorOffset);
if (!map->instance_descriptors()->IsEmpty()) { if (!map->instance_descriptors()->IsEmpty()) {
TagObject(map->instance_descriptors(), "(map descriptors)");
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
"descriptors", map->instance_descriptors(), "descriptors", map->instance_descriptors(),
Map::kInstanceDescriptorsOrBitField3Offset); Map::kInstanceDescriptorsOrBitField3Offset);
@ -1908,9 +1922,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
"code_cache", map->code_cache(), "code_cache", map->code_cache(),
Map::kCodeCacheOffset); Map::kCodeCacheOffset);
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
IndexedReferencesExtractor refs_extractor(this, obj, entry);
obj->Iterate(&refs_extractor);
} else if (obj->IsSharedFunctionInfo()) { } else if (obj->IsSharedFunctionInfo()) {
SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
@ -1919,16 +1930,61 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
"code", shared->unchecked_code(), "code", shared->unchecked_code(),
SharedFunctionInfo::kCodeOffset); SharedFunctionInfo::kCodeOffset);
TagObject(shared->scope_info(), "(function scope info)");
SetInternalReference(obj, entry,
"scope_info", shared->scope_info(),
SharedFunctionInfo::kScopeInfoOffset);
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
"instance_class_name", shared->instance_class_name(), "instance_class_name", shared->instance_class_name(),
SharedFunctionInfo::kInstanceClassNameOffset); SharedFunctionInfo::kInstanceClassNameOffset);
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
"script", shared->script(), "script", shared->script(),
SharedFunctionInfo::kScriptOffset); SharedFunctionInfo::kScriptOffset);
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); } else if (obj->IsScript()) {
IndexedReferencesExtractor refs_extractor(this, obj, entry); Script* script = Script::cast(obj);
obj->Iterate(&refs_extractor); SetInternalReference(obj, entry,
} else { "source", script->source(),
Script::kSourceOffset);
SetInternalReference(obj, entry,
"name", script->name(),
Script::kNameOffset);
SetInternalReference(obj, entry,
"data", script->data(),
Script::kDataOffset);
SetInternalReference(obj, entry,
"context_data", script->context_data(),
Script::kContextOffset);
TagObject(script->line_ends(), "(script line ends)");
SetInternalReference(obj, entry,
"line_ends", script->line_ends(),
Script::kLineEndsOffset);
} else if (obj->IsDescriptorArray()) {
DescriptorArray* desc_array = DescriptorArray::cast(obj);
if (desc_array->length() > DescriptorArray::kContentArrayIndex) {
Object* content_array =
desc_array->get(DescriptorArray::kContentArrayIndex);
TagObject(content_array, "(map descriptor content)");
SetInternalReference(obj, entry,
"content", content_array,
FixedArray::OffsetOfElementAt(
DescriptorArray::kContentArrayIndex));
}
} else if (obj->IsCodeCache()) {
CodeCache* code_cache = CodeCache::cast(obj);
TagObject(code_cache->default_cache(), "(default code cache)");
SetInternalReference(obj, entry,
"default_cache", code_cache->default_cache(),
CodeCache::kDefaultCacheOffset);
TagObject(code_cache->normal_type_cache(), "(code type cache)");
SetInternalReference(obj, entry,
"type_cache", code_cache->normal_type_cache(),
CodeCache::kNormalTypeCacheOffset);
} else if (obj->IsCode()) {
Code* code = Code::cast(obj);
TagObject(code->unchecked_relocation_info(), "(code relocation info)");
TagObject(code->unchecked_deoptimization_data(), "(code deopt data)");
}
if (extract_indexed_refs) {
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
IndexedReferencesExtractor refs_extractor(this, obj, entry); IndexedReferencesExtractor refs_extractor(this, obj, entry);
obj->Iterate(&refs_extractor); obj->Iterate(&refs_extractor);
@ -2086,7 +2142,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(
} }
SetRootGcRootsReference(); SetRootGcRootsReference();
RootsReferencesExtractor extractor(this); RootsReferencesExtractor extractor(this);
HEAP->IterateRoots(&extractor, VISIT_ALL); heap_->IterateRoots(&extractor, VISIT_ALL);
filler_ = NULL; filler_ = NULL;
return progress_->ProgressReport(false); return progress_->ProgressReport(false);
} }
@ -2241,6 +2297,18 @@ void V8HeapExplorer::SetGcRootsReference(Object* child_obj) {
} }
void V8HeapExplorer::TagObject(Object* obj, const char* tag) {
if (obj->IsHeapObject() &&
!obj->IsOddball() &&
obj != heap_->raw_unchecked_empty_byte_array() &&
obj != heap_->raw_unchecked_empty_fixed_array() &&
obj != heap_->raw_unchecked_empty_fixed_double_array() &&
obj != heap_->raw_unchecked_empty_descriptor_array()) {
objects_tags_.SetTag(obj, tag);
}
}
class GlobalObjectsEnumerator : public ObjectVisitor { class GlobalObjectsEnumerator : public ObjectVisitor {
public: public:
virtual void VisitPointers(Object** start, Object** end) { virtual void VisitPointers(Object** start, Object** end) {

2
deps/v8/src/profile-generator.h

@ -973,9 +973,11 @@ class V8HeapExplorer : public HeapEntriesAllocator {
void SetRootShortcutReference(Object* child); void SetRootShortcutReference(Object* child);
void SetRootGcRootsReference(); void SetRootGcRootsReference();
void SetGcRootsReference(Object* child); void SetGcRootsReference(Object* child);
void TagObject(Object* obj, const char* tag);
HeapEntry* GetEntry(Object* obj); HeapEntry* GetEntry(Object* obj);
Heap* heap_;
HeapSnapshot* snapshot_; HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_; HeapSnapshotsCollection* collection_;
SnapshottingProgressReportingInterface* progress_; SnapshottingProgressReportingInterface* progress_;

2
deps/v8/src/rewriter.cc

@ -218,7 +218,7 @@ bool Rewriter::Rewrite(CompilationInfo* info) {
ASSERT(function != NULL); ASSERT(function != NULL);
Scope* scope = function->scope(); Scope* scope = function->scope();
ASSERT(scope != NULL); ASSERT(scope != NULL);
if (scope->is_function_scope()) return true; if (!scope->is_global_scope() && !scope->is_eval_scope()) return true;
ZoneList<Statement*>* body = function->body(); ZoneList<Statement*>* body = function->body();
if (!body->is_empty()) { if (!body->is_empty()) {

139
deps/v8/src/runtime-profiler.cc

@ -43,32 +43,6 @@ namespace v8 {
namespace internal { namespace internal {
class PendingListNode : public Malloced {
public:
explicit PendingListNode(JSFunction* function);
~PendingListNode() { Destroy(); }
PendingListNode* next() const { return next_; }
void set_next(PendingListNode* node) { next_ = node; }
Handle<JSFunction> function() { return Handle<JSFunction>::cast(function_); }
// If the function is garbage collected before we've had the chance
// to optimize it the weak handle will be null.
bool IsValid() { return !function_.is_null(); }
// Returns the number of microseconds this node has been pending.
int Delay() const { return static_cast<int>(OS::Ticks() - start_); }
private:
void Destroy();
static void WeakCallback(v8::Persistent<v8::Value> object, void* data);
PendingListNode* next_;
Handle<Object> function_; // Weak handle.
int64_t start_;
};
// Optimization sampler constants. // Optimization sampler constants.
static const int kSamplerFrameCount = 2; static const int kSamplerFrameCount = 2;
static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 }; static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
@ -80,33 +54,10 @@ static const int kSamplerThresholdMin = 1;
static const int kSamplerThresholdDelta = 1; static const int kSamplerThresholdDelta = 1;
static const int kSamplerThresholdSizeFactorInit = 3; static const int kSamplerThresholdSizeFactorInit = 3;
static const int kSamplerThresholdSizeFactorMin = 1;
static const int kSamplerThresholdSizeFactorDelta = 1;
static const int kSizeLimit = 1500; static const int kSizeLimit = 1500;
PendingListNode::PendingListNode(JSFunction* function) : next_(NULL) {
GlobalHandles* global_handles = Isolate::Current()->global_handles();
function_ = global_handles->Create(function);
start_ = OS::Ticks();
global_handles->MakeWeak(function_.location(), this, &WeakCallback);
}
void PendingListNode::Destroy() {
if (!IsValid()) return;
GlobalHandles* global_handles = Isolate::Current()->global_handles();
global_handles->Destroy(function_.location());
function_= Handle<Object>::null();
}
void PendingListNode::WeakCallback(v8::Persistent<v8::Value>, void* data) {
reinterpret_cast<PendingListNode*>(data)->Destroy();
}
Atomic32 RuntimeProfiler::state_ = 0; Atomic32 RuntimeProfiler::state_ = 0;
// TODO(isolates): Create the semaphore lazily and clean it up when no // TODO(isolates): Create the semaphore lazily and clean it up when no
// longer required. // longer required.
@ -126,15 +77,7 @@ RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit), sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit),
sampler_ticks_until_threshold_adjustment_( sampler_ticks_until_threshold_adjustment_(
kSamplerTicksBetweenThresholdAdjustment), kSamplerTicksBetweenThresholdAdjustment),
js_ratio_(0), sampler_window_position_(0) {
sampler_window_position_(0),
optimize_soon_list_(NULL),
state_window_position_(0),
state_window_ticks_(0) {
state_counts_[IN_NON_JS_STATE] = kStateWindowSize;
state_counts_[IN_JS_STATE] = 0;
STATIC_ASSERT(IN_NON_JS_STATE == 0);
memset(state_window_, 0, sizeof(state_window_));
ClearSampleBuffer(); ClearSampleBuffer();
} }
@ -148,16 +91,13 @@ void RuntimeProfiler::GlobalSetup() {
} }
void RuntimeProfiler::Optimize(JSFunction* function, bool eager, int delay) { void RuntimeProfiler::Optimize(JSFunction* function) {
ASSERT(function->IsOptimizable()); ASSERT(function->IsOptimizable());
if (FLAG_trace_opt) { if (FLAG_trace_opt) {
PrintF("[marking (%s) ", eager ? "eagerly" : "lazily"); PrintF("[marking ");
function->PrintName(); function->PrintName();
PrintF(" 0x%" V8PRIxPTR, reinterpret_cast<intptr_t>(function->address())); PrintF(" 0x%" V8PRIxPTR, reinterpret_cast<intptr_t>(function->address()));
PrintF(" for recompilation"); PrintF(" for recompilation");
if (delay > 0) {
PrintF(" (delayed %0.3f ms)", static_cast<double>(delay) / 1000);
}
PrintF("]\n"); PrintF("]\n");
} }
@ -243,20 +183,6 @@ void RuntimeProfiler::AddSample(JSFunction* function, int weight) {
void RuntimeProfiler::OptimizeNow() { void RuntimeProfiler::OptimizeNow() {
HandleScope scope(isolate_); HandleScope scope(isolate_);
PendingListNode* current = optimize_soon_list_;
while (current != NULL) {
PendingListNode* next = current->next();
if (current->IsValid()) {
Handle<JSFunction> function = current->function();
int delay = current->Delay();
if (function->IsOptimizable()) {
Optimize(*function, true, delay);
}
}
delete current;
current = next;
}
optimize_soon_list_ = NULL;
// Run through the JavaScript frames and collect them. If we already // Run through the JavaScript frames and collect them. If we already
// have a sample of the function, we mark it for optimizations // have a sample of the function, we mark it for optimizations
@ -303,24 +229,9 @@ void RuntimeProfiler::OptimizeNow() {
: 1; : 1;
int threshold = sampler_threshold_ * threshold_size_factor; int threshold = sampler_threshold_ * threshold_size_factor;
int current_js_ratio = NoBarrier_Load(&js_ratio_);
// Adjust threshold depending on the ratio of time spent
// in JS code.
if (current_js_ratio < 20) {
// If we spend less than 20% of the time in JS code,
// do not optimize.
continue;
} else if (current_js_ratio < 75) {
// Below 75% of time spent in JS code, only optimize very
// frequently used functions.
threshold *= 3;
}
if (LookupSample(function) >= threshold) { if (LookupSample(function) >= threshold) {
Optimize(function, false, 0); Optimize(function);
isolate_->compilation_cache()->MarkForEagerOptimizing(
Handle<JSFunction>(function));
} }
} }
@ -333,40 +244,8 @@ void RuntimeProfiler::OptimizeNow() {
} }
void RuntimeProfiler::OptimizeSoon(JSFunction* function) {
if (!function->IsOptimizable()) return;
PendingListNode* node = new PendingListNode(function);
node->set_next(optimize_soon_list_);
optimize_soon_list_ = node;
}
#ifdef ENABLE_LOGGING_AND_PROFILING
void RuntimeProfiler::UpdateStateRatio(SamplerState current_state) {
SamplerState old_state = state_window_[state_window_position_];
state_counts_[old_state]--;
state_window_[state_window_position_] = current_state;
state_counts_[current_state]++;
ASSERT(IsPowerOf2(kStateWindowSize));
state_window_position_ = (state_window_position_ + 1) &
(kStateWindowSize - 1);
// Note: to calculate correct ratio we have to track how many valid
// ticks are actually in the state window, because on profiler
// startup this number can be less than the window size.
state_window_ticks_ = Min(kStateWindowSize, state_window_ticks_ + 1);
NoBarrier_Store(&js_ratio_, state_counts_[IN_JS_STATE] * 100 /
state_window_ticks_);
}
#endif
void RuntimeProfiler::NotifyTick() { void RuntimeProfiler::NotifyTick() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
// Record state sample.
SamplerState state = IsSomeIsolateInJS()
? IN_JS_STATE
: IN_NON_JS_STATE;
UpdateStateRatio(state);
isolate_->stack_guard()->RequestRuntimeProfilerTick(); isolate_->stack_guard()->RequestRuntimeProfilerTick();
#endif #endif
} }
@ -424,7 +303,6 @@ void RuntimeProfiler::HandleWakeUp(Isolate* isolate) {
// to get the right count of active isolates. // to get the right count of active isolates.
NoBarrier_AtomicIncrement(&state_, 1); NoBarrier_AtomicIncrement(&state_, 1);
semaphore_->Signal(); semaphore_->Signal();
isolate->ResetEagerOptimizingData();
#endif #endif
} }
@ -471,16 +349,9 @@ void RuntimeProfiler::UpdateSamplesAfterCompact(ObjectVisitor* visitor) {
bool RuntimeProfilerRateLimiter::SuspendIfNecessary() { bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
static const int kNonJSTicksThreshold = 100; if (!RuntimeProfiler::IsSomeIsolateInJS()) {
if (RuntimeProfiler::IsSomeIsolateInJS()) {
non_js_ticks_ = 0;
} else {
if (non_js_ticks_ < kNonJSTicksThreshold) {
++non_js_ticks_;
} else {
return RuntimeProfiler::WaitForSomeIsolateToEnterJS(); return RuntimeProfiler::WaitForSomeIsolateToEnterJS();
} }
}
#endif #endif
return false; return false;
} }

23
deps/v8/src/runtime-profiler.h

@ -37,7 +37,6 @@ namespace internal {
class Isolate; class Isolate;
class JSFunction; class JSFunction;
class Object; class Object;
class PendingListNode;
class Semaphore; class Semaphore;
class RuntimeProfiler { class RuntimeProfiler {
@ -52,7 +51,6 @@ class RuntimeProfiler {
} }
void OptimizeNow(); void OptimizeNow();
void OptimizeSoon(JSFunction* function);
void NotifyTick(); void NotifyTick();
@ -106,7 +104,7 @@ class RuntimeProfiler {
static void HandleWakeUp(Isolate* isolate); static void HandleWakeUp(Isolate* isolate);
void Optimize(JSFunction* function, bool eager, int delay); void Optimize(JSFunction* function);
void AttemptOnStackReplacement(JSFunction* function); void AttemptOnStackReplacement(JSFunction* function);
@ -118,31 +116,16 @@ class RuntimeProfiler {
void AddSample(JSFunction* function, int weight); void AddSample(JSFunction* function, int weight);
#ifdef ENABLE_LOGGING_AND_PROFILING
void UpdateStateRatio(SamplerState current_state);
#endif
Isolate* isolate_; Isolate* isolate_;
int sampler_threshold_; int sampler_threshold_;
int sampler_threshold_size_factor_; int sampler_threshold_size_factor_;
int sampler_ticks_until_threshold_adjustment_; int sampler_ticks_until_threshold_adjustment_;
// The ratio of ticks spent in JS code in percent.
Atomic32 js_ratio_;
Object* sampler_window_[kSamplerWindowSize]; Object* sampler_window_[kSamplerWindowSize];
int sampler_window_position_; int sampler_window_position_;
int sampler_window_weight_[kSamplerWindowSize]; int sampler_window_weight_[kSamplerWindowSize];
// Support for pending 'optimize soon' requests.
PendingListNode* optimize_soon_list_;
SamplerState state_window_[kStateWindowSize];
int state_window_position_;
int state_window_ticks_;
int state_counts_[2];
// Possible state values: // Possible state values:
// -1 => the profiler thread is waiting on the semaphore // -1 => the profiler thread is waiting on the semaphore
// 0 or positive => the number of isolates running JavaScript code. // 0 or positive => the number of isolates running JavaScript code.
@ -159,7 +142,7 @@ class RuntimeProfiler {
// Rate limiter intended to be used in the profiler thread. // Rate limiter intended to be used in the profiler thread.
class RuntimeProfilerRateLimiter BASE_EMBEDDED { class RuntimeProfilerRateLimiter BASE_EMBEDDED {
public: public:
RuntimeProfilerRateLimiter() : non_js_ticks_(0) { } RuntimeProfilerRateLimiter() {}
// Suspends the current thread (which must be the profiler thread) // Suspends the current thread (which must be the profiler thread)
// when not executing JavaScript to minimize CPU usage. Returns // when not executing JavaScript to minimize CPU usage. Returns
@ -170,8 +153,6 @@ class RuntimeProfilerRateLimiter BASE_EMBEDDED {
bool SuspendIfNecessary(); bool SuspendIfNecessary();
private: private:
int non_js_ticks_;
DISALLOW_COPY_AND_ASSIGN(RuntimeProfilerRateLimiter); DISALLOW_COPY_AND_ASSIGN(RuntimeProfilerRateLimiter);
}; };

166
deps/v8/src/runtime.cc

@ -3918,16 +3918,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
if (proto->IsNull()) return *obj_value; if (proto->IsNull()) return *obj_value;
js_object = Handle<JSObject>::cast(proto); js_object = Handle<JSObject>::cast(proto);
} }
NormalizeElements(js_object); Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
Handle<NumberDictionary> dictionary(js_object->element_dictionary());
// Make sure that we never go back to fast case. // Make sure that we never go back to fast case.
dictionary->set_requires_slow_elements(); dictionary->set_requires_slow_elements();
PropertyDetails details = PropertyDetails(attr, NORMAL); PropertyDetails details = PropertyDetails(attr, NORMAL);
Handle<NumberDictionary> extended_dictionary = Handle<NumberDictionary> extended_dictionary =
NumberDictionarySet(dictionary, index, obj_value, details); NumberDictionarySet(dictionary, index, obj_value, details);
if (*extended_dictionary != *dictionary) { if (*extended_dictionary != *dictionary) {
if (js_object->GetElementsKind() ==
JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
} else {
js_object->set_elements(*extended_dictionary); js_object->set_elements(*extended_dictionary);
} }
}
return *obj_value; return *obj_value;
} }
@ -3981,8 +3985,7 @@ static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attr) { PropertyAttributes attr) {
// Normalize the elements to enable attributes on the property. // Normalize the elements to enable attributes on the property.
NormalizeElements(js_object); Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
Handle<NumberDictionary> dictionary(js_object->element_dictionary());
// Make sure that we never go back to fast case. // Make sure that we never go back to fast case.
dictionary->set_requires_slow_elements(); dictionary->set_requires_slow_elements();
PropertyDetails details = PropertyDetails(attr, NORMAL); PropertyDetails details = PropertyDetails(attr, NORMAL);
@ -5742,6 +5745,27 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
} }
void FindAsciiStringIndices(Vector<const char> subject,
char pattern,
ZoneList<int>* indices,
unsigned int limit) {
ASSERT(limit > 0);
// Collect indices of pattern in subject using memchr.
// Stop after finding at most limit values.
const char* subject_start = reinterpret_cast<const char*>(subject.start());
const char* subject_end = subject_start + subject.length();
const char* pos = subject_start;
while (limit > 0) {
pos = reinterpret_cast<const char*>(
memchr(pos, pattern, subject_end - pos));
if (pos == NULL) return;
indices->Add(static_cast<int>(pos - subject_start));
pos++;
limit--;
}
}
template <typename SubjectChar, typename PatternChar> template <typename SubjectChar, typename PatternChar>
void FindStringIndices(Isolate* isolate, void FindStringIndices(Isolate* isolate,
Vector<const SubjectChar> subject, Vector<const SubjectChar> subject,
@ -5749,11 +5773,11 @@ void FindStringIndices(Isolate* isolate,
ZoneList<int>* indices, ZoneList<int>* indices,
unsigned int limit) { unsigned int limit) {
ASSERT(limit > 0); ASSERT(limit > 0);
// Collect indices of pattern in subject, and the end-of-string index. // Collect indices of pattern in subject.
// Stop after finding at most limit values. // Stop after finding at most limit values.
StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
int pattern_length = pattern.length(); int pattern_length = pattern.length();
int index = 0; int index = 0;
StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
while (limit > 0) { while (limit > 0) {
index = search.Search(subject, index); index = search.Search(subject, index);
if (index < 0) return; if (index < 0) return;
@ -5796,11 +5820,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
if (subject->IsAsciiRepresentation()) { if (subject->IsAsciiRepresentation()) {
Vector<const char> subject_vector = subject->ToAsciiVector(); Vector<const char> subject_vector = subject->ToAsciiVector();
if (pattern->IsAsciiRepresentation()) { if (pattern->IsAsciiRepresentation()) {
Vector<const char> pattern_vector = pattern->ToAsciiVector();
if (pattern_vector.length() == 1) {
FindAsciiStringIndices(subject_vector,
pattern_vector[0],
&indices,
limit);
} else {
FindStringIndices(isolate, FindStringIndices(isolate,
subject_vector, subject_vector,
pattern->ToAsciiVector(), pattern_vector,
&indices, &indices,
limit); limit);
}
} else { } else {
FindStringIndices(isolate, FindStringIndices(isolate,
subject_vector, subject_vector,
@ -7821,7 +7853,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
} }
} }
isolate->compilation_cache()->MarkForLazyOptimizing(function);
if (type == Deoptimizer::EAGER) { if (type == Deoptimizer::EAGER) {
RUNTIME_ASSERT(function->IsOptimized()); RUNTIME_ASSERT(function->IsOptimized());
} else { } else {
@ -9938,7 +9969,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
// If there is no JavaScript stack frame count is 0. // If there is no JavaScript stack frame count is 0.
return Smi::FromInt(0); return Smi::FromInt(0);
} }
for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
n += it.frame()->GetInlineCount();
}
return Smi::FromInt(n); return Smi::FromInt(n);
} }
@ -9951,7 +9985,7 @@ static const int kFrameDetailsLocalCountIndex = 4;
static const int kFrameDetailsSourcePositionIndex = 5; static const int kFrameDetailsSourcePositionIndex = 5;
static const int kFrameDetailsConstructCallIndex = 6; static const int kFrameDetailsConstructCallIndex = 6;
static const int kFrameDetailsAtReturnIndex = 7; static const int kFrameDetailsAtReturnIndex = 7;
static const int kFrameDetailsDebuggerFrameIndex = 8; static const int kFrameDetailsFlagsIndex = 8;
static const int kFrameDetailsFirstDynamicIndex = 9; static const int kFrameDetailsFirstDynamicIndex = 9;
// Return an array with frame details // Return an array with frame details
@ -9967,7 +10001,7 @@ static const int kFrameDetailsFirstDynamicIndex = 9;
// 5: Source position // 5: Source position
// 6: Constructor call // 6: Constructor call
// 7: Is at return // 7: Is at return
// 8: Debugger frame // 8: Flags
// Arguments name, value // Arguments name, value
// Locals name, value // Locals name, value
// Return value if any // Return value if any
@ -9990,16 +10024,26 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
// If there are no JavaScript stack frames return undefined. // If there are no JavaScript stack frames return undefined.
return heap->undefined_value(); return heap->undefined_value();
} }
int deoptimized_frame_index = -1; // Frame index in optimized frame.
DeoptimizedFrameInfo* deoptimized_frame = NULL;
int count = 0; int count = 0;
JavaScriptFrameIterator it(isolate, id); JavaScriptFrameIterator it(isolate, id);
for (; !it.done(); it.Advance()) { for (; !it.done(); it.Advance()) {
if (count == index) break; if (index < count + it.frame()->GetInlineCount()) break;
count++; count += it.frame()->GetInlineCount();
} }
if (it.done()) return heap->undefined_value(); if (it.done()) return heap->undefined_value();
bool is_optimized_frame = if (it.frame()->is_optimized()) {
it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION; deoptimized_frame_index =
it.frame()->GetInlineCount() - (index - count) - 1;
deoptimized_frame = Deoptimizer::DebuggerInspectableFrame(
it.frame(),
deoptimized_frame_index,
isolate);
}
// Traverse the saved contexts chain to find the active context for the // Traverse the saved contexts chain to find the active context for the
// selected frame. // selected frame.
@ -10022,6 +10066,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
// Get scope info and read from it for local variable information. // Get scope info and read from it for local variable information.
Handle<JSFunction> function(JSFunction::cast(it.frame()->function())); Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info()); Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ASSERT(*scope_info != SerializedScopeInfo::Empty());
ScopeInfo<> info(*scope_info); ScopeInfo<> info(*scope_info);
// Get the locals names and values into a temporary array. // Get the locals names and values into a temporary array.
@ -10033,23 +10078,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2); isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
// Fill in the values of the locals. // Fill in the values of the locals.
if (is_optimized_frame) {
// If we are inspecting an optimized frame use undefined as the
// value for all locals.
//
// TODO(1140): We should be able to get the correct values
// for locals in optimized frames.
for (int i = 0; i < info.NumberOfLocals(); i++) {
locals->set(i * 2, *info.LocalName(i));
locals->set(i * 2 + 1, isolate->heap()->undefined_value());
}
} else {
int i = 0; int i = 0;
for (; i < info.number_of_stack_slots(); ++i) { for (; i < info.number_of_stack_slots(); ++i) {
// Use the value from the stack. // Use the value from the stack.
locals->set(i * 2, *info.LocalName(i)); locals->set(i * 2, *info.LocalName(i));
if (it.frame()->is_optimized()) {
// Get the value from the deoptimized frame.
locals->set(i * 2 + 1,
deoptimized_frame->GetExpression(i));
} else {
// Get the value from the stack.
locals->set(i * 2 + 1, it.frame()->GetExpression(i)); locals->set(i * 2 + 1, it.frame()->GetExpression(i));
} }
}
if (i < info.NumberOfLocals()) {
// Get the context containing declarations. // Get the context containing declarations.
Handle<Context> context( Handle<Context> context(
Context::cast(it.frame()->context())->declaration_context()); Context::cast(it.frame()->context())->declaration_context());
@ -10064,7 +10106,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
// Check whether this frame is positioned at return. If not top // Check whether this frame is positioned at return. If not top
// frame or if the frame is optimized it cannot be at a return. // frame or if the frame is optimized it cannot be at a return.
bool at_return = false; bool at_return = false;
if (!is_optimized_frame && index == 0) { if (!it.frame()->is_optimized() && index == 0) {
at_return = isolate->debug()->IsBreakAtReturn(it.frame()); at_return = isolate->debug()->IsBreakAtReturn(it.frame());
} }
@ -10145,10 +10187,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
// Add the at return information. // Add the at return information.
details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
// Add information on whether this frame is invoked in the debugger context. // Add flags to indicate information on whether this frame is
details->set(kFrameDetailsDebuggerFrameIndex, // bit 0: invoked in the debugger context.
heap->ToBoolean(*save->context() == // bit 1: optimized frame.
*isolate->debug()->debug_context())); // bit 2: inlined in optimized frame
int flags = 0;
if (*save->context() == *isolate->debug()->debug_context()) {
flags |= 1 << 0;
}
if (it.frame()->is_optimized()) {
flags |= 1 << 1;
if (deoptimized_frame_index > 0) {
flags |= 1 << 2;
}
}
details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
// Fill the dynamic part. // Fill the dynamic part.
int details_index = kFrameDetailsFirstDynamicIndex; int details_index = kFrameDetailsFirstDynamicIndex;
@ -10167,7 +10220,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
// //
// TODO(3141533): We should be able to get the actual parameter // TODO(3141533): We should be able to get the actual parameter
// value for optimized frames. // value for optimized frames.
if (!is_optimized_frame && if (!it.frame()->is_optimized() &&
(i < it.frame()->ComputeParametersCount())) { (i < it.frame()->ComputeParametersCount())) {
details->set(details_index++, it.frame()->GetParameter(i)); details->set(details_index++, it.frame()->GetParameter(i));
} else { } else {
@ -10203,6 +10256,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
} }
details->set(kFrameDetailsReceiverIndex, *receiver); details->set(kFrameDetailsReceiverIndex, *receiver);
// Get rid of the calculated deoptimized frame if any.
if (deoptimized_frame != NULL) {
Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame,
isolate);
}
ASSERT_EQ(details_size, details_index); ASSERT_EQ(details_size, details_index);
return *isolate->factory()->NewJSArrayWithElements(details); return *isolate->factory()->NewJSArrayWithElements(details);
} }
@ -10263,7 +10322,7 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
} }
// Second fill all stack locals. // Second fill all stack locals.
for (int i = 0; i < scope_info.number_of_stack_slots(); i++) { for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
RETURN_IF_EMPTY_HANDLE_VALUE( RETURN_IF_EMPTY_HANDLE_VALUE(
isolate, isolate,
SetProperty(local_scope, SetProperty(local_scope,
@ -10274,6 +10333,7 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
Handle<JSObject>()); Handle<JSObject>());
} }
if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
// Third fill all context locals. // Third fill all context locals.
Handle<Context> frame_context(Context::cast(frame->context())); Handle<Context> frame_context(Context::cast(frame->context()));
Handle<Context> function_context(frame_context->declaration_context()); Handle<Context> function_context(frame_context->declaration_context());
@ -10283,8 +10343,8 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
return Handle<JSObject>(); return Handle<JSObject>();
} }
// Finally copy any properties from the function context extension. This will // Finally copy any properties from the function context extension.
// be variables introduced by eval. // These will be variables introduced by eval.
if (function_context->closure() == *function) { if (function_context->closure() == *function) {
if (function_context->has_extension() && if (function_context->has_extension() &&
!function_context->IsGlobalContext()) { !function_context->IsGlobalContext()) {
@ -10305,6 +10365,8 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
} }
} }
} }
}
return local_scope; return local_scope;
} }
@ -12074,22 +12136,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) { RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 2); v8::V8::ResumeProfiler();
CONVERT_CHECKED(Smi, smi_modules, args[0]);
CONVERT_CHECKED(Smi, smi_tag, args[1]);
v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) { RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 2); v8::V8::PauseProfiler();
CONVERT_CHECKED(Smi, smi_modules, args[0]);
CONVERT_CHECKED(Smi, smi_tag, args[1]);
v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
@ -12451,6 +12505,28 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
} }
#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
CONVERT_CHECKED(JSObject, obj, args[0]); \
return isolate->heap()->ToBoolean(obj->Has##Name()); \
}
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Implementation of Runtime // Implementation of Runtime

25
deps/v8/src/runtime.h

@ -334,7 +334,23 @@ namespace internal {
F(MessageGetScript, 1, 1) \ F(MessageGetScript, 1, 1) \
\ \
/* Pseudo functions - handled as macros by parser */ \ /* Pseudo functions - handled as macros by parser */ \
F(IS_VAR, 1, 1) F(IS_VAR, 1, 1) \
\
/* expose boolean functions from objects-inl.h */ \
F(HasFastElements, 1, 1) \
F(HasFastDoubleElements, 1, 1) \
F(HasDictionaryElements, 1, 1) \
F(HasExternalPixelElements, 1, 1) \
F(HasExternalArrayElements, 1, 1) \
F(HasExternalByteElements, 1, 1) \
F(HasExternalUnsignedByteElements, 1, 1) \
F(HasExternalShortElements, 1, 1) \
F(HasExternalUnsignedShortElements, 1, 1) \
F(HasExternalIntElements, 1, 1) \
F(HasExternalUnsignedIntElements, 1, 1) \
F(HasExternalFloatElements, 1, 1) \
F(HasExternalDoubleElements, 1, 1)
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
#define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) \ #define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) \
@ -413,8 +429,8 @@ namespace internal {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
#define RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F) \ #define RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F) \
F(ProfilerResume, 2, 1) \ F(ProfilerResume, 0, 1) \
F(ProfilerPause, 2, 1) F(ProfilerPause, 0, 1)
#else #else
#define RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F) #define RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F)
#endif #endif
@ -470,7 +486,8 @@ namespace internal {
F(IsRegExpEquivalent, 2, 1) \ F(IsRegExpEquivalent, 2, 1) \
F(HasCachedArrayIndex, 1, 1) \ F(HasCachedArrayIndex, 1, 1) \
F(GetCachedArrayIndex, 1, 1) \ F(GetCachedArrayIndex, 1, 1) \
F(FastAsciiArrayJoin, 2, 1) F(FastAsciiArrayJoin, 2, 1) \
F(IsNativeOrStrictMode, 1, 1)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

138
deps/v8/src/scopes.cc

@ -119,9 +119,9 @@ Scope::Scope(Type type)
temps_(0), temps_(0),
params_(0), params_(0),
unresolved_(0), unresolved_(0),
decls_(0) { decls_(0),
already_resolved_(false) {
SetDefaults(type, NULL, Handle<SerializedScopeInfo>::null()); SetDefaults(type, NULL, Handle<SerializedScopeInfo>::null());
ASSERT(!resolved());
} }
@ -131,14 +131,14 @@ Scope::Scope(Scope* outer_scope, Type type)
temps_(4), temps_(4),
params_(4), params_(4),
unresolved_(16), unresolved_(16),
decls_(4) { decls_(4),
already_resolved_(false) {
SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null()); SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null());
// At some point we might want to provide outer scopes to // At some point we might want to provide outer scopes to
// eval scopes (by walking the stack and reading the scope info). // eval scopes (by walking the stack and reading the scope info).
// In that case, the ASSERT below needs to be adjusted. // In that case, the ASSERT below needs to be adjusted.
ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL)); ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL));
ASSERT(!HasIllegalRedeclaration()); ASSERT(!HasIllegalRedeclaration());
ASSERT(!resolved());
} }
@ -148,15 +148,34 @@ Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info)
temps_(4), temps_(4),
params_(4), params_(4),
unresolved_(16), unresolved_(16),
decls_(4) { decls_(4),
already_resolved_(true) {
ASSERT(!scope_info.is_null()); ASSERT(!scope_info.is_null());
SetDefaults(FUNCTION_SCOPE, NULL, scope_info); SetDefaults(FUNCTION_SCOPE, NULL, scope_info);
ASSERT(resolved());
if (scope_info->HasHeapAllocatedLocals()) { if (scope_info->HasHeapAllocatedLocals()) {
num_heap_slots_ = scope_info_->NumberOfContextSlots(); num_heap_slots_ = scope_info_->NumberOfContextSlots();
} }
AddInnerScope(inner_scope);
}
Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name)
: inner_scopes_(1),
variables_(),
temps_(0),
params_(0),
unresolved_(0),
decls_(0),
already_resolved_(true) {
SetDefaults(CATCH_SCOPE, NULL, Handle<SerializedScopeInfo>::null());
AddInnerScope(inner_scope); AddInnerScope(inner_scope);
++num_var_or_const_;
Variable* variable = variables_.Declare(this,
catch_variable_name,
Variable::VAR,
true, // Valid left-hand side.
Variable::NORMAL);
AllocateHeapSlot(variable);
} }
@ -190,30 +209,43 @@ void Scope::SetDefaults(Type type,
Scope* Scope::DeserializeScopeChain(CompilationInfo* info, Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
Scope* global_scope) { Scope* global_scope) {
// Reconstruct the outer scope chain from a closure's context chain.
ASSERT(!info->closure().is_null()); ASSERT(!info->closure().is_null());
// If we have a serialized scope info, reuse it. Context* context = info->closure()->context();
Scope* current_scope = NULL;
Scope* innermost_scope = NULL; Scope* innermost_scope = NULL;
Scope* scope = NULL; bool contains_with = false;
while (!context->IsGlobalContext()) {
SerializedScopeInfo* scope_info = info->closure()->shared()->scope_info(); if (context->IsWithContext()) {
if (scope_info != SerializedScopeInfo::Empty()) { // All the inner scopes are inside a with.
JSFunction* current = *info->closure(); contains_with = true;
do { for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
current = current->context()->closure(); s->scope_inside_with_ = true;
Handle<SerializedScopeInfo> scope_info(current->shared()->scope_info()); }
if (*scope_info != SerializedScopeInfo::Empty()) { } else {
scope = new Scope(scope, scope_info); if (context->IsFunctionContext()) {
if (innermost_scope == NULL) innermost_scope = scope; SerializedScopeInfo* scope_info =
context->closure()->shared()->scope_info();
current_scope =
new Scope(current_scope, Handle<SerializedScopeInfo>(scope_info));
} else { } else {
ASSERT(current->context()->IsGlobalContext()); ASSERT(context->IsCatchContext());
String* name = String::cast(context->extension());
current_scope = new Scope(current_scope, Handle<String>(name));
} }
} while (!current->context()->IsGlobalContext()); if (contains_with) current_scope->RecordWithStatement();
if (innermost_scope == NULL) innermost_scope = current_scope;
} }
global_scope->AddInnerScope(scope); // Forget about a with when we move to a context for a different function.
if (innermost_scope == NULL) innermost_scope = global_scope; if (context->previous()->closure() != context->closure()) {
contains_with = false;
}
context = context->previous();
}
return innermost_scope; global_scope->AddInnerScope(current_scope);
return (innermost_scope == NULL) ? global_scope : innermost_scope;
} }
@ -238,7 +270,7 @@ bool Scope::Analyze(CompilationInfo* info) {
void Scope::Initialize(bool inside_with) { void Scope::Initialize(bool inside_with) {
ASSERT(!resolved()); ASSERT(!already_resolved());
// Add this scope as a new inner scope of the outer scope. // Add this scope as a new inner scope of the outer scope.
if (outer_scope_ != NULL) { if (outer_scope_ != NULL) {
@ -256,11 +288,16 @@ void Scope::Initialize(bool inside_with) {
// instead load them directly from the stack. Currently, the only // instead load them directly from the stack. Currently, the only
// such parameter is 'this' which is passed on the stack when // such parameter is 'this' which is passed on the stack when
// invoking scripts // invoking scripts
if (is_catch_scope()) {
ASSERT(outer_scope() != NULL);
receiver_ = outer_scope()->receiver();
} else {
Variable* var = Variable* var =
variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR, variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR,
false, Variable::THIS); false, Variable::THIS);
var->set_rewrite(new Slot(var, Slot::PARAMETER, -1)); var->set_rewrite(new Slot(var, Slot::PARAMETER, -1));
receiver_ = var; receiver_ = var;
}
if (is_function_scope()) { if (is_function_scope()) {
// Declare 'arguments' variable which exists in all functions. // Declare 'arguments' variable which exists in all functions.
@ -274,11 +311,10 @@ void Scope::Initialize(bool inside_with) {
Variable* Scope::LocalLookup(Handle<String> name) { Variable* Scope::LocalLookup(Handle<String> name) {
Variable* result = variables_.Lookup(name); Variable* result = variables_.Lookup(name);
if (result != NULL || !resolved()) { if (result != NULL || scope_info_.is_null()) {
return result; return result;
} }
// If the scope is resolved, we can find a variable in serialized scope // If we have a serialized scope info, we might find the variable there.
// info.
// //
// We should never lookup 'arguments' in this scope as it is implicitly // We should never lookup 'arguments' in this scope as it is implicitly
// present in every scope. // present in every scope.
@ -326,7 +362,7 @@ Variable* Scope::DeclareFunctionVar(Handle<String> name) {
void Scope::DeclareParameter(Handle<String> name) { void Scope::DeclareParameter(Handle<String> name) {
ASSERT(!resolved()); ASSERT(!already_resolved());
ASSERT(is_function_scope()); ASSERT(is_function_scope());
Variable* var = Variable* var =
variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL); variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL);
@ -335,7 +371,7 @@ void Scope::DeclareParameter(Handle<String> name) {
Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) { Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) {
ASSERT(!resolved()); ASSERT(!already_resolved());
// This function handles VAR and CONST modes. DYNAMIC variables are // This function handles VAR and CONST modes. DYNAMIC variables are
// introduces during variable allocation, INTERNAL variables are allocated // introduces during variable allocation, INTERNAL variables are allocated
// explicitly, and TEMPORARY variables are allocated via NewTemporary(). // explicitly, and TEMPORARY variables are allocated via NewTemporary().
@ -358,7 +394,7 @@ VariableProxy* Scope::NewUnresolved(Handle<String> name,
// Note that we must not share the unresolved variables with // Note that we must not share the unresolved variables with
// the same name because they may be removed selectively via // the same name because they may be removed selectively via
// RemoveUnresolved(). // RemoveUnresolved().
ASSERT(!resolved()); ASSERT(!already_resolved());
VariableProxy* proxy = new VariableProxy(name, false, inside_with, position); VariableProxy* proxy = new VariableProxy(name, false, inside_with, position);
unresolved_.Add(proxy); unresolved_.Add(proxy);
return proxy; return proxy;
@ -378,7 +414,7 @@ void Scope::RemoveUnresolved(VariableProxy* var) {
Variable* Scope::NewTemporary(Handle<String> name) { Variable* Scope::NewTemporary(Handle<String> name) {
ASSERT(!resolved()); ASSERT(!already_resolved());
Variable* var = Variable* var =
new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL); new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL);
temps_.Add(var); temps_.Add(var);
@ -508,12 +544,22 @@ int Scope::ContextChainLength(Scope* scope) {
} }
Scope* Scope::DeclarationScope() {
Scope* scope = this;
while (scope->is_catch_scope()) {
scope = scope->outer_scope();
}
return scope;
}
#ifdef DEBUG #ifdef DEBUG
static const char* Header(Scope::Type type) { static const char* Header(Scope::Type type) {
switch (type) { switch (type) {
case Scope::EVAL_SCOPE: return "eval"; case Scope::EVAL_SCOPE: return "eval";
case Scope::FUNCTION_SCOPE: return "function"; case Scope::FUNCTION_SCOPE: return "function";
case Scope::GLOBAL_SCOPE: return "global"; case Scope::GLOBAL_SCOPE: return "global";
case Scope::CATCH_SCOPE: return "catch";
} }
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
@ -864,8 +910,10 @@ bool Scope::MustAllocate(Variable* var) {
// visible name. // visible name.
if ((var->is_this() || var->name()->length() > 0) && if ((var->is_this() || var->name()->length() > 0) &&
(var->is_accessed_from_inner_scope() || (var->is_accessed_from_inner_scope() ||
scope_calls_eval_ || inner_scope_calls_eval_ || scope_calls_eval_ ||
scope_contains_with_)) { inner_scope_calls_eval_ ||
scope_contains_with_ ||
is_catch_scope())) {
var->set_is_used(true); var->set_is_used(true);
} }
// Global variables do not need to be allocated. // Global variables do not need to be allocated.
@ -874,16 +922,20 @@ bool Scope::MustAllocate(Variable* var) {
bool Scope::MustAllocateInContext(Variable* var) { bool Scope::MustAllocateInContext(Variable* var) {
// If var is accessed from an inner scope, or if there is a // If var is accessed from an inner scope, or if there is a possibility
// possibility that it might be accessed from the current or an inner // that it might be accessed from the current or an inner scope (through
// scope (through an eval() call), it must be allocated in the // an eval() call or a runtime with lookup), it must be allocated in the
// context. Exception: temporary variables are not allocated in the
// context. // context.
return //
var->mode() != Variable::TEMPORARY && // Exceptions: temporary variables are never allocated in a context;
(var->is_accessed_from_inner_scope() || // catch-bound variables are always allocated in a context.
scope_calls_eval_ || inner_scope_calls_eval_ || if (var->mode() == Variable::TEMPORARY) return false;
scope_contains_with_ || var->is_global()); if (is_catch_scope()) return true;
return var->is_accessed_from_inner_scope() ||
scope_calls_eval_ ||
inner_scope_calls_eval_ ||
scope_contains_with_ ||
var->is_global();
} }
@ -1010,7 +1062,7 @@ void Scope::AllocateVariablesRecursively() {
// If scope is already resolved, we still need to allocate // If scope is already resolved, we still need to allocate
// variables in inner scopes which might not had been resolved yet. // variables in inner scopes which might not had been resolved yet.
if (resolved()) return; if (already_resolved()) return;
// The number of slots required for variables. // The number of slots required for variables.
num_stack_slots_ = 0; num_stack_slots_ = 0;
num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;

31
deps/v8/src/scopes.h

@ -90,9 +90,10 @@ class Scope: public ZoneObject {
// Construction // Construction
enum Type { enum Type {
EVAL_SCOPE, // the top-level scope for an 'eval' source EVAL_SCOPE, // The top-level scope for an eval source.
FUNCTION_SCOPE, // the top-level scope for a function FUNCTION_SCOPE, // The top-level scope for a function.
GLOBAL_SCOPE // the top-level scope for a program or a top-level eval GLOBAL_SCOPE, // The top-level scope for a program or a top-level eval.
CATCH_SCOPE // The scope introduced by catch.
}; };
Scope(Scope* outer_scope, Type type); Scope(Scope* outer_scope, Type type);
@ -202,6 +203,7 @@ class Scope: public ZoneObject {
bool is_eval_scope() const { return type_ == EVAL_SCOPE; } bool is_eval_scope() const { return type_ == EVAL_SCOPE; }
bool is_function_scope() const { return type_ == FUNCTION_SCOPE; } bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
bool is_global_scope() const { return type_ == GLOBAL_SCOPE; } bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
bool is_catch_scope() const { return type_ == CATCH_SCOPE; }
bool is_strict_mode() const { return strict_mode_; } bool is_strict_mode() const { return strict_mode_; }
bool is_strict_mode_eval_scope() const { bool is_strict_mode_eval_scope() const {
return is_eval_scope() && is_strict_mode(); return is_eval_scope() && is_strict_mode();
@ -225,13 +227,8 @@ class Scope: public ZoneObject {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Accessors. // Accessors.
// A new variable proxy corresponding to the (function) receiver. // The variable corresponding the 'this' value.
VariableProxy* receiver() const { Variable* receiver() { return receiver_; }
VariableProxy* proxy =
new VariableProxy(FACTORY->this_symbol(), true, false);
proxy->BindTo(receiver_);
return proxy;
}
// The variable holding the function literal for named function // The variable holding the function literal for named function
// literals, or NULL. // literals, or NULL.
@ -293,6 +290,10 @@ class Scope: public ZoneObject {
// The number of contexts between this and scope; zero if this == scope. // The number of contexts between this and scope; zero if this == scope.
int ContextChainLength(Scope* scope); int ContextChainLength(Scope* scope);
// Find the first function, global, or eval scope. This is the scope
// where var declarations will be hoisted to in the implementation.
Scope* DeclarationScope();
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Strict mode support. // Strict mode support.
bool IsDeclared(Handle<String> name) { bool IsDeclared(Handle<String> name) {
@ -367,6 +368,10 @@ class Scope: public ZoneObject {
bool outer_scope_is_eval_scope_; bool outer_scope_is_eval_scope_;
bool force_eager_compilation_; bool force_eager_compilation_;
// True if it doesn't need scope resolution (e.g., if the scope was
// constructed based on a serialized scope info or a catch context).
bool already_resolved_;
// Computed as variables are declared. // Computed as variables are declared.
int num_var_or_const_; int num_var_or_const_;
@ -376,7 +381,7 @@ class Scope: public ZoneObject {
// Serialized scopes support. // Serialized scopes support.
Handle<SerializedScopeInfo> scope_info_; Handle<SerializedScopeInfo> scope_info_;
bool resolved() { return !scope_info_.is_null(); } bool already_resolved() { return already_resolved_; }
// Create a non-local variable with a given name. // Create a non-local variable with a given name.
// These variables are looked up dynamically at runtime. // These variables are looked up dynamically at runtime.
@ -412,8 +417,12 @@ class Scope: public ZoneObject {
void AllocateVariablesRecursively(); void AllocateVariablesRecursively();
private: private:
// Construct a function scope based on the scope info.
Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info); Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info);
// Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name);
void AddInnerScope(Scope* inner_scope) { void AddInnerScope(Scope* inner_scope) {
if (inner_scope != NULL) { if (inner_scope != NULL) {
inner_scopes_.Add(inner_scope); inner_scopes_.Add(inner_scope);

11
deps/v8/src/string.js

@ -251,7 +251,9 @@ function StringReplace(search, replace) {
// Compute the string to replace with. // Compute the string to replace with.
if (IS_FUNCTION(replace)) { if (IS_FUNCTION(replace)) {
builder.add(%_CallFunction(%GetGlobalReceiver(), var receiver =
%_IsNativeOrStrictMode(replace) ? void 0 : %GetGlobalReceiver();
builder.add(%_CallFunction(receiver,
search, search,
start, start,
subject, subject,
@ -418,7 +420,8 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) { if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
var match_start = 0; var match_start = 0;
var override = new InternalArray(null, 0, subject); var override = new InternalArray(null, 0, subject);
var receiver = %GetGlobalReceiver(); var receiver =
%_IsNativeOrStrictMode(replace) ? void 0 : %GetGlobalReceiver();
while (i < len) { while (i < len) {
var elem = res[i]; var elem = res[i];
if (%_IsSmi(elem)) { if (%_IsSmi(elem)) {
@ -475,8 +478,10 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
// No captures, only the match, which is always valid. // No captures, only the match, which is always valid.
var s = SubString(subject, index, endOfMatch); var s = SubString(subject, index, endOfMatch);
// Don't call directly to avoid exposing the built-in global object. // Don't call directly to avoid exposing the built-in global object.
var receiver =
%_IsNativeOrStrictMode(replace) ? void 0 : %GetGlobalReceiver();
replacement = replacement =
%_CallFunction(%GetGlobalReceiver(), s, index, subject, replace); %_CallFunction(receiver, s, index, subject, replace);
} else { } else {
var parameters = new InternalArray(m + 2); var parameters = new InternalArray(m + 2);
for (var j = 0; j < m; j++) { for (var j = 0; j < m; j++) {

4
deps/v8/src/stub-cache.cc

@ -1694,6 +1694,8 @@ MaybeObject* KeyedLoadStubCompiler::ComputeSharedKeyedLoadElementStub(
} else if (receiver_map->has_external_array_elements()) { } else if (receiver_map->has_external_array_elements()) {
JSObject::ElementsKind elements_kind = receiver_map->elements_kind(); JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
maybe_stub = KeyedLoadExternalArrayStub(elements_kind).TryGetCode(); maybe_stub = KeyedLoadExternalArrayStub(elements_kind).TryGetCode();
} else if (receiver_map->has_dictionary_elements()) {
maybe_stub = isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Slow);
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
@ -1746,6 +1748,8 @@ MaybeObject* KeyedStoreStubCompiler::ComputeSharedKeyedStoreElementStub(
} else if (receiver_map->has_external_array_elements()) { } else if (receiver_map->has_external_array_elements()) {
JSObject::ElementsKind elements_kind = receiver_map->elements_kind(); JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
maybe_stub = KeyedStoreExternalArrayStub(elements_kind).TryGetCode(); maybe_stub = KeyedStoreExternalArrayStub(elements_kind).TryGetCode();
} else if (receiver_map->has_dictionary_elements()) {
maybe_stub = isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Slow);
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }

1
deps/v8/src/type-info.cc

@ -122,6 +122,7 @@ bool TypeFeedbackOracle::StoreIsMegamorphicWithTypeInfo(Expression* expr) {
Builtins* builtins = Isolate::Current()->builtins(); Builtins* builtins = Isolate::Current()->builtins();
return code->is_keyed_store_stub() && return code->is_keyed_store_stub() &&
*code != builtins->builtin(Builtins::kKeyedStoreIC_Generic) && *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic) &&
*code != builtins->builtin(Builtins::kKeyedStoreIC_Generic_Strict) &&
code->ic_state() == MEGAMORPHIC; code->ic_state() == MEGAMORPHIC;
} }
return false; return false;

4
deps/v8/src/v8-counters.h

@ -170,14 +170,10 @@ namespace internal {
SC(named_load_inline_field, V8.NamedLoadInlineFast) \ SC(named_load_inline_field, V8.NamedLoadInlineFast) \
SC(keyed_load_inline_generic, V8.KeyedLoadInlineGeneric) \ SC(keyed_load_inline_generic, V8.KeyedLoadInlineGeneric) \
SC(keyed_load_inline_fast, V8.KeyedLoadInlineFast) \ SC(keyed_load_inline_fast, V8.KeyedLoadInlineFast) \
SC(named_load_full, V8.NamedLoadFull) \
SC(keyed_load_full, V8.KeyedLoadFull) \
SC(keyed_store_inline_generic, V8.KeyedStoreInlineGeneric) \ SC(keyed_store_inline_generic, V8.KeyedStoreInlineGeneric) \
SC(keyed_store_inline_fast, V8.KeyedStoreInlineFast) \ SC(keyed_store_inline_fast, V8.KeyedStoreInlineFast) \
SC(named_store_inline_generic, V8.NamedStoreInlineGeneric) \ SC(named_store_inline_generic, V8.NamedStoreInlineGeneric) \
SC(named_store_inline_fast, V8.NamedStoreInlineFast) \ SC(named_store_inline_fast, V8.NamedStoreInlineFast) \
SC(keyed_store_full, V8.KeyedStoreFull) \
SC(named_store_full, V8.NamedStoreFull) \
SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss) \ SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss) \
SC(named_store_global_inline, V8.NamedStoreGlobalInline) \ SC(named_store_global_inline, V8.NamedStoreGlobalInline) \
SC(named_store_global_inline_miss, V8.NamedStoreGlobalInlineMiss) \ SC(named_store_global_inline_miss, V8.NamedStoreGlobalInlineMiss) \

44
deps/v8/src/v8.cc

@ -100,42 +100,34 @@ void V8::TearDown() {
} }
static uint32_t random_seed() { static void seed_random(uint32_t* state) {
if (FLAG_random_seed == 0) { for (int i = 0; i < 2; ++i) {
return random(); state[i] = FLAG_random_seed;
while (state[i] == 0) {
state[i] = random();
}
} }
return FLAG_random_seed;
} }
typedef struct { // Random number generator using George Marsaglia's MWC algorithm.
uint32_t hi; static uint32_t random_base(uint32_t* state) {
uint32_t lo; // Initialize seed using the system random().
} random_state; // No non-zero seed will ever become zero again.
if (state[0] == 0) seed_random(state);
// Mix the bits. Never replaces state[i] with 0 if it is nonzero.
state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16);
state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16);
// Random number generator using George Marsaglia's MWC algorithm. return (state[0] << 14) + (state[1] & 0x3FFFF);
static uint32_t random_base(random_state *state) {
// Initialize seed using the system random(). If one of the seeds
// should ever become zero again, or if random() returns zero, we
// avoid getting stuck with zero bits in hi or lo by re-initializing
// them on demand.
if (state->hi == 0) state->hi = random_seed();
if (state->lo == 0) state->lo = random_seed();
// Mix the bits.
state->hi = 36969 * (state->hi & 0xFFFF) + (state->hi >> 16);
state->lo = 18273 * (state->lo & 0xFFFF) + (state->lo >> 16);
return (state->hi << 16) + (state->lo & 0xFFFF);
} }
// Used by JavaScript APIs // Used by JavaScript APIs
uint32_t V8::Random(Isolate* isolate) { uint32_t V8::Random(Isolate* isolate) {
ASSERT(isolate == Isolate::Current()); ASSERT(isolate == Isolate::Current());
// TODO(isolates): move lo and hi to isolate return random_base(isolate->random_seed());
static random_state state = {0, 0};
return random_base(&state);
} }
@ -144,9 +136,7 @@ uint32_t V8::Random(Isolate* isolate) {
// leaks that could be used in an exploit. // leaks that could be used in an exploit.
uint32_t V8::RandomPrivate(Isolate* isolate) { uint32_t V8::RandomPrivate(Isolate* isolate) {
ASSERT(isolate == Isolate::Current()); ASSERT(isolate == Isolate::Current());
// TODO(isolates): move lo and hi to isolate return random_base(isolate->private_random_seed());
static random_state state = {0, 0};
return random_base(&state);
} }

2
deps/v8/src/version.cc

@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script. // cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3 #define MAJOR_VERSION 3
#define MINOR_VERSION 4 #define MINOR_VERSION 4
#define BUILD_NUMBER 8 #define BUILD_NUMBER 9
#define PATCH_LEVEL 0 #define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise. // Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.) // (Boolean macro values are not supported by all preprocessors.)

6
deps/v8/src/x64/assembler-x64.h

@ -1168,7 +1168,7 @@ class Assembler : public AssemblerBase {
// Call near relative 32-bit displacement, relative to next instruction. // Call near relative 32-bit displacement, relative to next instruction.
void call(Label* L); void call(Label* L);
void call(Handle<Code> target, void call(Handle<Code> target,
RelocInfo::Mode rmode, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
unsigned ast_id = kNoASTId); unsigned ast_id = kNoASTId);
// Calls directly to the given address using a relative offset. // Calls directly to the given address using a relative offset.
@ -1350,7 +1350,9 @@ class Assembler : public AssemblerBase {
void Print(); void Print();
// Check the code size generated from label to here. // Check the code size generated from label to here.
int SizeOfCodeGeneratedSince(Label* l) { return pc_offset() - l->pos(); } int SizeOfCodeGeneratedSince(Label* label) {
return pc_offset() - label->pos();
}
// Mark address of the ExitJSFrame code. // Mark address of the ExitJSFrame code.
void RecordJSReturn(); void RecordJSReturn();

13
deps/v8/src/x64/code-stubs-x64.cc

@ -424,12 +424,10 @@ void UnaryOpStub::Generate(MacroAssembler* masm) {
void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
__ pop(rcx); // Save return address. __ pop(rcx); // Save return address.
__ push(rax);
// Left and right arguments are now on top. __ push(rax); // the operand
// Push this stub's key. Although the operation and the type info are
// encoded into the key, the encoding is opaque, so push them too.
__ Push(Smi::FromInt(MinorKey()));
__ Push(Smi::FromInt(op_)); __ Push(Smi::FromInt(op_));
__ Push(Smi::FromInt(mode_));
__ Push(Smi::FromInt(operand_type_)); __ Push(Smi::FromInt(operand_type_));
__ push(rcx); // Push return address. __ push(rcx); // Push return address.
@ -437,10 +435,7 @@ void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
// Patch the caller to an appropriate specialized stub and return the // Patch the caller to an appropriate specialized stub and return the
// operation result to the caller of the stub. // operation result to the caller of the stub.
__ TailCallExternalReference( __ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kUnaryOp_Patch), ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
masm->isolate()),
4,
1);
} }

16
deps/v8/src/x64/code-stubs-x64.h

@ -61,18 +61,11 @@ class TranscendentalCacheStub: public CodeStub {
class UnaryOpStub: public CodeStub { class UnaryOpStub: public CodeStub {
public: public:
UnaryOpStub(Token::Value op, UnaryOverwriteMode mode) UnaryOpStub(Token::Value op,
UnaryOverwriteMode mode,
UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
: op_(op), : op_(op),
mode_(mode), mode_(mode),
operand_type_(UnaryOpIC::UNINITIALIZED),
name_(NULL) {
}
UnaryOpStub(
int key,
UnaryOpIC::TypeInfo operand_type)
: op_(OpBits::decode(key)),
mode_(ModeBits::decode(key)),
operand_type_(operand_type), operand_type_(operand_type),
name_(NULL) { name_(NULL) {
} }
@ -90,8 +83,7 @@ class UnaryOpStub: public CodeStub {
#ifdef DEBUG #ifdef DEBUG
void Print() { void Print() {
PrintF("UnaryOpStub %d (op %s), " PrintF("UnaryOpStub %d (op %s), (mode %d, runtime_type_info %s)\n",
"(mode %d, runtime_type_info %s)\n",
MinorKey(), MinorKey(),
Token::String(op_), Token::String(op_),
static_cast<int>(mode_), static_cast<int>(mode_),

32
deps/v8/src/x64/deoptimizer-x64.cc

@ -316,7 +316,7 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
USE(height_in_bytes); USE(height_in_bytes);
unsigned fixed_size = ComputeFixedSize(function_); unsigned fixed_size = ComputeFixedSize(function_);
unsigned input_frame_size = static_cast<unsigned>(input_->GetFrameSize()); unsigned input_frame_size = input_->GetFrameSize();
ASSERT(fixed_size + height_in_bytes == input_frame_size); ASSERT(fixed_size + height_in_bytes == input_frame_size);
unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize; unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize;
@ -340,6 +340,9 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
output_ = new FrameDescription*[1]; output_ = new FrameDescription*[1];
output_[0] = new(output_frame_size) FrameDescription( output_[0] = new(output_frame_size) FrameDescription(
output_frame_size, function_); output_frame_size, function_);
#ifdef DEBUG
output_[0]->SetKind(Code::OPTIMIZED_FUNCTION);
#endif
// Clear the incoming parameters in the optimized frame to avoid // Clear the incoming parameters in the optimized frame to avoid
// confusing the garbage collector. // confusing the garbage collector.
@ -448,12 +451,15 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
// The 'fixed' part of the frame consists of the incoming parameters and // The 'fixed' part of the frame consists of the incoming parameters and
// the part described by JavaScriptFrameConstants. // the part described by JavaScriptFrameConstants.
unsigned fixed_frame_size = ComputeFixedSize(function); unsigned fixed_frame_size = ComputeFixedSize(function);
unsigned input_frame_size = static_cast<unsigned>(input_->GetFrameSize()); unsigned input_frame_size = input_->GetFrameSize();
unsigned output_frame_size = height_in_bytes + fixed_frame_size; unsigned output_frame_size = height_in_bytes + fixed_frame_size;
// Allocate and store the output frame description. // Allocate and store the output frame description.
FrameDescription* output_frame = FrameDescription* output_frame =
new(output_frame_size) FrameDescription(output_frame_size, function); new(output_frame_size) FrameDescription(output_frame_size, function);
#ifdef DEBUG
output_frame->SetKind(Code::FUNCTION);
#endif
bool is_bottommost = (0 == frame_index); bool is_bottommost = (0 == frame_index);
bool is_topmost = (output_count_ - 1 == frame_index); bool is_topmost = (output_count_ - 1 == frame_index);
@ -584,7 +590,7 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
output_frame->SetState(Smi::FromInt(state)); output_frame->SetState(Smi::FromInt(state));
// Set the continuation for the topmost frame. // Set the continuation for the topmost frame.
if (is_topmost) { if (is_topmost && bailout_type_ != DEBUGGER) {
Code* continuation = (bailout_type_ == EAGER) Code* continuation = (bailout_type_ == EAGER)
? isolate_->builtins()->builtin(Builtins::kNotifyDeoptimized) ? isolate_->builtins()->builtin(Builtins::kNotifyDeoptimized)
: isolate_->builtins()->builtin(Builtins::kNotifyLazyDeoptimized); : isolate_->builtins()->builtin(Builtins::kNotifyLazyDeoptimized);
@ -596,6 +602,26 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
} }
void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
// Set the register values. The values are not important as there are no
// callee saved registers in JavaScript frames, so all registers are
// spilled. Registers rbp and rsp are set to the correct values though.
for (int i = 0; i < Register::kNumRegisters; i++) {
input_->SetRegister(i, i * 4);
}
input_->SetRegister(rsp.code(), reinterpret_cast<intptr_t>(frame->sp()));
input_->SetRegister(rbp.code(), reinterpret_cast<intptr_t>(frame->fp()));
for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) {
input_->SetDoubleRegister(i, 0.0);
}
// Fill the frame content from the actual data on the frame.
for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
input_->SetFrameSlot(i, Memory::uint64_at(tos + i));
}
}
#define __ masm()-> #define __ masm()->
void Deoptimizer::EntryGenerator::Generate() { void Deoptimizer::EntryGenerator::Generate() {

191
deps/v8/src/x64/full-codegen-x64.cc

@ -78,15 +78,17 @@ class JumpPatchSite BASE_EMBEDDED {
} }
void EmitPatchInfo() { void EmitPatchInfo() {
if (patch_site_.is_bound()) {
int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
ASSERT(is_int8(delta_to_patch_site)); ASSERT(is_int8(delta_to_patch_site));
__ testl(rax, Immediate(delta_to_patch_site)); __ testl(rax, Immediate(delta_to_patch_site));
#ifdef DEBUG #ifdef DEBUG
info_emitted_ = true; info_emitted_ = true;
#endif #endif
} else {
__ nop(); // Signals no inlined code.
}
} }
bool is_bound() const { return patch_site_.is_bound(); }
private: private:
// jc will be patched with jz, jnc will become jnz. // jc will be patched with jz, jnc will become jnz.
@ -121,6 +123,7 @@ class JumpPatchSite BASE_EMBEDDED {
void FullCodeGenerator::Generate(CompilationInfo* info) { void FullCodeGenerator::Generate(CompilationInfo* info) {
ASSERT(info_ == NULL); ASSERT(info_ == NULL);
info_ = info; info_ = info;
scope_ = info->scope();
SetFunctionPosition(function()); SetFunctionPosition(function());
Comment cmnt(masm_, "[ function compiled by full code generator"); Comment cmnt(masm_, "[ function compiled by full code generator");
@ -140,7 +143,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ testq(rcx, rcx); __ testq(rcx, rcx);
__ j(zero, &ok, Label::kNear); __ j(zero, &ok, Label::kNear);
// +1 for return address. // +1 for return address.
int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
__ movq(Operand(rsp, receiver_offset), kScratchRegister); __ movq(Operand(rsp, receiver_offset), kScratchRegister);
__ bind(&ok); __ bind(&ok);
@ -152,7 +155,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ push(rdi); // Callee's JS Function. __ push(rdi); // Callee's JS Function.
{ Comment cmnt(masm_, "[ Allocate locals"); { Comment cmnt(masm_, "[ Allocate locals");
int locals_count = scope()->num_stack_slots(); int locals_count = info->scope()->num_stack_slots();
if (locals_count == 1) { if (locals_count == 1) {
__ PushRoot(Heap::kUndefinedValueRootIndex); __ PushRoot(Heap::kUndefinedValueRootIndex);
} else if (locals_count > 1) { } else if (locals_count > 1) {
@ -166,7 +169,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
bool function_in_register = true; bool function_in_register = true;
// Possibly allocate a local context. // Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
if (heap_slots > 0) { if (heap_slots > 0) {
Comment cmnt(masm_, "[ Allocate local context"); Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in rdi. // Argument to NewContext is the function, which is still in rdi.
@ -183,7 +186,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
// Copy any necessary parameters into the context. // Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters(); int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot(); Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (slot != NULL && slot->type() == Slot::CONTEXT) {
@ -215,11 +218,12 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
} }
// The receiver is just before the parameters on the caller's stack. // The receiver is just before the parameters on the caller's stack.
int offset = scope()->num_parameters() * kPointerSize; int num_parameters = info->scope()->num_parameters();
int offset = num_parameters * kPointerSize;
__ lea(rdx, __ lea(rdx,
Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
__ push(rdx); __ push(rdx);
__ Push(Smi::FromInt(scope()->num_parameters())); __ Push(Smi::FromInt(num_parameters));
// Arguments to ArgumentsAccessStub: // Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count. // function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous // The stub will rewrite receiver and parameter count if the previous
@ -332,7 +336,7 @@ void FullCodeGenerator::EmitReturnSequence() {
__ movq(rsp, rbp); __ movq(rsp, rbp);
__ pop(rbp); __ pop(rbp);
int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize; int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
__ Ret(arguments_bytes, rcx); __ Ret(arguments_bytes, rcx);
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
@ -749,7 +753,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ call(ic);
} }
} }
} }
@ -822,7 +826,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// Record position before stub call for type feedback. // Record position before stub call for type feedback.
SetSourcePosition(clause->position()); SetSourcePosition(clause->position());
Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
EmitCallIC(ic, &patch_site, clause->CompareId()); __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
patch_site.EmitPatchInfo();
__ testq(rax, rax); __ testq(rax, rax);
__ j(not_equal, &next_test); __ j(not_equal, &next_test);
@ -1128,7 +1133,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET ? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT; : RelocInfo::CODE_TARGET_CONTEXT;
EmitCallIC(ic, mode, AstNode::kNoNumber); __ call(ic, mode);
} }
@ -1208,7 +1213,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
__ Move(rax, key_literal->handle()); __ Move(rax, key_literal->handle());
Handle<Code> ic = Handle<Code> ic =
isolate()->builtins()->KeyedLoadIC_Initialize(); isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
__ jmp(done); __ jmp(done);
} }
} }
@ -1230,7 +1235,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
__ Move(rcx, var->name()); __ Move(rcx, var->name());
__ movq(rax, GlobalObjectOperand()); __ movq(rax, GlobalObjectOperand());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(rax); context()->Plug(rax);
} else if (slot != NULL && slot->type() == Slot::LOOKUP) { } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
@ -1378,7 +1383,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id()); __ call(ic, RelocInfo::CODE_TARGET, key->id());
PrepareForBailoutForId(key->id(), NO_REGISTERS); PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else { } else {
VisitForEffect(value); VisitForEffect(value);
@ -1607,14 +1612,14 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
Literal* key = prop->key()->AsLiteral(); Literal* key = prop->key()->AsLiteral();
__ Move(rcx, key->handle()); __ Move(rcx, key->handle());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
} }
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position()); SetSourcePosition(prop->position());
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
} }
@ -1636,7 +1641,8 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
__ bind(&stub_call); __ bind(&stub_call);
__ movq(rax, rcx); __ movq(rax, rcx);
BinaryOpStub stub(op, mode); BinaryOpStub stub(op, mode);
EmitCallIC(stub.GetCode(), &patch_site, expr->id()); __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
__ jmp(&done, Label::kNear); __ jmp(&done, Label::kNear);
__ bind(&smi_case); __ bind(&smi_case);
@ -1683,8 +1689,9 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
OverwriteMode mode) { OverwriteMode mode) {
__ pop(rdx); __ pop(rdx);
BinaryOpStub stub(op, mode); BinaryOpStub stub(op, mode);
// NULL signals no inlined smi code. JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
EmitCallIC(stub.GetCode(), NULL, expr->id()); __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
context()->Plug(rax); context()->Plug(rax);
} }
@ -1724,7 +1731,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ call(ic);
break; break;
} }
case KEYED_PROPERTY: { case KEYED_PROPERTY: {
@ -1737,7 +1744,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ call(ic);
break; break;
} }
} }
@ -1761,7 +1768,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) { } else if (op == Token::INIT_CONST) {
// Like var declarations, const declarations are hoisted to function // Like var declarations, const declarations are hoisted to function
@ -1854,7 +1861,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
// If the assignment ends an initialization block, revert to fast case. // If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) { if (expr->ends_initialization_block()) {
@ -1894,7 +1901,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
// If the assignment ends an initialization block, revert to fast case. // If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) { if (expr->ends_initialization_block()) {
@ -1946,7 +1953,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = Handle<Code> ic =
ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
EmitCallIC(ic, mode, expr->id()); __ call(ic, mode, expr->id());
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@ -1980,7 +1987,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Handle<Code> ic = Handle<Code> ic =
ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
__ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key. __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@ -2020,7 +2027,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
} }
// Push the receiver of the enclosing function and do runtime call. // Push the receiver of the enclosing function and do runtime call.
__ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); __ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize));
// Push the strict mode flag. // Push the strict mode flag.
__ Push(Smi::FromInt(strict_mode_flag())); __ Push(Smi::FromInt(strict_mode_flag()));
@ -2157,7 +2164,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else { } else {
// Call to a keyed property. // Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call, // For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed EmitCallIC. // for a regular property use EmitKeyedCallWithIC.
if (prop->is_synthetic()) { if (prop->is_synthetic()) {
// Do not visit the object and key subexpressions (they are shared // Do not visit the object and key subexpressions (they are shared
// by all occurrences of the same rewritten parameter). // by all occurrences of the same rewritten parameter).
@ -2175,7 +2182,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
SetSourcePosition(prop->position()); SetSourcePosition(prop->position());
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
// Push result (function). // Push result (function).
__ push(rax); __ push(rax);
// Push Global receiver. // Push Global receiver.
@ -2562,7 +2569,7 @@ void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
// parameter count in rax. // parameter count in rax.
VisitForAccumulatorValue(args->at(0)); VisitForAccumulatorValue(args->at(0));
__ movq(rdx, rax); __ movq(rdx, rax);
__ Move(rax, Smi::FromInt(scope()->num_parameters())); __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
__ CallStub(&stub); __ CallStub(&stub);
context()->Plug(rax); context()->Plug(rax);
@ -2574,7 +2581,7 @@ void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
Label exit; Label exit;
// Get the number of formal parameters. // Get the number of formal parameters.
__ Move(rax, Smi::FromInt(scope()->num_parameters())); __ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
// Check if the calling frame is an arguments adaptor frame. // Check if the calling frame is an arguments adaptor frame.
__ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
@ -3507,6 +3514,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
} }
void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
// Load the function into rax.
VisitForAccumulatorValue(args->at(0));
// Prepare for the test.
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
context()->PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Test for strict mode function.
__ movq(rdx, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
__ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
__ j(not_equal, if_true);
// Test for native function.
__ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset),
Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
__ j(not_equal, if_true);
// Not native or strict-mode function.
__ jmp(if_false);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
context()->Plug(if_true, if_false);
}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name(); Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') { if (name->length() > 0 && name->Get(0) == '_') {
@ -3537,7 +3577,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
RelocInfo::Mode mode = RelocInfo::CODE_TARGET; RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic = Handle<Code> ic =
ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
EmitCallIC(ic, mode, expr->id()); __ call(ic, mode, expr->id());
// Restore context register. // Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
} else { } else {
@ -3674,7 +3714,7 @@ void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
// accumulator register rax. // accumulator register rax.
VisitForAccumulatorValue(expr->expression()); VisitForAccumulatorValue(expr->expression());
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
EmitCallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
context()->Plug(rax); context()->Plug(rax);
} }
@ -3795,7 +3835,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ movq(rdx, rax); __ movq(rdx, rax);
__ Move(rax, Smi::FromInt(1)); __ Move(rax, Smi::FromInt(1));
} }
EmitCallIC(stub.GetCode(), &patch_site, expr->CountId()); __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
patch_site.EmitPatchInfo();
__ bind(&done); __ bind(&done);
// Store the value returned in rax. // Store the value returned in rax.
@ -3828,7 +3869,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict() ? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize(); : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
@ -3845,7 +3886,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
: isolate()->builtins()->KeyedStoreIC_Initialize(); : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
@ -3872,7 +3913,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference // Use a regular load, not a contextual load, to avoid a reference
// error. // error.
EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); __ call(ic);
PrepareForBailout(expr, TOS_REG); PrepareForBailout(expr, TOS_REG);
context()->Plug(rax); context()->Plug(rax);
} else if (proxy != NULL && } else if (proxy != NULL &&
@ -4067,7 +4108,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
// Record position and call the compare IC. // Record position and call the compare IC.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
Handle<Code> ic = CompareIC::GetUninitialized(op); Handle<Code> ic = CompareIC::GetUninitialized(op);
EmitCallIC(ic, &patch_site, expr->id()); __ call(ic, RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
__ testq(rax, rax); __ testq(rax, rax);
@ -4126,59 +4168,6 @@ Register FullCodeGenerator::context_register() {
} }
void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
RelocInfo::Mode mode,
unsigned ast_id) {
ASSERT(mode == RelocInfo::CODE_TARGET ||
mode == RelocInfo::CODE_TARGET_CONTEXT);
Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
__ IncrementCounter(counters->named_load_full(), 1);
break;
case Code::KEYED_LOAD_IC:
__ IncrementCounter(counters->keyed_load_full(), 1);
break;
case Code::STORE_IC:
__ IncrementCounter(counters->named_store_full(), 1);
break;
case Code::KEYED_STORE_IC:
__ IncrementCounter(counters->keyed_store_full(), 1);
default:
break;
}
__ call(ic, mode, ast_id);
}
void FullCodeGenerator::EmitCallIC(Handle<Code> ic,
JumpPatchSite* patch_site,
unsigned ast_id) {
Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
__ IncrementCounter(counters->named_load_full(), 1);
break;
case Code::KEYED_LOAD_IC:
__ IncrementCounter(counters->keyed_load_full(), 1);
break;
case Code::STORE_IC:
__ IncrementCounter(counters->named_store_full(), 1);
break;
case Code::KEYED_STORE_IC:
__ IncrementCounter(counters->keyed_store_full(), 1);
default:
break;
}
__ call(ic, RelocInfo::CODE_TARGET, ast_id);
if (patch_site != NULL && patch_site->is_bound()) {
patch_site->EmitPatchInfo();
} else {
__ nop(); // Signals no inlined code.
}
}
void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
ASSERT(IsAligned(frame_offset, kPointerSize)); ASSERT(IsAligned(frame_offset, kPointerSize));
__ movq(Operand(rbp, frame_offset), value); __ movq(Operand(rbp, frame_offset), value);
@ -4191,19 +4180,20 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
if (scope()->is_global_scope()) { Scope* declaration_scope = scope()->DeclarationScope();
if (declaration_scope->is_global_scope()) {
// Contexts nested in the global context have a canonical empty function // Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global // as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty // code. Pass a smi sentinel and let the runtime look up the empty
// function. // function.
__ Push(Smi::FromInt(0)); __ Push(Smi::FromInt(0));
} else if (scope()->is_eval_scope()) { } else if (declaration_scope->is_eval_scope()) {
// Contexts created by a call to eval have the same closure as the // Contexts created by a call to eval have the same closure as the
// context calling eval, not the anonymous closure containing the eval // context calling eval, not the anonymous closure containing the eval
// code. Fetch it from the context. // code. Fetch it from the context.
__ push(ContextOperand(rsi, Context::CLOSURE_INDEX)); __ push(ContextOperand(rsi, Context::CLOSURE_INDEX));
} else { } else {
ASSERT(scope()->is_function_scope()); ASSERT(declaration_scope->is_function_scope());
__ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
} }
} }
@ -4217,11 +4207,11 @@ void FullCodeGenerator::EnterFinallyBlock() {
ASSERT(!result_register().is(rdx)); ASSERT(!result_register().is(rdx));
ASSERT(!result_register().is(rcx)); ASSERT(!result_register().is(rcx));
// Cook return address on top of stack (smi encoded Code* delta) // Cook return address on top of stack (smi encoded Code* delta)
__ movq(rdx, Operand(rsp, 0)); __ pop(rdx);
__ Move(rcx, masm_->CodeObject()); __ Move(rcx, masm_->CodeObject());
__ subq(rdx, rcx); __ subq(rdx, rcx);
__ Integer32ToSmi(rdx, rdx); __ Integer32ToSmi(rdx, rdx);
__ movq(Operand(rsp, 0), rdx); __ push(rdx);
// Store result register while executing finally block. // Store result register while executing finally block.
__ push(result_register()); __ push(result_register());
} }
@ -4230,16 +4220,13 @@ void FullCodeGenerator::EnterFinallyBlock() {
void FullCodeGenerator::ExitFinallyBlock() { void FullCodeGenerator::ExitFinallyBlock() {
ASSERT(!result_register().is(rdx)); ASSERT(!result_register().is(rdx));
ASSERT(!result_register().is(rcx)); ASSERT(!result_register().is(rcx));
// Restore result register from stack.
__ pop(result_register()); __ pop(result_register());
// Uncook return address. // Uncook return address.
__ movq(rdx, Operand(rsp, 0)); __ pop(rdx);
__ SmiToInteger32(rdx, rdx); __ SmiToInteger32(rdx, rdx);
__ Move(rcx, masm_->CodeObject()); __ Move(rcx, masm_->CodeObject());
__ addq(rdx, rcx); __ addq(rdx, rcx);
__ movq(Operand(rsp, 0), rdx); __ jmp(rdx);
// And return.
__ ret(0);
} }

2
deps/v8/src/x64/ic-x64.cc

@ -1266,6 +1266,8 @@ static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
Register backing_store = parameter_map; Register backing_store = parameter_map;
__ movq(backing_store, FieldOperand(parameter_map, kBackingStoreOffset)); __ movq(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
__ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
__ movq(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset)); __ movq(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
__ cmpq(key, scratch); __ cmpq(key, scratch);
__ j(greater_equal, slow_case); __ j(greater_equal, slow_case);

260
deps/v8/src/x64/lithium-codegen-x64.cc

@ -1363,7 +1363,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id());
Representation r = instr->hydrogen()->representation(); Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32()) { if (r.IsInteger32()) {
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
__ testl(reg, reg); __ testl(reg, reg);
@ -1376,7 +1376,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
} else { } else {
ASSERT(r.IsTagged()); ASSERT(r.IsTagged());
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
HType type = instr->hydrogen()->type(); HType type = instr->hydrogen()->value()->type();
if (type.IsBoolean()) { if (type.IsBoolean()) {
__ CompareRoot(reg, Heap::kTrueValueRootIndex); __ CompareRoot(reg, Heap::kTrueValueRootIndex);
EmitBranch(true_block, false_block, equal); EmitBranch(true_block, false_block, equal);
@ -1483,32 +1483,6 @@ void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
} }
void LCodeGen::DoCmpID(LCmpID* instr) {
LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1);
LOperand* result = instr->result();
Label unordered;
if (instr->is_double()) {
// Don't base result on EFLAGS when a NaN is involved. Instead
// jump to the unordered case, which produces a false value.
__ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
__ j(parity_even, &unordered, Label::kNear);
} else {
EmitCmpI(left, right);
}
Label done;
Condition cc = TokenToCondition(instr->op(), instr->is_double());
__ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex);
__ j(cc, &done, Label::kNear);
__ bind(&unordered);
__ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
LOperand* left = instr->InputAt(0); LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1); LOperand* right = instr->InputAt(1);
@ -1529,22 +1503,6 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
} }
void LCodeGen::DoCmpObjectEq(LCmpObjectEq* instr) {
Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1));
Register result = ToRegister(instr->result());
Label different, done;
__ cmpq(left, right);
__ j(not_equal, &different, Label::kNear);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ jmp(&done, Label::kNear);
__ bind(&different);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
Register left = ToRegister(instr->InputAt(0)); Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1)); Register right = ToRegister(instr->InputAt(1));
@ -1556,19 +1514,6 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
} }
void LCodeGen::DoCmpConstantEq(LCmpConstantEq* instr) {
Register left = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label done;
__ cmpq(left, Immediate(instr->hydrogen()->right()));
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ j(equal, &done, Label::kNear);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
Register left = ToRegister(instr->InputAt(0)); Register left = ToRegister(instr->InputAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
@ -1579,50 +1524,6 @@ void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
} }
void LCodeGen::DoIsNull(LIsNull* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
// If the expression is known to be a smi, then it's
// definitely not null. Materialize false.
// Consider adding other type and representation tests too.
if (instr->hydrogen()->value()->type().IsSmi()) {
__ LoadRoot(result, Heap::kFalseValueRootIndex);
return;
}
__ CompareRoot(reg, Heap::kNullValueRootIndex);
if (instr->is_strict()) {
ASSERT(Heap::kTrueValueRootIndex >= 0);
__ movl(result, Immediate(Heap::kTrueValueRootIndex));
Label load;
__ j(equal, &load, Label::kNear);
__ Set(result, Heap::kFalseValueRootIndex);
__ bind(&load);
__ LoadRootIndexed(result, result, 0);
} else {
Label false_value, true_value, done;
__ j(equal, &true_value, Label::kNear);
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ j(equal, &true_value, Label::kNear);
__ JumpIfSmi(reg, &false_value, Label::kNear);
// Check for undetectable objects by looking in the bit field in
// the map. The object has already been smi checked.
Register scratch = result;
__ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
__ testb(FieldOperand(scratch, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, &true_value, Label::kNear);
__ bind(&false_value);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ jmp(&done, Label::kNear);
__ bind(&true_value);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
}
void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
@ -1685,25 +1586,6 @@ Condition LCodeGen::EmitIsObject(Register input,
} }
void LCodeGen::DoIsObject(LIsObject* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label is_false, is_true, done;
Condition true_cond = EmitIsObject(reg, &is_false, &is_true);
__ j(true_cond, &is_true);
__ bind(&is_false);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ jmp(&done);
__ bind(&is_true);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Register reg = ToRegister(instr->InputAt(0)); Register reg = ToRegister(instr->InputAt(0));
@ -1718,22 +1600,6 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
} }
void LCodeGen::DoIsSmi(LIsSmi* instr) {
LOperand* input_operand = instr->InputAt(0);
Register result = ToRegister(instr->result());
if (input_operand->IsRegister()) {
Register input = ToRegister(input_operand);
__ CheckSmiToIndicator(result, input);
} else {
Operand input = ToOperand(instr->InputAt(0));
__ CheckSmiToIndicator(result, input);
}
// result is zero if input is a smi, and one otherwise.
ASSERT(Heap::kFalseValueRootIndex == Heap::kTrueValueRootIndex + 1);
__ LoadRootIndexed(result, result, Heap::kTrueValueRootIndex);
}
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id());
@ -1750,25 +1616,6 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
} }
void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
Label false_label, done;
__ JumpIfSmi(input, &false_label);
__ movq(result, FieldOperand(input, HeapObject::kMapOffset));
__ testb(FieldOperand(result, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
__ j(zero, &false_label);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ jmp(&done);
__ bind(&false_label);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0)); Register temp = ToRegister(instr->TempAt(0));
@ -1784,7 +1631,7 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
} }
static InstanceType TestType(HHasInstanceType* instr) { static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from(); InstanceType from = instr->from();
InstanceType to = instr->to(); InstanceType to = instr->to();
if (from == FIRST_TYPE) return to; if (from == FIRST_TYPE) return to;
@ -1793,7 +1640,7 @@ static InstanceType TestType(HHasInstanceType* instr) {
} }
static Condition BranchCondition(HHasInstanceType* instr) { static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
InstanceType from = instr->from(); InstanceType from = instr->from();
InstanceType to = instr->to(); InstanceType to = instr->to();
if (from == to) return equal; if (from == to) return equal;
@ -1804,25 +1651,6 @@ static Condition BranchCondition(HHasInstanceType* instr) {
} }
void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
__ testl(input, Immediate(kSmiTagMask));
Label done, is_false;
__ j(zero, &is_false);
__ CmpObjectType(input, TestType(instr->hydrogen()), result);
__ j(NegateCondition(BranchCondition(instr->hydrogen())),
&is_false, Label::kNear);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ jmp(&done, Label::kNear);
__ bind(&is_false);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
@ -1852,21 +1680,6 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
} }
void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ testl(FieldOperand(input, String::kHashFieldOffset),
Immediate(String::kContainsCachedArrayIndexMask));
Label done;
__ j(zero, &done, Label::kNear);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoHasCachedArrayIndexAndBranch( void LCodeGen::DoHasCachedArrayIndexAndBranch(
LHasCachedArrayIndexAndBranch* instr) { LHasCachedArrayIndexAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
@ -1935,29 +1748,6 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
} }
void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(input.is(result));
Register temp = ToRegister(instr->TempAt(0));
Handle<String> class_name = instr->hydrogen()->class_name();
Label done;
Label is_true, is_false;
EmitClassOfTest(&is_true, &is_false, class_name, input, temp);
__ j(not_equal, &is_false);
__ bind(&is_true);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ jmp(&done, Label::kNear);
__ bind(&is_false);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0)); Register temp = ToRegister(instr->TempAt(0));
@ -4025,29 +3815,6 @@ void LCodeGen::DoTypeof(LTypeof* instr) {
} }
void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label true_label;
Label false_label;
Label done;
Condition final_branch_condition = EmitTypeofIs(&true_label,
&false_label,
input,
instr->type_literal());
__ j(final_branch_condition, &true_label);
__ bind(&false_label);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ jmp(&done, Label::kNear);
__ bind(&true_label);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
ASSERT(!operand->IsDoubleRegister()); ASSERT(!operand->IsDoubleRegister());
if (operand->IsConstantOperand()) { if (operand->IsConstantOperand()) {
@ -4139,25 +3906,6 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
} }
void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
Register result = ToRegister(instr->result());
Label true_label;
Label done;
EmitIsConstructCall(result);
__ j(equal, &true_label, Label::kNear);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ jmp(&done, Label::kNear);
__ bind(&true_label);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
Register temp = ToRegister(instr->TempAt(0)); Register temp = ToRegister(instr->TempAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id());

197
deps/v8/src/x64/lithium-x64.cc

@ -267,12 +267,6 @@ void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
} }
void LTypeofIs::PrintDataTo(StringStream* stream) {
InputAt(0)->PrintTo(stream);
stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
}
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if typeof "); stream->Add("if typeof ");
InputAt(0)->PrintTo(stream); InputAt(0)->PrintTo(stream);
@ -342,13 +336,6 @@ void LCallNew::PrintDataTo(StringStream* stream) {
} }
void LClassOfTest::PrintDataTo(StringStream* stream) {
stream->Add("= class_of_test(");
InputAt(0)->PrintTo(stream);
stream->Add(", \"%o\")", *hydrogen()->class_name());
}
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
arguments()->PrintTo(stream); arguments()->PrintTo(stream);
@ -985,18 +972,7 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
if (FLAG_stress_environments && !instr->HasEnvironment()) { if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr); instr = AssignEnvironment(instr);
} }
if (current->IsTest() && !instr->IsGoto()) {
ASSERT(instr->IsControl());
HTest* test = HTest::cast(current);
instr->set_hydrogen_value(test->value());
HBasicBlock* first = test->FirstSuccessor();
HBasicBlock* second = test->SecondSuccessor();
ASSERT(first != NULL && second != NULL);
instr->SetBranchTargets(first->block_id(), second->block_id());
} else {
instr->set_hydrogen_value(current); instr->set_hydrogen_value(current);
}
chunk_->AddInstruction(instr, current_block_); chunk_->AddInstruction(instr, current_block_);
} }
current_instruction_ = old_current; current_instruction_ = old_current;
@ -1041,81 +1017,17 @@ LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
} }
LInstruction* LChunkBuilder::DoTest(HTest* instr) { LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* v = instr->value(); HValue* v = instr->value();
if (!v->EmitAtUses()) return new LBranch(UseRegisterAtStart(v)); if (v->EmitAtUses()) {
ASSERT(!v->HasSideEffects()); ASSERT(v->IsConstant());
if (v->IsClassOfTest()) { ASSERT(!v->representation().IsDouble());
HClassOfTest* compare = HClassOfTest::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
TempRegister());
} else if (v->IsCompare()) {
HCompare* compare = HCompare::cast(v);
HValue* left = compare->left();
HValue* right = compare->right();
Representation r = compare->GetInputRepresentation();
if (r.IsInteger32()) {
ASSERT(left->representation().IsInteger32());
ASSERT(right->representation().IsInteger32());
return new LCmpIDAndBranch(UseRegisterAtStart(left),
UseOrConstantAtStart(right));
} else {
ASSERT(r.IsDouble());
ASSERT(left->representation().IsDouble());
ASSERT(right->representation().IsDouble());
return new LCmpIDAndBranch(UseRegisterAtStart(left),
UseRegisterAtStart(right));
}
} else if (v->IsIsSmi()) {
HIsSmi* compare = HIsSmi::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LIsSmiAndBranch(Use(compare->value()));
} else if (v->IsIsUndetectable()) {
HIsUndetectable* compare = HIsUndetectable::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()),
TempRegister());
} else if (v->IsHasInstanceType()) {
HHasInstanceType* compare = HHasInstanceType::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsHasCachedArrayIndex()) {
HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LHasCachedArrayIndexAndBranch(
UseRegisterAtStart(compare->value()));
} else if (v->IsIsNull()) {
HIsNull* compare = HIsNull::cast(v);
ASSERT(compare->value()->representation().IsTagged());
// We only need a temp register for non-strict compare.
LOperand* temp = compare->is_strict() ? NULL : TempRegister();
return new LIsNullAndBranch(UseRegisterAtStart(compare->value()), temp);
} else if (v->IsIsObject()) {
HIsObject* compare = HIsObject::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsCompareObjectEq()) {
HCompareObjectEq* compare = HCompareObjectEq::cast(v);
return new LCmpObjectEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
} else if (v->IsCompareConstantEq()) {
HCompareConstantEq* compare = HCompareConstantEq::cast(v);
return new LCmpConstantEqAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
} else if (v->IsIsConstructCall()) {
return new LIsConstructCallAndBranch(TempRegister());
} else if (v->IsConstant()) {
HBasicBlock* successor = HConstant::cast(v)->ToBoolean() HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
? instr->FirstSuccessor() ? instr->FirstSuccessor()
: instr->SecondSuccessor(); : instr->SecondSuccessor();
return new LGoto(successor->block_id()); return new LGoto(successor->block_id());
} else {
Abort("Undefined compare before branch");
return NULL;
} }
return new LBranch(UseRegisterAtStart(v));
} }
@ -1468,85 +1380,83 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
} }
LInstruction* LChunkBuilder::DoCompare(HCompare* instr) { LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
Token::Value op = instr->token(); Token::Value op = instr->token();
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
bool reversed = (op == Token::GT || op == Token::LTE);
LOperand* left = UseFixed(instr->left(), reversed ? rax : rdx);
LOperand* right = UseFixed(instr->right(), reversed ? rdx : rax);
LCmpT* result = new LCmpT(left, right);
return MarkAsCall(DefineFixed(result, rax), instr);
}
LInstruction* LChunkBuilder::DoCompareIDAndBranch(
HCompareIDAndBranch* instr) {
Representation r = instr->GetInputRepresentation(); Representation r = instr->GetInputRepresentation();
if (r.IsInteger32()) { if (r.IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32());
LOperand* left = UseRegisterAtStart(instr->left()); LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right()); LOperand* right = UseOrConstantAtStart(instr->right());
return DefineAsRegister(new LCmpID(left, right)); return new LCmpIDAndBranch(left, right);
} else if (r.IsDouble()) { } else {
ASSERT(r.IsDouble());
ASSERT(instr->left()->representation().IsDouble()); ASSERT(instr->left()->representation().IsDouble());
ASSERT(instr->right()->representation().IsDouble()); ASSERT(instr->right()->representation().IsDouble());
LOperand* left = UseRegisterAtStart(instr->left()); LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right()); LOperand* right = UseRegisterAtStart(instr->right());
return DefineAsRegister(new LCmpID(left, right)); return new LCmpIDAndBranch(left, right);
} else {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
bool reversed = (op == Token::GT || op == Token::LTE);
LOperand* left = UseFixed(instr->left(), reversed ? rax : rdx);
LOperand* right = UseFixed(instr->right(), reversed ? rdx : rax);
LCmpT* result = new LCmpT(left, right);
return MarkAsCall(DefineFixed(result, rax), instr);
} }
} }
LInstruction* LChunkBuilder::DoCompareObjectEq(HCompareObjectEq* instr) { LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
HCompareObjectEqAndBranch* instr) {
LOperand* left = UseRegisterAtStart(instr->left()); LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right()); LOperand* right = UseRegisterAtStart(instr->right());
LCmpObjectEq* result = new LCmpObjectEq(left, right); return new LCmpObjectEqAndBranch(left, right);
return DefineAsRegister(result);
} }
LInstruction* LChunkBuilder::DoCompareConstantEq( LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch(
HCompareConstantEq* instr) { HCompareConstantEqAndBranch* instr) {
LOperand* left = UseRegisterAtStart(instr->value()); return new LCmpConstantEqAndBranch(UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LCmpConstantEq(left));
} }
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) { LInstruction* LChunkBuilder::DoIsNullAndBranch(HIsNullAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value()); LOperand* temp = instr->is_strict() ? NULL : TempRegister();
return new LIsNullAndBranch(UseRegisterAtStart(instr->value()), temp);
return DefineAsRegister(new LIsNull(value));
} }
LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) { LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegister(instr->value()); return new LIsObjectAndBranch(UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LIsObject(value));
} }
LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseAtStart(instr->value()); return new LIsSmiAndBranch(Use(instr->value()));
return DefineAsRegister(new LIsSmi(value));
} }
LInstruction* LChunkBuilder::DoIsUndetectable(HIsUndetectable* instr) { LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
HIsUndetectableAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value()); return new LIsUndetectableAndBranch(UseRegisterAtStart(instr->value()),
TempRegister());
return DefineAsRegister(new LIsUndetectable(value));
} }
LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) { LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
HHasInstanceTypeAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value()); return new LHasInstanceTypeAndBranch(UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LHasInstanceType(value));
} }
@ -1559,17 +1469,17 @@ LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
} }
LInstruction* LChunkBuilder::DoHasCachedArrayIndex( LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
HHasCachedArrayIndex* instr) { HHasCachedArrayIndexAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegister(instr->value()); return new LHasCachedArrayIndexAndBranch(UseRegisterAtStart(instr->value()));
return DefineAsRegister(new LHasCachedArrayIndex(value));
} }
LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) { LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
Abort("Unimplemented: %s", "DoClassOfTest"); HClassOfTestAndBranch* instr) {
return NULL; return new LClassOfTestAndBranch(UseTempRegister(instr->value()),
TempRegister());
} }
@ -2152,13 +2062,14 @@ LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
} }
LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) { LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value()))); return new LTypeofIsAndBranch(UseTempRegister(instr->value()));
} }
LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) { LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
return DefineAsRegister(new LIsConstructCall); HIsConstructCallAndBranch* instr) {
return new LIsConstructCallAndBranch(TempRegister());
} }

190
deps/v8/src/x64/lithium-x64.h

@ -77,13 +77,9 @@ class LCodeGen;
V(ClampDToUint8) \ V(ClampDToUint8) \
V(ClampIToUint8) \ V(ClampIToUint8) \
V(ClampTToUint8) \ V(ClampTToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \ V(ClassOfTestAndBranch) \
V(CmpConstantEq) \
V(CmpConstantEqAndBranch) \ V(CmpConstantEqAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \ V(CmpIDAndBranch) \
V(CmpObjectEq) \
V(CmpObjectEqAndBranch) \ V(CmpObjectEqAndBranch) \
V(CmpMapAndBranch) \ V(CmpMapAndBranch) \
V(CmpT) \ V(CmpT) \
@ -103,9 +99,7 @@ class LCodeGen;
V(GlobalObject) \ V(GlobalObject) \
V(GlobalReceiver) \ V(GlobalReceiver) \
V(Goto) \ V(Goto) \
V(HasCachedArrayIndex) \
V(HasCachedArrayIndexAndBranch) \ V(HasCachedArrayIndexAndBranch) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \ V(HasInstanceTypeAndBranch) \
V(In) \ V(In) \
V(InstanceOf) \ V(InstanceOf) \
@ -113,15 +107,10 @@ class LCodeGen;
V(InstructionGap) \ V(InstructionGap) \
V(Integer32ToDouble) \ V(Integer32ToDouble) \
V(InvokeFunction) \ V(InvokeFunction) \
V(IsConstructCall) \
V(IsConstructCallAndBranch) \ V(IsConstructCallAndBranch) \
V(IsNull) \
V(IsNullAndBranch) \ V(IsNullAndBranch) \
V(IsObject) \
V(IsObjectAndBranch) \ V(IsObjectAndBranch) \
V(IsSmi) \
V(IsSmiAndBranch) \ V(IsSmiAndBranch) \
V(IsUndetectable) \
V(IsUndetectableAndBranch) \ V(IsUndetectableAndBranch) \
V(JSArrayLength) \ V(JSArrayLength) \
V(Label) \ V(Label) \
@ -173,7 +162,6 @@ class LCodeGen;
V(Throw) \ V(Throw) \
V(ToFastProperties) \ V(ToFastProperties) \
V(Typeof) \ V(Typeof) \
V(TypeofIs) \
V(TypeofIsAndBranch) \ V(TypeofIsAndBranch) \
V(UnaryMathOperation) \ V(UnaryMathOperation) \
V(UnknownOSRValue) \ V(UnknownOSRValue) \
@ -233,7 +221,6 @@ class LInstruction: public ZoneObject {
virtual bool IsGap() const { return false; } virtual bool IsGap() const { return false; }
virtual bool IsControl() const { return false; } virtual bool IsControl() const { return false; }
virtual void SetBranchTargets(int true_block_id, int false_block_id) { }
void set_environment(LEnvironment* env) { environment_ = env; } void set_environment(LEnvironment* env) { environment_ = env; }
LEnvironment* environment() const { return environment_; } LEnvironment* environment() const { return environment_; }
@ -457,16 +444,15 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> {
public: public:
virtual bool IsControl() const { return true; } virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; } int SuccessorCount() { return hydrogen()->SuccessorCount(); }
int false_block_id() const { return false_block_id_; } HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
void SetBranchTargets(int true_block_id, int false_block_id) { int true_block_id() { return hydrogen()->SuccessorAt(0)->block_id(); }
true_block_id_ = true_block_id; int false_block_id() { return hydrogen()->SuccessorAt(1)->block_id(); }
false_block_id_ = false_block_id;
}
private: private:
int true_block_id_; HControlInstruction* hydrogen() {
int false_block_id_; return HControlInstruction::cast(this->hydrogen_value());
}
}; };
@ -565,23 +551,6 @@ class LMulI: public LTemplateInstruction<1, 2, 0> {
}; };
class LCmpID: public LTemplateInstruction<1, 2, 0> {
public:
LCmpID(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
DECLARE_CONCRETE_INSTRUCTION(CmpID, "cmp-id")
DECLARE_HYDROGEN_ACCESSOR(Compare)
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const {
return hydrogen()->GetInputRepresentation().IsDouble();
}
};
class LCmpIDAndBranch: public LControlInstruction<2, 0> { class LCmpIDAndBranch: public LControlInstruction<2, 0> {
public: public:
LCmpIDAndBranch(LOperand* left, LOperand* right) { LCmpIDAndBranch(LOperand* left, LOperand* right) {
@ -590,7 +559,7 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch") DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
DECLARE_HYDROGEN_ACCESSOR(Compare) DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch)
Token::Value op() const { return hydrogen()->token(); } Token::Value op() const { return hydrogen()->token(); }
bool is_double() const { bool is_double() const {
@ -615,17 +584,6 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 0> {
}; };
class LCmpObjectEq: public LTemplateInstruction<1, 2, 0> {
public:
LCmpObjectEq(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
DECLARE_CONCRETE_INSTRUCTION(CmpObjectEq, "cmp-object-eq")
};
class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
public: public:
LCmpObjectEqAndBranch(LOperand* left, LOperand* right) { LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
@ -638,17 +596,6 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
}; };
class LCmpConstantEq: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCmpConstantEq(LOperand* left) {
inputs_[0] = left;
}
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEq, "cmp-constant-eq")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
};
class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> { class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LCmpConstantEqAndBranch(LOperand* left) { explicit LCmpConstantEqAndBranch(LOperand* left) {
@ -657,20 +604,7 @@ class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch, DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
"cmp-constant-eq-and-branch") "cmp-constant-eq-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq) DECLARE_HYDROGEN_ACCESSOR(CompareConstantEqAndBranch)
};
class LIsNull: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsNull(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsNull, "is-null")
DECLARE_HYDROGEN_ACCESSOR(IsNull)
bool is_strict() const { return hydrogen()->is_strict(); }
}; };
@ -682,7 +616,7 @@ class LIsNullAndBranch: public LControlInstruction<1, 1> {
} }
DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsNull) DECLARE_HYDROGEN_ACCESSOR(IsNullAndBranch)
bool is_strict() const { return hydrogen()->is_strict(); } bool is_strict() const { return hydrogen()->is_strict(); }
@ -690,16 +624,6 @@ class LIsNullAndBranch: public LControlInstruction<1, 1> {
}; };
class LIsObject: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsObject(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object")
};
class LIsObjectAndBranch: public LControlInstruction<1, 0> { class LIsObjectAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LIsObjectAndBranch(LOperand* value) { explicit LIsObjectAndBranch(LOperand* value) {
@ -707,22 +631,12 @@ class LIsObjectAndBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
class LIsSmi: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsSmi(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is-smi")
DECLARE_HYDROGEN_ACCESSOR(IsSmi)
};
class LIsSmiAndBranch: public LControlInstruction<1, 0> { class LIsSmiAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LIsSmiAndBranch(LOperand* value) { explicit LIsSmiAndBranch(LOperand* value) {
@ -730,22 +644,12 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
class LIsUndetectable: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsUndetectable(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(IsUndetectable, "is-undetectable")
DECLARE_HYDROGEN_ACCESSOR(IsUndetectable)
};
class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { class LIsUndetectableAndBranch: public LControlInstruction<1, 1> {
public: public:
explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) { explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) {
@ -755,22 +659,12 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> {
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch,
"is-undetectable-and-branch") "is-undetectable-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
class LHasInstanceType: public LTemplateInstruction<1, 1, 0> {
public:
explicit LHasInstanceType(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(HasInstanceType, "has-instance-type")
DECLARE_HYDROGEN_ACCESSOR(HasInstanceType)
};
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> { class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LHasInstanceTypeAndBranch(LOperand* value) { explicit LHasInstanceTypeAndBranch(LOperand* value) {
@ -779,7 +673,7 @@ class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch, DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
"has-instance-type-and-branch") "has-instance-type-and-branch")
DECLARE_HYDROGEN_ACCESSOR(HasInstanceType) DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -796,17 +690,6 @@ class LGetCachedArrayIndex: public LTemplateInstruction<1, 1, 0> {
}; };
class LHasCachedArrayIndex: public LTemplateInstruction<1, 1, 0> {
public:
explicit LHasCachedArrayIndex(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has-cached-array-index")
DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndex)
};
class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> { class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LHasCachedArrayIndexAndBranch(LOperand* value) { explicit LHasCachedArrayIndexAndBranch(LOperand* value) {
@ -815,19 +698,7 @@ class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> {
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch, DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
"has-cached-array-index-and-branch") "has-cached-array-index-and-branch")
virtual void PrintDataTo(StringStream* stream); DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
};
class LClassOfTest: public LTemplateInstruction<1, 1, 1> {
public:
LClassOfTest(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTest)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -842,7 +713,7 @@ class LClassOfTestAndBranch: public LControlInstruction<1, 1> {
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch,
"class-of-test-and-branch") "class-of-test-and-branch")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTest) DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -856,7 +727,7 @@ class LCmpT: public LTemplateInstruction<1, 2, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t") DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
DECLARE_HYDROGEN_ACCESSOR(Compare) DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
Token::Value op() const { return hydrogen()->token(); } Token::Value op() const { return hydrogen()->token(); }
}; };
@ -1002,7 +873,7 @@ class LBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
DECLARE_HYDROGEN_ACCESSOR(Value) DECLARE_HYDROGEN_ACCESSOR(Branch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -1972,21 +1843,6 @@ class LTypeof: public LTemplateInstruction<1, 1, 0> {
}; };
class LTypeofIs: public LTemplateInstruction<1, 1, 0> {
public:
explicit LTypeofIs(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(TypeofIs, "typeof-is")
DECLARE_HYDROGEN_ACCESSOR(TypeofIs)
Handle<String> type_literal() { return hydrogen()->type_literal(); }
virtual void PrintDataTo(StringStream* stream);
};
class LTypeofIsAndBranch: public LControlInstruction<1, 0> { class LTypeofIsAndBranch: public LControlInstruction<1, 0> {
public: public:
explicit LTypeofIsAndBranch(LOperand* value) { explicit LTypeofIsAndBranch(LOperand* value) {
@ -1994,7 +1850,7 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> {
} }
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch") DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch")
DECLARE_HYDROGEN_ACCESSOR(TypeofIs) DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch)
Handle<String> type_literal() { return hydrogen()->type_literal(); } Handle<String> type_literal() { return hydrogen()->type_literal(); }
@ -2002,13 +1858,6 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> {
}; };
class LIsConstructCall: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(IsConstructCall, "is-construct-call")
DECLARE_HYDROGEN_ACCESSOR(IsConstructCall)
};
class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { class LIsConstructCallAndBranch: public LControlInstruction<0, 1> {
public: public:
explicit LIsConstructCallAndBranch(LOperand* temp) { explicit LIsConstructCallAndBranch(LOperand* temp) {
@ -2017,6 +1866,7 @@ class LIsConstructCallAndBranch: public LControlInstruction<0, 1> {
DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch, DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch,
"is-construct-call-and-branch") "is-construct-call-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsConstructCallAndBranch)
}; };

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

Loading…
Cancel
Save