From e72b7b8002c487d32f3a651687acca13f2009b99 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 23 Apr 2010 12:05:36 -0700 Subject: [PATCH] Upgrade V8 to 2.2.4.2 --- deps/v8/ChangeLog | 9 + deps/v8/SConstruct | 30 +- deps/v8/include/v8.h | 2 + deps/v8/src/api.cc | 16 +- deps/v8/src/arm/codegen-arm.cc | 490 ++++++++++- deps/v8/src/arm/codegen-arm.h | 11 +- deps/v8/src/arm/full-codegen-arm.cc | 3 +- deps/v8/src/arm/macro-assembler-arm.cc | 92 +- deps/v8/src/arm/macro-assembler-arm.h | 4 +- deps/v8/src/arm/regexp-macro-assembler-arm.cc | 11 +- deps/v8/src/arm/regexp-macro-assembler-arm.h | 6 +- deps/v8/src/arm/simulator-arm.cc | 25 +- deps/v8/src/arm/stub-cache-arm.cc | 88 +- deps/v8/src/arm/virtual-frame-arm.cc | 3 + deps/v8/src/arm/virtual-frame-arm.h | 11 +- deps/v8/src/array.js | 8 +- deps/v8/src/assembler.cc | 8 +- deps/v8/src/assembler.h | 2 +- deps/v8/src/bootstrapper.cc | 41 + deps/v8/src/codegen.h | 4 +- deps/v8/src/compilation-cache.cc | 2 +- deps/v8/src/compilation-cache.h | 17 +- deps/v8/src/compiler.cc | 2 +- deps/v8/src/contexts.h | 2 + deps/v8/src/cpu-profiler-inl.h | 5 +- deps/v8/src/cpu-profiler.cc | 26 +- deps/v8/src/cpu-profiler.h | 8 +- deps/v8/src/d8-debug.cc | 19 +- deps/v8/src/d8.cc | 2 +- deps/v8/src/d8.h | 1 + deps/v8/src/d8.js | 11 +- deps/v8/src/debug-debugger.js | 6 +- deps/v8/src/execution.cc | 3 - deps/v8/src/factory.cc | 7 +- deps/v8/src/factory.h | 4 +- deps/v8/src/flag-definitions.h | 4 +- deps/v8/src/globals.h | 9 +- deps/v8/src/handles.cc | 32 +- deps/v8/src/handles.h | 5 + deps/v8/src/heap-inl.h | 4 +- deps/v8/src/heap.cc | 64 +- deps/v8/src/heap.h | 13 +- deps/v8/src/ia32/codegen-ia32.cc | 523 ++++++----- deps/v8/src/ia32/codegen-ia32.h | 103 ++- deps/v8/src/ia32/full-codegen-ia32.cc | 3 +- deps/v8/src/ia32/ic-ia32.cc | 75 +- deps/v8/src/ia32/macro-assembler-ia32.cc | 62 +- deps/v8/src/ia32/macro-assembler-ia32.h | 3 + .../src/ia32/regexp-macro-assembler-ia32.cc | 4 +- .../v8/src/ia32/regexp-macro-assembler-ia32.h | 6 +- deps/v8/src/ia32/stub-cache-ia32.cc | 82 +- deps/v8/src/ic.cc | 7 +- deps/v8/src/jsregexp.cc | 34 +- deps/v8/src/jsregexp.h | 6 +- deps/v8/src/liveedit-debugger.js | 824 +++++++++--------- deps/v8/src/liveedit.cc | 352 ++++++++ deps/v8/src/liveedit.h | 38 + deps/v8/src/log-inl.h | 4 - deps/v8/src/log.h | 20 +- deps/v8/src/macros.py | 3 + deps/v8/src/mips/simulator-mips.cc | 4 +- deps/v8/src/objects-debug.cc | 1 - deps/v8/src/objects-inl.h | 26 +- deps/v8/src/objects.cc | 8 +- deps/v8/src/objects.h | 44 +- deps/v8/src/parser.cc | 4 +- deps/v8/src/platform-linux.cc | 7 +- deps/v8/src/platform-macos.cc | 5 +- deps/v8/src/platform-win32.cc | 5 +- deps/v8/src/profile-generator-inl.h | 9 +- deps/v8/src/profile-generator.cc | 86 +- deps/v8/src/profile-generator.h | 69 +- .../src/regexp-macro-assembler-irregexp-inl.h | 4 +- .../v8/src/regexp-macro-assembler-irregexp.cc | 4 +- deps/v8/src/regexp-macro-assembler-irregexp.h | 4 +- deps/v8/src/regexp-macro-assembler.cc | 5 +- deps/v8/src/regexp-macro-assembler.h | 4 +- deps/v8/src/runtime.cc | 136 ++- deps/v8/src/runtime.h | 3 + deps/v8/src/serialize.cc | 4 +- deps/v8/src/serialize.h | 3 +- deps/v8/src/string.js | 14 +- deps/v8/src/stub-cache.cc | 32 + deps/v8/src/stub-cache.h | 13 + deps/v8/src/version.cc | 6 +- deps/v8/src/x64/assembler-x64.cc | 10 +- deps/v8/src/x64/builtins-x64.cc | 2 +- deps/v8/src/x64/codegen-x64.cc | 121 ++- deps/v8/src/x64/codegen-x64.h | 3 + deps/v8/src/x64/full-codegen-x64.cc | 3 +- deps/v8/src/x64/macro-assembler-x64.cc | 62 +- deps/v8/src/x64/macro-assembler-x64.h | 3 + deps/v8/src/x64/regexp-macro-assembler-x64.cc | 4 +- deps/v8/src/x64/regexp-macro-assembler-x64.h | 4 +- deps/v8/src/x64/stub-cache-x64.cc | 85 +- deps/v8/test/cctest/SConscript | 1 + deps/v8/test/cctest/test-cpu-profiler.cc | 6 +- deps/v8/test/cctest/test-debug.cc | 4 +- deps/v8/test/cctest/test-liveedit.cc | 174 ++++ deps/v8/test/cctest/test-profile-generator.cc | 59 +- deps/v8/test/cctest/test-regexp.cc | 14 +- deps/v8/test/mjsunit/debug-liveedit-1.js | 2 +- deps/v8/test/mjsunit/debug-liveedit-2.js | 2 +- .../mjsunit/debug-liveedit-check-stack.js | 4 +- deps/v8/test/mjsunit/debug-liveedit-diff.js | 100 +++ .../debug-liveedit-patch-positions-replace.js | 2 +- .../mjsunit/debug-liveedit-patch-positions.js | 4 +- deps/v8/test/mjsunit/fuzz-natives.js | 4 + deps/v8/test/mjsunit/regress/regress-675.js | 61 ++ deps/v8/test/mjsunit/regress/regress-681.js | 44 + deps/v8/test/mjsunit/string-index.js | 14 +- deps/v8/test/mjsunit/string-search.js | 10 + deps/v8/tools/gyp/v8.gyp | 4 - deps/v8/tools/v8.xcodeproj/project.pbxproj | 4 - deps/v8/tools/visual_studio/arm.vsprops | 2 +- deps/v8/tools/visual_studio/ia32.vsprops | 2 +- deps/v8/tools/visual_studio/x64.vsprops | 2 +- 117 files changed, 3466 insertions(+), 1109 deletions(-) create mode 100644 deps/v8/test/cctest/test-liveedit.cc create mode 100644 deps/v8/test/mjsunit/debug-liveedit-diff.js create mode 100644 deps/v8/test/mjsunit/regress/regress-675.js create mode 100644 deps/v8/test/mjsunit/regress/regress-681.js diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 2c0da0c6ed..93e878bc6b 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,12 @@ +2010-04-21: Version 2.3.4 + + Fixed warnings on arm on newer GCC versions. + + Fixed a number of minor bugs. + + Performance improvements on all platforms. + + 2010-04-14: Version 2.2.3 Added stack command and mem command to ARM simulator debugger. diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index 7242b37ae1..becf31dbfc 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -42,6 +42,18 @@ ANDROID_TOP = os.environ.get('TOP') if ANDROID_TOP is None: ANDROID_TOP="" +# ARM_TARGET_LIB is the path to the dynamic library to use on the target +# machine if cross-compiling to an arm machine. You will also need to set +# the additional cross-compiling environment variables to the cross compiler. +ARM_TARGET_LIB = os.environ.get('ARM_TARGET_LIB') +if ARM_TARGET_LIB: + ARM_LINK_FLAGS = ['-Wl,-rpath=' + ARM_TARGET_LIB + '/lib:' + + ARM_TARGET_LIB + '/usr/lib', + '-Wl,--dynamic-linker=' + ARM_TARGET_LIB + + '/lib/ld-linux.so.3'] +else: + ARM_LINK_FLAGS = [] + # TODO: Sort these issues out properly but as a temporary solution for gcc 4.4 # on linux we need these compiler flags to avoid crashes in the v8 test suite # and avoid dtoa.c strict aliasing issues @@ -99,8 +111,8 @@ ANDROID_LINKFLAGS = ['-nostdlib', LIBRARY_FLAGS = { 'all': { 'CPPPATH': [join(root_dir, 'src')], - 'regexp:native': { - 'CPPDEFINES': ['V8_NATIVE_REGEXP'] + 'regexp:interpreted': { + 'CPPDEFINES': ['V8_INTERPRETED_REGEXP'] }, 'mode:debug': { 'CPPDEFINES': ['V8_ENABLE_CHECKS'] @@ -114,9 +126,6 @@ LIBRARY_FLAGS = { 'profilingsupport:on': { 'CPPDEFINES': ['ENABLE_VMSTATE_TRACKING', 'ENABLE_LOGGING_AND_PROFILING'], }, - 'cppprofilesprocessor:on': { - 'CPPDEFINES': ['ENABLE_CPP_PROFILES_PROCESSOR'], - }, 'debuggersupport:on': { 'CPPDEFINES': ['ENABLE_DEBUGGER_SUPPORT'], } @@ -419,6 +428,9 @@ CCTEST_EXTRA_FLAGS = { 'CPPDEFINES': ['SK_RELEASE', 'NDEBUG'] } }, + 'arch:arm': { + 'LINKFLAGS': ARM_LINK_FLAGS + }, }, 'msvc': { 'all': { @@ -483,6 +495,9 @@ SAMPLE_FLAGS = { 'CPPDEFINES': ['SK_RELEASE', 'NDEBUG'] } }, + 'arch:arm': { + 'LINKFLAGS': ARM_LINK_FLAGS + }, 'arch:ia32': { 'CCFLAGS': ['-m32'], 'LINKFLAGS': ['-m32'] @@ -695,11 +710,6 @@ SIMPLE_OPTIONS = { 'default': 'on', 'help': 'enable profiling of JavaScript code' }, - 'cppprofilesprocessor': { - 'values': ['on', 'off'], - 'default': 'on', - 'help': 'enable C++ profiles processor' - }, 'debuggersupport': { 'values': ['on', 'off'], 'default': 'on', diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index d90289ab99..49417673a2 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -856,6 +856,8 @@ class V8EXPORT String : public Primitive { * copying begins. * \param length The number of bytes to copy from the string. * \param nchars_ref The number of characters written, can be NULL. + * \param hints Various hints that might affect performance of this or + * subsequent operations. * \return The number of bytes copied to the buffer * excluding the NULL terminator. */ diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 47950ebe18..4752a44252 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -4027,7 +4027,7 @@ Local Debug::GetDebugContext() { #endif // ENABLE_DEBUGGER_SUPPORT -#ifdef ENABLE_CPP_PROFILES_PROCESSOR +#ifdef ENABLE_LOGGING_AND_PROFILING Handle CpuProfileNode::GetFunctionName() const { IsDeadCheck("v8::CpuProfileNode::GetFunctionName"); @@ -4058,6 +4058,18 @@ int CpuProfileNode::GetLineNumber() const { } +double CpuProfileNode::GetTotalTime() const { + IsDeadCheck("v8::CpuProfileNode::GetTotalTime"); + return reinterpret_cast(this)->GetTotalMillis(); +} + + +double CpuProfileNode::GetSelfTime() const { + IsDeadCheck("v8::CpuProfileNode::GetSelfTime"); + return reinterpret_cast(this)->GetSelfMillis(); +} + + double CpuProfileNode::GetTotalSamplesCount() const { IsDeadCheck("v8::CpuProfileNode::GetTotalSamplesCount"); return reinterpret_cast(this)->total_ticks(); @@ -4148,7 +4160,7 @@ const CpuProfile* CpuProfiler::StopProfiling(Handle title) { i::CpuProfiler::StopProfiling(*Utils::OpenHandle(*title))); } -#endif // ENABLE_CPP_PROFILES_PROCESSOR +#endif // ENABLE_LOGGING_AND_PROFILING namespace internal { diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 0fc7b6d1d6..b2fe05f5a3 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -32,7 +32,10 @@ #include "compiler.h" #include "debug.h" #include "ic-inl.h" +#include "jsregexp.h" #include "parser.h" +#include "regexp-macro-assembler.h" +#include "regexp-stack.h" #include "register-allocator-inl.h" #include "runtime.h" #include "scopes.h" @@ -130,6 +133,7 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm) allocator_(NULL), cc_reg_(al), state_(NULL), + loop_nesting_(0), function_return_is_shadowed_(false) { } @@ -153,6 +157,11 @@ void CodeGenerator::Generate(CompilationInfo* info) { ASSERT(frame_ == NULL); frame_ = new VirtualFrame(); cc_reg_ = al; + + // Adjust for function-level loop nesting. + ASSERT_EQ(0, loop_nesting_); + loop_nesting_ = info->loop_nesting(); + { CodeGenState state(this); @@ -377,6 +386,10 @@ void CodeGenerator::Generate(CompilationInfo* info) { masm_->InstructionsGeneratedSince(&check_exit_codesize)); } + // Adjust for function-level loop nesting. + ASSERT(loop_nesting_ == info->loop_nesting()); + loop_nesting_ = 0; + // Code generation state must be reset. ASSERT(!has_cc()); ASSERT(state_ == NULL); @@ -1882,6 +1895,7 @@ void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { CodeForStatementPosition(node); node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); JumpTarget body(JumpTarget::BIDIRECTIONAL); + IncrementLoopNesting(); // Label the top of the loop for the backward CFG edge. If the test // is always true we can use the continue target, and if the test is @@ -1942,6 +1956,7 @@ void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { if (node->break_target()->is_linked()) { node->break_target()->Bind(); } + DecrementLoopNesting(); ASSERT(!has_valid_frame() || frame_->height() == original_height); } @@ -1960,6 +1975,7 @@ void CodeGenerator::VisitWhileStatement(WhileStatement* node) { if (info == ALWAYS_FALSE) return; node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); + IncrementLoopNesting(); // Label the top of the loop with the continue target for the backward // CFG edge. @@ -1991,6 +2007,7 @@ void CodeGenerator::VisitWhileStatement(WhileStatement* node) { if (node->break_target()->is_linked()) { node->break_target()->Bind(); } + DecrementLoopNesting(); ASSERT(!has_valid_frame() || frame_->height() == original_height); } @@ -2012,6 +2029,7 @@ void CodeGenerator::VisitForStatement(ForStatement* node) { if (info == ALWAYS_FALSE) return; node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); + IncrementLoopNesting(); // If there is no update statement, label the top of the loop with the // continue target, otherwise with the loop target. @@ -2066,6 +2084,7 @@ void CodeGenerator::VisitForStatement(ForStatement* node) { if (node->break_target()->is_linked()) { node->break_target()->Bind(); } + DecrementLoopNesting(); ASSERT(!has_valid_frame() || frame_->height() == original_height); } @@ -4015,8 +4034,8 @@ void CodeGenerator::GenerateRegExpExec(ZoneList* args) { Load(args->at(1)); Load(args->at(2)); Load(args->at(3)); - - frame_->CallRuntime(Runtime::kRegExpExec, 4); + RegExpExecStub stub; + frame_->CallStub(&stub, 4); frame_->EmitPush(r0); } @@ -4115,6 +4134,72 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList* args) { } +class DeferredSearchCache: public DeferredCode { + public: + DeferredSearchCache(Register dst, Register cache, Register key) + : dst_(dst), cache_(cache), key_(key) { + set_comment("[ DeferredSearchCache"); + } + + virtual void Generate(); + + private: + Register dst_, cache_, key_; +}; + + +void DeferredSearchCache::Generate() { + __ push(cache_); + __ push(key_); + __ CallRuntime(Runtime::kGetFromCache, 2); + if (!dst_.is(r0)) { + __ mov(dst_, r0); + } +} + + +void CodeGenerator::GenerateGetFromCache(ZoneList* args) { + ASSERT_EQ(2, args->length()); + + ASSERT_NE(NULL, args->at(0)->AsLiteral()); + int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); + + Handle jsfunction_result_caches( + Top::global_context()->jsfunction_result_caches()); + if (jsfunction_result_caches->length() <= cache_id) { + __ Abort("Attempt to use undefined cache."); + __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); + frame_->EmitPush(r0); + return; + } + Handle cache_obj( + FixedArray::cast(jsfunction_result_caches->get(cache_id))); + + Load(args->at(1)); + frame_->EmitPop(r2); + + DeferredSearchCache* deferred = new DeferredSearchCache(r0, r1, r2); + + const int kFingerOffset = + FixedArray::OffsetOfElementAt(JSFunctionResultCache::kFingerIndex); + ASSERT(kSmiTag == 0 && kSmiTagSize == 1); + __ mov(r1, Operand(cache_obj)); + __ ldr(r0, FieldMemOperand(r1, kFingerOffset)); + // r0 now holds finger offset as a smi. + __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + // r3 now points to the start of fixed array elements. + __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize, PreIndex)); + // Note side effect of PreIndex: r3 now points to the key of the pair. + __ cmp(r2, r0); + deferred->Branch(ne); + + __ ldr(r0, MemOperand(r3, kPointerSize)); + + deferred->BindExit(); + frame_->EmitPush(r0); +} + + void CodeGenerator::GenerateNumberToString(ZoneList* args) { ASSERT_EQ(args->length(), 1); @@ -5586,8 +5671,10 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { } else { // Call a native function to do a comparison between two non-NaNs. // Call C routine that may not cause GC or other trouble. - __ mov(r5, Operand(ExternalReference::compare_doubles())); - __ Jump(r5); // Tail call. + __ push(lr); + __ PrepareCallCFunction(4, r5); // Two doubles count as 4 arguments. + __ CallCFunction(ExternalReference::compare_doubles(), 4); + __ pop(pc); // Return. } } @@ -5909,7 +5996,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1; bool use_fp_registers = CpuFeatures::IsSupported(VFP3) && Token::MOD != op_; - ASSERT((lhs.is(r0) && rhs.is(r1)) || lhs.is(r1) && rhs.is(r0)); + ASSERT((lhs.is(r0) && rhs.is(r1)) || (lhs.is(r1) && rhs.is(r0))); if (ShouldGenerateSmiCode()) { // Smi-smi case (overflow). @@ -7014,7 +7101,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_termination_exception, Label* throw_out_of_memory_exception, bool do_gc, - bool always_allocate) { + bool always_allocate, + int frame_alignment_skew) { // r0: result parameter for PerformGC, if any // r4: number of arguments including receiver (C callee-saved) // r5: pointer to builtin function (C callee-saved) @@ -7022,8 +7110,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, if (do_gc) { // Passing r0. - ExternalReference gc_reference = ExternalReference::perform_gc_function(); - __ Call(gc_reference.address(), RelocInfo::RUNTIME_ENTRY); + __ PrepareCallCFunction(1, r1); + __ CallCFunction(ExternalReference::perform_gc_function(), 1); } ExternalReference scope_depth = @@ -7040,6 +7128,37 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, __ mov(r0, Operand(r4)); __ mov(r1, Operand(r6)); + int frame_alignment = MacroAssembler::ActivationFrameAlignment(); + int frame_alignment_mask = frame_alignment - 1; +#if defined(V8_HOST_ARCH_ARM) + if (FLAG_debug_code) { + if (frame_alignment > kPointerSize) { + Label alignment_as_expected; + ASSERT(IsPowerOf2(frame_alignment)); + __ sub(r2, sp, Operand(frame_alignment_skew)); + __ tst(r2, Operand(frame_alignment_mask)); + __ b(eq, &alignment_as_expected); + // Don't use Check here, as it will call Runtime_Abort re-entering here. + __ stop("Unexpected alignment"); + __ bind(&alignment_as_expected); + } + } +#endif + + // Just before the call (jump) below lr is pushed, so the actual alignment is + // adding one to the current skew. + int alignment_before_call = + (frame_alignment_skew + kPointerSize) & frame_alignment_mask; + if (alignment_before_call > 0) { + // Push until the alignment before the call is met. + __ mov(r2, Operand(0)); + for (int i = alignment_before_call; + (i & frame_alignment_mask) != 0; + i += kPointerSize) { + __ push(r2); + } + } + // TODO(1242173): To let the GC traverse the return address of the exit // frames, we need to know where the return address is. Right now, // we push it on the stack to be able to find it again, but we never @@ -7047,10 +7166,15 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // support moving the C entry code stub. This should be fixed, but currently // this is OK because the CEntryStub gets generated so early in the V8 boot // sequence that it is not moving ever. - masm->add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4 + masm->add(lr, pc, Operand(4)); // Compute return address: (pc + 8) + 4 masm->push(lr); masm->Jump(r5); + // Restore sp back to before aligning the stack. + if (alignment_before_call > 0) { + __ add(sp, sp, Operand(alignment_before_call)); + } + if (always_allocate) { // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 // though (contain the result). @@ -7137,7 +7261,8 @@ void CEntryStub::Generate(MacroAssembler* masm) { &throw_termination_exception, &throw_out_of_memory_exception, false, - false); + false, + -kPointerSize); // Do space-specific GC and retry runtime call. GenerateCore(masm, @@ -7145,7 +7270,8 @@ void CEntryStub::Generate(MacroAssembler* masm) { &throw_termination_exception, &throw_out_of_memory_exception, true, - false); + false, + 0); // Do full GC and retry runtime call one final time. Failure* failure = Failure::InternalError(); @@ -7155,7 +7281,8 @@ void CEntryStub::Generate(MacroAssembler* masm) { &throw_termination_exception, &throw_out_of_memory_exception, true, - true); + true, + kPointerSize); __ bind(&throw_out_of_memory_exception); GenerateThrowUncatchable(masm, OUT_OF_MEMORY); @@ -7502,6 +7629,345 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { } +void RegExpExecStub::Generate(MacroAssembler* masm) { + // Just jump directly to runtime if native RegExp is not selected at compile + // time or if regexp entry in generated code is turned off runtime switch or + // at compilation. +#ifndef V8_NATIVE_REGEXP + __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); +#else // V8_NATIVE_REGEXP + if (!FLAG_regexp_entry_native) { + __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); + return; + } + + // Stack frame on entry. + // sp[0]: last_match_info (expected JSArray) + // sp[4]: previous index + // sp[8]: subject string + // sp[12]: JSRegExp object + + static const int kLastMatchInfoOffset = 0 * kPointerSize; + static const int kPreviousIndexOffset = 1 * kPointerSize; + static const int kSubjectOffset = 2 * kPointerSize; + static const int kJSRegExpOffset = 3 * kPointerSize; + + Label runtime, invoke_regexp; + + // Allocation of registers for this function. These are in callee save + // registers and will be preserved by the call to the native RegExp code, as + // this code is called using the normal C calling convention. When calling + // directly from generated code the native RegExp code will not do a GC and + // therefore the content of these registers are safe to use after the call. + Register subject = r4; + Register regexp_data = r5; + Register last_match_info_elements = r6; + + // Ensure that a RegExp stack is allocated. + ExternalReference address_of_regexp_stack_memory_address = + ExternalReference::address_of_regexp_stack_memory_address(); + ExternalReference address_of_regexp_stack_memory_size = + ExternalReference::address_of_regexp_stack_memory_size(); + __ mov(r0, Operand(address_of_regexp_stack_memory_size)); + __ ldr(r0, MemOperand(r0, 0)); + __ tst(r0, Operand(r0)); + __ b(eq, &runtime); + + // Check that the first argument is a JSRegExp object. + __ ldr(r0, MemOperand(sp, kJSRegExpOffset)); + ASSERT_EQ(0, kSmiTag); + __ tst(r0, Operand(kSmiTagMask)); + __ b(eq, &runtime); + __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); + __ b(ne, &runtime); + + // Check that the RegExp has been compiled (data contains a fixed array). + __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); + if (FLAG_debug_code) { + __ tst(regexp_data, Operand(kSmiTagMask)); + __ Check(nz, "Unexpected type for RegExp data, FixedArray expected"); + __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); + __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); + } + + // regexp_data: RegExp data (FixedArray) + // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. + __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); + __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); + __ b(ne, &runtime); + + // regexp_data: RegExp data (FixedArray) + // Check that the number of captures fit in the static offsets vector buffer. + __ ldr(r2, + FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); + // Calculate number of capture registers (number_of_captures + 1) * 2. This + // uses the asumption that smis are 2 * their untagged value. + ASSERT_EQ(0, kSmiTag); + ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); + __ add(r2, r2, Operand(2)); // r2 was a smi. + // Check that the static offsets vector buffer is large enough. + __ cmp(r2, Operand(OffsetsVector::kStaticOffsetsVectorSize)); + __ b(hi, &runtime); + + // r2: Number of capture registers + // regexp_data: RegExp data (FixedArray) + // Check that the second argument is a string. + __ ldr(subject, MemOperand(sp, kSubjectOffset)); + __ tst(subject, Operand(kSmiTagMask)); + __ b(eq, &runtime); + Condition is_string = masm->IsObjectStringType(subject, r0); + __ b(NegateCondition(is_string), &runtime); + // Get the length of the string to r3. + __ ldr(r3, FieldMemOperand(subject, String::kLengthOffset)); + + // r2: Number of capture registers + // r3: Length of subject string + // subject: Subject string + // regexp_data: RegExp data (FixedArray) + // Check that the third argument is a positive smi less than the subject + // string length. A negative value will be greater (unsigned comparison). + __ ldr(r0, MemOperand(sp, kPreviousIndexOffset)); + __ cmp(r3, Operand(r0, ASR, kSmiTagSize + kSmiShiftSize)); + __ b(ls, &runtime); + + // r2: Number of capture registers + // subject: Subject string + // regexp_data: RegExp data (FixedArray) + // Check that the fourth object is a JSArray object. + __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset)); + __ tst(r0, Operand(kSmiTagMask)); + __ b(eq, &runtime); + __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); + __ b(ne, &runtime); + // Check that the JSArray is in fast case. + __ ldr(last_match_info_elements, + FieldMemOperand(r0, JSArray::kElementsOffset)); + __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); + __ cmp(r0, Operand(Factory::fixed_array_map())); + __ b(ne, &runtime); + // Check that the last match info has space for the capture registers and the + // additional information. + __ ldr(r0, + FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); + __ add(r2, r2, Operand(RegExpImpl::kLastMatchOverhead)); + __ cmp(r2, r0); + __ b(gt, &runtime); + + // subject: Subject string + // regexp_data: RegExp data (FixedArray) + // Check the representation and encoding of the subject string. + Label seq_string; + const int kStringRepresentationEncodingMask = + kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; + __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); + __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); + __ and_(r1, r0, Operand(kStringRepresentationEncodingMask)); + // First check for sequential string. + ASSERT_EQ(0, kStringTag); + ASSERT_EQ(0, kSeqStringTag); + __ tst(r1, Operand(kIsNotStringMask | kStringRepresentationMask)); + __ b(eq, &seq_string); + + // subject: Subject string + // regexp_data: RegExp data (FixedArray) + // Check for flat cons string. + // A flat cons string is a cons string where the second part is the empty + // string. In that case the subject string is just the first part of the cons + // string. Also in this case the first part of the cons string is known to be + // a sequential string or an external string. + __ and_(r0, r0, Operand(kStringRepresentationMask)); + __ cmp(r0, Operand(kConsStringTag)); + __ b(ne, &runtime); + __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); + __ LoadRoot(r1, Heap::kEmptyStringRootIndex); + __ cmp(r0, r1); + __ b(ne, &runtime); + __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); + __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); + __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); + ASSERT_EQ(0, kSeqStringTag); + __ tst(r0, Operand(kStringRepresentationMask)); + __ b(nz, &runtime); + __ and_(r1, r0, Operand(kStringRepresentationEncodingMask)); + + __ bind(&seq_string); + // r1: suject string type & kStringRepresentationEncodingMask + // subject: Subject string + // regexp_data: RegExp data (FixedArray) + // Check that the irregexp code has been generated for an ascii string. If + // it has, the field contains a code object otherwise it contains the hole. +#ifdef DEBUG + const int kSeqAsciiString = kStringTag | kSeqStringTag | kAsciiStringTag; + const int kSeqTwoByteString = kStringTag | kSeqStringTag | kTwoByteStringTag; + CHECK_EQ(4, kSeqAsciiString); + CHECK_EQ(0, kSeqTwoByteString); +#endif + // Find the code object based on the assumptions above. + __ mov(r3, Operand(r1, ASR, 2), SetCC); + __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); + __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); + + // Check that the irregexp code has been generated for the actual string + // encoding. If it has, the field contains a code object otherwise it contains + // the hole. + __ CompareObjectType(r7, r0, r0, CODE_TYPE); + __ b(ne, &runtime); + + // r3: encoding of subject string (1 if ascii, 0 if two_byte); + // r7: code + // subject: Subject string + // regexp_data: RegExp data (FixedArray) + // Load used arguments before starting to push arguments for call to native + // RegExp code to avoid handling changing stack height. + __ ldr(r1, MemOperand(sp, kPreviousIndexOffset)); + __ mov(r1, Operand(r1, ASR, kSmiTagSize)); + + // r1: previous index + // r3: encoding of subject string (1 if ascii, 0 if two_byte); + // r7: code + // subject: Subject string + // regexp_data: RegExp data (FixedArray) + // All checks done. Now push arguments for native regexp code. + __ IncrementCounter(&Counters::regexp_entry_native, 1, r0, r2); + + static const int kRegExpExecuteArguments = 7; + __ push(lr); + __ PrepareCallCFunction(kRegExpExecuteArguments, r0); + + // Argument 7 (sp[8]): Indicate that this is a direct call from JavaScript. + __ mov(r0, Operand(1)); + __ str(r0, MemOperand(sp, 2 * kPointerSize)); + + // Argument 6 (sp[4]): Start (high end) of backtracking stack memory area. + __ mov(r0, Operand(address_of_regexp_stack_memory_address)); + __ ldr(r0, MemOperand(r0, 0)); + __ mov(r2, Operand(address_of_regexp_stack_memory_size)); + __ ldr(r2, MemOperand(r2, 0)); + __ add(r0, r0, Operand(r2)); + __ str(r0, MemOperand(sp, 1 * kPointerSize)); + + // Argument 5 (sp[0]): static offsets vector buffer. + __ mov(r0, Operand(ExternalReference::address_of_static_offsets_vector())); + __ str(r0, MemOperand(sp, 0 * kPointerSize)); + + // For arguments 4 and 3 get string length, calculate start of string data and + // calculate the shift of the index (0 for ASCII and 1 for two byte). + __ ldr(r0, FieldMemOperand(subject, String::kLengthOffset)); + ASSERT_EQ(SeqAsciiString::kHeaderSize, SeqTwoByteString::kHeaderSize); + __ add(r9, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ eor(r3, r3, Operand(1)); + // Argument 4 (r3): End of string data + // Argument 3 (r2): Start of string data + __ add(r2, r9, Operand(r1, LSL, r3)); + __ add(r3, r9, Operand(r0, LSL, r3)); + + // Argument 2 (r1): Previous index. + // Already there + + // Argument 1 (r0): Subject string. + __ mov(r0, subject); + + // Locate the code entry and call it. + __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); + __ CallCFunction(r7, kRegExpExecuteArguments); + __ pop(lr); + + // r0: result + // subject: subject string (callee saved) + // regexp_data: RegExp data (callee saved) + // last_match_info_elements: Last match info elements (callee saved) + + // Check the result. + Label success; + __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS)); + __ b(eq, &success); + Label failure; + __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE)); + __ b(eq, &failure); + __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); + // If not exception it can only be retry. Handle that in the runtime system. + __ b(ne, &runtime); + // Result must now be exception. If there is no pending exception already a + // stack overflow (on the backtrack stack) was detected in RegExp code but + // haven't created the exception yet. Handle that in the runtime system. + // TODO(592): Rerunning the RegExp to get the stack overflow exception. + __ mov(r0, Operand(ExternalReference::the_hole_value_location())); + __ ldr(r0, MemOperand(r0, 0)); + __ mov(r1, Operand(ExternalReference(Top::k_pending_exception_address))); + __ ldr(r1, MemOperand(r1, 0)); + __ cmp(r0, r1); + __ b(eq, &runtime); + __ bind(&failure); + // For failure and exception return null. + __ mov(r0, Operand(Factory::null_value())); + __ add(sp, sp, Operand(4 * kPointerSize)); + __ Ret(); + + // Process the result from the native regexp code. + __ bind(&success); + __ ldr(r1, + FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); + // Calculate number of capture registers (number_of_captures + 1) * 2. + ASSERT_EQ(0, kSmiTag); + ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); + __ add(r1, r1, Operand(2)); // r1 was a smi. + + // r1: number of capture registers + // r4: subject string + // Store the capture count. + __ mov(r2, Operand(r1, LSL, kSmiTagSize + kSmiShiftSize)); // To smi. + __ str(r2, FieldMemOperand(last_match_info_elements, + RegExpImpl::kLastCaptureCountOffset)); + // Store last subject and last input. + __ mov(r3, last_match_info_elements); // Moved up to reduce latency. + __ mov(r2, Operand(RegExpImpl::kLastSubjectOffset)); // Ditto. + __ str(subject, + FieldMemOperand(last_match_info_elements, + RegExpImpl::kLastSubjectOffset)); + __ RecordWrite(r3, r2, r7); + __ str(subject, + FieldMemOperand(last_match_info_elements, + RegExpImpl::kLastInputOffset)); + __ mov(r3, last_match_info_elements); + __ mov(r2, Operand(RegExpImpl::kLastInputOffset)); + __ RecordWrite(r3, r2, r7); + + // Get the static offsets vector filled by the native regexp code. + ExternalReference address_of_static_offsets_vector = + ExternalReference::address_of_static_offsets_vector(); + __ mov(r2, Operand(address_of_static_offsets_vector)); + + // r1: number of capture registers + // r2: offsets vector + Label next_capture, done; + // Capture register counter starts from number of capture registers and + // counts down until wraping after zero. + __ add(r0, + last_match_info_elements, + Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag)); + __ bind(&next_capture); + __ sub(r1, r1, Operand(1), SetCC); + __ b(mi, &done); + // Read the value from the static offsets vector buffer. + __ ldr(r3, MemOperand(r2, kPointerSize, PostIndex)); + // Store the smi value in the last match info. + __ mov(r3, Operand(r3, LSL, kSmiTagSize)); + __ str(r3, MemOperand(r0, kPointerSize, PostIndex)); + __ jmp(&next_capture); + __ bind(&done); + + // Return last match info. + __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset)); + __ add(sp, sp, Operand(4 * kPointerSize)); + __ Ret(); + + // Do the runtime call to execute the regexp. + __ bind(&runtime); + __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); +#endif // V8_NATIVE_REGEXP +} + + void CallFunctionStub::Generate(MacroAssembler* masm) { Label slow; diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index 74aed1d79e..5abd814e39 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -215,8 +215,10 @@ class CodeGenerator: public AstVisitor { JumpTarget* true_target() const { return state_->true_target(); } JumpTarget* false_target() const { return state_->false_target(); } - // We don't track loop nesting level on ARM yet. - int loop_nesting() const { return 0; } + // Track loop nesting level. + int loop_nesting() const { return loop_nesting_; } + void IncrementLoopNesting() { loop_nesting_++; } + void DecrementLoopNesting() { loop_nesting_--; } // Node visitors. void VisitStatements(ZoneList* statements); @@ -284,6 +286,7 @@ class CodeGenerator: public AstVisitor { void LoadFromSlot(Slot* slot, TypeofState typeof_state); // Store the value on top of the stack to a slot. void StoreToSlot(Slot* slot, InitState init_state); + // Load a keyed property, leaving it in r0. The receiver and key are // passed on the stack, and remain there. void EmitKeyedLoad(bool is_global); @@ -409,6 +412,9 @@ class CodeGenerator: public AstVisitor { void GenerateRegExpConstructResult(ZoneList* args); + // Support for fast native caches. + void GenerateGetFromCache(ZoneList* args); + // Fast support for number to string. void GenerateNumberToString(ZoneList* args); @@ -455,6 +461,7 @@ class CodeGenerator: public AstVisitor { RegisterAllocator* allocator_; Condition cc_reg_; CodeGenState* state_; + int loop_nesting_; // Jump targets BreakTarget function_return_; diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 72f4128e6c..62365ffb46 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -666,7 +666,8 @@ void FullCodeGenerator::DeclareGlobals(Handle pairs) { void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { Comment cmnt(masm_, "[ FunctionLiteral"); - // Build the function boilerplate and instantiate it. + // Build the shared function info and instantiate the function based + // on it. Handle function_info = Compiler::BuildFunctionInfo(expr, script(), this); if (HasStackOverflow()) return; diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 1131760db3..376c4fbe81 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -355,10 +355,19 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { // ip = sp + kPointerSize * #args; add(ip, sp, Operand(r0, LSL, kPointerSizeLog2)); - // Align the stack at this point. After this point we have 5 pushes, - // so in fact we have to unalign here! See also the assert on the - // alignment in AlignStack. - AlignStack(1); + // Prepare the stack to be aligned when calling into C. After this point there + // are 5 pushes before the call into C, so the stack needs to be aligned after + // 5 pushes. + int frame_alignment = ActivationFrameAlignment(); + int frame_alignment_mask = frame_alignment - 1; + if (frame_alignment != kPointerSize) { + // The following code needs to be more general if this assert does not hold. + ASSERT(frame_alignment == 2 * kPointerSize); + // With 5 pushes left the frame must be unaligned at this point. + mov(r7, Operand(Smi::FromInt(0))); + tst(sp, Operand((frame_alignment - kPointerSize) & frame_alignment_mask)); + push(r7, eq); // Push if aligned to make it unaligned. + } // Push in reverse order: caller_fp, sp_on_exit, and caller_pc. stm(db_w, sp, fp.bit() | ip.bit() | lr.bit()); @@ -389,27 +398,20 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { } -void MacroAssembler::AlignStack(int offset) { +int MacroAssembler::ActivationFrameAlignment() { #if defined(V8_HOST_ARCH_ARM) // Running on the real platform. Use the alignment as mandated by the local // environment. // Note: This will break if we ever start generating snapshots on one ARM // platform for another ARM platform with a different alignment. - int activation_frame_alignment = OS::ActivationFrameAlignment(); + return OS::ActivationFrameAlignment(); #else // defined(V8_HOST_ARCH_ARM) // If we are using the simulator then we should always align to the expected // alignment. As the simulator is used to generate snapshots we do not know - // if the target platform will need alignment, so we will always align at - // this point here. - int activation_frame_alignment = 2 * kPointerSize; + // if the target platform will need alignment, so this is controlled from a + // flag. + return FLAG_sim_stack_alignment; #endif // defined(V8_HOST_ARCH_ARM) - if (activation_frame_alignment != kPointerSize) { - // This code needs to be made more general if this assert doesn't hold. - ASSERT(activation_frame_alignment == 2 * kPointerSize); - mov(r7, Operand(Smi::FromInt(0))); - tst(sp, Operand(activation_frame_alignment - offset)); - push(r7, eq); // Conditional push instruction. - } } @@ -1309,15 +1311,29 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { + ASSERT(!target.is(r1)); + + // Load the builtins object into target register. + ldr(target, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); + ldr(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset)); + // Load the JavaScript builtin function from the builtins object. - ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); - ldr(r1, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset)); - int builtins_offset = - JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize); - ldr(r1, FieldMemOperand(r1, builtins_offset)); - // Load the code entry point from the function into the target register. - ldr(target, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); - ldr(target, FieldMemOperand(target, SharedFunctionInfo::kCodeOffset)); + ldr(r1, FieldMemOperand(target, + JSBuiltinsObject::OffsetOfFunctionWithId(id))); + + // Load the code entry point from the builtins object. + ldr(target, FieldMemOperand(target, + JSBuiltinsObject::OffsetOfCodeWithId(id))); + if (FLAG_debug_code) { + // Make sure the code objects in the builtins object and in the + // builtin function are the same. + push(r1); + ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); + ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset)); + cmp(r1, target); + Assert(eq, "Builtin code object changed"); + pop(r1); + } add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag)); } @@ -1558,16 +1574,16 @@ void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(Register type, void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { - int frameAlignment = OS::ActivationFrameAlignment(); + int frame_alignment = ActivationFrameAlignment(); // Up to four simple arguments are passed in registers r0..r3. int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4; - if (frameAlignment > kPointerSize) { + if (frame_alignment > kPointerSize) { // Make stack end at alignment and make room for num_arguments - 4 words // and the original value of sp. mov(scratch, sp); sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize)); - ASSERT(IsPowerOf2(frameAlignment)); - and_(sp, sp, Operand(-frameAlignment)); + ASSERT(IsPowerOf2(frame_alignment)); + and_(sp, sp, Operand(-frame_alignment)); str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); } else { sub(sp, sp, Operand(stack_passed_arguments * kPointerSize)); @@ -1583,6 +1599,26 @@ void MacroAssembler::CallCFunction(ExternalReference function, void MacroAssembler::CallCFunction(Register function, int num_arguments) { + // Make sure that the stack is aligned before calling a C function unless + // running in the simulator. The simulator has its own alignment check which + // provides more information. +#if defined(V8_HOST_ARCH_ARM) + if (FLAG_debug_code) { + int frame_alignment = OS::ActivationFrameAlignment(); + int frame_alignment_mask = frame_alignment - 1; + if (frame_alignment > kPointerSize) { + ASSERT(IsPowerOf2(frame_alignment)); + Label alignment_as_expected; + tst(sp, Operand(frame_alignment_mask)); + b(eq, &alignment_as_expected); + // Don't use Check here, as it will call Runtime_Abort possibly + // re-entering here. + stop("Unexpected alignment"); + bind(&alignment_as_expected); + } + } +#endif + // Just call directly. The function called cannot cause a GC, or // allow preemption, so the return address in the link register // stays correct. diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index fa3a7ee65f..a2cd2701b9 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -116,8 +116,8 @@ class MacroAssembler: public Assembler { // Leave the current exit frame. Expects the return value in r0. void LeaveExitFrame(ExitFrame::Mode mode); - // Align the stack by optionally pushing a Smi zero. - void AlignStack(int offset); + // Get the actual activation frame alignment for target environment. + static int ActivationFrameAlignment(); void LoadContext(Register dst, int context_chain_length); diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index beb6bf12de..2fdba14af4 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -39,7 +39,7 @@ namespace v8 { namespace internal { -#ifdef V8_NATIVE_REGEXP +#ifndef V8_INTERPRETED_REGEXP /* * This assembler uses the following register assignment convention * - r5 : Pointer to current code object (Code*) including heap object tag. @@ -611,7 +611,6 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { __ add(frame_pointer(), sp, Operand(4 * kPointerSize)); __ push(r0); // Make room for "position - 1" constant (value is irrelevant). __ push(r0); // Make room for "at start" constant (value is irrelevant). - // Check if we have space on the stack for registers. Label stack_limit_hit; Label stack_ok; @@ -1001,6 +1000,12 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, // If not real stack overflow the stack guard was used to interrupt // execution for another purpose. + // If this is a direct call from JavaScript retry the RegExp forcing the call + // through the runtime system. Currently the direct call cannot handle a GC. + if (frame_entry(re_frame, kDirectCall) == 1) { + return RETRY; + } + // Prepare for possible GC. HandleScope handles; Handle code_handle(re_code); @@ -1230,6 +1235,6 @@ void RegExpCEntryStub::Generate(MacroAssembler* masm_) { #undef __ -#endif // V8_NATIVE_REGEXP +#endif // V8_INTERPRETED_REGEXP }} // namespace v8::internal diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.h b/deps/v8/src/arm/regexp-macro-assembler-arm.h index ef54388029..2c0a8d84d4 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.h +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.h @@ -32,14 +32,14 @@ namespace v8 { namespace internal { -#ifndef V8_NATIVE_REGEXP +#ifdef V8_INTERPRETED_REGEXP class RegExpMacroAssemblerARM: public RegExpMacroAssembler { public: RegExpMacroAssemblerARM(); virtual ~RegExpMacroAssemblerARM(); }; -#else +#else // V8_INTERPRETED_REGEXP class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { public: RegExpMacroAssemblerARM(Mode mode, int registers_to_save); @@ -258,7 +258,7 @@ class RegExpCEntryStub: public CodeStub { const char* GetName() { return "RegExpCEntryStub"; } }; -#endif // V8_NATIVE_REGEXP +#endif // V8_INTERPRETED_REGEXP }} // namespace v8::internal diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index b18fd79b38..827a88f356 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -1249,6 +1249,11 @@ void Simulator::SoftwareInterrupt(Instr* instr) { int swi = instr->SwiField(); switch (swi) { case call_rt_redirected: { + // Check if stack is aligned. Error if not aligned is reported below to + // include information on the function called. + bool stack_aligned = + (get_register(sp) + & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0; Redirection* redirection = Redirection::FromSwiInstruction(instr); int32_t arg0 = get_register(r0); int32_t arg1 = get_register(r1); @@ -1262,12 +1267,17 @@ void Simulator::SoftwareInterrupt(Instr* instr) { reinterpret_cast(redirection->external_function()); SimulatorRuntimeFPCall target = reinterpret_cast(external); - if (::v8::internal::FLAG_trace_sim) { + if (::v8::internal::FLAG_trace_sim || !stack_aligned) { double x, y; GetFpArgs(&x, &y); - PrintF("Call to host function at %p with args %f, %f\n", + PrintF("Call to host function at %p with args %f, %f", FUNCTION_ADDR(target), x, y); + if (!stack_aligned) { + PrintF(" with unaligned stack %08x\n", get_register(sp)); + } + PrintF("\n"); } + CHECK(stack_aligned); double result = target(arg0, arg1, arg2, arg3); SetFpResult(result); } else { @@ -1275,15 +1285,20 @@ void Simulator::SoftwareInterrupt(Instr* instr) { reinterpret_cast(redirection->external_function()); SimulatorRuntimeCall target = reinterpret_cast(external); - if (::v8::internal::FLAG_trace_sim) { + if (::v8::internal::FLAG_trace_sim || !stack_aligned) { PrintF( - "Call to host function at %p with args %08x, %08x, %08x, %08x\n", + "Call to host function at %p with args %08x, %08x, %08x, %08x", FUNCTION_ADDR(target), arg0, arg1, arg2, arg3); + if (!stack_aligned) { + PrintF(" with unaligned stack %08x\n", get_register(sp)); + } + PrintF("\n"); } + CHECK(stack_aligned); int64_t result = target(arg0, arg1, arg2, arg3); int32_t lo_res = static_cast(result); int32_t hi_res = static_cast(result >> 32); @@ -2524,4 +2539,4 @@ uintptr_t Simulator::PopAddress() { } } // namespace assembler::arm -#endif // !defined(__arm__) +#endif // __arm__ diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index bbffef22da..e0e166cf7e 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -600,6 +600,28 @@ static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler, } +// Generate code to check that a global property cell is empty. Create +// the property cell at compilation time if no cell exists for the +// property. +static Object* GenerateCheckPropertyCell(MacroAssembler* masm, + GlobalObject* global, + String* name, + Register scratch, + Label* miss) { + Object* probe = global->EnsurePropertyCell(name); + if (probe->IsFailure()) return probe; + JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); + ASSERT(cell->value()->IsTheHole()); + __ mov(scratch, Operand(Handle(cell))); + __ ldr(scratch, + FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ cmp(scratch, ip); + __ b(ne, miss); + return cell; +} + + #undef __ #define __ ACCESS_MASM(masm()) @@ -620,23 +642,19 @@ Register StubCompiler::CheckPrototypes(JSObject* object, masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss); // If we've skipped any global objects, it's not enough to verify - // that their maps haven't changed. + // that their maps haven't changed. We also need to check that the + // property cell for the property is still empty. while (object != holder) { if (object->IsGlobalObject()) { - GlobalObject* global = GlobalObject::cast(object); - Object* probe = global->EnsurePropertyCell(name); - if (probe->IsFailure()) { - set_failure(Failure::cast(probe)); + Object* cell = GenerateCheckPropertyCell(masm(), + GlobalObject::cast(object), + name, + scratch, + miss); + if (cell->IsFailure()) { + set_failure(Failure::cast(cell)); return result; } - JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); - ASSERT(cell->value()->IsTheHole()); - __ mov(scratch, Operand(Handle(cell))); - __ ldr(scratch, - FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ cmp(scratch, ip); - __ b(ne, miss); } object = JSObject::cast(object->GetPrototype()); } @@ -1389,6 +1407,50 @@ Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, } +Object* LoadStubCompiler::CompileLoadNonexistent(String* name, + JSObject* object, + JSObject* last) { + // ----------- S t a t e ------------- + // -- r2 : name + // -- lr : return address + // -- [sp] : receiver + // ----------------------------------- + Label miss; + + // Load receiver. + __ ldr(r0, MemOperand(sp, 0)); + + // Check that receiver is not a smi. + __ tst(r0, Operand(kSmiTagMask)); + __ b(eq, &miss); + + // Check the maps of the full prototype chain. + CheckPrototypes(object, r0, last, r3, r1, name, &miss); + + // If the last object in the prototype chain is a global object, + // check that the global property cell is empty. + if (last->IsGlobalObject()) { + Object* cell = GenerateCheckPropertyCell(masm(), + GlobalObject::cast(last), + name, + r1, + &miss); + if (cell->IsFailure()) return cell; + } + + // Return undefined if maps of the full prototype chain are still the + // same and no global property with this name contains a value. + __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); + __ Ret(); + + __ bind(&miss); + GenerateLoadMiss(masm(), Code::LOAD_IC); + + // Return the generated code. + return GetCode(NONEXISTENT, Heap::empty_string()); +} + + Object* LoadStubCompiler::CompileLoadField(JSObject* object, JSObject* holder, int index, diff --git a/deps/v8/src/arm/virtual-frame-arm.cc b/deps/v8/src/arm/virtual-frame-arm.cc index cf33e36945..a4c5484eb3 100644 --- a/deps/v8/src/arm/virtual-frame-arm.cc +++ b/deps/v8/src/arm/virtual-frame-arm.cc @@ -507,6 +507,9 @@ void VirtualFrame::SpillAll() { // Fall through. case NO_TOS_REGISTERS: break; + default: + UNREACHABLE(); + break; } ASSERT(register_allocation_map_ == 0); // Not yet implemented. } diff --git a/deps/v8/src/arm/virtual-frame-arm.h b/deps/v8/src/arm/virtual-frame-arm.h index 1350677b5e..c5a7fbbe01 100644 --- a/deps/v8/src/arm/virtual-frame-arm.h +++ b/deps/v8/src/arm/virtual-frame-arm.h @@ -376,8 +376,15 @@ class VirtualFrame : public ZoneObject { static const int kPreallocatedElements = 5 + 8; // 8 expression stack slots. // 5 states for the top of stack, which can be in memory or in r0 and r1. - enum TopOfStack { NO_TOS_REGISTERS, R0_TOS, R1_TOS, R1_R0_TOS, R0_R1_TOS, - TOS_STATES}; + enum TopOfStack { + NO_TOS_REGISTERS, + R0_TOS, + R1_TOS, + R1_R0_TOS, + R0_R1_TOS, + TOS_STATES + }; + static const int kMaxTOSRegisters = 2; static const bool kR0InUse[TOS_STATES]; diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index 54d7e57b83..a718fdcc44 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -712,10 +712,9 @@ function ArraySort(comparefn) { function InsertionSort(a, from, to) { for (var i = from + 1; i < to; i++) { var element = a[i]; - var key = %_IsSmi(element) ? element : ToString(element); for (var j = i - 1; j >= from; j--) { var tmp = a[j]; - var order = Compare(tmp, key); + var order = Compare(tmp, element); if (order > 0) { a[j + 1] = tmp; } else { @@ -734,9 +733,6 @@ function ArraySort(comparefn) { } var pivot_index = $floor($random() * (to - from)) + from; var pivot = a[pivot_index]; - // Pre-convert the element to a string for comparison if we know - // it will happen on each compare anyway. - var pivot_key = %_IsSmi(pivot) ? pivot : ToString(pivot); // Issue 95: Keep the pivot element out of the comparisons to avoid // infinite recursion if comparefn(pivot, pivot) != 0. a[pivot_index] = a[from]; @@ -747,7 +743,7 @@ function ArraySort(comparefn) { // From i to high_start are elements that haven't been compared yet. for (var i = from + 1; i < high_start; ) { var element = a[i]; - var order = Compare(element, pivot_key); + var order = Compare(element, pivot); if (order < 0) { a[i] = a[low_end]; a[low_end] = element; diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index ac27a656ec..ac03c200c2 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -46,7 +46,7 @@ #include "regexp-macro-assembler.h" #include "platform.h" // Include native regexp-macro-assembler. -#ifdef V8_NATIVE_REGEXP +#ifndef V8_INTERPRETED_REGEXP #if V8_TARGET_ARCH_IA32 #include "ia32/regexp-macro-assembler-ia32.h" #elif V8_TARGET_ARCH_X64 @@ -56,7 +56,7 @@ #else // Unknown architecture. #error "Unknown architecture." #endif // Target architecture. -#endif // V8_NATIVE_REGEXP +#endif // V8_INTERPRETED_REGEXP namespace v8 { namespace internal { @@ -680,7 +680,7 @@ ExternalReference ExternalReference::compile_array_push_call() { } -#ifdef V8_NATIVE_REGEXP +#ifndef V8_INTERPRETED_REGEXP ExternalReference ExternalReference::re_check_stack_guard_state() { Address function; @@ -723,7 +723,7 @@ ExternalReference ExternalReference::address_of_regexp_stack_memory_size() { return ExternalReference(RegExpStack::memory_size_address()); } -#endif +#endif // V8_INTERPRETED_REGEXP static double add_two_doubles(double x, double y) { diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 31ac44c841..03a2f8ea1c 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -457,7 +457,7 @@ class ExternalReference BASE_EMBEDDED { static ExternalReference debug_step_in_fp_address(); #endif -#ifdef V8_NATIVE_REGEXP +#ifndef V8_INTERPRETED_REGEXP // C functions called from RegExp generated code. // Function NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16() diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index d88c8e7f0c..ac9663d213 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -228,6 +228,7 @@ class Genesis BASE_EMBEDDED { // Used for creating a context from scratch. void InstallNativeFunctions(); bool InstallNatives(); + void InstallJSFunctionResultCaches(); // Used both for deserialized and from-scratch contexts to add the extensions // provided. static bool InstallExtensions(Handle global_context, @@ -1301,6 +1302,44 @@ bool Genesis::InstallNatives() { } +// Do not forget to update macros.py with named constant +// of cache id. +#define JSFUNCTION_RESULT_CACHE_LIST(F) \ + F(16, global_context()->regexp_function()) + + +static FixedArray* CreateCache(int size, JSFunction* factory) { + // Caches are supposed to live for a long time, allocate in old space. + int array_size = JSFunctionResultCache::kEntriesIndex + 2 * size; + Handle cache = + Factory::NewFixedArrayWithHoles(array_size, TENURED); + cache->set(JSFunctionResultCache::kFactoryIndex, factory); + cache->set(JSFunctionResultCache::kFingerIndex, + Smi::FromInt(JSFunctionResultCache::kEntriesIndex)); + cache->set(JSFunctionResultCache::kCacheSizeIndex, + Smi::FromInt(JSFunctionResultCache::kEntriesIndex)); + return *cache; +} + + +void Genesis::InstallJSFunctionResultCaches() { + const int kNumberOfCaches = 0 + +#define F(size, func) + 1 + JSFUNCTION_RESULT_CACHE_LIST(F) +#undef F + ; + + Handle caches = Factory::NewFixedArray(kNumberOfCaches, TENURED); + + int index = 0; +#define F(size, func) caches->set(index++, CreateCache(size, func)); + JSFUNCTION_RESULT_CACHE_LIST(F) +#undef F + + global_context()->set_jsfunction_result_caches(*caches); +} + + int BootstrapperActive::nesting_ = 0; @@ -1453,6 +1492,7 @@ bool Genesis::InstallJSBuiltins(Handle builtins) { Handle shared = Handle(function->shared()); if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false; + builtins->set_javascript_builtin_code(id, shared->code()); } return true; } @@ -1664,6 +1704,7 @@ Genesis::Genesis(Handle global_object, HookUpGlobalProxy(inner_global, global_proxy); InitializeGlobal(inner_global, empty_function); if (!InstallNatives()) return; + InstallJSFunctionResultCaches(); MakeFunctionInstancePrototypeWritable(); diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h index d56d4eee20..a42eb4a8b3 100644 --- a/deps/v8/src/codegen.h +++ b/deps/v8/src/codegen.h @@ -124,6 +124,7 @@ namespace internal { F(StringCompare, 2, 1) \ F(RegExpExec, 4, 1) \ F(RegExpConstructResult, 3, 1) \ + F(GetFromCache, 2, 1) \ F(NumberToString, 1, 1) \ F(MathPow, 2, 1) \ F(MathSin, 1, 1) \ @@ -424,7 +425,8 @@ class CEntryStub : public CodeStub { Label* throw_termination_exception, Label* throw_out_of_memory_exception, bool do_gc, - bool always_allocate_scope); + bool always_allocate_scope, + int alignment_skew = 0); void GenerateThrowTOS(MacroAssembler* masm); void GenerateThrowUncatchable(MacroAssembler* masm, UncatchableExceptionType type); diff --git a/deps/v8/src/compilation-cache.cc b/deps/v8/src/compilation-cache.cc index f1ab87b085..cec10fd250 100644 --- a/deps/v8/src/compilation-cache.cc +++ b/deps/v8/src/compilation-cache.cc @@ -270,7 +270,7 @@ Handle CompilationCacheScript::Lookup(Handle source, if (probe->IsSharedFunctionInfo()) { Handle function_info = Handle::cast(probe); - // Break when we've found a suitable boilerplate function that + // Break when we've found a suitable shared function info that // matches the origin. if (HasOrigin(function_info, name, line_offset, column_offset)) { result = *function_info; diff --git a/deps/v8/src/compilation-cache.h b/deps/v8/src/compilation-cache.h index d23182258e..6358a26047 100644 --- a/deps/v8/src/compilation-cache.h +++ b/deps/v8/src/compilation-cache.h @@ -32,12 +32,13 @@ namespace v8 { namespace internal { -// The compilation cache keeps function boilerplates for compiled -// scripts and evals. The boilerplates are looked up using the source -// string as the key. For regular expressions the compilation data is cached. +// The compilation cache keeps shared function infos for compiled +// scripts and evals. The shared function infos are looked up using +// the source string as the key. For regular expressions the +// compilation data is cached. class CompilationCache { public: - // Finds the script function boilerplate for a source + // Finds the script shared function info for a source // string. Returns an empty handle if the cache doesn't contain a // script for the given source string with the right origin. static Handle LookupScript(Handle source, @@ -45,7 +46,7 @@ class CompilationCache { int line_offset, int column_offset); - // Finds the function boilerplate for a source string for eval in a + // Finds the shared function info for a source string for eval in a // given context. Returns an empty handle if the cache doesn't // contain a script for the given source string. static Handle LookupEval(Handle source, @@ -57,13 +58,13 @@ class CompilationCache { static Handle LookupRegExp(Handle source, JSRegExp::Flags flags); - // Associate the (source, kind) pair to the boilerplate. This may - // overwrite an existing mapping. + // Associate the (source, kind) pair to the shared function + // info. This may overwrite an existing mapping. static void PutScript(Handle source, Handle function_info); // Associate the (source, context->closure()->shared(), kind) triple - // with the boilerplate. This may overwrite an existing mapping. + // with the shared function info. This may overwrite an existing mapping. static void PutEval(Handle source, Handle context, bool is_global, diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index aa80a029a7..c342dc227e 100755 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -541,7 +541,7 @@ Handle Compiler::BuildFunctionInfo(FunctionLiteral* literal, code); } - // Create a boilerplate function. + // Create a shared function info object. Handle result = Factory::NewSharedFunctionInfo(literal->name(), literal->materialized_literal_count(), diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h index ce112f3e80..ae9bd76d2a 100644 --- a/deps/v8/src/contexts.h +++ b/deps/v8/src/contexts.h @@ -83,6 +83,7 @@ enum ContextLookupFlags { V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \ V(CONFIGURE_GLOBAL_INDEX, JSFunction, configure_global_fun) \ V(FUNCTION_CACHE_INDEX, JSObject, function_cache) \ + V(JSFUNCTION_RESULT_CACHES_INDEX, FixedArray, jsfunction_result_caches) \ V(RUNTIME_CONTEXT_INDEX, Context, runtime_context) \ V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \ V(CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, JSFunction, \ @@ -205,6 +206,7 @@ class Context: public FixedArray { GET_STACK_TRACE_LINE_INDEX, CONFIGURE_GLOBAL_INDEX, FUNCTION_CACHE_INDEX, + JSFUNCTION_RESULT_CACHES_INDEX, RUNTIME_CONTEXT_INDEX, CALL_AS_FUNCTION_DELEGATE_INDEX, CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, diff --git a/deps/v8/src/cpu-profiler-inl.h b/deps/v8/src/cpu-profiler-inl.h index 036e1108e5..e454a9a93c 100644 --- a/deps/v8/src/cpu-profiler-inl.h +++ b/deps/v8/src/cpu-profiler-inl.h @@ -30,7 +30,7 @@ #include "cpu-profiler.h" -#ifdef ENABLE_CPP_PROFILES_PROCESSOR +#ifdef ENABLE_LOGGING_AND_PROFILING #include "circular-queue-inl.h" #include "profile-generator-inl.h" @@ -71,6 +71,7 @@ TickSampleEventRecord* TickSampleEventRecord::init(void* value) { TickSample* ProfilerEventsProcessor::TickSampleEvent() { + generator_->Tick(); TickSampleEventRecord* evt = TickSampleEventRecord::init(ticks_buffer_.Enqueue()); evt->order = enqueue_order_; // No increment! @@ -93,6 +94,6 @@ bool ProfilerEventsProcessor::FilterOutCodeCreateEvent( } } // namespace v8::internal -#endif // ENABLE_CPP_PROFILES_PROCESSOR +#endif // ENABLE_LOGGING_AND_PROFILING #endif // V8_CPU_PROFILER_INL_H_ diff --git a/deps/v8/src/cpu-profiler.cc b/deps/v8/src/cpu-profiler.cc index 22937c0fbb..ed3f6925e0 100644 --- a/deps/v8/src/cpu-profiler.cc +++ b/deps/v8/src/cpu-profiler.cc @@ -29,7 +29,7 @@ #include "cpu-profiler-inl.h" -#ifdef ENABLE_CPP_PROFILES_PROCESSOR +#ifdef ENABLE_LOGGING_AND_PROFILING #include "log-inl.h" @@ -253,14 +253,12 @@ void CpuProfiler::StartProfiling(String* title) { CpuProfile* CpuProfiler::StopProfiling(const char* title) { - ASSERT(singleton_ != NULL); - return singleton_->StopCollectingProfile(title); + return is_profiling() ? singleton_->StopCollectingProfile(title) : NULL; } CpuProfile* CpuProfiler::StopProfiling(String* title) { - ASSERT(singleton_ != NULL); - return singleton_->StopCollectingProfile(title); + return is_profiling() ? singleton_->StopCollectingProfile(title) : NULL; } @@ -422,6 +420,10 @@ void CpuProfiler::StartProcessorIfNotStarted() { generator_ = new ProfileGenerator(profiles_); processor_ = new ProfilerEventsProcessor(generator_); processor_->Start(); + // Enable stack sampling. + // It is important to have it started prior to logging, see issue 683: + // http://code.google.com/p/v8/issues/detail?id=683 + reinterpret_cast(Logger::ticker_)->Start(); // Enumerate stuff we already have in the heap. if (Heap::HasBeenSetup()) { Logger::LogCodeObjects(); @@ -429,15 +431,14 @@ void CpuProfiler::StartProcessorIfNotStarted() { Logger::LogFunctionObjects(); Logger::LogAccessorCallbacks(); } - // Enable stack sampling. - reinterpret_cast(Logger::ticker_)->Start(); } } CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) { + const double actual_sampling_rate = generator_->actual_sampling_rate(); StopProcessorIfLastProfile(); - CpuProfile* result = profiles_->StopProfiling(title); + CpuProfile* result = profiles_->StopProfiling(title, actual_sampling_rate); if (result != NULL) { result->Print(); } @@ -446,8 +447,9 @@ CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) { CpuProfile* CpuProfiler::StopCollectingProfile(String* title) { + const double actual_sampling_rate = generator_->actual_sampling_rate(); StopProcessorIfLastProfile(); - return profiles_->StopProfiling(title); + return profiles_->StopProfiling(title, actual_sampling_rate); } @@ -466,13 +468,13 @@ void CpuProfiler::StopProcessorIfLastProfile() { } } // namespace v8::internal -#endif // ENABLE_CPP_PROFILES_PROCESSOR +#endif // ENABLE_LOGGING_AND_PROFILING namespace v8 { namespace internal { void CpuProfiler::Setup() { -#ifdef ENABLE_CPP_PROFILES_PROCESSOR +#ifdef ENABLE_LOGGING_AND_PROFILING if (singleton_ == NULL) { singleton_ = new CpuProfiler(); } @@ -481,7 +483,7 @@ void CpuProfiler::Setup() { void CpuProfiler::TearDown() { -#ifdef ENABLE_CPP_PROFILES_PROCESSOR +#ifdef ENABLE_LOGGING_AND_PROFILING if (singleton_ != NULL) { delete singleton_; } diff --git a/deps/v8/src/cpu-profiler.h b/deps/v8/src/cpu-profiler.h index 594e44ec68..35d8d5e060 100644 --- a/deps/v8/src/cpu-profiler.h +++ b/deps/v8/src/cpu-profiler.h @@ -28,7 +28,7 @@ #ifndef V8_CPU_PROFILER_H_ #define V8_CPU_PROFILER_H_ -#ifdef ENABLE_CPP_PROFILES_PROCESSOR +#ifdef ENABLE_LOGGING_AND_PROFILING #include "circular-queue.h" @@ -197,7 +197,7 @@ class ProfilerEventsProcessor : public Thread { } while (false) #else #define PROFILE(Call) LOG(Call) -#endif // ENABLE_CPP_PROFILES_PROCESSOR +#endif // ENABLE_LOGGING_AND_PROFILING namespace v8 { @@ -208,7 +208,7 @@ class CpuProfiler { static void Setup(); static void TearDown(); -#ifdef ENABLE_CPP_PROFILES_PROCESSOR +#ifdef ENABLE_LOGGING_AND_PROFILING static void StartProfiling(const char* title); static void StartProfiling(String* title); static CpuProfile* StopProfiling(const char* title); @@ -265,7 +265,7 @@ class CpuProfiler { #else static INLINE(bool is_profiling()) { return false; } -#endif // ENABLE_CPP_PROFILES_PROCESSOR +#endif // ENABLE_LOGGING_AND_PROFILING private: DISALLOW_COPY_AND_ASSIGN(CpuProfiler); diff --git a/deps/v8/src/d8-debug.cc b/deps/v8/src/d8-debug.cc index 4e0243a9f9..5f3ed766ab 100644 --- a/deps/v8/src/d8-debug.cc +++ b/deps/v8/src/d8-debug.cc @@ -34,6 +34,11 @@ namespace v8 { +void PrintPrompt() { + printf("dbg> "); + fflush(stdout); +} + void HandleDebugEvent(DebugEvent event, Handle exec_state, @@ -86,7 +91,7 @@ void HandleDebugEvent(DebugEvent event, bool running = false; while (!running) { char command[kBufferSize]; - printf("dbg> "); + PrintPrompt(); char* str = fgets(command, kBufferSize, stdin); if (str == NULL) break; @@ -178,6 +183,7 @@ void RemoteDebugger::Run() { // Start the keyboard thread. KeyboardThread keyboard(this); keyboard.Start(); + PrintPrompt(); // Process events received from debugged VM and from the keyboard. bool terminate = false; @@ -264,7 +270,8 @@ void RemoteDebugger::HandleMessageReceived(char* message) { Handle details = Shell::DebugMessageDetails(Handle::Cast(String::New(message))); if (try_catch.HasCaught()) { - Shell::ReportException(&try_catch); + Shell::ReportException(&try_catch); + PrintPrompt(); return; } String::Utf8Value str(details->Get(String::New("text"))); @@ -277,7 +284,7 @@ void RemoteDebugger::HandleMessageReceived(char* message) { } else { printf("???\n"); } - printf("dbg> "); + PrintPrompt(); } @@ -289,13 +296,17 @@ void RemoteDebugger::HandleKeyboardCommand(char* command) { Handle request = Shell::DebugCommandToJSONRequest(String::New(command)); if (try_catch.HasCaught()) { - Shell::ReportException(&try_catch); + v8::String::Utf8Value exception(try_catch.Exception()); + const char* exception_string = Shell::ToCString(exception); + printf("%s\n", exception_string); + PrintPrompt(); return; } // If undefined is returned the command was handled internally and there is // no JSON to send. if (request->IsUndefined()) { + PrintPrompt(); return; } diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index 73cce46b34..531064f993 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -102,7 +102,7 @@ bool CounterMap::Match(void* key1, void* key2) { // Converts a V8 value to a C string. -const char* ToCString(const v8::String::Utf8Value& value) { +const char* Shell::ToCString(const v8::String::Utf8Value& value) { return *value ? *value : ""; } diff --git a/deps/v8/src/d8.h b/deps/v8/src/d8.h index 9df291b32a..30f04c750c 100644 --- a/deps/v8/src/d8.h +++ b/deps/v8/src/d8.h @@ -117,6 +117,7 @@ class Shell: public i::AllStatic { Handle name, bool print_result, bool report_exceptions); + static const char* ToCString(const v8::String::Utf8Value& value); static void ReportException(TryCatch* try_catch); static void Initialize(); static void OnExit(); diff --git a/deps/v8/src/d8.js b/deps/v8/src/d8.js index 369ab65cf5..b9ff09cee9 100644 --- a/deps/v8/src/d8.js +++ b/deps/v8/src/d8.js @@ -715,8 +715,6 @@ DebugRequest.prototype.scriptsCommandToJSONRequest_ = function(args) { // Create a JSON request for the break command. DebugRequest.prototype.breakCommandToJSONRequest_ = function(args) { // Build a evaluate request from the text command. - var request = this.createRequest('setbreakpoint'); - // Process arguments if any. if (args && args.length > 0) { var target = args; @@ -726,6 +724,8 @@ DebugRequest.prototype.breakCommandToJSONRequest_ = function(args) { var condition; var pos; + var request = this.createRequest('setbreakpoint'); + // Check for breakpoint condition. pos = args.indexOf(' '); if (pos > 0) { @@ -763,7 +763,7 @@ DebugRequest.prototype.breakCommandToJSONRequest_ = function(args) { request.arguments.column = column; request.arguments.condition = condition; } else { - throw new Error('Invalid break arguments.'); + var request = this.createRequest('suspend'); } return request.toJSONProtocol(); @@ -817,6 +817,7 @@ DebugRequest.prototype.helpCommand_ = function(args) { print('warning: arguments to \'help\' are ignored'); } + print('break'); print('break location [condition]'); print(' break on named function: location is a function name'); print(' break on function: location is ##'); @@ -931,6 +932,10 @@ function DebugResponseDetails(response) { var body = response.body(); var result = ''; switch (response.command()) { + case 'suspend': + details.text = 'stopped'; + break; + case 'setbreakpoint': result = 'set breakpoint #'; result += body.breakpoint; diff --git a/deps/v8/src/debug-debugger.js b/deps/v8/src/debug-debugger.js index ccec6af2fc..a0f3bdc5ac 100644 --- a/deps/v8/src/debug-debugger.js +++ b/deps/v8/src/debug-debugger.js @@ -1970,7 +1970,7 @@ DebugCommandProcessor.prototype.profileRequest_ = function(request, response) { DebugCommandProcessor.prototype.changeLiveRequest_ = function(request, response) { - if (!Debug.LiveEditChangeScript) { + if (!Debug.LiveEdit) { return response.failed('LiveEdit feature is not supported'); } if (!request.arguments) { @@ -2010,7 +2010,7 @@ DebugCommandProcessor.prototype.changeLiveRequest_ = function(request, response) return; } invocation = function() { - return Debug.LiveEditChangeScript(the_script, change_pos, change_len, + return Debug.LiveEdit.ApplyPatch(the_script, change_pos, change_len, new_string, change_log); } } @@ -2018,7 +2018,7 @@ DebugCommandProcessor.prototype.changeLiveRequest_ = function(request, response) try { invocation(); } catch (e) { - if (e instanceof Debug.LiveEditChangeScript.Failure) { + if (e instanceof Debug.LiveEdit.Failure) { // Let's treat it as a "success" so that body with change_log will be // sent back. "change_log" will have "failure" field set. change_log.push( { failure: true, message: e.toString() } ); diff --git a/deps/v8/src/execution.cc b/deps/v8/src/execution.cc index e8b0d942ad..006d358eaa 100644 --- a/deps/v8/src/execution.cc +++ b/deps/v8/src/execution.cc @@ -46,9 +46,6 @@ static Handle Invoke(bool construct, int argc, Object*** args, bool* has_pending_exception) { - // Make sure we have a real function, not a boilerplate function. - ASSERT(!func->IsBoilerplate()); - // Entering JavaScript. VMState state(JS); diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index dbcb4ec8d3..20f82612d2 100644 --- a/deps/v8/src/factory.cc +++ b/deps/v8/src/factory.cc @@ -43,9 +43,11 @@ Handle Factory::NewFixedArray(int size, PretenureFlag pretenure) { } -Handle Factory::NewFixedArrayWithHoles(int size) { +Handle Factory::NewFixedArrayWithHoles(int size, + PretenureFlag pretenure) { ASSERT(0 <= size); - CALL_HEAP_FUNCTION(Heap::AllocateFixedArrayWithHoles(size), FixedArray); + CALL_HEAP_FUNCTION(Heap::AllocateFixedArrayWithHoles(size, pretenure), + FixedArray); } @@ -312,7 +314,6 @@ Handle Factory::NewFunctionFromSharedFunctionInfo( context->global_context()); } result->set_literals(*literals); - ASSERT(!result->IsBoilerplate()); return result; } diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index 4307289dbd..0f2ae86b56 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -47,7 +47,9 @@ class Factory : public AllStatic { PretenureFlag pretenure = NOT_TENURED); // Allocate a new fixed array with non-existing entries (the hole). - static Handle NewFixedArrayWithHoles(int size); + static Handle NewFixedArrayWithHoles( + int size, + PretenureFlag pretenure = NOT_TENURED); static Handle NewNumberDictionary(int at_least_space_for); diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index 2e2074b7a6..181e634cd9 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -231,8 +231,10 @@ DEFINE_bool(allow_natives_syntax, false, "allow natives syntax") DEFINE_bool(optimize_ast, true, "optimize the ast") // simulator-arm.cc and simulator-mips.cc -DEFINE_bool(trace_sim, false, "trace simulator execution") +DEFINE_bool(trace_sim, false, "Trace simulator execution") DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions") +DEFINE_int(sim_stack_alignment, 8, + "Stack alingment in bytes in simulator (4 or 8, 8 is default)") // top.cc DEFINE_bool(trace_exception, false, diff --git a/deps/v8/src/globals.h b/deps/v8/src/globals.h index 3d48e2d78d..e3ef9589cd 100644 --- a/deps/v8/src/globals.h +++ b/deps/v8/src/globals.h @@ -147,6 +147,9 @@ const int kPointerSizeLog2 = 2; const intptr_t kIntptrSignBit = 0x80000000; #endif +// Mask for the sign bit in a smi. +const intptr_t kSmiSignMask = kIntptrSignBit; + const int kObjectAlignmentBits = kPointerSizeLog2; const intptr_t kObjectAlignment = 1 << kObjectAlignmentBits; const intptr_t kObjectAlignmentMask = kObjectAlignment - 1; @@ -428,7 +431,11 @@ enum PropertyType { CONSTANT_TRANSITION = 6, // only in fast mode NULL_DESCRIPTOR = 7, // only in fast mode // All properties before MAP_TRANSITION are real. - FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION + FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION, + // There are no IC stubs for NULL_DESCRIPTORS. Therefore, + // NULL_DESCRIPTOR can be used as the type flag for IC stubs for + // nonexistent properties. + NONEXISTENT = NULL_DESCRIPTOR }; diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc index 05cb3f2b38..84ee20bba1 100644 --- a/deps/v8/src/handles.cc +++ b/deps/v8/src/handles.cc @@ -457,6 +457,16 @@ void InitScriptLineEnds(Handle