diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 5eb4b26780..059b69252e 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,29 @@ +2012-01-05: Version 3.8.5 + + Fix broken test that assumes that no GC can clear the regexp cache (GC + can happen at any time due to Crankshaft). + + Fix handling of bogus receivers for Harmony collections. (issue 1884) + + Add netbsd support to gyp build. + + Determine page size at runtime on posix platforms. + + Ensure that store buffer filtering hash sets are cleared after + StoreBuffer::Filter. + + Randomize the seed used for string hashing. This helps guard against + CPU-eating DOS attacks against node.js servers. Based on code from + Bert Belder. This version only solves the issue for those that compile + V8 themselves or those that do not use snapshots. A snapshot-based + precompiled V8 will still have predictable string hash codes. + + Implement callback when script finishes running in V8 API. + + Improve performance of Math.min and Math.max for the case of two + arguments. (issue 1325) + + 2012-01-02: Version 3.8.4 Performance improvements for large Smi-only arrays. diff --git a/deps/v8/LICENSE b/deps/v8/LICENSE index e435050e90..2e516bab62 100644 --- a/deps/v8/LICENSE +++ b/deps/v8/LICENSE @@ -14,7 +14,9 @@ are: - Strongtalk assembler, the basis of the files assembler-arm-inl.h, assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h, - assembler-ia32.cc, assembler-ia32.h, assembler.cc and assembler.h. + assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h, + assembler-x64.cc, assembler-x64.h, assembler-mips-inl.h, + assembler-mips.cc, assembler-mips.h, assembler.cc and assembler.h. This code is copyrighted by Sun Microsystems Inc. and released under a 3-clause BSD license. @@ -24,7 +26,7 @@ are: These libraries have their own licenses; we recommend you read them, as their terms may differ from the terms below. -Copyright 2006-2011, the V8 project authors. All rights reserved. +Copyright 2006-2012, 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: diff --git a/deps/v8/build/common.gypi b/deps/v8/build/common.gypi index 9129d0170c..7aab91356a 100644 --- a/deps/v8/build/common.gypi +++ b/deps/v8/build/common.gypi @@ -1,4 +1,4 @@ -# Copyright 2011 the V8 project authors. All rights reserved. +# Copyright 2012 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: @@ -215,7 +215,8 @@ }, }, }], - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \ + or OS=="netbsd"', { 'conditions': [ [ 'target_arch=="ia32"', { 'cflags': [ '-m32' ], @@ -259,7 +260,10 @@ ['OS=="freebsd" or OS=="openbsd"', { 'cflags': [ '-I/usr/local/include' ], }], - ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { + ['OS=="netbsd"', { + 'cflags': [ '-I/usr/pkg/include' ], + }], + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', '-Wnon-virtual-dtor' ], }], @@ -267,7 +271,7 @@ }, 'Release': { 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { 'cflags!': [ '-O2', '-Os', @@ -290,6 +294,9 @@ ['OS=="freebsd" or OS=="openbsd"', { 'cflags': [ '-I/usr/local/include' ], }], + ['OS=="netbsd"', { + 'cflags': [ '-I/usr/pkg/include' ], + }], ['OS=="mac"', { 'xcode_settings': { 'GCC_OPTIMIZATION_LEVEL': '3', # -O3 diff --git a/deps/v8/build/standalone.gypi b/deps/v8/build/standalone.gypi index 4297f5c84a..86f6d46092 100644 --- a/deps/v8/build/standalone.gypi +++ b/deps/v8/build/standalone.gypi @@ -1,4 +1,4 @@ -# Copyright 2011 the V8 project authors. All rights reserved. +# Copyright 2012 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: @@ -37,13 +37,16 @@ 'variables': { 'variables': { 'conditions': [ - [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { - # This handles the Linux platforms we generally deal with. Anything - # else gets passed through, which probably won't work very well; such - # hosts should pass an explicit target_arch to gyp. + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { + # This handles the Linux platforms we generally deal with. + # Anything else gets passed through, which probably won't work + # very well; such hosts should pass an explicit target_arch + # to gyp. 'host_arch%': - ' target, AccessType type, @@ -3033,11 +3036,24 @@ class V8EXPORT V8 { AllocationAction action); /** - * This function removes callback which was installed by - * AddMemoryAllocationCallback function. + * Removes callback that was installed by AddMemoryAllocationCallback. */ static void RemoveMemoryAllocationCallback(MemoryAllocationCallback callback); + /** + * Adds a callback to notify the host application when a script finished + * running. If a script re-enters the runtime during executing, the + * CallCompletedCallback is only invoked when the outer-most script + * execution ends. Executing scripts inside the callback do not trigger + * further callbacks. + */ + static void AddCallCompletedCallback(CallCompletedCallback callback); + + /** + * Removes callback that was installed by AddCallCompletedCallback. + */ + static void RemoveCallCompletedCallback(CallCompletedCallback callback); + /** * Allows the host application to group objects together. If one * object in the group is alive, all objects in the group are alive. diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 7eaadbb6b1..3bd5a3180f 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -78,7 +78,7 @@ namespace v8 { bool has_pending_exception = false -#define EXCEPTION_BAILOUT_CHECK(isolate, value) \ +#define EXCEPTION_BAILOUT_CHECK_GENERIC(isolate, value, do_callback) \ do { \ i::HandleScopeImplementer* handle_scope_implementer = \ (isolate)->handle_scope_implementer(); \ @@ -91,11 +91,22 @@ namespace v8 { } \ bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero(); \ (isolate)->OptionalRescheduleException(call_depth_is_zero); \ + do_callback \ return value; \ } \ + do_callback \ } while (false) +#define EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, value) \ + EXCEPTION_BAILOUT_CHECK_GENERIC( \ + isolate, value, i::V8::FireCallCompletedCallback(isolate);) + + +#define EXCEPTION_BAILOUT_CHECK(isolate, value) \ + EXCEPTION_BAILOUT_CHECK_GENERIC(isolate, value, ;) + + #define API_ENTRY_CHECK(isolate, msg) \ do { \ if (v8::Locker::IsActive()) { \ @@ -1568,7 +1579,7 @@ Local Script::Run() { isolate->context()->global_proxy(), isolate); i::Handle result = i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception); - EXCEPTION_BAILOUT_CHECK(isolate, Local()); + EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local()); raw_result = *result; } i::Handle result(raw_result, isolate); @@ -3494,7 +3505,7 @@ Local Object::CallAsFunction(v8::Handle recv, EXCEPTION_PREAMBLE(isolate); i::Handle returned = i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception); - EXCEPTION_BAILOUT_CHECK(isolate, Local()); + EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local()); return Utils::ToLocal(scope.CloseAndEscape(returned)); } @@ -3515,7 +3526,7 @@ Local Object::CallAsConstructor(int argc, EXCEPTION_PREAMBLE(isolate); i::Handle returned = i::Execution::New(fun, argc, args, &has_pending_exception); - EXCEPTION_BAILOUT_CHECK(isolate, Local()); + EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local()); return Utils::ToLocal(scope.CloseAndEscape( i::Handle::cast(returned))); } @@ -3528,7 +3539,7 @@ Local Object::CallAsConstructor(int argc, EXCEPTION_PREAMBLE(isolate); i::Handle returned = i::Execution::Call(fun, obj, argc, args, &has_pending_exception); - EXCEPTION_BAILOUT_CHECK(isolate, Local()); + EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local()); ASSERT(!delegate->IsUndefined()); return Utils::ToLocal(scope.CloseAndEscape(returned)); } @@ -3555,7 +3566,7 @@ Local Function::NewInstance(int argc, EXCEPTION_PREAMBLE(isolate); i::Handle returned = i::Execution::New(function, argc, args, &has_pending_exception); - EXCEPTION_BAILOUT_CHECK(isolate, Local()); + EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local()); return scope.Close(Utils::ToLocal(i::Handle::cast(returned))); } @@ -3576,7 +3587,7 @@ Local Function::Call(v8::Handle recv, int argc, EXCEPTION_PREAMBLE(isolate); i::Handle returned = i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception); - EXCEPTION_BAILOUT_CHECK(isolate, Local()); + EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local()); raw_result = *returned; } i::Handle result(raw_result); @@ -5045,6 +5056,21 @@ void V8::RemoveMemoryAllocationCallback(MemoryAllocationCallback callback) { } +void V8::AddCallCompletedCallback(CallCompletedCallback callback) { + if (callback == NULL) return; + i::Isolate* isolate = i::Isolate::Current(); + if (IsDeadCheck(isolate, "v8::V8::AddLeaveScriptCallback()")) return; + i::V8::AddCallCompletedCallback(callback); +} + + +void V8::RemoveCallCompletedCallback(CallCompletedCallback callback) { + i::Isolate* isolate = i::Isolate::Current(); + if (IsDeadCheck(isolate, "v8::V8::RemoveLeaveScriptCallback()")) return; + i::V8::RemoveCallCompletedCallback(callback); +} + + void V8::PauseProfiler() { i::Isolate* isolate = i::Isolate::Current(); isolate->logger()->PauseProfiler(); diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index c452821ff6..69ef1872c7 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -316,7 +316,8 @@ static void AllocateJSArray(MacroAssembler* masm, static void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code) { Counters* counters = masm->isolate()->counters(); - Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array; + Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array, + has_non_smi_element; // Check for array construction with zero arguments or one. __ cmp(r0, Operand(0, RelocInfo::NONE)); @@ -415,7 +416,7 @@ static void ArrayNativeCode(MacroAssembler* masm, __ bind(&loop); __ ldr(r2, MemOperand(r7, kPointerSize, PostIndex)); if (FLAG_smi_only_arrays) { - __ JumpIfNotSmi(r2, call_generic_code); + __ JumpIfNotSmi(r2, &has_non_smi_element); } __ str(r2, MemOperand(r5, -kPointerSize, PreIndex)); __ bind(&entry); @@ -431,6 +432,10 @@ static void ArrayNativeCode(MacroAssembler* masm, __ add(sp, sp, Operand(kPointerSize)); __ mov(r0, r3); __ Jump(lr); + + __ bind(&has_non_smi_element); + __ UndoAllocationInNewSpace(r3, r4); + __ b(call_generic_code); } diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 209c48e2a0..e95e2cf421 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -5730,7 +5730,11 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, Register hash, Register character) { // hash = character + (character << 10); - __ add(hash, character, Operand(character, LSL, 10)); + __ LoadRoot(hash, Heap::kStringHashSeedRootIndex); + // Untag smi seed and add the character. + __ add(hash, character, Operand(hash, LSR, kSmiTagSize)); + // hash += hash << 10; + __ add(hash, hash, Operand(hash, LSL, 10)); // hash ^= hash >> 6; __ eor(hash, hash, Operand(hash, LSR, 6)); } diff --git a/deps/v8/src/checks.h b/deps/v8/src/checks.h index 8608b0eba9..d93d4510f6 100644 --- a/deps/v8/src/checks.h +++ b/deps/v8/src/checks.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -265,16 +265,16 @@ extern bool FLAG_enable_slow_asserts; // The ASSERT macro is equivalent to CHECK except that it only // generates code in debug builds. #ifdef DEBUG -#define ASSERT_RESULT(expr) CHECK(expr) -#define ASSERT(condition) CHECK(condition) -#define ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2) -#define ASSERT_NE(v1, v2) CHECK_NE(v1, v2) -#define ASSERT_GE(v1, v2) CHECK_GE(v1, v2) -#define ASSERT_LT(v1, v2) CHECK_LT(v1, v2) -#define ASSERT_LE(v1, v2) CHECK_LE(v1, v2) -#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition) +#define ASSERT_RESULT(expr) CHECK(expr) +#define ASSERT(condition) CHECK(condition) +#define ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2) +#define ASSERT_NE(v1, v2) CHECK_NE(v1, v2) +#define ASSERT_GE(v1, v2) CHECK_GE(v1, v2) +#define ASSERT_LT(v1, v2) CHECK_LT(v1, v2) +#define ASSERT_LE(v1, v2) CHECK_LE(v1, v2) +#define SLOW_ASSERT(condition) CHECK(!FLAG_enable_slow_asserts || (condition)) #else -#define ASSERT_RESULT(expr) (expr) +#define ASSERT_RESULT(expr) (expr) #define ASSERT(condition) ((void) 0) #define ASSERT_EQ(v1, v2) ((void) 0) #define ASSERT_NE(v1, v2) ((void) 0) diff --git a/deps/v8/src/collection.js b/deps/v8/src/collection.js index d11612681e..fcf4d38d94 100644 --- a/deps/v8/src/collection.js +++ b/deps/v8/src/collection.js @@ -47,6 +47,10 @@ function SetConstructor() { function SetAdd(key) { + if (!IS_SET(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Set.prototype.add', this]); + } if (IS_UNDEFINED(key)) { key = undefined_sentinel; } @@ -55,6 +59,10 @@ function SetAdd(key) { function SetHas(key) { + if (!IS_SET(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Set.prototype.has', this]); + } if (IS_UNDEFINED(key)) { key = undefined_sentinel; } @@ -63,6 +71,10 @@ function SetHas(key) { function SetDelete(key) { + if (!IS_SET(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Set.prototype.delete', this]); + } if (IS_UNDEFINED(key)) { key = undefined_sentinel; } @@ -80,6 +92,10 @@ function MapConstructor() { function MapGet(key) { + if (!IS_MAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Map.prototype.get', this]); + } if (IS_UNDEFINED(key)) { key = undefined_sentinel; } @@ -88,6 +104,10 @@ function MapGet(key) { function MapSet(key, value) { + if (!IS_MAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Map.prototype.set', this]); + } if (IS_UNDEFINED(key)) { key = undefined_sentinel; } @@ -96,6 +116,10 @@ function MapSet(key, value) { function MapHas(key) { + if (!IS_MAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Map.prototype.has', this]); + } if (IS_UNDEFINED(key)) { key = undefined_sentinel; } @@ -104,6 +128,10 @@ function MapHas(key) { function MapDelete(key) { + if (!IS_MAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Map.prototype.delete', this]); + } if (IS_UNDEFINED(key)) { key = undefined_sentinel; } @@ -126,6 +154,10 @@ function WeakMapConstructor() { function WeakMapGet(key) { + if (!IS_WEAKMAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakMap.prototype.get', this]); + } if (!IS_SPEC_OBJECT(key)) { throw %MakeTypeError('invalid_weakmap_key', [this, key]); } @@ -134,6 +166,10 @@ function WeakMapGet(key) { function WeakMapSet(key, value) { + if (!IS_WEAKMAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakMap.prototype.set', this]); + } if (!IS_SPEC_OBJECT(key)) { throw %MakeTypeError('invalid_weakmap_key', [this, key]); } @@ -142,6 +178,10 @@ function WeakMapSet(key, value) { function WeakMapHas(key) { + if (!IS_WEAKMAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakMap.prototype.has', this]); + } if (!IS_SPEC_OBJECT(key)) { throw %MakeTypeError('invalid_weakmap_key', [this, key]); } @@ -150,6 +190,10 @@ function WeakMapHas(key) { function WeakMapDelete(key) { + if (!IS_WEAKMAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakMap.prototype.delete', this]); + } if (!IS_SPEC_OBJECT(key)) { throw %MakeTypeError('invalid_weakmap_key', [this, key]); } diff --git a/deps/v8/src/d8-posix.cc b/deps/v8/src/d8-posix.cc index 289c3b0ae8..8a278e4e42 100644 --- a/deps/v8/src/d8-posix.cc +++ b/deps/v8/src/d8-posix.cc @@ -366,7 +366,8 @@ static Handle GetStdout(int child_fd, // We're disabling usage of waitid in Mac OS X because it doens't work for us: // a parent process hangs on waiting while a child process is already a zombie. // See http://code.google.com/p/v8/issues/detail?id=401. -#if defined(WNOWAIT) && !defined(ANDROID) && !defined(__APPLE__) +#if defined(WNOWAIT) && !defined(ANDROID) && !defined(__APPLE__) \ + && !defined(__NetBSD__) #if !defined(__FreeBSD__) #define HAS_WAITID 1 #endif diff --git a/deps/v8/src/d8.gyp b/deps/v8/src/d8.gyp index bdc23a20e9..a096af35b8 100644 --- a/deps/v8/src/d8.gyp +++ b/deps/v8/src/d8.gyp @@ -64,8 +64,8 @@ 'libraries': [ '-lreadline', ], 'sources': [ 'd8-readline.cc' ], }], - [ '(OS=="linux" or OS=="mac" or OS=="freebsd" \ - or OS=="openbsd" or OS=="solaris" or OS=="android")', { + ['(OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="netbsd" \ + or OS=="openbsd" or OS=="solaris" or OS=="android")', { 'sources': [ 'd8-posix.cc', ] }], [ 'OS=="win"', { diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index 1ae1b17eb5..07060dcb03 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -349,6 +349,14 @@ DEFINE_bool(trace_exception, false, "print stack trace when throwing exceptions") DEFINE_bool(preallocate_message_memory, false, "preallocate some memory to build stack traces.") +DEFINE_bool(randomize_string_hashes, + true, + "randomize string hashes to avoid predictable hash collisions " + "(with snapshots this option cannot override the baked-in seed)") +DEFINE_int(string_hash_seed, + 0, + "Fixed seed to use to string hashing (0 means random)" + "(with snapshots this option cannot override the baked-in seed)") // v8.cc DEFINE_bool(preemption, false, diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 5984834eaf..31cd889cbe 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -2318,6 +2318,10 @@ bool Heap::CreateInitialObjects() { } set_infinity_value(HeapNumber::cast(obj)); + // The hole has not been created yet, but we want to put something + // predictable in the gaps in the symbol table, so lets make that Smi zero. + set_the_hole_value(reinterpret_cast(Smi::FromInt(0))); + // Allocate initial symbol table. { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize); if (!maybe_obj->ToObject(&obj)) return false; @@ -5638,6 +5642,18 @@ bool Heap::Setup(bool create_heap_objects) { lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE); if (lo_space_ == NULL) return false; if (!lo_space_->Setup()) return false; + + // Setup the seed that is used to randomize the string hash function. + ASSERT(string_hash_seed() == 0); + if (FLAG_randomize_string_hashes) { + if (FLAG_string_hash_seed == 0) { + set_string_hash_seed( + Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff)); + } else { + set_string_hash_seed(Smi::FromInt(FLAG_string_hash_seed)); + } + } + if (create_heap_objects) { // Create initial maps. if (!CreateInitialMaps()) return false; diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index d92a4fb148..2d993bbc2b 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -96,6 +96,7 @@ inline Heap* _inline_get_heap_(); V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \ V(FixedArray, string_split_cache, StringSplitCache) \ V(Object, termination_exception, TerminationException) \ + V(Smi, string_hash_seed, StringHashSeed) \ V(Map, string_map, StringMap) \ V(Map, symbol_map, SymbolMap) \ V(Map, cons_string_map, ConsStringMap) \ @@ -954,8 +955,7 @@ class Heap { // Please note this function does not perform a garbage collection. MUST_USE_RESULT MaybeObject* LookupSymbol(Vector str); MUST_USE_RESULT MaybeObject* LookupAsciiSymbol(Vector str); - MUST_USE_RESULT MaybeObject* LookupTwoByteSymbol( - Vector str); + MUST_USE_RESULT MaybeObject* LookupTwoByteSymbol(Vector str); MUST_USE_RESULT MaybeObject* LookupAsciiSymbol(const char* str) { return LookupSymbol(CStrVector(str)); } @@ -1506,6 +1506,12 @@ class Heap { return idle_notification_will_schedule_next_gc_; } + uint32_t StringHashSeed() { + uint32_t seed = static_cast(string_hash_seed()->value()); + ASSERT(FLAG_randomize_string_hashes || seed == 0); + return seed; + } + private: Heap(); diff --git a/deps/v8/src/ia32/builtins-ia32.cc b/deps/v8/src/ia32/builtins-ia32.cc index 3d274f2e6b..55f66f1df8 100644 --- a/deps/v8/src/ia32/builtins-ia32.cc +++ b/deps/v8/src/ia32/builtins-ia32.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -1297,6 +1297,7 @@ static void ArrayNativeCode(MacroAssembler* masm, __ bind(&has_non_smi_element); // Throw away the array that's only been partially constructed. __ pop(eax); + __ UndoAllocationInNewSpace(eax); // Restore argc and constructor before running the generic code. __ bind(&prepare_generic_code_call); diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index bb422959e7..9bc024f40d 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -6033,10 +6033,24 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, Register hash, Register character, Register scratch) { - // hash = character + (character << 10); - __ mov(hash, character); - __ shl(hash, 10); - __ add(hash, character); + // hash = (seed + character) + ((seed + character) << 10); + if (Serializer::enabled()) { + ExternalReference roots_array_start = + ExternalReference::roots_array_start(masm->isolate()); + __ mov(scratch, Immediate(Heap::kStringHashSeedRootIndex)); + __ mov(scratch, Operand::StaticArray(scratch, + times_pointer_size, + roots_array_start)); + __ add(scratch, character); + __ mov(hash, scratch); + __ shl(scratch, 10); + __ add(hash, scratch); + } else { + int32_t seed = masm->isolate()->heap()->StringHashSeed(); + __ lea(scratch, Operand(character, seed)); + __ shl(scratch, 10); + __ lea(hash, Operand(scratch, character, times_1, seed)); + } // hash ^= hash >> 6; __ mov(scratch, hash); __ shr(scratch, 6); diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h index 2ea9b80b69..c044e1f578 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -106,15 +106,21 @@ class Simulator; // of handles to the actual constants. typedef ZoneList > ZoneObjectList; -#define RETURN_IF_SCHEDULED_EXCEPTION(isolate) \ - if (isolate->has_scheduled_exception()) \ - return isolate->PromoteScheduledException() +#define RETURN_IF_SCHEDULED_EXCEPTION(isolate) \ + do { \ + Isolate* __isolate__ = (isolate); \ + if (__isolate__->has_scheduled_exception()) { \ + return __isolate__->PromoteScheduledException(); \ + } \ + } while (false) #define RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, value) \ - if (call.is_null()) { \ - ASSERT(isolate->has_pending_exception()); \ - return value; \ - } + do { \ + if ((call).is_null()) { \ + ASSERT((isolate)->has_pending_exception()); \ + return (value); \ + } \ + } while (false) #define RETURN_IF_EMPTY_HANDLE(isolate, call) \ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, Failure::Exception()) diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py index bf7119feaa..34b07ab235 100644 --- a/deps/v8/src/macros.py +++ b/deps/v8/src/macros.py @@ -101,6 +101,9 @@ macro IS_OBJECT(arg) = (%_IsObject(arg)); macro IS_ARRAY(arg) = (%_IsArray(arg)); macro IS_FUNCTION(arg) = (%_IsFunction(arg)); macro IS_REGEXP(arg) = (%_IsRegExp(arg)); +macro IS_SET(arg) = (%_ClassOf(arg) === 'Set'); +macro IS_MAP(arg) = (%_ClassOf(arg) === 'Map'); +macro IS_WEAKMAP(arg) = (%_ClassOf(arg) === 'WeakMap'); macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date'); macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number'); macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String'); diff --git a/deps/v8/src/math.js b/deps/v8/src/math.js index 18492aa050..f4426f4a00 100644 --- a/deps/v8/src/math.js +++ b/deps/v8/src/math.js @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -119,6 +119,19 @@ function MathLog(x) { // ECMA 262 - 15.8.2.11 function MathMax(arg1, arg2) { // length == 2 var length = %_ArgumentsLength(); + if (length == 2) { + if (!IS_NUMBER(arg1)) arg1 = NonNumberToNumber(arg1); + if (!IS_NUMBER(arg2)) arg2 = NonNumberToNumber(arg2); + if (arg2 > arg1) return arg2; + if (arg1 > arg2) return arg1; + if (arg1 == arg2) { + // Make sure -0 is considered less than +0. -0 is never a Smi, +0 can be + // a Smi or a heap number. + return (arg1 == 0 && !%_IsSmi(arg1) && 1 / arg1 < 0) ? arg2 : arg1; + } + // All comparisons failed, one of the arguments must be NaN. + return 0/0; // Compiler constant-folds this to NaN. + } if (length == 0) { return -1/0; // Compiler constant-folds this to -Infinity. } @@ -131,7 +144,7 @@ function MathMax(arg1, arg2) { // length == 2 if (NUMBER_IS_NAN(n)) return n; // Make sure +0 is considered greater than -0. -0 is never a Smi, +0 can be // a Smi or heap number. - if (n > r || (r === 0 && n === 0 && !%_IsSmi(r) && 1 / r < 0)) r = n; + if (n > r || (r == 0 && n == 0 && !%_IsSmi(r) && 1 / r < 0)) r = n; } return r; } @@ -139,6 +152,19 @@ function MathMax(arg1, arg2) { // length == 2 // ECMA 262 - 15.8.2.12 function MathMin(arg1, arg2) { // length == 2 var length = %_ArgumentsLength(); + if (length == 2) { + if (!IS_NUMBER(arg1)) arg1 = NonNumberToNumber(arg1); + if (!IS_NUMBER(arg2)) arg2 = NonNumberToNumber(arg2); + if (arg2 > arg1) return arg1; + if (arg1 > arg2) return arg2; + if (arg1 == arg2) { + // Make sure -0 is considered less than +0. -0 is never a Smi, +0 can be + // a Smi or a heap number. + return (arg1 == 0 && !%_IsSmi(arg1) && 1 / arg1 < 0) ? arg1 : arg2; + } + // All comparisons failed, one of the arguments must be NaN. + return 0/0; // Compiler constant-folds this to NaN. + } if (length == 0) { return 1/0; // Compiler constant-folds this to Infinity. } @@ -149,9 +175,9 @@ function MathMin(arg1, arg2) { // length == 2 var n = %_Arguments(i); if (!IS_NUMBER(n)) n = NonNumberToNumber(n); if (NUMBER_IS_NAN(n)) return n; - // Make sure -0 is considered less than +0. -0 is never a Smi, +0 can b a + // Make sure -0 is considered less than +0. -0 is never a Smi, +0 can be a // Smi or a heap number. - if (n < r || (r === 0 && n === 0 && !%_IsSmi(n) && 1 / n < 0)) r = n; + if (n < r || (r == 0 && n == 0 && !%_IsSmi(n) && 1 / n < 0)) r = n; } return r; } diff --git a/deps/v8/src/mips/builtins-mips.cc b/deps/v8/src/mips/builtins-mips.cc index 701450b814..46a912bd59 100644 --- a/deps/v8/src/mips/builtins-mips.cc +++ b/deps/v8/src/mips/builtins-mips.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -74,17 +74,33 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm, } +// Load the built-in InternalArray function from the current context. +static void GenerateLoadInternalArrayFunction(MacroAssembler* masm, + Register result) { + // Load the global context. + + __ lw(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ lw(result, + FieldMemOperand(result, GlobalObject::kGlobalContextOffset)); + // Load the InternalArray function from the global context. + __ lw(result, + MemOperand(result, + Context::SlotOffset( + Context::INTERNAL_ARRAY_FUNCTION_INDEX))); +} + + // Load the built-in Array function from the current context. static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) { // Load the global context. __ lw(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); __ lw(result, - FieldMemOperand(result, GlobalObject::kGlobalContextOffset)); + FieldMemOperand(result, GlobalObject::kGlobalContextOffset)); // Load the Array function from the global context. __ lw(result, - MemOperand(result, - Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); + MemOperand(result, + Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); } @@ -308,7 +324,8 @@ static void AllocateJSArray(MacroAssembler* masm, static void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code) { Counters* counters = masm->isolate()->counters(); - Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array; + Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array, + has_non_smi_element; // Check for array construction with zero arguments or one. __ Branch(&argc_one_or_more, ne, a0, Operand(zero_reg)); @@ -406,7 +423,7 @@ static void ArrayNativeCode(MacroAssembler* masm, __ lw(a2, MemOperand(t3)); __ Addu(t3, t3, kPointerSize); if (FLAG_smi_only_arrays) { - __ JumpIfNotSmi(a2, call_generic_code); + __ JumpIfNotSmi(a2, &has_non_smi_element); } __ Addu(t1, t1, -kPointerSize); __ sw(a2, MemOperand(t1)); @@ -422,6 +439,46 @@ static void ArrayNativeCode(MacroAssembler* masm, __ Addu(sp, sp, Operand(kPointerSize)); __ mov(v0, a3); __ Ret(); + + __ bind(&has_non_smi_element); + __ UndoAllocationInNewSpace(a3, t0); + __ b(call_generic_code); +} + + +void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- a0 : number of arguments + // -- ra : return address + // -- sp[...]: constructor arguments + // ----------------------------------- + Label generic_array_code, one_or_more_arguments, two_or_more_arguments; + + // Get the InternalArray function. + GenerateLoadInternalArrayFunction(masm, a1); + + if (FLAG_debug_code) { + // Initial map for the builtin InternalArray functions should be maps. + __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); + __ And(t0, a2, Operand(kSmiTagMask)); + __ Assert(ne, "Unexpected initial map for InternalArray function", + t0, Operand(zero_reg)); + __ GetObjectType(a2, a3, t0); + __ Assert(eq, "Unexpected initial map for InternalArray function", + t0, Operand(MAP_TYPE)); + } + + // Run the native code for the InternalArray function called as a normal + // function. + ArrayNativeCode(masm, &generic_array_code); + + // Jump to the generic array code if the specialized code cannot handle the + // construction. + __ bind(&generic_array_code); + + Handle array_code = + masm->isolate()->builtins()->InternalArrayCodeGeneric(); + __ Jump(array_code, RelocInfo::CODE_TARGET); } diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc index b8e97f6dfe..3e811bd7cb 100644 --- a/deps/v8/src/mips/code-stubs-mips.cc +++ b/deps/v8/src/mips/code-stubs-mips.cc @@ -5924,11 +5924,15 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, void StringHelper::GenerateHashInit(MacroAssembler* masm, - Register hash, - Register character) { - // hash = character + (character << 10); - __ sll(hash, character, 10); + Register hash, + Register character) { + // hash = seed + character + ((seed + character) << 10); + __ LoadRoot(hash, Heap::kStringHashSeedRootIndex); + // Untag smi seed and add the character. + __ SmiUntag(hash); __ addu(hash, hash, character); + __ sll(at, hash, 10); + __ addu(hash, hash, at); // hash ^= hash >> 6; __ srl(at, hash, 6); __ xor_(hash, hash, at); @@ -5936,8 +5940,8 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, - Register hash, - Register character) { + Register hash, + Register character) { // hash += character; __ addu(hash, hash, character); // hash += hash << 10; diff --git a/deps/v8/src/mips/lithium-codegen-mips.cc b/deps/v8/src/mips/lithium-codegen-mips.cc index 53be7d1e17..06e886c6bb 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.cc +++ b/deps/v8/src/mips/lithium-codegen-mips.cc @@ -353,6 +353,18 @@ DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, } +Handle LCodeGen::ToHandle(LConstantOperand* op) const { + Handle literal = chunk_->LookupLiteral(op); + ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged()); + return literal; +} + + +bool LCodeGen::IsInteger32(LConstantOperand* op) const { + return chunk_->LookupLiteralRepresentation(op).IsInteger32(); +} + + int LCodeGen::ToInteger32(LConstantOperand* op) const { Handle value = chunk_->LookupLiteral(op); ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); diff --git a/deps/v8/src/mips/lithium-codegen-mips.h b/deps/v8/src/mips/lithium-codegen-mips.h index 32d4fb3f4d..68a7c5b1aa 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.h +++ b/deps/v8/src/mips/lithium-codegen-mips.h @@ -93,6 +93,9 @@ class LCodeGen BASE_EMBEDDED { // Returns a MemOperand pointing to the high word of a DoubleStackSlot. MemOperand ToHighMemOperand(LOperand* op) const; + bool IsInteger32(LConstantOperand* op) const; + Handle ToHandle(LConstantOperand* op) const; + // Try to generate code for the entire chunk, but it may fail if the // chunk contains constructs we cannot handle. Returns true if the // code generation attempt succeeded. diff --git a/deps/v8/src/mips/lithium-gap-resolver-mips.cc b/deps/v8/src/mips/lithium-gap-resolver-mips.cc index 8f7f89cf5d..2e5c64e7a2 100644 --- a/deps/v8/src/mips/lithium-gap-resolver-mips.cc +++ b/deps/v8/src/mips/lithium-gap-resolver-mips.cc @@ -252,14 +252,24 @@ void LGapResolver::EmitMove(int index) { } } else if (source->IsConstantOperand()) { - Operand source_operand = cgen_->ToOperand(source); + LConstantOperand* constant_source = LConstantOperand::cast(source); if (destination->IsRegister()) { - __ li(cgen_->ToRegister(destination), source_operand); + Register dst = cgen_->ToRegister(destination); + if (cgen_->IsInteger32(constant_source)) { + __ li(dst, Operand(cgen_->ToInteger32(constant_source))); + } else { + __ LoadObject(dst, cgen_->ToHandle(constant_source)); + } } else { ASSERT(destination->IsStackSlot()); ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone. - MemOperand destination_operand = cgen_->ToMemOperand(destination); - __ li(kSavedValueRegister, source_operand); + if (cgen_->IsInteger32(constant_source)) { + __ li(kSavedValueRegister, + Operand(cgen_->ToInteger32(constant_source))); + } else { + __ LoadObject(kSavedValueRegister, + cgen_->ToHandle(constant_source)); + } __ sw(kSavedValueRegister, cgen_->ToMemOperand(destination)); } diff --git a/deps/v8/src/mips/macro-assembler-mips.h b/deps/v8/src/mips/macro-assembler-mips.h index 4e14fbf977..bd5b94f57c 100644 --- a/deps/v8/src/mips/macro-assembler-mips.h +++ b/deps/v8/src/mips/macro-assembler-mips.h @@ -264,6 +264,14 @@ class MacroAssembler: public Assembler { void LoadHeapObject(Register dst, Handle object); + void LoadObject(Register result, Handle object) { + if (object->IsHeapObject()) { + LoadHeapObject(result, Handle::cast(object)); + } else { + li(result, object); + } + } + // --------------------------------------------------------------------------- // GC Support diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 99a0bb08d2..c5cf060829 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -2062,8 +2062,9 @@ int HashTable::FindEntry(Isolate* isolate, Key key) { // EnsureCapacity will guarantee the hash table is never full. while (true) { Object* element = KeyAt(entry); - if (element == isolate->heap()->undefined_value()) break; // Empty entry. - if (element != isolate->heap()->the_hole_value() && + // Empty entry. + if (element == isolate->heap()->raw_unchecked_undefined_value()) break; + if (element != isolate->heap()->raw_unchecked_the_hole_value() && Shape::IsMatch(key, element)) return entry; entry = NextProbe(entry, count++, capacity); } @@ -4320,13 +4321,15 @@ uint32_t String::Hash() { } -StringHasher::StringHasher(int length) +StringHasher::StringHasher(int length, uint32_t seed) : length_(length), - raw_running_hash_(0), + raw_running_hash_(seed), array_index_(0), is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize), is_first_char_(true), - is_valid_(true) { } + is_valid_(true) { + ASSERT(FLAG_randomize_string_hashes || raw_running_hash_ == 0); +} bool StringHasher::has_trivial_hash() { @@ -4378,7 +4381,7 @@ uint32_t StringHasher::GetHash() { result += (result << 3); result ^= (result >> 11); result += (result << 15); - if (result == 0) { + if ((result & String::kHashBitMask) == 0) { result = 27; } return result; @@ -4386,8 +4389,8 @@ uint32_t StringHasher::GetHash() { template -uint32_t HashSequentialString(const schar* chars, int length) { - StringHasher hasher(length); +uint32_t HashSequentialString(const schar* chars, int length, uint32_t seed) { + StringHasher hasher(length, seed); if (!hasher.has_trivial_hash()) { int i; for (i = 0; hasher.is_array_index() && (i < length); i++) { diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index f3a543f077..36879099e0 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -6682,6 +6682,20 @@ bool String::SlowEquals(String* other) { // Fast check: if hash code is computed for both strings // a fast negative check can be performed. if (HasHashCode() && other->HasHashCode()) { +#ifdef DEBUG + if (FLAG_enable_slow_asserts) { + if (Hash() != other->Hash()) { + bool found_difference = false; + for (int i = 0; i < len; i++) { + if (Get(i) != other->Get(i)) { + found_difference = true; + break; + } + } + ASSERT(found_difference); + } + } +#endif if (Hash() != other->Hash()) return false; } @@ -6817,12 +6831,16 @@ uint32_t String::ComputeAndSetHash() { // Compute the hash code. uint32_t field = 0; if (StringShape(this).IsSequentialAscii()) { - field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len); + field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), + len, + GetHeap()->StringHashSeed()); } else if (StringShape(this).IsSequentialTwoByte()) { - field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len); + field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), + len, + GetHeap()->StringHashSeed()); } else { StringInputBuffer buffer(this); - field = ComputeHashField(&buffer, len); + field = ComputeHashField(&buffer, len, GetHeap()->StringHashSeed()); } // Store the hash code in the object. @@ -6913,8 +6931,9 @@ uint32_t StringHasher::GetHashField() { uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer, - int length) { - StringHasher hasher(length); + int length, + uint32_t seed) { + StringHasher hasher(length, seed); // Very long strings have a trivial hash that doesn't inspect the // string contents. @@ -10456,8 +10475,8 @@ class RegExpKey : public HashTableKey { // Utf8SymbolKey carries a vector of chars as key. class Utf8SymbolKey : public HashTableKey { public: - explicit Utf8SymbolKey(Vector string) - : string_(string), hash_field_(0) { } + explicit Utf8SymbolKey(Vector string, uint32_t seed) + : string_(string), hash_field_(0), seed_(seed) { } bool IsMatch(Object* string) { return String::cast(string)->IsEqualTo(string_); @@ -10468,7 +10487,7 @@ class Utf8SymbolKey : public HashTableKey { unibrow::Utf8InputBuffer<> buffer(string_.start(), static_cast(string_.length())); chars_ = buffer.Length(); - hash_field_ = String::ComputeHashField(&buffer, chars_); + hash_field_ = String::ComputeHashField(&buffer, chars_, seed_); uint32_t result = hash_field_ >> String::kHashShift; ASSERT(result != 0); // Ensure that the hash value of 0 is never computed. return result; @@ -10487,17 +10506,18 @@ class Utf8SymbolKey : public HashTableKey { Vector string_; uint32_t hash_field_; int chars_; // Caches the number of characters when computing the hash code. + uint32_t seed_; }; template class SequentialSymbolKey : public HashTableKey { public: - explicit SequentialSymbolKey(Vector string) - : string_(string), hash_field_(0) { } + explicit SequentialSymbolKey(Vector string, uint32_t seed) + : string_(string), hash_field_(0), seed_(seed) { } uint32_t Hash() { - StringHasher hasher(string_.length()); + StringHasher hasher(string_.length(), seed_); // Very long strings have a trivial hash that doesn't inspect the // string contents. @@ -10533,14 +10553,15 @@ class SequentialSymbolKey : public HashTableKey { Vector string_; uint32_t hash_field_; + uint32_t seed_; }; class AsciiSymbolKey : public SequentialSymbolKey { public: - explicit AsciiSymbolKey(Vector str) - : SequentialSymbolKey(str) { } + AsciiSymbolKey(Vector str, uint32_t seed) + : SequentialSymbolKey(str, seed) { } bool IsMatch(Object* string) { return String::cast(string)->IsAsciiEqualTo(string_); @@ -10557,13 +10578,14 @@ class SubStringAsciiSymbolKey : public HashTableKey { public: explicit SubStringAsciiSymbolKey(Handle string, int from, - int length) - : string_(string), from_(from), length_(length) { } + int length, + uint32_t seed) + : string_(string), from_(from), length_(length), seed_(seed) { } uint32_t Hash() { ASSERT(length_ >= 0); ASSERT(from_ + length_ <= string_->length()); - StringHasher hasher(length_); + StringHasher hasher(length_, string_->GetHeap()->StringHashSeed()); // Very long strings have a trivial hash that doesn't inspect the // string contents. @@ -10615,13 +10637,14 @@ class SubStringAsciiSymbolKey : public HashTableKey { int from_; int length_; uint32_t hash_field_; + uint32_t seed_; }; class TwoByteSymbolKey : public SequentialSymbolKey { public: - explicit TwoByteSymbolKey(Vector str) - : SequentialSymbolKey(str) { } + explicit TwoByteSymbolKey(Vector str, uint32_t seed) + : SequentialSymbolKey(str, seed) { } bool IsMatch(Object* string) { return String::cast(string)->IsTwoByteEqualTo(string_); @@ -11406,10 +11429,12 @@ MaybeObject* SymbolTable::LookupString(String* string, Object** s) { // algorithm. class TwoCharHashTableKey : public HashTableKey { public: - TwoCharHashTableKey(uint32_t c1, uint32_t c2) + TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed) : c1_(c1), c2_(c2) { // Char 1. - uint32_t hash = c1 + (c1 << 10); + uint32_t hash = seed; + hash += c1; + hash += hash << 10; hash ^= hash >> 6; // Char 2. hash += c2; @@ -11419,9 +11444,9 @@ class TwoCharHashTableKey : public HashTableKey { hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; - if (hash == 0) hash = 27; + if ((hash & String::kHashBitMask) == 0) hash = 27; #ifdef DEBUG - StringHasher hasher(2); + StringHasher hasher(2, seed); hasher.AddCharacter(c1); hasher.AddCharacter(c2); // If this assert fails then we failed to reproduce the two-character @@ -11478,7 +11503,7 @@ bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1, uint32_t c2, String** symbol) { - TwoCharHashTableKey key(c1, c2); + TwoCharHashTableKey key(c1, c2, GetHeap()->StringHashSeed()); int entry = FindEntry(&key); if (entry == kNotFound) { return false; @@ -11491,15 +11516,16 @@ bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1, } -MaybeObject* SymbolTable::LookupSymbol(Vector str, Object** s) { - Utf8SymbolKey key(str); +MaybeObject* SymbolTable::LookupSymbol(Vector str, + Object** s) { + Utf8SymbolKey key(str, GetHeap()->StringHashSeed()); return LookupKey(&key, s); } MaybeObject* SymbolTable::LookupAsciiSymbol(Vector str, Object** s) { - AsciiSymbolKey key(str); + AsciiSymbolKey key(str, GetHeap()->StringHashSeed()); return LookupKey(&key, s); } @@ -11508,14 +11534,14 @@ MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle str, int from, int length, Object** s) { - SubStringAsciiSymbolKey key(str, from, length); + SubStringAsciiSymbolKey key(str, from, length, GetHeap()->StringHashSeed()); return LookupKey(&key, s); } MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector str, Object** s) { - TwoByteSymbolKey key(str); + TwoByteSymbolKey key(str, GetHeap()->StringHashSeed()); return LookupKey(&key, s); } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index a0e77cb86d..541334a5dc 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -6117,7 +6117,7 @@ enum RobustnessFlag {ROBUST_STRING_TRAVERSAL, FAST_STRING_TRAVERSAL}; class StringHasher { public: - explicit inline StringHasher(int length); + explicit inline StringHasher(int length, uint32_t seed); // Returns true if the hash of this string can be computed without // looking at the contents. @@ -6168,7 +6168,9 @@ class StringHasher { // Calculates string hash. template -inline uint32_t HashSequentialString(const schar* chars, int length); +inline uint32_t HashSequentialString(const schar* chars, + int length, + uint32_t seed); // The characteristics of a string are stored in its map. Retrieving these @@ -6391,7 +6393,8 @@ class String: public HeapObject { inline uint32_t Hash(); static uint32_t ComputeHashField(unibrow::CharacterStream* buffer, - int length); + int length, + uint32_t seed); static bool ComputeArrayIndex(unibrow::CharacterStream* buffer, uint32_t* index, @@ -6456,6 +6459,10 @@ class String: public HeapObject { // Shift constant retrieving hash code from hash field. static const int kHashShift = kNofHashBitFields; + // Only these bits are relevant in the hash, since the top two are shifted + // out. + static const uint32_t kHashBitMask = 0xffffffffu >> kHashShift; + // Array index strings this short can keep their index in the hash // field. static const int kMaxCachedArrayIndexLength = 7; diff --git a/deps/v8/src/platform-openbsd.cc b/deps/v8/src/platform-openbsd.cc index b3f4924eee..772d08b587 100644 --- a/deps/v8/src/platform-openbsd.cc +++ b/deps/v8/src/platform-openbsd.cc @@ -25,8 +25,8 @@ // (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. +// Platform specific code for OpenBSD and NetBSD goes here. For the POSIX +// comaptible parts the implementation is in platform-posix.cc. #include #include @@ -742,8 +742,20 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { if (sample == NULL) sample = &sample_obj; // Extracting the sample from the context is extremely machine dependent. - ucontext_t* ucontext = reinterpret_cast(context); sample->state = isolate->current_vm_state(); + ucontext_t* ucontext = reinterpret_cast(context); +#ifdef __NetBSD__ + mcontext_t& mcontext = ucontext->uc_mcontext; +#if V8_HOST_ARCH_IA32 + sample->pc = reinterpret_cast
(mcontext.__gregs[_REG_EIP]); + sample->sp = reinterpret_cast
(mcontext.__gregs[_REG_ESP]); + sample->fp = reinterpret_cast
(mcontext.__gregs[_REG_EBP]); +#elif V8_HOST_ARCH_X64 + sample->pc = reinterpret_cast
(mcontext.__gregs[_REG_RIP]); + sample->sp = reinterpret_cast
(mcontext.__gregs[_REG_RSP]); + sample->fp = reinterpret_cast
(mcontext.__gregs[_REG_RBP]); +#endif // V8_HOST_ARCH +#else // OpenBSD #if V8_HOST_ARCH_IA32 sample->pc = reinterpret_cast
(ucontext->sc_eip); sample->sp = reinterpret_cast
(ucontext->sc_esp); @@ -752,7 +764,8 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { sample->pc = reinterpret_cast
(ucontext->sc_rip); sample->sp = reinterpret_cast
(ucontext->sc_rsp); sample->fp = reinterpret_cast
(ucontext->sc_rbp); -#endif +#endif // V8_HOST_ARCH +#endif // __NetBSD__ sampler->SampleStack(sample); sampler->Tick(sample); } diff --git a/deps/v8/src/platform-posix.cc b/deps/v8/src/platform-posix.cc index a59d0bbdc3..08417ff9bc 100644 --- a/deps/v8/src/platform-posix.cc +++ b/deps/v8/src/platform-posix.cc @@ -71,7 +71,8 @@ intptr_t OS::MaxVirtualMemory() { intptr_t OS::CommitPageSize() { - return 4096; + static intptr_t page_size = getpagesize(); + return page_size; } diff --git a/deps/v8/src/profile-generator.cc b/deps/v8/src/profile-generator.cc index a46122be67..00fc7b736a 100644 --- a/deps/v8/src/profile-generator.cc +++ b/deps/v8/src/profile-generator.cc @@ -110,7 +110,8 @@ const char* StringsStorage::GetCopy(const char* src) { Vector dst = Vector::New(len + 1); OS::StrNCpy(dst, src, len); dst[len] = '\0'; - uint32_t hash = HashSequentialString(dst.start(), len); + uint32_t hash = + HashSequentialString(dst.start(), len, HEAP->StringHashSeed()); return AddOrDisposeString(dst.start(), hash); } @@ -143,7 +144,8 @@ const char* StringsStorage::GetVFormatted(const char* format, va_list args) { DeleteArray(str.start()); return format; } - uint32_t hash = HashSequentialString(str.start(), len); + uint32_t hash = HashSequentialString( + str.start(), len, HEAP->StringHashSeed()); return AddOrDisposeString(str.start(), hash); } @@ -153,7 +155,8 @@ const char* StringsStorage::GetName(String* name) { int length = Min(kMaxNameSize, name->length()); SmartArrayPointer data = name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length); - uint32_t hash = HashSequentialString(*data, length); + uint32_t hash = + HashSequentialString(*data, length, name->GetHeap()->StringHashSeed()); return AddOrDisposeString(data.Detach(), hash); } return ""; @@ -1501,7 +1504,9 @@ void HeapObjectsMap::RemoveDeadEntries() { uint64_t HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) { uint64_t id = static_cast(info->GetHash()); const char* label = info->GetLabel(); - id ^= HashSequentialString(label, static_cast(strlen(label))); + id ^= HashSequentialString(label, + static_cast(strlen(label)), + HEAP->StringHashSeed()); intptr_t element_count = info->GetElementCount(); if (element_count != -1) id ^= ComputeIntegerHash(static_cast(element_count)); diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index fb46114f66..811d72d91d 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -8707,14 +8707,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) { RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) { HandleScope scope(isolate); ASSERT(args.length() == 5); - CONVERT_CHECKED(JSReceiver, fun, args[0]); - Object* receiver = args[1]; - CONVERT_CHECKED(JSObject, arguments, args[2]); - CONVERT_CHECKED(Smi, shift, args[3]); - CONVERT_CHECKED(Smi, arity, args[4]); - - int offset = shift->value(); - int argc = arity->value(); + CONVERT_ARG_CHECKED(JSReceiver, fun, 0); + Handle receiver = args.at(1); + CONVERT_ARG_CHECKED(JSObject, arguments, 2); + CONVERT_SMI_ARG_CHECKED(offset, 3); + CONVERT_SMI_ARG_CHECKED(argc, 4); ASSERT(offset >= 0); ASSERT(argc >= 0); @@ -8730,17 +8727,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) { } for (int i = 0; i < argc; ++i) { - MaybeObject* maybe = arguments->GetElement(offset + i); - Object* object; - if (!maybe->To(&object)) return maybe; - argv[i] = Handle(object); + argv[i] = Object::GetElement(arguments, offset + i); } bool threw; - Handle hfun(fun); - Handle hreceiver(receiver); Handle result = - Execution::Call(hfun, hreceiver, argc, argv, &threw, true); + Execution::Call(fun, receiver, argc, argv, &threw, true); if (threw) return Failure::Exception(); return *result; diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index 84b0f1bcb4..ebd3e65192 100644 --- a/deps/v8/src/spaces.cc +++ b/deps/v8/src/spaces.cc @@ -1256,24 +1256,29 @@ bool SemiSpace::ShrinkTo(int new_capacity) { ASSERT((new_capacity & Page::kPageAlignmentMask) == 0); ASSERT(new_capacity >= initial_capacity_); ASSERT(new_capacity < capacity_); - // Semispaces grow backwards from the end of their allocated capacity, - // so we find the before and after start addresses relative to the - // end of the space. - Address space_end = start_ + maximum_capacity_; - Address old_start = space_end - capacity_; - size_t delta = capacity_ - new_capacity; - ASSERT(IsAligned(delta, OS::AllocateAlignment())); - if (!heap()->isolate()->memory_allocator()->UncommitBlock(old_start, delta)) { - return false; + if (is_committed()) { + // Semispaces grow backwards from the end of their allocated capacity, + // so we find the before and after start addresses relative to the + // end of the space. + Address space_end = start_ + maximum_capacity_; + Address old_start = space_end - capacity_; + size_t delta = capacity_ - new_capacity; + ASSERT(IsAligned(delta, OS::AllocateAlignment())); + + MemoryAllocator* allocator = heap()->isolate()->memory_allocator(); + if (!allocator->UncommitBlock(old_start, delta)) { + return false; + } + + int pages_after = new_capacity / Page::kPageSize; + NewSpacePage* new_last_page = + NewSpacePage::FromAddress(space_end - pages_after * Page::kPageSize); + new_last_page->set_next_page(anchor()); + anchor()->set_prev_page(new_last_page); + ASSERT((current_page_ <= first_page()) && (current_page_ >= new_last_page)); } - capacity_ = new_capacity; - int pages_after = capacity_ / Page::kPageSize; - NewSpacePage* new_last_page = - NewSpacePage::FromAddress(space_end - pages_after * Page::kPageSize); - new_last_page->set_next_page(anchor()); - anchor()->set_prev_page(new_last_page); - ASSERT((current_page_ <= first_page()) && (current_page_ >= new_last_page)); + capacity_ = new_capacity; return true; } diff --git a/deps/v8/src/store-buffer.cc b/deps/v8/src/store-buffer.cc index c0315f27a8..0f1fed0286 100644 --- a/deps/v8/src/store-buffer.cc +++ b/deps/v8/src/store-buffer.cc @@ -49,8 +49,9 @@ StoreBuffer::StoreBuffer(Heap* heap) callback_(NULL), may_move_store_buffer_entries_(true), virtual_memory_(NULL), - hash_map_1_(NULL), - hash_map_2_(NULL) { + hash_set_1_(NULL), + hash_set_2_(NULL), + hash_sets_are_empty_(true) { } @@ -97,18 +98,19 @@ void StoreBuffer::Setup() { false)); // Not executable. heap_->public_set_store_buffer_top(start_); - hash_map_1_ = new uintptr_t[kHashMapLength]; - hash_map_2_ = new uintptr_t[kHashMapLength]; + hash_set_1_ = new uintptr_t[kHashSetLength]; + hash_set_2_ = new uintptr_t[kHashSetLength]; + hash_sets_are_empty_ = false; - ZapHashTables(); + ClearFilteringHashSets(); } void StoreBuffer::TearDown() { delete virtual_memory_; delete old_virtual_memory_; - delete[] hash_map_1_; - delete[] hash_map_2_; + delete[] hash_set_1_; + delete[] hash_set_2_; old_start_ = old_top_ = old_limit_ = old_reserved_limit_ = NULL; start_ = limit_ = NULL; heap_->public_set_store_buffer_top(start_); @@ -148,7 +150,6 @@ static int CompareAddresses(const void* void_a, const void* void_b) { void StoreBuffer::Uniq() { - ASSERT(HashTablesAreZapped()); // Remove adjacent duplicates and cells that do not point at new space. Address previous = NULL; Address* write = old_start_; @@ -272,13 +273,16 @@ void StoreBuffer::Filter(int flag) { } } old_top_ = new_top; + + // Filtering hash sets are inconsistent with the store buffer after this + // operation. + ClearFilteringHashSets(); } void StoreBuffer::SortUniq() { Compact(); if (old_buffer_is_sorted_) return; - ZapHashTables(); qsort(reinterpret_cast(old_start_), old_top_ - old_start_, sizeof(*old_top_), @@ -286,6 +290,10 @@ void StoreBuffer::SortUniq() { Uniq(); old_buffer_is_sorted_ = true; + + // Filtering hash sets are inconsistent with the store buffer after this + // operation. + ClearFilteringHashSets(); } @@ -301,35 +309,23 @@ bool StoreBuffer::PrepareForIteration() { if (page_has_scan_on_scavenge_flag) { Filter(MemoryChunk::SCAN_ON_SCAVENGE); } - ZapHashTables(); + + // Filtering hash sets are inconsistent with the store buffer after + // iteration. + ClearFilteringHashSets(); + return page_has_scan_on_scavenge_flag; } #ifdef DEBUG void StoreBuffer::Clean() { - ZapHashTables(); + ClearFilteringHashSets(); Uniq(); // Also removes things that no longer point to new space. CheckForFullBuffer(); } -static bool Zapped(char* start, int size) { - for (int i = 0; i < size; i++) { - if (start[i] != 0) return false; - } - return true; -} - - -bool StoreBuffer::HashTablesAreZapped() { - return Zapped(reinterpret_cast(hash_map_1_), - sizeof(uintptr_t) * kHashMapLength) && - Zapped(reinterpret_cast(hash_map_2_), - sizeof(uintptr_t) * kHashMapLength); -} - - static Address* in_store_buffer_1_element_cache = NULL; @@ -357,18 +353,21 @@ bool StoreBuffer::CellIsInStoreBuffer(Address cell_address) { #endif -void StoreBuffer::ZapHashTables() { - memset(reinterpret_cast(hash_map_1_), - 0, - sizeof(uintptr_t) * kHashMapLength); - memset(reinterpret_cast(hash_map_2_), - 0, - sizeof(uintptr_t) * kHashMapLength); +void StoreBuffer::ClearFilteringHashSets() { + if (!hash_sets_are_empty_) { + memset(reinterpret_cast(hash_set_1_), + 0, + sizeof(uintptr_t) * kHashSetLength); + memset(reinterpret_cast(hash_set_2_), + 0, + sizeof(uintptr_t) * kHashSetLength); + hash_sets_are_empty_ = true; + } } void StoreBuffer::GCPrologue() { - ZapHashTables(); + ClearFilteringHashSets(); during_gc_ = true; } @@ -676,8 +675,9 @@ void StoreBuffer::Compact() { ASSERT(may_move_store_buffer_entries_); // Goes through the addresses in the store buffer attempting to remove // duplicates. In the interest of speed this is a lossy operation. Some - // duplicates will remain. We have two hash tables with different hash + // duplicates will remain. We have two hash sets with different hash // functions to reduce the number of unnecessary clashes. + hash_sets_are_empty_ = false; // Hash sets are in use. for (Address* current = start_; current < top; current++) { ASSERT(!heap_->cell_space()->Contains(*current)); ASSERT(!heap_->code_space()->Contains(*current)); @@ -686,21 +686,21 @@ void StoreBuffer::Compact() { // Shift out the last bits including any tags. int_addr >>= kPointerSizeLog2; int hash1 = - ((int_addr ^ (int_addr >> kHashMapLengthLog2)) & (kHashMapLength - 1)); - if (hash_map_1_[hash1] == int_addr) continue; - int hash2 = - ((int_addr - (int_addr >> kHashMapLengthLog2)) & (kHashMapLength - 1)); - hash2 ^= hash2 >> (kHashMapLengthLog2 * 2); - if (hash_map_2_[hash2] == int_addr) continue; - if (hash_map_1_[hash1] == 0) { - hash_map_1_[hash1] = int_addr; - } else if (hash_map_2_[hash2] == 0) { - hash_map_2_[hash2] = int_addr; + ((int_addr ^ (int_addr >> kHashSetLengthLog2)) & (kHashSetLength - 1)); + if (hash_set_1_[hash1] == int_addr) continue; + uintptr_t hash2 = (int_addr - (int_addr >> kHashSetLengthLog2)); + hash2 ^= hash2 >> (kHashSetLengthLog2 * 2); + hash2 &= (kHashSetLength - 1); + if (hash_set_2_[hash2] == int_addr) continue; + if (hash_set_1_[hash1] == 0) { + hash_set_1_[hash1] = int_addr; + } else if (hash_set_2_[hash2] == 0) { + hash_set_2_[hash2] = int_addr; } else { // Rather than slowing down we just throw away some entries. This will // cause some duplicates to remain undetected. - hash_map_1_[hash1] = int_addr; - hash_map_2_[hash2] = 0; + hash_set_1_[hash1] = int_addr; + hash_set_2_[hash2] = 0; } old_buffer_is_sorted_ = false; old_buffer_is_filtered_ = false; diff --git a/deps/v8/src/store-buffer.h b/deps/v8/src/store-buffer.h index ab2593808f..204fa3ff4e 100644 --- a/deps/v8/src/store-buffer.h +++ b/deps/v8/src/store-buffer.h @@ -85,8 +85,8 @@ class StoreBuffer { static const int kStoreBufferSize = kStoreBufferOverflowBit; static const int kStoreBufferLength = kStoreBufferSize / sizeof(Address); static const int kOldStoreBufferLength = kStoreBufferLength * 16; - static const int kHashMapLengthLog2 = 12; - static const int kHashMapLength = 1 << kHashMapLengthLog2; + static const int kHashSetLengthLog2 = 12; + static const int kHashSetLength = 1 << kHashSetLengthLog2; void Compact(); @@ -148,13 +148,18 @@ class StoreBuffer { bool may_move_store_buffer_entries_; VirtualMemory* virtual_memory_; - uintptr_t* hash_map_1_; - uintptr_t* hash_map_2_; + + // Two hash sets used for filtering. + // If address is in the hash set then it is guaranteed to be in the + // old part of the store buffer. + uintptr_t* hash_set_1_; + uintptr_t* hash_set_2_; + bool hash_sets_are_empty_; + + void ClearFilteringHashSets(); void CheckForFullBuffer(); void Uniq(); - void ZapHashTables(); - bool HashTablesAreZapped(); void ExemptPopularPages(int prime_sample_step, int threshold); void FindPointersToNewSpaceInRegion(Address start, diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc index 0354fc101a..c882d86f8d 100644 --- a/deps/v8/src/v8.cc +++ b/deps/v8/src/v8.cc @@ -51,6 +51,7 @@ bool V8::has_been_setup_ = false; bool V8::has_been_disposed_ = false; bool V8::has_fatal_error_ = false; bool V8::use_crankshaft_ = true; +List* V8::call_completed_callbacks_ = NULL; static Mutex* entropy_mutex = OS::CreateMutex(); static EntropySource entropy_source; @@ -104,6 +105,9 @@ void V8::TearDown() { is_running_ = false; has_been_disposed_ = true; + + delete call_completed_callbacks_; + call_completed_callbacks_ = NULL; } @@ -169,6 +173,41 @@ bool V8::IdleNotification(int hint) { } +void V8::AddCallCompletedCallback(CallCompletedCallback callback) { + if (call_completed_callbacks_ == NULL) { // Lazy init. + call_completed_callbacks_ = new List(); + } + for (int i = 0; i < call_completed_callbacks_->length(); i++) { + if (callback == call_completed_callbacks_->at(i)) return; + } + call_completed_callbacks_->Add(callback); +} + + +void V8::RemoveCallCompletedCallback(CallCompletedCallback callback) { + if (call_completed_callbacks_ == NULL) return; + for (int i = 0; i < call_completed_callbacks_->length(); i++) { + if (callback == call_completed_callbacks_->at(i)) { + call_completed_callbacks_->Remove(i); + } + } +} + + +void V8::FireCallCompletedCallback(Isolate* isolate) { + if (call_completed_callbacks_ == NULL) return; + HandleScopeImplementer* handle_scope_implementer = + isolate->handle_scope_implementer(); + if (!handle_scope_implementer->CallDepthIsZero()) return; + // Fire callbacks. Increase call depth to prevent recursive callbacks. + handle_scope_implementer->IncrementCallDepth(); + for (int i = 0; i < call_completed_callbacks_->length(); i++) { + call_completed_callbacks_->at(i)(); + } + handle_scope_implementer->DecrementCallDepth(); +} + + // Use a union type to avoid type-aliasing optimizations in GCC. typedef union { double double_value; diff --git a/deps/v8/src/v8.h b/deps/v8/src/v8.h index 71e7fe4bf4..b9a3e05386 100644 --- a/deps/v8/src/v8.h +++ b/deps/v8/src/v8.h @@ -108,6 +108,10 @@ class V8 : public AllStatic { // Idle notification directly from the API. static bool IdleNotification(int hint); + static void AddCallCompletedCallback(CallCompletedCallback callback); + static void RemoveCallCompletedCallback(CallCompletedCallback callback); + static void FireCallCompletedCallback(Isolate* isolate); + private: static void InitializeOncePerProcess(); @@ -123,6 +127,8 @@ class V8 : public AllStatic { static bool has_been_disposed_; // True if we are using the crankshaft optimizing compiler. static bool use_crankshaft_; + // List of callbacks when a Call completes. + static List* call_completed_callbacks_; }; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 46b2b1a3d5..617b7d1c50 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 8 -#define BUILD_NUMBER 4 +#define BUILD_NUMBER 5 #define PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/x64/builtins-x64.cc b/deps/v8/src/x64/builtins-x64.cc index dff55fb74d..ef63c7a27b 100644 --- a/deps/v8/src/x64/builtins-x64.cc +++ b/deps/v8/src/x64/builtins-x64.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -1199,7 +1199,8 @@ static void AllocateJSArray(MacroAssembler* masm, // a construct call and a normal call. static void ArrayNativeCode(MacroAssembler* masm, Label *call_generic_code) { - Label argc_one_or_more, argc_two_or_more, empty_array, not_empty_array; + Label argc_one_or_more, argc_two_or_more, empty_array, not_empty_array, + has_non_smi_element; // Check for array construction with zero arguments. __ testq(rax, rax); @@ -1306,7 +1307,7 @@ static void ArrayNativeCode(MacroAssembler* masm, __ bind(&loop); __ movq(kScratchRegister, Operand(r9, rcx, times_pointer_size, 0)); if (FLAG_smi_only_arrays) { - __ JumpIfNotSmi(kScratchRegister, call_generic_code); + __ JumpIfNotSmi(kScratchRegister, &has_non_smi_element); } __ movq(Operand(rdx, 0), kScratchRegister); __ addq(rdx, Immediate(kPointerSize)); @@ -1324,6 +1325,10 @@ static void ArrayNativeCode(MacroAssembler* masm, __ push(rcx); __ movq(rax, rbx); __ ret(0); + + __ bind(&has_non_smi_element); + __ UndoAllocationInNewSpace(rbx); + __ jmp(call_generic_code); } diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 1d67bae60a..ea9c494e8a 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -4958,10 +4958,13 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, Register hash, Register character, Register scratch) { - // hash = character + (character << 10); - __ movl(hash, character); - __ shll(hash, Immediate(10)); - __ addl(hash, character); + // hash = (seed + character) + ((seed + character) << 10); + __ LoadRoot(scratch, Heap::kStringHashSeedRootIndex); + __ SmiToInteger32(scratch, scratch); + __ addl(scratch, character); + __ movl(hash, scratch); + __ shll(scratch, Immediate(10)); + __ addl(hash, scratch); // hash ^= hash >> 6; __ movl(scratch, hash); __ shrl(scratch, Immediate(6)); diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index dab8b7c286..fb8becda38 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -14238,7 +14238,7 @@ THREADED_TEST(RoundRobinGetFromCache) { " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" " for (var i = 0; i < 16; i++) {" " var v = %_GetFromCache(0, keys[i]);" - " if (v !== values[i])" + " if (v.toString() !== values[i].toString())" " return 'Wrong value for ' + " " keys[i] + ': ' + v + ' vs. ' + values[i];" " };" @@ -15726,3 +15726,98 @@ THREADED_TEST(ForeignFunctionReceiver) { foreign_context.Dispose(); } + + +uint8_t callback_fired = 0; + + +void CallCompletedCallback1() { + i::OS::Print("Firing callback 1.\n"); + callback_fired ^= 1; // Toggle first bit. +} + + +void CallCompletedCallback2() { + i::OS::Print("Firing callback 2.\n"); + callback_fired ^= 2; // Toggle second bit. +} + + +Handle RecursiveCall(const Arguments& args) { + int32_t level = args[0]->Int32Value(); + if (level < 3) { + level++; + i::OS::Print("Entering recursion level %d.\n", level); + char script[64]; + i::Vector script_vector(script, sizeof(script)); + i::OS::SNPrintF(script_vector, "recursion(%d)", level); + CompileRun(script_vector.start()); + i::OS::Print("Leaving recursion level %d.\n", level); + CHECK_EQ(0, callback_fired); + } else { + i::OS::Print("Recursion ends.\n"); + CHECK_EQ(0, callback_fired); + } + return Undefined(); +} + + +TEST(CallCompletedCallback) { + v8::HandleScope scope; + LocalContext env; + v8::Handle recursive_runtime = + v8::FunctionTemplate::New(RecursiveCall); + env->Global()->Set(v8_str("recursion"), + recursive_runtime->GetFunction()); + // Adding the same callback a second time has no effect. + v8::V8::AddCallCompletedCallback(CallCompletedCallback1); + v8::V8::AddCallCompletedCallback(CallCompletedCallback1); + v8::V8::AddCallCompletedCallback(CallCompletedCallback2); + i::OS::Print("--- Script (1) ---\n"); + Local