Browse Source

upgrade v8 to 2.0.3

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
c8b6ef248e
  1. 25
      deps/v8/ChangeLog
  2. 24
      deps/v8/SConstruct
  3. 20
      deps/v8/include/v8.h
  4. 4
      deps/v8/src/SConscript
  5. 70
      deps/v8/src/accessors.cc
  6. 10
      deps/v8/src/accessors.h
  7. 46
      deps/v8/src/api.cc
  8. 1
      deps/v8/src/arm/assembler-arm.h
  9. 131
      deps/v8/src/arm/codegen-arm.cc
  10. 3
      deps/v8/src/arm/codegen-arm.h
  11. 27
      deps/v8/src/arm/constants-arm.h
  12. 2
      deps/v8/src/arm/debug-arm.cc
  13. 316
      deps/v8/src/arm/fast-codegen-arm.cc
  14. 13
      deps/v8/src/arm/ic-arm.cc
  15. 52
      deps/v8/src/arm/macro-assembler-arm.cc
  16. 7
      deps/v8/src/arm/macro-assembler-arm.h
  17. 5
      deps/v8/src/arm/stub-cache-arm.cc
  18. 36
      deps/v8/src/array.js
  19. 1
      deps/v8/src/ast.h
  20. 26
      deps/v8/src/bootstrapper.cc
  21. 1
      deps/v8/src/code-stubs.h
  22. 1
      deps/v8/src/codegen.cc
  23. 50
      deps/v8/src/compiler.cc
  24. 8
      deps/v8/src/d8.cc
  25. 21
      deps/v8/src/debug-delay.js
  26. 11
      deps/v8/src/debug.h
  27. 8
      deps/v8/src/dtoa-config.c
  28. 5
      deps/v8/src/factory.cc
  29. 37
      deps/v8/src/fast-codegen.cc
  30. 13
      deps/v8/src/fast-codegen.h
  31. 8
      deps/v8/src/flag-definitions.h
  32. 20
      deps/v8/src/global-handles.cc
  33. 2
      deps/v8/src/global-handles.h
  34. 48
      deps/v8/src/handles.cc
  35. 3
      deps/v8/src/handles.h
  36. 4
      deps/v8/src/heap-inl.h
  37. 193
      deps/v8/src/heap.cc
  38. 95
      deps/v8/src/heap.h
  39. 2
      deps/v8/src/ia32/assembler-ia32.h
  40. 312
      deps/v8/src/ia32/codegen-ia32.cc
  41. 34
      deps/v8/src/ia32/codegen-ia32.h
  42. 8
      deps/v8/src/ia32/debug-ia32.cc
  43. 319
      deps/v8/src/ia32/fast-codegen-ia32.cc
  44. 39
      deps/v8/src/ia32/ic-ia32.cc
  45. 145
      deps/v8/src/ia32/macro-assembler-ia32.cc
  46. 39
      deps/v8/src/ia32/macro-assembler-ia32.h
  47. 10
      deps/v8/src/ia32/stub-cache-ia32.cc
  48. 60
      deps/v8/src/log.cc
  49. 9
      deps/v8/src/log.h
  50. 65
      deps/v8/src/messages.js
  51. 24
      deps/v8/src/mirror-delay.js
  52. 65
      deps/v8/src/objects-debug.cc
  53. 152
      deps/v8/src/objects-inl.h
  54. 132
      deps/v8/src/objects.cc
  55. 506
      deps/v8/src/objects.h
  56. 5
      deps/v8/src/platform-freebsd.cc
  57. 5
      deps/v8/src/platform-linux.cc
  58. 5
      deps/v8/src/platform-macos.cc
  59. 597
      deps/v8/src/platform-openbsd.cc
  60. 9
      deps/v8/src/platform-posix.cc
  61. 124
      deps/v8/src/runtime.cc
  62. 11
      deps/v8/src/runtime.h
  63. 10
      deps/v8/src/runtime.js
  64. 87
      deps/v8/src/serialize.cc
  65. 2
      deps/v8/src/string-stream.cc
  66. 6
      deps/v8/src/stub-cache.cc
  67. 4
      deps/v8/src/stub-cache.h
  68. 9
      deps/v8/src/utils.cc
  69. 3
      deps/v8/src/utils.h
  70. 5
      deps/v8/src/v8-counters.h
  71. 2
      deps/v8/src/version.cc
  72. 6
      deps/v8/src/x64/assembler-x64.h
  73. 127
      deps/v8/src/x64/codegen-x64.cc
  74. 3
      deps/v8/src/x64/codegen-x64.h
  75. 7
      deps/v8/src/x64/debug-x64.cc
  76. 325
      deps/v8/src/x64/fast-codegen-x64.cc
  77. 39
      deps/v8/src/x64/ic-x64.cc
  78. 34
      deps/v8/src/x64/macro-assembler-x64.cc
  79. 9
      deps/v8/src/x64/macro-assembler-x64.h
  80. 8
      deps/v8/src/x64/stub-cache-x64.cc
  81. 4
      deps/v8/test/cctest/test-alloc.cc
  82. 231
      deps/v8/test/cctest/test-api.cc
  83. 8
      deps/v8/test/cctest/test-debug.cc
  84. 3
      deps/v8/test/cctest/test-heap.cc
  85. 75
      deps/v8/test/cctest/test-log.cc
  86. 37
      deps/v8/test/cctest/test-serialize.cc
  87. 117
      deps/v8/test/cctest/test-strings.cc
  88. 164
      deps/v8/test/mjsunit/arguments-read-and-assignment.js
  89. 33
      deps/v8/test/mjsunit/compiler/jsnatives.js
  90. 57
      deps/v8/test/mjsunit/compiler/objectliterals.js
  91. 32
      deps/v8/test/mjsunit/regress/regress-526.js
  92. 77
      deps/v8/test/mjsunit/regress/regress-r3391.js
  93. 20
      deps/v8/test/mjsunit/string-add.js
  94. 40
      deps/v8/test/mjsunit/typeof.js
  95. 2
      deps/v8/tools/codemap.js
  96. 11
      deps/v8/tools/gyp/v8.gyp
  97. 71
      deps/v8/tools/presubmit.py
  98. 2
      deps/v8/tools/utils.py
  99. 16
      deps/v8/tools/v8.xcodeproj/project.pbxproj

25
deps/v8/ChangeLog

@ -1,3 +1,26 @@
2009-12-03: Version 2.0.3
Optimized handling and adding of strings, for-in and Array.join.
Heap serialization is now non-destructive.
Improved profiler support with information on time spend in C++
callbacks registered through the API.
Added commands to the debugger protocol for starting/stopping
profiling.
Enabled the non-optimizing compiler for top-level code.
Changed the API to only allow strings to be set as data objects on
Contexts and scripts to avoid potentially keeping global objects
around for too long (issue 528).
OpenBSD support patch by Peter Valchev <pvalchev@gmail.com>.
Fixed bugs.
2009-11-24: Version 2.0.2 2009-11-24: Version 2.0.2
Improved profiler support. Improved profiler support.
@ -34,7 +57,7 @@
Reverted a change which caused crashes in RegExp replace. Reverted a change which caused crashes in RegExp replace.
Reverted a change which caused Chromium ui_tests failure. Reverted a change which caused Chromium ui_tests failure.
2009-10-28: Version 1.3.17 2009-10-28: Version 1.3.17

24
deps/v8/SConstruct

@ -149,6 +149,11 @@ LIBRARY_FLAGS = {
'LIBPATH' : ['/usr/local/lib'], 'LIBPATH' : ['/usr/local/lib'],
'CCFLAGS': ['-ansi'], 'CCFLAGS': ['-ansi'],
}, },
'os:openbsd': {
'CPPPATH' : ['/usr/local/include'],
'LIBPATH' : ['/usr/local/lib'],
'CCFLAGS': ['-ansi'],
},
'os:win32': { 'os:win32': {
'CCFLAGS': ['-DWIN32'], 'CCFLAGS': ['-DWIN32'],
'CXXFLAGS': ['-DWIN32'], 'CXXFLAGS': ['-DWIN32'],
@ -298,6 +303,9 @@ MKSNAPSHOT_EXTRA_FLAGS = {
'os:freebsd': { 'os:freebsd': {
'LIBS': ['execinfo', 'pthread'] 'LIBS': ['execinfo', 'pthread']
}, },
'os:openbsd': {
'LIBS': ['execinfo', 'pthread']
},
'os:win32': { 'os:win32': {
'LIBS': ['winmm', 'ws2_32'], 'LIBS': ['winmm', 'ws2_32'],
}, },
@ -344,6 +352,9 @@ CCTEST_EXTRA_FLAGS = {
'os:freebsd': { 'os:freebsd': {
'LIBS': ['execinfo', 'pthread'] 'LIBS': ['execinfo', 'pthread']
}, },
'os:openbsd': {
'LIBS': ['execinfo', 'pthread']
},
'os:win32': { 'os:win32': {
'LIBS': ['winmm', 'ws2_32'] 'LIBS': ['winmm', 'ws2_32']
}, },
@ -397,7 +408,11 @@ SAMPLE_FLAGS = {
}, },
'os:freebsd': { 'os:freebsd': {
'LIBPATH' : ['/usr/local/lib'], 'LIBPATH' : ['/usr/local/lib'],
'LIBS': ['execinfo', 'pthread'] 'LIBS': ['execinfo', 'pthread']
},
'os:openbsd': {
'LIBPATH' : ['/usr/local/lib'],
'LIBS': ['execinfo', 'pthread']
}, },
'os:win32': { 'os:win32': {
'LIBS': ['winmm', 'ws2_32'] 'LIBS': ['winmm', 'ws2_32']
@ -504,6 +519,9 @@ D8_FLAGS = {
'os:freebsd': { 'os:freebsd': {
'LIBS': ['pthread'], 'LIBS': ['pthread'],
}, },
'os:openbsd': {
'LIBS': ['pthread'],
},
'os:android': { 'os:android': {
'LIBPATH': [ANDROID_TOP + '/out/target/product/generic/obj/lib'], 'LIBPATH': [ANDROID_TOP + '/out/target/product/generic/obj/lib'],
'LINKFLAGS': ANDROID_LINKFLAGS, 'LINKFLAGS': ANDROID_LINKFLAGS,
@ -544,7 +562,7 @@ def GuessToolchain(os):
OS_GUESS = utils.GuessOS() OS_GUESS = utils.GuessOS()
TOOLCHAIN_GUESS = GuessToolchain(OS_GUESS) TOOLCHAIN_GUESS = GuessToolchain(OS_GUESS)
ARCH_GUESS = utils.GuessArchitecture() or "" ARCH_GUESS = utils.GuessArchitecture()
SIMPLE_OPTIONS = { SIMPLE_OPTIONS = {
@ -554,7 +572,7 @@ SIMPLE_OPTIONS = {
'help': 'the toolchain to use (' + TOOLCHAIN_GUESS + ')' 'help': 'the toolchain to use (' + TOOLCHAIN_GUESS + ')'
}, },
'os': { 'os': {
'values': ['freebsd', 'linux', 'macos', 'win32', 'android'], 'values': ['freebsd', 'linux', 'macos', 'win32', 'android', 'openbsd'],
'default': OS_GUESS, 'default': OS_GUESS,
'help': 'the os to build for (' + OS_GUESS + ')' 'help': 'the os to build for (' + OS_GUESS + ')'
}, },

20
deps/v8/include/v8.h

@ -598,7 +598,7 @@ class V8EXPORT Script {
* with the debugger as this data object is only available through the * with the debugger as this data object is only available through the
* debugger API. * debugger API.
*/ */
void SetData(Handle<Value> data); void SetData(Handle<String> data);
}; };
@ -2634,7 +2634,7 @@ class V8EXPORT Context {
* with the debugger to provide additional information on the context through * with the debugger to provide additional information on the context through
* the debugger API. * the debugger API.
*/ */
void SetData(Handle<Value> data); void SetData(Handle<String> data);
Local<Value> GetData(); Local<Value> GetData();
/** /**
@ -2819,6 +2819,18 @@ template <> struct SmiConstants<8> {
const int kSmiShiftSize = SmiConstants<sizeof(void*)>::kSmiShiftSize; const int kSmiShiftSize = SmiConstants<sizeof(void*)>::kSmiShiftSize;
const int kSmiValueSize = SmiConstants<sizeof(void*)>::kSmiValueSize; const int kSmiValueSize = SmiConstants<sizeof(void*)>::kSmiValueSize;
template <size_t ptr_size> struct InternalConstants;
// Internal constants for 32-bit systems.
template <> struct InternalConstants<4> {
static const int kStringResourceOffset = 3 * sizeof(void*);
};
// Internal constants for 64-bit systems.
template <> struct InternalConstants<8> {
static const int kStringResourceOffset = 2 * sizeof(void*);
};
/** /**
* This class exports constants and functionality from within v8 that * This class exports constants and functionality from within v8 that
* is necessary to implement inline functions in the v8 api. Don't * is necessary to implement inline functions in the v8 api. Don't
@ -2831,7 +2843,9 @@ class Internals {
// the implementation of v8. // the implementation of v8.
static const int kHeapObjectMapOffset = 0; static const int kHeapObjectMapOffset = 0;
static const int kMapInstanceTypeOffset = sizeof(void*) + sizeof(int); static const int kMapInstanceTypeOffset = sizeof(void*) + sizeof(int);
static const int kStringResourceOffset = 2 * sizeof(void*); static const int kStringResourceOffset =
InternalConstants<sizeof(void*)>::kStringResourceOffset;
static const int kProxyProxyOffset = sizeof(void*); static const int kProxyProxyOffset = sizeof(void*);
static const int kJSObjectHeaderSize = 3 * sizeof(void*); static const int kJSObjectHeaderSize = 3 * sizeof(void*);
static const int kFullStringRepresentationMask = 0x07; static const int kFullStringRepresentationMask = 0x07;

4
deps/v8/src/SConscript

@ -159,6 +159,7 @@ SOURCES = {
"""), """),
'simulator:arm': ['arm/simulator-arm.cc'], 'simulator:arm': ['arm/simulator-arm.cc'],
'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'], 'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
'os:openbsd': ['platform-openbsd.cc', 'platform-posix.cc'],
'os:linux': ['platform-linux.cc', 'platform-posix.cc'], 'os:linux': ['platform-linux.cc', 'platform-posix.cc'],
'os:android': ['platform-linux.cc', 'platform-posix.cc'], 'os:android': ['platform-linux.cc', 'platform-posix.cc'],
'os:macos': ['platform-macos.cc', 'platform-posix.cc'], 'os:macos': ['platform-macos.cc', 'platform-posix.cc'],
@ -187,6 +188,9 @@ D8_FILES = {
'os:freebsd': [ 'os:freebsd': [
'd8-posix.cc' 'd8-posix.cc'
], ],
'os:openbsd': [
'd8-posix.cc'
],
'os:win32': [ 'os:win32': [
'd8-windows.cc' 'd8-windows.cc'
], ],

70
deps/v8/src/accessors.cc

@ -315,14 +315,11 @@ Object* Accessors::ScriptGetLineEnds(Object* object, void*) {
HandleScope scope; HandleScope scope;
Handle<Script> script(Script::cast(JSValue::cast(object)->value())); Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
InitScriptLineEnds(script); InitScriptLineEnds(script);
if (script->line_ends_js_array()->IsUndefined()) { ASSERT(script->line_ends()->IsFixedArray());
Handle<FixedArray> line_ends_fixed_array( Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
FixedArray::cast(script->line_ends_fixed_array())); Handle<FixedArray> copy = Factory::CopyFixedArray(line_ends);
Handle<FixedArray> copy = Factory::CopyFixedArray(line_ends_fixed_array); Handle<JSArray> js_array = Factory::NewJSArrayWithElements(copy);
Handle<JSArray> js_array = Factory::NewJSArrayWithElements(copy); return *js_array;
script->set_line_ends_js_array(*js_array);
}
return script->line_ends_js_array();
} }
@ -352,29 +349,38 @@ const AccessorDescriptor Accessors::ScriptContextData = {
// //
// Accessors::ScriptGetEvalFromFunction // Accessors::ScriptGetEvalFromScript
// //
Object* Accessors::ScriptGetEvalFromFunction(Object* object, void*) { Object* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
Object* script = JSValue::cast(object)->value(); Object* script = JSValue::cast(object)->value();
return Script::cast(script)->eval_from_function(); if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
Handle<SharedFunctionInfo> eval_from_shared(
SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
if (eval_from_shared->script()->IsScript()) {
Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
return *GetScriptWrapper(eval_from_script);
}
}
return Heap::undefined_value();
} }
const AccessorDescriptor Accessors::ScriptEvalFromFunction = { const AccessorDescriptor Accessors::ScriptEvalFromScript = {
ScriptGetEvalFromFunction, ScriptGetEvalFromScript,
IllegalSetter, IllegalSetter,
0 0
}; };
// //
// Accessors::ScriptGetEvalFromPosition // Accessors::ScriptGetEvalFromScriptPosition
// //
Object* Accessors::ScriptGetEvalFromPosition(Object* object, void*) { Object* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
HandleScope scope; HandleScope scope;
Handle<Script> script(Script::cast(JSValue::cast(object)->value())); Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
@ -386,14 +392,42 @@ Object* Accessors::ScriptGetEvalFromPosition(Object* object, void*) {
// Get the function from where eval was called and find the source position // Get the function from where eval was called and find the source position
// from the instruction offset. // from the instruction offset.
Handle<Code> code(JSFunction::cast(script->eval_from_function())->code()); Handle<Code> code(SharedFunctionInfo::cast(
script->eval_from_shared())->code());
return Smi::FromInt(code->SourcePosition(code->instruction_start() + return Smi::FromInt(code->SourcePosition(code->instruction_start() +
script->eval_from_instructions_offset()->value())); script->eval_from_instructions_offset()->value()));
} }
const AccessorDescriptor Accessors::ScriptEvalFromPosition = { const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
ScriptGetEvalFromPosition, ScriptGetEvalFromScriptPosition,
IllegalSetter,
0
};
//
// Accessors::ScriptGetEvalFromFunctionName
//
Object* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
Object* script = JSValue::cast(object)->value();
Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
Script::cast(script)->eval_from_shared()));
// Find the name of the function calling eval.
if (!shared->name()->IsUndefined()) {
return shared->name();
} else {
return shared->inferred_name();
}
}
const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
ScriptGetEvalFromFunctionName,
IllegalSetter, IllegalSetter,
0 0
}; };

10
deps/v8/src/accessors.h

@ -51,8 +51,9 @@ namespace internal {
V(ScriptCompilationType) \ V(ScriptCompilationType) \
V(ScriptLineEnds) \ V(ScriptLineEnds) \
V(ScriptContextData) \ V(ScriptContextData) \
V(ScriptEvalFromFunction) \ V(ScriptEvalFromScript) \
V(ScriptEvalFromPosition) \ V(ScriptEvalFromScriptPosition) \
V(ScriptEvalFromFunctionName) \
V(ObjectPrototype) V(ObjectPrototype)
// Accessors contains all predefined proxy accessors. // Accessors contains all predefined proxy accessors.
@ -95,8 +96,9 @@ class Accessors : public AllStatic {
static Object* ScriptGetCompilationType(Object* object, void*); static Object* ScriptGetCompilationType(Object* object, void*);
static Object* ScriptGetLineEnds(Object* object, void*); static Object* ScriptGetLineEnds(Object* object, void*);
static Object* ScriptGetContextData(Object* object, void*); static Object* ScriptGetContextData(Object* object, void*);
static Object* ScriptGetEvalFromFunction(Object* object, void*); static Object* ScriptGetEvalFromScript(Object* object, void*);
static Object* ScriptGetEvalFromPosition(Object* object, void*); static Object* ScriptGetEvalFromScriptPosition(Object* object, void*);
static Object* ScriptGetEvalFromFunctionName(Object* object, void*);
static Object* ObjectGetPrototype(Object* receiver, void*); static Object* ObjectGetPrototype(Object* receiver, void*);
static Object* ObjectSetPrototype(JSObject* receiver, Object* value, void*); static Object* ObjectSetPrototype(JSObject* receiver, Object* value, void*);

46
deps/v8/src/api.cc

@ -126,6 +126,48 @@ static FatalErrorCallback& GetFatalErrorHandler() {
// When V8 cannot allocated memory FatalProcessOutOfMemory is called. // When V8 cannot allocated memory FatalProcessOutOfMemory is called.
// The default fatal error handler is called and execution is stopped. // The default fatal error handler is called and execution is stopped.
void i::V8::FatalProcessOutOfMemory(const char* location) { void i::V8::FatalProcessOutOfMemory(const char* location) {
i::HeapStats heap_stats;
int start_marker;
heap_stats.start_marker = &start_marker;
int new_space_size;
heap_stats.new_space_size = &new_space_size;
int new_space_capacity;
heap_stats.new_space_capacity = &new_space_capacity;
int old_pointer_space_size;
heap_stats.old_pointer_space_size = &old_pointer_space_size;
int old_pointer_space_capacity;
heap_stats.old_pointer_space_capacity = &old_pointer_space_capacity;
int old_data_space_size;
heap_stats.old_data_space_size = &old_data_space_size;
int old_data_space_capacity;
heap_stats.old_data_space_capacity = &old_data_space_capacity;
int code_space_size;
heap_stats.code_space_size = &code_space_size;
int code_space_capacity;
heap_stats.code_space_capacity = &code_space_capacity;
int map_space_size;
heap_stats.map_space_size = &map_space_size;
int map_space_capacity;
heap_stats.map_space_capacity = &map_space_capacity;
int cell_space_size;
heap_stats.cell_space_size = &cell_space_size;
int cell_space_capacity;
heap_stats.cell_space_capacity = &cell_space_capacity;
int lo_space_size;
heap_stats.lo_space_size = &lo_space_size;
int global_handle_count;
heap_stats.global_handle_count = &global_handle_count;
int weak_global_handle_count;
heap_stats.weak_global_handle_count = &weak_global_handle_count;
int pending_global_handle_count;
heap_stats.pending_global_handle_count = &pending_global_handle_count;
int near_death_global_handle_count;
heap_stats.near_death_global_handle_count = &near_death_global_handle_count;
int destroyed_global_handle_count;
heap_stats.destroyed_global_handle_count = &destroyed_global_handle_count;
int end_marker;
heap_stats.end_marker = &end_marker;
i::Heap::RecordStats(&heap_stats);
i::V8::SetFatalError(); i::V8::SetFatalError();
FatalErrorCallback callback = GetFatalErrorHandler(); FatalErrorCallback callback = GetFatalErrorHandler();
{ {
@ -451,7 +493,7 @@ void Context::Exit() {
} }
void Context::SetData(v8::Handle<Value> data) { void Context::SetData(v8::Handle<String> data) {
if (IsDeadCheck("v8::Context::SetData()")) return; if (IsDeadCheck("v8::Context::SetData()")) return;
ENTER_V8; ENTER_V8;
{ {
@ -1175,7 +1217,7 @@ Local<Value> Script::Id() {
} }
void Script::SetData(v8::Handle<Value> data) { void Script::SetData(v8::Handle<String> data) {
ON_BAILOUT("v8::Script::SetData()", return); ON_BAILOUT("v8::Script::SetData()", return);
LOG_API("Script::SetData"); LOG_API("Script::SetData");
{ {

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

@ -566,6 +566,7 @@ class Assembler : public Malloced {
// register. // register.
static const int kPcLoadDelta = 8; static const int kPcLoadDelta = 8;
static const int kJSReturnSequenceLength = 4;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Code generation // Code generation

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

@ -326,7 +326,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
// Calculate the exact length of the return sequence and make sure that // Calculate the exact length of the return sequence and make sure that
// the constant pool is not emitted inside of the return sequence. // the constant pool is not emitted inside of the return sequence.
int32_t sp_delta = (scope_->num_parameters() + 1) * kPointerSize; int32_t sp_delta = (scope_->num_parameters() + 1) * kPointerSize;
int return_sequence_length = Debug::kARMJSReturnSequenceLength; int return_sequence_length = Assembler::kJSReturnSequenceLength;
if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) { if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) {
// Additional mov instruction generated. // Additional mov instruction generated.
return_sequence_length++; return_sequence_length++;
@ -1560,7 +1560,7 @@ void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) {
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
VisitAndSpill(node->body()); VisitAndSpill(node->body());
// Compile the test. // Compile the test.
switch (info) { switch (info) {
case ALWAYS_TRUE: case ALWAYS_TRUE:
// If control can fall off the end of the body, jump back to the // If control can fall off the end of the body, jump back to the
@ -1775,19 +1775,77 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
jsobject.Bind(); jsobject.Bind();
// Get the set of properties (as a FixedArray or Map). // Get the set of properties (as a FixedArray or Map).
frame_->EmitPush(r0); // duplicate the object being enumerated // r0: value to be iterated over
frame_->EmitPush(r0); frame_->EmitPush(r0); // Push the object being iterated over.
// Check cache validity in generated code. This is a fast case for
// the JSObject::IsSimpleEnum cache validity checks. If we cannot
// guarantee cache validity, call the runtime system to check cache
// validity or get the property names in a fixed array.
JumpTarget call_runtime;
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
JumpTarget check_prototype;
JumpTarget use_cache;
__ mov(r1, Operand(r0));
loop.Bind();
// Check that there are no elements.
__ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
__ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
__ cmp(r2, r4);
call_runtime.Branch(ne);
// Check that instance descriptors are not empty so that we can
// check for an enum cache. Leave the map in r3 for the subsequent
// prototype load.
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
__ ldr(r2, FieldMemOperand(r3, Map::kInstanceDescriptorsOffset));
__ LoadRoot(ip, Heap::kEmptyDescriptorArrayRootIndex);
__ cmp(r2, ip);
call_runtime.Branch(eq);
// Check that there in an enum cache in the non-empty instance
// descriptors. This is the case if the next enumeration index
// field does not contain a smi.
__ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumerationIndexOffset));
__ tst(r2, Operand(kSmiTagMask));
call_runtime.Branch(eq);
// For all objects but the receiver, check that the cache is empty.
// r4: empty fixed array root.
__ cmp(r1, r0);
check_prototype.Branch(eq);
__ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheBridgeCacheOffset));
__ cmp(r2, r4);
call_runtime.Branch(ne);
check_prototype.Bind();
// Load the prototype from the map and loop if non-null.
__ ldr(r1, FieldMemOperand(r3, Map::kPrototypeOffset));
__ LoadRoot(ip, Heap::kNullValueRootIndex);
__ cmp(r1, ip);
loop.Branch(ne);
// The enum cache is valid. Load the map of the object being
// iterated over and use the cache for the iteration.
__ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
use_cache.Jump();
call_runtime.Bind();
// Call the runtime to get the property names for the object.
frame_->EmitPush(r0); // push the object (slot 4) for the runtime call
frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
// If we got a Map, we can do a fast modification check. // If we got a map from the runtime call, we can do a fast
// Otherwise, we got a FixedArray, and we have to do a slow check. // modification check. Otherwise, we got a fixed array, and we have
// to do a slow check.
// r0: map or fixed array (result from call to
// Runtime::kGetPropertyNamesFast)
__ mov(r2, Operand(r0)); __ mov(r2, Operand(r0));
__ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kMetaMapRootIndex); __ LoadRoot(ip, Heap::kMetaMapRootIndex);
__ cmp(r1, ip); __ cmp(r1, ip);
fixed_array.Branch(ne); fixed_array.Branch(ne);
use_cache.Bind();
// Get enum cache // Get enum cache
// r0: map (either the result from a call to
// Runtime::kGetPropertyNamesFast or has been fetched directly from
// the object)
__ mov(r1, Operand(r0)); __ mov(r1, Operand(r0));
__ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset)); __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
__ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset)); __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
@ -3308,9 +3366,6 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
// Now r2 has the string type. // Now r2 has the string type.
__ ldr(r3, FieldMemOperand(r1, String::kLengthOffset)); __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
__ and_(r4, r2, Operand(kStringSizeMask));
__ add(r4, r4, Operand(String::kLongLengthShift));
__ mov(r3, Operand(r3, LSR, r4));
// Now r3 has the length of the string. Compare with the index. // Now r3 has the length of the string. Compare with the index.
__ cmp(r3, Operand(r0, LSR, kSmiTagSize)); __ cmp(r3, Operand(r0, LSR, kSmiTagSize));
__ b(le, &slow); __ b(le, &slow);
@ -3508,6 +3563,17 @@ void CodeGenerator::GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
ASSERT_EQ(2, args->length());
Load(args->at(0));
Load(args->at(1));
frame_->CallRuntime(Runtime::kStringAdd, 2);
frame_->EmitPush(r0);
}
void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 2); ASSERT(args->length() == 2);
@ -5149,8 +5215,53 @@ static void HandleBinaryOpSlowCases(MacroAssembler* masm,
// We jump to here if something goes wrong (one param is not a number of any // We jump to here if something goes wrong (one param is not a number of any
// sort or new-space allocation fails). // sort or new-space allocation fails).
__ bind(&slow); __ bind(&slow);
// Push arguments to the stack
__ push(r1); __ push(r1);
__ push(r0); __ push(r0);
if (Token::ADD == operation) {
// Test for string arguments before calling runtime.
// r1 : first argument
// r0 : second argument
// sp[0] : second argument
// sp[1] : first argument
Label not_strings, not_string1, string1;
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &not_string1);
__ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
__ b(ge, &not_string1);
// First argument is a a string, test second.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &string1);
__ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE);
__ b(ge, &string1);
// First and second argument are strings.
__ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
// Only first argument is a string.
__ bind(&string1);
__ mov(r0, Operand(2)); // Set number of arguments.
__ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_JS);
// First argument was not a string, test second.
__ bind(&not_string1);
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &not_strings);
__ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE);
__ b(ge, &not_strings);
// Only second argument is a string.
__ b(&not_strings);
__ mov(r0, Operand(2)); // Set number of arguments.
__ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_JS);
__ bind(&not_strings);
}
__ mov(r0, Operand(1)); // Set number of arguments. __ mov(r0, Operand(1)); // Set number of arguments.
__ InvokeBuiltin(builtin, JUMP_JS); // Tail call. No return. __ InvokeBuiltin(builtin, JUMP_JS); // Tail call. No return.
@ -6388,7 +6499,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
__ b(eq, &adaptor); __ b(eq, &adaptor);
// Check index against formal parameters count limit passed in // Check index against formal parameters count limit passed in
// through register eax. Use unsigned comparison to get negative // through register r0. Use unsigned comparison to get negative
// check for free. // check for free.
__ cmp(r1, r0); __ cmp(r1, r0);
__ b(cs, &slow); __ b(cs, &slow);

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

@ -366,6 +366,9 @@ class CodeGenerator: public AstVisitor {
inline void GenerateMathSin(ZoneList<Expression*>* args); inline void GenerateMathSin(ZoneList<Expression*>* args);
inline void GenerateMathCos(ZoneList<Expression*>* args); inline void GenerateMathCos(ZoneList<Expression*>* args);
// Fast support for StringAdd.
void GenerateStringAdd(ZoneList<Expression*>* args);
// Simple condition analysis. // Simple condition analysis.
enum ConditionAnalysis { enum ConditionAnalysis {
ALWAYS_TRUE, ALWAYS_TRUE,

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

@ -43,24 +43,27 @@
# define USE_THUMB_INTERWORK 1 # define USE_THUMB_INTERWORK 1
#endif #endif
#if defined(__ARM_ARCH_5T__) || \ #if defined(__ARM_ARCH_7A__) || \
defined(__ARM_ARCH_5TE__) || \ defined(__ARM_ARCH_7R__) || \
defined(__ARM_ARCH_6__) || \
defined(__ARM_ARCH_7A__) || \
defined(__ARM_ARCH_7__) defined(__ARM_ARCH_7__)
# define CAN_USE_ARMV5_INSTRUCTIONS 1 # define CAN_USE_ARMV7_INSTRUCTIONS 1
# define CAN_USE_THUMB_INSTRUCTIONS 1
#endif #endif
#if defined(__ARM_ARCH_6__) || \ #if defined(__ARM_ARCH_6__) || \
defined(__ARM_ARCH_7A__) || \ defined(__ARM_ARCH_6J__) || \
defined(__ARM_ARCH_7__) defined(__ARM_ARCH_6K__) || \
defined(__ARM_ARCH_6Z__) || \
defined(__ARM_ARCH_6ZK__) || \
defined(__ARM_ARCH_6T2__) || \
defined(CAN_USE_ARMV7_INSTRUCTIONS)
# define CAN_USE_ARMV6_INSTRUCTIONS 1 # define CAN_USE_ARMV6_INSTRUCTIONS 1
#endif #endif
#if defined(__ARM_ARCH_7A__) || \ #if defined(__ARM_ARCH_5T__) || \
defined(__ARM_ARCH_7__) defined(__ARM_ARCH_5TE__) || \
# define CAN_USE_ARMV7_INSTRUCTIONS 1 defined(CAN_USE_ARMV6_INSTRUCTIONS)
# define CAN_USE_ARMV5_INSTRUCTIONS 1
# define CAN_USE_THUMB_INSTRUCTIONS 1
#endif #endif
// Simulator should support ARM5 instructions. // Simulator should support ARM5 instructions.

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

@ -61,7 +61,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
// Restore the JS frame exit code. // Restore the JS frame exit code.
void BreakLocationIterator::ClearDebugBreakAtReturn() { void BreakLocationIterator::ClearDebugBreakAtReturn() {
rinfo()->PatchCode(original_rinfo()->pc(), rinfo()->PatchCode(original_rinfo()->pc(),
Debug::kARMJSReturnSequenceLength); Assembler::kJSReturnSequenceLength);
} }

316
deps/v8/src/arm/fast-codegen-arm.cc

@ -73,16 +73,46 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
bool function_in_register = true; bool function_in_register = true;
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is in r1.
__ push(r1);
__ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false;
// Context is returned in both r0 and cp. It replaces the context
// passed to us. It's saved in the stack and kept live in cp.
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Copy any necessary parameters into the context.
int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context
__ str(r0, MemOperand(cp, Context::SlotOffset(slot->index())));
}
}
}
Variable* arguments = fun->scope()->arguments()->AsVariable(); Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) { if (arguments != NULL) {
// Function uses arguments object. // Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object"); Comment cmnt(masm_, "[ Allocate arguments object");
__ mov(r3, r1); if (!function_in_register) {
// Load this again, if it's used by the local context below.
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
} else {
__ 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.
__ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset + __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize)); fun->num_parameters() * kPointerSize));
__ mov(r1, Operand(Smi::FromInt(fun->num_parameters()))); __ mov(r1, Operand(Smi::FromInt(fun->num_parameters())));
__ stm(db_w, sp, r1.bit() | r2.bit() | r3.bit()); __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit());
// Arguments to ArgumentsAccessStub: // Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count. // function, receiver address, parameter count.
@ -90,33 +120,12 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
// stack frame was an arguments adapter frame. // stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub); __ CallStub(&stub);
__ str(r0, MemOperand(fp, SlotOffset(arguments->slot()))); // Duplicate the value; move-to-slot operation might clobber registers.
__ mov(r3, r0);
Move(arguments->slot(), r0, r1, r2);
Slot* dot_arguments_slot = Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot(); fun->scope()->arguments_shadow()->AsVariable()->slot();
__ str(r0, MemOperand(fp, SlotOffset(dot_arguments_slot))); Move(dot_arguments_slot, r3, r1, r2);
function_in_register = false;
}
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
if (!function_in_register) {
// Load this again, if it's used by the local context below.
__ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
}
// Argument to NewContext is the function, which is in r1.
__ push(r1);
__ CallRuntime(Runtime::kNewContext, 1);
// Context is returned in both r0 and cp. It replaces the context
// passed to us. It's saved in the stack and kept live in cp.
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
#ifdef DEBUG
// Assert we do not have to copy any parameters into the context.
for (int i = 0, len = fun->scope()->num_parameters(); i < len; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
ASSERT(slot != NULL && slot->type() != Slot::CONTEXT);
}
#endif
} }
// Check the stack for overflow or break request. // Check the stack for overflow or break request.
@ -179,7 +188,7 @@ void FastCodeGenerator::EmitReturnSequence(int position) {
// the constant pool is not emitted inside of the return sequence. // the constant pool is not emitted inside of the return sequence.
int num_parameters = function_->scope()->num_parameters(); int num_parameters = function_->scope()->num_parameters();
int32_t sp_delta = (num_parameters + 1) * kPointerSize; int32_t sp_delta = (num_parameters + 1) * kPointerSize;
int return_sequence_length = Debug::kARMJSReturnSequenceLength; int return_sequence_length = Assembler::kJSReturnSequenceLength;
if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) { if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) {
// Additional mov instruction generated. // Additional mov instruction generated.
return_sequence_length++; return_sequence_length++;
@ -238,7 +247,42 @@ void FastCodeGenerator::Move(Expression::Context context, Register source) {
} }
void FastCodeGenerator::Move(Expression::Context context, Slot* source) { template <>
MemOperand FastCodeGenerator::CreateSlotOperand<MemOperand>(
Slot* source,
Register scratch) {
switch (source->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
return MemOperand(fp, SlotOffset(source));
case Slot::CONTEXT: {
int context_chain_length =
function_->scope()->ContextChainLength(source->var()->scope());
__ LoadContext(scratch, context_chain_length);
return CodeGenerator::ContextOperand(scratch, source->index());
break;
}
case Slot::LOOKUP:
UNIMPLEMENTED();
// Fall-through.
default:
UNREACHABLE();
return MemOperand(r0, 0); // Dead code to make the compiler happy.
}
}
void FastCodeGenerator::Move(Register dst, Slot* source) {
// Use dst as scratch.
MemOperand location = CreateSlotOperand<MemOperand>(source, dst);
__ ldr(dst, location);
}
void FastCodeGenerator::Move(Expression::Context context,
Slot* source,
Register scratch) {
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
@ -248,8 +292,8 @@ void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
case Expression::kTest: // Fall through. case Expression::kTest: // Fall through.
case Expression::kValueTest: // Fall through. case Expression::kValueTest: // Fall through.
case Expression::kTestValue: case Expression::kTestValue:
__ ldr(ip, MemOperand(fp, SlotOffset(source))); Move(scratch, source);
Move(context, ip); Move(context, scratch);
break; break;
} }
} }
@ -272,24 +316,60 @@ void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
} }
void FastCodeGenerator::Move(Slot* dst,
Register src,
Register scratch1,
Register scratch2) {
switch (dst->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
__ str(src, MemOperand(fp, SlotOffset(dst)));
break;
case Slot::CONTEXT: {
int context_chain_length =
function_->scope()->ContextChainLength(dst->var()->scope());
__ LoadContext(scratch1, context_chain_length);
int index = Context::SlotOffset(dst->index());
__ mov(scratch2, Operand(index));
__ str(src, MemOperand(scratch1, index));
__ RecordWrite(scratch1, scratch2, src);
break;
}
case Slot::LOOKUP:
UNIMPLEMENTED();
default:
UNREACHABLE();
}
}
void FastCodeGenerator::DropAndMove(Expression::Context context, void FastCodeGenerator::DropAndMove(Expression::Context context,
Register source) { Register source,
int drop_count) {
ASSERT(drop_count > 0);
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
__ pop(); __ add(sp, sp, Operand(drop_count * kPointerSize));
break; break;
case Expression::kValue: case Expression::kValue:
if (drop_count > 1) {
__ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
}
__ str(source, MemOperand(sp)); __ str(source, MemOperand(sp));
break; break;
case Expression::kTest: case Expression::kTest:
ASSERT(!source.is(sp)); ASSERT(!source.is(sp));
__ pop(); __ add(sp, sp, Operand(drop_count * kPointerSize));
TestAndBranch(source, true_label_, false_label_); TestAndBranch(source, true_label_, false_label_);
break; break;
case Expression::kValueTest: { case Expression::kValueTest: {
Label discard; Label discard;
if (drop_count > 1) {
__ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
}
__ str(source, MemOperand(sp)); __ str(source, MemOperand(sp));
TestAndBranch(source, true_label_, &discard); TestAndBranch(source, true_label_, &discard);
__ bind(&discard); __ bind(&discard);
@ -299,6 +379,9 @@ void FastCodeGenerator::DropAndMove(Expression::Context context,
} }
case Expression::kTestValue: { case Expression::kTestValue: {
Label discard; Label discard;
if (drop_count > 1) {
__ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
}
__ str(source, MemOperand(sp)); __ str(source, MemOperand(sp));
TestAndBranch(source, &discard, false_label_); TestAndBranch(source, &discard, false_label_);
__ bind(&discard); __ bind(&discard);
@ -376,26 +459,26 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
__ mov(r0, Operand(Factory::the_hole_value())); __ mov(r0, Operand(Factory::the_hole_value()));
if (FLAG_debug_code) { if (FLAG_debug_code) {
// Check if we have the correct context pointer. // Check if we have the correct context pointer.
__ ldr(r1, CodeGenerator::ContextOperand( __ ldr(r1, CodeGenerator::ContextOperand(cp,
cp, Context::FCONTEXT_INDEX)); Context::FCONTEXT_INDEX));
__ cmp(r1, cp); __ cmp(r1, cp);
__ Check(eq, "Unexpected declaration in current context."); __ Check(eq, "Unexpected declaration in current context.");
} }
__ str(r0, CodeGenerator::ContextOperand(cp, slot->index())); __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
// No write barrier since the_hole_value is in old space. // No write barrier since the_hole_value is in old space.
ASSERT(Heap::InNewSpace(*Factory::the_hole_value())); ASSERT(!Heap::InNewSpace(*Factory::the_hole_value()));
} else if (decl->fun() != NULL) { } else if (decl->fun() != NULL) {
Visit(decl->fun()); Visit(decl->fun());
__ pop(r0); __ pop(r0);
if (FLAG_debug_code) { if (FLAG_debug_code) {
// Check if we have the correct context pointer. // Check if we have the correct context pointer.
__ ldr(r1, CodeGenerator::ContextOperand( __ ldr(r1, CodeGenerator::ContextOperand(cp,
cp, Context::FCONTEXT_INDEX)); Context::FCONTEXT_INDEX));
__ cmp(r1, cp); __ cmp(r1, cp);
__ Check(eq, "Unexpected declaration in current context."); __ Check(eq, "Unexpected declaration in current context.");
} }
__ str(r0, CodeGenerator::ContextOperand(cp, slot->index())); __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; int offset = Context::SlotOffset(slot->index());
__ mov(r2, Operand(offset)); __ mov(r2, Operand(offset));
// We know that we have written a function, which is not a smi. // We know that we have written a function, which is not a smi.
__ RecordWrite(cp, r2, r0); __ RecordWrite(cp, r2, r0);
@ -467,53 +550,60 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
DropAndMove(expr->context(), r0); DropAndMove(expr->context(), r0);
} else if (rewrite->AsSlot() != NULL) { } else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot(); Slot* slot = rewrite->AsSlot();
ASSERT_NE(NULL, slot); if (FLAG_debug_code) {
switch (slot->type()) { switch (slot->type()) {
case Slot::LOCAL: case Slot::LOCAL:
case Slot::PARAMETER: { case Slot::PARAMETER: {
Comment cmnt(masm_, "Stack slot"); Comment cmnt(masm_, "Stack slot");
Move(expr->context(), rewrite->AsSlot()); break;
break;
}
case Slot::CONTEXT: {
Comment cmnt(masm_, "Context slot");
int chain_length =
function_->scope()->ContextChainLength(slot->var()->scope());
if (chain_length > 0) {
// Move up the chain of contexts to the context containing the slot.
__ ldr(r0, CodeGenerator::ContextOperand(cp, Context::CLOSURE_INDEX));
// Load the function context (which is the incoming, outer context).
__ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
for (int i = 1; i < chain_length; i++) {
__ ldr(r0,
CodeGenerator::ContextOperand(r0, Context::CLOSURE_INDEX));
// Load the function context (which is the incoming, outer context).
__ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
}
// The context may be an intermediate context, not a function context.
__ ldr(r0,
CodeGenerator::ContextOperand(r0, Context::FCONTEXT_INDEX));
} else { // Slot is in the current context.
__ ldr(r0,
CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX));
} }
__ ldr(r0, CodeGenerator::ContextOperand(r0, slot->index())); case Slot::CONTEXT: {
Move(expr->context(), r0); Comment cmnt(masm_, "Context slot");
break; break;
}
case Slot::LOOKUP:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
} }
case Slot::LOOKUP:
UNREACHABLE();
break;
} }
Move(expr->context(), slot, r0);
} else { } else {
// The parameter variable has been rewritten into an explict access to // A variable has been rewritten into an explicit access to
// the arguments object. // an object property.
Property* property = rewrite->AsProperty(); Property* property = rewrite->AsProperty();
ASSERT_NOT_NULL(property); ASSERT_NOT_NULL(property);
ASSERT_EQ(expr->context(), property->context());
Visit(property); // Currently the only parameter expressions that can occur are
// on the form "slot[literal]".
// Check that the object is in a slot.
Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
ASSERT_NOT_NULL(object_var);
Slot* object_slot = object_var->slot();
ASSERT_NOT_NULL(object_slot);
// Load the object.
Move(r2, object_slot);
// Check that the key is a smi.
Literal* key_literal = property->key()->AsLiteral();
ASSERT_NOT_NULL(key_literal);
ASSERT(key_literal->handle()->IsSmi());
// Load the key.
__ mov(r1, Operand(key_literal->handle()));
// Push both as arguments to ic.
__ stm(db_w, sp, r2.bit() | r1.bit());
// Do a KEYED property load.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Drop key and object left on the stack by IC, and push the result.
DropAndMove(expr->context(), r0, 2);
} }
} }
@ -575,8 +665,9 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
} }
// If result_saved == true: the result is saved on top of the stack. // If result_saved == true: The result is saved on top of the
// If result_saved == false: the result is in r0. // stack and in r0.
// If result_saved == false: The result not on the stack, just in r0.
bool result_saved = false; bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) { for (int i = 0; i < expr->properties()->length(); i++) {
@ -604,6 +695,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
// StoreIC leaves the receiver on the stack. // StoreIC leaves the receiver on the stack.
__ ldr(r0, MemOperand(sp)); // Restore result into r0.
break; break;
} }
// Fall through. // Fall through.
@ -615,7 +707,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Visit(value); Visit(value);
ASSERT_EQ(Expression::kValue, value->context()); ASSERT_EQ(Expression::kValue, value->context());
__ CallRuntime(Runtime::kSetProperty, 3); __ CallRuntime(Runtime::kSetProperty, 3);
__ ldr(r0, MemOperand(sp)); // Restore result into r0 __ ldr(r0, MemOperand(sp)); // Restore result into r0.
break; break;
case ObjectLiteral::Property::GETTER: // Fall through. case ObjectLiteral::Property::GETTER: // Fall through.
@ -785,7 +877,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
// Overwrite the global object on the stack with the result if needed. // Overwrite the global object on the stack with the result if needed.
DropAndMove(expr->context(), r0); DropAndMove(expr->context(), r0);
} else { } else if (var->slot()) {
Slot* slot = var->slot(); Slot* slot = var->slot();
ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled. ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
switch (slot->type()) { switch (slot->type()) {
@ -884,6 +976,35 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
UNREACHABLE(); UNREACHABLE();
break; break;
} }
} else {
Property* property = var->rewrite()->AsProperty();
ASSERT_NOT_NULL(property);
// Load object and key onto the stack.
Slot* object_slot = property->obj()->AsSlot();
ASSERT_NOT_NULL(object_slot);
Move(Expression::kValue, object_slot, r0);
Literal* key_literal = property->key()->AsLiteral();
ASSERT_NOT_NULL(key_literal);
Move(Expression::kValue, key_literal);
// Value to store was pushed before object and key on the stack.
__ ldr(r0, MemOperand(sp, 2 * kPointerSize));
// Arguments to ic is value in r0, object and key on stack.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
if (expr->context() == Expression::kEffect) {
__ add(sp, sp, Operand(3 * kPointerSize));
} else if (expr->context() == Expression::kValue) {
// Value is still on the stack in esp[2 * kPointerSize]
__ add(sp, sp, Operand(2 * kPointerSize));
} else {
__ ldr(r0, MemOperand(sp, 2 * kPointerSize));
DropAndMove(expr->context(), r0, 3);
}
} }
} }
@ -1134,9 +1255,14 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) {
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Comment cmnt(masm_, "[ CallRuntime"); Comment cmnt(masm_, "[ CallRuntime");
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
Runtime::Function* function = expr->function();
ASSERT(function != NULL); if (expr->is_jsruntime()) {
// Prepare for calling JS runtime function.
__ mov(r1, Operand(expr->name()));
__ ldr(r0, CodeGenerator::GlobalObject());
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
__ stm(db_w, sp, r1.bit() | r0.bit());
}
// Push the arguments ("left-to-right"). // Push the arguments ("left-to-right").
int arg_count = args->length(); int arg_count = args->length();
@ -1145,8 +1271,20 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
ASSERT_EQ(Expression::kValue, args->at(i)->context()); ASSERT_EQ(Expression::kValue, args->at(i)->context());
} }
__ CallRuntime(function, arg_count); if (expr->is_jsruntime()) {
Move(expr->context(), r0); // Call the JS runtime function.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
__ Call(ic, RelocInfo::CODE_TARGET);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
DropAndMove(expr->context(), r0);
} else {
// Call the C runtime function.
__ CallRuntime(expr->function(), arg_count);
Move(expr->context(), r0);
}
} }

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

@ -107,12 +107,17 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
static const int kProbes = 4; static const int kProbes = 4;
for (int i = 0; i < kProbes; i++) { for (int i = 0; i < kProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask. // Compute the masked index: (hash + i + i * i) & mask.
__ ldr(t1, FieldMemOperand(r2, String::kLengthOffset)); __ ldr(t1, FieldMemOperand(r2, String::kHashFieldOffset));
__ mov(t1, Operand(t1, LSR, String::kHashShift));
if (i > 0) { if (i > 0) {
__ add(t1, t1, Operand(StringDictionary::GetProbeOffset(i))); // Add the probe offset (i + i * i) left shifted to avoid right shifting
// the hash in a separate instruction. The value hash + i + i * i is right
// shifted in the following and instruction.
ASSERT(StringDictionary::GetProbeOffset(i) <
1 << (32 - String::kHashFieldOffset));
__ add(t1, t1, Operand(
StringDictionary::GetProbeOffset(i) << String::kHashShift));
} }
__ and_(t1, t1, Operand(r3)); __ and_(t1, r3, Operand(t1, LSR, String::kHashShift));
// Scale the index by multiplying by the element size. // Scale the index by multiplying by the element size.
ASSERT(StringDictionary::kEntrySize == 3); ASSERT(StringDictionary::kEntrySize == 3);

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

@ -155,6 +155,15 @@ void MacroAssembler::Ret(Condition cond) {
} }
void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
LoadRoot(ip, Heap::kStackLimitRootIndex);
cmp(sp, Operand(ip));
b(lo, on_stack_overflow);
}
void MacroAssembler::SmiJumpTable(Register index, Vector<Label*> targets) { void MacroAssembler::SmiJumpTable(Register index, Vector<Label*> targets) {
// Empty the const pool. // Empty the const pool.
CheckConstPool(true, true); CheckConstPool(true, true);
@ -785,15 +794,13 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
mov(scratch1, Operand(new_space_allocation_top)); mov(scratch1, Operand(new_space_allocation_top));
if ((flags & RESULT_CONTAINS_TOP) == 0) { if ((flags & RESULT_CONTAINS_TOP) == 0) {
ldr(result, MemOperand(scratch1)); ldr(result, MemOperand(scratch1));
} else { } else if (FLAG_debug_code) {
#ifdef DEBUG
// Assert that result actually contains top on entry. scratch2 is used // Assert that result actually contains top on entry. scratch2 is used
// immediately below so this use of scratch2 does not cause difference with // immediately below so this use of scratch2 does not cause difference with
// respect to register content between debug and release mode. // respect to register content between debug and release mode.
ldr(scratch2, MemOperand(scratch1)); ldr(scratch2, MemOperand(scratch1));
cmp(result, scratch2); cmp(result, scratch2);
Check(eq, "Unexpected allocation top"); Check(eq, "Unexpected allocation top");
#endif
} }
// Calculate new top and bail out if new space is exhausted. Use result // Calculate new top and bail out if new space is exhausted. Use result
@ -806,7 +813,11 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
cmp(result, Operand(scratch2)); cmp(result, Operand(scratch2));
b(hi, gc_required); b(hi, gc_required);
// Update allocation top. result temporarily holds the new top, // Update allocation top. result temporarily holds the new top.
if (FLAG_debug_code) {
tst(result, Operand(kObjectAlignmentMask));
Check(eq, "Unaligned allocation in new space");
}
str(result, MemOperand(scratch1)); str(result, MemOperand(scratch1));
// Tag and adjust back to start of new object. // Tag and adjust back to start of new object.
@ -835,15 +846,13 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
mov(scratch1, Operand(new_space_allocation_top)); mov(scratch1, Operand(new_space_allocation_top));
if ((flags & RESULT_CONTAINS_TOP) == 0) { if ((flags & RESULT_CONTAINS_TOP) == 0) {
ldr(result, MemOperand(scratch1)); ldr(result, MemOperand(scratch1));
} else { } else if (FLAG_debug_code) {
#ifdef DEBUG
// Assert that result actually contains top on entry. scratch2 is used // Assert that result actually contains top on entry. scratch2 is used
// immediately below so this use of scratch2 does not cause difference with // immediately below so this use of scratch2 does not cause difference with
// respect to register content between debug and release mode. // respect to register content between debug and release mode.
ldr(scratch2, MemOperand(scratch1)); ldr(scratch2, MemOperand(scratch1));
cmp(result, scratch2); cmp(result, scratch2);
Check(eq, "Unexpected allocation top"); Check(eq, "Unexpected allocation top");
#endif
} }
// Calculate new top and bail out if new space is exhausted. Use result // Calculate new top and bail out if new space is exhausted. Use result
@ -857,7 +866,11 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
cmp(result, Operand(scratch2)); cmp(result, Operand(scratch2));
b(hi, gc_required); b(hi, gc_required);
// Update allocation top. result temporarily holds the new top, // Update allocation top. result temporarily holds the new top.
if (FLAG_debug_code) {
tst(result, Operand(kObjectAlignmentMask));
Check(eq, "Unaligned allocation in new space");
}
str(result, MemOperand(scratch1)); str(result, MemOperand(scratch1));
// Adjust back to start of new object. // Adjust back to start of new object.
@ -1153,6 +1166,9 @@ void MacroAssembler::Abort(const char* msg) {
RecordComment(msg); RecordComment(msg);
} }
#endif #endif
// Disable stub call restrictions to always allow calls to abort.
set_allow_stub_calls(true);
mov(r0, Operand(p0)); mov(r0, Operand(p0));
push(r0); push(r0);
mov(r0, Operand(Smi::FromInt(p1 - p0))); mov(r0, Operand(Smi::FromInt(p1 - p0)));
@ -1162,6 +1178,26 @@ void MacroAssembler::Abort(const char* msg) {
} }
void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
if (context_chain_length > 0) {
// Move up the chain of contexts to the context containing the slot.
ldr(dst, MemOperand(cp, Context::SlotOffset(Context::CLOSURE_INDEX)));
// Load the function context (which is the incoming, outer context).
ldr(dst, FieldMemOperand(dst, JSFunction::kContextOffset));
for (int i = 1; i < context_chain_length; i++) {
ldr(dst, MemOperand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
ldr(dst, FieldMemOperand(dst, JSFunction::kContextOffset));
}
// The context may be an intermediate context, not a function context.
ldr(dst, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
} else { // Slot is in the current function context.
// The context may be an intermediate context, not a function context.
ldr(dst, MemOperand(cp, Context::SlotOffset(Context::FCONTEXT_INDEX)));
}
}
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
CodePatcher::CodePatcher(byte* address, int instructions) CodePatcher::CodePatcher(byte* address, int instructions)
: address_(address), : address_(address),

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

@ -78,6 +78,11 @@ class MacroAssembler: public Assembler {
// well as the ip register. // well as the ip register.
void RecordWrite(Register object, Register offset, Register scratch); void RecordWrite(Register object, Register offset, Register scratch);
// ---------------------------------------------------------------------------
// Stack limit support
void StackLimitCheck(Label* on_stack_limit_hit);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Activation frames // Activation frames
@ -99,6 +104,8 @@ class MacroAssembler: public Assembler {
// Align the stack by optionally pushing a Smi zero. // Align the stack by optionally pushing a Smi zero.
void AlignStack(int offset); void AlignStack(int offset);
void LoadContext(Register dst, int context_chain_length);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// JavaScript invokes // JavaScript invokes

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

@ -105,7 +105,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ b(eq, &miss); __ b(eq, &miss);
// Get the map of the receiver and compute the hash. // Get the map of the receiver and compute the hash.
__ ldr(scratch, FieldMemOperand(name, String::kLengthOffset)); __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
__ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset)); __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ add(scratch, scratch, Operand(ip)); __ add(scratch, scratch, Operand(ip));
__ eor(scratch, scratch, Operand(flags)); __ eor(scratch, scratch, Operand(flags));
@ -229,10 +229,7 @@ void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
miss, &check_wrapper); miss, &check_wrapper);
// Load length directly from the string. // Load length directly from the string.
__ and_(scratch1, scratch1, Operand(kStringSizeMask));
__ add(scratch1, scratch1, Operand(String::kHashShift));
__ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset)); __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
__ mov(r0, Operand(r0, LSR, scratch1));
__ mov(r0, Operand(r0, LSL, kSmiTagSize)); __ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ Ret(); __ Ret();

36
deps/v8/src/array.js

@ -77,7 +77,8 @@ function SparseJoin(array, len, convert) {
var key = keys[i]; var key = keys[i];
if (key != last_key) { if (key != last_key) {
var e = array[key]; var e = array[key];
builder.add(convert(e)); if (typeof(e) !== 'string') e = convert(e);
builder.add(e);
last_key = key; last_key = key;
} }
} }
@ -114,17 +115,36 @@ function Join(array, length, separator, convert) {
if (length == 1) { if (length == 1) {
var e = array[0]; var e = array[0];
if (!IS_UNDEFINED(e) || (0 in array)) { if (!IS_UNDEFINED(e) || (0 in array)) {
if (typeof(e) === 'string') return e;
return convert(e); return convert(e);
} }
} }
var builder = new StringBuilder(); var builder = new StringBuilder();
for (var i = 0; i < length; i++) { // We pull the empty separator check outside the loop for speed!
var e = array[i]; if (separator.length == 0) {
if (i != 0) builder.add(separator); for (var i = 0; i < length; i++) {
if (!IS_UNDEFINED(e) || (i in array)) { var e = array[i];
builder.add(convert(e)); if (!IS_UNDEFINED(e) || (i in array)) {
if (typeof(e) !== 'string') e = convert(e);
if (e.length > 0) {
var elements = builder.elements;
elements[elements.length] = e;
}
}
}
} else {
for (var i = 0; i < length; i++) {
var e = array[i];
if (i != 0) builder.add(separator);
if (!IS_UNDEFINED(e) || (i in array)) {
if (typeof(e) !== 'string') e = convert(e);
if (e.length > 0) {
var elements = builder.elements;
elements[elements.length] = e;
}
}
} }
} }
return builder.generate(); return builder.generate();
@ -136,12 +156,14 @@ function Join(array, length, separator, convert) {
function ConvertToString(e) { function ConvertToString(e) {
if (typeof(e) === 'string') return e;
if (e == null) return ''; if (e == null) return '';
else return ToString(e); else return ToString(e);
} }
function ConvertToLocaleString(e) { function ConvertToLocaleString(e) {
if (typeof(e) === 'string') return e;
if (e == null) return ''; if (e == null) return '';
else { else {
// e_obj's toLocaleString might be overwritten, check if it is a function. // e_obj's toLocaleString might be overwritten, check if it is a function.
@ -149,7 +171,7 @@ function ConvertToLocaleString(e) {
// See issue 877615. // See issue 877615.
var e_obj = ToObject(e); var e_obj = ToObject(e);
if (IS_FUNCTION(e_obj.toLocaleString)) if (IS_FUNCTION(e_obj.toLocaleString))
return e_obj.toLocaleString(); return ToString(e_obj.toLocaleString());
else else
return ToString(e); return ToString(e);
} }

1
deps/v8/src/ast.h

@ -1080,6 +1080,7 @@ class CallRuntime: public Expression {
Handle<String> name() const { return name_; } Handle<String> name() const { return name_; }
Runtime::Function* function() const { return function_; } Runtime::Function* function() const { return function_; }
ZoneList<Expression*>* arguments() const { return arguments_; } ZoneList<Expression*>* arguments() const { return arguments_; }
bool is_jsruntime() const { return function_ == NULL; }
private: private:
Handle<String> name_; Handle<String> name_;

26
deps/v8/src/bootstrapper.cc

@ -1111,21 +1111,29 @@ bool Genesis::InstallNatives() {
Factory::LookupAsciiSymbol("context_data"), Factory::LookupAsciiSymbol("context_data"),
proxy_context_data, proxy_context_data,
common_attributes); common_attributes);
Handle<Proxy> proxy_eval_from_function = Handle<Proxy> proxy_eval_from_script =
Factory::NewProxy(&Accessors::ScriptEvalFromFunction); Factory::NewProxy(&Accessors::ScriptEvalFromScript);
script_descriptors = script_descriptors =
Factory::CopyAppendProxyDescriptor( Factory::CopyAppendProxyDescriptor(
script_descriptors, script_descriptors,
Factory::LookupAsciiSymbol("eval_from_function"), Factory::LookupAsciiSymbol("eval_from_script"),
proxy_eval_from_function, proxy_eval_from_script,
common_attributes); common_attributes);
Handle<Proxy> proxy_eval_from_position = Handle<Proxy> proxy_eval_from_script_position =
Factory::NewProxy(&Accessors::ScriptEvalFromPosition); Factory::NewProxy(&Accessors::ScriptEvalFromScriptPosition);
script_descriptors = script_descriptors =
Factory::CopyAppendProxyDescriptor( Factory::CopyAppendProxyDescriptor(
script_descriptors, script_descriptors,
Factory::LookupAsciiSymbol("eval_from_position"), Factory::LookupAsciiSymbol("eval_from_script_position"),
proxy_eval_from_position, proxy_eval_from_script_position,
common_attributes);
Handle<Proxy> proxy_eval_from_function_name =
Factory::NewProxy(&Accessors::ScriptEvalFromFunctionName);
script_descriptors =
Factory::CopyAppendProxyDescriptor(
script_descriptors,
Factory::LookupAsciiSymbol("eval_from_function_name"),
proxy_eval_from_function_name,
common_attributes); common_attributes);
Handle<Map> script_map = Handle<Map>(script_fun->initial_map()); Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
@ -1338,8 +1346,6 @@ bool Genesis::InstallExtension(v8::RegisteredExtension* current) {
ASSERT(Top::has_pending_exception() != result); ASSERT(Top::has_pending_exception() != result);
if (!result) { if (!result) {
Top::clear_pending_exception(); Top::clear_pending_exception();
v8::Utils::ReportApiFailure(
"v8::Context::New()", "Error installing extension");
} }
current->set_state(v8::INSTALLED); current->set_state(v8::INSTALLED);
return result; return result;

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

@ -36,6 +36,7 @@ namespace internal {
#define CODE_STUB_LIST_ALL_PLATFORMS(V) \ #define CODE_STUB_LIST_ALL_PLATFORMS(V) \
V(CallFunction) \ V(CallFunction) \
V(GenericBinaryOp) \ V(GenericBinaryOp) \
V(StringAdd) \
V(SmiOp) \ V(SmiOp) \
V(Compare) \ V(Compare) \
V(RecordWrite) \ V(RecordWrite) \

1
deps/v8/src/codegen.cc

@ -346,6 +346,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
{&CodeGenerator::GenerateMathCos, "_Math_cos"}, {&CodeGenerator::GenerateMathCos, "_Math_cos"},
{&CodeGenerator::GenerateIsObject, "_IsObject"}, {&CodeGenerator::GenerateIsObject, "_IsObject"},
{&CodeGenerator::GenerateIsFunction, "_IsFunction"}, {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
{&CodeGenerator::GenerateStringAdd, "_StringAdd"},
}; };

50
deps/v8/src/compiler.cc

@ -124,9 +124,12 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
// If there is no shared function info, try the fast code // If there is no shared function info, try the fast code
// generator for code in the global scope. Otherwise obey the // generator for code in the global scope. Otherwise obey the
// explicit hint in the shared function info. // explicit hint in the shared function info.
if (shared.is_null() && !literal->scope()->is_global_scope()) { // If always_fast_compiler is true, always try the fast compiler.
if (shared.is_null() && !literal->scope()->is_global_scope() &&
!FLAG_always_fast_compiler) {
if (FLAG_trace_bailout) PrintF("Non-global scope\n"); if (FLAG_trace_bailout) PrintF("Non-global scope\n");
} else if (!shared.is_null() && !shared->try_fast_codegen()) { } else if (!shared.is_null() && !shared->try_fast_codegen() &&
!FLAG_always_fast_compiler) {
if (FLAG_trace_bailout) PrintF("No hint to try fast\n"); if (FLAG_trace_bailout) PrintF("No hint to try fast\n");
} else { } else {
CodeGenSelector selector; CodeGenSelector selector;
@ -176,7 +179,8 @@ static Handle<JSFunction> MakeFunction(bool is_global,
// called. // called.
if (is_eval) { if (is_eval) {
JavaScriptFrameIterator it; JavaScriptFrameIterator it;
script->set_eval_from_function(it.frame()->function()); script->set_eval_from_shared(
JSFunction::cast(it.frame()->function())->shared());
int offset = static_cast<int>( int offset = static_cast<int>(
it.frame()->pc() - it.frame()->code()->instruction_start()); it.frame()->pc() - it.frame()->code()->instruction_start());
script->set_eval_from_instructions_offset(Smi::FromInt(offset)); script->set_eval_from_instructions_offset(Smi::FromInt(offset));
@ -599,11 +603,6 @@ CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
} }
} }
if (scope->arguments() != NULL) {
if (FLAG_trace_bailout) PrintF("function uses 'arguments'\n");
return NORMAL;
}
has_supported_syntax_ = true; has_supported_syntax_ = true;
VisitDeclarations(scope->declarations()); VisitDeclarations(scope->declarations());
if (!has_supported_syntax_) return NORMAL; if (!has_supported_syntax_) return NORMAL;
@ -802,7 +801,17 @@ void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
BAILOUT("Lookup slot"); BAILOUT("Lookup slot");
} }
} else { } else {
BAILOUT("access to arguments object"); #ifdef DEBUG
// Only remaining possibility is a property where the object is
// a slotted variable and the key is a smi.
Property* property = rewrite->AsProperty();
ASSERT_NOT_NULL(property);
Variable* object = property->obj()->AsVariableProxy()->AsVariable();
ASSERT_NOT_NULL(object);
ASSERT_NOT_NULL(object->slot());
ASSERT_NOT_NULL(property->key()->AsLiteral());
ASSERT(property->key()->AsLiteral()->handle()->IsSmi());
#endif
} }
} }
} }
@ -886,12 +895,21 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
// All global variables are supported. // All global variables are supported.
if (!var->is_global()) { if (!var->is_global()) {
if (var->slot() == NULL) { if (var->slot() == NULL) {
// This is a parameter that has rewritten to an arguments access. Property* property = var->AsProperty();
BAILOUT("non-global/non-slot assignment"); if (property == NULL) {
} BAILOUT("non-global/non-slot/non-property assignment");
Slot::Type type = var->slot()->type(); }
if (type == Slot::LOOKUP) { if (property->obj()->AsSlot() == NULL) {
BAILOUT("Lookup slot"); BAILOUT("variable rewritten to property non slot object assignment");
}
if (property->key()->AsLiteral() == NULL) {
BAILOUT("variable rewritten to property non literal key assignment");
}
} else {
Slot::Type type = var->slot()->type();
if (type == Slot::LOOKUP) {
BAILOUT("Lookup slot");
}
} }
} }
} else if (prop != NULL) { } else if (prop != NULL) {
@ -979,8 +997,6 @@ void CodeGenSelector::VisitCallNew(CallNew* expr) {
void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) { void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
// In case of JS runtime function bail out.
if (expr->function() == NULL) BAILOUT("call JS runtime function");
// Check for inline runtime call // Check for inline runtime call
if (expr->name()->Get(0) == '_' && if (expr->name()->Get(0) == '_' &&
CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) { CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {

8
deps/v8/src/d8.cc

@ -159,7 +159,11 @@ Handle<Value> Shell::Write(const Arguments& args) {
printf(" "); printf(" ");
} }
v8::String::Utf8Value str(args[i]); v8::String::Utf8Value str(args[i]);
fwrite(*str, sizeof(**str), str.length(), stdout); int n = fwrite(*str, sizeof(**str), str.length(), stdout);
if (n != str.length()) {
printf("Error in fwrite\n");
exit(1);
}
} }
return Undefined(); return Undefined();
} }
@ -203,7 +207,7 @@ Handle<Value> Shell::Load(const Arguments& args) {
return ThrowException(String::New("Error loading file")); return ThrowException(String::New("Error loading file"));
} }
if (!ExecuteString(source, String::New(*file), false, false)) { if (!ExecuteString(source, String::New(*file), false, false)) {
return ThrowException(String::New("Error executing file")); return ThrowException(String::New("Error executing file"));
} }
} }
return Undefined(); return Undefined();

21
deps/v8/src/debug-delay.js

@ -1245,6 +1245,8 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
this.suspendRequest_(request, response); this.suspendRequest_(request, response);
} else if (request.command == 'version') { } else if (request.command == 'version') {
this.versionRequest_(request, response); this.versionRequest_(request, response);
} else if (request.command == 'profile') {
this.profileRequest_(request, response);
} else { } else {
throw new Error('Unknown command "' + request.command + '" in request'); throw new Error('Unknown command "' + request.command + '" in request');
} }
@ -1924,6 +1926,25 @@ DebugCommandProcessor.prototype.versionRequest_ = 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');
}
if (request.arguments.command == 'resume') {
%ProfilerResume(modules);
} else if (request.arguments.command == 'pause') {
%ProfilerPause(modules);
} else {
return response.failed('Unknown command');
}
response.body = {};
};
// Check whether the previously processed command caused the VM to become // Check whether the previously processed command caused the VM to become
// running. // running.
DebugCommandProcessor.prototype.isRunning = function() { DebugCommandProcessor.prototype.isRunning = function() {

11
deps/v8/src/debug.h

@ -370,17 +370,6 @@ class Debug {
// Garbage collection notifications. // Garbage collection notifications.
static void AfterGarbageCollection(); static void AfterGarbageCollection();
// Code generation assumptions.
static const int kIa32CallInstructionLength = 5;
static const int kIa32JSReturnSequenceLength = 6;
// The x64 JS return sequence is padded with int3 to make it large
// enough to hold a call instruction when the debugger patches it.
static const int kX64CallInstructionLength = 13;
static const int kX64JSReturnSequenceLength = 13;
static const int kARMJSReturnSequenceLength = 4;
// Code generator routines. // Code generator routines.
static void GenerateLoadICDebugBreak(MacroAssembler* masm); static void GenerateLoadICDebugBreak(MacroAssembler* masm);
static void GenerateStoreICDebugBreak(MacroAssembler* masm); static void GenerateStoreICDebugBreak(MacroAssembler* masm);

8
deps/v8/src/dtoa-config.c

@ -38,7 +38,7 @@
*/ */
#if !(defined(__APPLE__) && defined(__MACH__)) && \ #if !(defined(__APPLE__) && defined(__MACH__)) && \
!defined(WIN32) && !defined(__FreeBSD__) !defined(WIN32) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
#include <endian.h> #include <endian.h>
#endif #endif
#include <math.h> #include <math.h>
@ -47,14 +47,16 @@
/* The floating point word order on ARM is big endian when floating point /* The floating point word order on ARM is big endian when floating point
* emulation is used, even if the byte order is little endian */ * emulation is used, even if the byte order is little endian */
#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32) && \ #if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32) && \
!defined(__FreeBSD__) && __FLOAT_WORD_ORDER == __BIG_ENDIAN !defined(__FreeBSD__) && !defined(__OpenBSD__) && \
__FLOAT_WORD_ORDER == __BIG_ENDIAN
#define IEEE_MC68k #define IEEE_MC68k
#else #else
#define IEEE_8087 #define IEEE_8087
#endif #endif
#define __MATH_H__ #define __MATH_H__
#if defined(__APPLE__) && defined(__MACH__) || defined(__FreeBSD__) #if defined(__APPLE__) && defined(__MACH__) || defined(__FreeBSD__) || \
defined(__OpenBSD__)
/* stdlib.h on FreeBSD and Apple's 10.5 and later SDKs will mangle the /* stdlib.h on FreeBSD and Apple's 10.5 and later SDKs will mangle the
* name of strtod. If it's included after strtod is redefined as * name of strtod. If it's included after strtod is redefined as
* gay_strtod, it will mangle the name of gay_strtod, which is * gay_strtod, it will mangle the name of gay_strtod, which is

5
deps/v8/src/factory.cc

@ -188,9 +188,8 @@ Handle<Script> Factory::NewScript(Handle<String> source) {
script->set_type(Smi::FromInt(Script::TYPE_NORMAL)); script->set_type(Smi::FromInt(Script::TYPE_NORMAL));
script->set_compilation_type(Smi::FromInt(Script::COMPILATION_TYPE_HOST)); script->set_compilation_type(Smi::FromInt(Script::COMPILATION_TYPE_HOST));
script->set_wrapper(*wrapper); script->set_wrapper(*wrapper);
script->set_line_ends_fixed_array(Heap::undefined_value()); script->set_line_ends(Heap::undefined_value());
script->set_line_ends_js_array(Heap::undefined_value()); script->set_eval_from_shared(Heap::undefined_value());
script->set_eval_from_function(Heap::undefined_value());
script->set_eval_from_instructions_offset(Smi::FromInt(0)); script->set_eval_from_instructions_offset(Smi::FromInt(0));
return script; return script;

37
deps/v8/src/fast-codegen.cc

@ -305,12 +305,15 @@ void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
Comment cmnt(masm_, "[ DoWhileStatement"); Comment cmnt(masm_, "[ DoWhileStatement");
increment_loop_depth(); increment_loop_depth();
Label body, exit; Label body, exit, stack_limit_hit, stack_check_success;
// Emit the test at the bottom of the loop.
__ bind(&body); __ bind(&body);
Visit(stmt->body()); Visit(stmt->body());
// Check stack before looping.
__ StackLimitCheck(&stack_limit_hit);
__ bind(&stack_check_success);
// We are not in an expression context because we have been compiling // We are not in an expression context because we have been compiling
// statements. Set up a test expression context for the condition. // statements. Set up a test expression context for the condition.
ASSERT_EQ(NULL, true_label_); ASSERT_EQ(NULL, true_label_);
@ -322,6 +325,11 @@ void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
true_label_ = NULL; true_label_ = NULL;
false_label_ = NULL; false_label_ = NULL;
__ bind(&stack_limit_hit);
StackCheckStub stack_stub;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
__ bind(&exit); __ bind(&exit);
decrement_loop_depth(); decrement_loop_depth();
@ -331,7 +339,7 @@ void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
Comment cmnt(masm_, "[ WhileStatement"); Comment cmnt(masm_, "[ WhileStatement");
increment_loop_depth(); increment_loop_depth();
Label test, body, exit; Label test, body, exit, stack_limit_hit, stack_check_success;
// Emit the test at the bottom of the loop. // Emit the test at the bottom of the loop.
__ jmp(&test); __ jmp(&test);
@ -340,6 +348,10 @@ void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
Visit(stmt->body()); Visit(stmt->body());
__ bind(&test); __ bind(&test);
// Check stack before looping.
__ StackLimitCheck(&stack_limit_hit);
__ bind(&stack_check_success);
// We are not in an expression context because we have been compiling // We are not in an expression context because we have been compiling
// statements. Set up a test expression context for the condition. // statements. Set up a test expression context for the condition.
ASSERT_EQ(NULL, true_label_); ASSERT_EQ(NULL, true_label_);
@ -351,6 +363,11 @@ void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
true_label_ = NULL; true_label_ = NULL;
false_label_ = NULL; false_label_ = NULL;
__ bind(&stack_limit_hit);
StackCheckStub stack_stub;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
__ bind(&exit); __ bind(&exit);
decrement_loop_depth(); decrement_loop_depth();
@ -359,7 +376,7 @@ void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
void FastCodeGenerator::VisitForStatement(ForStatement* stmt) { void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
Comment cmnt(masm_, "[ ForStatement"); Comment cmnt(masm_, "[ ForStatement");
Label test, body, exit; Label test, body, exit, stack_limit_hit, stack_check_success;
if (stmt->init() != NULL) Visit(stmt->init()); if (stmt->init() != NULL) Visit(stmt->init());
increment_loop_depth(); increment_loop_depth();
@ -367,9 +384,15 @@ void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
__ jmp(&test); __ jmp(&test);
__ bind(&body); __ bind(&body);
Visit(stmt->body()); Visit(stmt->body());
// Check stack before looping.
__ StackLimitCheck(&stack_limit_hit);
__ bind(&stack_check_success);
if (stmt->next() != NULL) Visit(stmt->next()); if (stmt->next() != NULL) Visit(stmt->next());
__ bind(&test); __ bind(&test);
if (stmt->cond() == NULL) { if (stmt->cond() == NULL) {
// For an empty test jump to the top of the loop. // For an empty test jump to the top of the loop.
__ jmp(&body); __ jmp(&body);
@ -378,6 +401,7 @@ void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
// statements. Set up a test expression context for the condition. // statements. Set up a test expression context for the condition.
ASSERT_EQ(NULL, true_label_); ASSERT_EQ(NULL, true_label_);
ASSERT_EQ(NULL, false_label_); ASSERT_EQ(NULL, false_label_);
true_label_ = &body; true_label_ = &body;
false_label_ = &exit; false_label_ = &exit;
ASSERT(stmt->cond()->context() == Expression::kTest); ASSERT(stmt->cond()->context() == Expression::kTest);
@ -386,6 +410,11 @@ void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
false_label_ = NULL; false_label_ = NULL;
} }
__ bind(&stack_limit_hit);
StackCheckStub stack_stub;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
__ bind(&exit); __ bind(&exit);
decrement_loop_depth(); decrement_loop_depth();
} }

13
deps/v8/src/fast-codegen.h

@ -56,14 +56,21 @@ class FastCodeGenerator: public AstVisitor {
private: private:
int SlotOffset(Slot* slot); int SlotOffset(Slot* slot);
void Move(Expression::Context destination, Register source); void Move(Expression::Context destination, Register source);
void Move(Expression::Context destination, Slot* source); void Move(Expression::Context destination, Slot* source, Register scratch);
void Move(Expression::Context destination, Literal* source); void Move(Expression::Context destination, Literal* source);
void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
void Move(Register dst, Slot* source);
// Templated to allow for Operand on intel and MemOperand on ARM.
template <typename MemoryLocation>
MemoryLocation CreateSlotOperand(Slot* slot, Register scratch);
// Drop the TOS, and store source to destination. // Drop the TOS, and store source to destination.
// If destination is TOS, just overwrite TOS with source. // If destination is TOS, just overwrite TOS with source.
void DropAndMove(Expression::Context destination, Register source); void DropAndMove(Expression::Context destination,
Register source,
int drop_count = 1);
// Test the JavaScript value in source as if in a test context, compile // Test the JavaScript value in source as if in a test context, compile
// control flow to a pair of labels. // control flow to a pair of labels.

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

@ -143,10 +143,12 @@ DEFINE_bool(debug_info, true, "add debug information to compiled functions")
DEFINE_bool(strict, false, "strict error checking") 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(fast_compiler, false, DEFINE_bool(fast_compiler, true,
"use the fast-mode compiler for some top-level code") "use the fast-mode compiler for some top-level code")
DEFINE_bool(trace_bailout, false, DEFINE_bool(trace_bailout, false,
"print reasons for failing to use fast compilation") "print reasons for failing to use fast compilation")
DEFINE_bool(always_fast_compiler, false,
"always try using the fast compiler")
// compilation-cache.cc // compilation-cache.cc
DEFINE_bool(compilation_cache, true, "enable compilation cache") DEFINE_bool(compilation_cache, true, "enable compilation cache")
@ -154,9 +156,9 @@ DEFINE_bool(compilation_cache, true, "enable compilation cache")
// debug.cc // debug.cc
DEFINE_bool(remote_debugging, false, "enable remote debugging") DEFINE_bool(remote_debugging, false, "enable remote debugging")
DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response") DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
DEFINE_bool(debugger_auto_break, false, DEFINE_bool(debugger_auto_break, true,
"automatically set the debug break flag when debugger commands are " "automatically set the debug break flag when debugger commands are "
"in the queue (experimental)") "in the queue")
// frames.cc // frames.cc
DEFINE_int(max_stack_trace_source_length, 300, DEFINE_int(max_stack_trace_source_length, 300,

20
deps/v8/src/global-handles.cc

@ -429,6 +429,26 @@ GlobalHandles::Node* GlobalHandles::head_ = NULL;
GlobalHandles::Node* GlobalHandles::first_free_ = NULL; GlobalHandles::Node* GlobalHandles::first_free_ = NULL;
GlobalHandles::Node* GlobalHandles::first_deallocated_ = NULL; GlobalHandles::Node* GlobalHandles::first_deallocated_ = NULL;
void GlobalHandles::RecordStats(HeapStats* stats) {
*stats->global_handle_count = 0;
*stats->weak_global_handle_count = 0;
*stats->pending_global_handle_count = 0;
*stats->near_death_global_handle_count = 0;
*stats->destroyed_global_handle_count = 0;
for (Node* current = head_; current != NULL; current = current->next()) {
*stats->global_handle_count++;
if (current->state_ == Node::WEAK) {
*stats->weak_global_handle_count++;
} else if (current->state_ == Node::PENDING) {
*stats->pending_global_handle_count++;
} else if (current->state_ == Node::NEAR_DEATH) {
*stats->near_death_global_handle_count++;
} else if (current->state_ == Node::DESTROYED) {
*stats->destroyed_global_handle_count++;
}
}
}
#ifdef DEBUG #ifdef DEBUG
void GlobalHandles::PrintStats() { void GlobalHandles::PrintStats() {

2
deps/v8/src/global-handles.h

@ -78,6 +78,8 @@ class GlobalHandles : public AllStatic {
// Returns the current number of weak handles. // Returns the current number of weak handles.
static int NumberOfWeakHandles() { return number_of_weak_handles_; } static int NumberOfWeakHandles() { return number_of_weak_handles_; }
static void RecordStats(HeapStats* stats);
// Returns the current number of weak handles to global objects. // Returns the current number of weak handles to global objects.
// These handles are also included in NumberOfWeakHandles(). // These handles are also included in NumberOfWeakHandles().
static int NumberOfGlobalObjectWeakHandles() { static int NumberOfGlobalObjectWeakHandles() {

48
deps/v8/src/handles.cc

@ -429,12 +429,12 @@ Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
// Init line_ends array with code positions of line ends inside script // Init line_ends array with code positions of line ends inside script
// source. // source.
void InitScriptLineEnds(Handle<Script> script) { void InitScriptLineEnds(Handle<Script> script) {
if (!script->line_ends_fixed_array()->IsUndefined()) return; if (!script->line_ends()->IsUndefined()) return;
if (!script->source()->IsString()) { if (!script->source()->IsString()) {
ASSERT(script->source()->IsUndefined()); ASSERT(script->source()->IsUndefined());
script->set_line_ends_fixed_array(*(Factory::NewFixedArray(0))); script->set_line_ends(*(Factory::NewFixedArray(0)));
ASSERT(script->line_ends_fixed_array()->IsFixedArray()); ASSERT(script->line_ends()->IsFixedArray());
return; return;
} }
@ -467,8 +467,8 @@ void InitScriptLineEnds(Handle<Script> script) {
} }
ASSERT(array_index == line_count); ASSERT(array_index == line_count);
script->set_line_ends_fixed_array(*array); script->set_line_ends(*array);
ASSERT(script->line_ends_fixed_array()->IsFixedArray()); ASSERT(script->line_ends()->IsFixedArray());
} }
@ -477,7 +477,7 @@ int GetScriptLineNumber(Handle<Script> script, int code_pos) {
InitScriptLineEnds(script); InitScriptLineEnds(script);
AssertNoAllocation no_allocation; AssertNoAllocation no_allocation;
FixedArray* line_ends_array = FixedArray* line_ends_array =
FixedArray::cast(script->line_ends_fixed_array()); FixedArray::cast(script->line_ends());
const int line_ends_len = line_ends_array->length(); const int line_ends_len = line_ends_array->length();
int line = -1; int line = -1;
@ -548,6 +548,12 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
KeyCollectionType type) { KeyCollectionType type) {
Handle<FixedArray> content = Factory::empty_fixed_array(); Handle<FixedArray> content = Factory::empty_fixed_array();
Handle<JSObject> arguments_boilerplate =
Handle<JSObject>(
Top::context()->global_context()->arguments_boilerplate());
Handle<JSFunction> arguments_function =
Handle<JSFunction>(
JSFunction::cast(arguments_boilerplate->map()->constructor()));
// Only collect keys if access is permitted. // Only collect keys if access is permitted.
for (Handle<Object> p = object; for (Handle<Object> p = object;
@ -577,8 +583,21 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
} }
// Compute the property keys. // We can cache the computed property keys if access checks are
content = UnionOfKeys(content, GetEnumPropertyKeys(current)); // not needed and no interceptors are involved.
//
// We do not use the cache if the object has elements and
// therefore it does not make sense to cache the property names
// for arguments objects. Arguments objects will always have
// elements.
bool cache_enum_keys =
((current->map()->constructor() != *arguments_function) &&
!current->IsAccessCheckNeeded() &&
!current->HasNamedInterceptor() &&
!current->HasIndexedInterceptor());
// Compute the property keys and cache them if possible.
content =
UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys));
// Add the property keys from the interceptor. // Add the property keys from the interceptor.
if (current->HasNamedInterceptor()) { if (current->HasNamedInterceptor()) {
@ -605,7 +624,8 @@ Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
} }
Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object) { Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
bool cache_result) {
int index = 0; int index = 0;
if (object->HasFastProperties()) { if (object->HasFastProperties()) {
if (object->map()->instance_descriptors()->HasEnumCache()) { if (object->map()->instance_descriptors()->HasEnumCache()) {
@ -628,10 +648,12 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object) {
} }
} }
(*storage)->SortPairs(*sort_array, sort_array->length()); (*storage)->SortPairs(*sort_array, sort_array->length());
Handle<FixedArray> bridge_storage = if (cache_result) {
Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength); Handle<FixedArray> bridge_storage =
DescriptorArray* desc = object->map()->instance_descriptors(); Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
desc->SetEnumCache(*bridge_storage, *storage); DescriptorArray* desc = object->map()->instance_descriptors();
desc->SetEnumCache(*bridge_storage, *storage);
}
ASSERT(storage->length() == index); ASSERT(storage->length() == index);
return storage; return storage;
} else { } else {

3
deps/v8/src/handles.h

@ -277,7 +277,8 @@ enum KeyCollectionType { LOCAL_ONLY, INCLUDE_PROTOS };
Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
KeyCollectionType type); KeyCollectionType type);
Handle<JSArray> GetKeysFor(Handle<JSObject> object); Handle<JSArray> GetKeysFor(Handle<JSObject> object);
Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object); Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
bool cache_result);
// Computes the union of keys and return the result. // Computes the union of keys and return the result.
// Used for implementing "for (n in object) { }" // Used for implementing "for (n in object) { }"

4
deps/v8/src/heap-inl.h

@ -41,10 +41,10 @@ int Heap::MaxObjectSizeInPagedSpace() {
Object* Heap::AllocateSymbol(Vector<const char> str, Object* Heap::AllocateSymbol(Vector<const char> str,
int chars, int chars,
uint32_t length_field) { uint32_t hash_field) {
unibrow::Utf8InputBuffer<> buffer(str.start(), unibrow::Utf8InputBuffer<> buffer(str.start(),
static_cast<unsigned>(str.length())); static_cast<unsigned>(str.length()));
return AllocateInternalSymbol(&buffer, chars, length_field); return AllocateInternalSymbol(&buffer, chars, hash_field);
} }

193
deps/v8/src/heap.cc

@ -1187,34 +1187,14 @@ bool Heap::CreateInitialMaps() {
roots_[entry.index] = Map::cast(obj); roots_[entry.index] = Map::cast(obj);
} }
obj = AllocateMap(SHORT_STRING_TYPE, SeqTwoByteString::kAlignedSize); obj = AllocateMap(STRING_TYPE, SeqTwoByteString::kAlignedSize);
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
set_undetectable_short_string_map(Map::cast(obj)); set_undetectable_string_map(Map::cast(obj));
Map::cast(obj)->set_is_undetectable(); Map::cast(obj)->set_is_undetectable();
obj = AllocateMap(MEDIUM_STRING_TYPE, SeqTwoByteString::kAlignedSize); obj = AllocateMap(ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
set_undetectable_medium_string_map(Map::cast(obj)); set_undetectable_ascii_string_map(Map::cast(obj));
Map::cast(obj)->set_is_undetectable();
obj = AllocateMap(LONG_STRING_TYPE, SeqTwoByteString::kAlignedSize);
if (obj->IsFailure()) return false;
set_undetectable_long_string_map(Map::cast(obj));
Map::cast(obj)->set_is_undetectable();
obj = AllocateMap(SHORT_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
if (obj->IsFailure()) return false;
set_undetectable_short_ascii_string_map(Map::cast(obj));
Map::cast(obj)->set_is_undetectable();
obj = AllocateMap(MEDIUM_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
if (obj->IsFailure()) return false;
set_undetectable_medium_ascii_string_map(Map::cast(obj));
Map::cast(obj)->set_is_undetectable();
obj = AllocateMap(LONG_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
if (obj->IsFailure()) return false;
set_undetectable_long_ascii_string_map(Map::cast(obj));
Map::cast(obj)->set_is_undetectable(); Map::cast(obj)->set_is_undetectable();
obj = AllocateMap(BYTE_ARRAY_TYPE, ByteArray::kAlignedSize); obj = AllocateMap(BYTE_ARRAY_TYPE, ByteArray::kAlignedSize);
@ -1839,10 +1819,19 @@ Object* Heap::AllocateConsString(String* first, String* second) {
// Copy the characters into the new object. // Copy the characters into the new object.
char* dest = SeqAsciiString::cast(result)->GetChars(); char* dest = SeqAsciiString::cast(result)->GetChars();
// Copy first part. // Copy first part.
char* src = SeqAsciiString::cast(first)->GetChars(); const char* src;
if (first->IsExternalString()) {
src = ExternalAsciiString::cast(first)->resource()->data();
} else {
src = SeqAsciiString::cast(first)->GetChars();
}
for (int i = 0; i < first_length; i++) *dest++ = src[i]; for (int i = 0; i < first_length; i++) *dest++ = src[i];
// Copy second part. // Copy second part.
src = SeqAsciiString::cast(second)->GetChars(); if (second->IsExternalString()) {
src = ExternalAsciiString::cast(second)->resource()->data();
} else {
src = SeqAsciiString::cast(second)->GetChars();
}
for (int i = 0; i < second_length; i++) *dest++ = src[i]; for (int i = 0; i < second_length; i++) *dest++ = src[i];
return result; return result;
} else { } else {
@ -1856,26 +1845,17 @@ Object* Heap::AllocateConsString(String* first, String* second) {
} }
} }
Map* map; Map* map = is_ascii ? cons_ascii_string_map() : cons_string_map();
if (length <= String::kMaxShortSize) {
map = is_ascii ? short_cons_ascii_string_map()
: short_cons_string_map();
} else if (length <= String::kMaxMediumSize) {
map = is_ascii ? medium_cons_ascii_string_map()
: medium_cons_string_map();
} else {
map = is_ascii ? long_cons_ascii_string_map()
: long_cons_string_map();
}
Object* result = Allocate(map, Object* result = Allocate(map,
always_allocate() ? OLD_POINTER_SPACE : NEW_SPACE); always_allocate() ? OLD_POINTER_SPACE : NEW_SPACE);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
ConsString* cons_string = ConsString::cast(result); ConsString* cons_string = ConsString::cast(result);
WriteBarrierMode mode = cons_string->GetWriteBarrierMode(); WriteBarrierMode mode = cons_string->GetWriteBarrierMode();
cons_string->set_length(length);
cons_string->set_hash_field(String::kEmptyHashField);
cons_string->set_first(first, mode); cons_string->set_first(first, mode);
cons_string->set_second(second, mode); cons_string->set_second(second, mode);
cons_string->set_length(length);
return result; return result;
} }
@ -1925,25 +1905,20 @@ Object* Heap::AllocateSubString(String* buffer,
Object* Heap::AllocateExternalStringFromAscii( Object* Heap::AllocateExternalStringFromAscii(
ExternalAsciiString::Resource* resource) { ExternalAsciiString::Resource* resource) {
Map* map;
size_t length = resource->length(); size_t length = resource->length();
if (length <= static_cast<size_t>(String::kMaxShortSize)) { if (length > static_cast<size_t>(String::kMaxLength)) {
map = short_external_ascii_string_map();
} else if (length <= static_cast<size_t>(String::kMaxMediumSize)) {
map = medium_external_ascii_string_map();
} else if (length <= static_cast<size_t>(String::kMaxLength)) {
map = long_external_ascii_string_map();
} else {
Top::context()->mark_out_of_memory(); Top::context()->mark_out_of_memory();
return Failure::OutOfMemoryException(); return Failure::OutOfMemoryException();
} }
Map* map = external_ascii_string_map();
Object* result = Allocate(map, Object* result = Allocate(map,
always_allocate() ? OLD_DATA_SPACE : NEW_SPACE); always_allocate() ? OLD_DATA_SPACE : NEW_SPACE);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
ExternalAsciiString* external_string = ExternalAsciiString::cast(result); ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
external_string->set_length(static_cast<int>(length)); external_string->set_length(static_cast<int>(length));
external_string->set_hash_field(String::kEmptyHashField);
external_string->set_resource(resource); external_string->set_resource(resource);
return result; return result;
@ -1957,13 +1932,15 @@ Object* Heap::AllocateExternalStringFromTwoByte(
Top::context()->mark_out_of_memory(); Top::context()->mark_out_of_memory();
return Failure::OutOfMemoryException(); return Failure::OutOfMemoryException();
} }
Map* map = ExternalTwoByteString::StringMap(static_cast<int>(length));
Map* map = Heap::external_string_map();
Object* result = Allocate(map, Object* result = Allocate(map,
always_allocate() ? OLD_DATA_SPACE : NEW_SPACE); always_allocate() ? OLD_DATA_SPACE : NEW_SPACE);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result); ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
external_string->set_length(static_cast<int>(length)); external_string->set_length(static_cast<int>(length));
external_string->set_hash_field(String::kEmptyHashField);
external_string->set_resource(resource); external_string->set_resource(resource);
return result; return result;
@ -2604,48 +2581,12 @@ Map* Heap::SymbolMapForString(String* string) {
// Find the corresponding symbol map for strings. // Find the corresponding symbol map for strings.
Map* map = string->map(); Map* map = string->map();
if (map == ascii_string_map()) return ascii_symbol_map();
if (map == short_ascii_string_map()) return short_ascii_symbol_map(); if (map == string_map()) return symbol_map();
if (map == medium_ascii_string_map()) return medium_ascii_symbol_map(); if (map == cons_string_map()) return cons_symbol_map();
if (map == long_ascii_string_map()) return long_ascii_symbol_map(); if (map == cons_ascii_string_map()) return cons_ascii_symbol_map();
if (map == external_string_map()) return external_symbol_map();
if (map == short_string_map()) return short_symbol_map(); if (map == external_ascii_string_map()) return external_ascii_symbol_map();
if (map == medium_string_map()) return medium_symbol_map();
if (map == long_string_map()) return long_symbol_map();
if (map == short_cons_string_map()) return short_cons_symbol_map();
if (map == medium_cons_string_map()) return medium_cons_symbol_map();
if (map == long_cons_string_map()) return long_cons_symbol_map();
if (map == short_cons_ascii_string_map()) {
return short_cons_ascii_symbol_map();
}
if (map == medium_cons_ascii_string_map()) {
return medium_cons_ascii_symbol_map();
}
if (map == long_cons_ascii_string_map()) {
return long_cons_ascii_symbol_map();
}
if (map == short_external_string_map()) {
return short_external_symbol_map();
}
if (map == medium_external_string_map()) {
return medium_external_symbol_map();
}
if (map == long_external_string_map()) {
return long_external_symbol_map();
}
if (map == short_external_ascii_string_map()) {
return short_external_ascii_symbol_map();
}
if (map == medium_external_ascii_string_map()) {
return medium_external_ascii_symbol_map();
}
if (map == long_external_ascii_string_map()) {
return long_external_ascii_symbol_map();
}
// No match found. // No match found.
return NULL; return NULL;
@ -2654,7 +2595,7 @@ Map* Heap::SymbolMapForString(String* string) {
Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
int chars, int chars,
uint32_t length_field) { uint32_t hash_field) {
// Ensure the chars matches the number of characters in the buffer. // Ensure the chars matches the number of characters in the buffer.
ASSERT(static_cast<unsigned>(chars) == buffer->Length()); ASSERT(static_cast<unsigned>(chars) == buffer->Length());
// Determine whether the string is ascii. // Determine whether the string is ascii.
@ -2669,22 +2610,10 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
Map* map; Map* map;
if (is_ascii) { if (is_ascii) {
if (chars <= String::kMaxShortSize) { map = ascii_symbol_map();
map = short_ascii_symbol_map();
} else if (chars <= String::kMaxMediumSize) {
map = medium_ascii_symbol_map();
} else {
map = long_ascii_symbol_map();
}
size = SeqAsciiString::SizeFor(chars); size = SeqAsciiString::SizeFor(chars);
} else { } else {
if (chars <= String::kMaxShortSize) { map = symbol_map();
map = short_symbol_map();
} else if (chars <= String::kMaxMediumSize) {
map = medium_symbol_map();
} else {
map = long_symbol_map();
}
size = SeqTwoByteString::SizeFor(chars); size = SeqTwoByteString::SizeFor(chars);
} }
@ -2695,9 +2624,10 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
reinterpret_cast<HeapObject*>(result)->set_map(map); reinterpret_cast<HeapObject*>(result)->set_map(map);
// The hash value contains the length of the string. // Set length and hash fields of the allocated string.
String* answer = String::cast(result); String* answer = String::cast(result);
answer->set_length_field(length_field); answer->set_length(chars);
answer->set_hash_field(hash_field);
ASSERT_EQ(size, answer->Size()); ASSERT_EQ(size, answer->Size());
@ -2728,19 +2658,10 @@ Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
} }
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
// Determine the map based on the string's length.
Map* map;
if (length <= String::kMaxShortSize) {
map = short_ascii_string_map();
} else if (length <= String::kMaxMediumSize) {
map = medium_ascii_string_map();
} else {
map = long_ascii_string_map();
}
// Partially initialize the object. // Partially initialize the object.
HeapObject::cast(result)->set_map(map); HeapObject::cast(result)->set_map(ascii_string_map());
String::cast(result)->set_length(length); String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField);
ASSERT_EQ(size, HeapObject::cast(result)->Size()); ASSERT_EQ(size, HeapObject::cast(result)->Size());
return result; return result;
} }
@ -2765,19 +2686,10 @@ Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) {
} }
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
// Determine the map based on the string's length.
Map* map;
if (length <= String::kMaxShortSize) {
map = short_string_map();
} else if (length <= String::kMaxMediumSize) {
map = medium_string_map();
} else {
map = long_string_map();
}
// Partially initialize the object. // Partially initialize the object.
HeapObject::cast(result)->set_map(map); HeapObject::cast(result)->set_map(string_map());
String::cast(result)->set_length(length); String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField);
ASSERT_EQ(size, HeapObject::cast(result)->Size()); ASSERT_EQ(size, HeapObject::cast(result)->Size());
return result; return result;
} }
@ -2998,6 +2910,11 @@ bool Heap::IdleNotification() {
last_gc_count = gc_count_; last_gc_count = gc_count_;
} else if (number_idle_notifications == kIdlesBeforeMarkSweep) { } else if (number_idle_notifications == kIdlesBeforeMarkSweep) {
// Before doing the mark-sweep collections we clear the
// compilation cache to avoid hanging on to source code and
// generated code for cached functions.
CompilationCache::Clear();
CollectAllGarbage(false); CollectAllGarbage(false);
new_space_.Shrink(); new_space_.Shrink();
last_gc_count = gc_count_; last_gc_count = gc_count_;
@ -3356,6 +3273,26 @@ bool Heap::ConfigureHeapDefault() {
} }
void Heap::RecordStats(HeapStats* stats) {
*stats->start_marker = 0xDECADE00;
*stats->end_marker = 0xDECADE01;
*stats->new_space_size = new_space_.Size();
*stats->new_space_capacity = new_space_.Capacity();
*stats->old_pointer_space_size = old_pointer_space_->Size();
*stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
*stats->old_data_space_size = old_data_space_->Size();
*stats->old_data_space_capacity = old_data_space_->Capacity();
*stats->code_space_size = code_space_->Size();
*stats->code_space_capacity = code_space_->Capacity();
*stats->map_space_size = map_space_->Size();
*stats->map_space_capacity = map_space_->Capacity();
*stats->cell_space_size = cell_space_->Size();
*stats->cell_space_capacity = cell_space_->Capacity();
*stats->lo_space_size = lo_space_->Size();
GlobalHandles::RecordStats(stats);
}
int Heap::PromotedSpaceSize() { int Heap::PromotedSpaceSize() {
return old_pointer_space_->Size() return old_pointer_space_->Size()
+ old_data_space_->Size() + old_data_space_->Size()

95
deps/v8/src/heap.h

@ -59,50 +59,20 @@ namespace internal {
V(Object, termination_exception, TerminationException) \ V(Object, termination_exception, TerminationException) \
V(Map, hash_table_map, HashTableMap) \ V(Map, hash_table_map, HashTableMap) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \ V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(Map, short_string_map, ShortStringMap) \ V(Map, string_map, StringMap) \
V(Map, medium_string_map, MediumStringMap) \ V(Map, ascii_string_map, AsciiStringMap) \
V(Map, long_string_map, LongStringMap) \ V(Map, symbol_map, SymbolMap) \
V(Map, short_ascii_string_map, ShortAsciiStringMap) \ V(Map, ascii_symbol_map, AsciiSymbolMap) \
V(Map, medium_ascii_string_map, MediumAsciiStringMap) \ V(Map, cons_symbol_map, ConsSymbolMap) \
V(Map, long_ascii_string_map, LongAsciiStringMap) \ V(Map, cons_ascii_symbol_map, ConsAsciiSymbolMap) \
V(Map, short_symbol_map, ShortSymbolMap) \ V(Map, external_symbol_map, ExternalSymbolMap) \
V(Map, medium_symbol_map, MediumSymbolMap) \ V(Map, external_ascii_symbol_map, ExternalAsciiSymbolMap) \
V(Map, long_symbol_map, LongSymbolMap) \ V(Map, cons_string_map, ConsStringMap) \
V(Map, short_ascii_symbol_map, ShortAsciiSymbolMap) \ V(Map, cons_ascii_string_map, ConsAsciiStringMap) \
V(Map, medium_ascii_symbol_map, MediumAsciiSymbolMap) \ V(Map, external_string_map, ExternalStringMap) \
V(Map, long_ascii_symbol_map, LongAsciiSymbolMap) \ V(Map, external_ascii_string_map, ExternalAsciiStringMap) \
V(Map, short_cons_symbol_map, ShortConsSymbolMap) \ V(Map, undetectable_string_map, UndetectableStringMap) \
V(Map, medium_cons_symbol_map, MediumConsSymbolMap) \ V(Map, undetectable_ascii_string_map, UndetectableAsciiStringMap) \
V(Map, long_cons_symbol_map, LongConsSymbolMap) \
V(Map, short_cons_ascii_symbol_map, ShortConsAsciiSymbolMap) \
V(Map, medium_cons_ascii_symbol_map, MediumConsAsciiSymbolMap) \
V(Map, long_cons_ascii_symbol_map, LongConsAsciiSymbolMap) \
V(Map, short_external_symbol_map, ShortExternalSymbolMap) \
V(Map, medium_external_symbol_map, MediumExternalSymbolMap) \
V(Map, long_external_symbol_map, LongExternalSymbolMap) \
V(Map, short_external_ascii_symbol_map, ShortExternalAsciiSymbolMap) \
V(Map, medium_external_ascii_symbol_map, MediumExternalAsciiSymbolMap) \
V(Map, long_external_ascii_symbol_map, LongExternalAsciiSymbolMap) \
V(Map, short_cons_string_map, ShortConsStringMap) \
V(Map, medium_cons_string_map, MediumConsStringMap) \
V(Map, long_cons_string_map, LongConsStringMap) \
V(Map, short_cons_ascii_string_map, ShortConsAsciiStringMap) \
V(Map, medium_cons_ascii_string_map, MediumConsAsciiStringMap) \
V(Map, long_cons_ascii_string_map, LongConsAsciiStringMap) \
V(Map, short_external_string_map, ShortExternalStringMap) \
V(Map, medium_external_string_map, MediumExternalStringMap) \
V(Map, long_external_string_map, LongExternalStringMap) \
V(Map, short_external_ascii_string_map, ShortExternalAsciiStringMap) \
V(Map, medium_external_ascii_string_map, MediumExternalAsciiStringMap) \
V(Map, long_external_ascii_string_map, LongExternalAsciiStringMap) \
V(Map, undetectable_short_string_map, UndetectableShortStringMap) \
V(Map, undetectable_medium_string_map, UndetectableMediumStringMap) \
V(Map, undetectable_long_string_map, UndetectableLongStringMap) \
V(Map, undetectable_short_ascii_string_map, UndetectableShortAsciiStringMap) \
V(Map, \
undetectable_medium_ascii_string_map, \
UndetectableMediumAsciiStringMap) \
V(Map, undetectable_long_ascii_string_map, UndetectableLongAsciiStringMap) \
V(Map, pixel_array_map, PixelArrayMap) \ V(Map, pixel_array_map, PixelArrayMap) \
V(Map, external_byte_array_map, ExternalByteArrayMap) \ V(Map, external_byte_array_map, ExternalByteArrayMap) \
V(Map, external_unsigned_byte_array_map, ExternalUnsignedByteArrayMap) \ V(Map, external_unsigned_byte_array_map, ExternalUnsignedByteArrayMap) \
@ -219,6 +189,7 @@ namespace internal {
// Forward declaration of the GCTracer class. // Forward declaration of the GCTracer class.
class GCTracer; class GCTracer;
class HeapStats;
// The all static Heap captures the interface to the global object heap. // The all static Heap captures the interface to the global object heap.
@ -409,11 +380,11 @@ class Heap : public AllStatic {
// Please note this function does not perform a garbage collection. // Please note this function does not perform a garbage collection.
static inline Object* AllocateSymbol(Vector<const char> str, static inline Object* AllocateSymbol(Vector<const char> str,
int chars, int chars,
uint32_t length_field); uint32_t hash_field);
static Object* AllocateInternalSymbol(unibrow::CharacterStream* buffer, static Object* AllocateInternalSymbol(unibrow::CharacterStream* buffer,
int chars, int chars,
uint32_t length_field); uint32_t hash_field);
static Object* AllocateExternalSymbol(Vector<const char> str, static Object* AllocateExternalSymbol(Vector<const char> str,
int chars); int chars);
@ -895,6 +866,8 @@ class Heap : public AllStatic {
static RootListIndex RootIndexForExternalArrayType( static RootListIndex RootIndexForExternalArrayType(
ExternalArrayType array_type); ExternalArrayType array_type);
static void RecordStats(HeapStats* stats);
private: private:
static int reserved_semispace_size_; static int reserved_semispace_size_;
static int max_semispace_size_; static int max_semispace_size_;
@ -910,7 +883,10 @@ class Heap : public AllStatic {
static int linear_allocation_scope_depth_; static int linear_allocation_scope_depth_;
static bool context_disposed_pending_; static bool context_disposed_pending_;
static const int kMaxMapSpaceSize = 8*MB; // The number of MapSpace pages is limited by the way we pack
// Map pointers during GC.
static const int kMaxMapSpaceSize =
(1 << MapWord::kMapPageIndexBits) * Page::kPageSize;
#if defined(V8_TARGET_ARCH_X64) #if defined(V8_TARGET_ARCH_X64)
static const int kMaxObjectSizeInNewSpace = 512*KB; static const int kMaxObjectSizeInNewSpace = 512*KB;
@ -1127,6 +1103,31 @@ class Heap : public AllStatic {
}; };
class HeapStats {
public:
int *start_marker;
int *new_space_size;
int *new_space_capacity;
int *old_pointer_space_size;
int *old_pointer_space_capacity;
int *old_data_space_size;
int *old_data_space_capacity;
int *code_space_size;
int *code_space_capacity;
int *map_space_size;
int *map_space_capacity;
int *cell_space_size;
int *cell_space_capacity;
int *lo_space_size;
int *global_handle_count;
int *weak_global_handle_count;
int *pending_global_handle_count;
int *near_death_global_handle_count;
int *destroyed_global_handle_count;
int *end_marker;
};
class AlwaysAllocateScope { class AlwaysAllocateScope {
public: public:
AlwaysAllocateScope() { AlwaysAllocateScope() {

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

@ -464,6 +464,8 @@ class Assembler : public Malloced {
// to jump to. // to jump to.
static const int kPatchReturnSequenceAddressOffset = 1; // JMP imm32. static const int kPatchReturnSequenceAddressOffset = 1; // JMP imm32.
static const int kCallInstructionLength = 5;
static const int kJSReturnSequenceLength = 6;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Code generation // Code generation

312
deps/v8/src/ia32/codegen-ia32.cc

@ -2490,7 +2490,7 @@ void CodeGenerator::GenerateReturnSequence(Result* return_value) {
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
// Check that the size of the code used for returning matches what is // Check that the size of the code used for returning matches what is
// expected by the debugger. // expected by the debugger.
ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, ASSERT_EQ(Assembler::kJSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif #endif
} }
@ -3056,13 +3056,59 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
jsobject.Bind(); jsobject.Bind();
// Get the set of properties (as a FixedArray or Map). // Get the set of properties (as a FixedArray or Map).
// eax: value to be iterated over // eax: value to be iterated over
frame_->EmitPush(eax); // push the object being iterated over (slot 4) frame_->EmitPush(eax); // Push the object being iterated over.
// Check cache validity in generated code. This is a fast case for
// the JSObject::IsSimpleEnum cache validity checks. If we cannot
// guarantee cache validity, call the runtime system to check cache
// validity or get the property names in a fixed array.
JumpTarget call_runtime;
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
JumpTarget check_prototype;
JumpTarget use_cache;
__ mov(ecx, eax);
loop.Bind();
// Check that there are no elements.
__ mov(edx, FieldOperand(ecx, JSObject::kElementsOffset));
__ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
call_runtime.Branch(not_equal);
// Check that instance descriptors are not empty so that we can
// check for an enum cache. Leave the map in ebx for the subsequent
// prototype load.
__ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
__ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
__ cmp(Operand(edx), Immediate(Factory::empty_descriptor_array()));
call_runtime.Branch(equal);
// Check that there in an enum cache in the non-empty instance
// descriptors. This is the case if the next enumeration index
// field does not contain a smi.
__ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
__ test(edx, Immediate(kSmiTagMask));
call_runtime.Branch(zero);
// For all objects but the receiver, check that the cache is empty.
__ cmp(ecx, Operand(eax));
check_prototype.Branch(equal);
__ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
__ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
call_runtime.Branch(not_equal);
check_prototype.Bind();
// Load the prototype from the map and loop if non-null.
__ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
__ cmp(Operand(ecx), Immediate(Factory::null_value()));
loop.Branch(not_equal);
// The enum cache is valid. Load the map of the object being
// iterated over and use the cache for the iteration.
__ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
use_cache.Jump();
call_runtime.Bind();
// Call the runtime to get the property names for the object.
frame_->EmitPush(eax); // push the Object (slot 4) for the runtime call frame_->EmitPush(eax); // push the Object (slot 4) for the runtime call
frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
// If we got a Map, we can do a fast modification check. // If we got a map from the runtime call, we can do a fast
// Otherwise, we got a FixedArray, and we have to do a slow check. // modification check. Otherwise, we got a fixed array, and we have
// to do a slow check.
// eax: map or fixed array (result from call to // eax: map or fixed array (result from call to
// Runtime::kGetPropertyNamesFast) // Runtime::kGetPropertyNamesFast)
__ mov(edx, Operand(eax)); __ mov(edx, Operand(eax));
@ -3070,9 +3116,13 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
__ cmp(ecx, Factory::meta_map()); __ cmp(ecx, Factory::meta_map());
fixed_array.Branch(not_equal); fixed_array.Branch(not_equal);
use_cache.Bind();
// Get enum cache // Get enum cache
// eax: map (result from call to Runtime::kGetPropertyNamesFast) // eax: map (either the result from a call to
// Runtime::kGetPropertyNamesFast or has been fetched directly from
// the object)
__ mov(ecx, Operand(eax)); __ mov(ecx, Operand(eax));
__ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset)); __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset));
// Get the bridge array held in the enumeration index field. // Get the bridge array held in the enumeration index field.
__ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
@ -4777,18 +4827,8 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
__ test(ecx, Immediate(kIsNotStringMask)); __ test(ecx, Immediate(kIsNotStringMask));
__ j(not_zero, &slow_case); __ j(not_zero, &slow_case);
// Here we make assumptions about the tag values and the shifts needed.
// See the comment in objects.h.
ASSERT(kLongStringTag == 0);
ASSERT(kMediumStringTag + String::kLongLengthShift ==
String::kMediumLengthShift);
ASSERT(kShortStringTag + String::kLongLengthShift ==
String::kShortLengthShift);
__ and_(ecx, kStringSizeMask);
__ add(Operand(ecx), Immediate(String::kLongLengthShift));
// Fetch the length field into the temporary register. // Fetch the length field into the temporary register.
__ mov(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset)); __ mov(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset));
__ shr_cl(temp.reg());
// Check for index out of range. // Check for index out of range.
__ cmp(index.reg(), Operand(temp.reg())); __ cmp(index.reg(), Operand(temp.reg()));
__ j(greater_equal, &slow_case); __ j(greater_equal, &slow_case);
@ -5222,6 +5262,18 @@ void CodeGenerator::GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
ASSERT_EQ(2, args->length());
Load(args->at(0));
Load(args->at(1));
StringAddStub stub(NO_STRING_ADD_FLAGS);
Result answer = frame_->CallStub(&stub, 2);
frame_->Push(&answer);
}
void CodeGenerator::VisitCallRuntime(CallRuntime* node) { void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
if (CheckForInlineRuntimeCall(node)) { if (CheckForInlineRuntimeCall(node)) {
return; return;
@ -6502,11 +6554,8 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
// String value => false iff empty. // String value => false iff empty.
__ cmp(ecx, FIRST_NONSTRING_TYPE); __ cmp(ecx, FIRST_NONSTRING_TYPE);
__ j(above_equal, &not_string); __ j(above_equal, &not_string);
__ and_(ecx, kStringSizeMask);
__ cmp(ecx, kShortStringTag);
__ j(not_equal, &true_result); // Empty string is always short.
__ mov(edx, FieldOperand(eax, String::kLengthOffset)); __ mov(edx, FieldOperand(eax, String::kLengthOffset));
__ shr(edx, String::kShortLengthShift); __ test(edx, Operand(edx));
__ j(zero, &false_result); __ j(zero, &false_result);
__ jmp(&true_result); __ jmp(&true_result);
@ -7042,7 +7091,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
switch (op_) { switch (op_) {
case Token::ADD: { case Token::ADD: {
// Test for string arguments before calling runtime. // Test for string arguments before calling runtime.
Label not_strings, both_strings, not_string1, string1; Label not_strings, not_string1, string1;
Result answer; Result answer;
__ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument.
__ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument.
@ -7057,8 +7106,9 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
__ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx); __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx);
__ j(above_equal, &string1); __ j(above_equal, &string1);
// First and second argument are strings. // First and second argument are strings. Jump to the string add stub.
__ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); StringAddStub stub(NO_STRING_CHECK_IN_STUB);
__ TailCallStub(&stub);
// Only first argument is a string. // Only first argument is a string.
__ bind(&string1); __ bind(&string1);
@ -8185,6 +8235,224 @@ int CompareStub::MinorKey() {
return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0);
} }
void StringAddStub::Generate(MacroAssembler* masm) {
Label string_add_runtime;
// Load the two arguments.
__ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument.
__ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument.
// Make sure that both arguments are strings if not known in advance.
if (string_check_) {
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &string_add_runtime);
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx);
__ j(above_equal, &string_add_runtime);
// First argument is a a string, test second.
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &string_add_runtime);
__ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx);
__ j(above_equal, &string_add_runtime);
}
// Both arguments are strings.
// eax: first string
// edx: second string
// Check if either of the strings are empty. In that case return the other.
Label second_not_zero_length, both_not_zero_length;
__ mov(ecx, FieldOperand(edx, String::kLengthOffset));
__ test(ecx, Operand(ecx));
__ j(not_zero, &second_not_zero_length);
// Second string is empty, result is first string which is already in eax.
__ IncrementCounter(&Counters::string_add_native, 1);
__ ret(2 * kPointerSize);
__ bind(&second_not_zero_length);
__ mov(ebx, FieldOperand(eax, String::kLengthOffset));
__ test(ebx, Operand(ebx));
__ j(not_zero, &both_not_zero_length);
// First string is empty, result is second string which is in edx.
__ mov(eax, edx);
__ IncrementCounter(&Counters::string_add_native, 1);
__ ret(2 * kPointerSize);
// Both strings are non-empty.
// eax: first string
// ebx: length of first string
// ecx: length of second string
// edx: second string
// Look at the length of the result of adding the two strings.
Label string_add_flat_result;
__ bind(&both_not_zero_length);
__ add(ebx, Operand(ecx));
// Use the runtime system when adding two one character strings, as it
// contains optimizations for this specific case using the symbol table.
__ cmp(ebx, 2);
__ j(equal, &string_add_runtime);
// Check if resulting string will be flat.
__ cmp(ebx, String::kMinNonFlatLength);
__ j(below, &string_add_flat_result);
// Handle exceptionally long strings in the runtime system.
ASSERT((String::kMaxLength & 0x80000000) == 0);
__ cmp(ebx, String::kMaxLength);
__ j(above, &string_add_runtime);
// If result is not supposed to be flat allocate a cons string object. If both
// strings are ascii the result is an ascii cons string.
Label non_ascii, allocated;
__ mov(edi, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset));
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
__ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
__ and_(ecx, Operand(edi));
__ test(ecx, Immediate(kAsciiStringTag));
__ j(zero, &non_ascii);
// Allocate an acsii cons string.
__ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime);
__ bind(&allocated);
// Fill the fields of the cons string.
__ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx);
__ mov(FieldOperand(ecx, ConsString::kHashFieldOffset),
Immediate(String::kEmptyHashField));
__ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax);
__ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx);
__ mov(eax, ecx);
__ IncrementCounter(&Counters::string_add_native, 1);
__ ret(2 * kPointerSize);
__ bind(&non_ascii);
// Allocate a two byte cons string.
__ AllocateConsString(ecx, edi, no_reg, &string_add_runtime);
__ jmp(&allocated);
// Handle creating a flat result. First check that both strings are not
// external strings.
// eax: first string
// ebx: length of resulting flat string
// edx: second string
__ bind(&string_add_flat_result);
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ and_(ecx, kStringRepresentationMask);
__ cmp(ecx, kExternalStringTag);
__ j(equal, &string_add_runtime);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ and_(ecx, kStringRepresentationMask);
__ cmp(ecx, kExternalStringTag);
__ j(equal, &string_add_runtime);
// Now check if both strings are ascii strings.
// eax: first string
// ebx: length of resulting flat string
// edx: second string
Label non_ascii_string_add_flat_result;
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
ASSERT(kAsciiStringTag != 0);
__ test(ecx, Immediate(kAsciiStringTag));
__ j(zero, &non_ascii_string_add_flat_result);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ test(ecx, Immediate(kAsciiStringTag));
__ j(zero, &string_add_runtime);
// Both strings are ascii strings. As they are short they are both flat.
__ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime);
// eax: result string
__ mov(ecx, eax);
// Locate first character of result.
__ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
// Load first argument and locate first character.
__ mov(edx, Operand(esp, 2 * kPointerSize));
__ mov(edi, FieldOperand(edx, String::kLengthOffset));
__ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
// eax: result string
// ecx: first character of result
// edx: first char of first argument
// edi: length of first argument
GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
// Load second argument and locate first character.
__ mov(edx, Operand(esp, 1 * kPointerSize));
__ mov(edi, FieldOperand(edx, String::kLengthOffset));
__ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
// eax: result string
// ecx: next character of result
// edx: first char of second argument
// edi: length of second argument
GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
__ IncrementCounter(&Counters::string_add_native, 1);
__ ret(2 * kPointerSize);
// Handle creating a flat two byte result.
// eax: first string - known to be two byte
// ebx: length of resulting flat string
// edx: second string
__ bind(&non_ascii_string_add_flat_result);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ and_(ecx, kAsciiStringTag);
__ j(not_zero, &string_add_runtime);
// Both strings are two byte strings. As they are short they are both
// flat.
__ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime);
// eax: result string
__ mov(ecx, eax);
// Locate first character of result.
__ add(Operand(ecx),
Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
// Load first argument and locate first character.
__ mov(edx, Operand(esp, 2 * kPointerSize));
__ mov(edi, FieldOperand(edx, String::kLengthOffset));
__ add(Operand(edx),
Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
// eax: result string
// ecx: first character of result
// edx: first char of first argument
// edi: length of first argument
GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
// Load second argument and locate first character.
__ mov(edx, Operand(esp, 1 * kPointerSize));
__ mov(edi, FieldOperand(edx, String::kLengthOffset));
__ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
// eax: result string
// ecx: next character of result
// edx: first char of second argument
// edi: length of second argument
GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
__ IncrementCounter(&Counters::string_add_native, 1);
__ ret(2 * kPointerSize);
// Just jump to runtime to add the two strings.
__ bind(&string_add_runtime);
__ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
}
void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
Register count,
Register scratch,
bool ascii) {
Label loop;
__ bind(&loop);
// This loop just copies one character at a time, as it is only used for very
// short strings.
if (ascii) {
__ mov_b(scratch, Operand(src, 0));
__ mov_b(Operand(dest, 0), scratch);
__ add(Operand(src), Immediate(1));
__ add(Operand(dest), Immediate(1));
} else {
__ mov_w(scratch, Operand(src, 0));
__ mov_w(Operand(dest, 0), scratch);
__ add(Operand(src), Immediate(2));
__ add(Operand(dest), Immediate(2));
}
__ sub(Operand(count), Immediate(1));
__ j(not_zero, &loop);
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

34
deps/v8/src/ia32/codegen-ia32.h

@ -546,6 +546,9 @@ class CodeGenerator: public AstVisitor {
inline void GenerateMathSin(ZoneList<Expression*>* args); inline void GenerateMathSin(ZoneList<Expression*>* args);
inline void GenerateMathCos(ZoneList<Expression*>* args); inline void GenerateMathCos(ZoneList<Expression*>* args);
// Fast support for StringAdd.
void GenerateStringAdd(ZoneList<Expression*>* args);
// Simple condition analysis. // Simple condition analysis.
enum ConditionAnalysis { enum ConditionAnalysis {
ALWAYS_TRUE, ALWAYS_TRUE,
@ -737,6 +740,37 @@ class GenericBinaryOpStub: public CodeStub {
}; };
// Flag that indicates how to generate code for the stub StringAddStub.
enum StringAddFlags {
NO_STRING_ADD_FLAGS = 0,
NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub.
};
class StringAddStub: public CodeStub {
public:
explicit StringAddStub(StringAddFlags flags) {
string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
}
private:
Major MajorKey() { return StringAdd; }
int MinorKey() { return string_check_ ? 0 : 1; }
void Generate(MacroAssembler* masm);
void GenerateCopyCharacters(MacroAssembler* masm,
Register desc,
Register src,
Register count,
Register scratch,
bool ascii);
// Should the stub check whether arguments are strings?
bool string_check_;
};
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_IA32_CODEGEN_IA32_H_ #endif // V8_IA32_CODEGEN_IA32_H_

8
deps/v8/src/ia32/debug-ia32.cc

@ -45,17 +45,17 @@ bool BreakLocationIterator::IsDebugBreakAtReturn() {
// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc
// for the precise return instructions sequence. // for the precise return instructions sequence.
void BreakLocationIterator::SetDebugBreakAtReturn() { void BreakLocationIterator::SetDebugBreakAtReturn() {
ASSERT(Debug::kIa32JSReturnSequenceLength >= ASSERT(Assembler::kJSReturnSequenceLength >=
Debug::kIa32CallInstructionLength); Assembler::kCallInstructionLength);
rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(), rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(),
Debug::kIa32JSReturnSequenceLength - Debug::kIa32CallInstructionLength); Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
} }
// Restore the JS frame exit code. // Restore the JS frame exit code.
void BreakLocationIterator::ClearDebugBreakAtReturn() { void BreakLocationIterator::ClearDebugBreakAtReturn() {
rinfo()->PatchCode(original_rinfo()->pc(), rinfo()->PatchCode(original_rinfo()->pc(),
Debug::kIa32JSReturnSequenceLength); Assembler::kJSReturnSequenceLength);
} }

319
deps/v8/src/ia32/fast-codegen-ia32.cc

@ -74,11 +74,41 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
bool function_in_register = true; bool function_in_register = true;
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in edi.
__ push(edi);
__ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false;
// Context is returned in both eax and esi. It replaces the context
// passed to us. It's saved in the stack and kept live in esi.
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
// Copy parameters into context if necessary.
int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context
__ mov(Operand(esi, Context::SlotOffset(slot->index())), eax);
}
}
}
Variable* arguments = fun->scope()->arguments()->AsVariable(); Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) { if (arguments != NULL) {
// Function uses arguments object. // Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object"); Comment cmnt(masm_, "[ Allocate arguments object");
__ push(edi); if (function_in_register) {
__ push(edi);
} else {
__ 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.
__ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset + __ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize)); fun->num_parameters() * kPointerSize));
@ -90,36 +120,13 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
// stack frame was an arguments adapter frame. // stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub); __ CallStub(&stub);
__ mov(Operand(ebp, SlotOffset(arguments->slot())), eax); __ mov(ecx, eax); // Duplicate result.
Move(arguments->slot(), eax, ebx, edx);
Slot* dot_arguments_slot = Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot(); fun->scope()->arguments_shadow()->AsVariable()->slot();
__ mov(Operand(ebp, SlotOffset(dot_arguments_slot)), eax); Move(dot_arguments_slot, ecx, ebx, edx);
function_in_register = false;
} }
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
if (function_in_register) {
// Argument to NewContext is the function, still in edi.
__ push(edi);
} else {
// Argument to NewContext is the function, no longer in edi.
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
}
__ CallRuntime(Runtime::kNewContext, 1);
// Context is returned in both eax and esi. It replaces the context
// passed to us. It's saved in the stack and kept live in esi.
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
#ifdef DEBUG
// Assert we do not have to copy any parameters into the context.
for (int i = 0, len = fun->scope()->num_parameters(); i < len; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
ASSERT(slot != NULL && slot->type() != Slot::CONTEXT);
}
#endif
}
{ Comment cmnt(masm_, "[ Declarations"); { Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(fun->scope()->declarations()); VisitDeclarations(fun->scope()->declarations());
@ -180,7 +187,7 @@ void FastCodeGenerator::EmitReturnSequence(int position) {
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
// Check that the size of the code used for returning matches what is // Check that the size of the code used for returning matches what is
// expected by the debugger. // expected by the debugger.
ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, ASSERT_EQ(Assembler::kJSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif #endif
} }
@ -220,20 +227,54 @@ void FastCodeGenerator::Move(Expression::Context context, Register source) {
} }
void FastCodeGenerator::Move(Expression::Context context, Slot* source) { template <>
Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source,
Register scratch) {
switch (source->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
return Operand(ebp, SlotOffset(source));
case Slot::CONTEXT: {
int context_chain_length =
function_->scope()->ContextChainLength(source->var()->scope());
__ LoadContext(scratch, context_chain_length);
return CodeGenerator::ContextOperand(scratch, source->index());
break;
}
case Slot::LOOKUP:
UNIMPLEMENTED();
// Fall-through.
default:
UNREACHABLE();
return Operand(eax, 0); // Dead code to make the compiler happy.
}
}
void FastCodeGenerator::Move(Register dst, Slot* source) {
Operand location = CreateSlotOperand<Operand>(source, dst);
__ mov(dst, location);
}
void FastCodeGenerator::Move(Expression::Context context,
Slot* source,
Register scratch) {
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
break; break;
case Expression::kValue: case Expression::kValue: {
__ push(Operand(ebp, SlotOffset(source))); Operand location = CreateSlotOperand<Operand>(source, scratch);
__ push(location);
break; break;
}
case Expression::kTest: // Fall through. case Expression::kTest: // Fall through.
case Expression::kValueTest: // Fall through. case Expression::kValueTest: // Fall through.
case Expression::kTestValue: case Expression::kTestValue:
__ mov(eax, Operand(ebp, SlotOffset(source))); Move(scratch, source);
Move(context, eax); Move(context, scratch);
break; break;
} }
} }
@ -258,24 +299,61 @@ void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
} }
void FastCodeGenerator::Move(Slot* dst,
Register src,
Register scratch1,
Register scratch2) {
switch (dst->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
__ mov(Operand(ebp, SlotOffset(dst)), src);
break;
case Slot::CONTEXT: {
ASSERT(!src.is(scratch1));
ASSERT(!src.is(scratch2));
ASSERT(!scratch1.is(scratch2));
int context_chain_length =
function_->scope()->ContextChainLength(dst->var()->scope());
__ LoadContext(scratch1, context_chain_length);
__ mov(Operand(scratch1, Context::SlotOffset(dst->index())), src);
int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
__ RecordWrite(scratch1, offset, src, scratch2);
break;
}
case Slot::LOOKUP:
UNIMPLEMENTED();
default:
UNREACHABLE();
}
}
void FastCodeGenerator::DropAndMove(Expression::Context context, void FastCodeGenerator::DropAndMove(Expression::Context context,
Register source) { Register source,
int count) {
ASSERT(count > 0);
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
__ add(Operand(esp), Immediate(kPointerSize)); __ add(Operand(esp), Immediate(count * kPointerSize));
break; break;
case Expression::kValue: case Expression::kValue:
if (count > 1) {
__ add(Operand(esp), Immediate((count - 1) * kPointerSize));
}
__ mov(Operand(esp, 0), source); __ mov(Operand(esp, 0), source);
break; break;
case Expression::kTest: case Expression::kTest:
ASSERT(!source.is(esp)); ASSERT(!source.is(esp));
__ add(Operand(esp), Immediate(kPointerSize)); __ add(Operand(esp), Immediate(count * kPointerSize));
TestAndBranch(source, true_label_, false_label_); TestAndBranch(source, true_label_, false_label_);
break; break;
case Expression::kValueTest: { case Expression::kValueTest: {
Label discard; Label discard;
if (count > 1) {
__ add(Operand(esp), Immediate((count - 1) * kPointerSize));
}
__ mov(Operand(esp, 0), source); __ mov(Operand(esp, 0), source);
TestAndBranch(source, true_label_, &discard); TestAndBranch(source, true_label_, &discard);
__ bind(&discard); __ bind(&discard);
@ -285,6 +363,9 @@ void FastCodeGenerator::DropAndMove(Expression::Context context,
} }
case Expression::kTestValue: { case Expression::kTestValue: {
Label discard; Label discard;
if (count > 1) {
__ add(Operand(esp), Immediate((count - 1) * kPointerSize));
}
__ mov(Operand(esp, 0), source); __ mov(Operand(esp, 0), source);
TestAndBranch(source, &discard, false_label_); TestAndBranch(source, &discard, false_label_);
__ bind(&discard); __ bind(&discard);
@ -380,6 +461,7 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
} }
__ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
// No write barrier since the_hole_value is in old space. // No write barrier since the_hole_value is in old space.
ASSERT(!Heap::InNewSpace(*Factory::the_hole_value()));
} else if (decl->fun() != NULL) { } else if (decl->fun() != NULL) {
Visit(decl->fun()); Visit(decl->fun());
__ pop(eax); __ pop(eax);
@ -391,7 +473,7 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
__ Check(equal, "Unexpected declaration in current context."); __ Check(equal, "Unexpected declaration in current context.");
} }
__ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; int offset = Context::SlotOffset(slot->index());
__ RecordWrite(esi, offset, eax, ecx); __ RecordWrite(esi, offset, eax, ecx);
} }
break; break;
@ -464,53 +546,61 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
DropAndMove(expr->context(), eax); DropAndMove(expr->context(), eax);
} else if (rewrite->AsSlot() != NULL) { } else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot(); Slot* slot = rewrite->AsSlot();
switch (slot->type()) { if (FLAG_debug_code) {
case Slot::LOCAL: switch (slot->type()) {
case Slot::PARAMETER: { case Slot::LOCAL:
Comment cmnt(masm_, "Stack slot"); case Slot::PARAMETER: {
Move(expr->context(), slot); Comment cmnt(masm_, "Stack slot");
break; break;
}
case Slot::CONTEXT: {
Comment cmnt(masm_, "Context slot");
int chain_length =
function_->scope()->ContextChainLength(slot->var()->scope());
if (chain_length > 0) {
// Move up the chain of contexts to the context containing the slot.
__ mov(eax,
Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX)));
// Load the function context (which is the incoming, outer context).
__ mov(eax, FieldOperand(eax, JSFunction::kContextOffset));
for (int i = 1; i < chain_length; i++) {
__ mov(eax,
Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)));
__ mov(eax, FieldOperand(eax, JSFunction::kContextOffset));
}
// The context may be an intermediate context, not a function context.
__ mov(eax,
Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX)));
} else { // Slot is in the current function context.
// The context may be an intermediate context, not a function context.
__ mov(eax,
Operand(esi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
} }
__ mov(eax, Operand(eax, Context::SlotOffset(slot->index()))); case Slot::CONTEXT: {
Move(expr->context(), eax); Comment cmnt(masm_, "Context slot");
break; break;
}
case Slot::LOOKUP:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
} }
case Slot::LOOKUP:
UNREACHABLE();
break;
} }
Move(expr->context(), slot, eax);
} else { } else {
// The parameter variable has been rewritten into an explict access to Comment cmnt(masm_, "Variable rewritten to Property");
// the arguments object. // A variable has been rewritten into an explicit access to
// an object property.
Property* property = rewrite->AsProperty(); Property* property = rewrite->AsProperty();
ASSERT_NOT_NULL(property); ASSERT_NOT_NULL(property);
ASSERT_EQ(expr->context(), property->context());
Visit(property); // Currently the only parameter expressions that can occur are
// on the form "slot[literal]".
// Check that the object is in a slot.
Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
ASSERT_NOT_NULL(object_var);
Slot* object_slot = object_var->slot();
ASSERT_NOT_NULL(object_slot);
// Load the object.
Move(Expression::kValue, object_slot, eax);
// Check that the key is a smi.
Literal* key_literal = property->key()->AsLiteral();
ASSERT_NOT_NULL(key_literal);
ASSERT(key_literal->handle()->IsSmi());
// Load the key.
Move(Expression::kValue, key_literal);
// Do a KEYED property load.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// Notice: We must not have a "test eax, ..." instruction after
// the call. It is treated specially by the LoadIC code.
__ nop();
// Drop key and object left on the stack by IC, and push the result.
DropAndMove(expr->context(), eax, 2);
} }
} }
@ -575,8 +665,9 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
} }
// If result_saved == true: the result is saved on top of the stack. // If result_saved == true: The result is saved on top of the
// If result_saved == false: the result not on the stack, just is in eax. // stack and in eax.
// If result_saved == false: The result not on the stack, just in eax.
bool result_saved = false; bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) { for (int i = 0; i < expr->properties()->length(); i++) {
@ -601,6 +692,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ call(ic, RelocInfo::CODE_TARGET);
// StoreIC leaves the receiver on the stack. // StoreIC leaves the receiver on the stack.
__ mov(eax, Operand(esp, 0)); // Restore result into eax.
break; break;
} }
// fall through // fall through
@ -776,34 +868,34 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
// Overwrite the receiver on the stack with the result if needed. // Overwrite the receiver on the stack with the result if needed.
DropAndMove(expr->context(), eax); DropAndMove(expr->context(), eax);
} else { } else if (var->slot() != NULL) {
Slot* slot = var->slot(); Slot* slot = var->slot();
ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
switch (slot->type()) { switch (slot->type()) {
case Slot::LOCAL: case Slot::LOCAL:
case Slot::PARAMETER: { case Slot::PARAMETER: {
Operand target = Operand(ebp, SlotOffset(var->slot()));
switch (expr->context()) { switch (expr->context()) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
// Perform assignment and discard value. // Perform assignment and discard value.
__ pop(Operand(ebp, SlotOffset(var->slot()))); __ pop(target);
break; break;
case Expression::kValue: case Expression::kValue:
// Perform assignment and preserve value. // Perform assignment and preserve value.
__ mov(eax, Operand(esp, 0)); __ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax); __ mov(target, eax);
break; break;
case Expression::kTest: case Expression::kTest:
// Perform assignment and test (and discard) value. // Perform assignment and test (and discard) value.
__ pop(eax); __ pop(eax);
__ mov(Operand(ebp, SlotOffset(var->slot())), eax); __ mov(target, eax);
TestAndBranch(eax, true_label_, false_label_); TestAndBranch(eax, true_label_, false_label_);
break; break;
case Expression::kValueTest: { case Expression::kValueTest: {
Label discard; Label discard;
__ mov(eax, Operand(esp, 0)); __ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax); __ mov(target, eax);
TestAndBranch(eax, true_label_, &discard); TestAndBranch(eax, true_label_, &discard);
__ bind(&discard); __ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize)); __ add(Operand(esp), Immediate(kPointerSize));
@ -813,7 +905,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
case Expression::kTestValue: { case Expression::kTestValue: {
Label discard; Label discard;
__ mov(eax, Operand(esp, 0)); __ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax); __ mov(target, eax);
TestAndBranch(eax, &discard, false_label_); TestAndBranch(eax, &discard, false_label_);
__ bind(&discard); __ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize)); __ add(Operand(esp), Immediate(kPointerSize));
@ -868,6 +960,35 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
UNREACHABLE(); UNREACHABLE();
break; break;
} }
} else {
Property* property = var->rewrite()->AsProperty();
ASSERT_NOT_NULL(property);
// Load object and key onto the stack.
Slot* object_slot = property->obj()->AsSlot();
ASSERT_NOT_NULL(object_slot);
Move(Expression::kValue, object_slot, eax);
Literal* key_literal = property->key()->AsLiteral();
ASSERT_NOT_NULL(key_literal);
Move(Expression::kValue, key_literal);
// Value to store was pushed before object and key on the stack.
__ mov(eax, Operand(esp, 2 * kPointerSize));
// Arguments to ic is value in eax, object and key on stack.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
if (expr->context() == Expression::kEffect) {
__ add(Operand(esp), Immediate(3 * kPointerSize));
} else if (expr->context() == Expression::kValue) {
// Value is still on the stack in esp[2 * kPointerSize]
__ add(Operand(esp), Immediate(2 * kPointerSize));
} else {
__ mov(eax, Operand(esp, 2 * kPointerSize));
DropAndMove(expr->context(), eax, 3);
}
} }
} }
@ -1127,9 +1248,13 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) {
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Comment cmnt(masm_, "[ CallRuntime"); Comment cmnt(masm_, "[ CallRuntime");
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
Runtime::Function* function = expr->function();
ASSERT(function != NULL); if (expr->is_jsruntime()) {
// Prepare for calling JS runtime function.
__ push(Immediate(expr->name()));
__ mov(eax, CodeGenerator::GlobalObject());
__ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
}
// Push the arguments ("left-to-right"). // Push the arguments ("left-to-right").
int arg_count = args->length(); int arg_count = args->length();
@ -1138,8 +1263,20 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
ASSERT_EQ(Expression::kValue, args->at(i)->context()); ASSERT_EQ(Expression::kValue, args->at(i)->context());
} }
__ CallRuntime(function, arg_count); if (expr->is_jsruntime()) {
Move(expr->context(), eax); // Call the JS runtime function.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
__ call(ic, RelocInfo::CODE_TARGET);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
DropAndMove(expr->context(), eax);
} else {
// Call the C runtime function.
__ CallRuntime(expr->function(), arg_count);
Move(expr->context(), eax);
}
} }

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

@ -31,6 +31,7 @@
#include "ic-inl.h" #include "ic-inl.h"
#include "runtime.h" #include "runtime.h"
#include "stub-cache.h" #include "stub-cache.h"
#include "utils.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
@ -108,7 +109,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
StringDictionary::kElementsStartIndex * kPointerSize; StringDictionary::kElementsStartIndex * kPointerSize;
for (int i = 0; i < kProbes; i++) { for (int i = 0; i < kProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask. // Compute the masked index: (hash + i + i * i) & mask.
__ mov(r1, FieldOperand(name, String::kLengthOffset)); __ mov(r1, FieldOperand(name, String::kHashFieldOffset));
__ shr(r1, String::kHashShift); __ shr(r1, String::kHashShift);
if (i > 0) { if (i > 0) {
__ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i))); __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
@ -216,18 +217,6 @@ void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
} }
#ifdef DEBUG
// For use in assert below.
static int TenToThe(int exponent) {
ASSERT(exponent <= 9);
ASSERT(exponent >= 1);
int answer = 10;
for (int i = 1; i < exponent; i++) answer *= 10;
return answer;
}
#endif
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- esp[0] : return address // -- esp[0] : return address
@ -309,7 +298,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
__ j(above_equal, &slow); __ j(above_equal, &slow);
// Is the string an array index, with cached numeric value? // Is the string an array index, with cached numeric value?
__ mov(ebx, FieldOperand(eax, String::kLengthOffset)); __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset));
__ test(ebx, Immediate(String::kIsArrayIndexMask)); __ test(ebx, Immediate(String::kIsArrayIndexMask));
__ j(not_zero, &index_string, not_taken); __ j(not_zero, &index_string, not_taken);
@ -324,20 +313,16 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ mov(eax, Operand(ecx)); __ mov(eax, Operand(ecx));
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0); __ ret(0);
// Array index string: If short enough use cache in length/hash field (ebx). // If the hash field contains an array index pick it out. The assert checks
// We assert that there are enough bits in an int32_t after the hash shift // that the constants for the maximum number of digits for an array index
// bits have been subtracted to allow space for the length and the cached // cached in the hash field and the number of bits reserved for it does not
// array index. // conflict.
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
(1 << (String::kShortLengthShift - String::kHashShift))); (1 << String::kArrayIndexValueBits));
__ bind(&index_string); __ bind(&index_string);
const int kLengthFieldLimit =
(String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
__ cmp(ebx, kLengthFieldLimit);
__ j(above_equal, &slow);
__ mov(eax, Operand(ebx)); __ mov(eax, Operand(ebx));
__ and_(eax, (1 << String::kShortLengthShift) - 1); __ and_(eax, String::kArrayIndexHashMask);
__ shr(eax, String::kLongLengthShift); __ shr(eax, String::kHashShift);
__ jmp(&index_int); __ jmp(&index_int);
} }
@ -403,13 +388,13 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
__ movsx_b(eax, Operand(ecx, eax, times_1, 0)); __ movsx_b(eax, Operand(ecx, eax, times_1, 0));
break; break;
case kExternalUnsignedByteArray: case kExternalUnsignedByteArray:
__ mov_b(eax, Operand(ecx, eax, times_1, 0)); __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
break; break;
case kExternalShortArray: case kExternalShortArray:
__ movsx_w(eax, Operand(ecx, eax, times_2, 0)); __ movsx_w(eax, Operand(ecx, eax, times_2, 0));
break; break;
case kExternalUnsignedShortArray: case kExternalUnsignedShortArray:
__ mov_w(eax, Operand(ecx, eax, times_2, 0)); __ movzx_w(eax, Operand(ecx, eax, times_2, 0));
break; break;
case kExternalIntArray: case kExternalIntArray:
case kExternalUnsignedIntArray: case kExternalUnsignedIntArray:

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

@ -213,6 +213,13 @@ void MacroAssembler::RecordWrite(Register object, int offset,
} }
void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
cmp(esp,
Operand::StaticVariable(ExternalReference::address_of_stack_limit()));
j(below, on_stack_overflow);
}
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::SaveRegistersToMemory(RegList regs) { void MacroAssembler::SaveRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0); ASSERT((regs & ~kJSCallerSaved) == 0);
@ -680,6 +687,11 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
void MacroAssembler::UpdateAllocationTopHelper(Register result_end, void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
Register scratch) { Register scratch) {
if (FLAG_debug_code) {
test(result_end, Immediate(kObjectAlignmentMask));
Check(zero, "Unaligned allocation in new space");
}
ExternalReference new_space_allocation_top = ExternalReference new_space_allocation_top =
ExternalReference::new_space_allocation_top_address(); ExternalReference::new_space_allocation_top_address();
@ -813,6 +825,109 @@ void MacroAssembler::AllocateHeapNumber(Register result,
} }
void MacroAssembler::AllocateTwoByteString(Register result,
Register length,
Register scratch1,
Register scratch2,
Register scratch3,
Label* gc_required) {
// Calculate the number of bytes needed for the characters in the string while
// observing object alignment.
ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
mov(scratch1, length);
ASSERT(kShortSize == 2);
shl(scratch1, 1);
add(Operand(scratch1), Immediate(kObjectAlignmentMask));
and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
// Allocate two byte string in new space.
AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
times_1,
scratch1,
result,
scratch2,
scratch3,
gc_required,
TAG_OBJECT);
// Set the map, length and hash field.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(Factory::string_map()));
mov(FieldOperand(result, String::kLengthOffset), length);
mov(FieldOperand(result, String::kHashFieldOffset),
Immediate(String::kEmptyHashField));
}
void MacroAssembler::AllocateAsciiString(Register result,
Register length,
Register scratch1,
Register scratch2,
Register scratch3,
Label* gc_required) {
// Calculate the number of bytes needed for the characters in the string while
// observing object alignment.
ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
mov(scratch1, length);
ASSERT(kCharSize == 1);
add(Operand(scratch1), Immediate(kObjectAlignmentMask));
and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
// Allocate ascii string in new space.
AllocateInNewSpace(SeqAsciiString::kHeaderSize,
times_1,
scratch1,
result,
scratch2,
scratch3,
gc_required,
TAG_OBJECT);
// Set the map, length and hash field.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(Factory::ascii_string_map()));
mov(FieldOperand(result, String::kLengthOffset), length);
mov(FieldOperand(result, String::kHashFieldOffset),
Immediate(String::kEmptyHashField));
}
void MacroAssembler::AllocateConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
// Allocate heap number in new space.
AllocateInNewSpace(ConsString::kSize,
result,
scratch1,
scratch2,
gc_required,
TAG_OBJECT);
// Set the map. The other fields are left uninitialized.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(Factory::cons_string_map()));
}
void MacroAssembler::AllocateAsciiConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
// Allocate heap number in new space.
AllocateInNewSpace(ConsString::kSize,
result,
scratch1,
scratch2,
gc_required,
TAG_OBJECT);
// Set the map. The other fields are left uninitialized.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(Factory::cons_ascii_string_map()));
}
void MacroAssembler::NegativeZeroTest(CodeGenerator* cgen, void MacroAssembler::NegativeZeroTest(CodeGenerator* cgen,
Register result, Register result,
Register op, Register op,
@ -906,6 +1021,12 @@ void MacroAssembler::CallStub(CodeStub* stub) {
} }
void MacroAssembler::TailCallStub(CodeStub* stub) {
ASSERT(allow_stub_calls()); // calls are not allowed in some stubs
jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
}
void MacroAssembler::StubReturn(int argc) { void MacroAssembler::StubReturn(int argc) {
ASSERT(argc >= 1 && generating_stub()); ASSERT(argc >= 1 && generating_stub());
ret((argc - 1) * kPointerSize); ret((argc - 1) * kPointerSize);
@ -1185,6 +1306,26 @@ Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
} }
void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
if (context_chain_length > 0) {
// Move up the chain of contexts to the context containing the slot.
mov(dst, Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX)));
// Load the function context (which is the incoming, outer context).
mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
for (int i = 1; i < context_chain_length; i++) {
mov(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
}
// The context may be an intermediate context, not a function context.
mov(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
} else { // Slot is in the current function context.
// The context may be an intermediate context, not a function context.
mov(dst, Operand(esi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
}
}
void MacroAssembler::Ret() { void MacroAssembler::Ret() {
ret(0); ret(0);
} }
@ -1252,11 +1393,15 @@ void MacroAssembler::Abort(const char* msg) {
RecordComment(msg); RecordComment(msg);
} }
#endif #endif
// Disable stub call restrictions to always allow calls to abort.
set_allow_stub_calls(true);
push(eax); push(eax);
push(Immediate(p0)); push(Immediate(p0));
push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0)))); push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
CallRuntime(Runtime::kAbort, 2); CallRuntime(Runtime::kAbort, 2);
// will not return here // will not return here
int3();
} }

39
deps/v8/src/ia32/macro-assembler-ia32.h

@ -68,6 +68,12 @@ class MacroAssembler: public Assembler {
RegList regs); RegList regs);
#endif #endif
// ---------------------------------------------------------------------------
// Stack limit support
// Do simple test for stack overflow. This doesn't handle an overflow.
void StackLimitCheck(Label* on_stack_limit_hit);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Activation frames // Activation frames
@ -90,6 +96,8 @@ class MacroAssembler: public Assembler {
// argument in register esi. // argument in register esi.
void LeaveExitFrame(ExitFrame::Mode mode); void LeaveExitFrame(ExitFrame::Mode mode);
// Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// JavaScript invokes // JavaScript invokes
@ -175,7 +183,7 @@ class MacroAssembler: public Assembler {
// scratch can be passed as no_reg in which case an additional object // scratch can be passed as no_reg in which case an additional object
// reference will be added to the reloc info. The returned pointers in result // reference will be added to the reloc info. The returned pointers in result
// and result_end have not yet been tagged as heap objects. If // and result_end have not yet been tagged as heap objects. If
// result_contains_top_on_entry is true the contnt of result is known to be // result_contains_top_on_entry is true the content of result is known to be
// the allocation top on entry (could be result_end from a previous call to // the allocation top on entry (could be result_end from a previous call to
// AllocateInNewSpace). If result_contains_top_on_entry is true scratch // AllocateInNewSpace). If result_contains_top_on_entry is true scratch
// should be no_reg as it is never used. // should be no_reg as it is never used.
@ -217,6 +225,32 @@ class MacroAssembler: public Assembler {
Register scratch2, Register scratch2,
Label* gc_required); Label* gc_required);
// Allocate a sequential string. All the header fields of the string object
// are initialized.
void AllocateTwoByteString(Register result,
Register length,
Register scratch1,
Register scratch2,
Register scratch3,
Label* gc_required);
void AllocateAsciiString(Register result,
Register length,
Register scratch1,
Register scratch2,
Register scratch3,
Label* gc_required);
// Allocate a raw cons string object. Only the map field of the result is
// initialized.
void AllocateConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
void AllocateAsciiConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Support functions. // Support functions.
@ -254,6 +288,9 @@ class MacroAssembler: public Assembler {
// Call a code stub. // Call a code stub.
void CallStub(CodeStub* stub); void CallStub(CodeStub* stub);
// Tail call a code stub (jump).
void TailCallStub(CodeStub* stub);
// Return from a code stub after popping its arguments. // Return from a code stub after popping its arguments.
void StubReturn(int argc); void StubReturn(int argc);

10
deps/v8/src/ia32/stub-cache-ia32.cc

@ -126,7 +126,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ j(zero, &miss, not_taken); __ j(zero, &miss, not_taken);
// Get the map of the receiver and compute the hash. // Get the map of the receiver and compute the hash.
__ mov(scratch, FieldOperand(name, String::kLengthOffset)); __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
__ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ xor_(scratch, flags); __ xor_(scratch, flags);
__ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
@ -135,7 +135,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
ProbeTable(masm, flags, kPrimary, name, scratch, extra); ProbeTable(masm, flags, kPrimary, name, scratch, extra);
// Primary miss: Compute hash for secondary probe. // Primary miss: Compute hash for secondary probe.
__ mov(scratch, FieldOperand(name, String::kLengthOffset)); __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
__ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ xor_(scratch, flags); __ xor_(scratch, flags);
__ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
@ -234,13 +234,9 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
// scratch register. // scratch register.
GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper); GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
// Load length directly from the string. // Load length from the string and convert to a smi.
__ bind(&load_length); __ bind(&load_length);
__ and_(scratch, kStringSizeMask);
__ mov(eax, FieldOperand(receiver, String::kLengthOffset)); __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
// ecx is also the receiver.
__ lea(ecx, Operand(scratch, String::kLongLengthShift));
__ shr_cl(eax);
__ shl(eax, kSmiTagSize); __ shl(eax, kSmiTagSize);
__ ret(0); __ ret(0);

60
deps/v8/src/log.cc

@ -680,22 +680,51 @@ class CompressionHelper {
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING
void Logger::CallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::CallbackEventInternal(const char* prefix, const char* name,
Address entry_point) {
if (!Log::IsEnabled() || !FLAG_log_code) return; if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,%s,", msg.Append("%s,%s,",
log_events_[CODE_CREATION_EVENT], log_events_[CALLBACK_TAG]); log_events_[CODE_CREATION_EVENT], log_events_[CALLBACK_TAG]);
msg.AppendAddress(entry_point); msg.AppendAddress(entry_point);
SmartPointer<char> str = msg.Append(",1,\"%s%s\"", prefix, name);
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append(",1,\"%s\"", *str);
if (FLAG_compress_log) { if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL); ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return; if (!compression_helper_->HandleMessage(&msg)) return;
} }
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
}
#endif
void Logger::CallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_code) return;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("", *str, entry_point);
#endif
}
void Logger::GetterCallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_code) return;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("get ", *str, entry_point);
#endif
}
void Logger::SetterCallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_code) return;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("set ", *str, entry_point);
#endif #endif
} }
@ -1098,6 +1127,7 @@ void Logger::ResumeProfiler(int flags) {
LOG(UncheckedStringEvent("profiler", "resume")); LOG(UncheckedStringEvent("profiler", "resume"));
FLAG_log_code = true; FLAG_log_code = true;
LogCompiledFunctions(); LogCompiledFunctions();
LogAccessorCallbacks();
if (!FLAG_sliding_state_window) ticker_->Start(); if (!FLAG_sliding_state_window) ticker_->Start();
} }
profiler_->resume(); profiler_->resume();
@ -1242,6 +1272,28 @@ void Logger::LogCompiledFunctions() {
DeleteArray(sfis); DeleteArray(sfis);
} }
void Logger::LogAccessorCallbacks() {
AssertNoAllocation no_alloc;
HeapIterator iterator;
while (iterator.has_next()) {
HeapObject* obj = iterator.next();
ASSERT(obj != NULL);
if (!obj->IsAccessorInfo()) continue;
AccessorInfo* ai = AccessorInfo::cast(obj);
if (!ai->name()->IsString()) continue;
String* name = String::cast(ai->name());
Address getter_entry = v8::ToCData<Address>(ai->getter());
if (getter_entry != 0) {
LOG(GetterCallbackEvent(name, getter_entry));
}
Address setter_entry = v8::ToCData<Address>(ai->setter());
if (setter_entry != 0) {
LOG(SetterCallbackEvent(name, setter_entry));
}
}
}
#endif #endif

9
deps/v8/src/log.h

@ -208,6 +208,8 @@ class Logger {
// ==== Events logged by --log-code. ==== // ==== Events logged by --log-code. ====
// Emits a code event for a callback function. // Emits a code event for a callback function.
static void CallbackEvent(String* name, Address entry_point); static void CallbackEvent(String* name, Address entry_point);
static void GetterCallbackEvent(String* name, Address entry_point);
static void SetterCallbackEvent(String* name, Address entry_point);
// Emits a code create event. // Emits a code create event.
static void CodeCreateEvent(LogEventsAndTags tag, static void CodeCreateEvent(LogEventsAndTags tag,
Code* code, const char* source); Code* code, const char* source);
@ -273,6 +275,8 @@ class Logger {
// Logs all compiled functions found in the heap. // Logs all compiled functions found in the heap.
static void LogCompiledFunctions(); static void LogCompiledFunctions();
// Logs all accessor callbacks found in the heap.
static void LogAccessorCallbacks();
// Used for logging stubs found in the snapshot. // Used for logging stubs found in the snapshot.
static void LogCodeObject(Object* code_object); static void LogCodeObject(Object* code_object);
@ -287,6 +291,11 @@ class Logger {
// Emits the profiler's first message. // Emits the profiler's first message.
static void ProfilerBeginEvent(); static void ProfilerBeginEvent();
// Emits callback event messages.
static void CallbackEventInternal(const char* prefix,
const char* name,
Address entry_point);
// Emits aliases for compressed messages. // Emits aliases for compressed messages.
static void LogAliases(); static void LogAliases();

65
deps/v8/src/messages.js

@ -238,14 +238,15 @@ function MakeError(type, args) {
Script.prototype.lineFromPosition = function(position) { Script.prototype.lineFromPosition = function(position) {
var lower = 0; var lower = 0;
var upper = this.lineCount() - 1; var upper = this.lineCount() - 1;
var line_ends = this.line_ends;
// We'll never find invalid positions so bail right away. // We'll never find invalid positions so bail right away.
if (position > this.line_ends[upper]) { if (position > line_ends[upper]) {
return -1; return -1;
} }
// This means we don't have to safe-guard indexing line_ends[i - 1]. // This means we don't have to safe-guard indexing line_ends[i - 1].
if (position <= this.line_ends[0]) { if (position <= line_ends[0]) {
return 0; return 0;
} }
@ -253,9 +254,9 @@ Script.prototype.lineFromPosition = function(position) {
while (upper >= 1) { while (upper >= 1) {
var i = (lower + upper) >> 1; var i = (lower + upper) >> 1;
if (position > this.line_ends[i]) { if (position > line_ends[i]) {
lower = i + 1; lower = i + 1;
} else if (position <= this.line_ends[i - 1]) { } else if (position <= line_ends[i - 1]) {
upper = i - 1; upper = i - 1;
} else { } else {
return i; return i;
@ -278,8 +279,9 @@ Script.prototype.locationFromPosition = function (position,
if (line == -1) return null; if (line == -1) return null;
// Determine start, end and column. // Determine start, end and column.
var start = line == 0 ? 0 : this.line_ends[line - 1] + 1; var line_ends = this.line_ends;
var end = this.line_ends[line]; var start = line == 0 ? 0 : line_ends[line - 1] + 1;
var end = line_ends[line];
if (end > 0 && StringCharAt.call(this.source, end - 1) == '\r') end--; if (end > 0 && StringCharAt.call(this.source, end - 1) == '\r') end--;
var column = position - start; var column = position - start;
@ -368,8 +370,9 @@ Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
return null; return null;
} }
var from_position = from_line == 0 ? 0 : this.line_ends[from_line - 1] + 1; var line_ends = this.line_ends;
var to_position = to_line == 0 ? 0 : this.line_ends[to_line - 1] + 1; var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
// Return a source slice with line numbers re-adjusted to the resource. // Return a source slice with line numbers re-adjusted to the resource.
return new SourceSlice(this, from_line + this.line_offset, to_line + this.line_offset, return new SourceSlice(this, from_line + this.line_offset, to_line + this.line_offset,
@ -391,8 +394,9 @@ Script.prototype.sourceLine = function (opt_line) {
} }
// Return the source line. // Return the source line.
var start = line == 0 ? 0 : this.line_ends[line - 1] + 1; var line_ends = this.line_ends;
var end = this.line_ends[line]; var start = line == 0 ? 0 : line_ends[line - 1] + 1;
var end = line_ends[line];
return StringSubstring.call(this.source, start, end); return StringSubstring.call(this.source, start, end);
} }
@ -625,10 +629,7 @@ CallSite.prototype.isEval = function () {
CallSite.prototype.getEvalOrigin = function () { CallSite.prototype.getEvalOrigin = function () {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
if (!script || script.compilation_type != 1) return FormatEvalOrigin(script);
return null;
return new CallSite(null, script.eval_from_function,
script.eval_from_position);
}; };
CallSite.prototype.getFunction = function () { CallSite.prototype.getFunction = function () {
@ -696,7 +697,7 @@ CallSite.prototype.getColumnNumber = function () {
if (script) { if (script) {
location = script.locationFromPosition(this.pos, true); location = script.locationFromPosition(this.pos, true);
} }
return location ? location.column : null; return location ? location.column + 1: null;
}; };
CallSite.prototype.isNative = function () { CallSite.prototype.isNative = function () {
@ -715,12 +716,44 @@ CallSite.prototype.isConstructor = function () {
return this.fun === constructor; return this.fun === constructor;
}; };
function FormatEvalOrigin(script) {
var eval_origin = "";
if (script.eval_from_function_name) {
eval_origin += script.eval_from_function_name;
} else {
eval_origin += "<anonymous>";
}
var eval_from_script = script.eval_from_script;
if (eval_from_script) {
if (eval_from_script.compilation_type == 1) {
// eval script originated from another eval.
eval_origin += " (eval at " + FormatEvalOrigin(eval_from_script) + ")";
} else {
// eval script originated from "real" scource.
if (eval_from_script.name) {
eval_origin += " (" + eval_from_script.name;
var location = eval_from_script.locationFromPosition(script.eval_from_script_position, true);
if (location) {
eval_origin += ":" + (location.line + 1);
eval_origin += ":" + (location.column + 1);
}
eval_origin += ")"
} else {
eval_origin += " (unknown source)";
}
}
}
return eval_origin;
};
function FormatSourcePosition(frame) { function FormatSourcePosition(frame) {
var fileLocation = ""; var fileLocation = "";
if (frame.isNative()) { if (frame.isNative()) {
fileLocation = "native"; fileLocation = "native";
} else if (frame.isEval()) { } else if (frame.isEval()) {
fileLocation = "eval at " + FormatSourcePosition(frame.getEvalOrigin()); fileLocation = "eval at " + frame.getEvalOrigin();
} else { } else {
var fileName = frame.getFileName(); var fileName = frame.getFileName();
if (fileName) { if (fileName) {

24
deps/v8/src/mirror-delay.js

@ -1793,16 +1793,21 @@ ScriptMirror.prototype.context = function() {
}; };
ScriptMirror.prototype.evalFromFunction = function() { ScriptMirror.prototype.evalFromScript = function() {
return MakeMirror(this.script_.eval_from_function); return MakeMirror(this.script_.eval_from_script);
};
ScriptMirror.prototype.evalFromFunctionName = function() {
return MakeMirror(this.script_.eval_from_function_name);
}; };
ScriptMirror.prototype.evalFromLocation = function() { ScriptMirror.prototype.evalFromLocation = function() {
var eval_from_function = this.evalFromFunction(); var eval_from_script = this.evalFromScript();
if (!eval_from_function.isUndefined()) { if (!eval_from_script.isUndefined()) {
var position = this.script_.eval_from_position; var position = this.script_.eval_from_script_position;
return eval_from_function.script().locationFromPosition(position, true); return eval_from_script.locationFromPosition(position, true);
} }
}; };
@ -2080,12 +2085,15 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
// For compilation type eval emit information on the script from which // For compilation type eval emit information on the script from which
// eval was called if a script is present. // eval was called if a script is present.
if (mirror.compilationType() == 1 && if (mirror.compilationType() == 1 &&
mirror.evalFromFunction().script()) { mirror.evalFromScript()) {
content.evalFromScript = content.evalFromScript =
this.serializeReference(mirror.evalFromFunction().script()); this.serializeReference(mirror.evalFromScript());
var evalFromLocation = mirror.evalFromLocation() var evalFromLocation = mirror.evalFromLocation()
content.evalFromLocation = { line: evalFromLocation.line, content.evalFromLocation = { line: evalFromLocation.line,
column: evalFromLocation.column} column: evalFromLocation.column}
if (mirror.evalFromFunctionName()) {
content.evalFromFunctionName = mirror.evalFromFunctionName();
}
} }
if (mirror.context()) { if (mirror.context()) {
content.context = this.serializeReference(mirror.context()); content.context = this.serializeReference(mirror.context());

65
deps/v8/src/objects-debug.cc

@ -547,42 +547,18 @@ static const char* TypeToString(InstanceType type) {
case INVALID_TYPE: return "INVALID"; case INVALID_TYPE: return "INVALID";
case MAP_TYPE: return "MAP"; case MAP_TYPE: return "MAP";
case HEAP_NUMBER_TYPE: return "HEAP_NUMBER"; case HEAP_NUMBER_TYPE: return "HEAP_NUMBER";
case SHORT_SYMBOL_TYPE: case SYMBOL_TYPE: return "SYMBOL";
case MEDIUM_SYMBOL_TYPE: case ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
case LONG_SYMBOL_TYPE: return "SYMBOL"; case CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
case SHORT_ASCII_SYMBOL_TYPE: case CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL";
case MEDIUM_ASCII_SYMBOL_TYPE: case EXTERNAL_ASCII_SYMBOL_TYPE:
case LONG_ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL"; case EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL";
case SHORT_CONS_SYMBOL_TYPE: case ASCII_STRING_TYPE: return "ASCII_STRING";
case MEDIUM_CONS_SYMBOL_TYPE: case STRING_TYPE: return "TWO_BYTE_STRING";
case LONG_CONS_SYMBOL_TYPE: return "CONS_SYMBOL"; case CONS_STRING_TYPE:
case SHORT_CONS_ASCII_SYMBOL_TYPE: case CONS_ASCII_STRING_TYPE: return "CONS_STRING";
case MEDIUM_CONS_ASCII_SYMBOL_TYPE: case EXTERNAL_ASCII_STRING_TYPE:
case LONG_CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL"; case EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
case SHORT_EXTERNAL_ASCII_SYMBOL_TYPE:
case MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE:
case LONG_EXTERNAL_ASCII_SYMBOL_TYPE:
case SHORT_EXTERNAL_SYMBOL_TYPE:
case MEDIUM_EXTERNAL_SYMBOL_TYPE:
case LONG_EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL";
case SHORT_ASCII_STRING_TYPE:
case MEDIUM_ASCII_STRING_TYPE:
case LONG_ASCII_STRING_TYPE: return "ASCII_STRING";
case SHORT_STRING_TYPE:
case MEDIUM_STRING_TYPE:
case LONG_STRING_TYPE: return "TWO_BYTE_STRING";
case SHORT_CONS_STRING_TYPE:
case MEDIUM_CONS_STRING_TYPE:
case LONG_CONS_STRING_TYPE:
case SHORT_CONS_ASCII_STRING_TYPE:
case MEDIUM_CONS_ASCII_STRING_TYPE:
case LONG_CONS_ASCII_STRING_TYPE: return "CONS_STRING";
case SHORT_EXTERNAL_ASCII_STRING_TYPE:
case MEDIUM_EXTERNAL_ASCII_STRING_TYPE:
case LONG_EXTERNAL_ASCII_STRING_TYPE:
case SHORT_EXTERNAL_STRING_TYPE:
case MEDIUM_EXTERNAL_STRING_TYPE:
case LONG_EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
case FIXED_ARRAY_TYPE: return "FIXED_ARRAY"; case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
case BYTE_ARRAY_TYPE: return "BYTE_ARRAY"; case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY"; case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY";
@ -1140,8 +1116,7 @@ void Script::ScriptVerify() {
VerifyPointer(data()); VerifyPointer(data());
VerifyPointer(wrapper()); VerifyPointer(wrapper());
type()->SmiVerify(); type()->SmiVerify();
VerifyPointer(line_ends_fixed_array()); VerifyPointer(line_ends());
VerifyPointer(line_ends_js_array());
VerifyPointer(id()); VerifyPointer(id());
} }
@ -1160,6 +1135,20 @@ void Script::ScriptPrint() {
type()->ShortPrint(); type()->ShortPrint();
PrintF("\n - id: "); PrintF("\n - id: ");
id()->ShortPrint(); id()->ShortPrint();
PrintF("\n - data: ");
data()->ShortPrint();
PrintF("\n - context data: ");
context_data()->ShortPrint();
PrintF("\n - wrapper: ");
wrapper()->ShortPrint();
PrintF("\n - compilation type: ");
compilation_type()->ShortPrint();
PrintF("\n - line ends: ");
line_ends()->ShortPrint();
PrintF("\n - eval from shared: ");
eval_from_shared()->ShortPrint();
PrintF("\n - eval from instructions offset: ");
eval_from_instructions_offset()->ShortPrint();
PrintF("\n"); PrintF("\n");
} }

152
deps/v8/src/objects-inl.h

@ -280,11 +280,6 @@ STATIC_CHECK((kStringRepresentationMask | kStringEncodingMask) ==
Internals::kFullStringRepresentationMask); Internals::kFullStringRepresentationMask);
uint32_t StringShape::size_tag() {
return (type_ & kStringSizeMask);
}
bool StringShape::IsSequentialAscii() { bool StringShape::IsSequentialAscii() {
return full_representation_tag() == (kSeqStringTag | kAsciiStringTag); return full_representation_tag() == (kSeqStringTag | kAsciiStringTag);
} }
@ -921,25 +916,6 @@ HeapObject* MapWord::ToForwardingAddress() {
} }
bool MapWord::IsSerializationAddress() {
return HAS_SMI_TAG(reinterpret_cast<Object*>(value_));
}
MapWord MapWord::FromSerializationAddress(int raw) {
// When the map word is being used as a serialization address we Smi-encode
// the serialization address (which is always a smallish positive integer).
return MapWord(reinterpret_cast<uintptr_t>(Smi::FromInt(raw)));
}
int MapWord::ToSerializationAddress() {
// When the map word is being used as a serialization address we treat the
// map word as a Smi and get the small integer that it encodes.
return reinterpret_cast<Smi*>(value_)->value();
}
bool MapWord::IsMarked() { bool MapWord::IsMarked() {
return (value_ & kMarkingMask) == 0; return (value_ & kMarkingMask) == 0;
} }
@ -1635,44 +1611,25 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
INT_ACCESSORS(Array, length, kLengthOffset) INT_ACCESSORS(Array, length, kLengthOffset)
bool String::Equals(String* other) { INT_ACCESSORS(String, length, kLengthOffset)
if (other == this) return true;
if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) {
return false;
}
return SlowEquals(other);
}
int String::length() {
uint32_t len = READ_INT_FIELD(this, kLengthOffset);
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
ASSERT(kLongStringTag == 0);
return len >> (StringShape(this).size_tag() + kLongLengthShift); uint32_t String::hash_field() {
return READ_UINT32_FIELD(this, kHashFieldOffset);
} }
void String::set_length(int value) { void String::set_hash_field(uint32_t value) {
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift); WRITE_UINT32_FIELD(this, kHashFieldOffset, value);
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
ASSERT(kLongStringTag == 0);
WRITE_INT_FIELD(this,
kLengthOffset,
value << (StringShape(this).size_tag() + kLongLengthShift));
}
uint32_t String::length_field() {
return READ_UINT32_FIELD(this, kLengthOffset);
} }
void String::set_length_field(uint32_t value) { bool String::Equals(String* other) {
WRITE_UINT32_FIELD(this, kLengthOffset, value); if (other == this) return true;
if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) {
return false;
}
return SlowEquals(other);
} }
@ -1779,30 +1736,12 @@ void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) { int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) {
uint32_t length = READ_INT_FIELD(this, kLengthOffset); uint32_t length = READ_INT_FIELD(this, kLengthOffset);
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
ASSERT(kLongStringTag == 0);
// Use the map (and not 'this') to compute the size tag, since
// TwoByteStringSize is called during GC when maps are encoded.
length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
return SizeFor(length); return SizeFor(length);
} }
int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) { int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
uint32_t length = READ_INT_FIELD(this, kLengthOffset); uint32_t length = READ_INT_FIELD(this, kLengthOffset);
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
ASSERT(kLongStringTag == 0);
// Use the map (and not 'this') to compute the size tag, since
// AsciiStringSize is called during GC when maps are encoded.
length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
return SizeFor(length); return SizeFor(length);
} }
@ -1850,34 +1789,6 @@ void ExternalAsciiString::set_resource(
} }
Map* ExternalAsciiString::StringMap(int length) {
Map* map;
// Number of characters: determines the map.
if (length <= String::kMaxShortSize) {
map = Heap::short_external_ascii_string_map();
} else if (length <= String::kMaxMediumSize) {
map = Heap::medium_external_ascii_string_map();
} else {
map = Heap::long_external_ascii_string_map();
}
return map;
}
Map* ExternalAsciiString::SymbolMap(int length) {
Map* map;
// Number of characters: determines the map.
if (length <= String::kMaxShortSize) {
map = Heap::short_external_ascii_symbol_map();
} else if (length <= String::kMaxMediumSize) {
map = Heap::medium_external_ascii_symbol_map();
} else {
map = Heap::long_external_ascii_symbol_map();
}
return map;
}
ExternalTwoByteString::Resource* ExternalTwoByteString::resource() { ExternalTwoByteString::Resource* ExternalTwoByteString::resource() {
return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)); return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset));
} }
@ -1889,34 +1800,6 @@ void ExternalTwoByteString::set_resource(
} }
Map* ExternalTwoByteString::StringMap(int length) {
Map* map;
// Number of characters: determines the map.
if (length <= String::kMaxShortSize) {
map = Heap::short_external_string_map();
} else if (length <= String::kMaxMediumSize) {
map = Heap::medium_external_string_map();
} else {
map = Heap::long_external_string_map();
}
return map;
}
Map* ExternalTwoByteString::SymbolMap(int length) {
Map* map;
// Number of characters: determines the map.
if (length <= String::kMaxShortSize) {
map = Heap::short_external_symbol_map();
} else if (length <= String::kMaxMediumSize) {
map = Heap::medium_external_symbol_map();
} else {
map = Heap::long_external_symbol_map();
}
return map;
}
byte ByteArray::get(int index) { byte ByteArray::get(int index) {
ASSERT(index >= 0 && index < this->length()); ASSERT(index >= 0 && index < this->length());
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
@ -2441,9 +2324,8 @@ ACCESSORS(Script, context_data, Object, kContextOffset)
ACCESSORS(Script, wrapper, Proxy, kWrapperOffset) ACCESSORS(Script, wrapper, Proxy, kWrapperOffset)
ACCESSORS(Script, type, Smi, kTypeOffset) ACCESSORS(Script, type, Smi, kTypeOffset)
ACCESSORS(Script, compilation_type, Smi, kCompilationTypeOffset) ACCESSORS(Script, compilation_type, Smi, kCompilationTypeOffset)
ACCESSORS(Script, line_ends_fixed_array, Object, kLineEndsFixedArrayOffset) ACCESSORS(Script, line_ends, Object, kLineEndsOffset)
ACCESSORS(Script, line_ends_js_array, Object, kLineEndsJSArrayOffset) ACCESSORS(Script, eval_from_shared, Object, kEvalFromSharedOffset)
ACCESSORS(Script, eval_from_function, Object, kEvalFromFunctionOffset)
ACCESSORS(Script, eval_from_instructions_offset, Smi, ACCESSORS(Script, eval_from_instructions_offset, Smi,
kEvalFrominstructionsOffsetOffset) kEvalFrominstructionsOffsetOffset)
@ -2900,13 +2782,13 @@ NumberDictionary* JSObject::element_dictionary() {
bool String::HasHashCode() { bool String::HasHashCode() {
return (length_field() & kHashComputedMask) != 0; return (hash_field() & kHashComputedMask) != 0;
} }
uint32_t String::Hash() { uint32_t String::Hash() {
// Fast case: has hash code already been computed? // Fast case: has hash code already been computed?
uint32_t field = length_field(); uint32_t field = hash_field();
if (field & kHashComputedMask) return field >> kHashShift; if (field & kHashComputedMask) return field >> kHashShift;
// Slow case: compute hash code and set it. // Slow case: compute hash code and set it.
return ComputeAndSetHash(); return ComputeAndSetHash();
@ -2923,7 +2805,7 @@ StringHasher::StringHasher(int length)
bool StringHasher::has_trivial_hash() { bool StringHasher::has_trivial_hash() {
return length_ > String::kMaxMediumSize; return length_ > String::kMaxHashCalcLength;
} }
@ -2979,7 +2861,7 @@ uint32_t StringHasher::GetHash() {
bool String::AsArrayIndex(uint32_t* index) { bool String::AsArrayIndex(uint32_t* index) {
uint32_t field = length_field(); uint32_t field = hash_field();
if ((field & kHashComputedMask) && !(field & kIsArrayIndexMask)) return false; if ((field & kHashComputedMask) && !(field & kIsArrayIndexMask)) return false;
return SlowAsArrayIndex(index); return SlowAsArrayIndex(index);
} }

132
deps/v8/src/objects.cc

@ -37,6 +37,7 @@
#include "scanner.h" #include "scanner.h"
#include "scopeinfo.h" #include "scopeinfo.h"
#include "string-stream.h" #include "string-stream.h"
#include "utils.h"
#ifdef ENABLE_DISASSEMBLER #ifdef ENABLE_DISASSEMBLER
#include "disassembler.h" #include "disassembler.h"
@ -754,19 +755,21 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
ASSERT(size >= ExternalString::kSize); ASSERT(size >= ExternalString::kSize);
bool is_symbol = this->IsSymbol(); bool is_symbol = this->IsSymbol();
int length = this->length(); int length = this->length();
int hash_field = this->hash_field();
// Morph the object to an external string by adjusting the map and // Morph the object to an external string by adjusting the map and
// reinitializing the fields. // reinitializing the fields.
this->set_map(ExternalTwoByteString::StringMap(length)); this->set_map(Heap::external_string_map());
ExternalTwoByteString* self = ExternalTwoByteString::cast(this); ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
self->set_length(length); self->set_length(length);
self->set_hash_field(hash_field);
self->set_resource(resource); self->set_resource(resource);
// Additionally make the object into an external symbol if the original string // Additionally make the object into an external symbol if the original string
// was a symbol to start with. // was a symbol to start with.
if (is_symbol) { if (is_symbol) {
self->Hash(); // Force regeneration of the hash value. self->Hash(); // Force regeneration of the hash value.
// Now morph this external string into a external symbol. // Now morph this external string into a external symbol.
self->set_map(ExternalTwoByteString::SymbolMap(length)); this->set_map(Heap::external_symbol_map());
} }
// Fill the remainder of the string with dead wood. // Fill the remainder of the string with dead wood.
@ -798,19 +801,21 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
ASSERT(size >= ExternalString::kSize); ASSERT(size >= ExternalString::kSize);
bool is_symbol = this->IsSymbol(); bool is_symbol = this->IsSymbol();
int length = this->length(); int length = this->length();
int hash_field = this->hash_field();
// Morph the object to an external string by adjusting the map and // Morph the object to an external string by adjusting the map and
// reinitializing the fields. // reinitializing the fields.
this->set_map(ExternalAsciiString::StringMap(length)); this->set_map(Heap::external_ascii_string_map());
ExternalAsciiString* self = ExternalAsciiString::cast(this); ExternalAsciiString* self = ExternalAsciiString::cast(this);
self->set_length(length); self->set_length(length);
self->set_hash_field(hash_field);
self->set_resource(resource); self->set_resource(resource);
// Additionally make the object into an external symbol if the original string // Additionally make the object into an external symbol if the original string
// was a symbol to start with. // was a symbol to start with.
if (is_symbol) { if (is_symbol) {
self->Hash(); // Force regeneration of the hash value. self->Hash(); // Force regeneration of the hash value.
// Now morph this external string into a external symbol. // Now morph this external string into a external symbol.
self->set_map(ExternalAsciiString::SymbolMap(length)); this->set_map(Heap::external_ascii_symbol_map());
} }
// Fill the remainder of the string with dead wood. // Fill the remainder of the string with dead wood.
@ -822,7 +827,7 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
void String::StringShortPrint(StringStream* accumulator) { void String::StringShortPrint(StringStream* accumulator) {
int len = length(); int len = length();
if (len > kMaxMediumSize) { if (len > kMaxShortPrintLength) {
accumulator->Add("<Very long string[%u]>", len); accumulator->Add("<Very long string[%u]>", len);
return; return;
} }
@ -2628,33 +2633,24 @@ bool JSObject::ReferencesObject(Object* obj) {
// Tests for the fast common case for property enumeration: // Tests for the fast common case for property enumeration:
// - this object has an enum cache // - This object and all prototypes has an enum cache (which means that it has
// - this object has no elements // no interceptors and needs no access checks).
// - no prototype has enumerable properties/elements // - This object has no elements.
// - neither this object nor any prototype has interceptors // - No prototype has enumerable properties/elements.
bool JSObject::IsSimpleEnum() { bool JSObject::IsSimpleEnum() {
JSObject* arguments_boilerplate =
Top::context()->global_context()->arguments_boilerplate();
JSFunction* arguments_function =
JSFunction::cast(arguments_boilerplate->map()->constructor());
if (IsAccessCheckNeeded()) return false;
if (map()->constructor() == arguments_function) return false;
for (Object* o = this; for (Object* o = this;
o != Heap::null_value(); o != Heap::null_value();
o = JSObject::cast(o)->GetPrototype()) { o = JSObject::cast(o)->GetPrototype()) {
JSObject* curr = JSObject::cast(o); JSObject* curr = JSObject::cast(o);
if (!curr->HasFastProperties()) return false;
if (!curr->map()->instance_descriptors()->HasEnumCache()) return false; if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
ASSERT(!curr->HasNamedInterceptor());
ASSERT(!curr->HasIndexedInterceptor());
ASSERT(!curr->IsAccessCheckNeeded());
if (curr->NumberOfEnumElements() > 0) return false; if (curr->NumberOfEnumElements() > 0) return false;
if (curr->HasNamedInterceptor()) return false;
if (curr->HasIndexedInterceptor()) return false;
if (curr != this) { if (curr != this) {
FixedArray* curr_fixed_array = FixedArray* curr_fixed_array =
FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache()); FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
if (curr_fixed_array->length() > 0) { if (curr_fixed_array->length() > 0) return false;
return false;
}
} }
} }
return true; return true;
@ -4484,23 +4480,11 @@ bool String::MarkAsUndetectable() {
if (StringShape(this).IsSymbol()) return false; if (StringShape(this).IsSymbol()) return false;
Map* map = this->map(); Map* map = this->map();
if (map == Heap::short_string_map()) { if (map == Heap::string_map()) {
this->set_map(Heap::undetectable_short_string_map()); this->set_map(Heap::undetectable_string_map());
return true;
} else if (map == Heap::medium_string_map()) {
this->set_map(Heap::undetectable_medium_string_map());
return true; return true;
} else if (map == Heap::long_string_map()) { } else if (map == Heap::ascii_string_map()) {
this->set_map(Heap::undetectable_long_string_map()); this->set_map(Heap::undetectable_ascii_string_map());
return true;
} else if (map == Heap::short_ascii_string_map()) {
this->set_map(Heap::undetectable_short_ascii_string_map());
return true;
} else if (map == Heap::medium_ascii_string_map()) {
this->set_map(Heap::undetectable_medium_ascii_string_map());
return true;
} else if (map == Heap::long_ascii_string_map()) {
this->set_map(Heap::undetectable_long_ascii_string_map());
return true; return true;
} }
// Rest cannot be marked as undetectable // Rest cannot be marked as undetectable
@ -4523,17 +4507,17 @@ bool String::IsEqualTo(Vector<const char> str) {
uint32_t String::ComputeAndSetHash() { uint32_t String::ComputeAndSetHash() {
// Should only be called if hash code has not yet been computed. // Should only be called if hash code has not yet been computed.
ASSERT(!(length_field() & kHashComputedMask)); ASSERT(!(hash_field() & kHashComputedMask));
// Compute the hash code. // Compute the hash code.
StringInputBuffer buffer(this); StringInputBuffer buffer(this);
uint32_t field = ComputeLengthAndHashField(&buffer, length()); uint32_t field = ComputeHashField(&buffer, length());
// Store the hash code in the object. // Store the hash code in the object.
set_length_field(field); set_hash_field(field);
// Check the hash code is there. // Check the hash code is there.
ASSERT(length_field() & kHashComputedMask); ASSERT(hash_field() & kHashComputedMask);
uint32_t result = field >> kHashShift; uint32_t result = field >> kHashShift;
ASSERT(result != 0); // Ensure that the hash value of 0 is never computed. ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
return result; return result;
@ -4573,9 +4557,10 @@ bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
bool String::SlowAsArrayIndex(uint32_t* index) { bool String::SlowAsArrayIndex(uint32_t* index) {
if (length() <= kMaxCachedArrayIndexLength) { if (length() <= kMaxCachedArrayIndexLength) {
Hash(); // force computation of hash code Hash(); // force computation of hash code
uint32_t field = length_field(); uint32_t field = hash_field();
if ((field & kIsArrayIndexMask) == 0) return false; if ((field & kIsArrayIndexMask) == 0) return false;
*index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift; // Isolate the array index form the full hash field.
*index = (kArrayIndexHashMask & field) >> kHashShift;
return true; return true;
} else { } else {
StringInputBuffer buffer(this); StringInputBuffer buffer(this);
@ -4584,37 +4569,42 @@ bool String::SlowAsArrayIndex(uint32_t* index) {
} }
static inline uint32_t HashField(uint32_t hash, bool is_array_index) { static inline uint32_t HashField(uint32_t hash,
bool is_array_index,
int length = -1) {
uint32_t result = uint32_t result =
(hash << String::kLongLengthShift) | String::kHashComputedMask; (hash << String::kHashShift) | String::kHashComputedMask;
if (is_array_index) result |= String::kIsArrayIndexMask; if (is_array_index) {
// For array indexes mix the length into the hash as an array index could
// be zero.
ASSERT(length > 0);
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
(1 << String::kArrayIndexValueBits));
result |= String::kIsArrayIndexMask;
result |= length << String::kArrayIndexHashLengthShift;
}
return result; return result;
} }
uint32_t StringHasher::GetHashField() { uint32_t StringHasher::GetHashField() {
ASSERT(is_valid()); ASSERT(is_valid());
if (length_ <= String::kMaxShortSize) { if (length_ <= String::kMaxHashCalcLength) {
uint32_t payload;
if (is_array_index()) { if (is_array_index()) {
payload = v8::internal::HashField(array_index(), true); return v8::internal::HashField(array_index(), true, length_);
} else { } else {
payload = v8::internal::HashField(GetHash(), false); return v8::internal::HashField(GetHash(), false);
} }
return (payload & ((1 << String::kShortLengthShift) - 1)) |
(length_ << String::kShortLengthShift);
} else if (length_ <= String::kMaxMediumSize) {
uint32_t payload = v8::internal::HashField(GetHash(), false); uint32_t payload = v8::internal::HashField(GetHash(), false);
return (payload & ((1 << String::kMediumLengthShift) - 1)) | return payload;
(length_ << String::kMediumLengthShift);
} else { } else {
return v8::internal::HashField(length_, false); return v8::internal::HashField(length_, false);
} }
} }
uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer, uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
int length) { int length) {
StringHasher hasher(length); StringHasher hasher(length);
// Very long strings have a trivial hash that doesn't inspect the // Very long strings have a trivial hash that doesn't inspect the
@ -6177,6 +6167,7 @@ Object* JSObject::GetPropertyPostInterceptor(JSObject* receiver,
return pt->GetPropertyWithReceiver(receiver, name, attributes); return pt->GetPropertyWithReceiver(receiver, name, attributes);
} }
Object* JSObject::GetLocalPropertyPostInterceptor( Object* JSObject::GetLocalPropertyPostInterceptor(
JSObject* receiver, JSObject* receiver,
String* name, String* name,
@ -6478,6 +6469,15 @@ int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
int JSObject::NumberOfEnumElements() { int JSObject::NumberOfEnumElements() {
// Fast case for objects with no elements.
if (!IsJSValue() && HasFastElements()) {
uint32_t length = IsJSArray() ?
static_cast<uint32_t>(
Smi::cast(JSArray::cast(this)->length())->value()) :
static_cast<uint32_t>(FixedArray::cast(elements())->length());
if (length == 0) return 0;
}
// Compute the number of enumerable elements.
return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM)); return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
} }
@ -6737,19 +6737,19 @@ class RegExpKey : public HashTableKey {
class Utf8SymbolKey : public HashTableKey { class Utf8SymbolKey : public HashTableKey {
public: public:
explicit Utf8SymbolKey(Vector<const char> string) explicit Utf8SymbolKey(Vector<const char> string)
: string_(string), length_field_(0) { } : string_(string), hash_field_(0) { }
bool IsMatch(Object* string) { bool IsMatch(Object* string) {
return String::cast(string)->IsEqualTo(string_); return String::cast(string)->IsEqualTo(string_);
} }
uint32_t Hash() { uint32_t Hash() {
if (length_field_ != 0) return length_field_ >> String::kHashShift; if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
unibrow::Utf8InputBuffer<> buffer(string_.start(), unibrow::Utf8InputBuffer<> buffer(string_.start(),
static_cast<unsigned>(string_.length())); static_cast<unsigned>(string_.length()));
chars_ = buffer.Length(); chars_ = buffer.Length();
length_field_ = String::ComputeLengthAndHashField(&buffer, chars_); hash_field_ = String::ComputeHashField(&buffer, chars_);
uint32_t result = length_field_ >> String::kHashShift; uint32_t result = hash_field_ >> String::kHashShift;
ASSERT(result != 0); // Ensure that the hash value of 0 is never computed. ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
return result; return result;
} }
@ -6759,12 +6759,12 @@ class Utf8SymbolKey : public HashTableKey {
} }
Object* AsObject() { Object* AsObject() {
if (length_field_ == 0) Hash(); if (hash_field_ == 0) Hash();
return Heap::AllocateSymbol(string_, chars_, length_field_); return Heap::AllocateSymbol(string_, chars_, hash_field_);
} }
Vector<const char> string_; Vector<const char> string_;
uint32_t length_field_; uint32_t hash_field_;
int chars_; // Caches the number of characters when computing the hash code. int chars_; // Caches the number of characters when computing the hash code.
}; };
@ -6805,7 +6805,7 @@ class SymbolKey : public HashTableKey {
StringInputBuffer buffer(string_); StringInputBuffer buffer(string_);
return Heap::AllocateInternalSymbol(&buffer, return Heap::AllocateInternalSymbol(&buffer,
string_->length(), string_->length(),
string_->length_field()); string_->hash_field());
} }
static uint32_t StringHash(Object* obj) { static uint32_t StringHash(Object* obj) {

506
deps/v8/src/objects.h

@ -221,248 +221,128 @@ enum PropertyNormalizationMode {
// NOTE: Everything following JS_VALUE_TYPE is considered a // NOTE: Everything following JS_VALUE_TYPE is considered a
// JSObject for GC purposes. The first four entries here have typeof // JSObject for GC purposes. The first four entries here have typeof
// 'object', whereas JS_FUNCTION_TYPE has typeof 'function'. // 'object', whereas JS_FUNCTION_TYPE has typeof 'function'.
#define INSTANCE_TYPE_LIST_ALL(V) \ #define INSTANCE_TYPE_LIST_ALL(V) \
V(SHORT_SYMBOL_TYPE) \ V(SYMBOL_TYPE) \
V(MEDIUM_SYMBOL_TYPE) \ V(ASCII_SYMBOL_TYPE) \
V(LONG_SYMBOL_TYPE) \ V(CONS_SYMBOL_TYPE) \
V(SHORT_ASCII_SYMBOL_TYPE) \ V(CONS_ASCII_SYMBOL_TYPE) \
V(MEDIUM_ASCII_SYMBOL_TYPE) \ V(EXTERNAL_SYMBOL_TYPE) \
V(LONG_ASCII_SYMBOL_TYPE) \ V(EXTERNAL_ASCII_SYMBOL_TYPE) \
V(SHORT_CONS_SYMBOL_TYPE) \ V(STRING_TYPE) \
V(MEDIUM_CONS_SYMBOL_TYPE) \ V(ASCII_STRING_TYPE) \
V(LONG_CONS_SYMBOL_TYPE) \ V(CONS_STRING_TYPE) \
V(SHORT_CONS_ASCII_SYMBOL_TYPE) \ V(CONS_ASCII_STRING_TYPE) \
V(MEDIUM_CONS_ASCII_SYMBOL_TYPE) \ V(EXTERNAL_STRING_TYPE) \
V(LONG_CONS_ASCII_SYMBOL_TYPE) \ V(EXTERNAL_ASCII_STRING_TYPE) \
V(SHORT_EXTERNAL_SYMBOL_TYPE) \ V(PRIVATE_EXTERNAL_ASCII_STRING_TYPE) \
V(MEDIUM_EXTERNAL_SYMBOL_TYPE) \ \
V(LONG_EXTERNAL_SYMBOL_TYPE) \ V(MAP_TYPE) \
V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE) \ V(HEAP_NUMBER_TYPE) \
V(MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE) \ V(FIXED_ARRAY_TYPE) \
V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE) \ V(CODE_TYPE) \
V(SHORT_STRING_TYPE) \ V(JS_GLOBAL_PROPERTY_CELL_TYPE) \
V(MEDIUM_STRING_TYPE) \ V(ODDBALL_TYPE) \
V(LONG_STRING_TYPE) \ V(PROXY_TYPE) \
V(SHORT_ASCII_STRING_TYPE) \ V(BYTE_ARRAY_TYPE) \
V(MEDIUM_ASCII_STRING_TYPE) \ V(PIXEL_ARRAY_TYPE) \
V(LONG_ASCII_STRING_TYPE) \ /* Note: the order of these external array */ \
V(SHORT_CONS_STRING_TYPE) \ /* types is relied upon in */ \
V(MEDIUM_CONS_STRING_TYPE) \ /* Object::IsExternalArray(). */ \
V(LONG_CONS_STRING_TYPE) \ V(EXTERNAL_BYTE_ARRAY_TYPE) \
V(SHORT_CONS_ASCII_STRING_TYPE) \ V(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE) \
V(MEDIUM_CONS_ASCII_STRING_TYPE) \ V(EXTERNAL_SHORT_ARRAY_TYPE) \
V(LONG_CONS_ASCII_STRING_TYPE) \ V(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE) \
V(SHORT_EXTERNAL_STRING_TYPE) \ V(EXTERNAL_INT_ARRAY_TYPE) \
V(MEDIUM_EXTERNAL_STRING_TYPE) \ V(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE) \
V(LONG_EXTERNAL_STRING_TYPE) \ V(EXTERNAL_FLOAT_ARRAY_TYPE) \
V(SHORT_EXTERNAL_ASCII_STRING_TYPE) \ V(FILLER_TYPE) \
V(MEDIUM_EXTERNAL_ASCII_STRING_TYPE) \ \
V(LONG_EXTERNAL_ASCII_STRING_TYPE) \ V(ACCESSOR_INFO_TYPE) \
V(LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE) \ V(ACCESS_CHECK_INFO_TYPE) \
\ V(INTERCEPTOR_INFO_TYPE) \
V(MAP_TYPE) \ V(SHARED_FUNCTION_INFO_TYPE) \
V(HEAP_NUMBER_TYPE) \ V(CALL_HANDLER_INFO_TYPE) \
V(FIXED_ARRAY_TYPE) \ V(FUNCTION_TEMPLATE_INFO_TYPE) \
V(CODE_TYPE) \ V(OBJECT_TEMPLATE_INFO_TYPE) \
V(JS_GLOBAL_PROPERTY_CELL_TYPE) \ V(SIGNATURE_INFO_TYPE) \
V(ODDBALL_TYPE) \ V(TYPE_SWITCH_INFO_TYPE) \
V(PROXY_TYPE) \ V(SCRIPT_TYPE) \
V(BYTE_ARRAY_TYPE) \ \
V(PIXEL_ARRAY_TYPE) \ V(JS_VALUE_TYPE) \
/* Note: the order of these external array */ \ V(JS_OBJECT_TYPE) \
/* types is relied upon in */ \ V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
/* Object::IsExternalArray(). */ \ V(JS_GLOBAL_OBJECT_TYPE) \
V(EXTERNAL_BYTE_ARRAY_TYPE) \ V(JS_BUILTINS_OBJECT_TYPE) \
V(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE) \ V(JS_GLOBAL_PROXY_TYPE) \
V(EXTERNAL_SHORT_ARRAY_TYPE) \ V(JS_ARRAY_TYPE) \
V(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE) \ V(JS_REGEXP_TYPE) \
V(EXTERNAL_INT_ARRAY_TYPE) \ \
V(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE) \ V(JS_FUNCTION_TYPE) \
V(EXTERNAL_FLOAT_ARRAY_TYPE) \
V(FILLER_TYPE) \
\
V(ACCESSOR_INFO_TYPE) \
V(ACCESS_CHECK_INFO_TYPE) \
V(INTERCEPTOR_INFO_TYPE) \
V(SHARED_FUNCTION_INFO_TYPE) \
V(CALL_HANDLER_INFO_TYPE) \
V(FUNCTION_TEMPLATE_INFO_TYPE) \
V(OBJECT_TEMPLATE_INFO_TYPE) \
V(SIGNATURE_INFO_TYPE) \
V(TYPE_SWITCH_INFO_TYPE) \
V(SCRIPT_TYPE) \
\
V(JS_VALUE_TYPE) \
V(JS_OBJECT_TYPE) \
V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
V(JS_GLOBAL_OBJECT_TYPE) \
V(JS_BUILTINS_OBJECT_TYPE) \
V(JS_GLOBAL_PROXY_TYPE) \
V(JS_ARRAY_TYPE) \
V(JS_REGEXP_TYPE) \
\
V(JS_FUNCTION_TYPE) \
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
#define INSTANCE_TYPE_LIST_DEBUGGER(V) \ #define INSTANCE_TYPE_LIST_DEBUGGER(V) \
V(DEBUG_INFO_TYPE) \ V(DEBUG_INFO_TYPE) \
V(BREAK_POINT_INFO_TYPE) V(BREAK_POINT_INFO_TYPE)
#else #else
#define INSTANCE_TYPE_LIST_DEBUGGER(V) #define INSTANCE_TYPE_LIST_DEBUGGER(V)
#endif #endif
#define INSTANCE_TYPE_LIST(V) \ #define INSTANCE_TYPE_LIST(V) \
INSTANCE_TYPE_LIST_ALL(V) \ INSTANCE_TYPE_LIST_ALL(V) \
INSTANCE_TYPE_LIST_DEBUGGER(V) INSTANCE_TYPE_LIST_DEBUGGER(V)
// Since string types are not consecutive, this macro is used to // Since string types are not consecutive, this macro is used to
// iterate over them. // iterate over them.
#define STRING_TYPE_LIST(V) \ #define STRING_TYPE_LIST(V) \
V(SHORT_SYMBOL_TYPE, \ V(SYMBOL_TYPE, \
SeqTwoByteString::kAlignedSize, \ SeqTwoByteString::kAlignedSize, \
short_symbol, \ symbol, \
ShortSymbol) \ Symbol) \
V(MEDIUM_SYMBOL_TYPE, \ V(ASCII_SYMBOL_TYPE, \
SeqTwoByteString::kAlignedSize, \
medium_symbol, \
MediumSymbol) \
V(LONG_SYMBOL_TYPE, \
SeqTwoByteString::kAlignedSize, \
long_symbol, \
LongSymbol) \
V(SHORT_ASCII_SYMBOL_TYPE, \
SeqAsciiString::kAlignedSize, \
short_ascii_symbol, \
ShortAsciiSymbol) \
V(MEDIUM_ASCII_SYMBOL_TYPE, \
SeqAsciiString::kAlignedSize, \ SeqAsciiString::kAlignedSize, \
medium_ascii_symbol, \ ascii_symbol, \
MediumAsciiSymbol) \ AsciiSymbol) \
V(LONG_ASCII_SYMBOL_TYPE, \ V(CONS_SYMBOL_TYPE, \
SeqAsciiString::kAlignedSize, \
long_ascii_symbol, \
LongAsciiSymbol) \
V(SHORT_CONS_SYMBOL_TYPE, \
ConsString::kSize, \
short_cons_symbol, \
ShortConsSymbol) \
V(MEDIUM_CONS_SYMBOL_TYPE, \
ConsString::kSize, \ ConsString::kSize, \
medium_cons_symbol, \ cons_symbol, \
MediumConsSymbol) \ ConsSymbol) \
V(LONG_CONS_SYMBOL_TYPE, \ V(CONS_ASCII_SYMBOL_TYPE, \
ConsString::kSize, \ ConsString::kSize, \
long_cons_symbol, \ cons_ascii_symbol, \
LongConsSymbol) \ ConsAsciiSymbol) \
V(SHORT_CONS_ASCII_SYMBOL_TYPE, \ V(EXTERNAL_SYMBOL_TYPE, \
ConsString::kSize, \
short_cons_ascii_symbol, \
ShortConsAsciiSymbol) \
V(MEDIUM_CONS_ASCII_SYMBOL_TYPE, \
ConsString::kSize, \
medium_cons_ascii_symbol, \
MediumConsAsciiSymbol) \
V(LONG_CONS_ASCII_SYMBOL_TYPE, \
ConsString::kSize, \
long_cons_ascii_symbol, \
LongConsAsciiSymbol) \
V(SHORT_EXTERNAL_SYMBOL_TYPE, \
ExternalTwoByteString::kSize, \
short_external_symbol, \
ShortExternalSymbol) \
V(MEDIUM_EXTERNAL_SYMBOL_TYPE, \
ExternalTwoByteString::kSize, \ ExternalTwoByteString::kSize, \
medium_external_symbol, \ external_symbol, \
MediumExternalSymbol) \ ExternalSymbol) \
V(LONG_EXTERNAL_SYMBOL_TYPE, \ V(EXTERNAL_ASCII_SYMBOL_TYPE, \
ExternalTwoByteString::kSize, \
long_external_symbol, \
LongExternalSymbol) \
V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE, \
ExternalAsciiString::kSize, \
short_external_ascii_symbol, \
ShortExternalAsciiSymbol) \
V(MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE, \
ExternalAsciiString::kSize, \ ExternalAsciiString::kSize, \
medium_external_ascii_symbol, \ external_ascii_symbol, \
MediumExternalAsciiSymbol) \ ExternalAsciiSymbol) \
V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE, \ V(STRING_TYPE, \
ExternalAsciiString::kSize, \
long_external_ascii_symbol, \
LongExternalAsciiSymbol) \
V(SHORT_STRING_TYPE, \
SeqTwoByteString::kAlignedSize, \
short_string, \
ShortString) \
V(MEDIUM_STRING_TYPE, \
SeqTwoByteString::kAlignedSize, \ SeqTwoByteString::kAlignedSize, \
medium_string, \ string, \
MediumString) \ String) \
V(LONG_STRING_TYPE, \ V(ASCII_STRING_TYPE, \
SeqTwoByteString::kAlignedSize, \
long_string, \
LongString) \
V(SHORT_ASCII_STRING_TYPE, \
SeqAsciiString::kAlignedSize, \
short_ascii_string, \
ShortAsciiString) \
V(MEDIUM_ASCII_STRING_TYPE, \
SeqAsciiString::kAlignedSize, \ SeqAsciiString::kAlignedSize, \
medium_ascii_string, \ ascii_string, \
MediumAsciiString) \ AsciiString) \
V(LONG_ASCII_STRING_TYPE, \ V(CONS_STRING_TYPE, \
SeqAsciiString::kAlignedSize, \
long_ascii_string, \
LongAsciiString) \
V(SHORT_CONS_STRING_TYPE, \
ConsString::kSize, \
short_cons_string, \
ShortConsString) \
V(MEDIUM_CONS_STRING_TYPE, \
ConsString::kSize, \ ConsString::kSize, \
medium_cons_string, \ cons_string, \
MediumConsString) \ ConsString) \
V(LONG_CONS_STRING_TYPE, \ V(CONS_ASCII_STRING_TYPE, \
ConsString::kSize, \ ConsString::kSize, \
long_cons_string, \ cons_ascii_string, \
LongConsString) \ ConsAsciiString) \
V(SHORT_CONS_ASCII_STRING_TYPE, \ V(EXTERNAL_STRING_TYPE, \
ConsString::kSize, \
short_cons_ascii_string, \
ShortConsAsciiString) \
V(MEDIUM_CONS_ASCII_STRING_TYPE, \
ConsString::kSize, \
medium_cons_ascii_string, \
MediumConsAsciiString) \
V(LONG_CONS_ASCII_STRING_TYPE, \
ConsString::kSize, \
long_cons_ascii_string, \
LongConsAsciiString) \
V(SHORT_EXTERNAL_STRING_TYPE, \
ExternalTwoByteString::kSize, \
short_external_string, \
ShortExternalString) \
V(MEDIUM_EXTERNAL_STRING_TYPE, \
ExternalTwoByteString::kSize, \
medium_external_string, \
MediumExternalString) \
V(LONG_EXTERNAL_STRING_TYPE, \
ExternalTwoByteString::kSize, \ ExternalTwoByteString::kSize, \
long_external_string, \ external_string, \
LongExternalString) \ ExternalString) \
V(SHORT_EXTERNAL_ASCII_STRING_TYPE, \ V(EXTERNAL_ASCII_STRING_TYPE, \
ExternalAsciiString::kSize, \ ExternalAsciiString::kSize, \
short_external_ascii_string, \ external_ascii_string, \
ShortExternalAsciiString) \ ExternalAsciiString) \
V(MEDIUM_EXTERNAL_ASCII_STRING_TYPE, \
ExternalAsciiString::kSize, \
medium_external_ascii_string, \
MediumExternalAsciiString) \
V(LONG_EXTERNAL_ASCII_STRING_TYPE, \
ExternalAsciiString::kSize, \
long_external_ascii_string, \
LongExternalAsciiString)
// A struct is a simple object a set of object-valued fields. Including an // A struct is a simple object a set of object-valued fields. Including an
// object type in this causes the compiler to generate most of the boilerplate // object type in this causes the compiler to generate most of the boilerplate
@ -473,27 +353,27 @@ enum PropertyNormalizationMode {
// Note that for subtle reasons related to the ordering or numerical values of // Note that for subtle reasons related to the ordering or numerical values of
// type tags, elements in this list have to be added to the INSTANCE_TYPE_LIST // type tags, elements in this list have to be added to the INSTANCE_TYPE_LIST
// manually. // manually.
#define STRUCT_LIST_ALL(V) \ #define STRUCT_LIST_ALL(V) \
V(ACCESSOR_INFO, AccessorInfo, accessor_info) \ V(ACCESSOR_INFO, AccessorInfo, accessor_info) \
V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info) \ V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info) \
V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info) \ V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info) \
V(CALL_HANDLER_INFO, CallHandlerInfo, call_handler_info) \ V(CALL_HANDLER_INFO, CallHandlerInfo, call_handler_info) \
V(FUNCTION_TEMPLATE_INFO, FunctionTemplateInfo, function_template_info) \ V(FUNCTION_TEMPLATE_INFO, FunctionTemplateInfo, function_template_info) \
V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \ V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \
V(SIGNATURE_INFO, SignatureInfo, signature_info) \ V(SIGNATURE_INFO, SignatureInfo, signature_info) \
V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \ V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \
V(SCRIPT, Script, script) V(SCRIPT, Script, script)
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
#define STRUCT_LIST_DEBUGGER(V) \ #define STRUCT_LIST_DEBUGGER(V) \
V(DEBUG_INFO, DebugInfo, debug_info) \ V(DEBUG_INFO, DebugInfo, debug_info) \
V(BREAK_POINT_INFO, BreakPointInfo, break_point_info) V(BREAK_POINT_INFO, BreakPointInfo, break_point_info)
#else #else
#define STRUCT_LIST_DEBUGGER(V) #define STRUCT_LIST_DEBUGGER(V)
#endif #endif
#define STRUCT_LIST(V) \ #define STRUCT_LIST(V) \
STRUCT_LIST_ALL(V) \ STRUCT_LIST_ALL(V) \
STRUCT_LIST_DEBUGGER(V) STRUCT_LIST_DEBUGGER(V)
// We use the full 8 bits of the instance_type field to encode heap object // We use the full 8 bits of the instance_type field to encode heap object
@ -509,15 +389,6 @@ const uint32_t kIsSymbolMask = 0x20;
const uint32_t kNotSymbolTag = 0x0; const uint32_t kNotSymbolTag = 0x0;
const uint32_t kSymbolTag = 0x20; const uint32_t kSymbolTag = 0x20;
// If bit 7 is clear, bits 3 and 4 are the string's size (short, medium or
// long). These values are very special in that they are also used to shift
// the length field to get the length, removing the hash value. This avoids
// using if or switch when getting the length of a string.
const uint32_t kStringSizeMask = 0x18;
const uint32_t kShortStringTag = 0x18;
const uint32_t kMediumStringTag = 0x10;
const uint32_t kLongStringTag = 0x00;
// If bit 7 is clear then bit 2 indicates whether the string consists of // If bit 7 is clear then bit 2 indicates whether the string consists of
// two-byte characters or one-byte characters. // two-byte characters or one-byte characters.
const uint32_t kStringEncodingMask = 0x4; const uint32_t kStringEncodingMask = 0x4;
@ -547,60 +418,20 @@ const uint32_t kShortcutTypeTag = kConsStringTag;
enum InstanceType { enum InstanceType {
SHORT_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSeqStringTag, SYMBOL_TYPE = kSymbolTag | kSeqStringTag,
MEDIUM_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSeqStringTag, ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kSeqStringTag,
LONG_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSeqStringTag, CONS_SYMBOL_TYPE = kSymbolTag | kConsStringTag,
SHORT_ASCII_SYMBOL_TYPE = CONS_ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kConsStringTag,
kShortStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag, EXTERNAL_SYMBOL_TYPE = kSymbolTag | kExternalStringTag,
MEDIUM_ASCII_SYMBOL_TYPE = EXTERNAL_ASCII_SYMBOL_TYPE =
kMediumStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag, kAsciiStringTag | kSymbolTag | kExternalStringTag,
LONG_ASCII_SYMBOL_TYPE = STRING_TYPE = kSeqStringTag,
kLongStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag, ASCII_STRING_TYPE = kAsciiStringTag | kSeqStringTag,
SHORT_CONS_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kConsStringTag, CONS_STRING_TYPE = kConsStringTag,
MEDIUM_CONS_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kConsStringTag, CONS_ASCII_STRING_TYPE = kAsciiStringTag | kConsStringTag,
LONG_CONS_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kConsStringTag, EXTERNAL_STRING_TYPE = kExternalStringTag,
SHORT_CONS_ASCII_SYMBOL_TYPE = EXTERNAL_ASCII_STRING_TYPE = kAsciiStringTag | kExternalStringTag,
kShortStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag, PRIVATE_EXTERNAL_ASCII_STRING_TYPE = EXTERNAL_ASCII_STRING_TYPE,
MEDIUM_CONS_ASCII_SYMBOL_TYPE =
kMediumStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
LONG_CONS_ASCII_SYMBOL_TYPE =
kLongStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
SHORT_EXTERNAL_SYMBOL_TYPE =
kShortStringTag | kSymbolTag | kExternalStringTag,
MEDIUM_EXTERNAL_SYMBOL_TYPE =
kMediumStringTag | kSymbolTag | kExternalStringTag,
LONG_EXTERNAL_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kExternalStringTag,
SHORT_EXTERNAL_ASCII_SYMBOL_TYPE =
kShortStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE =
kMediumStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
LONG_EXTERNAL_ASCII_SYMBOL_TYPE =
kLongStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
SHORT_STRING_TYPE = kShortStringTag | kSeqStringTag,
MEDIUM_STRING_TYPE = kMediumStringTag | kSeqStringTag,
LONG_STRING_TYPE = kLongStringTag | kSeqStringTag,
SHORT_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kSeqStringTag,
MEDIUM_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kSeqStringTag,
LONG_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kSeqStringTag,
SHORT_CONS_STRING_TYPE = kShortStringTag | kConsStringTag,
MEDIUM_CONS_STRING_TYPE = kMediumStringTag | kConsStringTag,
LONG_CONS_STRING_TYPE = kLongStringTag | kConsStringTag,
SHORT_CONS_ASCII_STRING_TYPE =
kShortStringTag | kAsciiStringTag | kConsStringTag,
MEDIUM_CONS_ASCII_STRING_TYPE =
kMediumStringTag | kAsciiStringTag | kConsStringTag,
LONG_CONS_ASCII_STRING_TYPE =
kLongStringTag | kAsciiStringTag | kConsStringTag,
SHORT_EXTERNAL_STRING_TYPE = kShortStringTag | kExternalStringTag,
MEDIUM_EXTERNAL_STRING_TYPE = kMediumStringTag | kExternalStringTag,
LONG_EXTERNAL_STRING_TYPE = kLongStringTag | kExternalStringTag,
SHORT_EXTERNAL_ASCII_STRING_TYPE =
kShortStringTag | kAsciiStringTag | kExternalStringTag,
MEDIUM_EXTERNAL_ASCII_STRING_TYPE =
kMediumStringTag | kAsciiStringTag | kExternalStringTag,
LONG_EXTERNAL_ASCII_STRING_TYPE =
kLongStringTag | kAsciiStringTag | kExternalStringTag,
LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE = LONG_EXTERNAL_ASCII_STRING_TYPE,
MAP_TYPE = kNotStringTag, MAP_TYPE = kNotStringTag,
HEAP_NUMBER_TYPE, HEAP_NUMBER_TYPE,
@ -999,16 +830,6 @@ class MapWord BASE_EMBEDDED {
// View this map word as a forwarding address. // View this map word as a forwarding address.
inline HeapObject* ToForwardingAddress(); inline HeapObject* ToForwardingAddress();
// True if this map word is a serialization address. This will only be the
// case during a destructive serialization of the heap.
inline bool IsSerializationAddress();
// Create a map word from a serialization address.
static inline MapWord FromSerializationAddress(int raw);
// View this map word as a serialization address.
inline int ToSerializationAddress();
// Marking phase of full collection: the map word of live objects is // Marking phase of full collection: the map word of live objects is
// marked, and may be marked as overflowed (eg, the object is live, its // marked, and may be marked as overflowed (eg, the object is live, its
// children have not been visited, and it does not fit in the marking // children have not been visited, and it does not fit in the marking
@ -3182,14 +3003,11 @@ class Script: public Struct {
DECL_ACCESSORS(compilation_type, Smi) DECL_ACCESSORS(compilation_type, Smi)
// [line_ends]: FixedArray of line ends positions. // [line_ends]: FixedArray of line ends positions.
DECL_ACCESSORS(line_ends_fixed_array, Object) DECL_ACCESSORS(line_ends, Object)
// [line_ends]: JSArray of line ends positions. // [eval_from_shared]: for eval scripts the shared funcion info for the
DECL_ACCESSORS(line_ends_js_array, Object) // function from which eval was called.
DECL_ACCESSORS(eval_from_shared, Object)
// [eval_from_function]: for eval scripts the funcion from which eval was
// called.
DECL_ACCESSORS(eval_from_function, Object)
// [eval_from_instructions_offset]: the instruction offset in the code for the // [eval_from_instructions_offset]: the instruction offset in the code for the
// function from which eval was called where eval was called. // function from which eval was called where eval was called.
@ -3215,19 +3033,11 @@ class Script: public Struct {
static const int kWrapperOffset = kContextOffset + kPointerSize; static const int kWrapperOffset = kContextOffset + kPointerSize;
static const int kTypeOffset = kWrapperOffset + kPointerSize; static const int kTypeOffset = kWrapperOffset + kPointerSize;
static const int kCompilationTypeOffset = kTypeOffset + kPointerSize; static const int kCompilationTypeOffset = kTypeOffset + kPointerSize;
// We have the line ends array both in FixedArray form and in JSArray form. static const int kLineEndsOffset = kCompilationTypeOffset + kPointerSize;
// The FixedArray form is useful when we don't have a context and so can't static const int kIdOffset = kLineEndsOffset + kPointerSize;
// create a JSArray. The JSArray form is useful when we want to see the static const int kEvalFromSharedOffset = kIdOffset + kPointerSize;
// array from JS code (e.g. debug-delay.js) which cannot handle unboxed
// FixedArray objects.
static const int kLineEndsFixedArrayOffset =
kCompilationTypeOffset + kPointerSize;
static const int kLineEndsJSArrayOffset =
kLineEndsFixedArrayOffset + kPointerSize;
static const int kIdOffset = kLineEndsJSArrayOffset + kPointerSize;
static const int kEvalFromFunctionOffset = kIdOffset + kPointerSize;
static const int kEvalFrominstructionsOffsetOffset = static const int kEvalFrominstructionsOffsetOffset =
kEvalFromFunctionOffset + kPointerSize; kEvalFromSharedOffset + kPointerSize;
static const int kSize = kEvalFrominstructionsOffsetOffset + kPointerSize; static const int kSize = kEvalFrominstructionsOffsetOffset + kPointerSize;
private: private:
@ -3910,12 +3720,9 @@ class String: public HeapObject {
inline int length(); inline int length();
inline void set_length(int value); inline void set_length(int value);
// Get and set the uninterpreted length field of the string. Notice // Get and set the hash field of the string.
// that the length field is also used to cache the hash value of inline uint32_t hash_field();
// strings. In order to get or set the actual length of the string inline void set_hash_field(uint32_t value);
// use the length() and set_length methods.
inline uint32_t length_field();
inline void set_length_field(uint32_t value);
inline bool IsAsciiRepresentation(); inline bool IsAsciiRepresentation();
inline bool IsTwoByteRepresentation(); inline bool IsTwoByteRepresentation();
@ -3986,8 +3793,8 @@ class String: public HeapObject {
// Returns a hash value used for the property table // Returns a hash value used for the property table
inline uint32_t Hash(); inline uint32_t Hash();
static uint32_t ComputeLengthAndHashField(unibrow::CharacterStream* buffer, static uint32_t ComputeHashField(unibrow::CharacterStream* buffer,
int length); int length);
static bool ComputeArrayIndex(unibrow::CharacterStream* buffer, static bool ComputeArrayIndex(unibrow::CharacterStream* buffer,
uint32_t* index, uint32_t* index,
@ -4018,7 +3825,8 @@ class String: public HeapObject {
// Layout description. // Layout description.
static const int kLengthOffset = HeapObject::kHeaderSize; static const int kLengthOffset = HeapObject::kHeaderSize;
static const int kSize = kLengthOffset + kIntSize; static const int kHashFieldOffset = kLengthOffset + kIntSize;
static const int kSize = kHashFieldOffset + kIntSize;
// Notice: kSize is not pointer-size aligned if pointers are 64-bit. // Notice: kSize is not pointer-size aligned if pointers are 64-bit.
// Maximum number of characters to consider when trying to convert a string // Maximum number of characters to consider when trying to convert a string
@ -4042,22 +3850,30 @@ class String: public HeapObject {
static const int kIsArrayIndexMask = 1 << 1; static const int kIsArrayIndexMask = 1 << 1;
static const int kNofLengthBitFields = 2; static const int kNofLengthBitFields = 2;
// Shift constant retrieving hash code from hash field.
static const int kHashShift = kNofLengthBitFields;
// Array index strings this short can keep their index in the hash // Array index strings this short can keep their index in the hash
// field. // field.
static const int kMaxCachedArrayIndexLength = 7; static const int kMaxCachedArrayIndexLength = 7;
// Shift constants for retrieving length and hash code from // For strings which are array indexes the hash value has the string length
// length/hash field. // mixed into the hash, mainly to avoid a hash value of zero which would be
static const int kHashShift = kNofLengthBitFields; // the case for the string '0'. 24 bits are used for the array index value.
static const int kShortLengthShift = kHashShift + kShortStringTag; static const int kArrayIndexHashLengthShift = 24 + kNofLengthBitFields;
static const int kMediumLengthShift = kHashShift + kMediumStringTag; static const int kArrayIndexHashMask = (1 << kArrayIndexHashLengthShift) - 1;
static const int kLongLengthShift = kHashShift + kLongStringTag; static const int kArrayIndexValueBits =
kArrayIndexHashLengthShift - kHashShift;
// Value of empty hash field indicating that the hash is not computed.
static const int kEmptyHashField = 0;
// Maximal string length.
static const int kMaxLength = (1 << (32 - 2)) - 1;
// Maximal string length that can be stored in the hash/length field for // Max length for computing hash. For strings longer than this limit the
// different types of strings. // string length is used as the hash value.
static const int kMaxShortSize = (1 << (32 - kShortLengthShift)) - 1; static const int kMaxHashCalcLength = 16383;
static const int kMaxMediumSize = (1 << (32 - kMediumLengthShift)) - 1;
static const int kMaxLength = (1 << (32 - kLongLengthShift)) - 1;
// Limit for truncation in short printing. // Limit for truncation in short printing.
static const int kMaxShortPrintLength = 1024; static const int kMaxShortPrintLength = 1024;
@ -4339,9 +4155,6 @@ class ExternalAsciiString: public ExternalString {
unsigned* offset, unsigned* offset,
unsigned chars); unsigned chars);
// Identify the map for the external string/symbol with a particular length.
static inline Map* StringMap(int length);
static inline Map* SymbolMap(int length);
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalAsciiString); DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalAsciiString);
}; };
@ -4374,9 +4187,6 @@ class ExternalTwoByteString: public ExternalString {
unsigned* offset_ptr, unsigned* offset_ptr,
unsigned chars); unsigned chars);
// Identify the map for the external string/symbol with a particular length.
static inline Map* StringMap(int length);
static inline Map* SymbolMap(int length);
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalTwoByteString); DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalTwoByteString);
}; };

5
deps/v8/src/platform-freebsd.cc

@ -89,11 +89,6 @@ uint64_t OS::CpuFeaturesImpliedByPlatform() {
} }
double OS::nan_value() {
return NAN;
}
int OS::ActivationFrameAlignment() { int OS::ActivationFrameAlignment() {
// 16 byte alignment on FreeBSD // 16 byte alignment on FreeBSD
return 16; return 16;

5
deps/v8/src/platform-linux.cc

@ -95,11 +95,6 @@ uint64_t OS::CpuFeaturesImpliedByPlatform() {
} }
double OS::nan_value() {
return NAN;
}
#ifdef __arm__ #ifdef __arm__
bool OS::ArmCpuHasFeature(CpuFeature feature) { bool OS::ArmCpuHasFeature(CpuFeature feature) {
const char* search_string = NULL; const char* search_string = NULL;

5
deps/v8/src/platform-macos.cc

@ -252,11 +252,6 @@ uint64_t OS::CpuFeaturesImpliedByPlatform() {
} }
double OS::nan_value() {
return NAN;
}
int OS::ActivationFrameAlignment() { int OS::ActivationFrameAlignment() {
// OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI
// Function Call Guide". // Function Call Guide".

597
deps/v8/src/platform-openbsd.cc

@ -0,0 +1,597 @@
// Copyright 2006-2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Platform specific code for OpenBSD goes here. For the POSIX comaptible parts
// the implementation is in platform-posix.cc.
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/types.h> // mmap & munmap
#include <sys/mman.h> // mmap & munmap
#include <sys/stat.h> // open
#include <sys/fcntl.h> // open
#include <unistd.h> // getpagesize
#include <execinfo.h> // backtrace, backtrace_symbols
#include <strings.h> // index
#include <errno.h>
#include <stdarg.h>
#include <limits.h>
#undef MAP_TYPE
#include "v8.h"
#include "platform.h"
namespace v8 {
namespace internal {
// 0 is never a valid thread id on OpenBSD since tids and pids share a
// name space and pid 0 is used to kill the group (see man 2 kill).
static const pthread_t kNoThread = (pthread_t) 0;
double ceiling(double x) {
// Correct as on OS X
if (-1.0 < x && x < 0.0) {
return -0.0;
} else {
return ceil(x);
}
}
void OS::Setup() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
// to an unsigned. Going directly can cause an overflow and the seed to be
// set to all ones. The seed will be identical for different instances that
// call this setup code within the same millisecond.
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed));
}
uint64_t OS::CpuFeaturesImpliedByPlatform() {
return 0; // OpenBSD runs on anything.
}
int OS::ActivationFrameAlignment() {
// 16 byte alignment on OpenBSD
return 16;
}
// We keep the lowest and highest addresses mapped as a quick way of
// determining that pointers are outside the heap (used mostly in assertions
// and verification). The estimate is conservative, ie, not all addresses in
// 'allocated' space are actually allocated to our heap. The range is
// [lowest, highest), inclusive on the low and and exclusive on the high end.
static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
static void* highest_ever_allocated = reinterpret_cast<void*>(0);
static void UpdateAllocatedSpaceLimits(void* address, int size) {
lowest_ever_allocated = Min(lowest_ever_allocated, address);
highest_ever_allocated =
Max(highest_ever_allocated,
reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
}
bool OS::IsOutsideAllocatedSpace(void* address) {
return address < lowest_ever_allocated || address >= highest_ever_allocated;
}
size_t OS::AllocateAlignment() {
return getpagesize();
}
void* OS::Allocate(const size_t requested,
size_t* allocated,
bool executable) {
const size_t msize = RoundUp(requested, getpagesize());
int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
if (mbase == MAP_FAILED) {
LOG(StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
UpdateAllocatedSpaceLimits(mbase, msize);
return mbase;
}
void OS::Free(void* buf, const size_t length) {
int result = munmap(buf, length);
USE(result);
ASSERT(result == 0);
}
#ifdef ENABLE_HEAP_PROTECTION
void OS::Protect(void* address, size_t size) {
UNIMPLEMENTED();
}
void OS::Unprotect(void* address, size_t size, bool is_executable) {
UNIMPLEMENTED();
}
#endif
void OS::Sleep(int milliseconds) {
unsigned int ms = static_cast<unsigned int>(milliseconds);
usleep(1000 * ms);
}
void OS::Abort() {
// Redirect to std abort to signal abnormal program termination.
abort();
}
void OS::DebugBreak() {
#if defined(__arm__) || defined(__thumb__)
asm("bkpt 0");
#else
asm("int $3");
#endif
}
class PosixMemoryMappedFile : public OS::MemoryMappedFile {
public:
PosixMemoryMappedFile(FILE* file, void* memory, int size)
: file_(file), memory_(memory), size_(size) { }
virtual ~PosixMemoryMappedFile();
virtual void* memory() { return memory_; }
private:
FILE* file_;
void* memory_;
int size_;
};
OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
void* initial) {
FILE* file = fopen(name, "w+");
if (file == NULL) return NULL;
int result = fwrite(initial, size, 1, file);
if (result < 1) {
fclose(file);
return NULL;
}
void* memory =
mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
return new PosixMemoryMappedFile(file, memory, size);
}
PosixMemoryMappedFile::~PosixMemoryMappedFile() {
if (memory_) munmap(memory_, size_);
fclose(file_);
}
#ifdef ENABLE_LOGGING_AND_PROFILING
static unsigned StringToLong(char* buffer) {
return static_cast<unsigned>(strtol(buffer, NULL, 16)); // NOLINT
}
#endif
void OS::LogSharedLibraryAddresses() {
#ifdef ENABLE_LOGGING_AND_PROFILING
static const int MAP_LENGTH = 1024;
int fd = open("/proc/self/maps", O_RDONLY);
if (fd < 0) return;
while (true) {
char addr_buffer[11];
addr_buffer[0] = '0';
addr_buffer[1] = 'x';
addr_buffer[10] = 0;
int result = read(fd, addr_buffer + 2, 8);
if (result < 8) break;
unsigned start = StringToLong(addr_buffer);
result = read(fd, addr_buffer + 2, 1);
if (result < 1) break;
if (addr_buffer[2] != '-') break;
result = read(fd, addr_buffer + 2, 8);
if (result < 8) break;
unsigned end = StringToLong(addr_buffer);
char buffer[MAP_LENGTH];
int bytes_read = -1;
do {
bytes_read++;
if (bytes_read >= MAP_LENGTH - 1)
break;
result = read(fd, buffer + bytes_read, 1);
if (result < 1) break;
} while (buffer[bytes_read] != '\n');
buffer[bytes_read] = 0;
// Ignore mappings that are not executable.
if (buffer[3] != 'x') continue;
char* start_of_path = index(buffer, '/');
// There may be no filename in this line. Skip to next.
if (start_of_path == NULL) continue;
buffer[bytes_read] = 0;
LOG(SharedLibraryEvent(start_of_path, start, end));
}
close(fd);
#endif
}
int OS::StackWalk(Vector<OS::StackFrame> frames) {
UNIMPLEMENTED();
return 1;
}
// Constants used for mmap.
static const int kMmapFd = -1;
static const int kMmapFdOffset = 0;
VirtualMemory::VirtualMemory(size_t size) {
address_ = mmap(NULL, size, PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
kMmapFd, kMmapFdOffset);
size_ = size;
}
VirtualMemory::~VirtualMemory() {
if (IsReserved()) {
if (0 == munmap(address(), size())) address_ = MAP_FAILED;
}
}
bool VirtualMemory::IsReserved() {
return address_ != MAP_FAILED;
}
bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
if (MAP_FAILED == mmap(address, size, prot,
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
kMmapFd, kMmapFdOffset)) {
return false;
}
UpdateAllocatedSpaceLimits(address, size);
return true;
}
bool VirtualMemory::Uncommit(void* address, size_t size) {
return mmap(address, size, PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
kMmapFd, kMmapFdOffset) != MAP_FAILED;
}
class ThreadHandle::PlatformData : public Malloced {
public:
explicit PlatformData(ThreadHandle::Kind kind) {
Initialize(kind);
}
void Initialize(ThreadHandle::Kind kind) {
switch (kind) {
case ThreadHandle::SELF: thread_ = pthread_self(); break;
case ThreadHandle::INVALID: thread_ = kNoThread; break;
}
}
pthread_t thread_; // Thread handle for pthread.
};
ThreadHandle::ThreadHandle(Kind kind) {
data_ = new PlatformData(kind);
}
void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
data_->Initialize(kind);
}
ThreadHandle::~ThreadHandle() {
delete data_;
}
bool ThreadHandle::IsSelf() const {
return pthread_equal(data_->thread_, pthread_self());
}
bool ThreadHandle::IsValid() const {
return data_->thread_ != kNoThread;
}
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
}
Thread::~Thread() {
}
static void* ThreadEntry(void* arg) {
Thread* thread = reinterpret_cast<Thread*>(arg);
// This is also initialized by the first argument to pthread_create() but we
// don't know which thread will run first (the original thread or the new
// one) so we initialize it here too.
thread->thread_handle_data()->thread_ = pthread_self();
ASSERT(thread->IsValid());
thread->Run();
return NULL;
}
void Thread::Start() {
pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
ASSERT(IsValid());
}
void Thread::Join() {
pthread_join(thread_handle_data()->thread_, NULL);
}
Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
pthread_key_t key;
int result = pthread_key_create(&key, NULL);
USE(result);
ASSERT(result == 0);
return static_cast<LocalStorageKey>(key);
}
void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
int result = pthread_key_delete(pthread_key);
USE(result);
ASSERT(result == 0);
}
void* Thread::GetThreadLocal(LocalStorageKey key) {
pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
return pthread_getspecific(pthread_key);
}
void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
pthread_setspecific(pthread_key, value);
}
void Thread::YieldCPU() {
sched_yield();
}
class OpenBSDMutex : public Mutex {
public:
OpenBSDMutex() {
pthread_mutexattr_t attrs;
int result = pthread_mutexattr_init(&attrs);
ASSERT(result == 0);
result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
ASSERT(result == 0);
result = pthread_mutex_init(&mutex_, &attrs);
ASSERT(result == 0);
}
virtual ~OpenBSDMutex() { pthread_mutex_destroy(&mutex_); }
virtual int Lock() {
int result = pthread_mutex_lock(&mutex_);
return result;
}
virtual int Unlock() {
int result = pthread_mutex_unlock(&mutex_);
return result;
}
private:
pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
};
Mutex* OS::CreateMutex() {
return new OpenBSDMutex();
}
class OpenBSDSemaphore : public Semaphore {
public:
explicit OpenBSDSemaphore(int count) { sem_init(&sem_, 0, count); }
virtual ~OpenBSDSemaphore() { sem_destroy(&sem_); }
virtual void Wait();
virtual bool Wait(int timeout);
virtual void Signal() { sem_post(&sem_); }
private:
sem_t sem_;
};
void OpenBSDSemaphore::Wait() {
while (true) {
int result = sem_wait(&sem_);
if (result == 0) return; // Successfully got semaphore.
CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
}
}
bool OpenBSDSemaphore::Wait(int timeout) {
const long kOneSecondMicros = 1000000; // NOLINT
// Split timeout into second and nanosecond parts.
struct timeval delta;
delta.tv_usec = timeout % kOneSecondMicros;
delta.tv_sec = timeout / kOneSecondMicros;
struct timeval current_time;
// Get the current time.
if (gettimeofday(&current_time, NULL) == -1) {
return false;
}
// Calculate time for end of timeout.
struct timeval end_time;
timeradd(&current_time, &delta, &end_time);
struct timespec ts;
TIMEVAL_TO_TIMESPEC(&end_time, &ts);
while (true) {
int result = sem_trywait(&sem_);
if (result == 0) return true; // Successfully got semaphore.
if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
}
}
Semaphore* OS::CreateSemaphore(int count) {
return new OpenBSDSemaphore(count);
}
#ifdef ENABLE_LOGGING_AND_PROFILING
static Sampler* active_sampler_ = NULL;
static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
USE(info);
if (signal != SIGPROF) return;
if (active_sampler_ == NULL) return;
TickSample sample;
// We always sample the VM state.
sample.state = Logger::state();
active_sampler_->Tick(&sample);
}
class Sampler::PlatformData : public Malloced {
public:
PlatformData() {
signal_handler_installed_ = false;
}
bool signal_handler_installed_;
struct sigaction old_signal_handler_;
struct itimerval old_timer_value_;
};
Sampler::Sampler(int interval, bool profiling)
: interval_(interval), profiling_(profiling), active_(false) {
data_ = new PlatformData();
}
Sampler::~Sampler() {
delete data_;
}
void Sampler::Start() {
// There can only be one active sampler at the time on POSIX
// platforms.
if (active_sampler_ != NULL) return;
// Request profiling signals.
struct sigaction sa;
sa.sa_sigaction = ProfilerSignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
data_->signal_handler_installed_ = true;
// Set the itimer to generate a tick for each interval.
itimerval itimer;
itimer.it_interval.tv_sec = interval_ / 1000;
itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
// Set this sampler as the active sampler.
active_sampler_ = this;
active_ = true;
}
void Sampler::Stop() {
// Restore old signal handler
if (data_->signal_handler_installed_) {
setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
sigaction(SIGPROF, &data_->old_signal_handler_, 0);
data_->signal_handler_installed_ = false;
}
// This sampler is no longer the active sampler.
active_sampler_ = NULL;
active_ = false;
}
#endif // ENABLE_LOGGING_AND_PROFILING
} } // namespace v8::internal

9
deps/v8/src/platform-posix.cc

@ -27,7 +27,7 @@
// Platform specific code for POSIX goes here. This is not a platform on its // Platform specific code for POSIX goes here. This is not a platform on its
// own but contains the parts which are the same across POSIX platforms Linux, // own but contains the parts which are the same across POSIX platforms Linux,
// Mac OS and FreeBSD. // Mac OS, FreeBSD and OpenBSD.
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
@ -61,6 +61,13 @@ double modulo(double x, double y) {
return fmod(x, y); return fmod(x, y);
} }
double OS::nan_value() {
// NAN from math.h is defined in C99 and not in POSIX.
return NAN;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// POSIX date/time support. // POSIX date/time support.
// //

124
deps/v8/src/runtime.cc

@ -788,51 +788,72 @@ static Object* Runtime_InitializeVarGlobal(Arguments args) {
// case of callbacks in the prototype chain (this rules out using // case of callbacks in the prototype chain (this rules out using
// SetProperty). We have IgnoreAttributesAndSetLocalProperty for // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
// this. // this.
// Note that objects can have hidden prototypes, so we need to traverse
// the whole chain of hidden prototypes to do a 'local' lookup.
JSObject* real_holder = global;
LookupResult lookup; LookupResult lookup;
global->LocalLookup(*name, &lookup); while (true) {
if (!lookup.IsProperty()) { real_holder->LocalLookup(*name, &lookup);
if (assign) { if (lookup.IsProperty()) {
return global->IgnoreAttributesAndSetLocalProperty(*name, // Determine if this is a redeclaration of something read-only.
args[1], if (lookup.IsReadOnly()) {
attributes); // If we found readonly property on one of hidden prototypes,
// just shadow it.
if (real_holder != Top::context()->global()) break;
return ThrowRedeclarationError("const", name);
}
// Determine if this is a redeclaration of an intercepted read-only
// property and figure out if the property exists at all.
bool found = true;
PropertyType type = lookup.type();
if (type == INTERCEPTOR) {
HandleScope handle_scope;
Handle<JSObject> holder(real_holder);
PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
real_holder = *holder;
if (intercepted == ABSENT) {
// The interceptor claims the property isn't there. We need to
// make sure to introduce it.
found = false;
} else if ((intercepted & READ_ONLY) != 0) {
// The property is present, but read-only. Since we're trying to
// overwrite it with a variable declaration we must throw a
// re-declaration error. However if we found readonly property
// on one of hidden prototypes, just shadow it.
if (real_holder != Top::context()->global()) break;
return ThrowRedeclarationError("const", name);
}
}
if (found && !assign) {
// The global property is there and we're not assigning any value
// to it. Just return.
return Heap::undefined_value();
}
// Assign the value (or undefined) to the property.
Object* value = (assign) ? args[1] : Heap::undefined_value();
return real_holder->SetProperty(&lookup, *name, value, attributes);
} }
return Heap::undefined_value();
}
// Determine if this is a redeclaration of something read-only. Object* proto = real_holder->GetPrototype();
if (lookup.IsReadOnly()) { if (!proto->IsJSObject())
return ThrowRedeclarationError("const", name); break;
}
// Determine if this is a redeclaration of an intercepted read-only if (!JSObject::cast(proto)->map()->is_hidden_prototype())
// property and figure out if the property exists at all. break;
bool found = true;
PropertyType type = lookup.type();
if (type == INTERCEPTOR) {
PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
if (intercepted == ABSENT) {
// The interceptor claims the property isn't there. We need to
// make sure to introduce it.
found = false;
} else if ((intercepted & READ_ONLY) != 0) {
// The property is present, but read-only. Since we're trying to
// overwrite it with a variable declaration we must throw a
// re-declaration error.
return ThrowRedeclarationError("const", name);
}
// Restore global object from context (in case of GC).
global = Top::context()->global();
}
if (found && !assign) { real_holder = JSObject::cast(proto);
// The global property is there and we're not assigning any value
// to it. Just return.
return Heap::undefined_value();
} }
// Assign the value (or undefined) to the property. global = Top::context()->global();
Object* value = (assign) ? args[1] : Heap::undefined_value(); if (assign) {
return global->SetProperty(&lookup, *name, value, attributes); return global->IgnoreAttributesAndSetLocalProperty(*name,
args[1],
attributes);
}
return Heap::undefined_value();
} }
@ -3762,6 +3783,7 @@ static Object* Runtime_StringAdd(Arguments args) {
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
CONVERT_CHECKED(String, str1, args[0]); CONVERT_CHECKED(String, str1, args[0]);
CONVERT_CHECKED(String, str2, args[1]); CONVERT_CHECKED(String, str2, args[1]);
Counters::string_add_runtime.Increment();
return Heap::AllocateConsString(str1, str2); return Heap::AllocateConsString(str1, str2);
} }
@ -4987,6 +5009,9 @@ static Object* Runtime_DebugPrint(Arguments args) {
PrintF("DebugPrint: "); PrintF("DebugPrint: ");
} }
args[0]->Print(); args[0]->Print();
if (args[0]->IsHeapObject()) {
HeapObject::cast(args[0])->map()->Print();
}
#else #else
// ShortPrint is available in release mode. Print is not. // ShortPrint is available in release mode. Print is not.
args[0]->ShortPrint(); args[0]->ShortPrint();
@ -7667,8 +7692,31 @@ static Object* Runtime_FunctionGetInferredName(Arguments args) {
CONVERT_CHECKED(JSFunction, f, args[0]); CONVERT_CHECKED(JSFunction, f, args[0]);
return f->shared()->inferred_name(); return f->shared()->inferred_name();
} }
#endif // ENABLE_DEBUGGER_SUPPORT #endif // ENABLE_DEBUGGER_SUPPORT
#ifdef ENABLE_LOGGING_AND_PROFILING
static Object* Runtime_ProfilerResume(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(Smi, smi_modules, args[0]);
v8::V8::ResumeProfilerEx(smi_modules->value());
return Heap::undefined_value();
}
static Object* Runtime_ProfilerPause(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(Smi, smi_modules, args[0]);
v8::V8::PauseProfilerEx(smi_modules->value());
return Heap::undefined_value();
}
#endif // ENABLE_LOGGING_AND_PROFILING
// Finds the script object from the script data. NOTE: This operation uses // Finds the script object from the script data. NOTE: This operation uses
// heap traversal to find the function generated for the source position // heap traversal to find the function generated for the source position

11
deps/v8/src/runtime.h

@ -318,6 +318,14 @@ namespace internal {
#define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) #define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F)
#endif #endif
#ifdef ENABLE_LOGGING_AND_PROFILING
#define RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F) \
F(ProfilerResume, 1, 1) \
F(ProfilerPause, 1, 1)
#else
#define RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F)
#endif
#ifdef DEBUG #ifdef DEBUG
#define RUNTIME_FUNCTION_LIST_DEBUG(F) \ #define RUNTIME_FUNCTION_LIST_DEBUG(F) \
/* Testing */ \ /* Testing */ \
@ -336,7 +344,8 @@ namespace internal {
RUNTIME_FUNCTION_LIST_ALWAYS_1(F) \ RUNTIME_FUNCTION_LIST_ALWAYS_1(F) \
RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \ RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
RUNTIME_FUNCTION_LIST_DEBUG(F) \ RUNTIME_FUNCTION_LIST_DEBUG(F) \
RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) \
RUNTIME_FUNCTION_LIST_PROFILER_SUPPORT(F)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Runtime provides access to all C++ runtime functions. // Runtime provides access to all C++ runtime functions.

10
deps/v8/src/runtime.js

@ -146,16 +146,16 @@ function COMPARE(x, ncr) {
function ADD(x) { function ADD(x) {
// Fast case: Check for number operands and do the addition. // Fast case: Check for number operands and do the addition.
if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberAdd(this, x); if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberAdd(this, x);
if (IS_STRING(this) && IS_STRING(x)) return %StringAdd(this, x); if (IS_STRING(this) && IS_STRING(x)) return %_StringAdd(this, x);
// Default implementation. // Default implementation.
var a = %ToPrimitive(this, NO_HINT); var a = %ToPrimitive(this, NO_HINT);
var b = %ToPrimitive(x, NO_HINT); var b = %ToPrimitive(x, NO_HINT);
if (IS_STRING(a)) { if (IS_STRING(a)) {
return %StringAdd(a, %ToString(b)); return %_StringAdd(a, %ToString(b));
} else if (IS_STRING(b)) { } else if (IS_STRING(b)) {
return %StringAdd(%ToString(a), b); return %_StringAdd(%ToString(a), b);
} else { } else {
return %NumberAdd(%ToNumber(a), %ToNumber(b)); return %NumberAdd(%ToNumber(a), %ToNumber(b));
} }
@ -173,7 +173,7 @@ function STRING_ADD_LEFT(y) {
: %ToString(%ToPrimitive(y, NO_HINT)); : %ToString(%ToPrimitive(y, NO_HINT));
} }
} }
return %StringAdd(this, y); return %_StringAdd(this, y);
} }
@ -189,7 +189,7 @@ function STRING_ADD_RIGHT(y) {
: %ToString(%ToPrimitive(x, NO_HINT)); : %ToString(%ToPrimitive(x, NO_HINT));
} }
} }
return %StringAdd(x, y); return %_StringAdd(x, y);
} }

87
deps/v8/src/serialize.cc

@ -44,6 +44,69 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Mapping objects to their location after deserialization.
// This is used during building, but not at runtime by V8.
class SerializationAddressMapper {
public:
static bool IsMapped(HeapObject* obj) {
EnsureMapExists();
return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
}
static int MappedTo(HeapObject* obj) {
ASSERT(IsMapped(obj));
return reinterpret_cast<intptr_t>(serialization_map_->Lookup(Key(obj),
Hash(obj),
false)->value);
}
static void Map(HeapObject* obj, int to) {
EnsureMapExists();
ASSERT(!IsMapped(obj));
HashMap::Entry* entry =
serialization_map_->Lookup(Key(obj), Hash(obj), true);
entry->value = Value(to);
}
static void Zap() {
if (serialization_map_ != NULL) {
delete serialization_map_;
}
serialization_map_ = NULL;
}
private:
static bool SerializationMatchFun(void* key1, void* key2) {
return key1 == key2;
}
static uint32_t Hash(HeapObject* obj) {
return reinterpret_cast<intptr_t>(obj->address());
}
static void* Key(HeapObject* obj) {
return reinterpret_cast<void*>(obj->address());
}
static void* Value(int v) {
return reinterpret_cast<void*>(v);
}
static void EnsureMapExists() {
if (serialization_map_ == NULL) {
serialization_map_ = new HashMap(&SerializationMatchFun);
}
}
static HashMap* serialization_map_;
};
HashMap* SerializationAddressMapper::serialization_map_ = NULL;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Coding of external references. // Coding of external references.
@ -871,6 +934,7 @@ void Serializer::Serialize() {
Heap::IterateRoots(this, VISIT_ONLY_STRONG); Heap::IterateRoots(this, VISIT_ONLY_STRONG);
delete external_reference_encoder_; delete external_reference_encoder_;
external_reference_encoder_ = NULL; external_reference_encoder_ = NULL;
SerializationAddressMapper::Zap();
} }
@ -894,10 +958,9 @@ void Serializer::SerializeObject(
ReferenceRepresentation reference_representation) { ReferenceRepresentation reference_representation) {
CHECK(o->IsHeapObject()); CHECK(o->IsHeapObject());
HeapObject* heap_object = HeapObject::cast(o); HeapObject* heap_object = HeapObject::cast(o);
MapWord map_word = heap_object->map_word(); if (SerializationAddressMapper::IsMapped(heap_object)) {
if (map_word.IsSerializationAddress()) {
int space = SpaceOfAlreadySerializedObject(heap_object); int space = SpaceOfAlreadySerializedObject(heap_object);
int address = map_word.ToSerializationAddress(); int address = SerializationAddressMapper::MappedTo(heap_object);
int offset = CurrentAllocationAddress(space) - address; int offset = CurrentAllocationAddress(space) - address;
bool from_start = true; bool from_start = true;
if (SpaceIsPaged(space)) { if (SpaceIsPaged(space)) {
@ -965,24 +1028,23 @@ void Serializer::ObjectSerializer::Serialize() {
} }
sink_->PutInt(size >> kObjectAlignmentBits, "Size in words"); sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
// Get the map before overwriting it.
Map* map = object_->map();
// Mark this object as already serialized. // Mark this object as already serialized.
bool start_new_page; bool start_new_page;
object_->set_map_word(MapWord::FromSerializationAddress( SerializationAddressMapper::Map(
serializer_->Allocate(space, size, &start_new_page))); object_,
serializer_->Allocate(space, size, &start_new_page));
if (start_new_page) { if (start_new_page) {
sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage"); sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage");
sink_->PutSection(space, "NewPageSpace"); sink_->PutSection(space, "NewPageSpace");
} }
// Serialize the map (first word of the object). // Serialize the map (first word of the object).
serializer_->SerializeObject(map, TAGGED_REPRESENTATION); serializer_->SerializeObject(object_->map(), TAGGED_REPRESENTATION);
// Serialize the rest of the object. // Serialize the rest of the object.
CHECK_EQ(0, bytes_processed_so_far_); CHECK_EQ(0, bytes_processed_so_far_);
bytes_processed_so_far_ = kPointerSize; bytes_processed_so_far_ = kPointerSize;
object_->IterateBody(map->instance_type(), size, this); object_->IterateBody(object_->map()->instance_type(), size, this);
OutputRawData(object_->address() + size); OutputRawData(object_->address() + size);
} }
@ -1044,12 +1106,9 @@ void Serializer::ObjectSerializer::VisitExternalAsciiString(
Address references_start = reinterpret_cast<Address>(resource_pointer); Address references_start = reinterpret_cast<Address>(resource_pointer);
OutputRawData(references_start); OutputRawData(references_start);
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
// Use raw_unchecked when maps are munged. Object* source = Heap::natives_source_cache()->get(i);
Object* source = Heap::raw_unchecked_natives_source_cache()->get(i);
if (!source->IsUndefined()) { if (!source->IsUndefined()) {
// Don't use cast when maps are munged. ExternalAsciiString* string = ExternalAsciiString::cast(source);
ExternalAsciiString* string =
reinterpret_cast<ExternalAsciiString*>(source);
typedef v8::String::ExternalAsciiStringResource Resource; typedef v8::String::ExternalAsciiStringResource Resource;
Resource* resource = string->resource(); Resource* resource = string->resource();
if (resource == *resource_pointer) { if (resource == *resource_pointer) {

2
deps/v8/src/string-stream.cc

@ -188,7 +188,7 @@ void StringStream::Add(Vector<const char> format, Vector<FmtElm> elms) {
void StringStream::PrintObject(Object* o) { void StringStream::PrintObject(Object* o) {
o->ShortPrint(this); o->ShortPrint(this);
if (o->IsString()) { if (o->IsString()) {
if (String::cast(o)->length() <= String::kMaxMediumSize) { if (String::cast(o)->length() <= String::kMaxShortPrintLength) {
return; return;
} }
} else if (o->IsNumber() || o->IsOddball()) { } else if (o->IsNumber() || o->IsOddball()) {

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

@ -750,6 +750,9 @@ Object* LoadCallbackProperty(Arguments args) {
{ {
// Leaving JavaScript. // Leaving JavaScript.
VMState state(EXTERNAL); VMState state(EXTERNAL);
#ifdef ENABLE_LOGGING_AND_PROFILING
state.set_external_callback(getter_address);
#endif
result = fun(v8::Utils::ToLocal(args.at<String>(4)), info); result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
} }
RETURN_IF_SCHEDULED_EXCEPTION(); RETURN_IF_SCHEDULED_EXCEPTION();
@ -773,6 +776,9 @@ Object* StoreCallbackProperty(Arguments args) {
{ {
// Leaving JavaScript. // Leaving JavaScript.
VMState state(EXTERNAL); VMState state(EXTERNAL);
#ifdef ENABLE_LOGGING_AND_PROFILING
state.set_external_callback(setter_address);
#endif
fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info); fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
} }
RETURN_IF_SCHEDULED_EXCEPTION(); RETURN_IF_SCHEDULED_EXCEPTION();

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

@ -226,9 +226,9 @@ class StubCache : public AllStatic {
// hash code would effectively throw away two bits of the hash // hash code would effectively throw away two bits of the hash
// code. // code.
ASSERT(kHeapObjectTagSize == String::kHashShift); ASSERT(kHeapObjectTagSize == String::kHashShift);
// Compute the hash of the name (use entire length field). // Compute the hash of the name (use entire hash field).
ASSERT(name->HasHashCode()); ASSERT(name->HasHashCode());
uint32_t field = name->length_field(); uint32_t field = name->hash_field();
// Using only the low bits in 64-bit mode is unlikely to increase the // Using only the low bits in 64-bit mode is unlikely to increase the
// risk of collision even if the heap is spread over an area larger than // risk of collision even if the heap is spread over an area larger than
// 4Gb (and not at all if it isn't). // 4Gb (and not at all if it isn't).

9
deps/v8/src/utils.cc

@ -309,4 +309,13 @@ char* StringBuilder::Finalize() {
return buffer_.start(); return buffer_.start();
} }
int TenToThe(int exponent) {
ASSERT(exponent <= 9);
ASSERT(exponent >= 1);
int answer = 10;
for (int i = 1; i < exponent; i++) answer *= 10;
return answer;
}
} } // namespace v8::internal } } // namespace v8::internal

3
deps/v8/src/utils.h

@ -584,6 +584,9 @@ static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
} }
// Calculate 10^exponent.
int TenToThe(int exponent);
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_UTILS_H_ #endif // V8_UTILS_H_

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

@ -153,8 +153,9 @@ namespace internal {
SC(zone_segment_bytes, V8.ZoneSegmentBytes) \ SC(zone_segment_bytes, V8.ZoneSegmentBytes) \
SC(compute_entry_frame, V8.ComputeEntryFrame) \ SC(compute_entry_frame, V8.ComputeEntryFrame) \
SC(generic_binary_stub_calls, V8.GenericBinaryStubCalls) \ SC(generic_binary_stub_calls, V8.GenericBinaryStubCalls) \
SC(generic_binary_stub_calls_regs, V8.GenericBinaryStubCallsRegs) SC(generic_binary_stub_calls_regs, V8.GenericBinaryStubCallsRegs) \
SC(string_add_runtime, V8.StringAddRuntime) \
SC(string_add_native, V8.StringAddNative)
// This file contains all the v8 counters that are in use. // This file contains all the v8 counters that are in use.
class Counters : AllStatic { class Counters : AllStatic {

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 2 #define MAJOR_VERSION 2
#define MINOR_VERSION 0 #define MINOR_VERSION 0
#define BUILD_NUMBER 2 #define BUILD_NUMBER 3
#define PATCH_LEVEL 0 #define PATCH_LEVEL 0
#define CANDIDATE_VERSION false #define CANDIDATE_VERSION false

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

@ -482,6 +482,12 @@ class Assembler : public Malloced {
static const int kPatchReturnSequenceAddressOffset = 13 - 4; static const int kPatchReturnSequenceAddressOffset = 13 - 4;
// TODO(X64): Rename this, removing the "Real", after changing the above. // TODO(X64): Rename this, removing the "Real", after changing the above.
static const int kRealPatchReturnSequenceAddressOffset = 2; static const int kRealPatchReturnSequenceAddressOffset = 2;
// The x64 JS return sequence is padded with int3 to make it large
// enough to hold a call instruction when the debugger patches it.
static const int kCallInstructionLength = 13;
static const int kJSReturnSequenceLength = 13;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Code generation // Code generation
// //

127
deps/v8/src/x64/codegen-x64.cc

@ -505,13 +505,13 @@ void CodeGenerator::GenerateReturnSequence(Result* return_value) {
// Add padding that will be overwritten by a debugger breakpoint. // Add padding that will be overwritten by a debugger breakpoint.
// frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k" // frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k"
// with length 7 (3 + 1 + 3). // with length 7 (3 + 1 + 3).
const int kPadding = Debug::kX64JSReturnSequenceLength - 7; const int kPadding = Assembler::kJSReturnSequenceLength - 7;
for (int i = 0; i < kPadding; ++i) { for (int i = 0; i < kPadding; ++i) {
masm_->int3(); masm_->int3();
} }
// Check that the size of the code used for returning matches what is // Check that the size of the code used for returning matches what is
// expected by the debugger. // expected by the debugger.
ASSERT_EQ(Debug::kX64JSReturnSequenceLength, ASSERT_EQ(Assembler::kJSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif #endif
DeleteFrame(); DeleteFrame();
@ -1662,8 +1662,54 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
jsobject.Bind(); jsobject.Bind();
// Get the set of properties (as a FixedArray or Map). // Get the set of properties (as a FixedArray or Map).
// rax: value to be iterated over // rax: value to be iterated over
frame_->EmitPush(rax); // push the object being iterated over (slot 4) frame_->EmitPush(rax); // Push the object being iterated over.
// Check cache validity in generated code. This is a fast case for
// the JSObject::IsSimpleEnum cache validity checks. If we cannot
// guarantee cache validity, call the runtime system to check cache
// validity or get the property names in a fixed array.
JumpTarget call_runtime;
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
JumpTarget check_prototype;
JumpTarget use_cache;
__ movq(rcx, rax);
loop.Bind();
// Check that there are no elements.
__ movq(rdx, FieldOperand(rcx, JSObject::kElementsOffset));
__ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
call_runtime.Branch(not_equal);
// Check that instance descriptors are not empty so that we can
// check for an enum cache. Leave the map in ebx for the subsequent
// prototype load.
__ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
__ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset));
__ CompareRoot(rdx, Heap::kEmptyDescriptorArrayRootIndex);
call_runtime.Branch(equal);
// Check that there in an enum cache in the non-empty instance
// descriptors. This is the case if the next enumeration index
// field does not contain a smi.
__ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
is_smi = masm_->CheckSmi(rdx);
call_runtime.Branch(is_smi);
// For all objects but the receiver, check that the cache is empty.
__ cmpq(rcx, rax);
check_prototype.Branch(equal);
__ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
__ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
call_runtime.Branch(not_equal);
check_prototype.Bind();
// Load the prototype from the map and loop if non-null.
__ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
__ CompareRoot(rcx, Heap::kNullValueRootIndex);
loop.Branch(not_equal);
// The enum cache is valid. Load the map of the object being
// iterated over and use the cache for the iteration.
__ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
use_cache.Jump();
call_runtime.Bind();
// Call the runtime to get the property names for the object.
frame_->EmitPush(rax); // push the Object (slot 4) for the runtime call frame_->EmitPush(rax); // push the Object (slot 4) for the runtime call
frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
@ -1676,8 +1722,11 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
__ CompareRoot(rcx, Heap::kMetaMapRootIndex); __ CompareRoot(rcx, Heap::kMetaMapRootIndex);
fixed_array.Branch(not_equal); fixed_array.Branch(not_equal);
use_cache.Bind();
// Get enum cache // Get enum cache
// rax: map (result from call to Runtime::kGetPropertyNamesFast) // rax: map (either the result from a call to
// Runtime::kGetPropertyNamesFast or has been fetched directly from
// the object)
__ movq(rcx, rax); __ movq(rcx, rax);
__ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset)); __ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset));
// Get the bridge array held in the enumeration index field. // Get the bridge array held in the enumeration index field.
@ -3767,20 +3816,8 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
__ testb(rcx, Immediate(kIsNotStringMask)); __ testb(rcx, Immediate(kIsNotStringMask));
__ j(not_zero, &slow_case); __ j(not_zero, &slow_case);
// Here we make assumptions about the tag values and the shifts needed.
// See the comment in objects.h.
ASSERT(kLongStringTag == 0);
ASSERT(kMediumStringTag + String::kLongLengthShift ==
String::kMediumLengthShift);
ASSERT(kShortStringTag + String::kLongLengthShift ==
String::kShortLengthShift);
__ and_(rcx, Immediate(kStringSizeMask));
__ addq(rcx, Immediate(String::kLongLengthShift));
// Fetch the length field into the temporary register.
__ movl(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset));
__ shrl_cl(temp.reg());
// Check for index out of range. // Check for index out of range.
__ cmpl(index.reg(), temp.reg()); __ cmpl(index.reg(), FieldOperand(object.reg(), String::kLengthOffset));
__ j(greater_equal, &slow_case); __ j(greater_equal, &slow_case);
// Reload the instance type (into the temp register this time).. // Reload the instance type (into the temp register this time)..
__ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); __ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset));
@ -4008,6 +4045,17 @@ void CodeGenerator::GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
ASSERT_EQ(2, args->length());
Load(args->at(0));
Load(args->at(1));
Result answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
frame_->Push(&answer);
}
void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) { void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1); ASSERT(args->length() == 1);
JumpTarget leave, null, function, non_function_constructor; JumpTarget leave, null, function, non_function_constructor;
@ -6175,11 +6223,8 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
// String value => false iff empty. // String value => false iff empty.
__ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE)); __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE));
__ j(above_equal, &not_string); __ j(above_equal, &not_string);
__ and_(rcx, Immediate(kStringSizeMask));
__ cmpq(rcx, Immediate(kShortStringTag));
__ j(not_equal, &true_result); // Empty string is always short.
__ movl(rdx, FieldOperand(rax, String::kLengthOffset)); __ movl(rdx, FieldOperand(rax, String::kLengthOffset));
__ shr(rdx, Immediate(String::kShortLengthShift)); __ testl(rdx, rdx);
__ j(zero, &false_result); __ j(zero, &false_result);
__ jmp(&true_result); __ jmp(&true_result);
@ -7732,9 +7777,47 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
__ push(rcx); __ push(rcx);
} }
switch (op_) { switch (op_) {
case Token::ADD: case Token::ADD: {
// Test for string arguments before calling runtime.
Label not_strings, both_strings, not_string1, string1;
Condition is_smi;
Result answer;
__ movq(rdx, Operand(rsp, 2 * kPointerSize)); // First argument.
__ movq(rax, Operand(rsp, 1 * kPointerSize)); // Second argument.
is_smi = masm->CheckSmi(rdx);
__ j(is_smi, &not_string1);
__ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx);
__ j(above_equal, &not_string1);
// First argument is a a string, test second.
is_smi = masm->CheckSmi(rax);
__ j(is_smi, &string1);
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax);
__ j(above_equal, &string1);
// First and second argument are strings.
Runtime::Function* f = Runtime::FunctionForId(Runtime::kStringAdd);
__ TailCallRuntime(ExternalReference(f), 2, f->result_size);
// Only first argument is a string.
__ bind(&string1);
__ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
// First argument was not a string, test second.
__ bind(&not_string1);
is_smi = masm->CheckSmi(rax);
__ j(is_smi, &not_strings);
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax);
__ j(above_equal, &not_strings);
// Only second argument is a string.
__ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
__ bind(&not_strings);
// Neither argument is a string.
__ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
break; break;
}
case Token::SUB: case Token::SUB:
__ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
break; break;

3
deps/v8/src/x64/codegen-x64.h

@ -544,6 +544,9 @@ class CodeGenerator: public AstVisitor {
inline void GenerateMathSin(ZoneList<Expression*>* args); inline void GenerateMathSin(ZoneList<Expression*>* args);
inline void GenerateMathCos(ZoneList<Expression*>* args); inline void GenerateMathCos(ZoneList<Expression*>* args);
// Fast support for StringAdd.
void GenerateStringAdd(ZoneList<Expression*>* args);
// Simple condition analysis. // Simple condition analysis.
enum ConditionAnalysis { enum ConditionAnalysis {
ALWAYS_TRUE, ALWAYS_TRUE,

7
deps/v8/src/x64/debug-x64.cc

@ -181,7 +181,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
void BreakLocationIterator::ClearDebugBreakAtReturn() { void BreakLocationIterator::ClearDebugBreakAtReturn() {
rinfo()->PatchCode(original_rinfo()->pc(), rinfo()->PatchCode(original_rinfo()->pc(),
Debug::kX64JSReturnSequenceLength); Assembler::kJSReturnSequenceLength);
} }
@ -191,9 +191,10 @@ bool BreakLocationIterator::IsDebugBreakAtReturn() {
void BreakLocationIterator::SetDebugBreakAtReturn() { void BreakLocationIterator::SetDebugBreakAtReturn() {
ASSERT(Debug::kX64JSReturnSequenceLength >= Debug::kX64CallInstructionLength); ASSERT(Assembler::kJSReturnSequenceLength >=
Assembler::kCallInstructionLength);
rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(), rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(),
Debug::kX64JSReturnSequenceLength - Debug::kX64CallInstructionLength); Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
} }
#endif // ENABLE_DEBUGGER_SUPPORT #endif // ENABLE_DEBUGGER_SUPPORT

325
deps/v8/src/x64/fast-codegen-x64.cc

@ -76,11 +76,43 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
bool function_in_register = true; bool function_in_register = true;
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in rdi.
__ push(rdi);
__ CallRuntime(Runtime::kNewContext, 1);
function_in_register = false;
// Context is returned in both rax and rsi. It replaces the context
// passed to us. It's saved in the stack and kept live in rsi.
__ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
// Copy any necessary parameters into the context.
int num_parameters = fun->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context
__ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax);
}
}
}
// Possibly allocate an arguments object.
Variable* arguments = fun->scope()->arguments()->AsVariable(); Variable* arguments = fun->scope()->arguments()->AsVariable();
if (arguments != NULL) { if (arguments != NULL) {
// Function uses arguments object. // Arguments object must be allocated after the context object, in
// case the "arguments" or ".arguments" variables are in the context.
Comment cmnt(masm_, "[ Allocate arguments object"); Comment cmnt(masm_, "[ Allocate arguments object");
__ push(rdi); if (function_in_register) {
__ push(rdi);
} else {
__ 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.
__ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset + __ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize)); fun->num_parameters() * kPointerSize));
@ -93,34 +125,11 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub); __ CallStub(&stub);
// Store new arguments object in both "arguments" and ".arguments" slots. // Store new arguments object in both "arguments" and ".arguments" slots.
__ movq(Operand(rbp, SlotOffset(arguments->slot())), rax); __ movq(rcx, rax);
Move(arguments->slot(), rax, rbx, rdx);
Slot* dot_arguments_slot = Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot(); fun->scope()->arguments_shadow()->AsVariable()->slot();
__ movq(Operand(rbp, SlotOffset(dot_arguments_slot)), rax); Move(dot_arguments_slot, rcx, rbx, rdx);
function_in_register = false;
}
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
if (function_in_register) {
// Argument to NewContext is the function, still in rdi.
__ push(rdi);
} else {
// Argument to NewContext is the function, no longer in rdi.
__ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
}
__ CallRuntime(Runtime::kNewContext, 1);
// Context is returned in both rax and rsi. It replaces the context
// passed to us. It's saved in the stack and kept live in rsi.
__ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
#ifdef DEBUG
// Assert we do not have to copy any parameters into the context.
for (int i = 0, len = fun->scope()->num_parameters(); i < len; i++) {
Slot* slot = fun->scope()->parameter(i)->slot();
ASSERT(slot != NULL && slot->type() != Slot::CONTEXT);
}
#endif
} }
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
@ -180,13 +189,13 @@ void FastCodeGenerator::EmitReturnSequence(int position) {
// Add padding that will be overwritten by a debugger breakpoint. We // Add padding that will be overwritten by a debugger breakpoint. We
// have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7
// (3 + 1 + 3). // (3 + 1 + 3).
const int kPadding = Debug::kX64JSReturnSequenceLength - 7; const int kPadding = Assembler::kJSReturnSequenceLength - 7;
for (int i = 0; i < kPadding; ++i) { for (int i = 0; i < kPadding; ++i) {
masm_->int3(); masm_->int3();
} }
// Check that the size of the code used for returning matches what is // Check that the size of the code used for returning matches what is
// expected by the debugger. // expected by the debugger.
ASSERT_EQ(Debug::kX64JSReturnSequenceLength, ASSERT_EQ(Assembler::kJSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif #endif
} }
@ -227,20 +236,54 @@ void FastCodeGenerator::Move(Expression::Context context, Register source) {
} }
void FastCodeGenerator::Move(Expression::Context context, Slot* source) { template <>
Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source,
Register scratch) {
switch (source->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
return Operand(rbp, SlotOffset(source));
case Slot::CONTEXT: {
int context_chain_length =
function_->scope()->ContextChainLength(source->var()->scope());
__ LoadContext(scratch, context_chain_length);
return CodeGenerator::ContextOperand(scratch, source->index());
break;
}
case Slot::LOOKUP:
UNIMPLEMENTED();
// Fall-through.
default:
UNREACHABLE();
return Operand(rax, 0); // Dead code to make the compiler happy.
}
}
void FastCodeGenerator::Move(Register dst, Slot* source) {
Operand location = CreateSlotOperand<Operand>(source, dst);
__ movq(dst, location);
}
void FastCodeGenerator::Move(Expression::Context context,
Slot* source,
Register scratch) {
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
break; break;
case Expression::kValue: case Expression::kValue: {
__ push(Operand(rbp, SlotOffset(source))); Operand location = CreateSlotOperand<Operand>(source, scratch);
__ push(location);
break; break;
}
case Expression::kTest: // Fall through. case Expression::kTest: // Fall through.
case Expression::kValueTest: // Fall through. case Expression::kValueTest: // Fall through.
case Expression::kTestValue: case Expression::kTestValue:
__ movq(rax, Operand(rbp, SlotOffset(source))); Move(scratch, source);
Move(context, rax); Move(context, scratch);
break; break;
} }
} }
@ -265,24 +308,61 @@ void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
} }
void FastCodeGenerator::Move(Slot* dst,
Register src,
Register scratch1,
Register scratch2) {
switch (dst->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
__ movq(Operand(rbp, SlotOffset(dst)), src);
break;
case Slot::CONTEXT: {
ASSERT(!src.is(scratch1));
ASSERT(!src.is(scratch2));
ASSERT(!scratch1.is(scratch2));
int context_chain_length =
function_->scope()->ContextChainLength(dst->var()->scope());
__ LoadContext(scratch1, context_chain_length);
__ movq(Operand(scratch1, Context::SlotOffset(dst->index())), src);
int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
__ RecordWrite(scratch1, offset, src, scratch2);
break;
}
case Slot::LOOKUP:
UNIMPLEMENTED();
default:
UNREACHABLE();
}
}
void FastCodeGenerator::DropAndMove(Expression::Context context, void FastCodeGenerator::DropAndMove(Expression::Context context,
Register source) { Register source,
int drop_count) {
ASSERT(drop_count > 0);
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
__ addq(rsp, Immediate(kPointerSize)); __ addq(rsp, Immediate(drop_count * kPointerSize));
break; break;
case Expression::kValue: case Expression::kValue:
if (drop_count > 1) {
__ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
}
__ movq(Operand(rsp, 0), source); __ movq(Operand(rsp, 0), source);
break; break;
case Expression::kTest: case Expression::kTest:
ASSERT(!source.is(rsp)); ASSERT(!source.is(rsp));
__ addq(rsp, Immediate(kPointerSize)); __ addq(rsp, Immediate(drop_count * kPointerSize));
TestAndBranch(source, true_label_, false_label_); TestAndBranch(source, true_label_, false_label_);
break; break;
case Expression::kValueTest: { case Expression::kValueTest: {
Label discard; Label discard;
if (drop_count > 1) {
__ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
}
__ movq(Operand(rsp, 0), source); __ movq(Operand(rsp, 0), source);
TestAndBranch(source, true_label_, &discard); TestAndBranch(source, true_label_, &discard);
__ bind(&discard); __ bind(&discard);
@ -382,26 +462,26 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
__ Move(rax, Factory::the_hole_value()); __ Move(rax, Factory::the_hole_value());
if (FLAG_debug_code) { if (FLAG_debug_code) {
// Check if we have the correct context pointer. // Check if we have the correct context pointer.
__ movq(rbx, CodeGenerator::ContextOperand( __ movq(rbx, CodeGenerator::ContextOperand(rsi,
rsi, Context::FCONTEXT_INDEX)); Context::FCONTEXT_INDEX));
__ cmpq(rbx, rsi); __ cmpq(rbx, rsi);
__ Check(equal, "Unexpected declaration in current context."); __ Check(equal, "Unexpected declaration in current context.");
} }
__ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax); __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
// No write barrier since the_hole_value is in old space. // No write barrier since the_hole_value is in old space.
ASSERT(Heap::InNewSpace(*Factory::the_hole_value())); ASSERT(!Heap::InNewSpace(*Factory::the_hole_value()));
} else if (decl->fun() != NULL) { } else if (decl->fun() != NULL) {
Visit(decl->fun()); Visit(decl->fun());
__ pop(rax); __ pop(rax);
if (FLAG_debug_code) { if (FLAG_debug_code) {
// Check if we have the correct context pointer. // Check if we have the correct context pointer.
__ movq(rbx, CodeGenerator::ContextOperand( __ movq(rbx, CodeGenerator::ContextOperand(rsi,
rsi, Context::FCONTEXT_INDEX)); Context::FCONTEXT_INDEX));
__ cmpq(rbx, rsi); __ cmpq(rbx, rsi);
__ Check(equal, "Unexpected declaration in current context."); __ Check(equal, "Unexpected declaration in current context.");
} }
__ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax); __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; int offset = Context::SlotOffset(slot->index());
__ RecordWrite(rsi, offset, rax, rcx); __ RecordWrite(rsi, offset, rax, rcx);
} }
break; break;
@ -473,53 +553,59 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
DropAndMove(expr->context(), rax); DropAndMove(expr->context(), rax);
} else if (rewrite->AsSlot() != NULL) { } else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot(); Slot* slot = rewrite->AsSlot();
switch (slot->type()) { if (FLAG_debug_code) {
case Slot::LOCAL: switch (slot->type()) {
case Slot::PARAMETER: { case Slot::LOCAL:
Comment cmnt(masm_, "Stack slot"); case Slot::PARAMETER: {
Move(expr->context(), slot); Comment cmnt(masm_, "Stack slot");
break; break;
}
case Slot::CONTEXT: {
Comment cmnt(masm_, "Context slot");
int chain_length =
function_->scope()->ContextChainLength(slot->var()->scope());
if (chain_length > 0) {
// Move up the chain of contexts to the context containing the slot.
__ movq(rax,
Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX)));
// Load the function context (which is the incoming, outer context).
__ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
for (int i = 1; i < chain_length; i++) {
__ movq(rax,
Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)));
__ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
}
// The context may be an intermediate context, not a function context.
__ movq(rax,
Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)));
} else { // Slot is in the current function context.
// The context may be an intermediate context, not a function context.
__ movq(rax,
Operand(rsi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
} }
__ movq(rax, Operand(rax, Context::SlotOffset(slot->index()))); case Slot::CONTEXT: {
Move(expr->context(), rax); Comment cmnt(masm_, "Context slot");
break; break;
}
case Slot::LOOKUP:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
} }
case Slot::LOOKUP:
UNREACHABLE();
break;
} }
Move(expr->context(), slot, rax);
} else { } else {
// The parameter variable has been rewritten into an explict access to // A variable has been rewritten into an explicit access to
// the arguments object. // an object property.
Property* property = rewrite->AsProperty(); Property* property = rewrite->AsProperty();
ASSERT_NOT_NULL(property); ASSERT_NOT_NULL(property);
ASSERT_EQ(expr->context(), property->context());
Visit(property); // Currently the only parameter expressions that can occur are
// on the form "slot[literal]".
// Check that the object is in a slot.
Variable* object = property->obj()->AsVariableProxy()->AsVariable();
ASSERT_NOT_NULL(object);
Slot* object_slot = object->slot();
ASSERT_NOT_NULL(object_slot);
// Load the object.
Move(Expression::kValue, object_slot, rax);
// Check that the key is a smi.
Literal* key_literal = property->key()->AsLiteral();
ASSERT_NOT_NULL(key_literal);
ASSERT(key_literal->handle()->IsSmi());
// Load the key.
Move(Expression::kValue, key_literal);
// Do a KEYED property load.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// Notice: We must not have a "test rax, ..." instruction after
// the call. It is treated specially by the LoadIC code.
// Drop key and object left on the stack by IC, and push the result.
DropAndMove(expr->context(), rax, 2);
} }
} }
@ -580,8 +666,9 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
} }
// If result_saved == true: the result is saved on top of the stack. // If result_saved == true: The result is saved on top of the
// If result_saved == false: the result is not on the stack, just in rax. // stack and in rax.
// If result_saved == false: The result not on the stack, just in rax.
bool result_saved = false; bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) { for (int i = 0; i < expr->properties()->length(); i++) {
@ -606,6 +693,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ call(ic, RelocInfo::CODE_TARGET);
// StoreIC leaves the receiver on the stack. // StoreIC leaves the receiver on the stack.
__ movq(rax, Operand(rsp, 0)); // Restore result back into rax.
break; break;
} }
// fall through // fall through
@ -781,7 +869,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
// Overwrite the global object on the stack with the result if needed. // Overwrite the global object on the stack with the result if needed.
DropAndMove(expr->context(), rax); DropAndMove(expr->context(), rax);
} else { } else if (var->slot()) {
Slot* slot = var->slot(); Slot* slot = var->slot();
ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled. ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
switch (slot->type()) { switch (slot->type()) {
@ -873,6 +961,36 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
UNREACHABLE(); UNREACHABLE();
break; break;
} }
} else {
Property* property = var->AsProperty();
ASSERT_NOT_NULL(property);
// A variable has been rewritten into a property on an object.
// Load object and key onto the stack.
Slot* object_slot = property->obj()->AsSlot();
ASSERT_NOT_NULL(object_slot);
Move(Expression::kValue, object_slot, rax);
Literal* key_literal = property->key()->AsLiteral();
ASSERT_NOT_NULL(key_literal);
Move(Expression::kValue, key_literal);
// Value to store was pushed before object and key on the stack.
__ movq(rax, Operand(rsp, 2 * kPointerSize));
// Arguments to ic is value in rax, object and key on stack.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
if (expr->context() == Expression::kEffect) {
__ addq(rsp, Immediate(3 * kPointerSize));
} else if (expr->context() == Expression::kValue) {
// Value is still on the stack in rsp[2 * kPointerSize]
__ addq(rsp, Immediate(2 * kPointerSize));
} else {
__ movq(rax, Operand(rsp, 2 * kPointerSize));
DropAndMove(expr->context(), rax, 3);
}
} }
} }
@ -969,9 +1087,9 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
Visit(expr->key()); Visit(expr->key());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test rax,..." // Notice: We must not have a "test rax, ..." instruction after
// instruction after the call it is treated specially by the LoadIC code. // the call. It is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC. // Drop key left on the stack by IC.
__ addq(rsp, Immediate(kPointerSize)); __ addq(rsp, Immediate(kPointerSize));
} }
@ -1054,7 +1172,7 @@ void FastCodeGenerator::VisitCall(Call* expr) {
SetSourcePosition(prop->position()); SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test eax,..." // By emitting a nop we make sure that we do not have a "test rax,..."
// instruction after the call it is treated specially by the LoadIC code. // instruction after the call it is treated specially by the LoadIC code.
__ nop(); __ nop();
// Drop key left on the stack by IC. // Drop key left on the stack by IC.
@ -1134,9 +1252,13 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) {
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Comment cmnt(masm_, "[ CallRuntime"); Comment cmnt(masm_, "[ CallRuntime");
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
Runtime::Function* function = expr->function();
ASSERT(function != NULL); if (expr->is_jsruntime()) {
// Prepare for calling JS runtime function.
__ Push(expr->name());
__ movq(rax, CodeGenerator::GlobalObject());
__ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
}
// Push the arguments ("left-to-right"). // Push the arguments ("left-to-right").
int arg_count = args->length(); int arg_count = args->length();
@ -1145,8 +1267,19 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
ASSERT_EQ(Expression::kValue, args->at(i)->context()); ASSERT_EQ(Expression::kValue, args->at(i)->context());
} }
__ CallRuntime(function, arg_count); if (expr->is_jsruntime()) {
Move(expr->context(), rax); // Call the JS runtime function.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
__ call(ic, RelocInfo::CODE_TARGET);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
DropAndMove(expr->context(), rax);
} else {
__ CallRuntime(expr->function(), arg_count);
Move(expr->context(), rax);
}
} }
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {

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

@ -31,6 +31,7 @@
#include "ic-inl.h" #include "ic-inl.h"
#include "runtime.h" #include "runtime.h"
#include "stub-cache.h" #include "stub-cache.h"
#include "utils.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
@ -107,7 +108,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
StringDictionary::kElementsStartIndex * kPointerSize; StringDictionary::kElementsStartIndex * kPointerSize;
for (int i = 0; i < kProbes; i++) { for (int i = 0; i < kProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask. // Compute the masked index: (hash + i + i * i) & mask.
__ movl(r1, FieldOperand(name, String::kLengthOffset)); __ movl(r1, FieldOperand(name, String::kHashFieldOffset));
__ shrl(r1, Immediate(String::kHashShift)); __ shrl(r1, Immediate(String::kHashShift));
if (i > 0) { if (i > 0) {
__ addl(r1, Immediate(StringDictionary::GetProbeOffset(i))); __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
@ -239,18 +240,6 @@ void KeyedLoadIC::Generate(MacroAssembler* masm,
} }
#ifdef DEBUG
// For use in assert below.
static int TenToThe(int exponent) {
ASSERT(exponent <= 9);
ASSERT(exponent >= 1);
int answer = 10;
for (int i = 1; i < exponent; i++) answer *= 10;
return answer;
}
#endif
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rsp[0] : return address // -- rsp[0] : return address
@ -327,7 +316,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx); __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
__ j(above_equal, &slow); __ j(above_equal, &slow);
// Is the string an array index, with cached numeric value? // Is the string an array index, with cached numeric value?
__ movl(rbx, FieldOperand(rax, String::kLengthOffset)); __ movl(rbx, FieldOperand(rax, String::kHashFieldOffset));
__ testl(rbx, Immediate(String::kIsArrayIndexMask)); __ testl(rbx, Immediate(String::kIsArrayIndexMask));
// If the string is a symbol, do a quick inline probe of the receiver's // If the string is a symbol, do a quick inline probe of the receiver's
@ -342,20 +331,16 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ movq(rax, rcx); __ movq(rax, rcx);
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0); __ ret(0);
// Array index string: If short enough use cache in length/hash field (rbx). // If the hash field contains an array index pick it out. The assert checks
// We assert that there are enough bits in an int32_t after the hash shift // that the constants for the maximum number of digits for an array index
// bits have been subtracted to allow space for the length and the cached // cached in the hash field and the number of bits reserved for it does not
// array index. // conflict.
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
(1 << (String::kShortLengthShift - String::kHashShift))); (1 << String::kArrayIndexValueBits));
__ bind(&index_string); __ bind(&index_string);
const int kLengthFieldLimit =
(String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
__ cmpl(rbx, Immediate(kLengthFieldLimit));
__ j(above_equal, &slow);
__ movl(rax, rbx); __ movl(rax, rbx);
__ and_(rax, Immediate((1 << String::kShortLengthShift) - 1)); __ and_(rax, Immediate(String::kArrayIndexHashMask));
__ shrl(rax, Immediate(String::kLongLengthShift)); __ shrl(rax, Immediate(String::kHashShift));
__ jmp(&index_int); __ jmp(&index_int);
} }
@ -393,7 +378,7 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
// ExternalArray. // ExternalArray.
// rax: index (as a smi) // rax: index (as a smi)
// rcx: JSObject // rcx: JSObject
__ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); __ movq(rcx, FieldOperand(rcx, JSObject::kElementsOffset));
__ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
Heap::RootIndexForExternalArrayType(array_type)); Heap::RootIndexForExternalArrayType(array_type));
__ j(not_equal, &slow); __ j(not_equal, &slow);
@ -413,7 +398,7 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
__ movsxbq(rax, Operand(rcx, rax, times_1, 0)); __ movsxbq(rax, Operand(rcx, rax, times_1, 0));
break; break;
case kExternalUnsignedByteArray: case kExternalUnsignedByteArray:
__ movb(rax, Operand(rcx, rax, times_1, 0)); __ movzxbq(rax, Operand(rcx, rax, times_1, 0));
break; break;
case kExternalShortArray: case kExternalShortArray:
__ movsxwq(rax, Operand(rcx, rax, times_2, 0)); __ movsxwq(rax, Operand(rcx, rax, times_2, 0));

34
deps/v8/src/x64/macro-assembler-x64.cc

@ -67,6 +67,12 @@ void MacroAssembler::CompareRoot(Operand with, Heap::RootListIndex index) {
} }
void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
CompareRoot(rsp, Heap::kStackLimitRootIndex);
j(below, on_stack_overflow);
}
static void RecordWriteHelper(MacroAssembler* masm, static void RecordWriteHelper(MacroAssembler* masm,
Register object, Register object,
Register addr, Register addr,
@ -282,6 +288,9 @@ void MacroAssembler::Abort(const char* msg) {
RecordComment(msg); RecordComment(msg);
} }
#endif #endif
// Disable stub call restrictions to always allow calls to abort.
set_allow_stub_calls(true);
push(rax); push(rax);
movq(kScratchRegister, p0, RelocInfo::NONE); movq(kScratchRegister, p0, RelocInfo::NONE);
push(kScratchRegister); push(kScratchRegister);
@ -291,6 +300,7 @@ void MacroAssembler::Abort(const char* msg) {
push(kScratchRegister); push(kScratchRegister);
CallRuntime(Runtime::kAbort, 2); CallRuntime(Runtime::kAbort, 2);
// will not return here // will not return here
int3();
} }
@ -2088,6 +2098,11 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
void MacroAssembler::UpdateAllocationTopHelper(Register result_end, void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
Register scratch) { Register scratch) {
if (FLAG_debug_code) {
testq(result_end, Immediate(kObjectAlignmentMask));
Check(zero, "Unaligned allocation in new space");
}
ExternalReference new_space_allocation_top = ExternalReference new_space_allocation_top =
ExternalReference::new_space_allocation_top_address(); ExternalReference::new_space_allocation_top_address();
@ -2229,6 +2244,25 @@ void MacroAssembler::AllocateHeapNumber(Register result,
} }
void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
if (context_chain_length > 0) {
// Move up the chain of contexts to the context containing the slot.
movq(dst, Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX)));
// Load the function context (which is the incoming, outer context).
movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
for (int i = 1; i < context_chain_length; i++) {
movq(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
movq(dst, FieldOperand(dst, JSFunction::kContextOffset));
}
// The context may be an intermediate context, not a function context.
movq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
} else { // context is the current function context.
// The context may be an intermediate context, not a function context.
movq(dst, Operand(rsi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
}
}
CodePatcher::CodePatcher(byte* address, int size) CodePatcher::CodePatcher(byte* address, int size)
: address_(address), size_(size), masm_(address, size + Assembler::kGap) { : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
// Create a new macro assembler pointing to the address of the code to patch. // Create a new macro assembler pointing to the address of the code to patch.

9
deps/v8/src/x64/macro-assembler-x64.h

@ -97,6 +97,12 @@ class MacroAssembler: public Assembler {
RegList regs); RegList regs);
#endif #endif
// ---------------------------------------------------------------------------
// Stack limit support
// Do simple test for stack overflow. This doesn't handle an overflow.
void StackLimitCheck(Label* on_stack_limit_hit);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Activation frames // Activation frames
@ -542,6 +548,9 @@ class MacroAssembler: public Assembler {
// occurred. // occurred.
void IllegalOperation(int num_arguments); void IllegalOperation(int num_arguments);
// Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Runtime calls // Runtime calls

8
deps/v8/src/x64/stub-cache-x64.cc

@ -173,7 +173,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ JumpIfSmi(receiver, &miss); __ JumpIfSmi(receiver, &miss);
// Get the map of the receiver and compute the hash. // Get the map of the receiver and compute the hash.
__ movl(scratch, FieldOperand(name, String::kLengthOffset)); __ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
// Use only the low 32 bits of the map pointer. // Use only the low 32 bits of the map pointer.
__ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ xor_(scratch, Immediate(flags)); __ xor_(scratch, Immediate(flags));
@ -183,7 +183,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
ProbeTable(masm, flags, kPrimary, name, scratch); ProbeTable(masm, flags, kPrimary, name, scratch);
// Primary miss: Compute hash for secondary probe. // Primary miss: Compute hash for secondary probe.
__ movl(scratch, FieldOperand(name, String::kLengthOffset)); __ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
__ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ xor_(scratch, Immediate(flags)); __ xor_(scratch, Immediate(flags));
__ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize)); __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
@ -323,11 +323,7 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
// Load length directly from the string. // Load length directly from the string.
__ bind(&load_length); __ bind(&load_length);
__ and_(scratch, Immediate(kStringSizeMask));
__ movl(rax, FieldOperand(receiver, String::kLengthOffset)); __ movl(rax, FieldOperand(receiver, String::kLengthOffset));
// rcx is also the receiver.
__ lea(rcx, Operand(scratch, String::kLongLengthShift));
__ shr_cl(rax);
__ Integer32ToSmi(rax, rax); __ Integer32ToSmi(rax, rax);
__ ret(0); __ ret(0);

4
deps/v8/test/cctest/test-alloc.cc

@ -65,9 +65,9 @@ static Object* AllocateAfterFailures() {
// Old data space. // Old data space.
OldSpace* old_data_space = Heap::old_data_space(); OldSpace* old_data_space = Heap::old_data_space();
static const int kOldDataSpaceFillerSize = SeqAsciiString::SizeFor(0); static const int kOldDataSpaceFillerSize = ByteArray::SizeFor(0);
while (old_data_space->Available() > kOldDataSpaceFillerSize) { while (old_data_space->Available() > kOldDataSpaceFillerSize) {
CHECK(!Heap::AllocateRawAsciiString(0, TENURED)->IsFailure()); CHECK(!Heap::AllocateByteArray(0, TENURED)->IsFailure());
} }
CHECK(!Heap::AllocateRawAsciiString(100, TENURED)->IsFailure()); CHECK(!Heap::AllocateRawAsciiString(100, TENURED)->IsFailure());

231
deps/v8/test/cctest/test-api.cc

@ -2670,6 +2670,40 @@ THREADED_TEST(AutoExtensions) {
} }
static const char* kSyntaxErrorInExtensionSource =
"[";
// Test that a syntax error in an extension does not cause a fatal
// error but results in an empty context.
THREADED_TEST(SyntaxErrorExtensions) {
v8::HandleScope handle_scope;
v8::RegisterExtension(new Extension("syntaxerror",
kSyntaxErrorInExtensionSource));
const char* extension_names[] = { "syntaxerror" };
v8::ExtensionConfiguration extensions(1, extension_names);
v8::Handle<Context> context = Context::New(&extensions);
CHECK(context.IsEmpty());
}
static const char* kExceptionInExtensionSource =
"throw 42";
// Test that an exception when installing an extension does not cause
// a fatal error but results in an empty context.
THREADED_TEST(ExceptionExtensions) {
v8::HandleScope handle_scope;
v8::RegisterExtension(new Extension("exception",
kExceptionInExtensionSource));
const char* extension_names[] = { "exception" };
v8::ExtensionConfiguration extensions(1, extension_names);
v8::Handle<Context> context = Context::New(&extensions);
CHECK(context.IsEmpty());
}
static void CheckDependencies(const char* name, const char* expected) { static void CheckDependencies(const char* name, const char* expected) {
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::ExtensionConfiguration config(1, &name); v8::ExtensionConfiguration config(1, &name);
@ -7029,27 +7063,17 @@ static void MorphAString(i::String* string,
CHECK(i::StringShape(string).IsExternal()); CHECK(i::StringShape(string).IsExternal());
if (string->IsAsciiRepresentation()) { if (string->IsAsciiRepresentation()) {
// Check old map is not symbol or long. // Check old map is not symbol or long.
CHECK(string->map() == i::Heap::short_external_ascii_string_map() || CHECK(string->map() == i::Heap::external_ascii_string_map());
string->map() == i::Heap::medium_external_ascii_string_map());
// Morph external string to be TwoByte string. // Morph external string to be TwoByte string.
if (string->length() <= i::String::kMaxShortSize) { string->set_map(i::Heap::external_string_map());
string->set_map(i::Heap::short_external_string_map());
} else {
string->set_map(i::Heap::medium_external_string_map());
}
i::ExternalTwoByteString* morphed = i::ExternalTwoByteString* morphed =
i::ExternalTwoByteString::cast(string); i::ExternalTwoByteString::cast(string);
morphed->set_resource(uc16_resource); morphed->set_resource(uc16_resource);
} else { } else {
// Check old map is not symbol or long. // Check old map is not symbol or long.
CHECK(string->map() == i::Heap::short_external_string_map() || CHECK(string->map() == i::Heap::external_string_map());
string->map() == i::Heap::medium_external_string_map());
// Morph external string to be ASCII string. // Morph external string to be ASCII string.
if (string->length() <= i::String::kMaxShortSize) { string->set_map(i::Heap::external_ascii_string_map());
string->set_map(i::Heap::short_external_ascii_string_map());
} else {
string->set_map(i::Heap::medium_external_ascii_string_map());
}
i::ExternalAsciiString* morphed = i::ExternalAsciiString* morphed =
i::ExternalAsciiString::cast(string); i::ExternalAsciiString::cast(string);
morphed->set_resource(ascii_resource); morphed->set_resource(ascii_resource);
@ -8059,6 +8083,85 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
result = CompileRun("ext_array[1] = 23;"); result = CompileRun("ext_array[1] = 23;");
CHECK_EQ(23, result->Int32Value()); CHECK_EQ(23, result->Int32Value());
// Test more complex manipulations which cause eax to contain values
// that won't be completely overwritten by loads from the arrays.
// This catches bugs in the instructions used for the KeyedLoadIC
// for byte and word types.
{
const int kXSize = 300;
const int kYSize = 300;
const int kLargeElementCount = kXSize * kYSize * 4;
ElementType* large_array_data =
static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
i::Handle<ExternalArrayClass> large_array =
i::Handle<ExternalArrayClass>::cast(
i::Factory::NewExternalArray(kLargeElementCount,
array_type,
array_data));
v8::Handle<v8::Object> large_obj = v8::Object::New();
// Set the elements to be the external array.
large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
array_type,
kLargeElementCount);
context->Global()->Set(v8_str("large_array"), large_obj);
// Initialize contents of a few rows.
for (int x = 0; x < 300; x++) {
int row = 0;
int offset = row * 300 * 4;
large_array_data[offset + 4 * x + 0] = (ElementType) 127;
large_array_data[offset + 4 * x + 1] = (ElementType) 0;
large_array_data[offset + 4 * x + 2] = (ElementType) 0;
large_array_data[offset + 4 * x + 3] = (ElementType) 127;
row = 150;
offset = row * 300 * 4;
large_array_data[offset + 4 * x + 0] = (ElementType) 127;
large_array_data[offset + 4 * x + 1] = (ElementType) 0;
large_array_data[offset + 4 * x + 2] = (ElementType) 0;
large_array_data[offset + 4 * x + 3] = (ElementType) 127;
row = 298;
offset = row * 300 * 4;
large_array_data[offset + 4 * x + 0] = (ElementType) 127;
large_array_data[offset + 4 * x + 1] = (ElementType) 0;
large_array_data[offset + 4 * x + 2] = (ElementType) 0;
large_array_data[offset + 4 * x + 3] = (ElementType) 127;
}
// The goal of the code below is to make "offset" large enough
// that the computation of the index (which goes into eax) has
// high bits set which will not be overwritten by a byte or short
// load.
result = CompileRun("var failed = false;"
"var offset = 0;"
"for (var i = 0; i < 300; i++) {"
" if (large_array[4 * i] != 127 ||"
" large_array[4 * i + 1] != 0 ||"
" large_array[4 * i + 2] != 0 ||"
" large_array[4 * i + 3] != 127) {"
" failed = true;"
" }"
"}"
"offset = 150 * 300 * 4;"
"for (var i = 0; i < 300; i++) {"
" if (large_array[offset + 4 * i] != 127 ||"
" large_array[offset + 4 * i + 1] != 0 ||"
" large_array[offset + 4 * i + 2] != 0 ||"
" large_array[offset + 4 * i + 3] != 127) {"
" failed = true;"
" }"
"}"
"offset = 298 * 300 * 4;"
"for (var i = 0; i < 300; i++) {"
" if (large_array[offset + 4 * i] != 127 ||"
" large_array[offset + 4 * i + 1] != 0 ||"
" large_array[offset + 4 * i + 2] != 0 ||"
" large_array[offset + 4 * i + 3] != 127) {"
" failed = true;"
" }"
"}"
"!failed;");
CHECK_EQ(true, result->BooleanValue());
free(large_array_data);
}
free(array_data); free(array_data);
} }
@ -8409,3 +8512,103 @@ THREADED_TEST(SpaghettiStackReThrow) {
v8::String::Utf8Value value(try_catch.Exception()); v8::String::Utf8Value value(try_catch.Exception());
CHECK_EQ(0, strcmp(*value, "Hey!")); CHECK_EQ(0, strcmp(*value, "Hey!"));
} }
static int GetGlobalObjectsCount() {
int count = 0;
v8::internal::HeapIterator it;
while (it.has_next()) {
v8::internal::HeapObject* object = it.next();
if (object->IsJSGlobalObject()) count++;
}
return count;
}
TEST(Regress528) {
v8::V8::Initialize();
v8::HandleScope scope;
v8::Persistent<Context> context;
v8::Persistent<Context> other_context;
int gc_count;
// Create a context used to keep the code from aging in the compilation
// cache.
other_context = Context::New();
// Context-dependent context data creates reference from the compilation
// cache to the global object.
const char* source_simple = "1";
context = Context::New();
{
v8::HandleScope scope;
context->Enter();
Local<v8::String> obj = v8::String::New("");
context->SetData(obj);
CompileRun(source_simple);
context->Exit();
}
context.Dispose();
for (gc_count = 1; gc_count < 10; gc_count++) {
other_context->Enter();
CompileRun(source_simple);
other_context->Exit();
v8::internal::Heap::CollectAllGarbage(false);
if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
CHECK_EQ(1, GetGlobalObjectsCount());
// Eval in a function creates reference from the compilation cache to the
// global object.
const char* source_eval = "function f(){eval('1')}; f()";
context = Context::New();
{
v8::HandleScope scope;
context->Enter();
CompileRun(source_eval);
context->Exit();
}
context.Dispose();
for (gc_count = 1; gc_count < 10; gc_count++) {
other_context->Enter();
CompileRun(source_eval);
other_context->Exit();
v8::internal::Heap::CollectAllGarbage(false);
if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
CHECK_EQ(1, GetGlobalObjectsCount());
// Looking up the line number for an exception creates reference from the
// compilation cache to the global object.
const char* source_exception = "function f(){throw 1;} f()";
context = Context::New();
{
v8::HandleScope scope;
context->Enter();
v8::TryCatch try_catch;
CompileRun(source_exception);
CHECK(try_catch.HasCaught());
v8::Handle<v8::Message> message = try_catch.Message();
CHECK(!message.IsEmpty());
CHECK_EQ(1, message->GetLineNumber());
context->Exit();
}
context.Dispose();
for (gc_count = 1; gc_count < 10; gc_count++) {
other_context->Enter();
CompileRun(source_exception);
other_context->Exit();
v8::internal::Heap::CollectAllGarbage(false);
if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
CHECK_EQ(1, GetGlobalObjectsCount());
other_context.Dispose();
}

8
deps/v8/test/cctest/test-debug.cc

@ -5016,7 +5016,7 @@ TEST(ScriptNameAndData) {
v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name")); v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name"));
v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2); v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
script2->Run(); script2->Run();
script2->SetData(data_obj); script2->SetData(data_obj->ToString());
f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f"))); f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
f->Call(env->Global(), 0, NULL); f->Call(env->Global(), 0, NULL);
CHECK_EQ(3, break_point_hit_count); CHECK_EQ(3, break_point_hit_count);
@ -5069,8 +5069,8 @@ TEST(ContextData) {
CHECK(context_2->GetData()->IsUndefined()); CHECK(context_2->GetData()->IsUndefined());
// Set and check different data values. // Set and check different data values.
v8::Handle<v8::Value> data_1 = v8::Number::New(1); v8::Handle<v8::String> data_1 = v8::String::New("1");
v8::Handle<v8::Value> data_2 = v8::String::New("2"); v8::Handle<v8::String> data_2 = v8::String::New("2");
context_1->SetData(data_1); context_1->SetData(data_1);
context_2->SetData(data_2); context_2->SetData(data_2);
CHECK(context_1->GetData()->StrictEquals(data_1)); CHECK(context_1->GetData()->StrictEquals(data_1));
@ -5233,7 +5233,7 @@ static void ExecuteScriptForContextCheck() {
CHECK(context_1->GetData()->IsUndefined()); CHECK(context_1->GetData()->IsUndefined());
// Set and check a data value. // Set and check a data value.
v8::Handle<v8::Value> data_1 = v8::Number::New(1); v8::Handle<v8::String> data_1 = v8::String::New("1");
context_1->SetData(data_1); context_1->SetData(data_1);
CHECK(context_1->GetData()->StrictEquals(data_1)); CHECK(context_1->GetData()->StrictEquals(data_1));

3
deps/v8/test/cctest/test-heap.cc

@ -37,8 +37,7 @@ TEST(HeapMaps) {
CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize); CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize);
CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize); CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, FixedArray::kHeaderSize); CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, FixedArray::kHeaderSize);
CheckMap(Heap::long_string_map(), LONG_STRING_TYPE, CheckMap(Heap::string_map(), STRING_TYPE, SeqTwoByteString::kAlignedSize);
SeqTwoByteString::kAlignedSize);
} }

75
deps/v8/test/cctest/test-log.cc

@ -538,6 +538,81 @@ TEST(LogCallbacks) {
} }
static v8::Handle<v8::Value> Prop1Getter(v8::Local<v8::String> property,
const v8::AccessorInfo& info) {
return v8::Handle<v8::Value>();
}
static void Prop1Setter(v8::Local<v8::String> property,
v8::Local<v8::Value> value,
const v8::AccessorInfo& info) {
}
static v8::Handle<v8::Value> Prop2Getter(v8::Local<v8::String> property,
const v8::AccessorInfo& info) {
return v8::Handle<v8::Value>();
}
TEST(LogAccessorCallbacks) {
const bool saved_prof_lazy = i::FLAG_prof_lazy;
const bool saved_prof = i::FLAG_prof;
const bool saved_prof_auto = i::FLAG_prof_auto;
i::FLAG_prof = true;
i::FLAG_prof_lazy = false;
i::FLAG_prof_auto = false;
i::FLAG_logfile = "*";
// If tests are being run manually, V8 will be already initialized
// by the bottom test.
const bool need_to_set_up_logger = i::V8::IsRunning();
v8::HandleScope scope;
v8::Handle<v8::Context> env = v8::Context::New();
if (need_to_set_up_logger) Logger::Setup();
env->Enter();
// Skip all initially logged stuff.
EmbeddedVector<char, 102400> buffer;
int log_pos = GetLogLines(0, &buffer);
v8::Persistent<v8::FunctionTemplate> obj =
v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
obj->SetClassName(v8::String::New("Obj"));
v8::Handle<v8::ObjectTemplate> inst = obj->InstanceTemplate();
inst->SetAccessor(v8::String::New("prop1"), Prop1Getter, Prop1Setter);
inst->SetAccessor(v8::String::New("prop2"), Prop2Getter);
i::Logger::LogAccessorCallbacks();
log_pos = GetLogLines(log_pos, &buffer);
CHECK_GT(log_pos, 0);
buffer[log_pos] = 0;
printf("%s", buffer.start());
EmbeddedVector<char, 100> prop1_getter_record;
i::OS::SNPrintF(prop1_getter_record,
"code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop1\"",
Prop1Getter);
CHECK_NE(NULL, strstr(buffer.start(), prop1_getter_record.start()));
EmbeddedVector<char, 100> prop1_setter_record;
i::OS::SNPrintF(prop1_setter_record,
"code-creation,Callback,0x%" V8PRIxPTR ",1,\"set prop1\"",
Prop1Setter);
CHECK_NE(NULL, strstr(buffer.start(), prop1_setter_record.start()));
EmbeddedVector<char, 100> prop2_getter_record;
i::OS::SNPrintF(prop2_getter_record,
"code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop2\"",
Prop2Getter);
CHECK_NE(NULL, strstr(buffer.start(), prop2_getter_record.start()));
obj.Dispose();
env->Exit();
Logger::TearDown();
i::FLAG_prof_lazy = saved_prof_lazy;
i::FLAG_prof = saved_prof;
i::FLAG_prof_auto = saved_prof_auto;
}
static inline bool IsStringEqualTo(const char* r, const char* s) { static inline bool IsStringEqualTo(const char* r, const char* s) {
return strncmp(r, s, strlen(r)) == 0; return strncmp(r, s, strlen(r)) == 0;
} }

37
deps/v8/test/cctest/test-serialize.cc

@ -192,6 +192,15 @@ TEST(Serialize) {
} }
// Test that heap serialization is non-destructive.
TEST(SerializeTwice) {
Serializer::Enable();
v8::V8::Initialize();
Serialize();
Serialize();
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Tests that the heap can be deserialized. // Tests that the heap can be deserialized.
@ -218,7 +227,17 @@ DEPENDENT_TEST(Deserialize, Serialize) {
Deserialize(); Deserialize();
fflush(stdout); v8::Persistent<v8::Context> env = v8::Context::New();
env->Enter();
SanityCheck();
}
DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
v8::HandleScope scope;
Deserialize();
v8::Persistent<v8::Context> env = v8::Context::New(); v8::Persistent<v8::Context> env = v8::Context::New();
env->Enter(); env->Enter();
@ -242,6 +261,22 @@ DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
} }
DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
SerializeTwice) {
v8::HandleScope scope;
Deserialize();
v8::Persistent<v8::Context> env = v8::Context::New();
env->Enter();
const char* c_source = "\"1234\".length";
v8::Local<v8::String> source = v8::String::New(c_source);
v8::Local<v8::Script> script = v8::Script::Compile(source);
CHECK_EQ(4, script->Run()->Int32Value());
}
TEST(TestThatAlwaysSucceeds) { TEST(TestThatAlwaysSucceeds) {
} }

117
deps/v8/test/cctest/test-strings.cc

@ -63,6 +63,21 @@ class Resource: public v8::String::ExternalStringResource,
}; };
class AsciiResource: public v8::String::ExternalAsciiStringResource,
public ZoneObject {
public:
explicit AsciiResource(Vector<const char> string): data_(string.start()) {
length_ = string.length();
}
virtual const char* data() const { return data_; }
virtual size_t length() const { return length_; }
private:
const char* data_;
size_t length_;
};
static void InitializeBuildingBlocks( static void InitializeBuildingBlocks(
Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) { Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) {
// A list of pointers that we don't have any interest in cleaning up. // A list of pointers that we don't have any interest in cleaning up.
@ -329,25 +344,89 @@ TEST(Utf8Conversion) {
} }
class TwoByteResource: public v8::String::ExternalStringResource { TEST(ExternalShortStringAdd) {
public: ZoneScope zone(DELETE_ON_EXIT);
TwoByteResource(const uint16_t* data, size_t length, bool* destructed)
: data_(data), length_(length), destructed_(destructed) {
CHECK_NE(destructed, NULL);
*destructed_ = false;
}
virtual ~TwoByteResource() { InitializeVM();
CHECK_NE(destructed_, NULL); v8::HandleScope handle_scope;
CHECK(!*destructed_);
*destructed_ = true;
}
const uint16_t* data() const { return data_; } // Make sure we cover all always-flat lengths and at least one above.
size_t length() const { return length_; } static const int kMaxLength = 20;
CHECK_GT(kMaxLength, i::String::kMinNonFlatLength);
// Allocate two JavaScript arrays for holding short strings.
v8::Handle<v8::Array> ascii_external_strings =
v8::Array::New(kMaxLength + 1);
v8::Handle<v8::Array> non_ascii_external_strings =
v8::Array::New(kMaxLength + 1);
// Generate short ascii and non-ascii external strings.
for (int i = 0; i <= kMaxLength; i++) {
char* ascii = Zone::NewArray<char>(i + 1);
for (int j = 0; j < i; j++) {
ascii[j] = 'a';
}
// Terminating '\0' is left out on purpose. It is not required for external
// string data.
AsciiResource* ascii_resource =
new AsciiResource(Vector<const char>(ascii, i));
v8::Local<v8::String> ascii_external_string =
v8::String::NewExternal(ascii_resource);
ascii_external_strings->Set(v8::Integer::New(i), ascii_external_string);
uc16* non_ascii = Zone::NewArray<uc16>(i + 1);
for (int j = 0; j < i; j++) {
non_ascii[j] = 0x1234;
}
// Terminating '\0' is left out on purpose. It is not required for external
// string data.
Resource* resource = new Resource(Vector<const uc16>(non_ascii, i));
v8::Local<v8::String> non_ascii_external_string =
v8::String::NewExternal(resource);
non_ascii_external_strings->Set(v8::Integer::New(i),
non_ascii_external_string);
}
private: // Add the arrays with the short external strings in the global object.
const uint16_t* data_; v8::Handle<v8::Object> global = env->Global();
size_t length_; global->Set(v8_str("external_ascii"), ascii_external_strings);
bool* destructed_; global->Set(v8_str("external_non_ascii"), non_ascii_external_strings);
}; global->Set(v8_str("max_length"), v8::Integer::New(kMaxLength));
// Add short external ascii and non-ascii strings checking the result.
static const char* source =
"function test() {"
" var ascii_chars = 'aaaaaaaaaaaaaaaaaaaa';"
" var non_ascii_chars = '\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234';" //NOLINT
" if (ascii_chars.length != max_length) return 1;"
" if (non_ascii_chars.length != max_length) return 2;"
" var ascii = Array(max_length + 1);"
" var non_ascii = Array(max_length + 1);"
" for (var i = 0; i <= max_length; i++) {"
" ascii[i] = ascii_chars.substring(0, i);"
" non_ascii[i] = non_ascii_chars.substring(0, i);"
" };"
" for (var i = 0; i <= max_length; i++) {"
" if (ascii[i] != external_ascii[i]) return 3;"
" if (non_ascii[i] != external_non_ascii[i]) return 4;"
" for (var j = 0; j < i; j++) {"
" if (external_ascii[i] !="
" (external_ascii[j] + external_ascii[i - j])) return 5;"
" if (external_non_ascii[i] !="
" (external_non_ascii[j] + external_non_ascii[i - j])) return 6;"
" if (non_ascii[i] != (non_ascii[j] + non_ascii[i - j])) return 7;"
" if (ascii[i] != (ascii[j] + ascii[i - j])) return 8;"
" if (ascii[i] != (external_ascii[j] + ascii[i - j])) return 9;"
" if (ascii[i] != (ascii[j] + external_ascii[i - j])) return 10;"
" if (non_ascii[i] !="
" (external_non_ascii[j] + non_ascii[i - j])) return 11;"
" if (non_ascii[i] !="
" (non_ascii[j] + external_non_ascii[i - j])) return 12;"
" }"
" }"
" return 0;"
"};"
"test()";
CHECK_EQ(0,
v8::Script::Compile(v8::String::New(source))->Run()->Int32Value());
}

164
deps/v8/test/mjsunit/arguments-read-and-assignment.js

@ -0,0 +1,164 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Testing basic functionality of the arguments object.
// Introduced to ensure that the fast compiler does the right thing.
// The arguments object itself.
assertEquals(42, function(){ return arguments;}(42)[0],
"return arguments value");
assertEquals(42, function(){ return arguments;}(42)[0],
"arguments in plain value context");
assertEquals(42, function(){ arguments;return 42}(37),
"arguments in effect context");
assertEquals(42, function(){ if(arguments)return 42;}(),
"arguments in a boolean context");
assertEquals(42, function(){ return arguments || true;}(42)[0],
"arguments in a short-circuit boolean context - or");
assertEquals(true, function(){ return arguments && [true];}(42)[0],
"arguments in a short-circuit boolean context - and");
assertEquals(42, function(){ arguments = 42; return 42;}(),
"arguments assignment");
// Properties of the arguments object.
assertEquals(42, function(){ return arguments[0]; }(42),
"args[0] value returned");
assertEquals(42, function(){ arguments[0]; return 42}(),
"args[0] value ignored");
assertEquals(42, function(){ if (arguments[0]) return 42; }(37),
"args[0] to boolean");
assertEquals(42, function(){ return arguments[0] || "no"; }(42),
"args[0] short-circuit boolean or true");
assertEquals(42, function(){ return arguments[0] || 42; }(0),
"args[0] short-circuit boolean or false");
assertEquals(37, function(){ return arguments[0] && 37; }(42),
"args[0] short-circuit boolean and true");
assertEquals(0, function(){ return arguments[0] && 42; }(0),
"args[0] short-circuit boolean and false");
assertEquals(42, function(){ arguments[0] = 42; return arguments[0]; }(37),
"args[0] assignment");
// Link between arguments and parameters.
assertEquals(42, function(a) { arguments[0] = 42; return a; }(37),
"assign args[0]->a");
assertEquals(42, function(a) { a = 42; return arguments[0]; }(37),
"assign a->args[0]");
assertEquals(54, function(a, b) { arguments[1] = 54; return b; }(42, 37),
"assign args[1]->b:b");
assertEquals(54, function(a, b) { b = 54; return arguments[1]; }(42, 47),
"assign b->args[1]:b");
assertEquals(42, function(a, b) { arguments[1] = 54; return a; }(42, 37),
"assign args[1]->b:a");
assertEquals(42, function(a, b) { b = 54; return arguments[0]; }(42, 47),
"assign b->args[1]:a");
// Capture parameters in nested contexts.
assertEquals(33,
function(a,b) {
return a + arguments[0] +
function(b){ return a + b + arguments[0]; }(b); }(7,6),
"captured parameters");
assertEquals(42, function(a) {
arguments[0] = 42;
return function(b){ return a; }();
}(37),
"capture value returned");
assertEquals(42,
function(a) {
arguments[0] = 26;
return function(b){ a; return 42; }();
}(37),
"capture value ignored");
assertEquals(42,
function(a) {
arguments[0] = 26;
return function(b){ if (a) return 42; }();
}(37),
"capture to boolean");
assertEquals(42,
function(a) {
arguments[0] = 42;
return function(b){ return a || "no"; }();
}(37),
"capture short-circuit boolean or true");
assertEquals(0,
function(a) {
arguments[0] = 0;
return function(b){ return a && 42; }();
}(37),
"capture short-circuit boolean and false");
// Deeply nested.
assertEquals(42,
function(a,b) {
return arguments[2] +
function(){
return b +
function() {
return a;
}();
}();
}(7,14,21),
"deep nested capture");
// Assignment to captured parameters.
assertEquals(42, function(a,b) {
arguments[1] = 11;
return a + function(){ a = b; return a; }() + a;
}(20, 37), "captured assignment");
// Inside non-function scopes.
assertEquals(42,
function(a) {
arguments[0] = 20;
with ({ b : 22 }) { return a + b; }
}(37),
"a in with");
assertEquals(42,
function(a) {
with ({ b : 22 }) { return arguments[0] + b; }
}(20),
"args in with");
assertEquals(42,
function(a) {
arguments[0] = 20;
with ({ b : 22 }) {
return function() { return a; }() + b; }
}(37),
"captured a in with");
assertEquals(42,
function(a) {
arguments[0] = 12;
with ({ b : 22 }) {
return function f() {
try { throw 8 } catch(e) { return e + a };
}() + b;
}
}(37),
"in a catch in a named function captured a in with ");
// Escaping arguments.
function weirdargs(a,b,c) { if (!a) return arguments;
return [b[2],c]; }
var args1 = weirdargs(false, null, 40);
var res = weirdargs(true, args1, 15);
assertEquals(40, res[0], "return old args element");
assertEquals(15, res[1], "return own args element");

33
deps/v8/test/mjsunit/compiler/jsnatives.js

@ -0,0 +1,33 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
// Test call of JS runtime functions.
var a = %GlobalParseInt("21", 16);
assertEquals(33, a);

57
deps/v8/test/mjsunit/compiler/objectliterals.js

@ -0,0 +1,57 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test object literals with getter, setter and prototype properties.
var o = { x: 41, get bar() { return {x:42} } };
assertEquals(41, o.x);
assertEquals(42, o.bar.x);
o = { f: function() { return 41 },
get bar() { return this.x },
x:0,
set bar(t) { this.x = t },
g: function() { return 43 }
};
o.bar = 7;
assertEquals(7, o.bar);
assertEquals(7, o.x);
assertEquals(41, o.f());
assertEquals(43, o.g());
p = {x:42};
o = {get foo() { return this.x; },
f: function() { return this.foo + 1 },
set bar(t) { this.x = t; },
__proto__: p,
};
assertEquals(42, o.x);
assertEquals(42, o.foo);
assertEquals(43, o.f());
o.bar = 44;
assertEquals(44, o.foo);

32
deps/v8/test/mjsunit/regress/regress-526.js

@ -0,0 +1,32 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test object literals with computed property and getter.
var o = { foo: function() { }, get bar() { return {x:42} } };
assertEquals(42, o.bar.x);

77
deps/v8/test/mjsunit/regress/regress-r3391.js

@ -0,0 +1,77 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Check what we do if toLocaleString doesn't return a string when we are
// calling Array.prototype.toLocaleString. The standard is somewhat
// vague on this point. This test is now passed by both V8 and JSC.
var evil_called = 0;
var evil_locale_called = 0;
var exception_thrown = 0;
function evil_to_string() {
evil_called++;
return this;
}
function evil_to_locale_string() {
evil_locale_called++;
return this;
}
var o = {toString: evil_to_string, toLocaleString: evil_to_locale_string};
try {
[o].toLocaleString();
} catch(e) {
exception_thrown++;
}
assertEquals(1, evil_called, "evil1");
assertEquals(1, evil_locale_called, "local1");
assertEquals(1, exception_thrown, "exception1");
try {
[o].toString();
} catch(e) {
exception_thrown++;
}
assertEquals(2, evil_called, "evil2");
assertEquals(1, evil_locale_called, "local2");
assertEquals(2, exception_thrown, "exception2");
try {
[o].join(o);
} catch(e) {
exception_thrown++;
}
assertEquals(3, evil_called, "evil3");
assertEquals(1, evil_locale_called, "local3");
assertEquals(3, exception_thrown, "exception3");
print("ok");

20
deps/v8/test/mjsunit/string-add.js

@ -173,3 +173,23 @@ assertEquals(0, null + null, "uu");
assertEquals("42strz", reswz, "swwz"); assertEquals("42strz", reswz, "swwz");
assertEquals(84, resww, "swww"); assertEquals(84, resww, "swww");
})(1); })(1);
// Generate ascii and non ascii strings from length 0 to 20.
var ascii = 'aaaaaaaaaaaaaaaaaaaa';
var non_ascii = '\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234\u1234';
assertEquals(20, ascii.length);
assertEquals(20, non_ascii.length);
var a = Array(21);
var b = Array(21);
for (var i = 0; i <= 20; i++) {
a[i] = ascii.substring(0, i);
b[i] = non_ascii.substring(0, i);
}
// Add ascii and non-ascii strings generating strings with length from 0 to 20.
for (var i = 0; i <= 20; i++) {
for (var j = 0; j < i; j++) {
assertEquals(a[i], a[j] + a[i - j])
assertEquals(b[i], b[j] + b[i - j])
}
}

40
deps/v8/test/mjsunit/typeof.js

@ -0,0 +1,40 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --nofast-compiler
// The type of a regular expression should be 'function', including in
// the context of string equality comparisons.
var r = new RegExp;
assertEquals('function', typeof r);
assertTrue(typeof r == 'function');
function test(x, y) { return x == y; }
assertFalse(test('object', typeof r));
assertFalse(typeof r == 'object');

2
deps/v8/tools/codemap.js

@ -244,7 +244,7 @@ devtools.profiler.CodeMap.CodeEntry.prototype.toString = function() {
devtools.profiler.CodeMap.NameGenerator = function() { devtools.profiler.CodeMap.NameGenerator = function() {
this.knownNames_ = []; this.knownNames_ = {};
}; };

11
deps/v8/tools/gyp/v8.gyp

@ -506,6 +506,17 @@
], ],
} }
], ],
['OS=="openbsd"', {
'link_settings': {
'libraries': [
'-L/usr/local/lib -lexecinfo',
]},
'sources': [
'../../src/platform-openbsd.cc',
'../../src/platform-posix.cc'
],
}
],
['OS=="mac"', { ['OS=="mac"', {
'sources': [ 'sources': [
'../../src/platform-macos.cc', '../../src/platform-macos.cc',

71
deps/v8/tools/presubmit.py

@ -28,9 +28,11 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import md5
import optparse import optparse
import os import os
from os.path import abspath, join, dirname, basename, exists from os.path import abspath, join, dirname, basename, exists
import pickle
import re import re
import sys import sys
import subprocess import subprocess
@ -93,6 +95,50 @@ whitespace/todo
""".split() """.split()
class FileContentsCache(object):
def __init__(self, sums_file_name):
self.sums = {}
self.sums_file_name = sums_file_name
def Load(self):
try:
sums_file = None
try:
sums_file = open(self.sums_file_name, 'r')
self.sums = pickle.load(sums_file)
except IOError:
# File might not exist, this is OK.
pass
finally:
if sums_file:
sums_file.close()
def Save(self):
try:
sums_file = open(self.sums_file_name, 'w')
pickle.dump(self.sums, sums_file)
finally:
sums_file.close()
def FilterUnchangedFiles(self, files):
changed_or_new = []
for file in files:
try:
handle = open(file, "r")
file_sum = md5.new(handle.read()).digest()
if not file in self.sums or self.sums[file] != file_sum:
changed_or_new.append(file)
self.sums[file] = file_sum
finally:
handle.close()
return changed_or_new
def RemoveFile(self, file):
if file in self.sums:
self.sums.pop(file)
class SourceFileProcessor(object): class SourceFileProcessor(object):
""" """
Utility class that can run through a directory structure, find all relevant Utility class that can run through a directory structure, find all relevant
@ -137,7 +183,7 @@ class CppLintProcessor(SourceFileProcessor):
or (name == 'third_party')) or (name == 'third_party'))
IGNORE_LINT = ['flag-definitions.h'] IGNORE_LINT = ['flag-definitions.h']
def IgnoreFile(self, name): def IgnoreFile(self, name):
return (super(CppLintProcessor, self).IgnoreFile(name) return (super(CppLintProcessor, self).IgnoreFile(name)
or (name in CppLintProcessor.IGNORE_LINT)) or (name in CppLintProcessor.IGNORE_LINT))
@ -146,13 +192,32 @@ class CppLintProcessor(SourceFileProcessor):
return ['src', 'public', 'samples', join('test', 'cctest')] return ['src', 'public', 'samples', join('test', 'cctest')]
def ProcessFiles(self, files, path): def ProcessFiles(self, files, path):
good_files_cache = FileContentsCache('.cpplint-cache')
good_files_cache.Load()
files = good_files_cache.FilterUnchangedFiles(files)
if len(files) == 0:
print 'No changes in files detected. Skipping cpplint check.'
return True
filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES]) filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES])
command = ['cpplint.py', '--filter', filt] + join(files) command = ['cpplint.py', '--filter', filt] + join(files)
local_cpplint = join(path, "tools", "cpplint.py") local_cpplint = join(path, "tools", "cpplint.py")
if exists(local_cpplint): if exists(local_cpplint):
command = ['python', local_cpplint, '--filter', filt] + join(files) command = ['python', local_cpplint, '--filter', filt] + join(files)
process = subprocess.Popen(command)
return process.wait() == 0 process = subprocess.Popen(command, stderr=subprocess.PIPE)
LINT_ERROR_PATTERN = re.compile(r'^(.+)[:(]\d+[:)]')
while True:
out_line = process.stderr.readline()
if out_line == '' and process.poll() != None:
break
sys.stderr.write(out_line)
m = LINT_ERROR_PATTERN.match(out_line)
if m:
good_files_cache.RemoveFile(m.group(1))
good_files_cache.Save()
return process.returncode == 0
COPYRIGHT_HEADER_PATTERN = re.compile( COPYRIGHT_HEADER_PATTERN = re.compile(

2
deps/v8/tools/utils.py

@ -55,6 +55,8 @@ def GuessOS():
return 'win32' return 'win32'
elif id == 'FreeBSD': elif id == 'FreeBSD':
return 'freebsd' return 'freebsd'
elif id == 'OpenBSD':
return 'openbsd'
else: else:
return None return None

16
deps/v8/tools/v8.xcodeproj/project.pbxproj

@ -214,6 +214,10 @@
9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F4B7B870FCC877A00DC4117 /* log-utils.cc */; }; 9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F4B7B870FCC877A00DC4117 /* log-utils.cc */; };
9F92FAA90F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; }; 9F92FAA90F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; };
9F92FAAA0F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; }; 9F92FAAA0F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; };
9FBE03DE10BD409900F8BFBA /* fast-codegen.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FBE03DC10BD409900F8BFBA /* fast-codegen.cc */; };
9FBE03DF10BD409900F8BFBA /* fast-codegen.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FBE03DC10BD409900F8BFBA /* fast-codegen.cc */; };
9FBE03E210BD40EA00F8BFBA /* fast-codegen-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FBE03E110BD40EA00F8BFBA /* fast-codegen-ia32.cc */; };
9FBE03E510BD412600F8BFBA /* fast-codegen-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FBE03E410BD412600F8BFBA /* fast-codegen-arm.cc */; };
9FC86ABD0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; }; 9FC86ABD0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; };
9FC86ABE0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; }; 9FC86ABE0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -550,6 +554,10 @@
9F4B7B880FCC877A00DC4117 /* log-utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "log-utils.h"; sourceTree = "<group>"; }; 9F4B7B880FCC877A00DC4117 /* log-utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "log-utils.h"; sourceTree = "<group>"; };
9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "func-name-inferrer.cc"; sourceTree = "<group>"; }; 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "func-name-inferrer.cc"; sourceTree = "<group>"; };
9F92FAA80F8F28AD0089F02C /* func-name-inferrer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "func-name-inferrer.h"; sourceTree = "<group>"; }; 9F92FAA80F8F28AD0089F02C /* func-name-inferrer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "func-name-inferrer.h"; sourceTree = "<group>"; };
9FBE03DC10BD409900F8BFBA /* fast-codegen.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "fast-codegen.cc"; sourceTree = "<group>"; };
9FBE03DD10BD409900F8BFBA /* fast-codegen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "fast-codegen.h"; sourceTree = "<group>"; };
9FBE03E110BD40EA00F8BFBA /* fast-codegen-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "fast-codegen-ia32.cc"; path = "ia32/fast-codegen-ia32.cc"; sourceTree = "<group>"; };
9FBE03E410BD412600F8BFBA /* fast-codegen-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "fast-codegen-arm.cc"; path = "arm/fast-codegen-arm.cc"; sourceTree = "<group>"; };
9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "oprofile-agent.cc"; sourceTree = "<group>"; }; 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "oprofile-agent.cc"; sourceTree = "<group>"; };
9FC86ABC0F5FEDAC00F22668 /* oprofile-agent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "oprofile-agent.h"; sourceTree = "<group>"; }; 9FC86ABC0F5FEDAC00F22668 /* oprofile-agent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "oprofile-agent.h"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -715,6 +723,10 @@
897FF1310E719B8F00D62E90 /* execution.h */, 897FF1310E719B8F00D62E90 /* execution.h */,
897FF1320E719B8F00D62E90 /* factory.cc */, 897FF1320E719B8F00D62E90 /* factory.cc */,
897FF1330E719B8F00D62E90 /* factory.h */, 897FF1330E719B8F00D62E90 /* factory.h */,
9FBE03DC10BD409900F8BFBA /* fast-codegen.cc */,
9FBE03DD10BD409900F8BFBA /* fast-codegen.h */,
9FBE03E410BD412600F8BFBA /* fast-codegen-arm.cc */,
9FBE03E110BD40EA00F8BFBA /* fast-codegen-ia32.cc */,
89471C7F0EB23EE400B6874B /* flag-definitions.h */, 89471C7F0EB23EE400B6874B /* flag-definitions.h */,
897FF1350E719B8F00D62E90 /* flags.cc */, 897FF1350E719B8F00D62E90 /* flags.cc */,
897FF1360E719B8F00D62E90 /* flags.h */, 897FF1360E719B8F00D62E90 /* flags.h */,
@ -1225,6 +1237,8 @@
9F4B7B890FCC877A00DC4117 /* log-utils.cc in Sources */, 9F4B7B890FCC877A00DC4117 /* log-utils.cc in Sources */,
8981F6001010501900D1520E /* frame-element.cc in Sources */, 8981F6001010501900D1520E /* frame-element.cc in Sources */,
9F11D9A0105AF0A300EBE5B2 /* heap-profiler.cc in Sources */, 9F11D9A0105AF0A300EBE5B2 /* heap-profiler.cc in Sources */,
9FBE03DE10BD409900F8BFBA /* fast-codegen.cc in Sources */,
9FBE03E210BD40EA00F8BFBA /* fast-codegen-ia32.cc in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -1332,6 +1346,8 @@
9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */, 9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */,
8981F6011010502800D1520E /* frame-element.cc in Sources */, 8981F6011010502800D1520E /* frame-element.cc in Sources */,
9F11D9A1105AF0A300EBE5B2 /* heap-profiler.cc in Sources */, 9F11D9A1105AF0A300EBE5B2 /* heap-profiler.cc in Sources */,
9FBE03DF10BD409900F8BFBA /* fast-codegen.cc in Sources */,
9FBE03E510BD412600F8BFBA /* fast-codegen-arm.cc in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

Loading…
Cancel
Save