From: isaacs Date: Thu, 29 Mar 2012 02:51:38 +0000 (-0700) Subject: Upgrade V8 to 3.9.24.6 X-Git-Tag: v0.7.7~15 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4b64542fe09477fc5c70e974eb1a78cdce755eb7;p=platform%2Fupstream%2Fnodejs.git Upgrade V8 to 3.9.24.6 --- diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index 869be2b..dfefad1 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -51,3 +51,4 @@ Tobias Burnus Vlad Burlik Yuqiang Xian Zaheer Ahmad +Zhongping Wang diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 9ba1362..2240ec0 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,84 @@ +2012-03-23: Version 3.9.24 + + Activated count-based profiler for ARM. + + Fixed use of proxies as f.prototype properties. (issue 2021) + + Enabled snapshots on MIPS. + + Performance and stability improvements on all platforms. + + +2012-03-21: Version 3.9.23 + + Use correct arguments adaptation environment when inlining function + containing arguments. (Issue 2014) + + Performance and stability improvements on all platforms. + + +2012-03-20: Version 3.9.22 + + Enabled count-based profiler by default. + + Implemented a hash based look-up to speed up address checks + in large object space (issue 853). + + Performance and stability improvements on all platforms. + + +2012-03-19: Version 3.9.21 + + Fixed push-to-trunk script (and re-push). + + Added API call that identifies strings that are guaranteed only to + contain ASCII characters. + + +2012-03-19: Version 3.9.20 + + Fixed declarations escaping global strict eval. (Issue 1624) + + Fixed wrapping of receiver for non-strict callbacks. (Issue 1973) + + Fixed function declarations overwriting read-only global properties. + (Chromium issue 115452) + + Fixed --use-strict flag in combination with --harmony[-scoping]. + + Debugger: naive implementation of "step into Function.prototype.bind". + + Debugger: added ability to set script source from within OnBeforeCompile + + Added flag to always call DebugBreak on abort. + + Re-enabled constructor inlining and inline === comparison with boolean + constants. (Issue 2009) + + Don't use an explicit s0 in ClampDoubleToUint8. (Issue 2004) + + Performance and stability improvements on all platforms. + + +2012-03-14: Version 3.9.19 + + Ensure there is a smi check of the receiver for global load and call + ICs (Chromium issue 117794). + + Performance and stability improvements on all platforms. + + +2012-03-13: Version 3.9.18 + + Ensure consistency of Math.sqrt on Intel platforms. + + Remove static initializers in v8. (issue 1859) + + Add explicit dependency on v8_base in the GYP-based build. + + Performance and stability improvements on all platforms. + + 2012-03-12: Version 3.9.17 Fixed VFP detection through compiler defines. (issue 1996) diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index bfa53a7..34d0efc 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -185,6 +185,9 @@ LIBRARY_FLAGS = { 'mips_arch_variant:mips32r2': { 'CPPDEFINES': ['_MIPS_ARCH_MIPS32R2'] }, + 'mips_arch_variant:loongson': { + 'CPPDEFINES': ['_MIPS_ARCH_LOONGSON'] + }, 'simulator:none': { 'CCFLAGS': ['-EL'], 'LINKFLAGS': ['-EL'], @@ -194,6 +197,9 @@ LIBRARY_FLAGS = { 'mips_arch_variant:mips32r1': { 'CCFLAGS': ['-mips32', '-Wa,-mips32'] }, + 'mips_arch_variant:loongson': { + 'CCFLAGS': ['-march=mips3', '-Wa,-march=mips3'] + }, 'library:static': { 'LINKFLAGS': ['-static', '-static-libgcc'] }, @@ -212,9 +218,12 @@ LIBRARY_FLAGS = { 'LINKFLAGS': ['-m32'], 'mipsabi:softfloat': { 'CPPDEFINES': ['__mips_soft_float=1'], + 'fpu:on': { + 'CPPDEFINES' : ['CAN_USE_FPU_INSTRUCTIONS'] + } }, 'mipsabi:hardfloat': { - 'CPPDEFINES': ['__mips_hard_float=1'], + 'CPPDEFINES': ['__mips_hard_float=1', 'CAN_USE_FPU_INSTRUCTIONS'], } }, 'arch:x64': { @@ -545,6 +554,9 @@ SAMPLE_FLAGS = { 'mips_arch_variant:mips32r2': { 'CPPDEFINES': ['_MIPS_ARCH_MIPS32R2'] }, + 'mips_arch_variant:loongson': { + 'CPPDEFINES': ['_MIPS_ARCH_LOONGSON'] + }, 'simulator:none': { 'CCFLAGS': ['-EL'], 'LINKFLAGS': ['-EL'], @@ -554,6 +566,9 @@ SAMPLE_FLAGS = { 'mips_arch_variant:mips32r1': { 'CCFLAGS': ['-mips32', '-Wa,-mips32'] }, + 'mips_arch_variant:loongson': { + 'CCFLAGS': ['-march=mips3', '-Wa,-march=mips3'] + }, 'library:static': { 'LINKFLAGS': ['-static', '-static-libgcc'] }, @@ -563,7 +578,10 @@ SAMPLE_FLAGS = { }, 'mipsabi:hardfloat': { 'CCFLAGS': ['-mhard-float'], - 'LINKFLAGS': ['-mhard-float'] + 'LINKFLAGS': ['-mhard-float'], + 'fpu:on': { + 'CPPDEFINES' : ['CAN_USE_FPU_INSTRUCTIONS'] + } } } }, @@ -697,6 +715,9 @@ PREPARSER_FLAGS = { 'mips_arch_variant:mips32r2': { 'CPPDEFINES': ['_MIPS_ARCH_MIPS32R2'] }, + 'mips_arch_variant:loongson': { + 'CPPDEFINES': ['_MIPS_ARCH_LOONGSON'] + }, 'simulator:none': { 'CCFLAGS': ['-EL'], 'LINKFLAGS': ['-EL'], @@ -706,6 +727,9 @@ PREPARSER_FLAGS = { 'mips_arch_variant:mips32r1': { 'CCFLAGS': ['-mips32', '-Wa,-mips32'] }, + 'mips_arch_variant:loongson': { + 'CCFLAGS': ['-march=mips3', '-Wa,-march=mips3'] + }, 'library:static': { 'LINKFLAGS': ['-static', '-static-libgcc'] }, @@ -1114,7 +1138,7 @@ SIMPLE_OPTIONS = { 'help': 'generate calling conventiont according to selected mips ABI' }, 'mips_arch_variant': { - 'values': ['mips32r2', 'mips32r1'], + 'values': ['mips32r2', 'mips32r1', 'loongson'], 'default': 'mips32r2', 'help': 'mips variant' }, @@ -1128,6 +1152,11 @@ SIMPLE_OPTIONS = { 'default': 'on', 'help': 'use vfp3 instructions when building the snapshot [Arm only]' }, + 'fpu': { + 'values': ['on', 'off'], + 'default': 'on', + 'help': 'use fpu instructions when building the snapshot [MIPS only]' + }, } diff --git a/deps/v8/benchmarks/README.txt b/deps/v8/benchmarks/README.txt index 6676f37..59f76ff 100644 --- a/deps/v8/benchmarks/README.txt +++ b/deps/v8/benchmarks/README.txt @@ -77,3 +77,10 @@ input strings. Furthermore, the benchmark runner was changed to run the benchmarks for at least a few times to stabilize the reported numbers on slower machines. + + +Changes from Version 6 to Version 7 +=================================== + +Added the Navier-Stokes benchmark, a 2D differential equation solver +that stresses arithmetic computations on double arrays. diff --git a/deps/v8/benchmarks/revisions.html b/deps/v8/benchmarks/revisions.html index 6ff75be..3ce9889 100644 --- a/deps/v8/benchmarks/revisions.html +++ b/deps/v8/benchmarks/revisions.html @@ -19,6 +19,10 @@ not comparable unless both results are run with the same revision of the benchmark suite.

+

Version 7 (link)

+ +

This version includes the new Navier-Stokes benchmark, a 2D differential + equation solver that stresses arithmetic computations on double arrays.

Version 6 (link)

