Browse Source

upgrade v8 to 2.0.3

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
c8b6ef248e
  1. 23
      deps/v8/ChangeLog
  2. 22
      deps/v8/SConstruct
  3. 20
      deps/v8/include/v8.h
  4. 4
      deps/v8/src/SConscript
  5. 68
      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. 129
      deps/v8/src/arm/codegen-arm.cc
  10. 3
      deps/v8/src/arm/codegen-arm.h
  11. 25
      deps/v8/src/arm/constants-arm.h
  12. 2
      deps/v8/src/arm/debug-arm.cc
  13. 292
      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. 28
      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. 42
      deps/v8/src/compiler.cc
  24. 6
      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. 40
      deps/v8/src/handles.cc
  35. 3
      deps/v8/src/handles.h
  36. 4
      deps/v8/src/heap-inl.h
  37. 191
      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. 295
      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. 130
      deps/v8/src/objects.cc
  55. 382
      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. 78
      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. 301
      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. 69
      deps/v8/tools/presubmit.py
  98. 2
      deps/v8/tools/utils.py
  99. 16
      deps/v8/tools/v8.xcodeproj/project.pbxproj

23
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
Improved profiler support.

22
deps/v8/SConstruct

@ -149,6 +149,11 @@ LIBRARY_FLAGS = {
'LIBPATH' : ['/usr/local/lib'],
'CCFLAGS': ['-ansi'],
},
'os:openbsd': {
'CPPPATH' : ['/usr/local/include'],
'LIBPATH' : ['/usr/local/lib'],
'CCFLAGS': ['-ansi'],
},
'os:win32': {
'CCFLAGS': ['-DWIN32'],
'CXXFLAGS': ['-DWIN32'],
@ -298,6 +303,9 @@ MKSNAPSHOT_EXTRA_FLAGS = {
'os:freebsd': {
'LIBS': ['execinfo', 'pthread']
},
'os:openbsd': {
'LIBS': ['execinfo', 'pthread']
},
'os:win32': {
'LIBS': ['winmm', 'ws2_32'],
},
@ -344,6 +352,9 @@ CCTEST_EXTRA_FLAGS = {
'os:freebsd': {
'LIBS': ['execinfo', 'pthread']
},
'os:openbsd': {
'LIBS': ['execinfo', 'pthread']
},
'os:win32': {
'LIBS': ['winmm', 'ws2_32']
},
@ -399,6 +410,10 @@ SAMPLE_FLAGS = {
'LIBPATH' : ['/usr/local/lib'],
'LIBS': ['execinfo', 'pthread']
},
'os:openbsd': {
'LIBPATH' : ['/usr/local/lib'],
'LIBS': ['execinfo', 'pthread']
},
'os:win32': {
'LIBS': ['winmm', 'ws2_32']
},
@ -504,6 +519,9 @@ D8_FLAGS = {
'os:freebsd': {
'LIBS': ['pthread'],
},
'os:openbsd': {
'LIBS': ['pthread'],
},
'os:android': {
'LIBPATH': [ANDROID_TOP + '/out/target/product/generic/obj/lib'],
'LINKFLAGS': ANDROID_LINKFLAGS,
@ -544,7 +562,7 @@ def GuessToolchain(os):
OS_GUESS = utils.GuessOS()
TOOLCHAIN_GUESS = GuessToolchain(OS_GUESS)
ARCH_GUESS = utils.GuessArchitecture() or ""
ARCH_GUESS = utils.GuessArchitecture()
SIMPLE_OPTIONS = {
@ -554,7 +572,7 @@ SIMPLE_OPTIONS = {
'help': 'the toolchain to use (' + TOOLCHAIN_GUESS + ')'
},
'os': {
'values': ['freebsd', 'linux', 'macos', 'win32', 'android'],
'values': ['freebsd', 'linux', 'macos', 'win32', 'android', 'openbsd'],
'default': 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
* 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
* the debugger API.
*/
void SetData(Handle<Value> data);
void SetData(Handle<String> data);
Local<Value> GetData();
/**
@ -2819,6 +2819,18 @@ template <> struct SmiConstants<8> {
const int kSmiShiftSize = SmiConstants<sizeof(void*)>::kSmiShiftSize;
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
* is necessary to implement inline functions in the v8 api. Don't
@ -2831,7 +2843,9 @@ class Internals {
// the implementation of v8.
static const int kHeapObjectMapOffset = 0;
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 kJSObjectHeaderSize = 3 * sizeof(void*);
static const int kFullStringRepresentationMask = 0x07;

4
deps/v8/src/SConscript

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

68
deps/v8/src/accessors.cc

@ -315,14 +315,11 @@ Object* Accessors::ScriptGetLineEnds(Object* object, void*) {
HandleScope scope;
Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
InitScriptLineEnds(script);
if (script->line_ends_js_array()->IsUndefined()) {
Handle<FixedArray> line_ends_fixed_array(
FixedArray::cast(script->line_ends_fixed_array()));
Handle<FixedArray> copy = Factory::CopyFixedArray(line_ends_fixed_array);
ASSERT(script->line_ends()->IsFixedArray());
Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
Handle<FixedArray> copy = Factory::CopyFixedArray(line_ends);
Handle<JSArray> js_array = Factory::NewJSArrayWithElements(copy);
script->set_line_ends_js_array(*js_array);
}
return script->line_ends_js_array();
return *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();
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 = {
ScriptGetEvalFromFunction,
const AccessorDescriptor Accessors::ScriptEvalFromScript = {
ScriptGetEvalFromScript,
IllegalSetter,
0
};
//
// Accessors::ScriptGetEvalFromPosition
// Accessors::ScriptGetEvalFromScriptPosition
//
Object* Accessors::ScriptGetEvalFromPosition(Object* object, void*) {
Object* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
HandleScope scope;
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
// 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() +
script->eval_from_instructions_offset()->value()));
}
const AccessorDescriptor Accessors::ScriptEvalFromPosition = {
ScriptGetEvalFromPosition,
const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
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,
0
};

10
deps/v8/src/accessors.h

@ -51,8 +51,9 @@ namespace internal {
V(ScriptCompilationType) \
V(ScriptLineEnds) \
V(ScriptContextData) \
V(ScriptEvalFromFunction) \
V(ScriptEvalFromPosition) \
V(ScriptEvalFromScript) \
V(ScriptEvalFromScriptPosition) \
V(ScriptEvalFromFunctionName) \
V(ObjectPrototype)
// Accessors contains all predefined proxy accessors.
@ -95,8 +96,9 @@ class Accessors : public AllStatic {
static Object* ScriptGetCompilationType(Object* object, void*);
static Object* ScriptGetLineEnds(Object* object, void*);
static Object* ScriptGetContextData(Object* object, void*);
static Object* ScriptGetEvalFromFunction(Object* object, void*);
static Object* ScriptGetEvalFromPosition(Object* object, void*);
static Object* ScriptGetEvalFromScript(Object* object, void*);
static Object* ScriptGetEvalFromScriptPosition(Object* object, void*);
static Object* ScriptGetEvalFromFunctionName(Object* object, void*);
static Object* ObjectGetPrototype(Object* receiver, 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.
// The default fatal error handler is called and execution is stopped.
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();
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;
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);
LOG_API("Script::SetData");
{

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

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

129
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
// the constant pool is not emitted inside of the return sequence.
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)) {
// Additional mov instruction generated.
return_sequence_length++;
@ -1775,19 +1775,77 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
jsobject.Bind();
// Get the set of properties (as a FixedArray or Map).
frame_->EmitPush(r0); // duplicate the object being enumerated
frame_->EmitPush(r0);
// r0: value to be iterated over
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);
// If we got a Map, we can do a fast modification check.
// Otherwise, we got a FixedArray, and we have to do a slow check.
// If we got a map from the runtime call, we can do a fast
// 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));
__ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kMetaMapRootIndex);
__ cmp(r1, ip);
fixed_array.Branch(ne);
use_cache.Bind();
// 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));
__ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
__ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
@ -3308,9 +3366,6 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
// Now r2 has the string type.
__ 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.
__ cmp(r3, Operand(r0, LSR, kSmiTagSize));
__ 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) {
VirtualFrame::SpilledScope spilled_scope;
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
// sort or new-space allocation fails).
__ bind(&slow);
// Push arguments to the stack
__ push(r1);
__ 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.
__ InvokeBuiltin(builtin, JUMP_JS); // Tail call. No return.
@ -6388,7 +6499,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
__ b(eq, &adaptor);
// 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.
__ cmp(r1, r0);
__ 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 GenerateMathCos(ZoneList<Expression*>* args);
// Fast support for StringAdd.
void GenerateStringAdd(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {
ALWAYS_TRUE,

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

@ -43,24 +43,27 @@
# define USE_THUMB_INTERWORK 1
#endif
#if defined(__ARM_ARCH_5T__) || \
defined(__ARM_ARCH_5TE__) || \
defined(__ARM_ARCH_6__) || \
defined(__ARM_ARCH_7A__) || \
#if defined(__ARM_ARCH_7A__) || \
defined(__ARM_ARCH_7R__) || \
defined(__ARM_ARCH_7__)
# define CAN_USE_ARMV5_INSTRUCTIONS 1
# define CAN_USE_THUMB_INSTRUCTIONS 1
# define CAN_USE_ARMV7_INSTRUCTIONS 1
#endif
#if defined(__ARM_ARCH_6__) || \
defined(__ARM_ARCH_7A__) || \
defined(__ARM_ARCH_7__)
defined(__ARM_ARCH_6J__) || \
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
#endif
#if defined(__ARM_ARCH_7A__) || \
defined(__ARM_ARCH_7__)
# define CAN_USE_ARMV7_INSTRUCTIONS 1
#if defined(__ARM_ARCH_5T__) || \
defined(__ARM_ARCH_5TE__) || \
defined(CAN_USE_ARMV6_INSTRUCTIONS)
# define CAN_USE_ARMV5_INSTRUCTIONS 1
# define CAN_USE_THUMB_INSTRUCTIONS 1
#endif
// 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.
void BreakLocationIterator::ClearDebugBreakAtReturn() {
rinfo()->PatchCode(original_rinfo()->pc(),
Debug::kARMJSReturnSequenceLength);
Assembler::kJSReturnSequenceLength);
}

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

@ -73,16 +73,46 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
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();
if (arguments != NULL) {
// Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object");
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.
__ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize));
__ 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:
// function, receiver address, parameter count.
@ -90,33 +120,12 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
// stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ 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 =
fun->scope()->arguments_shadow()->AsVariable()->slot();
__ str(r0, MemOperand(fp, SlotOffset(dot_arguments_slot)));
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
Move(dot_arguments_slot, r3, r1, r2);
}
// 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.
int num_parameters = function_->scope()->num_parameters();
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)) {
// Additional mov instruction generated.
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) {
case Expression::kUninitialized:
UNREACHABLE();
@ -248,8 +292,8 @@ void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
case Expression::kTest: // Fall through.
case Expression::kValueTest: // Fall through.
case Expression::kTestValue:
__ ldr(ip, MemOperand(fp, SlotOffset(source)));
Move(context, ip);
Move(scratch, source);
Move(context, scratch);
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,
Register source) {
Register source,
int drop_count) {
ASSERT(drop_count > 0);
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
__ pop();
__ add(sp, sp, Operand(drop_count * kPointerSize));
break;
case Expression::kValue:
if (drop_count > 1) {
__ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
}
__ str(source, MemOperand(sp));
break;
case Expression::kTest:
ASSERT(!source.is(sp));
__ pop();
__ add(sp, sp, Operand(drop_count * kPointerSize));
TestAndBranch(source, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
if (drop_count > 1) {
__ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
}
__ str(source, MemOperand(sp));
TestAndBranch(source, true_label_, &discard);
__ bind(&discard);
@ -299,6 +379,9 @@ void FastCodeGenerator::DropAndMove(Expression::Context context,
}
case Expression::kTestValue: {
Label discard;
if (drop_count > 1) {
__ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
}
__ str(source, MemOperand(sp));
TestAndBranch(source, &discard, false_label_);
__ bind(&discard);
@ -376,26 +459,26 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
__ mov(r0, Operand(Factory::the_hole_value()));
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ ldr(r1, CodeGenerator::ContextOperand(
cp, Context::FCONTEXT_INDEX));
__ ldr(r1, CodeGenerator::ContextOperand(cp,
Context::FCONTEXT_INDEX));
__ cmp(r1, cp);
__ Check(eq, "Unexpected declaration in current context.");
}
__ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
// 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) {
Visit(decl->fun());
__ pop(r0);
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ ldr(r1, CodeGenerator::ContextOperand(
cp, Context::FCONTEXT_INDEX));
__ ldr(r1, CodeGenerator::ContextOperand(cp,
Context::FCONTEXT_INDEX));
__ cmp(r1, cp);
__ Check(eq, "Unexpected declaration in current context.");
}
__ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
int offset = Context::SlotOffset(slot->index());
__ mov(r2, Operand(offset));
// We know that we have written a function, which is not a smi.
__ RecordWrite(cp, r2, r0);
@ -467,53 +550,60 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
DropAndMove(expr->context(), r0);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
ASSERT_NE(NULL, slot);
if (FLAG_debug_code) {
switch (slot->type()) {
case Slot::LOCAL:
case Slot::PARAMETER: {
Comment cmnt(masm_, "Stack slot");
Move(expr->context(), rewrite->AsSlot());
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()));
Move(expr->context(), r0);
break;
}
case Slot::LOOKUP:
UNREACHABLE();
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
Move(expr->context(), slot, r0);
} else {
// The parameter variable has been rewritten into an explict access to
// the arguments object.
// A variable has been rewritten into an explicit access to
// an object property.
Property* property = rewrite->AsProperty();
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);
}
// If result_saved == true: the result is saved on top of the stack.
// If result_saved == false: the result is in r0.
// If result_saved == true: The result is saved on top of the
// stack and in r0.
// If result_saved == false: The result not on the stack, just in r0.
bool result_saved = false;
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));
__ Call(ic, RelocInfo::CODE_TARGET);
// StoreIC leaves the receiver on the stack.
__ ldr(r0, MemOperand(sp)); // Restore result into r0.
break;
}
// Fall through.
@ -615,7 +707,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Visit(value);
ASSERT_EQ(Expression::kValue, value->context());
__ CallRuntime(Runtime::kSetProperty, 3);
__ ldr(r0, MemOperand(sp)); // Restore result into r0
__ ldr(r0, MemOperand(sp)); // Restore result into r0.
break;
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.
DropAndMove(expr->context(), r0);
} else {
} else if (var->slot()) {
Slot* slot = var->slot();
ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
switch (slot->type()) {
@ -884,6 +976,35 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
UNREACHABLE();
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) {
Comment cmnt(masm_, "[ CallRuntime");
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").
int arg_count = args->length();
@ -1145,8 +1271,20 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
ASSERT_EQ(Expression::kValue, args->at(i)->context());
}
__ CallRuntime(function, arg_count);
if (expr->is_jsruntime()) {
// 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;
for (int i = 0; i < kProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ ldr(t1, FieldMemOperand(r2, String::kLengthOffset));
__ mov(t1, Operand(t1, LSR, String::kHashShift));
__ ldr(t1, FieldMemOperand(r2, String::kHashFieldOffset));
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.
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) {
// Empty the const pool.
CheckConstPool(true, true);
@ -785,15 +794,13 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
mov(scratch1, Operand(new_space_allocation_top));
if ((flags & RESULT_CONTAINS_TOP) == 0) {
ldr(result, MemOperand(scratch1));
} else {
#ifdef DEBUG
} else if (FLAG_debug_code) {
// Assert that result actually contains top on entry. scratch2 is used
// immediately below so this use of scratch2 does not cause difference with
// respect to register content between debug and release mode.
ldr(scratch2, MemOperand(scratch1));
cmp(result, scratch2);
Check(eq, "Unexpected allocation top");
#endif
}
// 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));
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));
// 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));
if ((flags & RESULT_CONTAINS_TOP) == 0) {
ldr(result, MemOperand(scratch1));
} else {
#ifdef DEBUG
} else if (FLAG_debug_code) {
// Assert that result actually contains top on entry. scratch2 is used
// immediately below so this use of scratch2 does not cause difference with
// respect to register content between debug and release mode.
ldr(scratch2, MemOperand(scratch1));
cmp(result, scratch2);
Check(eq, "Unexpected allocation top");
#endif
}
// 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));
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));
// Adjust back to start of new object.
@ -1153,6 +1166,9 @@ void MacroAssembler::Abort(const char* msg) {
RecordComment(msg);
}
#endif
// Disable stub call restrictions to always allow calls to abort.
set_allow_stub_calls(true);
mov(r0, Operand(p0));
push(r0);
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
CodePatcher::CodePatcher(byte* address, int instructions)
: address_(address),

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

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

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

@ -105,7 +105,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ b(eq, &miss);
// 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));
__ add(scratch, scratch, Operand(ip));
__ eor(scratch, scratch, Operand(flags));
@ -229,10 +229,7 @@ void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
miss, &check_wrapper);
// Load length directly from the string.
__ and_(scratch1, scratch1, Operand(kStringSizeMask));
__ add(scratch1, scratch1, Operand(String::kHashShift));
__ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
__ mov(r0, Operand(r0, LSR, scratch1));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ Ret();

28
deps/v8/src/array.js

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

1
deps/v8/src/ast.h

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

26
deps/v8/src/bootstrapper.cc

@ -1111,21 +1111,29 @@ bool Genesis::InstallNatives() {
Factory::LookupAsciiSymbol("context_data"),
proxy_context_data,
common_attributes);
Handle<Proxy> proxy_eval_from_function =
Factory::NewProxy(&Accessors::ScriptEvalFromFunction);
Handle<Proxy> proxy_eval_from_script =
Factory::NewProxy(&Accessors::ScriptEvalFromScript);
script_descriptors =
Factory::CopyAppendProxyDescriptor(
script_descriptors,
Factory::LookupAsciiSymbol("eval_from_function"),
proxy_eval_from_function,
Factory::LookupAsciiSymbol("eval_from_script"),
proxy_eval_from_script,
common_attributes);
Handle<Proxy> proxy_eval_from_position =
Factory::NewProxy(&Accessors::ScriptEvalFromPosition);
Handle<Proxy> proxy_eval_from_script_position =
Factory::NewProxy(&Accessors::ScriptEvalFromScriptPosition);
script_descriptors =
Factory::CopyAppendProxyDescriptor(
script_descriptors,
Factory::LookupAsciiSymbol("eval_from_position"),
proxy_eval_from_position,
Factory::LookupAsciiSymbol("eval_from_script_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);
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);
if (!result) {
Top::clear_pending_exception();
v8::Utils::ReportApiFailure(
"v8::Context::New()", "Error installing extension");
}
current->set_state(v8::INSTALLED);
return result;

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

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

1
deps/v8/src/codegen.cc

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

42
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
// generator for code in the global scope. Otherwise obey the
// 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");
} 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");
} else {
CodeGenSelector selector;
@ -176,7 +179,8 @@ static Handle<JSFunction> MakeFunction(bool is_global,
// called.
if (is_eval) {
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>(
it.frame()->pc() - it.frame()->code()->instruction_start());
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;
VisitDeclarations(scope->declarations());
if (!has_supported_syntax_) return NORMAL;
@ -802,7 +801,17 @@ void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
BAILOUT("Lookup slot");
}
} 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,14 +895,23 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
// All global variables are supported.
if (!var->is_global()) {
if (var->slot() == NULL) {
// This is a parameter that has rewritten to an arguments access.
BAILOUT("non-global/non-slot assignment");
Property* property = var->AsProperty();
if (property == NULL) {
BAILOUT("non-global/non-slot/non-property assignment");
}
if (property->obj()->AsSlot() == NULL) {
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) {
ProcessExpression(prop->obj(), Expression::kValue);
CHECK_BAILOUT;
@ -979,8 +997,6 @@ void CodeGenSelector::VisitCallNew(CallNew* 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
if (expr->name()->Get(0) == '_' &&
CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {

6
deps/v8/src/d8.cc

@ -159,7 +159,11 @@ Handle<Value> Shell::Write(const Arguments& args) {
printf(" ");
}
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();
}

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

@ -1245,6 +1245,8 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
this.suspendRequest_(request, response);
} else if (request.command == 'version') {
this.versionRequest_(request, response);
} else if (request.command == 'profile') {
this.profileRequest_(request, response);
} else {
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
// running.
DebugCommandProcessor.prototype.isRunning = function() {

11
deps/v8/src/debug.h

@ -370,17 +370,6 @@ class Debug {
// Garbage collection notifications.
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.
static void GenerateLoadICDebugBreak(MacroAssembler* masm);
static void GenerateStoreICDebugBreak(MacroAssembler* masm);

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

@ -38,7 +38,7 @@
*/
#if !(defined(__APPLE__) && defined(__MACH__)) && \
!defined(WIN32) && !defined(__FreeBSD__)
!defined(WIN32) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
#include <endian.h>
#endif
#include <math.h>
@ -47,14 +47,16 @@
/* The floating point word order on ARM is big endian when floating point
* emulation is used, even if the byte order is little endian */
#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
#else
#define IEEE_8087
#endif
#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
* name of strtod. If it's included after strtod is redefined as
* 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_compilation_type(Smi::FromInt(Script::COMPILATION_TYPE_HOST));
script->set_wrapper(*wrapper);
script->set_line_ends_fixed_array(Heap::undefined_value());
script->set_line_ends_js_array(Heap::undefined_value());
script->set_eval_from_function(Heap::undefined_value());
script->set_line_ends(Heap::undefined_value());
script->set_eval_from_shared(Heap::undefined_value());
script->set_eval_from_instructions_offset(Smi::FromInt(0));
return script;

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

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

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

@ -56,14 +56,21 @@ class FastCodeGenerator: public AstVisitor {
private:
int SlotOffset(Slot* slot);
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(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.
// 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
// 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_int(min_preparse_length, 1024,
"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")
DEFINE_bool(trace_bailout, false,
"print reasons for failing to use fast compilation")
DEFINE_bool(always_fast_compiler, false,
"always try using the fast compiler")
// compilation-cache.cc
DEFINE_bool(compilation_cache, true, "enable compilation cache")
@ -154,9 +156,9 @@ DEFINE_bool(compilation_cache, true, "enable compilation cache")
// debug.cc
DEFINE_bool(remote_debugging, false, "enable remote debugging")
DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
DEFINE_bool(debugger_auto_break, false,
DEFINE_bool(debugger_auto_break, true,
"automatically set the debug break flag when debugger commands are "
"in the queue (experimental)")
"in the queue")
// frames.cc
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_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
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.
static int NumberOfWeakHandles() { return number_of_weak_handles_; }
static void RecordStats(HeapStats* stats);
// Returns the current number of weak handles to global objects.
// These handles are also included in NumberOfWeakHandles().
static int NumberOfGlobalObjectWeakHandles() {

40
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
// source.
void InitScriptLineEnds(Handle<Script> script) {
if (!script->line_ends_fixed_array()->IsUndefined()) return;
if (!script->line_ends()->IsUndefined()) return;
if (!script->source()->IsString()) {
ASSERT(script->source()->IsUndefined());
script->set_line_ends_fixed_array(*(Factory::NewFixedArray(0)));
ASSERT(script->line_ends_fixed_array()->IsFixedArray());
script->set_line_ends(*(Factory::NewFixedArray(0)));
ASSERT(script->line_ends()->IsFixedArray());
return;
}
@ -467,8 +467,8 @@ void InitScriptLineEnds(Handle<Script> script) {
}
ASSERT(array_index == line_count);
script->set_line_ends_fixed_array(*array);
ASSERT(script->line_ends_fixed_array()->IsFixedArray());
script->set_line_ends(*array);
ASSERT(script->line_ends()->IsFixedArray());
}
@ -477,7 +477,7 @@ int GetScriptLineNumber(Handle<Script> script, int code_pos) {
InitScriptLineEnds(script);
AssertNoAllocation no_allocation;
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();
int line = -1;
@ -548,6 +548,12 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
KeyCollectionType type) {
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.
for (Handle<Object> p = object;
@ -577,8 +583,21 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
}
// Compute the property keys.
content = UnionOfKeys(content, GetEnumPropertyKeys(current));
// We can cache the computed property keys if access checks are
// 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.
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;
if (object->HasFastProperties()) {
if (object->map()->instance_descriptors()->HasEnumCache()) {
@ -628,10 +648,12 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object) {
}
}
(*storage)->SortPairs(*sort_array, sort_array->length());
if (cache_result) {
Handle<FixedArray> bridge_storage =
Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
DescriptorArray* desc = object->map()->instance_descriptors();
desc->SetEnumCache(*bridge_storage, *storage);
}
ASSERT(storage->length() == index);
return storage;
} else {

3
deps/v8/src/handles.h

@ -277,7 +277,8 @@ enum KeyCollectionType { LOCAL_ONLY, INCLUDE_PROTOS };
Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
KeyCollectionType type);
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.
// 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,
int chars,
uint32_t length_field) {
uint32_t hash_field) {
unibrow::Utf8InputBuffer<> buffer(str.start(),
static_cast<unsigned>(str.length()));
return AllocateInternalSymbol(&buffer, chars, length_field);
return AllocateInternalSymbol(&buffer, chars, hash_field);
}

191
deps/v8/src/heap.cc

@ -1187,34 +1187,14 @@ bool Heap::CreateInitialMaps() {
roots_[entry.index] = Map::cast(obj);
}
obj = AllocateMap(SHORT_STRING_TYPE, SeqTwoByteString::kAlignedSize);
obj = AllocateMap(STRING_TYPE, SeqTwoByteString::kAlignedSize);
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();
obj = AllocateMap(MEDIUM_STRING_TYPE, SeqTwoByteString::kAlignedSize);
obj = AllocateMap(ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
if (obj->IsFailure()) return false;
set_undetectable_medium_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));
set_undetectable_ascii_string_map(Map::cast(obj));
Map::cast(obj)->set_is_undetectable();
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.
char* dest = SeqAsciiString::cast(result)->GetChars();
// 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];
// Copy second part.
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];
return result;
} else {
@ -1856,26 +1845,17 @@ Object* Heap::AllocateConsString(String* first, String* second) {
}
}
Map* 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();
}
Map* map = is_ascii ? cons_ascii_string_map() : cons_string_map();
Object* result = Allocate(map,
always_allocate() ? OLD_POINTER_SPACE : NEW_SPACE);
if (result->IsFailure()) return result;
ConsString* cons_string = ConsString::cast(result);
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_second(second, mode);
cons_string->set_length(length);
return result;
}
@ -1925,25 +1905,20 @@ Object* Heap::AllocateSubString(String* buffer,
Object* Heap::AllocateExternalStringFromAscii(
ExternalAsciiString::Resource* resource) {
Map* map;
size_t length = resource->length();
if (length <= static_cast<size_t>(String::kMaxShortSize)) {
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 {
if (length > static_cast<size_t>(String::kMaxLength)) {
Top::context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
Map* map = external_ascii_string_map();
Object* result = Allocate(map,
always_allocate() ? OLD_DATA_SPACE : NEW_SPACE);
if (result->IsFailure()) return result;
ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
external_string->set_length(static_cast<int>(length));
external_string->set_hash_field(String::kEmptyHashField);
external_string->set_resource(resource);
return result;
@ -1957,13 +1932,15 @@ Object* Heap::AllocateExternalStringFromTwoByte(
Top::context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
Map* map = ExternalTwoByteString::StringMap(static_cast<int>(length));
Map* map = Heap::external_string_map();
Object* result = Allocate(map,
always_allocate() ? OLD_DATA_SPACE : NEW_SPACE);
if (result->IsFailure()) return result;
ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
external_string->set_length(static_cast<int>(length));
external_string->set_hash_field(String::kEmptyHashField);
external_string->set_resource(resource);
return result;
@ -2604,48 +2581,12 @@ Map* Heap::SymbolMapForString(String* string) {
// Find the corresponding symbol map for strings.
Map* map = string->map();
if (map == short_ascii_string_map()) return short_ascii_symbol_map();
if (map == medium_ascii_string_map()) return medium_ascii_symbol_map();
if (map == long_ascii_string_map()) return long_ascii_symbol_map();
if (map == short_string_map()) return short_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();
}
if (map == ascii_string_map()) return ascii_symbol_map();
if (map == string_map()) return symbol_map();
if (map == cons_string_map()) return cons_symbol_map();
if (map == cons_ascii_string_map()) return cons_ascii_symbol_map();
if (map == external_string_map()) return external_symbol_map();
if (map == external_ascii_string_map()) return external_ascii_symbol_map();
// No match found.
return NULL;
@ -2654,7 +2595,7 @@ Map* Heap::SymbolMapForString(String* string) {
Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
int chars,
uint32_t length_field) {
uint32_t hash_field) {
// Ensure the chars matches the number of characters in the buffer.
ASSERT(static_cast<unsigned>(chars) == buffer->Length());
// Determine whether the string is ascii.
@ -2669,22 +2610,10 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
Map* map;
if (is_ascii) {
if (chars <= String::kMaxShortSize) {
map = short_ascii_symbol_map();
} else if (chars <= String::kMaxMediumSize) {
map = medium_ascii_symbol_map();
} else {
map = long_ascii_symbol_map();
}
map = ascii_symbol_map();
size = SeqAsciiString::SizeFor(chars);
} else {
if (chars <= String::kMaxShortSize) {
map = short_symbol_map();
} else if (chars <= String::kMaxMediumSize) {
map = medium_symbol_map();
} else {
map = long_symbol_map();
}
map = symbol_map();
size = SeqTwoByteString::SizeFor(chars);
}
@ -2695,9 +2624,10 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
if (result->IsFailure()) return result;
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);
answer->set_length_field(length_field);
answer->set_length(chars);
answer->set_hash_field(hash_field);
ASSERT_EQ(size, answer->Size());
@ -2728,19 +2658,10 @@ Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
}
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.
HeapObject::cast(result)->set_map(map);
HeapObject::cast(result)->set_map(ascii_string_map());
String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField);
ASSERT_EQ(size, HeapObject::cast(result)->Size());
return result;
}
@ -2765,19 +2686,10 @@ Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) {
}
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.
HeapObject::cast(result)->set_map(map);
HeapObject::cast(result)->set_map(string_map());
String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField);
ASSERT_EQ(size, HeapObject::cast(result)->Size());
return result;
}
@ -2998,6 +2910,11 @@ bool Heap::IdleNotification() {
last_gc_count = gc_count_;
} 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);
new_space_.Shrink();
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() {
return old_pointer_space_->Size()
+ old_data_space_->Size()

95
deps/v8/src/heap.h

@ -59,50 +59,20 @@ namespace internal {
V(Object, termination_exception, TerminationException) \
V(Map, hash_table_map, HashTableMap) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(Map, short_string_map, ShortStringMap) \
V(Map, medium_string_map, MediumStringMap) \
V(Map, long_string_map, LongStringMap) \
V(Map, short_ascii_string_map, ShortAsciiStringMap) \
V(Map, medium_ascii_string_map, MediumAsciiStringMap) \
V(Map, long_ascii_string_map, LongAsciiStringMap) \
V(Map, short_symbol_map, ShortSymbolMap) \
V(Map, medium_symbol_map, MediumSymbolMap) \
V(Map, long_symbol_map, LongSymbolMap) \
V(Map, short_ascii_symbol_map, ShortAsciiSymbolMap) \
V(Map, medium_ascii_symbol_map, MediumAsciiSymbolMap) \
V(Map, long_ascii_symbol_map, LongAsciiSymbolMap) \
V(Map, short_cons_symbol_map, ShortConsSymbolMap) \
V(Map, medium_cons_symbol_map, MediumConsSymbolMap) \
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, string_map, StringMap) \
V(Map, ascii_string_map, AsciiStringMap) \
V(Map, symbol_map, SymbolMap) \
V(Map, ascii_symbol_map, AsciiSymbolMap) \
V(Map, cons_symbol_map, ConsSymbolMap) \
V(Map, cons_ascii_symbol_map, ConsAsciiSymbolMap) \
V(Map, external_symbol_map, ExternalSymbolMap) \
V(Map, external_ascii_symbol_map, ExternalAsciiSymbolMap) \
V(Map, cons_string_map, ConsStringMap) \
V(Map, cons_ascii_string_map, ConsAsciiStringMap) \
V(Map, external_string_map, ExternalStringMap) \
V(Map, external_ascii_string_map, ExternalAsciiStringMap) \
V(Map, undetectable_string_map, UndetectableStringMap) \
V(Map, undetectable_ascii_string_map, UndetectableAsciiStringMap) \
V(Map, pixel_array_map, PixelArrayMap) \
V(Map, external_byte_array_map, ExternalByteArrayMap) \
V(Map, external_unsigned_byte_array_map, ExternalUnsignedByteArrayMap) \
@ -219,6 +189,7 @@ namespace internal {
// Forward declaration of the GCTracer class.
class GCTracer;
class HeapStats;
// 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.
static inline Object* AllocateSymbol(Vector<const char> str,
int chars,
uint32_t length_field);
uint32_t hash_field);
static Object* AllocateInternalSymbol(unibrow::CharacterStream* buffer,
int chars,
uint32_t length_field);
uint32_t hash_field);
static Object* AllocateExternalSymbol(Vector<const char> str,
int chars);
@ -895,6 +866,8 @@ class Heap : public AllStatic {
static RootListIndex RootIndexForExternalArrayType(
ExternalArrayType array_type);
static void RecordStats(HeapStats* stats);
private:
static int reserved_semispace_size_;
static int max_semispace_size_;
@ -910,7 +883,10 @@ class Heap : public AllStatic {
static int linear_allocation_scope_depth_;
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)
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 {
public:
AlwaysAllocateScope() {

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

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

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

@ -2490,7 +2490,7 @@ void CodeGenerator::GenerateReturnSequence(Result* return_value) {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Check that the size of the code used for returning matches what is
// expected by the debugger.
ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
ASSERT_EQ(Assembler::kJSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif
}
@ -3056,13 +3056,59 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
jsobject.Bind();
// Get the set of properties (as a FixedArray or Map).
// 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_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
// If we got a Map, we can do a fast modification check.
// Otherwise, we got a FixedArray, and we have to do a slow check.
// If we got a map from the runtime call, we can do a fast
// 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
// Runtime::kGetPropertyNamesFast)
__ mov(edx, Operand(eax));
@ -3070,9 +3116,13 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
__ cmp(ecx, Factory::meta_map());
fixed_array.Branch(not_equal);
use_cache.Bind();
// 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, FieldOperand(ecx, Map::kInstanceDescriptorsOffset));
// Get the bridge array held in the enumeration index field.
__ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
@ -4777,18 +4827,8 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
__ test(ecx, Immediate(kIsNotStringMask));
__ 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.
__ mov(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset));
__ shr_cl(temp.reg());
// Check for index out of range.
__ cmp(index.reg(), Operand(temp.reg()));
__ 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) {
if (CheckForInlineRuntimeCall(node)) {
return;
@ -6502,11 +6554,8 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
// String value => false iff empty.
__ cmp(ecx, FIRST_NONSTRING_TYPE);
__ 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));
__ shr(edx, String::kShortLengthShift);
__ test(edx, Operand(edx));
__ j(zero, &false_result);
__ jmp(&true_result);
@ -7042,7 +7091,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
switch (op_) {
case Token::ADD: {
// Test for string arguments before calling runtime.
Label not_strings, both_strings, not_string1, string1;
Label not_strings, not_string1, string1;
Result answer;
__ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument.
__ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument.
@ -7057,8 +7106,9 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
__ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx);
__ j(above_equal, &string1);
// First and second argument are strings.
__ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
// First and second argument are strings. Jump to the string add stub.
StringAddStub stub(NO_STRING_CHECK_IN_STUB);
__ TailCallStub(&stub);
// Only first argument is a string.
__ bind(&string1);
@ -8185,6 +8235,224 @@ int CompareStub::MinorKey() {
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 __
} } // 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 GenerateMathCos(ZoneList<Expression*>* args);
// Fast support for StringAdd.
void GenerateStringAdd(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {
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
#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
// for the precise return instructions sequence.
void BreakLocationIterator::SetDebugBreakAtReturn() {
ASSERT(Debug::kIa32JSReturnSequenceLength >=
Debug::kIa32CallInstructionLength);
ASSERT(Assembler::kJSReturnSequenceLength >=
Assembler::kCallInstructionLength);
rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(),
Debug::kIa32JSReturnSequenceLength - Debug::kIa32CallInstructionLength);
Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
}
// Restore the JS frame exit code.
void BreakLocationIterator::ClearDebugBreakAtReturn() {
rinfo()->PatchCode(original_rinfo()->pc(),
Debug::kIa32JSReturnSequenceLength);
Assembler::kJSReturnSequenceLength);
}

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

@ -74,11 +74,41 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
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();
if (arguments != NULL) {
// Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object");
if (function_in_register) {
__ push(edi);
} else {
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
}
// Receiver is just before the parameters on the caller's stack.
__ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize));
@ -90,36 +120,13 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
// stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub);
__ mov(Operand(ebp, SlotOffset(arguments->slot())), eax);
__ mov(ecx, eax); // Duplicate result.
Move(arguments->slot(), eax, ebx, edx);
Slot* dot_arguments_slot =
fun->scope()->arguments_shadow()->AsVariable()->slot();
__ mov(Operand(ebp, SlotOffset(dot_arguments_slot)), eax);
function_in_register = false;
Move(dot_arguments_slot, ecx, ebx, edx);
}
// 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");
VisitDeclarations(fun->scope()->declarations());
@ -180,7 +187,7 @@ void FastCodeGenerator::EmitReturnSequence(int position) {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Check that the size of the code used for returning matches what is
// expected by the debugger.
ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
ASSERT_EQ(Assembler::kJSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#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) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
break;
case Expression::kValue:
__ push(Operand(ebp, SlotOffset(source)));
case Expression::kValue: {
Operand location = CreateSlotOperand<Operand>(source, scratch);
__ push(location);
break;
}
case Expression::kTest: // Fall through.
case Expression::kValueTest: // Fall through.
case Expression::kTestValue:
__ mov(eax, Operand(ebp, SlotOffset(source)));
Move(context, eax);
Move(scratch, source);
Move(context, scratch);
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,
Register source) {
Register source,
int count) {
ASSERT(count > 0);
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
__ add(Operand(esp), Immediate(kPointerSize));
__ add(Operand(esp), Immediate(count * kPointerSize));
break;
case Expression::kValue:
if (count > 1) {
__ add(Operand(esp), Immediate((count - 1) * kPointerSize));
}
__ mov(Operand(esp, 0), source);
break;
case Expression::kTest:
ASSERT(!source.is(esp));
__ add(Operand(esp), Immediate(kPointerSize));
__ add(Operand(esp), Immediate(count * kPointerSize));
TestAndBranch(source, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
if (count > 1) {
__ add(Operand(esp), Immediate((count - 1) * kPointerSize));
}
__ mov(Operand(esp, 0), source);
TestAndBranch(source, true_label_, &discard);
__ bind(&discard);
@ -285,6 +363,9 @@ void FastCodeGenerator::DropAndMove(Expression::Context context,
}
case Expression::kTestValue: {
Label discard;
if (count > 1) {
__ add(Operand(esp), Immediate((count - 1) * kPointerSize));
}
__ mov(Operand(esp, 0), source);
TestAndBranch(source, &discard, false_label_);
__ bind(&discard);
@ -380,6 +461,7 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
}
__ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
// No write barrier since the_hole_value is in old space.
ASSERT(!Heap::InNewSpace(*Factory::the_hole_value()));
} else if (decl->fun() != NULL) {
Visit(decl->fun());
__ pop(eax);
@ -391,7 +473,7 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
__ Check(equal, "Unexpected declaration in current context.");
}
__ 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);
}
break;
@ -464,53 +546,61 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
DropAndMove(expr->context(), eax);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
switch (slot->type()) {
case Slot::LOCAL:
case Slot::PARAMETER: {
Comment cmnt(masm_, "Stack slot");
Move(expr->context(), slot);
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())));
Move(expr->context(), eax);
break;
}
case Slot::LOOKUP:
UNREACHABLE();
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
Move(expr->context(), slot, eax);
} else {
// The parameter variable has been rewritten into an explict access to
// the arguments object.
Comment cmnt(masm_, "Variable rewritten to Property");
// A variable has been rewritten into an explicit access to
// an object property.
Property* property = rewrite->AsProperty();
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);
}
// If result_saved == true: the result is saved on top of the stack.
// If result_saved == false: the result not on the stack, just is in eax.
// If result_saved == true: The result is saved on top of the
// stack and in eax.
// If result_saved == false: The result not on the stack, just in eax.
bool result_saved = false;
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));
__ call(ic, RelocInfo::CODE_TARGET);
// StoreIC leaves the receiver on the stack.
__ mov(eax, Operand(esp, 0)); // Restore result into eax.
break;
}
// fall through
@ -776,34 +868,34 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
// Overwrite the receiver on the stack with the result if needed.
DropAndMove(expr->context(), eax);
} else {
} else if (var->slot() != NULL) {
Slot* slot = var->slot();
ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
switch (slot->type()) {
case Slot::LOCAL:
case Slot::PARAMETER: {
Operand target = Operand(ebp, SlotOffset(var->slot()));
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
// Perform assignment and discard value.
__ pop(Operand(ebp, SlotOffset(var->slot())));
__ pop(target);
break;
case Expression::kValue:
// Perform assignment and preserve value.
__ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
__ mov(target, eax);
break;
case Expression::kTest:
// Perform assignment and test (and discard) value.
__ pop(eax);
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
__ mov(target, eax);
TestAndBranch(eax, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
__ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
__ mov(target, eax);
TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
@ -813,7 +905,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
case Expression::kTestValue: {
Label discard;
__ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
__ mov(target, eax);
TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
@ -868,6 +960,35 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
UNREACHABLE();
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) {
Comment cmnt(masm_, "[ CallRuntime");
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").
int arg_count = args->length();
@ -1138,8 +1263,20 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
ASSERT_EQ(Expression::kValue, args->at(i)->context());
}
__ CallRuntime(function, arg_count);
if (expr->is_jsruntime()) {
// 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 "runtime.h"
#include "stub-cache.h"
#include "utils.h"
namespace v8 {
namespace internal {
@ -108,7 +109,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
StringDictionary::kElementsStartIndex * kPointerSize;
for (int i = 0; i < kProbes; i++) {
// 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);
if (i > 0) {
__ 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) {
// ----------- S t a t e -------------
// -- esp[0] : return address
@ -309,7 +298,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
__ j(above_equal, &slow);
// 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));
__ j(not_zero, &index_string, not_taken);
@ -324,20 +313,16 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ mov(eax, Operand(ecx));
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0);
// Array index string: If short enough use cache in length/hash field (ebx).
// We assert that there are enough bits in an int32_t after the hash shift
// bits have been subtracted to allow space for the length and the cached
// array index.
// If the hash field contains an array index pick it out. The assert checks
// that the constants for the maximum number of digits for an array index
// cached in the hash field and the number of bits reserved for it does not
// conflict.
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
(1 << (String::kShortLengthShift - String::kHashShift)));
(1 << String::kArrayIndexValueBits));
__ bind(&index_string);
const int kLengthFieldLimit =
(String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
__ cmp(ebx, kLengthFieldLimit);
__ j(above_equal, &slow);
__ mov(eax, Operand(ebx));
__ and_(eax, (1 << String::kShortLengthShift) - 1);
__ shr(eax, String::kLongLengthShift);
__ and_(eax, String::kArrayIndexHashMask);
__ shr(eax, String::kHashShift);
__ jmp(&index_int);
}
@ -403,13 +388,13 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
__ movsx_b(eax, Operand(ecx, eax, times_1, 0));
break;
case kExternalUnsignedByteArray:
__ mov_b(eax, Operand(ecx, eax, times_1, 0));
__ movzx_b(eax, Operand(ecx, eax, times_1, 0));
break;
case kExternalShortArray:
__ movsx_w(eax, Operand(ecx, eax, times_2, 0));
break;
case kExternalUnsignedShortArray:
__ mov_w(eax, Operand(ecx, eax, times_2, 0));
__ movzx_w(eax, Operand(ecx, eax, times_2, 0));
break;
case kExternalIntArray:
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
void MacroAssembler::SaveRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
@ -680,6 +687,11 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
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_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,
Register result,
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) {
ASSERT(argc >= 1 && generating_stub());
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() {
ret(0);
}
@ -1252,11 +1393,15 @@ void MacroAssembler::Abort(const char* msg) {
RecordComment(msg);
}
#endif
// Disable stub call restrictions to always allow calls to abort.
set_allow_stub_calls(true);
push(eax);
push(Immediate(p0));
push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
CallRuntime(Runtime::kAbort, 2);
// will not return here
int3();
}

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

@ -68,6 +68,12 @@ class MacroAssembler: public Assembler {
RegList regs);
#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
@ -90,6 +96,8 @@ class MacroAssembler: public Assembler {
// argument in register esi.
void LeaveExitFrame(ExitFrame::Mode mode);
// Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length);
// ---------------------------------------------------------------------------
// JavaScript invokes
@ -175,7 +183,7 @@ class MacroAssembler: public Assembler {
// 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
// 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
// AllocateInNewSpace). If result_contains_top_on_entry is true scratch
// should be no_reg as it is never used.
@ -217,6 +225,32 @@ class MacroAssembler: public Assembler {
Register scratch2,
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.
@ -254,6 +288,9 @@ class MacroAssembler: public Assembler {
// Call a code stub.
void CallStub(CodeStub* stub);
// Tail call a code stub (jump).
void TailCallStub(CodeStub* stub);
// Return from a code stub after popping its arguments.
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);
// 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));
__ xor_(scratch, flags);
__ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
@ -135,7 +135,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
ProbeTable(masm, flags, kPrimary, name, scratch, extra);
// 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));
__ xor_(scratch, flags);
__ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
@ -234,13 +234,9 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
// scratch register.
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);
__ and_(scratch, kStringSizeMask);
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
// ecx is also the receiver.
__ lea(ecx, Operand(scratch, String::kLongLengthShift));
__ shr_cl(eax);
__ shl(eax, kSmiTagSize);
__ ret(0);

60
deps/v8/src/log.cc

@ -680,22 +680,51 @@ class CompressionHelper {
#endif // ENABLE_LOGGING_AND_PROFILING
void Logger::CallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::CallbackEventInternal(const char* prefix, const char* name,
Address entry_point) {
if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.Append("%s,%s,",
log_events_[CODE_CREATION_EVENT], log_events_[CALLBACK_TAG]);
msg.AppendAddress(entry_point);
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append(",1,\"%s\"", *str);
msg.Append(",1,\"%s%s\"", prefix, name);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n');
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
}
@ -1098,6 +1127,7 @@ void Logger::ResumeProfiler(int flags) {
LOG(UncheckedStringEvent("profiler", "resume"));
FLAG_log_code = true;
LogCompiledFunctions();
LogAccessorCallbacks();
if (!FLAG_sliding_state_window) ticker_->Start();
}
profiler_->resume();
@ -1242,6 +1272,28 @@ void Logger::LogCompiledFunctions() {
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

9
deps/v8/src/log.h

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

65
deps/v8/src/messages.js

@ -238,14 +238,15 @@ function MakeError(type, args) {
Script.prototype.lineFromPosition = function(position) {
var lower = 0;
var upper = this.lineCount() - 1;
var line_ends = this.line_ends;
// We'll never find invalid positions so bail right away.
if (position > this.line_ends[upper]) {
if (position > line_ends[upper]) {
return -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;
}
@ -253,9 +254,9 @@ Script.prototype.lineFromPosition = function(position) {
while (upper >= 1) {
var i = (lower + upper) >> 1;
if (position > this.line_ends[i]) {
if (position > line_ends[i]) {
lower = i + 1;
} else if (position <= this.line_ends[i - 1]) {
} else if (position <= line_ends[i - 1]) {
upper = i - 1;
} else {
return i;
@ -278,8 +279,9 @@ Script.prototype.locationFromPosition = function (position,
if (line == -1) return null;
// Determine start, end and column.
var start = line == 0 ? 0 : this.line_ends[line - 1] + 1;
var end = this.line_ends[line];
var line_ends = this.line_ends;
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--;
var column = position - start;
@ -368,8 +370,9 @@ Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
return null;
}
var from_position = from_line == 0 ? 0 : this.line_ends[from_line - 1] + 1;
var to_position = to_line == 0 ? 0 : this.line_ends[to_line - 1] + 1;
var line_ends = this.line_ends;
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 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.
var start = line == 0 ? 0 : this.line_ends[line - 1] + 1;
var end = this.line_ends[line];
var line_ends = this.line_ends;
var start = line == 0 ? 0 : line_ends[line - 1] + 1;
var end = line_ends[line];
return StringSubstring.call(this.source, start, end);
}
@ -625,10 +629,7 @@ CallSite.prototype.isEval = function () {
CallSite.prototype.getEvalOrigin = function () {
var script = %FunctionGetScript(this.fun);
if (!script || script.compilation_type != 1)
return null;
return new CallSite(null, script.eval_from_function,
script.eval_from_position);
return FormatEvalOrigin(script);
};
CallSite.prototype.getFunction = function () {
@ -696,7 +697,7 @@ CallSite.prototype.getColumnNumber = function () {
if (script) {
location = script.locationFromPosition(this.pos, true);
}
return location ? location.column : null;
return location ? location.column + 1: null;
};
CallSite.prototype.isNative = function () {
@ -715,12 +716,44 @@ CallSite.prototype.isConstructor = function () {
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) {
var fileLocation = "";
if (frame.isNative()) {
fileLocation = "native";
} else if (frame.isEval()) {
fileLocation = "eval at " + FormatSourcePosition(frame.getEvalOrigin());
fileLocation = "eval at " + frame.getEvalOrigin();
} else {
var fileName = frame.getFileName();
if (fileName) {

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

@ -1793,16 +1793,21 @@ ScriptMirror.prototype.context = function() {
};
ScriptMirror.prototype.evalFromFunction = function() {
return MakeMirror(this.script_.eval_from_function);
ScriptMirror.prototype.evalFromScript = function() {
return MakeMirror(this.script_.eval_from_script);
};
ScriptMirror.prototype.evalFromFunctionName = function() {
return MakeMirror(this.script_.eval_from_function_name);
};
ScriptMirror.prototype.evalFromLocation = function() {
var eval_from_function = this.evalFromFunction();
if (!eval_from_function.isUndefined()) {
var position = this.script_.eval_from_position;
return eval_from_function.script().locationFromPosition(position, true);
var eval_from_script = this.evalFromScript();
if (!eval_from_script.isUndefined()) {
var position = this.script_.eval_from_script_position;
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
// eval was called if a script is present.
if (mirror.compilationType() == 1 &&
mirror.evalFromFunction().script()) {
mirror.evalFromScript()) {
content.evalFromScript =
this.serializeReference(mirror.evalFromFunction().script());
this.serializeReference(mirror.evalFromScript());
var evalFromLocation = mirror.evalFromLocation()
content.evalFromLocation = { line: evalFromLocation.line,
column: evalFromLocation.column}
if (mirror.evalFromFunctionName()) {
content.evalFromFunctionName = mirror.evalFromFunctionName();
}
}
if (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 MAP_TYPE: return "MAP";
case HEAP_NUMBER_TYPE: return "HEAP_NUMBER";
case SHORT_SYMBOL_TYPE:
case MEDIUM_SYMBOL_TYPE:
case LONG_SYMBOL_TYPE: return "SYMBOL";
case SHORT_ASCII_SYMBOL_TYPE:
case MEDIUM_ASCII_SYMBOL_TYPE:
case LONG_ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
case SHORT_CONS_SYMBOL_TYPE:
case MEDIUM_CONS_SYMBOL_TYPE:
case LONG_CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
case SHORT_CONS_ASCII_SYMBOL_TYPE:
case MEDIUM_CONS_ASCII_SYMBOL_TYPE:
case LONG_CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL";
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 SYMBOL_TYPE: return "SYMBOL";
case ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
case CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
case CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL";
case EXTERNAL_ASCII_SYMBOL_TYPE:
case EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL";
case ASCII_STRING_TYPE: return "ASCII_STRING";
case STRING_TYPE: return "TWO_BYTE_STRING";
case CONS_STRING_TYPE:
case CONS_ASCII_STRING_TYPE: return "CONS_STRING";
case EXTERNAL_ASCII_STRING_TYPE:
case EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY";
@ -1140,8 +1116,7 @@ void Script::ScriptVerify() {
VerifyPointer(data());
VerifyPointer(wrapper());
type()->SmiVerify();
VerifyPointer(line_ends_fixed_array());
VerifyPointer(line_ends_js_array());
VerifyPointer(line_ends());
VerifyPointer(id());
}
@ -1160,6 +1135,20 @@ void Script::ScriptPrint() {
type()->ShortPrint();
PrintF("\n - id: ");
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");
}

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

@ -280,11 +280,6 @@ STATIC_CHECK((kStringRepresentationMask | kStringEncodingMask) ==
Internals::kFullStringRepresentationMask);
uint32_t StringShape::size_tag() {
return (type_ & kStringSizeMask);
}
bool StringShape::IsSequentialAscii() {
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() {
return (value_ & kMarkingMask) == 0;
}
@ -1635,44 +1611,25 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
INT_ACCESSORS(Array, length, kLengthOffset)
bool String::Equals(String* other) {
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);
INT_ACCESSORS(String, length, 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) {
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
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_hash_field(uint32_t value) {
WRITE_UINT32_FIELD(this, kHashFieldOffset, value);
}
void String::set_length_field(uint32_t value) {
WRITE_UINT32_FIELD(this, kLengthOffset, value);
bool String::Equals(String* other) {
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) {
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);
}
int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
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);
}
@ -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() {
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) {
ASSERT(index >= 0 && index < this->length());
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, type, Smi, kTypeOffset)
ACCESSORS(Script, compilation_type, Smi, kCompilationTypeOffset)
ACCESSORS(Script, line_ends_fixed_array, Object, kLineEndsFixedArrayOffset)
ACCESSORS(Script, line_ends_js_array, Object, kLineEndsJSArrayOffset)
ACCESSORS(Script, eval_from_function, Object, kEvalFromFunctionOffset)
ACCESSORS(Script, line_ends, Object, kLineEndsOffset)
ACCESSORS(Script, eval_from_shared, Object, kEvalFromSharedOffset)
ACCESSORS(Script, eval_from_instructions_offset, Smi,
kEvalFrominstructionsOffsetOffset)
@ -2900,13 +2782,13 @@ NumberDictionary* JSObject::element_dictionary() {
bool String::HasHashCode() {
return (length_field() & kHashComputedMask) != 0;
return (hash_field() & kHashComputedMask) != 0;
}
uint32_t String::Hash() {
// Fast case: has hash code already been computed?
uint32_t field = length_field();
uint32_t field = hash_field();
if (field & kHashComputedMask) return field >> kHashShift;
// Slow case: compute hash code and set it.
return ComputeAndSetHash();
@ -2923,7 +2805,7 @@ StringHasher::StringHasher(int length)
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) {
uint32_t field = length_field();
uint32_t field = hash_field();
if ((field & kHashComputedMask) && !(field & kIsArrayIndexMask)) return false;
return SlowAsArrayIndex(index);
}

130
deps/v8/src/objects.cc

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

382
deps/v8/src/objects.h

@ -222,43 +222,19 @@ enum PropertyNormalizationMode {
// JSObject for GC purposes. The first four entries here have typeof
// 'object', whereas JS_FUNCTION_TYPE has typeof 'function'.
#define INSTANCE_TYPE_LIST_ALL(V) \
V(SHORT_SYMBOL_TYPE) \
V(MEDIUM_SYMBOL_TYPE) \
V(LONG_SYMBOL_TYPE) \
V(SHORT_ASCII_SYMBOL_TYPE) \
V(MEDIUM_ASCII_SYMBOL_TYPE) \
V(LONG_ASCII_SYMBOL_TYPE) \
V(SHORT_CONS_SYMBOL_TYPE) \
V(MEDIUM_CONS_SYMBOL_TYPE) \
V(LONG_CONS_SYMBOL_TYPE) \
V(SHORT_CONS_ASCII_SYMBOL_TYPE) \
V(MEDIUM_CONS_ASCII_SYMBOL_TYPE) \
V(LONG_CONS_ASCII_SYMBOL_TYPE) \
V(SHORT_EXTERNAL_SYMBOL_TYPE) \
V(MEDIUM_EXTERNAL_SYMBOL_TYPE) \
V(LONG_EXTERNAL_SYMBOL_TYPE) \
V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE) \
V(MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE) \
V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE) \
V(SHORT_STRING_TYPE) \
V(MEDIUM_STRING_TYPE) \
V(LONG_STRING_TYPE) \
V(SHORT_ASCII_STRING_TYPE) \
V(MEDIUM_ASCII_STRING_TYPE) \
V(LONG_ASCII_STRING_TYPE) \
V(SHORT_CONS_STRING_TYPE) \
V(MEDIUM_CONS_STRING_TYPE) \
V(LONG_CONS_STRING_TYPE) \
V(SHORT_CONS_ASCII_STRING_TYPE) \
V(MEDIUM_CONS_ASCII_STRING_TYPE) \
V(LONG_CONS_ASCII_STRING_TYPE) \
V(SHORT_EXTERNAL_STRING_TYPE) \
V(MEDIUM_EXTERNAL_STRING_TYPE) \
V(LONG_EXTERNAL_STRING_TYPE) \
V(SHORT_EXTERNAL_ASCII_STRING_TYPE) \
V(MEDIUM_EXTERNAL_ASCII_STRING_TYPE) \
V(LONG_EXTERNAL_ASCII_STRING_TYPE) \
V(LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE) \
V(SYMBOL_TYPE) \
V(ASCII_SYMBOL_TYPE) \
V(CONS_SYMBOL_TYPE) \
V(CONS_ASCII_SYMBOL_TYPE) \
V(EXTERNAL_SYMBOL_TYPE) \
V(EXTERNAL_ASCII_SYMBOL_TYPE) \
V(STRING_TYPE) \
V(ASCII_STRING_TYPE) \
V(CONS_STRING_TYPE) \
V(CONS_ASCII_STRING_TYPE) \
V(EXTERNAL_STRING_TYPE) \
V(EXTERNAL_ASCII_STRING_TYPE) \
V(PRIVATE_EXTERNAL_ASCII_STRING_TYPE) \
\
V(MAP_TYPE) \
V(HEAP_NUMBER_TYPE) \
@ -319,150 +295,54 @@ enum PropertyNormalizationMode {
// Since string types are not consecutive, this macro is used to
// iterate over them.
#define STRING_TYPE_LIST(V) \
V(SHORT_SYMBOL_TYPE, \
V(SYMBOL_TYPE, \
SeqTwoByteString::kAlignedSize, \
short_symbol, \
ShortSymbol) \
V(MEDIUM_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, \
symbol, \
Symbol) \
V(ASCII_SYMBOL_TYPE, \
SeqAsciiString::kAlignedSize, \
medium_ascii_symbol, \
MediumAsciiSymbol) \
V(LONG_ASCII_SYMBOL_TYPE, \
SeqAsciiString::kAlignedSize, \
long_ascii_symbol, \
LongAsciiSymbol) \
V(SHORT_CONS_SYMBOL_TYPE, \
ConsString::kSize, \
short_cons_symbol, \
ShortConsSymbol) \
V(MEDIUM_CONS_SYMBOL_TYPE, \
ascii_symbol, \
AsciiSymbol) \
V(CONS_SYMBOL_TYPE, \
ConsString::kSize, \
medium_cons_symbol, \
MediumConsSymbol) \
V(LONG_CONS_SYMBOL_TYPE, \
cons_symbol, \
ConsSymbol) \
V(CONS_ASCII_SYMBOL_TYPE, \
ConsString::kSize, \
long_cons_symbol, \
LongConsSymbol) \
V(SHORT_CONS_ASCII_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, \
cons_ascii_symbol, \
ConsAsciiSymbol) \
V(EXTERNAL_SYMBOL_TYPE, \
ExternalTwoByteString::kSize, \
medium_external_symbol, \
MediumExternalSymbol) \
V(LONG_EXTERNAL_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, \
external_symbol, \
ExternalSymbol) \
V(EXTERNAL_ASCII_SYMBOL_TYPE, \
ExternalAsciiString::kSize, \
medium_external_ascii_symbol, \
MediumExternalAsciiSymbol) \
V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE, \
ExternalAsciiString::kSize, \
long_external_ascii_symbol, \
LongExternalAsciiSymbol) \
V(SHORT_STRING_TYPE, \
SeqTwoByteString::kAlignedSize, \
short_string, \
ShortString) \
V(MEDIUM_STRING_TYPE, \
external_ascii_symbol, \
ExternalAsciiSymbol) \
V(STRING_TYPE, \
SeqTwoByteString::kAlignedSize, \
medium_string, \
MediumString) \
V(LONG_STRING_TYPE, \
SeqTwoByteString::kAlignedSize, \
long_string, \
LongString) \
V(SHORT_ASCII_STRING_TYPE, \
SeqAsciiString::kAlignedSize, \
short_ascii_string, \
ShortAsciiString) \
V(MEDIUM_ASCII_STRING_TYPE, \
string, \
String) \
V(ASCII_STRING_TYPE, \
SeqAsciiString::kAlignedSize, \
medium_ascii_string, \
MediumAsciiString) \
V(LONG_ASCII_STRING_TYPE, \
SeqAsciiString::kAlignedSize, \
long_ascii_string, \
LongAsciiString) \
V(SHORT_CONS_STRING_TYPE, \
ConsString::kSize, \
short_cons_string, \
ShortConsString) \
V(MEDIUM_CONS_STRING_TYPE, \
ascii_string, \
AsciiString) \
V(CONS_STRING_TYPE, \
ConsString::kSize, \
medium_cons_string, \
MediumConsString) \
V(LONG_CONS_STRING_TYPE, \
cons_string, \
ConsString) \
V(CONS_ASCII_STRING_TYPE, \
ConsString::kSize, \
long_cons_string, \
LongConsString) \
V(SHORT_CONS_ASCII_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, \
cons_ascii_string, \
ConsAsciiString) \
V(EXTERNAL_STRING_TYPE, \
ExternalTwoByteString::kSize, \
long_external_string, \
LongExternalString) \
V(SHORT_EXTERNAL_ASCII_STRING_TYPE, \
external_string, \
ExternalString) \
V(EXTERNAL_ASCII_STRING_TYPE, \
ExternalAsciiString::kSize, \
short_external_ascii_string, \
ShortExternalAsciiString) \
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)
external_ascii_string, \
ExternalAsciiString) \
// 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
@ -509,15 +389,6 @@ const uint32_t kIsSymbolMask = 0x20;
const uint32_t kNotSymbolTag = 0x0;
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
// two-byte characters or one-byte characters.
const uint32_t kStringEncodingMask = 0x4;
@ -547,60 +418,20 @@ const uint32_t kShortcutTypeTag = kConsStringTag;
enum InstanceType {
SHORT_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSeqStringTag,
MEDIUM_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSeqStringTag,
LONG_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSeqStringTag,
SHORT_ASCII_SYMBOL_TYPE =
kShortStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
MEDIUM_ASCII_SYMBOL_TYPE =
kMediumStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
LONG_ASCII_SYMBOL_TYPE =
kLongStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
SHORT_CONS_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kConsStringTag,
MEDIUM_CONS_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kConsStringTag,
LONG_CONS_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kConsStringTag,
SHORT_CONS_ASCII_SYMBOL_TYPE =
kShortStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
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,
SYMBOL_TYPE = kSymbolTag | kSeqStringTag,
ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kSeqStringTag,
CONS_SYMBOL_TYPE = kSymbolTag | kConsStringTag,
CONS_ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kConsStringTag,
EXTERNAL_SYMBOL_TYPE = kSymbolTag | kExternalStringTag,
EXTERNAL_ASCII_SYMBOL_TYPE =
kAsciiStringTag | kSymbolTag | kExternalStringTag,
STRING_TYPE = kSeqStringTag,
ASCII_STRING_TYPE = kAsciiStringTag | kSeqStringTag,
CONS_STRING_TYPE = kConsStringTag,
CONS_ASCII_STRING_TYPE = kAsciiStringTag | kConsStringTag,
EXTERNAL_STRING_TYPE = kExternalStringTag,
EXTERNAL_ASCII_STRING_TYPE = kAsciiStringTag | kExternalStringTag,
PRIVATE_EXTERNAL_ASCII_STRING_TYPE = EXTERNAL_ASCII_STRING_TYPE,
MAP_TYPE = kNotStringTag,
HEAP_NUMBER_TYPE,
@ -999,16 +830,6 @@ class MapWord BASE_EMBEDDED {
// View this map word as a forwarding address.
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
// 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
@ -3182,14 +3003,11 @@ class Script: public Struct {
DECL_ACCESSORS(compilation_type, Smi)
// [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.
DECL_ACCESSORS(line_ends_js_array, Object)
// [eval_from_function]: for eval scripts the funcion from which eval was
// called.
DECL_ACCESSORS(eval_from_function, Object)
// [eval_from_shared]: for eval scripts the shared funcion info for the
// function from which eval was called.
DECL_ACCESSORS(eval_from_shared, Object)
// [eval_from_instructions_offset]: the instruction offset in the code for the
// 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 kTypeOffset = kWrapperOffset + kPointerSize;
static const int kCompilationTypeOffset = kTypeOffset + kPointerSize;
// We have the line ends array both in FixedArray form and in JSArray form.
// The FixedArray form is useful when we don't have a context and so can't
// create a JSArray. The JSArray form is useful when we want to see the
// 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 kLineEndsOffset = kCompilationTypeOffset + kPointerSize;
static const int kIdOffset = kLineEndsOffset + kPointerSize;
static const int kEvalFromSharedOffset = kIdOffset + kPointerSize;
static const int kEvalFrominstructionsOffsetOffset =
kEvalFromFunctionOffset + kPointerSize;
kEvalFromSharedOffset + kPointerSize;
static const int kSize = kEvalFrominstructionsOffsetOffset + kPointerSize;
private:
@ -3910,12 +3720,9 @@ class String: public HeapObject {
inline int length();
inline void set_length(int value);
// Get and set the uninterpreted length field of the string. Notice
// that the length field is also used to cache the hash value of
// strings. In order to get or set the actual length of the string
// use the length() and set_length methods.
inline uint32_t length_field();
inline void set_length_field(uint32_t value);
// Get and set the hash field of the string.
inline uint32_t hash_field();
inline void set_hash_field(uint32_t value);
inline bool IsAsciiRepresentation();
inline bool IsTwoByteRepresentation();
@ -3986,7 +3793,7 @@ class String: public HeapObject {
// Returns a hash value used for the property table
inline uint32_t Hash();
static uint32_t ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
static uint32_t ComputeHashField(unibrow::CharacterStream* buffer,
int length);
static bool ComputeArrayIndex(unibrow::CharacterStream* buffer,
@ -4018,7 +3825,8 @@ class String: public HeapObject {
// Layout description.
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.
// 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 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
// field.
static const int kMaxCachedArrayIndexLength = 7;
// Shift constants for retrieving length and hash code from
// length/hash field.
static const int kHashShift = kNofLengthBitFields;
static const int kShortLengthShift = kHashShift + kShortStringTag;
static const int kMediumLengthShift = kHashShift + kMediumStringTag;
static const int kLongLengthShift = kHashShift + kLongStringTag;
// For strings which are array indexes the hash value has the string length
// mixed into the hash, mainly to avoid a hash value of zero which would be
// the case for the string '0'. 24 bits are used for the array index value.
static const int kArrayIndexHashLengthShift = 24 + kNofLengthBitFields;
static const int kArrayIndexHashMask = (1 << kArrayIndexHashLengthShift) - 1;
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
// different types of strings.
static const int kMaxShortSize = (1 << (32 - kShortLengthShift)) - 1;
static const int kMaxMediumSize = (1 << (32 - kMediumLengthShift)) - 1;
static const int kMaxLength = (1 << (32 - kLongLengthShift)) - 1;
// Max length for computing hash. For strings longer than this limit the
// string length is used as the hash value.
static const int kMaxHashCalcLength = 16383;
// Limit for truncation in short printing.
static const int kMaxShortPrintLength = 1024;
@ -4339,9 +4155,6 @@ class ExternalAsciiString: public ExternalString {
unsigned* offset,
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:
DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalAsciiString);
};
@ -4374,9 +4187,6 @@ class ExternalTwoByteString: public ExternalString {
unsigned* offset_ptr,
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:
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() {
// 16 byte alignment on FreeBSD
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__
bool OS::ArmCpuHasFeature(CpuFeature feature) {
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() {
// OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI
// 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
// 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 <errno.h>
@ -61,6 +61,13 @@ double modulo(double x, double 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.
//

78
deps/v8/src/runtime.cc

@ -788,19 +788,18 @@ static Object* Runtime_InitializeVarGlobal(Arguments args) {
// case of callbacks in the prototype chain (this rules out using
// SetProperty). We have IgnoreAttributesAndSetLocalProperty for
// 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;
global->LocalLookup(*name, &lookup);
if (!lookup.IsProperty()) {
if (assign) {
return global->IgnoreAttributesAndSetLocalProperty(*name,
args[1],
attributes);
}
return Heap::undefined_value();
}
while (true) {
real_holder->LocalLookup(*name, &lookup);
if (lookup.IsProperty()) {
// Determine if this is a redeclaration of something read-only.
if (lookup.IsReadOnly()) {
// If we found readonly property on one of hidden prototypes,
// just shadow it.
if (real_holder != Top::context()->global()) break;
return ThrowRedeclarationError("const", name);
}
@ -809,7 +808,10 @@ static Object* Runtime_InitializeVarGlobal(Arguments args) {
bool found = true;
PropertyType type = lookup.type();
if (type == INTERCEPTOR) {
PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
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.
@ -817,11 +819,11 @@ static Object* Runtime_InitializeVarGlobal(Arguments args) {
} 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.
// 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);
}
// Restore global object from context (in case of GC).
global = Top::context()->global();
}
if (found && !assign) {
@ -832,7 +834,26 @@ static Object* Runtime_InitializeVarGlobal(Arguments args) {
// Assign the value (or undefined) to the property.
Object* value = (assign) ? args[1] : Heap::undefined_value();
return global->SetProperty(&lookup, *name, value, attributes);
return real_holder->SetProperty(&lookup, *name, value, attributes);
}
Object* proto = real_holder->GetPrototype();
if (!proto->IsJSObject())
break;
if (!JSObject::cast(proto)->map()->is_hidden_prototype())
break;
real_holder = JSObject::cast(proto);
}
global = Top::context()->global();
if (assign) {
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);
CONVERT_CHECKED(String, str1, args[0]);
CONVERT_CHECKED(String, str2, args[1]);
Counters::string_add_runtime.Increment();
return Heap::AllocateConsString(str1, str2);
}
@ -4987,6 +5009,9 @@ static Object* Runtime_DebugPrint(Arguments args) {
PrintF("DebugPrint: ");
}
args[0]->Print();
if (args[0]->IsHeapObject()) {
HeapObject::cast(args[0])->map()->Print();
}
#else
// ShortPrint is available in release mode. Print is not.
args[0]->ShortPrint();
@ -7667,8 +7692,31 @@ static Object* Runtime_FunctionGetInferredName(Arguments args) {
CONVERT_CHECKED(JSFunction, f, args[0]);
return f->shared()->inferred_name();
}
#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
// 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)
#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
#define RUNTIME_FUNCTION_LIST_DEBUG(F) \
/* Testing */ \
@ -336,7 +344,8 @@ namespace internal {
RUNTIME_FUNCTION_LIST_ALWAYS_1(F) \
RUNTIME_FUNCTION_LIST_ALWAYS_2(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.

10
deps/v8/src/runtime.js

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

87
deps/v8/src/serialize.cc

@ -44,6 +44,69 @@
namespace v8 {
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.
@ -871,6 +934,7 @@ void Serializer::Serialize() {
Heap::IterateRoots(this, VISIT_ONLY_STRONG);
delete external_reference_encoder_;
external_reference_encoder_ = NULL;
SerializationAddressMapper::Zap();
}
@ -894,10 +958,9 @@ void Serializer::SerializeObject(
ReferenceRepresentation reference_representation) {
CHECK(o->IsHeapObject());
HeapObject* heap_object = HeapObject::cast(o);
MapWord map_word = heap_object->map_word();
if (map_word.IsSerializationAddress()) {
if (SerializationAddressMapper::IsMapped(heap_object)) {
int space = SpaceOfAlreadySerializedObject(heap_object);
int address = map_word.ToSerializationAddress();
int address = SerializationAddressMapper::MappedTo(heap_object);
int offset = CurrentAllocationAddress(space) - address;
bool from_start = true;
if (SpaceIsPaged(space)) {
@ -965,24 +1028,23 @@ void Serializer::ObjectSerializer::Serialize() {
}
sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
// Get the map before overwriting it.
Map* map = object_->map();
// Mark this object as already serialized.
bool start_new_page;
object_->set_map_word(MapWord::FromSerializationAddress(
serializer_->Allocate(space, size, &start_new_page)));
SerializationAddressMapper::Map(
object_,
serializer_->Allocate(space, size, &start_new_page));
if (start_new_page) {
sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage");
sink_->PutSection(space, "NewPageSpace");
}
// 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.
CHECK_EQ(0, bytes_processed_so_far_);
bytes_processed_so_far_ = kPointerSize;
object_->IterateBody(map->instance_type(), size, this);
object_->IterateBody(object_->map()->instance_type(), size, this);
OutputRawData(object_->address() + size);
}
@ -1044,12 +1106,9 @@ void Serializer::ObjectSerializer::VisitExternalAsciiString(
Address references_start = reinterpret_cast<Address>(resource_pointer);
OutputRawData(references_start);
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
// Use raw_unchecked when maps are munged.
Object* source = Heap::raw_unchecked_natives_source_cache()->get(i);
Object* source = Heap::natives_source_cache()->get(i);
if (!source->IsUndefined()) {
// Don't use cast when maps are munged.
ExternalAsciiString* string =
reinterpret_cast<ExternalAsciiString*>(source);
ExternalAsciiString* string = ExternalAsciiString::cast(source);
typedef v8::String::ExternalAsciiStringResource Resource;
Resource* resource = string->resource();
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) {
o->ShortPrint(this);
if (o->IsString()) {
if (String::cast(o)->length() <= String::kMaxMediumSize) {
if (String::cast(o)->length() <= String::kMaxShortPrintLength) {
return;
}
} else if (o->IsNumber() || o->IsOddball()) {

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

@ -750,6 +750,9 @@ Object* LoadCallbackProperty(Arguments args) {
{
// Leaving JavaScript.
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);
}
RETURN_IF_SCHEDULED_EXCEPTION();
@ -773,6 +776,9 @@ Object* StoreCallbackProperty(Arguments args) {
{
// Leaving JavaScript.
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);
}
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
// code.
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());
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
// risk of collision even if the heap is spread over an area larger than
// 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();
}
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

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
#endif // V8_UTILS_H_

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

@ -153,8 +153,9 @@ namespace internal {
SC(zone_segment_bytes, V8.ZoneSegmentBytes) \
SC(compute_entry_frame, V8.ComputeEntryFrame) \
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.
class Counters : AllStatic {

2
deps/v8/src/version.cc

@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 0
#define BUILD_NUMBER 2
#define BUILD_NUMBER 3
#define PATCH_LEVEL 0
#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;
// TODO(X64): Rename this, removing the "Real", after changing the above.
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
//

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.
// frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k"
// 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) {
masm_->int3();
}
// Check that the size of the code used for returning matches what is
// expected by the debugger.
ASSERT_EQ(Debug::kX64JSReturnSequenceLength,
ASSERT_EQ(Assembler::kJSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif
DeleteFrame();
@ -1662,8 +1662,54 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
jsobject.Bind();
// Get the set of properties (as a FixedArray or Map).
// 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_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
@ -1676,8 +1722,11 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
__ CompareRoot(rcx, Heap::kMetaMapRootIndex);
fixed_array.Branch(not_equal);
use_cache.Bind();
// 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, FieldOperand(rcx, Map::kInstanceDescriptorsOffset));
// Get the bridge array held in the enumeration index field.
@ -3767,20 +3816,8 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
__ testb(rcx, Immediate(kIsNotStringMask));
__ 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.
__ cmpl(index.reg(), temp.reg());
__ cmpl(index.reg(), FieldOperand(object.reg(), String::kLengthOffset));
__ j(greater_equal, &slow_case);
// Reload the instance type (into the temp register this time)..
__ 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) {
ASSERT(args->length() == 1);
JumpTarget leave, null, function, non_function_constructor;
@ -6175,11 +6223,8 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
// String value => false iff empty.
__ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE));
__ 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));
__ shr(rdx, Immediate(String::kShortLengthShift));
__ testl(rdx, rdx);
__ j(zero, &false_result);
__ jmp(&true_result);
@ -7732,9 +7777,47 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
__ push(rcx);
}
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);
break;
}
case Token::SUB:
__ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
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 GenerateMathCos(ZoneList<Expression*>* args);
// Fast support for StringAdd.
void GenerateStringAdd(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {
ALWAYS_TRUE,

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

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

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

@ -76,11 +76,43 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
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();
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");
if (function_in_register) {
__ push(rdi);
} else {
__ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
}
// The receiver is just before the parameters on the caller's stack.
__ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
fun->num_parameters() * kPointerSize));
@ -93,34 +125,11 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub);
// 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 =
fun->scope()->arguments_shadow()->AsVariable()->slot();
__ movq(Operand(rbp, SlotOffset(dot_arguments_slot)), rax);
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
Move(dot_arguments_slot, rcx, rbx, rdx);
}
{ 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
// have just generated "movq rsp, rbp; pop rbp; ret k" 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) {
masm_->int3();
}
// Check that the size of the code used for returning matches what is
// expected by the debugger.
ASSERT_EQ(Debug::kX64JSReturnSequenceLength,
ASSERT_EQ(Assembler::kJSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#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) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
break;
case Expression::kValue:
__ push(Operand(rbp, SlotOffset(source)));
case Expression::kValue: {
Operand location = CreateSlotOperand<Operand>(source, scratch);
__ push(location);
break;
}
case Expression::kTest: // Fall through.
case Expression::kValueTest: // Fall through.
case Expression::kTestValue:
__ movq(rax, Operand(rbp, SlotOffset(source)));
Move(context, rax);
Move(scratch, source);
Move(context, scratch);
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,
Register source) {
Register source,
int drop_count) {
ASSERT(drop_count > 0);
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
__ addq(rsp, Immediate(kPointerSize));
__ addq(rsp, Immediate(drop_count * kPointerSize));
break;
case Expression::kValue:
if (drop_count > 1) {
__ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
}
__ movq(Operand(rsp, 0), source);
break;
case Expression::kTest:
ASSERT(!source.is(rsp));
__ addq(rsp, Immediate(kPointerSize));
__ addq(rsp, Immediate(drop_count * kPointerSize));
TestAndBranch(source, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
if (drop_count > 1) {
__ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
}
__ movq(Operand(rsp, 0), source);
TestAndBranch(source, true_label_, &discard);
__ bind(&discard);
@ -382,26 +462,26 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
__ Move(rax, Factory::the_hole_value());
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ movq(rbx, CodeGenerator::ContextOperand(
rsi, Context::FCONTEXT_INDEX));
__ movq(rbx, CodeGenerator::ContextOperand(rsi,
Context::FCONTEXT_INDEX));
__ cmpq(rbx, rsi);
__ Check(equal, "Unexpected declaration in current context.");
}
__ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
// 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) {
Visit(decl->fun());
__ pop(rax);
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ movq(rbx, CodeGenerator::ContextOperand(
rsi, Context::FCONTEXT_INDEX));
__ movq(rbx, CodeGenerator::ContextOperand(rsi,
Context::FCONTEXT_INDEX));
__ cmpq(rbx, rsi);
__ Check(equal, "Unexpected declaration in current context.");
}
__ 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);
}
break;
@ -473,53 +553,59 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
DropAndMove(expr->context(), rax);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
switch (slot->type()) {
case Slot::LOCAL:
case Slot::PARAMETER: {
Comment cmnt(masm_, "Stack slot");
Move(expr->context(), slot);
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())));
Move(expr->context(), rax);
break;
}
case Slot::LOOKUP:
UNREACHABLE();
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
Move(expr->context(), slot, rax);
} else {
// The parameter variable has been rewritten into an explict access to
// the arguments object.
// A variable has been rewritten into an explicit access to
// an object property.
Property* property = rewrite->AsProperty();
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);
}
// If result_saved == true: the result is saved on top of the stack.
// If result_saved == false: the result is not on the stack, just in rax.
// If result_saved == true: The result is saved on top of the
// stack and in rax.
// If result_saved == false: The result not on the stack, just in rax.
bool result_saved = false;
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));
__ call(ic, RelocInfo::CODE_TARGET);
// StoreIC leaves the receiver on the stack.
__ movq(rax, Operand(rsp, 0)); // Restore result back into rax.
break;
}
// fall through
@ -781,7 +869,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
// Overwrite the global object on the stack with the result if needed.
DropAndMove(expr->context(), rax);
} else {
} else if (var->slot()) {
Slot* slot = var->slot();
ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
switch (slot->type()) {
@ -873,6 +961,36 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
UNREACHABLE();
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());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// 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.
__ nop();
// Notice: We must not have a "test rax, ..." instruction after
// the call. It is treated specially by the LoadIC code.
// Drop key left on the stack by IC.
__ addq(rsp, Immediate(kPointerSize));
}
@ -1054,7 +1172,7 @@ void FastCodeGenerator::VisitCall(Call* expr) {
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ 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.
__ nop();
// Drop key left on the stack by IC.
@ -1134,9 +1252,13 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) {
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Comment cmnt(masm_, "[ CallRuntime");
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").
int arg_count = args->length();
@ -1145,8 +1267,19 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
ASSERT_EQ(Expression::kValue, args->at(i)->context());
}
__ CallRuntime(function, arg_count);
if (expr->is_jsruntime()) {
// 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) {

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

@ -31,6 +31,7 @@
#include "ic-inl.h"
#include "runtime.h"
#include "stub-cache.h"
#include "utils.h"
namespace v8 {
namespace internal {
@ -107,7 +108,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
StringDictionary::kElementsStartIndex * kPointerSize;
for (int i = 0; i < kProbes; i++) {
// 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));
if (i > 0) {
__ 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) {
// ----------- S t a t e -------------
// -- rsp[0] : return address
@ -327,7 +316,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
__ j(above_equal, &slow);
// 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));
// 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);
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0);
// Array index string: If short enough use cache in length/hash field (rbx).
// We assert that there are enough bits in an int32_t after the hash shift
// bits have been subtracted to allow space for the length and the cached
// array index.
// If the hash field contains an array index pick it out. The assert checks
// that the constants for the maximum number of digits for an array index
// cached in the hash field and the number of bits reserved for it does not
// conflict.
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
(1 << (String::kShortLengthShift - String::kHashShift)));
(1 << String::kArrayIndexValueBits));
__ bind(&index_string);
const int kLengthFieldLimit =
(String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
__ cmpl(rbx, Immediate(kLengthFieldLimit));
__ j(above_equal, &slow);
__ movl(rax, rbx);
__ and_(rax, Immediate((1 << String::kShortLengthShift) - 1));
__ shrl(rax, Immediate(String::kLongLengthShift));
__ and_(rax, Immediate(String::kArrayIndexHashMask));
__ shrl(rax, Immediate(String::kHashShift));
__ jmp(&index_int);
}
@ -393,7 +378,7 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
// ExternalArray.
// rax: index (as a smi)
// rcx: JSObject
__ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
__ movq(rcx, FieldOperand(rcx, JSObject::kElementsOffset));
__ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
Heap::RootIndexForExternalArrayType(array_type));
__ j(not_equal, &slow);
@ -413,7 +398,7 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
__ movsxbq(rax, Operand(rcx, rax, times_1, 0));
break;
case kExternalUnsignedByteArray:
__ movb(rax, Operand(rcx, rax, times_1, 0));
__ movzxbq(rax, Operand(rcx, rax, times_1, 0));
break;
case kExternalShortArray:
__ 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,
Register object,
Register addr,
@ -282,6 +288,9 @@ void MacroAssembler::Abort(const char* msg) {
RecordComment(msg);
}
#endif
// Disable stub call restrictions to always allow calls to abort.
set_allow_stub_calls(true);
push(rax);
movq(kScratchRegister, p0, RelocInfo::NONE);
push(kScratchRegister);
@ -291,6 +300,7 @@ void MacroAssembler::Abort(const char* msg) {
push(kScratchRegister);
CallRuntime(Runtime::kAbort, 2);
// will not return here
int3();
}
@ -2088,6 +2098,11 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
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_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)
: address_(address), size_(size), masm_(address, size + Assembler::kGap) {
// 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);
#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
@ -542,6 +548,9 @@ class MacroAssembler: public Assembler {
// occurred.
void IllegalOperation(int num_arguments);
// Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length);
// ---------------------------------------------------------------------------
// Runtime calls

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

@ -173,7 +173,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ JumpIfSmi(receiver, &miss);
// 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.
__ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ xor_(scratch, Immediate(flags));
@ -183,7 +183,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
ProbeTable(masm, flags, kPrimary, name, scratch);
// 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));
__ xor_(scratch, Immediate(flags));
__ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
@ -323,11 +323,7 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
// Load length directly from the string.
__ bind(&load_length);
__ and_(scratch, Immediate(kStringSizeMask));
__ movl(rax, FieldOperand(receiver, String::kLengthOffset));
// rcx is also the receiver.
__ lea(rcx, Operand(scratch, String::kLongLengthShift));
__ shr_cl(rax);
__ Integer32ToSmi(rax, rax);
__ ret(0);

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

@ -65,9 +65,9 @@ static Object* AllocateAfterFailures() {
// 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) {
CHECK(!Heap::AllocateRawAsciiString(0, TENURED)->IsFailure());
CHECK(!Heap::AllocateByteArray(0, 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) {
v8::HandleScope handle_scope;
v8::ExtensionConfiguration config(1, &name);
@ -7029,27 +7063,17 @@ static void MorphAString(i::String* string,
CHECK(i::StringShape(string).IsExternal());
if (string->IsAsciiRepresentation()) {
// Check old map is not symbol or long.
CHECK(string->map() == i::Heap::short_external_ascii_string_map() ||
string->map() == i::Heap::medium_external_ascii_string_map());
CHECK(string->map() == i::Heap::external_ascii_string_map());
// Morph external string to be TwoByte string.
if (string->length() <= i::String::kMaxShortSize) {
string->set_map(i::Heap::short_external_string_map());
} else {
string->set_map(i::Heap::medium_external_string_map());
}
string->set_map(i::Heap::external_string_map());
i::ExternalTwoByteString* morphed =
i::ExternalTwoByteString::cast(string);
morphed->set_resource(uc16_resource);
} else {
// Check old map is not symbol or long.
CHECK(string->map() == i::Heap::short_external_string_map() ||
string->map() == i::Heap::medium_external_string_map());
CHECK(string->map() == i::Heap::external_string_map());
// Morph external string to be ASCII string.
if (string->length() <= i::String::kMaxShortSize) {
string->set_map(i::Heap::short_external_ascii_string_map());
} else {
string->set_map(i::Heap::medium_external_ascii_string_map());
}
string->set_map(i::Heap::external_ascii_string_map());
i::ExternalAsciiString* morphed =
i::ExternalAsciiString::cast(string);
morphed->set_resource(ascii_resource);
@ -8059,6 +8083,85 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
result = CompileRun("ext_array[1] = 23;");
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);
}
@ -8409,3 +8512,103 @@ THREADED_TEST(SpaghettiStackReThrow) {
v8::String::Utf8Value value(try_catch.Exception());
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::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
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->Call(env->Global(), 0, NULL);
CHECK_EQ(3, break_point_hit_count);
@ -5069,8 +5069,8 @@ TEST(ContextData) {
CHECK(context_2->GetData()->IsUndefined());
// Set and check different data values.
v8::Handle<v8::Value> data_1 = v8::Number::New(1);
v8::Handle<v8::Value> data_2 = v8::String::New("2");
v8::Handle<v8::String> data_1 = v8::String::New("1");
v8::Handle<v8::String> data_2 = v8::String::New("2");
context_1->SetData(data_1);
context_2->SetData(data_2);
CHECK(context_1->GetData()->StrictEquals(data_1));
@ -5233,7 +5233,7 @@ static void ExecuteScriptForContextCheck() {
CHECK(context_1->GetData()->IsUndefined());
// 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);
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::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, FixedArray::kHeaderSize);
CheckMap(Heap::long_string_map(), LONG_STRING_TYPE,
SeqTwoByteString::kAlignedSize);
CheckMap(Heap::string_map(), STRING_TYPE, 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) {
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.
@ -218,7 +227,17 @@ DEPENDENT_TEST(Deserialize, Serialize) {
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();
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) {
}

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(
Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) {
// 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 {
public:
TwoByteResource(const uint16_t* data, size_t length, bool* destructed)
: data_(data), length_(length), destructed_(destructed) {
CHECK_NE(destructed, NULL);
*destructed_ = false;
}
TEST(ExternalShortStringAdd) {
ZoneScope zone(DELETE_ON_EXIT);
virtual ~TwoByteResource() {
CHECK_NE(destructed_, NULL);
CHECK(!*destructed_);
*destructed_ = true;
}
InitializeVM();
v8::HandleScope handle_scope;
const uint16_t* data() const { return data_; }
size_t length() const { return length_; }
// Make sure we cover all always-flat lengths and at least one above.
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:
const uint16_t* data_;
size_t length_;
bool* destructed_;
};
// Add the arrays with the short external strings in the global object.
v8::Handle<v8::Object> global = env->Global();
global->Set(v8_str("external_ascii"), ascii_external_strings);
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(84, resww, "swww");
})(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() {
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"', {
'sources': [
'../../src/platform-macos.cc',

69
deps/v8/tools/presubmit.py

@ -28,9 +28,11 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import md5
import optparse
import os
from os.path import abspath, join, dirname, basename, exists
import pickle
import re
import sys
import subprocess
@ -93,6 +95,50 @@ whitespace/todo
""".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):
"""
Utility class that can run through a directory structure, find all relevant
@ -146,13 +192,32 @@ class CppLintProcessor(SourceFileProcessor):
return ['src', 'public', 'samples', join('test', 'cctest')]
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])
command = ['cpplint.py', '--filter', filt] + join(files)
local_cpplint = join(path, "tools", "cpplint.py")
if exists(local_cpplint):
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(

2
deps/v8/tools/utils.py

@ -55,6 +55,8 @@ def GuessOS():
return 'win32'
elif id == 'FreeBSD':
return 'freebsd'
elif id == 'OpenBSD':
return 'openbsd'
else:
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 */; };
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 */; };
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 */; };
9FC86ABE0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; };
/* 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>"; };
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>"; };
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>"; };
9FC86ABC0F5FEDAC00F22668 /* oprofile-agent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "oprofile-agent.h"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -715,6 +723,10 @@
897FF1310E719B8F00D62E90 /* execution.h */,
897FF1320E719B8F00D62E90 /* factory.cc */,
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 */,
897FF1350E719B8F00D62E90 /* flags.cc */,
897FF1360E719B8F00D62E90 /* flags.h */,
@ -1225,6 +1237,8 @@
9F4B7B890FCC877A00DC4117 /* log-utils.cc in Sources */,
8981F6001010501900D1520E /* frame-element.cc in Sources */,
9F11D9A0105AF0A300EBE5B2 /* heap-profiler.cc in Sources */,
9FBE03DE10BD409900F8BFBA /* fast-codegen.cc in Sources */,
9FBE03E210BD40EA00F8BFBA /* fast-codegen-ia32.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1332,6 +1346,8 @@
9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */,
8981F6011010502800D1520E /* frame-element.cc in Sources */,
9F11D9A1105AF0A300EBE5B2 /* heap-profiler.cc in Sources */,
9FBE03DF10BD409900F8BFBA /* fast-codegen.cc in Sources */,
9FBE03E510BD412600F8BFBA /* fast-codegen-arm.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

Loading…
Cancel
Save