diff --git a/deps/v8/benchmarks/run.html b/deps/v8/benchmarks/run.html index 8786d1f..f1d14c1 100644 --- a/deps/v8/benchmarks/run.html +++ b/deps/v8/benchmarks/run.html @@ -53,16 +53,16 @@ function Run() { BenchmarkSuite.RunSuites({ NotifyStep: ShowProgress, NotifyError: AddError, NotifyResult: AddResult, - NotifyScore: AddScore }); + NotifyScore: AddScore }); } function ShowWarningIfObsolete() { - // If anything goes wrong we will just catch the exception and no + // If anything goes wrong we will just catch the exception and no // warning is shown, i.e., no harm is done. try { var xmlhttp; - var next_version = parseInt(BenchmarkSuite.version) + 1; - var next_version_url = "../v" + next_version + "/run.html"; + var next_version = parseInt(BenchmarkSuite.version) + 1; + var next_version_url = "../v" + next_version + "/run.html"; if (window.XMLHttpRequest) { xmlhttp = new window.XMLHttpRequest(); } else if (window.ActiveXObject) { @@ -76,7 +76,7 @@ function ShowWarningIfObsolete() { }; xmlhttp.send(null); } catch(e) { - // Ignore exception if check for next version fails. + // Ignore exception if check for next version fails. // Hence no warning is displayed. } } @@ -84,7 +84,7 @@ function ShowWarningIfObsolete() { function Load() { var version = BenchmarkSuite.version; document.getElementById("version").innerHTML = version; - ShowWarningIfObsolete(); + ShowWarningIfObsolete(); setTimeout(Run, 200); } @@ -92,11 +92,11 @@ function Load() {

V8 Benchmark Suite - version ?

-
+
Warning! This is not the latest version of the V8 benchmark -suite. Consider running the +suite. Consider running the -latest version. +latest version.
@@ -118,7 +118,7 @@ higher scores means better performance: Bigger is better! (1761 lines).
  • Splay
    Data manipulation benchmark that deals with splay trees and exercises the automatic memory management subsystem (394 lines).
  • -
  • NavierStokes (beta)
    Solves NavierStokes equations in 2D, heavily manipulating double precision arrays. Based on Oliver Hunt's code (396 lines).
  • +
  • NavierStokes
    Solves NavierStokes equations in 2D, heavily manipulating double precision arrays. Based on Oliver Hunt's code (387 lines).
  • diff --git a/deps/v8/build/common.gypi b/deps/v8/build/common.gypi index 6e1cbea..5c0c323 100644 --- a/deps/v8/build/common.gypi +++ b/deps/v8/build/common.gypi @@ -62,6 +62,9 @@ # Similar to the ARM hard float ABI but on MIPS. 'v8_use_mips_abi_hardfloat%': 'true', + # Default arch variant for MIPS. + 'mips_arch_variant%': 'mips32r2', + 'v8_enable_debugger_support%': 1, 'v8_enable_disassembler%': 0, @@ -184,6 +187,9 @@ }], ['mips_arch_variant=="mips32r2"', { 'cflags': ['-mips32r2', '-Wa,-mips32r2'], + }], + ['mips_arch_variant=="loongson"', { + 'cflags': ['-mips3', '-Wa,-mips3'], }, { 'cflags': ['-mips32', '-Wa,-mips32'], }], @@ -209,6 +215,9 @@ ['mips_arch_variant=="mips32r2"', { 'defines': ['_MIPS_ARCH_MIPS32R2',], }], + ['mips_arch_variant=="loongson"', { + 'defines': ['_MIPS_ARCH_LOONGSON',], + }], # The MIPS assembler assumes the host is 32 bits, # so force building 32-bit host tools. ['host_arch=="x64"', { @@ -305,7 +314,7 @@ 'cflags': [ '-I/usr/pkg/include' ], }], ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { - 'cflags': [ '-Wno-unused-parameter', + 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', '-Wnon-virtual-dtor', '-Woverloaded-virtual' ], }], ], @@ -352,6 +361,7 @@ }], # OS=="mac" ['OS=="win"', { 'msvs_configuration_attributes': { + 'OutputDirectory': '<(DEPTH)\\build\\$(ConfigurationName)', 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)', 'CharacterSet': '1', }, diff --git a/deps/v8/build/mipsu.gypi b/deps/v8/build/mipsu.gypi index 306f105..637ff84 100644 --- a/deps/v8/build/mipsu.gypi +++ b/deps/v8/build/mipsu.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: @@ -29,6 +29,5 @@ 'variables': { 'target_arch': 'ia32', 'v8_target_arch': 'mips', - 'mips_arch_variant': 'mips32r2', }, } diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index e4037b9..33179f5 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -1021,6 +1021,14 @@ class String : public Primitive { V8EXPORT int Utf8Length() const; /** + * A fast conservative check for non-ASCII characters. May + * return true even for ASCII strings, but if it returns + * false you can be sure that all characters are in the range + * 0-127. + */ + V8EXPORT bool MayContainNonAscii() const; + + /** * Write the contents of the string to an external buffer. * If no arguments are given, expects the buffer to be large * enough to hold the entire string and NULL terminator. Copies diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index fde7a80..0d0b535 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -101,6 +101,7 @@ SOURCES = { objects.cc objects-printer.cc objects-visiting.cc + once.cc parser.cc preparser.cc preparse-data.cc diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index d8c7ba0..49a026b 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -1430,7 +1430,7 @@ void ObjectTemplate::SetInternalFieldCount(int value) { ScriptData* ScriptData::PreCompile(const char* input, int length) { - i::Utf8ToUC16CharacterStream stream( + i::Utf8ToUtf16CharacterStream stream( reinterpret_cast(input), length); return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping); } @@ -1439,11 +1439,11 @@ ScriptData* ScriptData::PreCompile(const char* input, int length) { ScriptData* ScriptData::PreCompile(v8::Handle source) { i::Handle str = Utils::OpenHandle(*source); if (str->IsExternalTwoByteString()) { - i::ExternalTwoByteStringUC16CharacterStream stream( + i::ExternalTwoByteStringUtf16CharacterStream stream( i::Handle::cast(str), 0, str->length()); return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping); } else { - i::GenericStringUC16CharacterStream stream(str, 0, str->length()); + i::GenericStringUtf16CharacterStream stream(str, 0, str->length()); return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping); } } @@ -3064,8 +3064,11 @@ bool Object::SetAccessor(Handle name, i::Handle info = MakeAccessorInfo(name, getter, setter, data, settings, attributes); + bool fast = Utils::OpenHandle(this)->HasFastProperties(); i::Handle result = i::SetAccessor(Utils::OpenHandle(this), info); - return !result.is_null() && !result->IsUndefined(); + if (result.is_null() || result->IsUndefined()) return false; + if (fast) i::JSObject::TransformToFastProperties(Utils::OpenHandle(this), 0); + return true; } @@ -3690,7 +3693,104 @@ int String::Length() const { int String::Utf8Length() const { i::Handle str = Utils::OpenHandle(this); if (IsDeadCheck(str->GetIsolate(), "v8::String::Utf8Length()")) return 0; - return str->Utf8Length(); + return i::Utf8Length(str); +} + + +// Will fail with a negative answer if the recursion depth is too high. +static int RecursivelySerializeToUtf8(i::String* string, + char* buffer, + int start, + int end, + int recursion_budget, + int32_t previous_character, + int32_t* last_character) { + int utf8_bytes = 0; + while (true) { + if (string->IsAsciiRepresentation()) { + i::String::WriteToFlat(string, buffer, start, end); + *last_character = unibrow::Utf16::kNoPreviousCharacter; + return utf8_bytes + end - start; + } + switch (i::StringShape(string).representation_tag()) { + case i::kExternalStringTag: { + const uint16_t* data = i::ExternalTwoByteString::cast(string)-> + ExternalTwoByteStringGetData(0); + char* current = buffer; + for (int i = start; i < end; i++) { + uint16_t character = data[i]; + current += + unibrow::Utf8::Encode(current, character, previous_character); + previous_character = character; + } + *last_character = previous_character; + return static_cast(utf8_bytes + current - buffer); + } + case i::kSeqStringTag: { + const uint16_t* data = + i::SeqTwoByteString::cast(string)->SeqTwoByteStringGetData(0); + char* current = buffer; + for (int i = start; i < end; i++) { + uint16_t character = data[i]; + current += + unibrow::Utf8::Encode(current, character, previous_character); + previous_character = character; + } + *last_character = previous_character; + return static_cast(utf8_bytes + current - buffer); + } + case i::kSlicedStringTag: { + i::SlicedString* slice = i::SlicedString::cast(string); + unsigned offset = slice->offset(); + string = slice->parent(); + start += offset; + end += offset; + continue; + } + case i::kConsStringTag: { + i::ConsString* cons_string = i::ConsString::cast(string); + i::String* first = cons_string->first(); + int boundary = first->length(); + if (start >= boundary) { + // Only need RHS. + string = cons_string->second(); + start -= boundary; + end -= boundary; + continue; + } else if (end <= boundary) { + // Only need LHS. + string = first; + } else { + if (recursion_budget == 0) return -1; + int extra_utf8_bytes = + RecursivelySerializeToUtf8(first, + buffer, + start, + boundary, + recursion_budget - 1, + previous_character, + &previous_character); + if (extra_utf8_bytes < 0) return extra_utf8_bytes; + buffer += extra_utf8_bytes; + utf8_bytes += extra_utf8_bytes; + string = cons_string->second(); + start = 0; + end -= boundary; + } + } + } + } + UNREACHABLE(); + return 0; +} + + +bool String::MayContainNonAscii() const { + i::Handle str = Utils::OpenHandle(this); + if (IsDeadCheck(str->GetIsolate(), "v8::String::MayContainNonAscii()")) { + return false; + } + return !str->HasOnlyAsciiChars(); } @@ -3703,11 +3803,12 @@ int String::WriteUtf8(char* buffer, LOG_API(isolate, "String::WriteUtf8"); ENTER_V8(isolate); i::Handle str = Utils::OpenHandle(this); + int string_length = str->length(); if (str->IsAsciiRepresentation()) { int len; if (capacity == -1) { capacity = str->length() + 1; - len = str->length(); + len = string_length; } else { len = i::Min(capacity, str->length()); } @@ -3720,6 +3821,42 @@ int String::WriteUtf8(char* buffer, return len; } + if (capacity == -1 || capacity / 3 >= string_length) { + int32_t previous = unibrow::Utf16::kNoPreviousCharacter; + const int kMaxRecursion = 100; + int utf8_bytes = + RecursivelySerializeToUtf8(*str, + buffer, + 0, + string_length, + kMaxRecursion, + previous, + &previous); + if (utf8_bytes >= 0) { + // Success serializing with recursion. + if ((options & NO_NULL_TERMINATION) == 0 && + (capacity > utf8_bytes || capacity == -1)) { + buffer[utf8_bytes++] = '\0'; + } + if (nchars_ref != NULL) *nchars_ref = string_length; + return utf8_bytes; + } + FlattenString(str); + // Recurse once. This time around the string is flat and the serializing + // with recursion will certainly succeed. + return WriteUtf8(buffer, capacity, nchars_ref, options); + } else if (capacity >= string_length) { + // First check that the buffer is large enough. If it is, then recurse + // once without a capacity limit, which will get into the other branch of + // this 'if'. + int utf8_bytes = i::Utf8Length(str); + if ((options & NO_NULL_TERMINATION) == 0) utf8_bytes++; + if (utf8_bytes <= capacity) { + return WriteUtf8(buffer, -1, nchars_ref, options); + } + } + + // Slow case. i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer(); isolate->string_tracker()->RecordWrite(str); if (options & HINT_MANY_WRITES_EXPECTED) { @@ -3736,11 +3873,13 @@ int String::WriteUtf8(char* buffer, int i; int pos = 0; int nchars = 0; + int previous = unibrow::Utf16::kNoPreviousCharacter; for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) { i::uc32 c = write_input_buffer.GetNext(); - int written = unibrow::Utf8::Encode(buffer + pos, c); + int written = unibrow::Utf8::Encode(buffer + pos, c, previous); pos += written; nchars++; + previous = c; } if (i < len) { // For the last characters we need to check the length for each one @@ -3749,16 +3888,33 @@ int String::WriteUtf8(char* buffer, char intermediate[unibrow::Utf8::kMaxEncodedSize]; for (; i < len && pos < capacity; i++) { i::uc32 c = write_input_buffer.GetNext(); - int written = unibrow::Utf8::Encode(intermediate, c); - if (pos + written <= capacity) { - for (int j = 0; j < written; j++) - buffer[pos + j] = intermediate[j]; + if (unibrow::Utf16::IsTrailSurrogate(c) && + unibrow::Utf16::IsLeadSurrogate(previous)) { + // We can't use the intermediate buffer here because the encoding + // of surrogate pairs is done under assumption that you can step + // back and fix the UTF8 stream. Luckily we only need space for one + // more byte, so there is always space. + ASSERT(pos < capacity); + int written = unibrow::Utf8::Encode(buffer + pos, c, previous); + ASSERT(written == 1); pos += written; nchars++; } else { - // We've reached the end of the buffer - break; + int written = + unibrow::Utf8::Encode(intermediate, + c, + unibrow::Utf16::kNoPreviousCharacter); + if (pos + written <= capacity) { + for (int j = 0; j < written; j++) + buffer[pos + j] = intermediate[j]; + pos += written; + nchars++; + } else { + // We've reached the end of the buffer + break; + } } + previous = c; } } if (nchars_ref != NULL) *nchars_ref = nchars; @@ -4014,7 +4170,7 @@ void v8::Object::SetPointerInInternalField(int index, void* value) { bool v8::V8::Initialize() { - i::Isolate* isolate = i::Isolate::UncheckedCurrent(); + i::Isolate* isolate = i::Isolate::Current(); if (isolate != NULL && isolate->IsInitialized()) { return true; } @@ -4907,7 +5063,7 @@ Local v8::Number::New(double value) { Local v8::Integer::New(int32_t value) { - i::Isolate* isolate = i::Isolate::UncheckedCurrent(); + i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::Integer::New()"); if (i::Smi::IsValid(value)) { return Utils::IntegerToLocal(i::Handle(i::Smi::FromInt(value), @@ -5185,7 +5341,7 @@ bool V8::IsExecutionTerminating(Isolate* isolate) { Isolate* Isolate::GetCurrent() { - i::Isolate* isolate = i::Isolate::UncheckedCurrent(); + i::Isolate* isolate = i::Isolate::Current(); return reinterpret_cast(isolate); } @@ -5240,7 +5396,8 @@ String::Utf8Value::Utf8Value(v8::Handle obj) TryCatch try_catch; Handle str = obj->ToString(); if (str.IsEmpty()) return; - length_ = str->Utf8Length(); + i::Handle i_str = Utils::OpenHandle(*str); + length_ = i::Utf8Length(i_str); str_ = i::NewArray(length_ + 1); str->WriteUtf8(str_); } diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h index dd8ffcd..d5db686 100644 --- a/deps/v8/src/arm/assembler-arm-inl.h +++ b/deps/v8/src/arm/assembler-arm-inl.h @@ -80,7 +80,7 @@ Address RelocInfo::target_address_address() { int RelocInfo::target_address_size() { - return Assembler::kExternalTargetSize; + return kPointerSize; } @@ -364,8 +364,14 @@ Address Assembler::target_address_at(Address pc) { } -void Assembler::set_target_at(Address constant_pool_entry, - Address target) { +void Assembler::deserialization_set_special_target_at( + Address constant_pool_entry, Address target) { + Memory::Address_at(constant_pool_entry) = target; +} + + +void Assembler::set_external_target_at(Address constant_pool_entry, + Address target) { Memory::Address_at(constant_pool_entry) = target; } diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index ff15221..ec28da4 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -139,7 +139,6 @@ bool RelocInfo::IsCodedSpecially() { } - void RelocInfo::PatchCode(byte* instructions, int instruction_count) { // Patch the code at the current address with the supplied instructions. Instr* pc = reinterpret_cast(pc_); @@ -238,25 +237,27 @@ MemOperand::MemOperand(Register rn, Register rm, // add(sp, sp, 4) instruction (aka Pop()) const Instr kPopInstruction = - al | PostIndex | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12; + al | PostIndex | 4 | LeaveCC | I | kRegister_sp_Code * B16 | + kRegister_sp_Code * B12; // str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r)) // register r is not encoded. const Instr kPushRegPattern = - al | B26 | 4 | NegPreIndex | sp.code() * B16; + al | B26 | 4 | NegPreIndex | kRegister_sp_Code * B16; // ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r)) // register r is not encoded. const Instr kPopRegPattern = - al | B26 | L | 4 | PostIndex | sp.code() * B16; + al | B26 | L | 4 | PostIndex | kRegister_sp_Code * B16; // mov lr, pc -const Instr kMovLrPc = al | MOV | pc.code() | lr.code() * B12; +const Instr kMovLrPc = al | MOV | kRegister_pc_Code | kRegister_lr_Code * B12; // ldr rd, [pc, #offset] const Instr kLdrPCMask = kCondMask | 15 * B24 | 7 * B20 | 15 * B16; -const Instr kLdrPCPattern = al | 5 * B24 | L | pc.code() * B16; +const Instr kLdrPCPattern = al | 5 * B24 | L | kRegister_pc_Code * B16; // blxcc rm const Instr kBlxRegMask = 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4; const Instr kBlxRegPattern = B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX; +const Instr kBlxIp = al | kBlxRegPattern | ip.code(); const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16; const Instr kMovMvnPattern = 0xd * B21; const Instr kMovMvnFlip = B22; @@ -273,13 +274,13 @@ const Instr kAndBicFlip = 0xe * B21; // A mask for the Rd register for push, pop, ldr, str instructions. const Instr kLdrRegFpOffsetPattern = - al | B26 | L | Offset | fp.code() * B16; + al | B26 | L | Offset | kRegister_fp_Code * B16; const Instr kStrRegFpOffsetPattern = - al | B26 | Offset | fp.code() * B16; + al | B26 | Offset | kRegister_fp_Code * B16; const Instr kLdrRegFpNegOffsetPattern = - al | B26 | L | NegOffset | fp.code() * B16; + al | B26 | L | NegOffset | kRegister_fp_Code * B16; const Instr kStrRegFpNegOffsetPattern = - al | B26 | NegOffset | fp.code() * B16; + al | B26 | NegOffset | kRegister_fp_Code * B16; const Instr kLdrStrInstrTypeMask = 0xffff0000; const Instr kLdrStrInstrArgumentMask = 0x0000ffff; const Instr kLdrStrOffsetMask = 0x00000fff; diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index 11e39df..e2d5f59 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -124,24 +124,47 @@ struct Register { int code_; }; -const Register no_reg = { -1 }; - -const Register r0 = { 0 }; -const Register r1 = { 1 }; -const Register r2 = { 2 }; -const Register r3 = { 3 }; -const Register r4 = { 4 }; -const Register r5 = { 5 }; -const Register r6 = { 6 }; -const Register r7 = { 7 }; -const Register r8 = { 8 }; // Used as context register. -const Register r9 = { 9 }; // Used as lithium codegen scratch register. -const Register r10 = { 10 }; // Used as roots register. -const Register fp = { 11 }; -const Register ip = { 12 }; -const Register sp = { 13 }; -const Register lr = { 14 }; -const Register pc = { 15 }; +// These constants are used in several locations, including static initializers +const int kRegister_no_reg_Code = -1; +const int kRegister_r0_Code = 0; +const int kRegister_r1_Code = 1; +const int kRegister_r2_Code = 2; +const int kRegister_r3_Code = 3; +const int kRegister_r4_Code = 4; +const int kRegister_r5_Code = 5; +const int kRegister_r6_Code = 6; +const int kRegister_r7_Code = 7; +const int kRegister_r8_Code = 8; +const int kRegister_r9_Code = 9; +const int kRegister_r10_Code = 10; +const int kRegister_fp_Code = 11; +const int kRegister_ip_Code = 12; +const int kRegister_sp_Code = 13; +const int kRegister_lr_Code = 14; +const int kRegister_pc_Code = 15; + +const Register no_reg = { kRegister_no_reg_Code }; + +const Register r0 = { kRegister_r0_Code }; +const Register r1 = { kRegister_r1_Code }; +const Register r2 = { kRegister_r2_Code }; +const Register r3 = { kRegister_r3_Code }; +const Register r4 = { kRegister_r4_Code }; +const Register r5 = { kRegister_r5_Code }; +const Register r6 = { kRegister_r6_Code }; +const Register r7 = { kRegister_r7_Code }; +// Used as context register. +const Register r8 = { kRegister_r8_Code }; +// Used as lithium codegen scratch register. +const Register r9 = { kRegister_r9_Code }; +// Used as roots register. +const Register r10 = { kRegister_r10_Code }; +const Register fp = { kRegister_fp_Code }; +const Register ip = { kRegister_ip_Code }; +const Register sp = { kRegister_sp_Code }; +const Register lr = { kRegister_lr_Code }; +const Register pc = { kRegister_pc_Code }; + // Single word VFP register. struct SwVfpRegister { @@ -581,6 +604,7 @@ extern const Instr kLdrPCMask; extern const Instr kLdrPCPattern; extern const Instr kBlxRegMask; extern const Instr kBlxRegPattern; +extern const Instr kBlxIp; extern const Instr kMovMvnMask; extern const Instr kMovMvnPattern; @@ -662,20 +686,18 @@ class Assembler : public AssemblerBase { // This sets the branch destination (which is in the constant pool on ARM). // This is for calls and branches within generated code. - inline static void set_target_at(Address constant_pool_entry, Address target); + inline static void deserialization_set_special_target_at( + Address constant_pool_entry, Address target); // This sets the branch destination (which is in the constant pool on ARM). // This is for calls and branches to runtime code. inline static void set_external_target_at(Address constant_pool_entry, - Address target) { - set_target_at(constant_pool_entry, target); - } + Address target); // Here we are patching the address in the constant pool, not the actual call // instruction. The address in the constant pool is the same size as a // pointer. - static const int kCallTargetSize = kPointerSize; - static const int kExternalTargetSize = kPointerSize; + static const int kSpecialTargetSize = kPointerSize; // Size of an instruction. static const int kInstrSize = sizeof(Instr); diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 250f020..f772db9 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -480,7 +480,7 @@ void ConvertToDoubleStub::Generate(MacroAssembler* masm) { __ b(gt, ¬_special); // For 1 or -1 we need to or in the 0 exponent (biased to 1023). - static const uint32_t exponent_word_for_1 = + const uint32_t exponent_word_for_1 = HeapNumber::kExponentBias << HeapNumber::kExponentShift; __ orr(exponent, exponent, Operand(exponent_word_for_1), LeaveCC, eq); // 1, 0 and -1 all have 0 for the second word. @@ -4237,7 +4237,7 @@ Register InstanceofStub::right() { return r1; } void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { // The displacement is the offset of the last parameter (if any) // relative to the frame pointer. - static const int kDisplacement = + const int kDisplacement = StandardFrameConstants::kCallerSPOffset - kPointerSize; // Check that the key is a smi. @@ -4622,10 +4622,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // 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; + const int kLastMatchInfoOffset = 0 * kPointerSize; + const int kPreviousIndexOffset = 1 * kPointerSize; + const int kSubjectOffset = 2 * kPointerSize; + const int kJSRegExpOffset = 3 * kPointerSize; Label runtime, invoke_regexp; @@ -4824,8 +4824,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ IncrementCounter(isolate->counters()->regexp_entry_native(), 1, r0, r2); // Isolates: note we add an additional parameter here (isolate pointer). - static const int kRegExpExecuteArguments = 8; - static const int kParameterRegisters = 4; + const int kRegExpExecuteArguments = 8; + const int kParameterRegisters = 4; __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); // Stack pointer now points to cell where return address is to be written. @@ -5714,7 +5714,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, // scratch: - // Perform a number of probes in the symbol table. - static const int kProbes = 4; + const int kProbes = 4; Label found_in_symbol_table; Label next_probe[kProbes]; Register candidate = scratch5; // Scratch register contains candidate. @@ -5839,9 +5839,9 @@ void SubStringStub::Generate(MacroAssembler* masm) { // 0 <= from <= to <= string.length. // If any of these assumptions fail, we call the runtime system. - static const int kToOffset = 0 * kPointerSize; - static const int kFromOffset = 1 * kPointerSize; - static const int kStringOffset = 2 * kPointerSize; + const int kToOffset = 0 * kPointerSize; + const int kFromOffset = 1 * kPointerSize; + const int kStringOffset = 2 * kPointerSize; __ Ldrd(r2, r3, MemOperand(sp, kToOffset)); STATIC_ASSERT(kFromOffset == kToOffset + 4); @@ -7085,43 +7085,45 @@ struct AheadOfTimeWriteBarrierStubList { RememberedSetAction action; }; +#define REG(Name) { kRegister_ ## Name ## _Code } -struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { +static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { // Used in RegExpExecStub. - { r6, r4, r7, EMIT_REMEMBERED_SET }, - { r6, r2, r7, EMIT_REMEMBERED_SET }, + { REG(r6), REG(r4), REG(r7), EMIT_REMEMBERED_SET }, + { REG(r6), REG(r2), REG(r7), EMIT_REMEMBERED_SET }, // Used in CompileArrayPushCall. // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore. // Also used in KeyedStoreIC::GenerateGeneric. - { r3, r4, r5, EMIT_REMEMBERED_SET }, + { REG(r3), REG(r4), REG(r5), EMIT_REMEMBERED_SET }, // Used in CompileStoreGlobal. - { r4, r1, r2, OMIT_REMEMBERED_SET }, + { REG(r4), REG(r1), REG(r2), OMIT_REMEMBERED_SET }, // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField. - { r1, r2, r3, EMIT_REMEMBERED_SET }, - { r3, r2, r1, EMIT_REMEMBERED_SET }, + { REG(r1), REG(r2), REG(r3), EMIT_REMEMBERED_SET }, + { REG(r3), REG(r2), REG(r1), EMIT_REMEMBERED_SET }, // Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. - { r2, r1, r3, EMIT_REMEMBERED_SET }, - { r3, r1, r2, EMIT_REMEMBERED_SET }, + { REG(r2), REG(r1), REG(r3), EMIT_REMEMBERED_SET }, + { REG(r3), REG(r1), REG(r2), EMIT_REMEMBERED_SET }, // KeyedStoreStubCompiler::GenerateStoreFastElement. - { r3, r2, r4, EMIT_REMEMBERED_SET }, - { r2, r3, r4, EMIT_REMEMBERED_SET }, + { REG(r3), REG(r2), REG(r4), EMIT_REMEMBERED_SET }, + { REG(r2), REG(r3), REG(r4), EMIT_REMEMBERED_SET }, // ElementsTransitionGenerator::GenerateSmiOnlyToObject // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble // and ElementsTransitionGenerator::GenerateDoubleToObject - { r2, r3, r9, EMIT_REMEMBERED_SET }, - { r2, r3, r9, OMIT_REMEMBERED_SET }, + { REG(r2), REG(r3), REG(r9), EMIT_REMEMBERED_SET }, + { REG(r2), REG(r3), REG(r9), OMIT_REMEMBERED_SET }, // ElementsTransitionGenerator::GenerateDoubleToObject - { r6, r2, r0, EMIT_REMEMBERED_SET }, - { r2, r6, r9, EMIT_REMEMBERED_SET }, + { REG(r6), REG(r2), REG(r0), EMIT_REMEMBERED_SET }, + { REG(r2), REG(r6), REG(r9), EMIT_REMEMBERED_SET }, // StoreArrayLiteralElementStub::Generate - { r5, r0, r6, EMIT_REMEMBERED_SET }, + { REG(r5), REG(r0), REG(r6), EMIT_REMEMBERED_SET }, // Null termination. - { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET} + { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET} }; +#undef REG bool RecordWriteStub::IsPregenerated() { - for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; + for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; !entry->object.is(no_reg); entry++) { if (object_.is(entry->object) && @@ -7148,7 +7150,7 @@ void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() { void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { - for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; + for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; !entry->object.is(no_reg); entry++) { RecordWriteStub stub(entry->object, diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 6e18277..befd8f2 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -37,8 +37,7 @@ namespace internal { #define __ ACCESS_MASM(masm) -TranscendentalFunction CreateTranscendentalFunction( - TranscendentalCache::Type type) { +UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { switch (type) { case TranscendentalCache::SIN: return &sin; case TranscendentalCache::COS: return &cos; @@ -50,6 +49,10 @@ TranscendentalFunction CreateTranscendentalFunction( } +UnaryMathFunction CreateSqrtFunction() { + return &sqrt; +} + // ------------------------------------------------------------------------- // Platform-specific RuntimeCallHelper functions. diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index d9a4d4b..7b2a3c4 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -108,6 +108,10 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } +static const int32_t kBranchBeforeStackCheck = 0x2a000001; +static const int32_t kBranchBeforeInterrupt = 0x5a000004; + + void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, Address pc_after, Code* check_code, @@ -118,10 +122,16 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, // 2a 00 00 01 bcs ok // e5 9f c? ?? ldr ip, [pc, ] // e1 2f ff 3c blx ip - ASSERT(Memory::int32_at(pc_after - kInstrSize) == - (al | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | ip.code())); + ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp); ASSERT(Assembler::IsLdrPcImmediateOffset( Assembler::instr_at(pc_after - 2 * kInstrSize))); + if (FLAG_count_based_interrupts) { + ASSERT_EQ(kBranchBeforeInterrupt, + Memory::int32_at(pc_after - 3 * kInstrSize)); + } else { + ASSERT_EQ(kBranchBeforeStackCheck, + Memory::int32_at(pc_after - 3 * kInstrSize)); + } // We patch the code to the following form: // e1 5d 00 0c cmp sp, @@ -155,13 +165,21 @@ void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code, Code* check_code, Code* replacement_code) { const int kInstrSize = Assembler::kInstrSize; - ASSERT(Memory::uint32_at(pc_after - kInstrSize) == 0xe12fff3c); - ASSERT(Memory::uint8_at(pc_after - kInstrSize - 1) == 0xe5); - ASSERT(Memory::uint8_at(pc_after - kInstrSize - 2) == 0x9f); + ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp); + ASSERT(Assembler::IsLdrPcImmediateOffset( + Assembler::instr_at(pc_after - 2 * kInstrSize))); // Replace NOP with conditional jump. CodePatcher patcher(pc_after - 3 * kInstrSize, 1); - patcher.masm()->b(+4, cs); + if (FLAG_count_based_interrupts) { + patcher.masm()->b(+16, pl); + ASSERT_EQ(kBranchBeforeInterrupt, + Memory::int32_at(pc_after - 3 * kInstrSize)); + } else { + patcher.masm()->b(+4, cs); + ASSERT_EQ(kBranchBeforeStackCheck, + Memory::int32_at(pc_after - 3 * kInstrSize)); + } // Replace the stack check address in the constant pool // with the entry address of the replacement code. diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 77f4e44..0cbd46e 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -34,6 +34,7 @@ #include "compiler.h" #include "debug.h" #include "full-codegen.h" +#include "isolate-inl.h" #include "parser.h" #include "scopes.h" #include "stub-cache.h" @@ -109,7 +110,9 @@ class JumpPatchSite BASE_EMBEDDED { }; +// TODO(jkummerow): Obsolete as soon as x64 is updated. Remove. int FullCodeGenerator::self_optimization_header_size() { + UNREACHABLE(); return 24; } @@ -132,32 +135,11 @@ void FullCodeGenerator::Generate() { CompilationInfo* info = info_; handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); + profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell( + Handle(Smi::FromInt(FLAG_interrupt_budget))); SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); - // We can optionally optimize based on counters rather than statistical - // sampling. - if (info->ShouldSelfOptimize()) { - if (FLAG_trace_opt_verbose) { - PrintF("[adding self-optimization header to %s]\n", - *info->function()->debug_name()->ToCString()); - } - has_self_optimization_header_ = true; - MaybeObject* maybe_cell = isolate()->heap()->AllocateJSGlobalPropertyCell( - Smi::FromInt(Compiler::kCallsUntilPrimitiveOpt)); - JSGlobalPropertyCell* cell; - if (maybe_cell->To(&cell)) { - __ mov(r2, Operand(Handle(cell))); - __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); - __ sub(r3, r3, Operand(Smi::FromInt(1)), SetCC); - __ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); - Handle compile_stub( - isolate()->builtins()->builtin(Builtins::kLazyRecompile)); - __ Jump(compile_stub, RelocInfo::CODE_TARGET, eq); - ASSERT(masm_->pc_offset() == self_optimization_header_size()); - } - } - #ifdef DEBUG if (strlen(FLAG_stop_at) > 0 && info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { @@ -336,20 +318,68 @@ void FullCodeGenerator::ClearAccumulator() { } +void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { + __ mov(r2, Operand(profiling_counter_)); + __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); + __ sub(r3, r3, Operand(Smi::FromInt(delta)), SetCC); + __ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); +} + + +void FullCodeGenerator::EmitProfilingCounterReset() { + int reset_value = FLAG_interrupt_budget; + if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { + // Self-optimization is a one-off thing: if it fails, don't try again. + reset_value = Smi::kMaxValue; + } + if (isolate()->IsDebuggerActive()) { + // Detect debug break requests as soon as possible. + reset_value = 10; + } + __ mov(r2, Operand(profiling_counter_)); + __ mov(r3, Operand(Smi::FromInt(reset_value))); + __ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); +} + + +static const int kMaxBackEdgeWeight = 127; +static const int kBackEdgeDistanceDivisor = 142; + + void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, Label* back_edge_target) { Comment cmnt(masm_, "[ Stack check"); Label ok; - __ LoadRoot(ip, Heap::kStackLimitRootIndex); - __ cmp(sp, Operand(ip)); - __ b(hs, &ok); - StackCheckStub stub; - __ CallStub(&stub); + + if (FLAG_count_based_interrupts) { + int weight = 1; + if (FLAG_weighted_back_edges) { + ASSERT(back_edge_target->is_bound()); + int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); + weight = Min(kMaxBackEdgeWeight, + Max(1, distance / kBackEdgeDistanceDivisor)); + } + EmitProfilingCounterDecrement(weight); + __ b(pl, &ok); + InterruptStub stub; + __ CallStub(&stub); + } else { + __ LoadRoot(ip, Heap::kStackLimitRootIndex); + __ cmp(sp, Operand(ip)); + __ b(hs, &ok); + StackCheckStub stub; + __ CallStub(&stub); + } + // Record a mapping of this PC offset to the OSR id. This is used to find // the AST id from the unoptimized code in order to use it as a key into // the deoptimization input data found in the optimized code. RecordStackCheck(stmt->OsrEntryId()); + if (FLAG_count_based_interrupts) { + EmitProfilingCounterReset(); + } + __ bind(&ok); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); // Record a mapping of the OSR id to this PC. This is used if the OSR @@ -371,6 +401,32 @@ void FullCodeGenerator::EmitReturnSequence() { __ push(r0); __ CallRuntime(Runtime::kTraceExit, 1); } + if (FLAG_interrupt_at_exit || FLAG_self_optimization) { + // Pretend that the exit is a backwards jump to the entry. + int weight = 1; + if (info_->ShouldSelfOptimize()) { + weight = FLAG_interrupt_budget / FLAG_self_opt_count; + } else if (FLAG_weighted_back_edges) { + int distance = masm_->pc_offset(); + weight = Min(kMaxBackEdgeWeight, + Max(1, distance / kBackEdgeDistanceDivisor)); + } + EmitProfilingCounterDecrement(weight); + Label ok; + __ b(pl, &ok); + __ push(r0); + if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { + __ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); + __ push(r2); + __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); + } else { + InterruptStub stub; + __ CallStub(&stub); + } + __ pop(r0); + EmitProfilingCounterReset(); + __ bind(&ok); + } #ifdef DEBUG // Add a label for checking the size of the code used for returning. @@ -888,7 +944,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // Record position before stub call for type feedback. SetSourcePosition(clause->position()); Handle ic = CompareIC::GetUninitialized(Token::EQ_STRICT); - __ Call(ic, RelocInfo::CODE_TARGET, clause->CompareId()); + CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); patch_site.EmitPatchInfo(); __ cmp(r0, Operand(0)); @@ -1186,7 +1242,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT; Handle ic = isolate()->builtins()->LoadIC_Initialize(); - __ Call(ic, mode); + CallIC(ic, mode); } @@ -1270,7 +1326,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { __ ldr(r0, GlobalObjectOperand()); __ mov(r2, Operand(var->name())); Handle ic = isolate()->builtins()->LoadIC_Initialize(); - __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); context()->Plug(r0); break; } @@ -1410,6 +1466,16 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { } +void FullCodeGenerator::EmitAccessor(Expression* expression) { + if (expression == NULL) { + __ LoadRoot(r1, Heap::kNullValueRootIndex); + __ push(r1); + } else { + VisitForStackValue(expression); + } +} + + void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); Handle constant_properties = expr->constant_properties(); @@ -1445,6 +1511,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { // marked expressions, no store code is emitted. expr->CalculateEmitStore(); + AccessorTable accessor_table(isolate()->zone()); for (int i = 0; i < expr->properties()->length(); i++) { ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; @@ -1470,7 +1537,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Handle ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ Call(ic, RelocInfo::CODE_TARGET, key->id()); + CallIC(ic, RelocInfo::CODE_TARGET, key->id()); PrepareForBailoutForId(key->id(), NO_REGISTERS); } else { VisitForEffect(value); @@ -1493,27 +1560,29 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { } break; case ObjectLiteral::Property::GETTER: + accessor_table.lookup(key)->second->getter = value; + break; case ObjectLiteral::Property::SETTER: - // Duplicate receiver on stack. - __ ldr(r0, MemOperand(sp)); - __ push(r0); - VisitForStackValue(key); - if (property->kind() == ObjectLiteral::Property::GETTER) { - VisitForStackValue(value); - __ LoadRoot(r1, Heap::kNullValueRootIndex); - __ push(r1); - } else { - __ LoadRoot(r1, Heap::kNullValueRootIndex); - __ push(r1); - VisitForStackValue(value); - } - __ mov(r0, Operand(Smi::FromInt(NONE))); - __ push(r0); - __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5); + accessor_table.lookup(key)->second->setter = value; break; } } + // Emit code to define accessors, using only a single call to the runtime for + // each pair of corresponding getters and setters. + for (AccessorTable::Iterator it = accessor_table.begin(); + it != accessor_table.end(); + ++it) { + __ ldr(r0, MemOperand(sp)); // Duplicate receiver. + __ push(r0); + VisitForStackValue(it->first); + EmitAccessor(it->second->getter); + EmitAccessor(it->second->setter); + __ mov(r0, Operand(Smi::FromInt(NONE))); + __ push(r0); + __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5); + } + if (expr->has_function()) { ASSERT(result_saved); __ ldr(r0, MemOperand(sp)); @@ -1736,7 +1805,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ mov(r2, Operand(key->handle())); // Call load IC. It has arguments receiver and property name r0 and r2. Handle ic = isolate()->builtins()->LoadIC_Initialize(); - __ Call(ic, RelocInfo::CODE_TARGET, prop->id()); + CallIC(ic, RelocInfo::CODE_TARGET, prop->id()); } @@ -1744,7 +1813,7 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); // Call keyed load IC. It has arguments key and receiver in r0 and r1. Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - __ Call(ic, RelocInfo::CODE_TARGET, prop->id()); + CallIC(ic, RelocInfo::CODE_TARGET, prop->id()); } @@ -1771,7 +1840,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, __ bind(&stub_call); BinaryOpStub stub(op, mode); - __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); patch_site.EmitPatchInfo(); __ jmp(&done); @@ -1854,7 +1923,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, __ pop(r1); BinaryOpStub stub(op, mode); JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. - __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); patch_site.EmitPatchInfo(); context()->Plug(r0); } @@ -1895,7 +1964,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { Handle ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ Call(ic); + CallIC(ic); break; } case KEYED_PROPERTY: { @@ -1908,7 +1977,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { Handle ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - __ Call(ic); + CallIC(ic); break; } } @@ -1925,7 +1994,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Handle ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); } else if (op == Token::INIT_CONST) { // Const initializers need a write barrier. @@ -2043,7 +2112,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { Handle ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); // If the assignment ends an initialization block, revert to fast case. if (expr->ends_initialization_block()) { @@ -2089,7 +2158,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { Handle ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); // If the assignment ends an initialization block, revert to fast case. if (expr->ends_initialization_block()) { @@ -2123,6 +2192,14 @@ void FullCodeGenerator::VisitProperty(Property* expr) { } } + +void FullCodeGenerator::CallIC(Handle code, + RelocInfo::Mode rmode, + unsigned ast_id) { + ic_total_count_++; + __ Call(code, rmode, ast_id); +} + void FullCodeGenerator::EmitCallWithIC(Call* expr, Handle name, RelocInfo::Mode mode) { @@ -2140,7 +2217,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, // Call the IC initialization code. Handle ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); - __ Call(ic, mode, expr->id()); + CallIC(ic, mode, expr->id()); RecordJSReturnSite(expr); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -2173,7 +2250,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, Handle ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. - __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); RecordJSReturnSite(expr); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -3770,7 +3847,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { RelocInfo::Mode mode = RelocInfo::CODE_TARGET; Handle ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); - __ Call(ic, mode, expr->id()); + CallIC(ic, mode, expr->id()); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); } else { @@ -3925,7 +4002,7 @@ void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, // accumulator register r0. VisitForAccumulatorValue(expr->expression()); SetSourcePosition(expr->position()); - __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); context()->Plug(r0); } @@ -4036,7 +4113,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { SetSourcePosition(expr->position()); BinaryOpStub stub(Token::ADD, NO_OVERWRITE); - __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); patch_site.EmitPatchInfo(); __ bind(&done); @@ -4068,7 +4145,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Handle ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { if (!context()->IsEffect()) { @@ -4085,7 +4162,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Handle ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { if (!context()->IsEffect()) { @@ -4111,7 +4188,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { Handle ic = isolate()->builtins()->LoadIC_Initialize(); // Use a regular load, not a contextual load, to avoid a reference // error. - __ Call(ic); + CallIC(ic); PrepareForBailout(expr, TOS_REG); context()->Plug(r0); } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { @@ -4294,7 +4371,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { // Record position and call the compare IC. SetSourcePosition(expr->position()); Handle ic = CompareIC::GetUninitialized(op); - __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); patch_site.EmitPatchInfo(); PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); __ cmp(r0, Operand(0)); diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index 36421d9..cdc1947 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -1098,6 +1098,14 @@ LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal( } +LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) { + LOperand* receiver = UseRegisterAtStart(instr->receiver()); + LOperand* function = UseRegisterAtStart(instr->function()); + LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function); + return AssignEnvironment(DefineSameAsFirst(result)); +} + + LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) { LOperand* function = UseFixed(instr->function(), r1); LOperand* receiver = UseFixed(instr->receiver(), r0); diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index ae19677..62cde6e 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -178,7 +178,8 @@ class LCodeGen; V(ForInCacheArray) \ V(CheckMapValue) \ V(LoadFieldByIndex) \ - V(DateField) + V(DateField) \ + V(WrapReceiver) #define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \ @@ -468,6 +469,20 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> { }; +class LWrapReceiver: public LTemplateInstruction<1, 2, 0> { + public: + LWrapReceiver(LOperand* receiver, LOperand* function) { + inputs_[0] = receiver; + inputs_[1] = function; + } + + DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver") + + LOperand* receiver() { return inputs_[0]; } + LOperand* function() { return inputs_[1]; } +}; + + class LApplyArguments: public LTemplateInstruction<1, 4, 0> { public: LApplyArguments(LOperand* function, diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 012ea45..82b80a2 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -648,7 +648,6 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { ASSERT(environment->HasBeenRegistered()); int id = environment->deoptimization_index(); Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); - ASSERT(entry != NULL); if (entry == NULL) { Abort("bailout was not prepared"); return; @@ -2800,15 +2799,10 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { } -void LCodeGen::DoApplyArguments(LApplyArguments* instr) { +void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { Register receiver = ToRegister(instr->receiver()); Register function = ToRegister(instr->function()); - Register length = ToRegister(instr->length()); - Register elements = ToRegister(instr->elements()); Register scratch = scratch0(); - ASSERT(receiver.is(r0)); // Used for parameter count. - ASSERT(function.is(r1)); // Required by InvokeFunction. - ASSERT(ToRegister(instr->result()).is(r0)); // If the receiver is null or undefined, we have to pass the global // object as a receiver to normal functions. Values have to be @@ -2849,6 +2843,18 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { __ ldr(receiver, FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset)); __ bind(&receiver_ok); +} + + +void LCodeGen::DoApplyArguments(LApplyArguments* instr) { + Register receiver = ToRegister(instr->receiver()); + Register function = ToRegister(instr->function()); + Register length = ToRegister(instr->length()); + Register elements = ToRegister(instr->elements()); + Register scratch = scratch0(); + ASSERT(receiver.is(r0)); // Used for parameter count. + ASSERT(function.is(r1)); // Required by InvokeFunction. + ASSERT(ToRegister(instr->result()).is(r0)); // Copy the arguments to this function possibly from the // adaptor frame below it. @@ -4601,34 +4607,51 @@ void LCodeGen::EmitDeepCopy(Handle object, } } - // Copy elements backing store header. - ASSERT(!has_elements || elements->IsFixedArray()); if (has_elements) { + // Copy elements backing store header. __ LoadHeapObject(source, elements); for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) { __ ldr(r2, FieldMemOperand(source, i)); __ str(r2, FieldMemOperand(result, elements_offset + i)); } - } - // Copy elements backing store content. - ASSERT(!has_elements || elements->IsFixedArray()); - int elements_length = has_elements ? elements->length() : 0; - for (int i = 0; i < elements_length; i++) { - int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i); - Handle value = JSObject::GetElement(object, i); - if (value->IsJSObject()) { - Handle value_object = Handle::cast(value); - __ add(r2, result, Operand(*offset)); - __ str(r2, FieldMemOperand(result, total_offset)); - __ LoadHeapObject(source, value_object); - EmitDeepCopy(value_object, result, source, offset); - } else if (value->IsHeapObject()) { - __ LoadHeapObject(r2, Handle::cast(value)); - __ str(r2, FieldMemOperand(result, total_offset)); + // Copy elements backing store content. + int elements_length = has_elements ? elements->length() : 0; + if (elements->IsFixedDoubleArray()) { + Handle double_array = + Handle::cast(elements); + for (int i = 0; i < elements_length; i++) { + int64_t value = double_array->get_representation(i); + // We only support little endian mode... + int32_t value_low = value & 0xFFFFFFFF; + int32_t value_high = value >> 32; + int total_offset = + elements_offset + FixedDoubleArray::OffsetOfElementAt(i); + __ mov(r2, Operand(value_low)); + __ str(r2, FieldMemOperand(result, total_offset)); + __ mov(r2, Operand(value_high)); + __ str(r2, FieldMemOperand(result, total_offset + 4)); + } + } else if (elements->IsFixedArray()) { + for (int i = 0; i < elements_length; i++) { + int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i); + Handle value = JSObject::GetElement(object, i); + if (value->IsJSObject()) { + Handle value_object = Handle::cast(value); + __ add(r2, result, Operand(*offset)); + __ str(r2, FieldMemOperand(result, total_offset)); + __ LoadHeapObject(source, value_object); + EmitDeepCopy(value_object, result, source, offset); + } else if (value->IsHeapObject()) { + __ LoadHeapObject(r2, Handle::cast(value)); + __ str(r2, FieldMemOperand(result, total_offset)); + } else { + __ mov(r2, Operand(value)); + __ str(r2, FieldMemOperand(result, total_offset)); + } + } } else { - __ mov(r2, Operand(value)); - __ str(r2, FieldMemOperand(result, total_offset)); + UNREACHABLE(); } } } diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 45dd80f..857c2bf 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -3647,8 +3647,8 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg, bind(&in_bounds); Vmov(temp_double_reg, 0.5); vadd(temp_double_reg, input_reg, temp_double_reg); - vcvt_u32_f64(s0, temp_double_reg); - vmov(result_reg, s0); + vcvt_u32_f64(temp_double_reg.low(), temp_double_reg); + vmov(result_reg, temp_double_reg.low()); bind(&done); } diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index de83c13..10ff2dd 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -472,7 +472,7 @@ void RegExpMacroAssemblerARM::CheckNotCharacterAfterMinusAnd( uc16 minus, uc16 mask, Label* on_not_equal) { - ASSERT(minus < String::kMaxUC16CharCode); + ASSERT(minus < String::kMaxUtf16CodeUnit); __ sub(r0, current_character(), Operand(minus)); __ and_(r0, r0, Operand(mask)); __ cmp(r0, Operand(c)); diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 74fca2e..06f8385 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -1387,14 +1387,8 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(Handle object, // Get the receiver from the stack. __ ldr(r0, MemOperand(sp, argc * kPointerSize)); - // If the object is the holder then we know that it's a global - // object which can only happen for contextual calls. In this case, - // the receiver cannot be a smi. - if (!object.is_identical_to(holder)) { - __ JumpIfSmi(r0, miss); - } - // Check that the maps haven't changed. + __ JumpIfSmi(r0, miss); CheckPrototypes(object, r0, holder, r3, r1, r4, name, miss); } @@ -2813,14 +2807,8 @@ Handle LoadStubCompiler::CompileLoadGlobal( // ----------------------------------- Label miss; - // If the object is the holder then we know that it's a global - // object which can only happen for contextual calls. In this case, - // the receiver cannot be a smi. - if (!object.is_identical_to(holder)) { - __ JumpIfSmi(r0, &miss); - } - // Check that the map of the global has not changed. + __ JumpIfSmi(r0, &miss); CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss); // Get the value from the cell. diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index 07509b5..4944202 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -45,6 +45,7 @@ #include "ic.h" #include "isolate.h" #include "jsregexp.h" +#include "lazy-instance.h" #include "platform.h" #include "regexp-macro-assembler.h" #include "regexp-stack.h" @@ -84,15 +85,36 @@ namespace v8 { namespace internal { +// ----------------------------------------------------------------------------- +// Common double constants. + +struct DoubleConstant BASE_EMBEDDED { + double min_int; + double one_half; + double minus_zero; + double zero; + double uint8_max_value; + double negative_infinity; + double canonical_non_hole_nan; + double the_hole_nan; +}; + +struct InitializeDoubleConstants { + static void Construct(DoubleConstant* double_constants) { + double_constants->min_int = kMinInt; + double_constants->one_half = 0.5; + double_constants->minus_zero = -0.0; + double_constants->uint8_max_value = 255; + double_constants->zero = 0.0; + double_constants->canonical_non_hole_nan = OS::nan_value(); + double_constants->the_hole_nan = BitCast(kHoleNanInt64); + double_constants->negative_infinity = -V8_INFINITY; + } +}; + +static LazyInstance::type + double_constants = LAZY_INSTANCE_INITIALIZER; -const double DoubleConstant::min_int = kMinInt; -const double DoubleConstant::one_half = 0.5; -const double DoubleConstant::minus_zero = -0.0; -const double DoubleConstant::uint8_max_value = 255; -const double DoubleConstant::zero = 0.0; -const double DoubleConstant::canonical_non_hole_nan = OS::nan_value(); -const double DoubleConstant::the_hole_nan = BitCast(kHoleNanInt64); -const double DoubleConstant::negative_infinity = -V8_INFINITY; const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING"; // ----------------------------------------------------------------------------- @@ -937,49 +959,49 @@ ExternalReference ExternalReference::scheduled_exception_address( ExternalReference ExternalReference::address_of_min_int() { return ExternalReference(reinterpret_cast( - const_cast(&DoubleConstant::min_int))); + &double_constants.Pointer()->min_int)); } ExternalReference ExternalReference::address_of_one_half() { return ExternalReference(reinterpret_cast( - const_cast(&DoubleConstant::one_half))); + &double_constants.Pointer()->one_half)); } ExternalReference ExternalReference::address_of_minus_zero() { return ExternalReference(reinterpret_cast( - const_cast(&DoubleConstant::minus_zero))); + &double_constants.Pointer()->minus_zero)); } ExternalReference ExternalReference::address_of_zero() { return ExternalReference(reinterpret_cast( - const_cast(&DoubleConstant::zero))); + &double_constants.Pointer()->zero)); } ExternalReference ExternalReference::address_of_uint8_max_value() { return ExternalReference(reinterpret_cast( - const_cast(&DoubleConstant::uint8_max_value))); + &double_constants.Pointer()->uint8_max_value)); } ExternalReference ExternalReference::address_of_negative_infinity() { return ExternalReference(reinterpret_cast( - const_cast(&DoubleConstant::negative_infinity))); + &double_constants.Pointer()->negative_infinity)); } ExternalReference ExternalReference::address_of_canonical_non_hole_nan() { return ExternalReference(reinterpret_cast( - const_cast(&DoubleConstant::canonical_non_hole_nan))); + &double_constants.Pointer()->canonical_non_hole_nan)); } ExternalReference ExternalReference::address_of_the_hole_nan() { return ExternalReference(reinterpret_cast( - const_cast(&DoubleConstant::the_hole_nan))); + &double_constants.Pointer()->the_hole_nan)); } diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 5063879..918a2a6 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -67,21 +67,6 @@ class AssemblerBase: public Malloced { int jit_cookie_; }; -// ----------------------------------------------------------------------------- -// Common double constants. - -class DoubleConstant: public AllStatic { - public: - static const double min_int; - static const double one_half; - static const double minus_zero; - static const double zero; - static const double uint8_max_value; - static const double negative_infinity; - static const double canonical_non_hole_nan; - static const double the_hole_nan; -}; - // ----------------------------------------------------------------------------- // Labels represent pc locations; they are typically jump or call targets. diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 239e5d0..4b6ae68 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -399,6 +399,9 @@ bool FunctionDeclaration::IsInlineable() const { void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { // Record type feedback from the oracle in the AST. + is_uninitialized_ = oracle->LoadIsUninitialized(this); + if (is_uninitialized_) return; + is_monomorphic_ = oracle->LoadIsMonomorphicNormal(this); receiver_types_.Clear(); if (key()->IsPropertyName()) { @@ -602,6 +605,13 @@ void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) { } +void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { + receiver_type_ = oracle->ObjectLiteralStoreIsMonomorphic(this) + ? oracle->GetObjectLiteralStoreMap(this) + : Handle::null(); +} + + // ---------------------------------------------------------------------------- // Implementation of AstVisitor @@ -1054,8 +1064,6 @@ void AstConstructionVisitor::VisitForStatement(ForStatement* node) { void AstConstructionVisitor::VisitForInStatement(ForInStatement* node) { increase_node_count(); - add_flag(kDontOptimize); - add_flag(kDontInline); add_flag(kDontSelfOptimize); } diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 0986488..b827302 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -1320,6 +1320,11 @@ class ObjectLiteral: public MaterializedLiteral { Expression* value() { return value_; } Kind kind() { return kind_; } + // Type feedback information. + void RecordTypeFeedback(TypeFeedbackOracle* oracle); + bool IsMonomorphic() { return !receiver_type_.is_null(); } + Handle GetReceiverType() { return receiver_type_; } + bool IsCompileTimeValue(); void set_emit_store(bool emit_store); @@ -1336,6 +1341,7 @@ class ObjectLiteral: public MaterializedLiteral { Expression* value_; Kind kind_; bool emit_store_; + Handle receiver_type_; }; DECLARE_NODE_TYPE(ObjectLiteral) @@ -1360,6 +1366,12 @@ class ObjectLiteral: public MaterializedLiteral { kHasFunction = 1 << 1 }; + struct Accessors: public ZoneObject { + Accessors() : getter(NULL), setter(NULL) { } + Expression* getter; + Expression* setter; + }; + protected: template friend class AstNodeFactory; @@ -1515,6 +1527,7 @@ class Property: public Expression { virtual bool IsMonomorphic() { return is_monomorphic_; } virtual SmallMapList* GetReceiverTypes() { return &receiver_types_; } bool IsArrayLength() { return is_array_length_; } + bool IsUninitialized() { return is_uninitialized_; } protected: template friend class AstNodeFactory; @@ -1528,6 +1541,7 @@ class Property: public Expression { key_(key), pos_(pos), is_monomorphic_(false), + is_uninitialized_(false), is_array_length_(false), is_string_length_(false), is_string_access_(false), @@ -1540,6 +1554,7 @@ class Property: public Expression { SmallMapList receiver_types_; bool is_monomorphic_ : 1; + bool is_uninitialized_ : 1; bool is_array_length_ : 1; bool is_string_length_ : 1; bool is_string_access_ : 1; diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index ca202f2..0f493e6 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -33,6 +33,7 @@ #include "builtins.h" #include "gdb-jit.h" #include "ic-inl.h" +#include "heap-profiler.h" #include "mark-compact.h" #include "vm-state-inl.h" @@ -380,6 +381,8 @@ static FixedArray* LeftTrimFixedArray(Heap* heap, MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); } + HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(), + elms->address() + size_delta)); return FixedArray::cast(HeapObject::FromAddress( elms->address() + to_trim * kPointerSize)); } @@ -508,8 +511,7 @@ BUILTIN(ArrayPush) { } FixedArray* new_elms = FixedArray::cast(obj); - AssertNoAllocation no_gc; - CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, 0, + CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0, new_elms, FAST_ELEMENTS, 0, len); FillWithHoles(heap, new_elms, new_length, capacity); @@ -645,8 +647,7 @@ BUILTIN(ArrayUnshift) { if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* new_elms = FixedArray::cast(obj); - AssertNoAllocation no_gc; - CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, 0, + CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0, new_elms, FAST_ELEMENTS, to_add, len); FillWithHoles(heap, new_elms, new_length, capacity); elms = new_elms; @@ -757,8 +758,7 @@ BUILTIN(ArraySlice) { JSArray* result_array; if (!maybe_array->To(&result_array)) return maybe_array; - AssertNoAllocation no_gc; - CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, k, + CopyObjectToObjectElements(elms, FAST_ELEMENTS, k, FixedArray::cast(result_array->elements()), FAST_ELEMENTS, 0, result_len); @@ -831,9 +831,8 @@ BUILTIN(ArraySplice) { if (!maybe_array->To(&result_array)) return maybe_array; { - AssertNoAllocation no_gc; // Fill newly created array. - CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, actual_start, + CopyObjectToObjectElements(elms, FAST_ELEMENTS, actual_start, FixedArray::cast(result_array->elements()), FAST_ELEMENTS, 0, actual_delete_count); } @@ -883,12 +882,11 @@ BUILTIN(ArraySplice) { FixedArray* new_elms = FixedArray::cast(obj); { - AssertNoAllocation no_gc; // Copy the part before actual_start as is. - CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, 0, + CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0, new_elms, FAST_ELEMENTS, 0, actual_start); const int to_copy = len - actual_delete_count - actual_start; - CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, + CopyObjectToObjectElements(elms, FAST_ELEMENTS, actual_start + actual_delete_count, new_elms, FAST_ELEMENTS, actual_start + item_count, to_copy); @@ -973,14 +971,13 @@ BUILTIN(ArrayConcat) { if (result_len == 0) return result_array; // Copy data. - AssertNoAllocation no_gc; int start_pos = 0; FixedArray* result_elms(FixedArray::cast(result_array->elements())); for (int i = 0; i < n_arguments; i++) { JSArray* array = JSArray::cast(args[i]); int len = Smi::cast(array->length())->value(); FixedArray* elms = FixedArray::cast(array->elements()); - CopyObjectToObjectElements(&no_gc, elms, FAST_ELEMENTS, 0, + CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0, result_elms, FAST_ELEMENTS, start_pos, len); start_pos += len; @@ -1570,30 +1567,30 @@ struct BuiltinDesc { BuiltinExtraArguments extra_args; }; +#define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} } + class BuiltinFunctionTable { public: - BuiltinFunctionTable() { - Builtins::InitBuiltinFunctionTable(); + BuiltinDesc* functions() { + CallOnce(&once_, &Builtins::InitBuiltinFunctionTable); + return functions_; } - static const BuiltinDesc* functions() { return functions_; } - - private: - static BuiltinDesc functions_[Builtins::builtin_count + 1]; + OnceType once_; + BuiltinDesc functions_[Builtins::builtin_count + 1]; friend class Builtins; }; -BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1]; - -static const BuiltinFunctionTable builtin_function_table_init; +static BuiltinFunctionTable builtin_function_table = + BUILTIN_FUNCTION_TABLE_INIT; // Define array of pointers to generators and C builtin functions. // We do this in a sort of roundabout way so that we can do the initialization // within the lexical scope of Builtins:: and within a context where // Code::Flags names a non-abstract type. void Builtins::InitBuiltinFunctionTable() { - BuiltinDesc* functions = BuiltinFunctionTable::functions_; + BuiltinDesc* functions = builtin_function_table.functions_; functions[builtin_count].generator = NULL; functions[builtin_count].c_code = NULL; functions[builtin_count].s_name = NULL; @@ -1637,7 +1634,7 @@ void Builtins::SetUp(bool create_heap_objects) { // Create a scope for the handles in the builtins. HandleScope scope(isolate); - const BuiltinDesc* functions = BuiltinFunctionTable::functions(); + const BuiltinDesc* functions = builtin_function_table.functions(); // For now we generate builtin adaptor code into a stack-allocated // buffer, before copying it into individual code objects. Be careful diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc index 3f65120..0163580 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -71,13 +71,6 @@ void CodeGenerator::MakeCodePrologue(CompilationInfo* info) { } else { print_source = FLAG_print_source; print_ast = FLAG_print_ast; - Vector filter = CStrVector(FLAG_hydrogen_filter); - if (print_source && !filter.is_empty()) { - print_source = info->function()->name()->IsEqualTo(filter); - } - if (print_ast && !filter.is_empty()) { - print_ast = info->function()->name()->IsEqualTo(filter); - } ftype = "user-defined"; } @@ -124,11 +117,9 @@ void CodeGenerator::PrintCode(Handle code, CompilationInfo* info) { bool print_code = Isolate::Current()->bootstrapper()->IsActive() ? FLAG_print_builtin_code : (FLAG_print_code || (info->IsOptimizing() && FLAG_print_opt_code)); - Vector filter = CStrVector(FLAG_hydrogen_filter); - FunctionLiteral* function = info->function(); - bool match = filter.is_empty() || function->debug_name()->IsEqualTo(filter); - if (print_code && match) { + if (print_code) { // Print the source code if available. + FunctionLiteral* function = info->function(); Handle