diff --git a/ChangeLog b/ChangeLog index 566ec16a08..3f330c6bde 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,23 @@ -2012.01.16, Version 0.7.0 (unstable) +2012.01.23, Version 0.7.1 (unstable) + +* Update V8 to 3.8.8 + +* Install node-waf by default (Fedor Indutny) + +* crypto: Add ability to turn off PKCS padding (Ingmar Runge) + +* v8: implement VirtualMemory class on SunOS (Ben Noordhuis) + +* Add cluster.setupMaster (Andreas Madsen) + +* move `path.exists*` to `fs.exists*` (Maciej MaƂecki) + +* typed arrays: set class name (Ben Noordhuis) + +* libuv bug fixes (Igor Zinkovsky, Ben Noordhuis, Dan VerWeire) + + +2012.01.16, Version 0.7.0 (unstable), 9cc55dca6f67a6096c858b841c677b0593404321 * Upgrade V8 to 3.8.6 @@ -13,7 +32,7 @@ * Bug fixes -2012.01.19, Version 0.6.8 (stable) +2012.01.19, Version 0.6.8 (stable), d18cebaf8a7ac701dabd71a3aa4eb0571db6a645 * Update V8 to 3.6.6.19 diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 1c1bddda82..24af827b5e 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,41 @@ +2012-01-23: Version 3.8.8 + + Limited number of loop iterations in Heap::ReserveSpace + (Chromium issue 99027). + + Fixed solaris build (VirtualMemory) (issue 1761). + + Fixed strict vs. non-strict handling of function proxies in + higher-order array and string methods. + + Enabled asynchronous remote debugging with d8 (issue 1691). + + Stability and performance improvements on all platforms. + + +2012-01-19: Version 3.8.7 + + Ensure that LRandom restores rsi after call to the C function on x64. + (Chromium issue http://crbug.com/110509) + + Fixing include issues on *bsd when building with scons. + (issue 1897) + + Provide a switch to specify -fno-strict-aliasing + (issue 1887) + + Move WIN32 define from standalone.gypi to common.gypi + (issue 1760) + + Fix corner-case in heap size estimation. + (issue 1893) + + Fix and enable NEW_NON_STRICT_FAST ArgumentsAccess stub on x64. + (issue 1903) + + Performance improvements and bug fixes. + + 2012-01-16: Version 3.8.6 Add primitive WebGL array support to d8. diff --git a/deps/v8/Makefile b/deps/v8/Makefile index 09d1e8bdfe..73e84216b4 100644 --- a/deps/v8/Makefile +++ b/deps/v8/Makefile @@ -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: @@ -33,6 +33,8 @@ OUTDIR ?= out TESTJOBS ?= -j16 GYPFLAGS ?= TESTFLAGS ?= +ANDROID_NDK_ROOT ?= +ANDROID_TOOL_PREFIX = $(ANDROID_NDK_ROOT)/toolchain/bin/arm-linux-androideabi # Special build flags. Use them like this: "make library=shared" @@ -85,6 +87,10 @@ endif ifeq ($(presubmit), no) TESTFLAGS += --no-presubmit endif +# strictaliasing=off (workaround for GCC-4.5) +ifeq ($(strictaliasing), off) + GYPFLAGS += -Dv8_no_strict_aliasing=1 +endif # ----------------- available targets: -------------------- # - "dependencies": pulls in external dependencies (currently: GYP) @@ -93,6 +99,7 @@ endif # - every combination ., e.g. "ia32.release" # - "native": current host's architecture, release mode # - any of the above with .check appended, e.g. "ia32.release.check" +# - "android": cross-compile for Android/ARM (release mode) # - default (no target specified): build all DEFAULT_ARCHES and MODES # - "check": build all targets and run all tests # - ".clean" for any in ARCHES @@ -120,7 +127,8 @@ ENVFILE = $(OUTDIR)/environment .PHONY: all check clean dependencies $(ENVFILE).new native \ $(ARCHES) $(MODES) $(BUILDS) $(CHECKS) $(addsuffix .clean,$(ARCHES)) \ - $(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES)) + $(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES)) \ + must-set-ANDROID_NDK_ROOT # Target definitions. "all" is the default. all: $(MODES) @@ -144,6 +152,18 @@ native: $(OUTDIR)/Makefile-native CXX="$(CXX)" LINK="$(LINK)" BUILDTYPE=Release \ builddir="$(shell pwd)/$(OUTDIR)/$@" +# TODO(jkummerow): add "android.debug" when we need it. +android android.release: $(OUTDIR)/Makefile-android + @$(MAKE) -C "$(OUTDIR)" -f Makefile-android \ + CXX="$(ANDROID_TOOL_PREFIX)-g++" \ + AR="$(ANDROID_TOOL_PREFIX)-ar" \ + RANLIB="$(ANDROID_TOOL_PREFIX)-ranlib" \ + CC="$(ANDROID_TOOL_PREFIX)-gcc" \ + LD="$(ANDROID_TOOL_PREFIX)-ld" \ + LINK="$(ANDROID_TOOL_PREFIX)-g++" \ + BUILDTYPE=Release \ + builddir="$(shell pwd)/$(OUTDIR)/android.release" + # Test targets. check: all @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \ @@ -178,6 +198,11 @@ native.clean: rm -rf $(OUTDIR)/native find $(OUTDIR) -regex '.*\(host\|target\)-native\.mk' -delete +android.clean: + rm -f $(OUTDIR)/Makefile-android + rm -rf $(OUTDIR)/android.release + find $(OUTDIR) -regex '.*\(host\|target\)-android\.mk' -delete + clean: $(addsuffix .clean,$(ARCHES)) native.clean # GYP file generation targets. @@ -205,6 +230,18 @@ $(OUTDIR)/Makefile-native: $(GYPFILES) $(ENVFILE) build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ -Ibuild/standalone.gypi --depth=. -S-native $(GYPFLAGS) +$(OUTDIR)/Makefile-android: $(GYPFILES) $(ENVFILE) build/android.gypi \ + must-set-ANDROID_NDK_ROOT + CC="${ANDROID_TOOL_PREFIX}-gcc" \ + build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ + -Ibuild/standalone.gypi --depth=. -Ibuild/android.gypi \ + -S-android $(GYPFLAGS) + +must-set-ANDROID_NDK_ROOT: +ifndef ANDROID_NDK_ROOT + $(error ANDROID_NDK_ROOT is not set) +endif + # Replaces the old with the new environment file if they're different, which # will trigger GYP to regenerate Makefiles. $(ENVFILE): $(ENVFILE).new diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index 3f129079cb..d4eaebef8d 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -33,6 +33,7 @@ import os from os.path import join, dirname, abspath from types import DictType, StringTypes root_dir = dirname(File('SConstruct').rfile().abspath) +src_dir = join(root_dir, 'src') sys.path.insert(0, join(root_dir, 'tools')) import js2c, utils @@ -53,7 +54,7 @@ GCC_DTOA_EXTRA_CCFLAGS = [] LIBRARY_FLAGS = { 'all': { - 'CPPPATH': [join(root_dir, 'src')], + 'CPPPATH': [src_dir], 'regexp:interpreted': { 'CPPDEFINES': ['V8_INTERPRETED_REGEXP'] }, @@ -111,13 +112,13 @@ LIBRARY_FLAGS = { } }, 'os:freebsd': { - 'CPPPATH' : ['/usr/local/include'], + 'CPPPATH' : [src_dir, '/usr/local/include'], 'LIBPATH' : ['/usr/local/lib'], 'CCFLAGS': ['-ansi'], 'LIBS': ['execinfo'] }, 'os:openbsd': { - 'CPPPATH' : ['/usr/local/include'], + 'CPPPATH' : [src_dir, '/usr/local/include'], 'LIBPATH' : ['/usr/local/lib'], 'CCFLAGS': ['-ansi'], }, @@ -125,12 +126,12 @@ LIBRARY_FLAGS = { # On Solaris, to get isinf, INFINITY, fpclassify and other macros one # needs to define __C99FEATURES__. 'CPPDEFINES': ['__C99FEATURES__'], - 'CPPPATH' : ['/usr/local/include'], + 'CPPPATH' : [src_dir, '/usr/local/include'], 'LIBPATH' : ['/usr/local/lib'], 'CCFLAGS': ['-ansi'], }, 'os:netbsd': { - 'CPPPATH' : ['/usr/pkg/include'], + 'CPPPATH' : [src_dir, '/usr/pkg/include'], 'LIBPATH' : ['/usr/pkg/lib'], }, 'os:win32': { @@ -403,7 +404,7 @@ DTOA_EXTRA_FLAGS = { CCTEST_EXTRA_FLAGS = { 'all': { - 'CPPPATH': [join(root_dir, 'src')], + 'CPPPATH': [src_dir], 'library:shared': { 'CPPDEFINES': ['USING_V8_SHARED'] }, @@ -460,7 +461,7 @@ CCTEST_EXTRA_FLAGS = { SAMPLE_FLAGS = { 'all': { - 'CPPPATH': [join(abspath('.'), 'include')], + 'CPPPATH': [join(root_dir, 'include')], 'library:shared': { 'CPPDEFINES': ['USING_V8_SHARED'] }, @@ -643,7 +644,7 @@ SAMPLE_FLAGS = { PREPARSER_FLAGS = { 'all': { - 'CPPPATH': [join(abspath('.'), 'include'), join(abspath('.'), 'src')], + 'CPPPATH': [join(root_dir, 'include'), src_dir], 'library:shared': { 'CPPDEFINES': ['USING_V8_SHARED'] }, diff --git a/deps/v8/build/android.gypi b/deps/v8/build/android.gypi new file mode 100644 index 0000000000..ffd06484f7 --- /dev/null +++ b/deps/v8/build/android.gypi @@ -0,0 +1,225 @@ +# 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Definitions for building standalone V8 binaries to run on Android. +# This is mostly excerpted from: +# http://src.chromium.org/viewvc/chrome/trunk/src/build/common.gypi + +{ + 'variables': { + # Location of Android NDK. + 'variables': { + 'variables': { + 'android_ndk_root%': 'handle_scope_implementer()->RestoreContext(); isolate->set_context(last_context); + isolate->set_context_exit_happened(true); } diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 15ef9bcf9d..c33df5cf77 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -5821,7 +5821,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ b(eq, &return_r0); Label result_longer_than_two; - // Check for special case of two character ascii string, in which case + // Check for special case of two character ASCII string, in which case // we do a lookup in the symbol table first. __ cmp(r2, Operand(2)); __ b(gt, &result_longer_than_two); @@ -5951,7 +5951,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ tst(r1, Operand(kStringEncodingMask)); __ b(eq, &two_byte_sequential); - // Allocate and copy the resulting ascii string. + // Allocate and copy the resulting ASCII string. __ AllocateAsciiString(r0, r2, r4, r6, r7, &runtime); // Locate first character of substring to copy. @@ -6268,7 +6268,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ bind(&longer_than_two); // Check if resulting string will be flat. - __ cmp(r6, Operand(String::kMinNonFlatLength)); + __ cmp(r6, Operand(ConsString::kMinLength)); __ b(lt, &string_add_flat_result); // Handle exceptionally long strings in the runtime system. STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); @@ -6322,7 +6322,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ jmp(&allocated); // We cannot encounter sliced strings or cons strings here since: - STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); + STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); // Handle creating a flat result from either external or sequential strings. // Locate the first characters' locations. // r0: first string diff --git a/deps/v8/src/arm/constants-arm.h b/deps/v8/src/arm/constants-arm.h index 49b8db79f8..e767001e1d 100644 --- a/deps/v8/src/arm/constants-arm.h +++ b/deps/v8/src/arm/constants-arm.h @@ -573,13 +573,13 @@ class Instruction { // The naming of these accessor corresponds to figure A3-1. // // Two kind of accessors are declared: - // - Field() will return the raw field, ie the field's bits at their + // - Field() will return the raw field, i.e. the field's bits at their // original place in the instruction encoding. - // eg. if instr is the 'addgt r0, r1, r2' instruction, encoded as 0xC0810002 - // ConditionField(instr) will return 0xC0000000. + // e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as + // 0xC0810002 ConditionField(instr) will return 0xC0000000. // - Value() will return the field value, shifted back to bit 0. - // eg. if instr is the 'addgt r0, r1, r2' instruction, encoded as 0xC0810002 - // ConditionField(instr) will return 0xC. + // e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as + // 0xC0810002 ConditionField(instr) will return 0xC. // Generally applicable fields diff --git a/deps/v8/src/arm/disasm-arm.cc b/deps/v8/src/arm/disasm-arm.cc index 603b3cfd9c..16b568cbaf 100644 --- a/deps/v8/src/arm/disasm-arm.cc +++ b/deps/v8/src/arm/disasm-arm.cc @@ -473,7 +473,7 @@ int Decoder::FormatOption(Instruction* instr, const char* format) { return 1; } case 'i': { // 'i: immediate value from adjacent bits. - // Expects tokens in the form imm%02d@%02d, ie. imm05@07, imm10@16 + // Expects tokens in the form imm%02d@%02d, i.e. imm05@07, imm10@16 int width = (format[3] - '0') * 10 + (format[4] - '0'); int lsb = (format[6] - '0') * 10 + (format[7] - '0'); diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 38999a8e36..6654263989 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -115,7 +115,7 @@ class JumpPatchSite BASE_EMBEDDED { // function. // // The live registers are: -// o r1: the JS function object being called (ie, ourselves) +// o r1: the JS function object being called (i.e., ourselves) // o cp: our context // o fp: our caller's frame pointer // o sp: stack pointer @@ -3618,7 +3618,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // One-character separator case __ bind(&one_char_separator); - // Replace separator with its ascii character value. + // Replace separator with its ASCII character value. __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize)); // Jump into the loop after the code that copies the separator, so the first // element is not preceded by a separator @@ -3629,7 +3629,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // result_pos: the position to which we are currently copying characters. // element: Current array element. // elements_end: Array end. - // separator: Single separator ascii char (in lower byte). + // separator: Single separator ASCII char (in lower byte). // Copy the separator character to the result. __ strb(separator, MemOperand(result_pos, 1, PostIndex)); diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 219d354c7e..583453ab2c 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -1031,14 +1031,25 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift)); __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset)); __ eor(r3, r3, Operand(r4, ASR, String::kHashShift)); - __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask)); + int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask; + __ And(r3, r3, Operand(mask)); // Load the key (consisting of map and symbol) from the cache and // check for match. + Label try_second_entry, hit_on_first_entry, load_in_object_property; ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys(isolate); __ mov(r4, Operand(cache_keys)); __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1)); + // Move r4 to second entry. + __ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex)); + __ cmp(r2, r5); + __ b(ne, &try_second_entry); + __ ldr(r5, MemOperand(r4, -kPointerSize)); // Load symbol + __ cmp(r0, r5); + __ b(eq, &hit_on_first_entry); + + __ bind(&try_second_entry); __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol. __ cmp(r2, r5); __ b(ne, &slow); @@ -1053,6 +1064,18 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // r3 : lookup cache index ExternalReference cache_field_offsets = ExternalReference::keyed_lookup_cache_field_offsets(isolate); + + // Hit on second entry. + __ mov(r4, Operand(cache_field_offsets)); + __ add(r3, r3, Operand(1)); + __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2)); + __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset)); + __ sub(r5, r5, r6, SetCC); + __ b(ge, &property_array_property); + __ jmp(&load_in_object_property); + + // Hit on first entry. + __ bind(&hit_on_first_entry); __ mov(r4, Operand(cache_field_offsets)); __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2)); __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset)); @@ -1060,6 +1083,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ b(ge, &property_array_property); // Load in-object property. + __ bind(&load_in_object_property); __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset)); __ add(r6, r6, r5); // Index from start of object. __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag. diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index b5ed517087..080785725f 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -262,7 +262,7 @@ bool LCodeGen::GenerateDeferredCode() { bool LCodeGen::GenerateDeoptJumpTable() { // Check that the jump table is accessible from everywhere in the function - // code, ie that offsets to the table can be encoded in the 24bit signed + // code, i.e. that offsets to the table can be encoded in the 24bit signed // immediate of a branch instruction. // To simplify we consider the code size from the first instruction to the // end of the jump table. We also don't consider the pc load delta. @@ -2387,7 +2387,7 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, Handle name) { LookupResult lookup(isolate()); type->LookupInDescriptors(NULL, *name, &lookup); - ASSERT(lookup.IsProperty() && + ASSERT(lookup.IsFound() && (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); if (lookup.type() == FIELD) { int index = lookup.GetLocalFieldIndexFromMap(*type); @@ -2828,7 +2828,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { this, pointers, Safepoint::kLazyDeopt); // The number of arguments is stored in receiver which is r0, as expected // by InvokeFunction. - v8::internal::ParameterCount actual(receiver); + ParameterCount actual(receiver); __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator, CALL_AS_METHOD); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -2883,31 +2883,41 @@ void LCodeGen::CallKnownFunction(Handle function, int arity, LInstruction* instr, CallKind call_kind) { - // Change context if needed. - bool change_context = - (info()->closure()->context() != function->context()) || - scope()->contains_with() || - (scope()->num_heap_slots() > 0); - if (change_context) { - __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); - } - - // Set r0 to arguments count if adaption is not needed. Assumes that r0 - // is available to write to at this point. - if (!function->NeedsArgumentsAdaption()) { - __ mov(r0, Operand(arity)); - } + bool can_invoke_directly = !function->NeedsArgumentsAdaption() || + function->shared()->formal_parameter_count() == arity; LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); - // Invoke function. - __ SetCallKind(r5, call_kind); - __ ldr(ip, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); - __ Call(ip); + if (can_invoke_directly) { + __ LoadHeapObject(r1, function); + // Change context if needed. + bool change_context = + (info()->closure()->context() != function->context()) || + scope()->contains_with() || + (scope()->num_heap_slots() > 0); + if (change_context) { + __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); + } - // Set up deoptimization. - RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); + // Set r0 to arguments count if adaption is not needed. Assumes that r0 + // is available to write to at this point. + if (!function->NeedsArgumentsAdaption()) { + __ mov(r0, Operand(arity)); + } + + // Invoke function. + __ SetCallKind(r5, call_kind); + __ ldr(ip, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); + __ Call(ip); + + // Set up deoptimization. + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); + } else { + SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); + ParameterCount count(arity); + __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind); + } // Restore context. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -2916,7 +2926,6 @@ void LCodeGen::CallKnownFunction(Handle function, void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { ASSERT(ToRegister(instr->result()).is(r0)); - __ LoadHeapObject(r1, instr->function()); CallKnownFunction(instr->function(), instr->arity(), instr, @@ -3351,7 +3360,6 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { ASSERT(ToRegister(instr->result()).is(r0)); - __ LoadHeapObject(r1, instr->target()); CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); } diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index fa97611cf8..9894ff202e 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -957,10 +957,12 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, Handle code_constant, Register code_reg, Label* done, + bool* definitely_mismatches, InvokeFlag flag, const CallWrapper& call_wrapper, CallKind call_kind) { bool definitely_matches = false; + *definitely_mismatches = false; Label regular_invoke; // Check whether the expected and actual arguments count match. If not, @@ -991,6 +993,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, // arguments. definitely_matches = true; } else { + *definitely_mismatches = true; mov(r2, Operand(expected.immediate())); } } @@ -1018,7 +1021,9 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, SetCallKind(r5, call_kind); Call(adaptor); call_wrapper.AfterCall(); - b(done); + if (!*definitely_mismatches) { + b(done); + } } else { SetCallKind(r5, call_kind); Jump(adaptor, RelocInfo::CODE_TARGET); @@ -1038,23 +1043,26 @@ void MacroAssembler::InvokeCode(Register code, ASSERT(flag == JUMP_FUNCTION || has_frame()); Label done; - - InvokePrologue(expected, actual, Handle::null(), code, &done, flag, + bool definitely_mismatches = false; + InvokePrologue(expected, actual, Handle::null(), code, + &done, &definitely_mismatches, flag, call_wrapper, call_kind); - if (flag == CALL_FUNCTION) { - call_wrapper.BeforeCall(CallSize(code)); - SetCallKind(r5, call_kind); - Call(code); - call_wrapper.AfterCall(); - } else { - ASSERT(flag == JUMP_FUNCTION); - SetCallKind(r5, call_kind); - Jump(code); - } + if (!definitely_mismatches) { + if (flag == CALL_FUNCTION) { + call_wrapper.BeforeCall(CallSize(code)); + SetCallKind(r5, call_kind); + Call(code); + call_wrapper.AfterCall(); + } else { + ASSERT(flag == JUMP_FUNCTION); + SetCallKind(r5, call_kind); + Jump(code); + } - // Continue here if InvokePrologue does handle the invocation due to - // mismatched parameter counts. - bind(&done); + // Continue here if InvokePrologue does handle the invocation due to + // mismatched parameter counts. + bind(&done); + } } @@ -1068,20 +1076,23 @@ void MacroAssembler::InvokeCode(Handle code, ASSERT(flag == JUMP_FUNCTION || has_frame()); Label done; - - InvokePrologue(expected, actual, code, no_reg, &done, flag, + bool definitely_mismatches = false; + InvokePrologue(expected, actual, code, no_reg, + &done, &definitely_mismatches, flag, NullCallWrapper(), call_kind); - if (flag == CALL_FUNCTION) { - SetCallKind(r5, call_kind); - Call(code, rmode); - } else { - SetCallKind(r5, call_kind); - Jump(code, rmode); - } + if (!definitely_mismatches) { + if (flag == CALL_FUNCTION) { + SetCallKind(r5, call_kind); + Call(code, rmode); + } else { + SetCallKind(r5, call_kind); + Jump(code, rmode); + } - // Continue here if InvokePrologue does handle the invocation due to - // mismatched parameter counts. - bind(&done); + // Continue here if InvokePrologue does handle the invocation due to + // mismatched parameter counts. + bind(&done); + } } @@ -1116,6 +1127,7 @@ void MacroAssembler::InvokeFunction(Register fun, void MacroAssembler::InvokeFunction(Handle function, const ParameterCount& actual, InvokeFlag flag, + const CallWrapper& call_wrapper, CallKind call_kind) { // You can't call a function without a valid frame. ASSERT(flag == JUMP_FUNCTION || has_frame()); @@ -1129,7 +1141,7 @@ void MacroAssembler::InvokeFunction(Handle function, // allow recompilation to take effect without changing any of the // call sites. ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); - InvokeCode(r3, expected, actual, flag, NullCallWrapper(), call_kind); + InvokeCode(r3, expected, actual, flag, call_wrapper, call_kind); } @@ -2387,7 +2399,7 @@ void MacroAssembler::ConvertToInt32(Register source, b(gt, not_int32); // We know the exponent is smaller than 30 (biased). If it is less than - // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie + // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e. // it rounds to zero. const uint32_t zero_exponent = HeapNumber::kExponentBias + 0; sub(scratch2, scratch2, Operand(zero_exponent - fudge_factor), SetCC); diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 4b55a3b064..60c2e6f6bf 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -243,7 +243,7 @@ class MacroAssembler: public Assembler { Register scratch3, Label* object_is_white_and_not_data); - // Detects conservatively whether an object is data-only, ie it does need to + // Detects conservatively whether an object is data-only, i.e. it does need to // be scanned by the garbage collector. void JumpIfDataObject(Register value, Register scratch, @@ -539,6 +539,7 @@ class MacroAssembler: public Assembler { void InvokeFunction(Handle function, const ParameterCount& actual, InvokeFlag flag, + const CallWrapper& call_wrapper, CallKind call_kind); void IsObjectJSObjectType(Register heap_object, @@ -606,7 +607,7 @@ class MacroAssembler: public Assembler { } // Check if the given instruction is a 'type' marker. - // ie. check if is is a mov r, r (referenced as nop(type)) + // i.e. check if is is a mov r, r (referenced as nop(type)) // These instructions are generated to mark special location in the code, // like some special IC code. static inline bool IsMarkedCode(Instr instr, int type) { @@ -810,7 +811,7 @@ class MacroAssembler: public Assembler { // Check if the map of an object is equal to a specified map and branch to // label if not. Skip the smi check if not required (object is known to be a // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match - // against maps that are ElementsKind transition maps of the specificed map. + // against maps that are ElementsKind transition maps of the specified map. void CheckMap(Register obj, Register scratch, Handle map, @@ -908,7 +909,7 @@ class MacroAssembler: public Assembler { // Truncates a double using a specific rounding mode. // Clears the z flag (ne condition) if an overflow occurs. // If exact_conversion is true, the z flag is also cleared if the conversion - // was inexact, ie. if the double value could not be converted exactly + // was inexact, i.e. if the double value could not be converted exactly // to a 32bit integer. void EmitVFPTruncate(VFPRoundingMode rounding_mode, SwVfpRegister result, @@ -1025,7 +1026,7 @@ class MacroAssembler: public Assembler { // Calls an API function. Allocates HandleScope, extracts returned value // from handle and propagates exceptions. Restores context. stack_space - // - space to be unwound on exit (includes the call js arguments space and + // - space to be unwound on exit (includes the call JS arguments space and // the additional space allocated for the fast call). void CallApiFunctionAndReturn(ExternalReference function, int stack_space); @@ -1248,6 +1249,7 @@ class MacroAssembler: public Assembler { Handle code_constant, Register code_reg, Label* done, + bool* definitely_mismatches, InvokeFlag flag, const CallWrapper& call_wrapper, CallKind call_kind); diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index c3a82ff934..33fbee52d6 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -562,11 +562,11 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- // -- sp[0] : holder (set by CheckPrototypes) - // -- sp[4] : callee js function + // -- sp[4] : callee JS function // -- sp[8] : call data - // -- sp[12] : last js argument + // -- sp[12] : last JS argument // -- ... - // -- sp[(argc + 3) * 4] : first js argument + // -- sp[(argc + 3) * 4] : first JS argument // -- sp[(argc + 4) * 4] : receiver // ----------------------------------- // Get the function and setup the context. @@ -583,7 +583,7 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, } else { __ Move(r6, call_data); } - // Store js function and call data. + // Store JS function and call data. __ stm(ib, sp, r5.bit() | r6.bit()); // r2 points to call data as expected by Arguments @@ -738,7 +738,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(optimization.constant_function(), arguments_, - JUMP_FUNCTION, call_kind); + JUMP_FUNCTION, NullCallWrapper(), call_kind); } // Deferred code for fast API call case---clean preallocated space. @@ -1179,7 +1179,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle object, // and CALLBACKS, so inline only them, other cases may be added // later. bool compile_followup_inline = false; - if (lookup->IsProperty() && lookup->IsCacheable()) { + if (lookup->IsFound() && lookup->IsCacheable()) { if (lookup->type() == FIELD) { compile_followup_inline = true; } else if (lookup->type() == CALLBACKS && @@ -1904,7 +1904,8 @@ Handle CallStubCompiler::CompileStringFromCharCodeCall( // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. __ bind(&slow); - __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD); + __ InvokeFunction( + function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); __ bind(&miss); // r2: function name. @@ -1983,7 +1984,7 @@ Handle CallStubCompiler::CompileMathFloorCall( __ vmrs(r3); // Set custom FPCSR: // - Set rounding mode to "Round towards Minus Infinity" - // (ie bits [23:22] = 0b10). + // (i.e. bits [23:22] = 0b10). // - Clear vfp cumulative exception flags (bits [3:0]). // - Make sure Flush-to-zero mode control bit is unset (bit 22). __ bic(r9, r3, @@ -2049,7 +2050,8 @@ Handle CallStubCompiler::CompileMathFloorCall( __ bind(&slow); // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. - __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD); + __ InvokeFunction( + function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); __ bind(&miss); // r2: function name. @@ -2147,7 +2149,8 @@ Handle CallStubCompiler::CompileMathAbsCall( // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. __ bind(&slow); - __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD); + __ InvokeFunction( + function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); __ bind(&miss); // r2: function name. @@ -2325,7 +2328,8 @@ Handle CallStubCompiler::CompileCallConstant(Handle object, CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; - __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind); + __ InvokeFunction( + function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind); // Handle call cache miss. __ bind(&miss); diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index 3d8e278b9e..16e37c5a7b 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -204,7 +204,7 @@ function ConvertToLocaleString(e) { if (IS_NULL_OR_UNDEFINED(e)) { return ''; } else { - // According to ES5, seciton 15.4.4.3, the toLocaleString conversion + // According to ES5, section 15.4.4.3, the toLocaleString conversion // must throw a TypeError if ToObject(e).toLocaleString isn't // callable. var e_obj = ToObject(e); diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 8c705a84b4..540c15a456 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -271,7 +271,7 @@ class RelocInfo BASE_EMBEDDED { INLINE(void apply(intptr_t delta)); // Is the pointer this relocation info refers to coded like a plain pointer - // or is it strange in some way (eg relative or patched into a series of + // or is it strange in some way (e.g. relative or patched into a series of // instructions). bool IsCodedSpecially(); diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 2e26999c8c..580a485078 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -724,17 +724,11 @@ void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) { } -static bool CanCallWithoutIC(Handle target, int arity) { - SharedFunctionInfo* info = target->shared(); - // If the number of formal parameters of the target function does - // not match the number of arguments we're passing, we don't want to - // deal with it. Otherwise, we can call it directly. - return !target->NeedsArgumentsAdaption() || - info->formal_parameter_count() == arity; -} - - bool Call::ComputeTarget(Handle type, Handle name) { + // If there is an interceptor, we can't compute the target for + // a direct call. + if (type->has_named_interceptor()) return false; + if (check_type_ == RECEIVER_MAP_CHECK) { // For primitive checks the holder is set up to point to the // corresponding prototype object, i.e. one step of the algorithm @@ -752,9 +746,9 @@ bool Call::ComputeTarget(Handle type, Handle name) { && type->prototype()->IsJSObject()) { holder_ = Handle(JSObject::cast(type->prototype())); type = Handle(holder()->map()); - } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { + } else if (lookup.IsFound() && lookup.type() == CONSTANT_FUNCTION) { target_ = Handle(lookup.GetConstantFunctionFromMap(*type)); - return CanCallWithoutIC(target_, arguments()->length()); + return true; } else { return false; } @@ -766,7 +760,7 @@ bool Call::ComputeGlobalTarget(Handle global, LookupResult* lookup) { target_ = Handle::null(); cell_ = Handle::null(); - ASSERT(lookup->IsProperty() && + ASSERT(lookup->IsFound() && lookup->type() == NORMAL && lookup->holder() == *global); cell_ = Handle(global->GetPropertyCell(lookup)); @@ -774,8 +768,7 @@ bool Call::ComputeGlobalTarget(Handle global, Handle candidate(JSFunction::cast(cell_->value())); // If the function is in new space we assume it's more likely to // change and thus prefer the general IC code. - if (!HEAP->InNewSpace(*candidate) && - CanCallWithoutIC(candidate, arguments()->length())) { + if (!HEAP->InNewSpace(*candidate)) { target_ = candidate; return true; } diff --git a/deps/v8/src/bignum-dtoa.h b/deps/v8/src/bignum-dtoa.h index ea1acbbfc8..93ec1f7706 100644 --- a/deps/v8/src/bignum-dtoa.h +++ b/deps/v8/src/bignum-dtoa.h @@ -44,7 +44,7 @@ enum BignumDtoaMode { BIGNUM_DTOA_PRECISION }; -// Converts the given double 'v' to ascii. +// Converts the given double 'v' to ASCII. // The result should be interpreted as buffer * 10^(point-length). // The buffer will be null-terminated. // diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 752b220e5b..cedb0efd00 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -1099,11 +1099,11 @@ void Genesis::InitializeGlobal(Handle inner_global, #ifdef DEBUG LookupResult lookup(isolate); result->LocalLookup(heap->callee_symbol(), &lookup); - ASSERT(lookup.IsProperty() && (lookup.type() == FIELD)); + ASSERT(lookup.IsFound() && (lookup.type() == FIELD)); ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsCalleeIndex); result->LocalLookup(heap->length_symbol(), &lookup); - ASSERT(lookup.IsProperty() && (lookup.type() == FIELD)); + ASSERT(lookup.IsFound() && (lookup.type() == FIELD)); ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex); ASSERT(result->map()->inobject_properties() > Heap::kArgumentsCalleeIndex); @@ -1197,7 +1197,7 @@ void Genesis::InitializeGlobal(Handle inner_global, #ifdef DEBUG LookupResult lookup(isolate); result->LocalLookup(heap->length_symbol(), &lookup); - ASSERT(lookup.IsProperty() && (lookup.type() == FIELD)); + ASSERT(lookup.IsFound() && (lookup.type() == FIELD)); ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex); ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex); diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 69e5161ce5..90a8d3e1b8 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -411,7 +411,7 @@ static FixedArray* LeftTrimFixedArray(Heap* heap, int size_delta = to_trim * kPointerSize; if (heap->marking()->TransferMark(elms->address(), elms->address() + size_delta)) { - MemoryChunk::IncrementLiveBytes(elms->address(), -size_delta); + MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); } return FixedArray::cast(HeapObject::FromAddress( diff --git a/deps/v8/src/d8-debug.cc b/deps/v8/src/d8-debug.cc index 1cbc0b39a0..de0faa8ae6 100644 --- a/deps/v8/src/d8-debug.cc +++ b/deps/v8/src/d8-debug.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -310,9 +310,7 @@ void RemoteDebugger::HandleKeyboardCommand(char* command) { Handle request = Shell::DebugCommandToJSONRequest(String::New(command)); if (try_catch.HasCaught()) { - v8::String::Utf8Value exception(try_catch.Exception()); - const char* exception_string = Shell::ToCString(exception); - printf("%s\n", exception_string); + Shell::ReportException(&try_catch); PrintPrompt(); return; } diff --git a/deps/v8/src/d8-readline.cc b/deps/v8/src/d8-readline.cc index 71be933109..ed7721c513 100644 --- a/deps/v8/src/d8-readline.cc +++ b/deps/v8/src/d8-readline.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -49,10 +49,14 @@ namespace v8 { class ReadLineEditor: public LineEditor { public: ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { } - virtual i::SmartArrayPointer Prompt(const char* prompt); + virtual Handle Prompt(const char* prompt); virtual bool Open(); virtual bool Close(); virtual void AddHistory(const char* str); + + static const char* kHistoryFileName; + static const int kMaxHistoryEntries; + private: static char** AttemptedCompletion(const char* text, int start, int end); static char* CompletionGenerator(const char* text, int state); @@ -66,25 +70,38 @@ char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"', '\0'}; +const char* ReadLineEditor::kHistoryFileName = ".d8_history"; +const int ReadLineEditor::kMaxHistoryEntries = 1000; + + bool ReadLineEditor::Open() { rl_initialize(); rl_attempted_completion_function = AttemptedCompletion; rl_completer_word_break_characters = kWordBreakCharacters; rl_bind_key('\t', rl_complete); using_history(); - stifle_history(Shell::kMaxHistoryEntries); - return read_history(Shell::kHistoryFileName) == 0; + stifle_history(kMaxHistoryEntries); + return read_history(kHistoryFileName) == 0; } bool ReadLineEditor::Close() { - return write_history(Shell::kHistoryFileName) == 0; + return write_history(kHistoryFileName) == 0; } -i::SmartArrayPointer ReadLineEditor::Prompt(const char* prompt) { - char* result = readline(prompt); - return i::SmartArrayPointer(result); +Handle ReadLineEditor::Prompt(const char* prompt) { + char* result = NULL; + { // Release lock for blocking input. + Unlocker unlock(Isolate::GetCurrent()); + result = readline(prompt); + } + if (result != NULL) { + AddHistory(result); + } else { + return Handle(); + } + return String::New(result); } @@ -118,10 +135,10 @@ char* ReadLineEditor::CompletionGenerator(const char* text, int state) { static unsigned current_index; static Persistent current_completions; if (state == 0) { - i::SmartArrayPointer full_text(i::StrNDup(rl_line_buffer, rl_point)); HandleScope scope; + Local full_text = String::New(rl_line_buffer, rl_point); Handle completions = - Shell::GetCompletions(String::New(text), String::New(*full_text)); + Shell::GetCompletions(String::New(text), full_text); current_completions = Persistent::New(completions); current_index = 0; } diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index 97828a4ac4..bfb9944027 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -66,11 +66,7 @@ namespace v8 { - -#ifndef V8_SHARED LineEditor *LineEditor::first_ = NULL; -const char* Shell::kHistoryFileName = ".d8_history"; -const int Shell::kMaxHistoryEntries = 1000; LineEditor::LineEditor(Type type, const char* name) @@ -96,31 +92,29 @@ LineEditor* LineEditor::Get() { class DumbLineEditor: public LineEditor { public: DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { } - virtual i::SmartArrayPointer Prompt(const char* prompt); + virtual Handle Prompt(const char* prompt); }; static DumbLineEditor dumb_line_editor; -i::SmartArrayPointer DumbLineEditor::Prompt(const char* prompt) { - static const int kBufferSize = 256; - char buffer[kBufferSize]; +Handle DumbLineEditor::Prompt(const char* prompt) { printf("%s", prompt); - char* str = fgets(buffer, kBufferSize, stdin); - return i::SmartArrayPointer(str ? i::StrDup(str) : str); + return Shell::ReadFromStdin(); } +#ifndef V8_SHARED CounterMap* Shell::counter_map_; i::OS::MemoryMappedFile* Shell::counters_file_ = NULL; CounterCollection Shell::local_counters_; CounterCollection* Shell::counters_ = &local_counters_; i::Mutex* Shell::context_mutex_(i::OS::CreateMutex()); Persistent Shell::utility_context_; -LineEditor* Shell::console = NULL; #endif // V8_SHARED +LineEditor* Shell::console = NULL; Persistent Shell::evaluation_context_; ShellOptions Shell::options; const char* Shell::kPrompt = "d8> "; @@ -238,7 +232,7 @@ Handle Shell::Read(const Arguments& args) { } -Handle Shell::ReadLine(const Arguments& args) { +Handle Shell::ReadFromStdin() { static const int kBufferSize = 256; char buffer[kBufferSize]; Handle accumulator = String::New(""); @@ -247,7 +241,12 @@ Handle Shell::ReadLine(const Arguments& args) { // Continue reading if the line ends with an escape '\\' or the line has // not been fully read into the buffer yet (does not end with '\n'). // If fgets gets an error, just give up. - if (fgets(buffer, kBufferSize, stdin) == NULL) return Null(); + char* input = NULL; + { // Release lock for blocking input. + Unlocker unlock(Isolate::GetCurrent()); + input = fgets(buffer, kBufferSize, stdin); + } + if (input == NULL) return Handle(); length = static_cast(strlen(buffer)); if (length == 0) { return accumulator; @@ -532,6 +531,10 @@ Handle Shell::Version(const Arguments& args) { void Shell::ReportException(v8::TryCatch* try_catch) { HandleScope handle_scope; +#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) + bool enter_context = !Context::InContext(); + if (enter_context) utility_context_->Enter(); +#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT v8::String::Utf8Value exception(try_catch->Exception()); const char* exception_string = ToCString(exception); Handle message = try_catch->Message(); @@ -566,6 +569,9 @@ void Shell::ReportException(v8::TryCatch* try_catch) { } } printf("\n"); +#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) + if (enter_context) utility_context_->Exit(); +#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT } @@ -603,6 +609,12 @@ Handle Shell::DebugCommandToJSONRequest(Handle command) { Handle val = Handle::Cast(fun)->Call(global, kArgc, argv); return val; } + + +void Shell::DispatchDebugMessages() { + v8::Context::Scope scope(Shell::evaluation_context_); + v8::Debug::ProcessDebugMessages(); +} #endif // ENABLE_DEBUGGER_SUPPORT #endif // V8_SHARED @@ -872,6 +884,7 @@ void Shell::Initialize() { // Start the debugger agent if requested. if (i::FLAG_debugger_agent) { v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true); + v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true); } #endif // ENABLE_DEBUGGER_SUPPORT #endif // V8_SHARED @@ -1047,28 +1060,15 @@ void Shell::RunShell() { Context::Scope context_scope(evaluation_context_); HandleScope outer_scope; Handle name = String::New("(d8)"); -#ifndef V8_SHARED console = LineEditor::Get(); printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name()); console->Open(); while (true) { - i::SmartArrayPointer input = console->Prompt(Shell::kPrompt); - if (input.is_empty()) break; - console->AddHistory(*input); HandleScope inner_scope; - ExecuteString(String::New(*input), name, true, true); + Handle input = console->Prompt(Shell::kPrompt); + if (input.IsEmpty()) break; + ExecuteString(input, name, true, true); } -#else - printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion()); - static const int kBufferSize = 256; - while (true) { - char buffer[kBufferSize]; - printf("%s", Shell::kPrompt); - if (fgets(buffer, kBufferSize, stdin) == NULL) break; - HandleScope inner_scope; - ExecuteString(String::New(buffer), name, true, true); - } -#endif // V8_SHARED printf("\n"); } diff --git a/deps/v8/src/d8.gyp b/deps/v8/src/d8.gyp index a096af35b8..3b92d03681 100644 --- a/deps/v8/src/d8.gyp +++ b/deps/v8/src/d8.gyp @@ -1,4 +1,4 @@ -# Copyright 2010 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: diff --git a/deps/v8/src/d8.h b/deps/v8/src/d8.h index 6c7733ccfa..60a8c1bf76 100644 --- a/deps/v8/src/d8.h +++ b/deps/v8/src/d8.h @@ -116,14 +116,13 @@ class CounterMap { #endif // V8_SHARED -#ifndef V8_SHARED class LineEditor { public: enum Type { DUMB = 0, READLINE = 1 }; LineEditor(Type type, const char* name); virtual ~LineEditor() { } - virtual i::SmartArrayPointer Prompt(const char* prompt) = 0; + virtual Handle Prompt(const char* prompt) = 0; virtual bool Open() { return true; } virtual bool Close() { return true; } virtual void AddHistory(const char* str) { } @@ -136,7 +135,6 @@ class LineEditor { LineEditor* next_; static LineEditor* first_; }; -#endif // V8_SHARED class SourceGroup { @@ -268,12 +266,13 @@ class Shell : public i::AllStatic { size_t buckets); static void AddHistogramSample(void* histogram, int sample); static void MapCounters(const char* name); -#endif // V8_SHARED #ifdef ENABLE_DEBUGGER_SUPPORT static Handle DebugMessageDetails(Handle message); static Handle DebugCommandToJSONRequest(Handle command); -#endif + static void DispatchDebugMessages(); +#endif // ENABLE_DEBUGGER_SUPPORT +#endif // V8_SHARED #ifdef WIN32 #undef Yield @@ -287,7 +286,10 @@ class Shell : public i::AllStatic { static Handle EnableProfiler(const Arguments& args); static Handle DisableProfiler(const Arguments& args); static Handle Read(const Arguments& args); - static Handle ReadLine(const Arguments& args); + static Handle ReadFromStdin(); + static Handle ReadLine(const Arguments& args) { + return ReadFromStdin(); + } static Handle Load(const Arguments& args); static Handle ArrayBuffer(const Arguments& args); static Handle Int8Array(const Arguments& args); @@ -335,11 +337,8 @@ class Shell : public i::AllStatic { static Handle RemoveDirectory(const Arguments& args); static void AddOSMethods(Handle os_template); -#ifndef V8_SHARED - static const char* kHistoryFileName; - static const int kMaxHistoryEntries; + static LineEditor* console; -#endif // V8_SHARED static const char* kPrompt; static ShellOptions options; diff --git a/deps/v8/src/dtoa.h b/deps/v8/src/dtoa.h index a2d6fdebde..948a079191 100644 --- a/deps/v8/src/dtoa.h +++ b/deps/v8/src/dtoa.h @@ -49,7 +49,7 @@ enum DtoaMode { // be at least kBase10MaximalLength + 1 characters long. const int kBase10MaximalLength = 17; -// Converts the given double 'v' to ascii. +// Converts the given double 'v' to ASCII. // The result should be interpreted as buffer * 10^(point-length). // // The output depends on the given mode: diff --git a/deps/v8/src/execution.cc b/deps/v8/src/execution.cc index 125241ceec..8a0242ff42 100644 --- a/deps/v8/src/execution.cc +++ b/deps/v8/src/execution.cc @@ -356,7 +356,7 @@ void StackGuard::EnableInterrupts() { void StackGuard::SetStackLimit(uintptr_t limit) { ExecutionAccess access(isolate_); - // If the current limits are special (eg due to a pending interrupt) then + // If the current limits are special (e.g. due to a pending interrupt) then // leave them alone. uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit); if (thread_local_.jslimit_ == thread_local_.real_jslimit_) { diff --git a/deps/v8/src/extensions/experimental/break-iterator.cc b/deps/v8/src/extensions/experimental/break-iterator.cc deleted file mode 100644 index e695a3e978..0000000000 --- a/deps/v8/src/extensions/experimental/break-iterator.cc +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "src/extensions/experimental/break-iterator.h" - -#include - -#include "unicode/brkiter.h" -#include "unicode/locid.h" -#include "unicode/rbbi.h" - -namespace v8 { -namespace internal { - -v8::Persistent BreakIterator::break_iterator_template_; - -icu::BreakIterator* BreakIterator::UnpackBreakIterator( - v8::Handle obj) { - if (break_iterator_template_->HasInstance(obj)) { - return static_cast( - obj->GetPointerFromInternalField(0)); - } - - return NULL; -} - -icu::UnicodeString* BreakIterator::ResetAdoptedText( - v8::Handle obj, v8::Handle value) { - // Get the previous value from the internal field. - icu::UnicodeString* text = static_cast( - obj->GetPointerFromInternalField(1)); - delete text; - - // Assign new value to the internal pointer. - v8::String::Value text_value(value); - text = new icu::UnicodeString( - reinterpret_cast(*text_value), text_value.length()); - obj->SetPointerInInternalField(1, text); - - // Return new unicode string pointer. - return text; -} - -void BreakIterator::DeleteBreakIterator(v8::Persistent object, - void* param) { - v8::Persistent persistent_object = - v8::Persistent::Cast(object); - - // First delete the hidden C++ object. - // Unpacking should never return NULL here. That would only happen if - // this method is used as the weak callback for persistent handles not - // pointing to a break iterator. - delete UnpackBreakIterator(persistent_object); - - delete static_cast( - persistent_object->GetPointerFromInternalField(1)); - - // Then dispose of the persistent handle to JS object. - persistent_object.Dispose(); -} - -// Throws a JavaScript exception. -static v8::Handle ThrowUnexpectedObjectError() { - // Returns undefined, and schedules an exception to be thrown. - return v8::ThrowException(v8::Exception::Error( - v8::String::New("BreakIterator method called on an object " - "that is not a BreakIterator."))); -} - -v8::Handle BreakIterator::BreakIteratorAdoptText( - const v8::Arguments& args) { - if (args.Length() != 1 || !args[0]->IsString()) { - return v8::ThrowException(v8::Exception::SyntaxError( - v8::String::New("Text input is required."))); - } - - icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder()); - if (!break_iterator) { - return ThrowUnexpectedObjectError(); - } - - break_iterator->setText(*ResetAdoptedText(args.Holder(), args[0])); - - return v8::Undefined(); -} - -v8::Handle BreakIterator::BreakIteratorFirst( - const v8::Arguments& args) { - icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder()); - if (!break_iterator) { - return ThrowUnexpectedObjectError(); - } - - return v8::Int32::New(break_iterator->first()); -} - -v8::Handle BreakIterator::BreakIteratorNext( - const v8::Arguments& args) { - icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder()); - if (!break_iterator) { - return ThrowUnexpectedObjectError(); - } - - return v8::Int32::New(break_iterator->next()); -} - -v8::Handle BreakIterator::BreakIteratorCurrent( - const v8::Arguments& args) { - icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder()); - if (!break_iterator) { - return ThrowUnexpectedObjectError(); - } - - return v8::Int32::New(break_iterator->current()); -} - -v8::Handle BreakIterator::BreakIteratorBreakType( - const v8::Arguments& args) { - icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder()); - if (!break_iterator) { - return ThrowUnexpectedObjectError(); - } - - // TODO(cira): Remove cast once ICU fixes base BreakIterator class. - icu::RuleBasedBreakIterator* rule_based_iterator = - static_cast(break_iterator); - int32_t status = rule_based_iterator->getRuleStatus(); - // Keep return values in sync with JavaScript BreakType enum. - if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) { - return v8::Int32::New(UBRK_WORD_NONE); - } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) { - return v8::Int32::New(UBRK_WORD_NUMBER); - } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) { - return v8::Int32::New(UBRK_WORD_LETTER); - } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) { - return v8::Int32::New(UBRK_WORD_KANA); - } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) { - return v8::Int32::New(UBRK_WORD_IDEO); - } else { - return v8::Int32::New(-1); - } -} - -v8::Handle BreakIterator::JSBreakIterator( - const v8::Arguments& args) { - v8::HandleScope handle_scope; - - if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) { - return v8::ThrowException(v8::Exception::SyntaxError( - v8::String::New("Locale and iterator type are required."))); - } - - v8::String::Utf8Value locale(args[0]); - icu::Locale icu_locale(*locale); - - UErrorCode status = U_ZERO_ERROR; - icu::BreakIterator* break_iterator = NULL; - v8::String::Utf8Value type(args[1]); - if (!strcmp(*type, "character")) { - break_iterator = - icu::BreakIterator::createCharacterInstance(icu_locale, status); - } else if (!strcmp(*type, "word")) { - break_iterator = - icu::BreakIterator::createWordInstance(icu_locale, status); - } else if (!strcmp(*type, "sentence")) { - break_iterator = - icu::BreakIterator::createSentenceInstance(icu_locale, status); - } else if (!strcmp(*type, "line")) { - break_iterator = - icu::BreakIterator::createLineInstance(icu_locale, status); - } else { - return v8::ThrowException(v8::Exception::SyntaxError( - v8::String::New("Invalid iterator type."))); - } - - if (U_FAILURE(status)) { - delete break_iterator; - return v8::ThrowException(v8::Exception::Error( - v8::String::New("Failed to create break iterator."))); - } - - if (break_iterator_template_.IsEmpty()) { - v8::Local raw_template(v8::FunctionTemplate::New()); - - raw_template->SetClassName(v8::String::New("v8Locale.v8BreakIterator")); - - // Define internal field count on instance template. - v8::Local object_template = - raw_template->InstanceTemplate(); - - // Set aside internal fields for icu break iterator and adopted text. - object_template->SetInternalFieldCount(2); - - // Define all of the prototype methods on prototype template. - v8::Local proto = raw_template->PrototypeTemplate(); - proto->Set(v8::String::New("adoptText"), - v8::FunctionTemplate::New(BreakIteratorAdoptText)); - proto->Set(v8::String::New("first"), - v8::FunctionTemplate::New(BreakIteratorFirst)); - proto->Set(v8::String::New("next"), - v8::FunctionTemplate::New(BreakIteratorNext)); - proto->Set(v8::String::New("current"), - v8::FunctionTemplate::New(BreakIteratorCurrent)); - proto->Set(v8::String::New("breakType"), - v8::FunctionTemplate::New(BreakIteratorBreakType)); - - break_iterator_template_ = - v8::Persistent::New(raw_template); - } - - // Create an empty object wrapper. - v8::Local local_object = - break_iterator_template_->GetFunction()->NewInstance(); - v8::Persistent wrapper = - v8::Persistent::New(local_object); - - // Set break iterator as internal field of the resulting JS object. - wrapper->SetPointerInInternalField(0, break_iterator); - // Make sure that the pointer to adopted text is NULL. - wrapper->SetPointerInInternalField(1, NULL); - - // Make object handle weak so we can delete iterator once GC kicks in. - wrapper.MakeWeak(NULL, DeleteBreakIterator); - - return wrapper; -} - -} } // namespace v8::internal diff --git a/deps/v8/src/extensions/experimental/break-iterator.h b/deps/v8/src/extensions/experimental/break-iterator.h deleted file mode 100644 index 73b9bbd567..0000000000 --- a/deps/v8/src/extensions/experimental/break-iterator.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef V8_EXTENSIONS_EXPERIMENTAL_BREAK_ITERATOR_H_ -#define V8_EXTENSIONS_EXPERIMENTAL_BREAK_ITERATOR_H_ - -#include "include/v8.h" - -#include "unicode/uversion.h" - -namespace U_ICU_NAMESPACE { -class BreakIterator; -class UnicodeString; -} - -namespace v8 { -namespace internal { - -class BreakIterator { - public: - static v8::Handle JSBreakIterator(const v8::Arguments& args); - - // Helper methods for various bindings. - - // Unpacks break iterator object from corresponding JavaScript object. - static icu::BreakIterator* UnpackBreakIterator(v8::Handle obj); - - // Deletes the old value and sets the adopted text in - // corresponding JavaScript object. - static icu::UnicodeString* ResetAdoptedText(v8::Handle obj, - v8::Handle text_value); - - // Release memory we allocated for the BreakIterator once the JS object that - // holds the pointer gets garbage collected. - static void DeleteBreakIterator(v8::Persistent object, - void* param); - - // Assigns new text to the iterator. - static v8::Handle BreakIteratorAdoptText( - const v8::Arguments& args); - - // Moves iterator to the beginning of the string and returns new position. - static v8::Handle BreakIteratorFirst(const v8::Arguments& args); - - // Moves iterator to the next position and returns it. - static v8::Handle BreakIteratorNext(const v8::Arguments& args); - - // Returns current iterator's current position. - static v8::Handle BreakIteratorCurrent( - const v8::Arguments& args); - - // Returns type of the item from current position. - // This call is only valid for word break iterators. Others just return 0. - static v8::Handle BreakIteratorBreakType( - const v8::Arguments& args); - - private: - BreakIterator() {} - - static v8::Persistent break_iterator_template_; -}; - -} } // namespace v8::internal - -#endif // V8_EXTENSIONS_EXPERIMENTAL_BREAK_ITERATOR_H_ diff --git a/deps/v8/src/extensions/experimental/collator.cc b/deps/v8/src/extensions/experimental/collator.cc deleted file mode 100644 index 5cf219256a..0000000000 --- a/deps/v8/src/extensions/experimental/collator.cc +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "src/extensions/experimental/collator.h" - -#include "unicode/coll.h" -#include "unicode/locid.h" -#include "unicode/ucol.h" - -namespace v8 { -namespace internal { - -v8::Persistent Collator::collator_template_; - -icu::Collator* Collator::UnpackCollator(v8::Handle obj) { - if (collator_template_->HasInstance(obj)) { - return static_cast(obj->GetPointerFromInternalField(0)); - } - - return NULL; -} - -void Collator::DeleteCollator(v8::Persistent object, void* param) { - v8::Persistent persistent_object = - v8::Persistent::Cast(object); - - // First delete the hidden C++ object. - // Unpacking should never return NULL here. That would only happen if - // this method is used as the weak callback for persistent handles not - // pointing to a collator. - delete UnpackCollator(persistent_object); - - // Then dispose of the persistent handle to JS object. - persistent_object.Dispose(); -} - -// Throws a JavaScript exception. -static v8::Handle ThrowUnexpectedObjectError() { - // Returns undefined, and schedules an exception to be thrown. - return v8::ThrowException(v8::Exception::Error( - v8::String::New("Collator method called on an object " - "that is not a Collator."))); -} - -// Extract a boolean option named in |option| and set it to |result|. -// Return true if it's specified. Otherwise, return false. -static bool ExtractBooleanOption(const v8::Local& options, - const char* option, - bool* result) { - v8::HandleScope handle_scope; - v8::TryCatch try_catch; - v8::Handle value = options->Get(v8::String::New(option)); - if (try_catch.HasCaught()) { - return false; - } - // No need to check if |value| is empty because it's taken care of - // by TryCatch above. - if (!value->IsUndefined() && !value->IsNull()) { - if (value->IsBoolean()) { - *result = value->BooleanValue(); - return true; - } - } - return false; -} - -// When there's an ICU error, throw a JavaScript error with |message|. -static v8::Handle ThrowExceptionForICUError(const char* message) { - return v8::ThrowException(v8::Exception::Error(v8::String::New(message))); -} - -v8::Handle Collator::CollatorCompare(const v8::Arguments& args) { - if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) { - return v8::ThrowException(v8::Exception::SyntaxError( - v8::String::New("Two string arguments are required."))); - } - - icu::Collator* collator = UnpackCollator(args.Holder()); - if (!collator) { - return ThrowUnexpectedObjectError(); - } - - v8::String::Value string_value1(args[0]); - v8::String::Value string_value2(args[1]); - const UChar* string1 = reinterpret_cast(*string_value1); - const UChar* string2 = reinterpret_cast(*string_value2); - UErrorCode status = U_ZERO_ERROR; - UCollationResult result = collator->compare( - string1, string_value1.length(), string2, string_value2.length(), status); - - if (U_FAILURE(status)) { - return ThrowExceptionForICUError( - "Unexpected failure in Collator.compare."); - } - - return v8::Int32::New(result); -} - -v8::Handle Collator::JSCollator(const v8::Arguments& args) { - v8::HandleScope handle_scope; - - if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsObject()) { - return v8::ThrowException(v8::Exception::SyntaxError( - v8::String::New("Locale and collation options are required."))); - } - - v8::String::AsciiValue locale(args[0]); - icu::Locale icu_locale(*locale); - - icu::Collator* collator = NULL; - UErrorCode status = U_ZERO_ERROR; - collator = icu::Collator::createInstance(icu_locale, status); - - if (U_FAILURE(status)) { - delete collator; - return ThrowExceptionForICUError("Failed to create collator."); - } - - v8::Local options(args[1]->ToObject()); - - // Below, we change collation options that are explicitly specified - // by a caller in JavaScript. Otherwise, we don't touch because - // we don't want to change the locale-dependent default value. - // The three options below are very likely to have the same default - // across locales, but I haven't checked them all. Others we may add - // in the future have certainly locale-dependent default (e.g. - // caseFirst is upperFirst for Danish while is off for most other locales). - - bool ignore_case, ignore_accents, numeric; - - if (ExtractBooleanOption(options, "ignoreCase", &ignore_case)) { - // We need to explicitly set the level to secondary to get case ignored. - // The default L3 ignores UCOL_CASE_LEVEL == UCOL_OFF ! - if (ignore_case) { - collator->setStrength(icu::Collator::SECONDARY); - } - collator->setAttribute(UCOL_CASE_LEVEL, ignore_case ? UCOL_OFF : UCOL_ON, - status); - if (U_FAILURE(status)) { - delete collator; - return ThrowExceptionForICUError("Failed to set ignoreCase."); - } - } - - // Accents are taken into account with strength secondary or higher. - if (ExtractBooleanOption(options, "ignoreAccents", &ignore_accents)) { - if (!ignore_accents) { - collator->setStrength(icu::Collator::SECONDARY); - } else { - collator->setStrength(icu::Collator::PRIMARY); - } - } - - if (ExtractBooleanOption(options, "numeric", &numeric)) { - collator->setAttribute(UCOL_NUMERIC_COLLATION, - numeric ? UCOL_ON : UCOL_OFF, status); - if (U_FAILURE(status)) { - delete collator; - return ThrowExceptionForICUError("Failed to set numeric sort option."); - } - } - - if (collator_template_.IsEmpty()) { - v8::Local raw_template(v8::FunctionTemplate::New()); - raw_template->SetClassName(v8::String::New("v8Locale.Collator")); - - // Define internal field count on instance template. - v8::Local object_template = - raw_template->InstanceTemplate(); - - // Set aside internal fields for icu collator. - object_template->SetInternalFieldCount(1); - - // Define all of the prototype methods on prototype template. - v8::Local proto = raw_template->PrototypeTemplate(); - proto->Set(v8::String::New("compare"), - v8::FunctionTemplate::New(CollatorCompare)); - - collator_template_ = - v8::Persistent::New(raw_template); - } - - // Create an empty object wrapper. - v8::Local local_object = - collator_template_->GetFunction()->NewInstance(); - v8::Persistent wrapper = - v8::Persistent::New(local_object); - - // Set collator as internal field of the resulting JS object. - wrapper->SetPointerInInternalField(0, collator); - - // Make object handle weak so we can delete iterator once GC kicks in. - wrapper.MakeWeak(NULL, DeleteCollator); - - return wrapper; -} - -} } // namespace v8::internal diff --git a/deps/v8/src/extensions/experimental/collator.h b/deps/v8/src/extensions/experimental/collator.h deleted file mode 100644 index ca7e4dc9d4..0000000000 --- a/deps/v8/src/extensions/experimental/collator.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef V8_EXTENSIONS_EXPERIMENTAL_COLLATOR_H -#define V8_EXTENSIONS_EXPERIMENTAL_COLLATOR_H_ - -#include "include/v8.h" - -#include "unicode/uversion.h" - -namespace U_ICU_NAMESPACE { -class Collator; -class UnicodeString; -} - -namespace v8 { -namespace internal { - -class Collator { - public: - static v8::Handle JSCollator(const v8::Arguments& args); - - // Helper methods for various bindings. - - // Unpacks collator object from corresponding JavaScript object. - static icu::Collator* UnpackCollator(v8::Handle obj); - - // Release memory we allocated for the Collator once the JS object that - // holds the pointer gets garbage collected. - static void DeleteCollator(v8::Persistent object, void* param); - - // Compare two strings and returns -1, 0 and 1 depending on - // whether string1 is smaller than, equal to or larger than string2. - static v8::Handle CollatorCompare(const v8::Arguments& args); - - private: - Collator() {} - - static v8::Persistent collator_template_; -}; - -} } // namespace v8::internal - -#endif // V8_EXTENSIONS_EXPERIMENTAL_COLLATOR diff --git a/deps/v8/src/extensions/experimental/datetime-format.cc b/deps/v8/src/extensions/experimental/datetime-format.cc deleted file mode 100644 index 94a29ac0ae..0000000000 --- a/deps/v8/src/extensions/experimental/datetime-format.cc +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "src/extensions/experimental/datetime-format.h" - -#include - -#include "src/extensions/experimental/i18n-utils.h" -#include "unicode/dtfmtsym.h" -#include "unicode/dtptngen.h" -#include "unicode/locid.h" -#include "unicode/smpdtfmt.h" - -namespace v8 { -namespace internal { - -v8::Persistent DateTimeFormat::datetime_format_template_; - -static icu::DateFormat* CreateDateTimeFormat(v8::Handle, - v8::Handle); -static v8::Handle GetSymbols( - const v8::Arguments&, - const icu::UnicodeString*, int32_t, - const icu::UnicodeString*, int32_t, - const icu::UnicodeString*, int32_t); -static v8::Handle ThrowUnexpectedObjectError(); -static icu::DateFormat::EStyle GetDateTimeStyle(const icu::UnicodeString&); - -icu::SimpleDateFormat* DateTimeFormat::UnpackDateTimeFormat( - v8::Handle obj) { - if (datetime_format_template_->HasInstance(obj)) { - return static_cast( - obj->GetPointerFromInternalField(0)); - } - - return NULL; -} - -void DateTimeFormat::DeleteDateTimeFormat(v8::Persistent object, - void* param) { - v8::Persistent persistent_object = - v8::Persistent::Cast(object); - - // First delete the hidden C++ object. - // Unpacking should never return NULL here. That would only happen if - // this method is used as the weak callback for persistent handles not - // pointing to a date time formatter. - delete UnpackDateTimeFormat(persistent_object); - - // Then dispose of the persistent handle to JS object. - persistent_object.Dispose(); -} - -v8::Handle DateTimeFormat::Format(const v8::Arguments& args) { - v8::HandleScope handle_scope; - - double millis = 0.0; - if (args.Length() != 1 || !args[0]->IsDate()) { - // Create a new date. - v8::TryCatch try_catch; - v8::Local date_script = - v8::Script::Compile(v8::String::New("eval('new Date()')")); - millis = date_script->Run()->NumberValue(); - if (try_catch.HasCaught()) { - return try_catch.ReThrow(); - } - } else { - millis = v8::Date::Cast(*args[0])->NumberValue(); - } - - icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder()); - if (!date_format) { - return ThrowUnexpectedObjectError(); - } - - icu::UnicodeString result; - date_format->format(millis, result); - - return v8::String::New( - reinterpret_cast(result.getBuffer()), result.length()); -} - -v8::Handle DateTimeFormat::GetMonths(const v8::Arguments& args) { - icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder()); - if (!date_format) { - return ThrowUnexpectedObjectError(); - } - - const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols(); - - int32_t narrow_count; - const icu::UnicodeString* narrow = symbols->getMonths( - narrow_count, - icu::DateFormatSymbols::STANDALONE, - icu::DateFormatSymbols::NARROW); - int32_t abbrev_count; - const icu::UnicodeString* abbrev = symbols->getMonths( - abbrev_count, - icu::DateFormatSymbols::STANDALONE, - icu::DateFormatSymbols::ABBREVIATED); - int32_t wide_count; - const icu::UnicodeString* wide = symbols->getMonths( - wide_count, - icu::DateFormatSymbols::STANDALONE, - icu::DateFormatSymbols::WIDE); - - return GetSymbols( - args, narrow, narrow_count, abbrev, abbrev_count, wide, wide_count); -} - -v8::Handle DateTimeFormat::GetWeekdays(const v8::Arguments& args) { - icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder()); - if (!date_format) { - return ThrowUnexpectedObjectError(); - } - - const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols(); - - int32_t narrow_count; - const icu::UnicodeString* narrow = symbols->getWeekdays( - narrow_count, - icu::DateFormatSymbols::STANDALONE, - icu::DateFormatSymbols::NARROW); - int32_t abbrev_count; - const icu::UnicodeString* abbrev = symbols->getWeekdays( - abbrev_count, - icu::DateFormatSymbols::STANDALONE, - icu::DateFormatSymbols::ABBREVIATED); - int32_t wide_count; - const icu::UnicodeString* wide = symbols->getWeekdays( - wide_count, - icu::DateFormatSymbols::STANDALONE, - icu::DateFormatSymbols::WIDE); - - // getXXXWeekdays always returns 8 elements - ICU stable API. - // We can't use ASSERT_EQ(8, narrow_count) because ASSERT is internal to v8. - if (narrow_count != 8 || abbrev_count != 8 || wide_count != 8) { - return v8::ThrowException(v8::Exception::Error( - v8::String::New("Failed to get weekday information."))); - } - - // ICU documentation says we should ignore element 0 of the returned array. - return GetSymbols(args, narrow + 1, narrow_count - 1, abbrev + 1, - abbrev_count -1 , wide + 1, wide_count - 1); -} - -v8::Handle DateTimeFormat::GetEras(const v8::Arguments& args) { - icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder()); - if (!date_format) { - return ThrowUnexpectedObjectError(); - } - - const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols(); - - int32_t narrow_count; - const icu::UnicodeString* narrow = symbols->getNarrowEras(narrow_count); - int32_t abbrev_count; - const icu::UnicodeString* abbrev = symbols->getEras(abbrev_count); - int32_t wide_count; - const icu::UnicodeString* wide = symbols->getEraNames(wide_count); - - return GetSymbols( - args, narrow, narrow_count, abbrev, abbrev_count, wide, wide_count); -} - -v8::Handle DateTimeFormat::GetAmPm(const v8::Arguments& args) { - icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder()); - if (!date_format) { - return ThrowUnexpectedObjectError(); - } - - const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols(); - - // In this case narrow == abbreviated == wide - int32_t count; - const icu::UnicodeString* wide = symbols->getAmPmStrings(count); - - return GetSymbols(args, wide, count, wide, count, wide, count); -} - -v8::Handle DateTimeFormat::JSDateTimeFormat( - const v8::Arguments& args) { - v8::HandleScope handle_scope; - - if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsObject()) { - return v8::ThrowException(v8::Exception::SyntaxError( - v8::String::New("Locale and date/time options are required."))); - } - - icu::SimpleDateFormat* date_format = static_cast( - CreateDateTimeFormat(args[0]->ToString(), args[1]->ToObject())); - - if (datetime_format_template_.IsEmpty()) { - v8::Local raw_template(v8::FunctionTemplate::New()); - - raw_template->SetClassName(v8::String::New("v8Locale.DateTimeFormat")); - - // Define internal field count on instance template. - v8::Local object_template = - raw_template->InstanceTemplate(); - - // Set aside internal field for icu date time formatter. - object_template->SetInternalFieldCount(1); - - // Define all of the prototype methods on prototype template. - v8::Local proto = raw_template->PrototypeTemplate(); - proto->Set(v8::String::New("format"), - v8::FunctionTemplate::New(Format)); - proto->Set(v8::String::New("getMonths"), - v8::FunctionTemplate::New(GetMonths)); - proto->Set(v8::String::New("getWeekdays"), - v8::FunctionTemplate::New(GetWeekdays)); - proto->Set(v8::String::New("getEras"), - v8::FunctionTemplate::New(GetEras)); - proto->Set(v8::String::New("getAmPm"), - v8::FunctionTemplate::New(GetAmPm)); - - datetime_format_template_ = - v8::Persistent::New(raw_template); - } - - // Create an empty object wrapper. - v8::Local local_object = - datetime_format_template_->GetFunction()->NewInstance(); - v8::Persistent wrapper = - v8::Persistent::New(local_object); - - // Set date time formatter as internal field of the resulting JS object. - wrapper->SetPointerInInternalField(0, date_format); - - // Set resolved pattern in options.pattern. - icu::UnicodeString pattern; - date_format->toPattern(pattern); - v8::Local options = v8::Object::New(); - options->Set(v8::String::New("pattern"), - v8::String::New(reinterpret_cast( - pattern.getBuffer()), pattern.length())); - wrapper->Set(v8::String::New("options"), options); - - // Make object handle weak so we can delete iterator once GC kicks in. - wrapper.MakeWeak(NULL, DeleteDateTimeFormat); - - return wrapper; -} - -// Returns SimpleDateFormat. -static icu::DateFormat* CreateDateTimeFormat( - v8::Handle locale, v8::Handle settings) { - v8::HandleScope handle_scope; - - v8::String::AsciiValue ascii_locale(locale); - icu::Locale icu_locale(*ascii_locale); - - // Make formatter from skeleton. - icu::SimpleDateFormat* date_format = NULL; - UErrorCode status = U_ZERO_ERROR; - icu::UnicodeString skeleton; - if (I18NUtils::ExtractStringSetting(settings, "skeleton", &skeleton)) { - v8::Local generator( - icu::DateTimePatternGenerator::createInstance(icu_locale, status)); - icu::UnicodeString pattern = - generator->getBestPattern(skeleton, status); - - date_format = new icu::SimpleDateFormat(pattern, icu_locale, status); - if (U_SUCCESS(status)) { - return date_format; - } else { - delete date_format; - } - } - - // Extract date style and time style from settings. - icu::UnicodeString date_style; - icu::DateFormat::EStyle icu_date_style = icu::DateFormat::kNone; - if (I18NUtils::ExtractStringSetting(settings, "dateStyle", &date_style)) { - icu_date_style = GetDateTimeStyle(date_style); - } - - icu::UnicodeString time_style; - icu::DateFormat::EStyle icu_time_style = icu::DateFormat::kNone; - if (I18NUtils::ExtractStringSetting(settings, "timeStyle", &time_style)) { - icu_time_style = GetDateTimeStyle(time_style); - } - - // Try all combinations of date/time styles. - if (icu_date_style == icu::DateFormat::kNone && - icu_time_style == icu::DateFormat::kNone) { - // Return default short date, short - return icu::DateFormat::createDateTimeInstance( - icu::DateFormat::kShort, icu::DateFormat::kShort, icu_locale); - } else if (icu_date_style != icu::DateFormat::kNone && - icu_time_style != icu::DateFormat::kNone) { - return icu::DateFormat::createDateTimeInstance( - icu_date_style, icu_time_style, icu_locale); - } else if (icu_date_style != icu::DateFormat::kNone) { - return icu::DateFormat::createDateInstance(icu_date_style, icu_locale); - } else { - // icu_time_style != icu::DateFormat::kNone - return icu::DateFormat::createTimeInstance(icu_time_style, icu_locale); - } -} - -// Creates a v8::Array of narrow, abbrev or wide symbols. -static v8::Handle GetSymbols(const v8::Arguments& args, - const icu::UnicodeString* narrow, - int32_t narrow_count, - const icu::UnicodeString* abbrev, - int32_t abbrev_count, - const icu::UnicodeString* wide, - int32_t wide_count) { - v8::HandleScope handle_scope; - - // Make wide width default. - const icu::UnicodeString* result = wide; - int32_t count = wide_count; - - if (args.Length() == 1 && args[0]->IsString()) { - v8::String::AsciiValue ascii_value(args[0]); - if (strcmp(*ascii_value, "abbreviated") == 0) { - result = abbrev; - count = abbrev_count; - } else if (strcmp(*ascii_value, "narrow") == 0) { - result = narrow; - count = narrow_count; - } - } - - v8::Handle symbols = v8::Array::New(); - for (int32_t i = 0; i < count; ++i) { - symbols->Set(i, v8::String::New( - reinterpret_cast(result[i].getBuffer()), - result[i].length())); - } - - return handle_scope.Close(symbols); -} - -// Throws a JavaScript exception. -static v8::Handle ThrowUnexpectedObjectError() { - // Returns undefined, and schedules an exception to be thrown. - return v8::ThrowException(v8::Exception::Error( - v8::String::New("DateTimeFormat method called on an object " - "that is not a DateTimeFormat."))); -} - -// Returns icu date/time style. -static icu::DateFormat::EStyle GetDateTimeStyle( - const icu::UnicodeString& type) { - if (type == UNICODE_STRING_SIMPLE("medium")) { - return icu::DateFormat::kMedium; - } else if (type == UNICODE_STRING_SIMPLE("long")) { - return icu::DateFormat::kLong; - } else if (type == UNICODE_STRING_SIMPLE("full")) { - return icu::DateFormat::kFull; - } - - return icu::DateFormat::kShort; -} - -} } // namespace v8::internal diff --git a/deps/v8/src/extensions/experimental/datetime-format.h b/deps/v8/src/extensions/experimental/datetime-format.h deleted file mode 100644 index a6a228c77d..0000000000 --- a/deps/v8/src/extensions/experimental/datetime-format.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef V8_EXTENSIONS_EXPERIMENTAL_DATETIME_FORMAT_H_ -#define V8_EXTENSIONS_EXPERIMENTAL_DATETIME_FORMAT_H_ - -#include "include/v8.h" - -#include "unicode/uversion.h" - -namespace U_ICU_NAMESPACE { -class SimpleDateFormat; -} - -namespace v8 { -namespace internal { - -class DateTimeFormat { - public: - static v8::Handle JSDateTimeFormat(const v8::Arguments& args); - - // Helper methods for various bindings. - - // Unpacks date format object from corresponding JavaScript object. - static icu::SimpleDateFormat* UnpackDateTimeFormat( - v8::Handle obj); - - // Release memory we allocated for the DateFormat once the JS object that - // holds the pointer gets garbage collected. - static void DeleteDateTimeFormat(v8::Persistent object, - void* param); - - // Formats date and returns corresponding string. - static v8::Handle Format(const v8::Arguments& args); - - // All date time symbol methods below return stand-alone names in - // either narrow, abbreviated or wide width. - - // Get list of months. - static v8::Handle GetMonths(const v8::Arguments& args); - - // Get list of weekdays. - static v8::Handle GetWeekdays(const v8::Arguments& args); - - // Get list of eras. - static v8::Handle GetEras(const v8::Arguments& args); - - // Get list of day periods. - static v8::Handle GetAmPm(const v8::Arguments& args); - - private: - DateTimeFormat(); - - static v8::Persistent datetime_format_template_; -}; - -} } // namespace v8::internal - -#endif // V8_EXTENSIONS_EXPERIMENTAL_DATETIME_FORMAT_H_ diff --git a/deps/v8/src/extensions/experimental/experimental.gyp b/deps/v8/src/extensions/experimental/experimental.gyp deleted file mode 100644 index 24fb683160..0000000000 --- a/deps/v8/src/extensions/experimental/experimental.gyp +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2011 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -{ - 'variables': { - # TODO(cira): Find out how to pass this value for arbitrary embedder. - # Chromium sets it in common.gypi and does force include of that file for - # all sub projects. - 'icu_src_dir%': '../../../../third_party/icu', - }, - 'targets': [ - { - 'target_name': 'i18n_api', - 'type': 'static_library', - 'sources': [ - 'break-iterator.cc', - 'break-iterator.h', - 'collator.cc', - 'collator.h', - 'datetime-format.cc', - 'datetime-format.h', - 'i18n-extension.cc', - 'i18n-extension.h', - 'i18n-locale.cc', - 'i18n-locale.h', - 'i18n-natives.h', - 'i18n-utils.cc', - 'i18n-utils.h', - 'language-matcher.cc', - 'language-matcher.h', - 'number-format.cc', - 'number-format.h', - '<(SHARED_INTERMEDIATE_DIR)/i18n-js.cc', - ], - 'include_dirs': [ - '<(icu_src_dir)/public/common', - # v8/ is root for all includes. - '../../..' - ], - 'dependencies': [ - '<(icu_src_dir)/icu.gyp:*', - 'js2c_i18n#host', - '../../../tools/gyp/v8.gyp:v8', - ], - 'direct_dependent_settings': { - # Adds -Iv8 for embedders. - 'include_dirs': [ - '../../..' - ], - }, - }, - { - 'target_name': 'js2c_i18n', - 'type': 'none', - 'toolsets': ['host'], - 'variables': { - 'js_files': [ - 'i18n.js' - ], - }, - 'actions': [ - { - 'action_name': 'js2c_i18n', - 'inputs': [ - 'i18n-js2c.py', - '<@(js_files)', - ], - 'outputs': [ - '<(SHARED_INTERMEDIATE_DIR)/i18n-js.cc', - ], - 'action': [ - 'python', - 'i18n-js2c.py', - '<@(_outputs)', - '<@(js_files)' - ], - }, - ], - }, - ], # targets -} diff --git a/deps/v8/src/extensions/experimental/i18n-extension.cc b/deps/v8/src/extensions/experimental/i18n-extension.cc deleted file mode 100644 index c5afcf0bfc..0000000000 --- a/deps/v8/src/extensions/experimental/i18n-extension.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "src/extensions/experimental/i18n-extension.h" - -#include "src/extensions/experimental/break-iterator.h" -#include "src/extensions/experimental/collator.h" -#include "src/extensions/experimental/datetime-format.h" -#include "src/extensions/experimental/i18n-locale.h" -#include "src/extensions/experimental/i18n-natives.h" -#include "src/extensions/experimental/number-format.h" - -namespace v8 { -namespace internal { - -I18NExtension* I18NExtension::extension_ = NULL; - -I18NExtension::I18NExtension() - : v8::Extension("v8/i18n", I18Natives::GetScriptSource()) { -} - -v8::Handle I18NExtension::GetNativeFunction( - v8::Handle name) { - if (name->Equals(v8::String::New("NativeJSLocale"))) { - return v8::FunctionTemplate::New(I18NLocale::JSLocale); - } else if (name->Equals(v8::String::New("NativeJSBreakIterator"))) { - return v8::FunctionTemplate::New(BreakIterator::JSBreakIterator); - } else if (name->Equals(v8::String::New("NativeJSCollator"))) { - return v8::FunctionTemplate::New(Collator::JSCollator); - } else if (name->Equals(v8::String::New("NativeJSDateTimeFormat"))) { - return v8::FunctionTemplate::New(DateTimeFormat::JSDateTimeFormat); - } else if (name->Equals(v8::String::New("NativeJSNumberFormat"))) { - return v8::FunctionTemplate::New(NumberFormat::JSNumberFormat); - } - - return v8::Handle(); -} - -I18NExtension* I18NExtension::get() { - if (!extension_) { - extension_ = new I18NExtension(); - } - return extension_; -} - -void I18NExtension::Register() { - static v8::DeclareExtension i18n_extension_declaration(I18NExtension::get()); -} - -} } // namespace v8::internal diff --git a/deps/v8/src/extensions/experimental/i18n-extension.h b/deps/v8/src/extensions/experimental/i18n-extension.h deleted file mode 100644 index 5401f2504e..0000000000 --- a/deps/v8/src/extensions/experimental/i18n-extension.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef V8_EXTENSIONS_EXPERIMENTAL_I18N_EXTENSION_H_ -#define V8_EXTENSIONS_EXPERIMENTAL_I18N_EXTENSION_H_ - -#include "include/v8.h" - -namespace v8 { -namespace internal { - - -class I18NExtension : public v8::Extension { - public: - I18NExtension(); - - virtual v8::Handle GetNativeFunction( - v8::Handle name); - - // V8 code prefers Register, while Chrome and WebKit use get kind of methods. - static void Register(); - static I18NExtension* get(); - - private: - static I18NExtension* extension_; -}; - -} } // namespace v8::internal - -#endif // V8_EXTENSIONS_EXPERIMENTAL_I18N_EXTENSION_H_ diff --git a/deps/v8/src/extensions/experimental/i18n-js2c.py b/deps/v8/src/extensions/experimental/i18n-js2c.py deleted file mode 100644 index 9c3128bd2a..0000000000 --- a/deps/v8/src/extensions/experimental/i18n-js2c.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2011 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# This is a utility for converting I18N JavaScript source code into C-style -# char arrays. It is used for embedded JavaScript code in the V8 -# library. -# This is a pared down copy of v8/tools/js2c.py that avoids use of -# v8/src/natives.h and produces different cc template. - -import os, re, sys, string - - -def ToCArray(lines): - result = [] - for chr in lines: - value = ord(chr) - assert value < 128 - result.append(str(value)) - result.append("0") - return ", ".join(result) - - -def RemoveCommentsAndTrailingWhitespace(lines): - lines = re.sub(r'//.*\n', '\n', lines) # end-of-line comments - lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments. - lines = re.sub(r'\s+\n+', '\n', lines) # trailing whitespace - return lines - - -def ReadFile(filename): - file = open(filename, "rt") - try: - lines = file.read() - finally: - file.close() - return lines - - -EVAL_PATTERN = re.compile(r'\beval\s*\('); -WITH_PATTERN = re.compile(r'\bwith\s*\('); - - -def Validate(lines, file): - lines = RemoveCommentsAndTrailingWhitespace(lines) - # Because of simplified context setup, eval and with is not - # allowed in the natives files. - eval_match = EVAL_PATTERN.search(lines) - if eval_match: - raise ("Eval disallowed in natives: %s" % file) - with_match = WITH_PATTERN.search(lines) - if with_match: - raise ("With statements disallowed in natives: %s" % file) - - -HEADER_TEMPLATE = """\ -// Copyright 2011 Google Inc. All Rights Reserved. - -// This file was generated from .js source files by gyp. If you -// want to make changes to this file you should either change the -// javascript source files or the i18n-js2c.py script. - -#include "src/extensions/experimental/i18n-natives.h" - -namespace v8 { -namespace internal { - -// static -const char* I18Natives::GetScriptSource() { - // JavaScript source gets injected here. - static const char i18n_source[] = {%s}; - - return i18n_source; -} - -} // internal -} // v8 -""" - - -def JS2C(source, target): - filename = str(source) - - lines = ReadFile(filename) - Validate(lines, filename) - data = ToCArray(lines) - - # Emit result - output = open(target, "w") - output.write(HEADER_TEMPLATE % data) - output.close() - - -def main(): - target = sys.argv[1] - source = sys.argv[2] - JS2C(source, target) - - -if __name__ == "__main__": - main() diff --git a/deps/v8/src/extensions/experimental/i18n-locale.cc b/deps/v8/src/extensions/experimental/i18n-locale.cc deleted file mode 100644 index 46a5f87e11..0000000000 --- a/deps/v8/src/extensions/experimental/i18n-locale.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "src/extensions/experimental/i18n-locale.h" - -#include "src/extensions/experimental/i18n-utils.h" -#include "src/extensions/experimental/language-matcher.h" -#include "unicode/locid.h" -#include "unicode/uloc.h" - -namespace v8 { -namespace internal { - -const char* const I18NLocale::kLocaleID = "localeID"; -const char* const I18NLocale::kRegionID = "regionID"; -const char* const I18NLocale::kICULocaleID = "icuLocaleID"; - -v8::Handle I18NLocale::JSLocale(const v8::Arguments& args) { - v8::HandleScope handle_scope; - - if (args.Length() != 1 || !args[0]->IsObject()) { - return v8::Undefined(); - } - - v8::Local settings = args[0]->ToObject(); - - // Get best match for locale. - v8::TryCatch try_catch; - v8::Handle locale_id = settings->Get(v8::String::New(kLocaleID)); - if (try_catch.HasCaught()) { - return v8::Undefined(); - } - - LocaleIDMatch result; - if (locale_id->IsArray()) { - LanguageMatcher::GetBestMatchForPriorityList( - v8::Handle::Cast(locale_id), &result); - } else if (locale_id->IsString()) { - LanguageMatcher::GetBestMatchForString(locale_id->ToString(), &result); - } else { - LanguageMatcher::GetBestMatchForString(v8::String::New(""), &result); - } - - // Get best match for region. - char region_id[ULOC_COUNTRY_CAPACITY]; - I18NUtils::StrNCopy(region_id, ULOC_COUNTRY_CAPACITY, ""); - - v8::Handle region = settings->Get(v8::String::New(kRegionID)); - if (try_catch.HasCaught()) { - return v8::Undefined(); - } - - if (!GetBestMatchForRegionID(result.icu_id, region, region_id)) { - // Set region id to empty string because region couldn't be inferred. - I18NUtils::StrNCopy(region_id, ULOC_COUNTRY_CAPACITY, ""); - } - - // Build JavaScript object that contains bcp and icu locale ID and region ID. - v8::Handle locale = v8::Object::New(); - locale->Set(v8::String::New(kLocaleID), v8::String::New(result.bcp47_id)); - locale->Set(v8::String::New(kICULocaleID), v8::String::New(result.icu_id)); - locale->Set(v8::String::New(kRegionID), v8::String::New(region_id)); - - return handle_scope.Close(locale); -} - -bool I18NLocale::GetBestMatchForRegionID( - const char* locale_id, v8::Handle region_id, char* result) { - if (region_id->IsString() && region_id->ToString()->Length() != 0) { - icu::Locale user_locale( - icu::Locale("und", *v8::String::Utf8Value(region_id->ToString()))); - I18NUtils::StrNCopy( - result, ULOC_COUNTRY_CAPACITY, user_locale.getCountry()); - return true; - } - // Maximize locale_id to infer the region (e.g. expand "de" to "de-Latn-DE" - // and grab "DE" from the result). - UErrorCode status = U_ZERO_ERROR; - char maximized_locale[ULOC_FULLNAME_CAPACITY]; - uloc_addLikelySubtags( - locale_id, maximized_locale, ULOC_FULLNAME_CAPACITY, &status); - uloc_getCountry(maximized_locale, result, ULOC_COUNTRY_CAPACITY, &status); - - return !U_FAILURE(status); -} - -} } // namespace v8::internal diff --git a/deps/v8/src/extensions/experimental/i18n-locale.h b/deps/v8/src/extensions/experimental/i18n-locale.h deleted file mode 100644 index 607818ce51..0000000000 --- a/deps/v8/src/extensions/experimental/i18n-locale.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef V8_EXTENSIONS_EXPERIMENTAL_I18N_LOCALE_H_ -#define V8_EXTENSIONS_EXPERIMENTAL_I18N_LOCALE_H_ - -#include "include/v8.h" - -namespace v8 { -namespace internal { - -class I18NLocale { - public: - I18NLocale() {} - - // Implementations of window.Locale methods. - static v8::Handle JSLocale(const v8::Arguments& args); - - // Infers region id given the locale id, or uses user specified region id. - // Result is canonicalized. - // Returns status of ICU operation (maximizing locale or get region call). - static bool GetBestMatchForRegionID( - const char* locale_id, v8::Handle regions, char* result); - - private: - // Key name for localeID parameter. - static const char* const kLocaleID; - // Key name for regionID parameter. - static const char* const kRegionID; - // Key name for the icuLocaleID result. - static const char* const kICULocaleID; -}; - -} } // namespace v8::internal - -#endif // V8_EXTENSIONS_EXPERIMENTAL_I18N_LOCALE_H_ diff --git a/deps/v8/src/extensions/experimental/i18n-utils.cc b/deps/v8/src/extensions/experimental/i18n-utils.cc deleted file mode 100644 index dc2be1a210..0000000000 --- a/deps/v8/src/extensions/experimental/i18n-utils.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "src/extensions/experimental/i18n-utils.h" - -#include - -#include "unicode/unistr.h" - -namespace v8 { -namespace internal { - -// static -void I18NUtils::StrNCopy(char* dest, int length, const char* src) { - if (!dest || !src) return; - - strncpy(dest, src, length); - dest[length - 1] = '\0'; -} - -// static -bool I18NUtils::ExtractStringSetting(const v8::Handle& settings, - const char* setting, - icu::UnicodeString* result) { - if (!setting || !result) return false; - - v8::HandleScope handle_scope; - v8::TryCatch try_catch; - v8::Handle value = settings->Get(v8::String::New(setting)); - if (try_catch.HasCaught()) { - return false; - } - // No need to check if |value| is empty because it's taken care of - // by TryCatch above. - if (!value->IsUndefined() && !value->IsNull() && value->IsString()) { - v8::String::Utf8Value utf8_value(value); - if (*utf8_value == NULL) return false; - result->setTo(icu::UnicodeString::fromUTF8(*utf8_value)); - return true; - } - return false; -} - -// static -void I18NUtils::AsciiToUChar(const char* source, - int32_t source_length, - UChar* target, - int32_t target_length) { - int32_t length = - source_length < target_length ? source_length : target_length; - - if (length <= 0) { - return; - } - - for (int32_t i = 0; i < length - 1; ++i) { - target[i] = static_cast(source[i]); - } - - target[length - 1] = 0x0u; -} - -} } // namespace v8::internal diff --git a/deps/v8/src/extensions/experimental/i18n-utils.h b/deps/v8/src/extensions/experimental/i18n-utils.h deleted file mode 100644 index 7c31528be8..0000000000 --- a/deps/v8/src/extensions/experimental/i18n-utils.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef V8_EXTENSIONS_EXPERIMENTAL_I18N_UTILS_H_ -#define V8_EXTENSIONS_EXPERIMENTAL_I18N_UTILS_H_ - -#include "include/v8.h" - -#include "unicode/uversion.h" - -namespace U_ICU_NAMESPACE { -class UnicodeString; -} - -namespace v8 { -namespace internal { - -class I18NUtils { - public: - // Safe string copy. Null terminates the destination. Copies at most - // (length - 1) bytes. - // We can't use snprintf since it's not supported on all relevant platforms. - // We can't use OS::SNPrintF, it's only for internal code. - static void StrNCopy(char* dest, int length, const char* src); - - // Extract a string setting named in |settings| and set it to |result|. - // Return true if it's specified. Otherwise, return false. - static bool ExtractStringSetting(const v8::Handle& settings, - const char* setting, - icu::UnicodeString* result); - - // Converts ASCII array into UChar array. - // Target is always \0 terminated. - static void AsciiToUChar(const char* source, - int32_t source_length, - UChar* target, - int32_t target_length); - - private: - I18NUtils() {} -}; - -} } // namespace v8::internal - -#endif // V8_EXTENSIONS_EXPERIMENTAL_I18N_UTILS_H_ diff --git a/deps/v8/src/extensions/experimental/i18n.js b/deps/v8/src/extensions/experimental/i18n.js deleted file mode 100644 index 56bcf9e478..0000000000 --- a/deps/v8/src/extensions/experimental/i18n.js +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright 2006-2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// TODO(cira): Rename v8Locale into LocaleInfo once we have stable API. -/** - * LocaleInfo class is an aggregate class of all i18n API calls. - * @param {Object} settings - localeID and regionID to create LocaleInfo from. - * {Array.|string} settings.localeID - - * Unicode identifier of the locale. - * See http://unicode.org/reports/tr35/#BCP_47_Conformance - * {string} settings.regionID - ISO3166 region ID with addition of - * invalid, undefined and reserved region codes. - * @constructor - */ -v8Locale = function(settings) { - native function NativeJSLocale(); - - // Assume user wanted to do v8Locale("sr"); - if (typeof(settings) === "string") { - settings = {'localeID': settings}; - } - - var properties = NativeJSLocale( - v8Locale.__createSettingsOrDefault(settings, {'localeID': 'root'})); - - // Keep the resolved ICU locale ID around to avoid resolving localeID to - // ICU locale ID every time BreakIterator, Collator and so forth are called. - this.__icuLocaleID = properties.icuLocaleID; - this.options = {'localeID': properties.localeID, - 'regionID': properties.regionID}; -}; - -/** - * Clones existing locale with possible overrides for some of the options. - * @param {!Object} settings - overrides for current locale settings. - * @returns {Object} - new LocaleInfo object. - */ -v8Locale.prototype.derive = function(settings) { - return new v8Locale( - v8Locale.__createSettingsOrDefault(settings, this.options)); -}; - -/** - * v8BreakIterator class implements locale aware segmenatation. - * It is not part of EcmaScript proposal. - * @param {Object} locale - locale object to pass to break - * iterator implementation. - * @param {string} type - type of segmenatation: - * - character - * - word - * - sentence - * - line - * @private - * @constructor - */ -v8Locale.v8BreakIterator = function(locale, type) { - native function NativeJSBreakIterator(); - - locale = v8Locale.__createLocaleOrDefault(locale); - // BCP47 ID would work in this case, but we use ICU locale for consistency. - var iterator = NativeJSBreakIterator(locale.__icuLocaleID, type); - iterator.type = type; - return iterator; -}; - -/** - * Type of the break we encountered during previous iteration. - * @type{Enum} - */ -v8Locale.v8BreakIterator.BreakType = { - 'unknown': -1, - 'none': 0, - 'number': 100, - 'word': 200, - 'kana': 300, - 'ideo': 400 -}; - -/** - * Creates new v8BreakIterator based on current locale. - * @param {string} - type of segmentation. See constructor. - * @returns {Object} - new v8BreakIterator object. - */ -v8Locale.prototype.v8CreateBreakIterator = function(type) { - return new v8Locale.v8BreakIterator(this, type); -}; - -// TODO(jungshik): Set |collator.options| to actually recognized / resolved -// values. -/** - * Collator class implements locale-aware sort. - * @param {Object} locale - locale object to pass to collator implementation. - * @param {Object} settings - collation flags: - * - ignoreCase - * - ignoreAccents - * - numeric - * @private - * @constructor - */ -v8Locale.Collator = function(locale, settings) { - native function NativeJSCollator(); - - locale = v8Locale.__createLocaleOrDefault(locale); - var collator = NativeJSCollator( - locale.__icuLocaleID, v8Locale.__createSettingsOrDefault(settings, {})); - return collator; -}; - -/** - * Creates new Collator based on current locale. - * @param {Object} - collation flags. See constructor. - * @returns {Object} - new Collator object. - */ -v8Locale.prototype.createCollator = function(settings) { - return new v8Locale.Collator(this, settings); -}; - -/** - * DateTimeFormat class implements locale-aware date and time formatting. - * Constructor is not part of public API. - * @param {Object} locale - locale object to pass to formatter. - * @param {Object} settings - formatting flags: - * - skeleton - * - dateStyle - * - timeStyle - * @private - * @constructor - */ -v8Locale.__DateTimeFormat = function(locale, settings) { - native function NativeJSDateTimeFormat(); - - settings = v8Locale.__createSettingsOrDefault(settings, {}); - - var cleanSettings = {}; - if (settings.hasOwnProperty('skeleton')) { - cleanSettings['skeleton'] = settings['skeleton']; - } else { - cleanSettings = {}; - if (settings.hasOwnProperty('dateStyle')) { - var ds = settings['dateStyle']; - if (!/^(short|medium|long|full)$/.test(ds)) ds = 'short'; - cleanSettings['dateStyle'] = ds; - } else if (settings.hasOwnProperty('dateType')) { - // Obsolete. New spec requires dateStyle, but we'll keep this around - // for current users. - // TODO(cira): Remove when all internal users switch to dateStyle. - var dt = settings['dateType']; - if (!/^(short|medium|long|full)$/.test(dt)) dt = 'short'; - cleanSettings['dateStyle'] = dt; - } - - if (settings.hasOwnProperty('timeStyle')) { - var ts = settings['timeStyle']; - if (!/^(short|medium|long|full)$/.test(ts)) ts = 'short'; - cleanSettings['timeStyle'] = ts; - } else if (settings.hasOwnProperty('timeType')) { - // TODO(cira): Remove when all internal users switch to timeStyle. - var tt = settings['timeType']; - if (!/^(short|medium|long|full)$/.test(tt)) tt = 'short'; - cleanSettings['timeStyle'] = tt; - } - } - - // Default is to show short date and time. - if (!cleanSettings.hasOwnProperty('skeleton') && - !cleanSettings.hasOwnProperty('dateStyle') && - !cleanSettings.hasOwnProperty('timeStyle')) { - cleanSettings = {'dateStyle': 'short', - 'timeStyle': 'short'}; - } - - locale = v8Locale.__createLocaleOrDefault(locale); - var formatter = NativeJSDateTimeFormat(locale.__icuLocaleID, cleanSettings); - - // NativeJSDateTimeFormat creates formatter.options for us, we just need - // to append actual settings to it. - for (key in cleanSettings) { - formatter.options[key] = cleanSettings[key]; - } - - /** - * Clones existing date time format with possible overrides for some - * of the options. - * @param {!Object} overrideSettings - overrides for current format settings. - * @returns {Object} - new DateTimeFormat object. - * @public - */ - formatter.derive = function(overrideSettings) { - // To remove a setting user can specify undefined as its value. We'll remove - // it from the map in that case. - for (var prop in overrideSettings) { - if (settings.hasOwnProperty(prop) && !overrideSettings[prop]) { - delete settings[prop]; - } - } - return new v8Locale.__DateTimeFormat( - locale, v8Locale.__createSettingsOrDefault(overrideSettings, settings)); - }; - - return formatter; -}; - -/** - * Creates new DateTimeFormat based on current locale. - * @param {Object} - formatting flags. See constructor. - * @returns {Object} - new DateTimeFormat object. - */ -v8Locale.prototype.createDateTimeFormat = function(settings) { - return new v8Locale.__DateTimeFormat(this, settings); -}; - -/** - * NumberFormat class implements locale-aware number formatting. - * Constructor is not part of public API. - * @param {Object} locale - locale object to pass to formatter. - * @param {Object} settings - formatting flags: - * - skeleton - * - pattern - * - style - decimal, currency, percent or scientific - * - currencyCode - ISO 4217 3-letter currency code - * @private - * @constructor - */ -v8Locale.__NumberFormat = function(locale, settings) { - native function NativeJSNumberFormat(); - - settings = v8Locale.__createSettingsOrDefault(settings, {}); - - var cleanSettings = {}; - if (settings.hasOwnProperty('skeleton')) { - // Assign skeleton to cleanSettings and fix invalid currency pattern - // if present - 'ooxo' becomes 'o'. - cleanSettings['skeleton'] = - settings['skeleton'].replace(/\u00a4+[^\u00a4]+\u00a4+/g, '\u00a4'); - } else if (settings.hasOwnProperty('pattern')) { - cleanSettings['pattern'] = settings['pattern']; - } else if (settings.hasOwnProperty('style')) { - var style = settings['style']; - if (!/^(decimal|currency|percent|scientific)$/.test(style)) { - style = 'decimal'; - } - cleanSettings['style'] = style; - } - - // Default is to show decimal style. - if (!cleanSettings.hasOwnProperty('skeleton') && - !cleanSettings.hasOwnProperty('pattern') && - !cleanSettings.hasOwnProperty('style')) { - cleanSettings = {'style': 'decimal'}; - } - - // Add currency code if available and valid (3-letter ASCII code). - if (settings.hasOwnProperty('currencyCode') && - /^[a-zA-Z]{3}$/.test(settings['currencyCode'])) { - cleanSettings['currencyCode'] = settings['currencyCode'].toUpperCase(); - } - - locale = v8Locale.__createLocaleOrDefault(locale); - // Pass in region ID for proper currency detection. Use ZZ if region is empty. - var region = locale.options.regionID !== '' ? locale.options.regionID : 'ZZ'; - var formatter = NativeJSNumberFormat( - locale.__icuLocaleID, 'und_' + region, cleanSettings); - - // ICU doesn't always uppercase the currency code. - if (formatter.options.hasOwnProperty('currencyCode')) { - formatter.options['currencyCode'] = - formatter.options['currencyCode'].toUpperCase(); - } - - for (key in cleanSettings) { - // Don't overwrite keys that are alredy in. - if (formatter.options.hasOwnProperty(key)) continue; - - formatter.options[key] = cleanSettings[key]; - } - - /** - * Clones existing number format with possible overrides for some - * of the options. - * @param {!Object} overrideSettings - overrides for current format settings. - * @returns {Object} - new or cached NumberFormat object. - * @public - */ - formatter.derive = function(overrideSettings) { - // To remove a setting user can specify undefined as its value. We'll remove - // it from the map in that case. - for (var prop in overrideSettings) { - if (settings.hasOwnProperty(prop) && !overrideSettings[prop]) { - delete settings[prop]; - } - } - return new v8Locale.__NumberFormat( - locale, v8Locale.__createSettingsOrDefault(overrideSettings, settings)); - }; - - return formatter; -}; - -/** - * Creates new NumberFormat based on current locale. - * @param {Object} - formatting flags. See constructor. - * @returns {Object} - new or cached NumberFormat object. - */ -v8Locale.prototype.createNumberFormat = function(settings) { - return new v8Locale.__NumberFormat(this, settings); -}; - -/** - * Merges user settings and defaults. - * Settings that are not of object type are rejected. - * Actual property values are not validated, but whitespace is trimmed if they - * are strings. - * @param {!Object} settings - user provided settings. - * @param {!Object} defaults - default values for this type of settings. - * @returns {Object} - valid settings object. - * @private - */ -v8Locale.__createSettingsOrDefault = function(settings, defaults) { - if (!settings || typeof(settings) !== 'object' ) { - return defaults; - } - for (var key in defaults) { - if (!settings.hasOwnProperty(key)) { - settings[key] = defaults[key]; - } - } - // Clean up settings. - for (var key in settings) { - // Trim whitespace. - if (typeof(settings[key]) === "string") { - settings[key] = settings[key].trim(); - } - // Remove all properties that are set to undefined/null. This allows - // derive method to remove a setting we don't need anymore. - if (!settings[key]) { - delete settings[key]; - } - } - - return settings; -}; - -/** - * If locale is valid (defined and of v8Locale type) we return it. If not - * we create default locale and return it. - * @param {!Object} locale - user provided locale. - * @returns {Object} - v8Locale object. - * @private - */ -v8Locale.__createLocaleOrDefault = function(locale) { - if (!locale || !(locale instanceof v8Locale)) { - return new v8Locale(); - } else { - return locale; - } -}; diff --git a/deps/v8/src/extensions/experimental/language-matcher.cc b/deps/v8/src/extensions/experimental/language-matcher.cc deleted file mode 100644 index 127e57178a..0000000000 --- a/deps/v8/src/extensions/experimental/language-matcher.cc +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// TODO(cira): Remove LanguageMatcher from v8 when ICU implements -// language matching API. - -#include "src/extensions/experimental/language-matcher.h" - -#include - -#include "src/extensions/experimental/i18n-utils.h" -#include "unicode/datefmt.h" // For getAvailableLocales -#include "unicode/locid.h" -#include "unicode/uloc.h" - -namespace v8 { -namespace internal { - -const unsigned int LanguageMatcher::kLanguageWeight = 75; -const unsigned int LanguageMatcher::kScriptWeight = 20; -const unsigned int LanguageMatcher::kRegionWeight = 5; -const unsigned int LanguageMatcher::kThreshold = 50; -const unsigned int LanguageMatcher::kPositionBonus = 1; -const char* const LanguageMatcher::kDefaultLocale = "root"; - -static const char* GetLanguageException(const char*); -static bool BCP47ToICUFormat(const char*, char*); -static int CompareLocaleSubtags(const char*, const char*); -static bool BuildLocaleName(const char*, const char*, LocaleIDMatch*); - -LocaleIDMatch::LocaleIDMatch() - : score(-1) { - I18NUtils::StrNCopy( - bcp47_id, ULOC_FULLNAME_CAPACITY, LanguageMatcher::kDefaultLocale); - - I18NUtils::StrNCopy( - icu_id, ULOC_FULLNAME_CAPACITY, LanguageMatcher::kDefaultLocale); -} - -LocaleIDMatch& LocaleIDMatch::operator=(const LocaleIDMatch& rhs) { - I18NUtils::StrNCopy(this->bcp47_id, ULOC_FULLNAME_CAPACITY, rhs.bcp47_id); - I18NUtils::StrNCopy(this->icu_id, ULOC_FULLNAME_CAPACITY, rhs.icu_id); - this->score = rhs.score; - - return *this; -} - -// static -void LanguageMatcher::GetBestMatchForPriorityList( - v8::Handle locales, LocaleIDMatch* result) { - v8::HandleScope handle_scope; - - unsigned int position_bonus = locales->Length() * kPositionBonus; - - int max_score = 0; - LocaleIDMatch match; - for (unsigned int i = 0; i < locales->Length(); ++i) { - position_bonus -= kPositionBonus; - - v8::TryCatch try_catch; - v8::Local locale_id = locales->Get(v8::Integer::New(i)); - - // Return default if exception is raised when reading parameter. - if (try_catch.HasCaught()) break; - - // JavaScript arrays can be heterogenous so check each item - // if it's a string. - if (!locale_id->IsString()) continue; - - if (!CompareToSupportedLocaleIDList(locale_id->ToString(), &match)) { - continue; - } - - // Skip items under threshold. - if (match.score < kThreshold) continue; - - match.score += position_bonus; - if (match.score > max_score) { - *result = match; - - max_score = match.score; - } - } -} - -// static -void LanguageMatcher::GetBestMatchForString( - v8::Handle locale, LocaleIDMatch* result) { - LocaleIDMatch match; - - if (CompareToSupportedLocaleIDList(locale, &match) && - match.score >= kThreshold) { - *result = match; - } -} - -// static -bool LanguageMatcher::CompareToSupportedLocaleIDList( - v8::Handle locale_id, LocaleIDMatch* result) { - static int32_t available_count = 0; - // Depending on how ICU data is built, locales returned by - // Locale::getAvailableLocale() are not guaranteed to support DateFormat, - // Collation and other services. We can call getAvailableLocale() of all the - // services we want to support and take the intersection of them all, but - // using DateFormat::getAvailableLocales() should suffice. - // TODO(cira): Maybe make this thread-safe? - static const icu::Locale* available_locales = - icu::DateFormat::getAvailableLocales(available_count); - - // Skip this locale_id if it's not in ASCII. - static LocaleIDMatch default_match; - v8::String::AsciiValue ascii_value(locale_id); - if (*ascii_value == NULL) return false; - - char locale[ULOC_FULLNAME_CAPACITY]; - if (!BCP47ToICUFormat(*ascii_value, locale)) return false; - - icu::Locale input_locale(locale); - - // Position of the best match locale in list of available locales. - int position = -1; - const char* language = GetLanguageException(input_locale.getLanguage()); - const char* script = input_locale.getScript(); - const char* region = input_locale.getCountry(); - for (int32_t i = 0; i < available_count; ++i) { - int current_score = 0; - int sign = - CompareLocaleSubtags(language, available_locales[i].getLanguage()); - current_score += sign * kLanguageWeight; - - sign = CompareLocaleSubtags(script, available_locales[i].getScript()); - current_score += sign * kScriptWeight; - - sign = CompareLocaleSubtags(region, available_locales[i].getCountry()); - current_score += sign * kRegionWeight; - - if (current_score >= kThreshold && current_score > result->score) { - result->score = current_score; - position = i; - } - } - - // Didn't find any good matches so use defaults. - if (position == -1) return false; - - return BuildLocaleName(available_locales[position].getBaseName(), - input_locale.getName(), result); -} - -// For some unsupported language subtags it is better to fallback to related -// language that is supported than to default. -static const char* GetLanguageException(const char* language) { - // Serbo-croatian to Serbian. - if (!strcmp(language, "sh")) return "sr"; - - // Norweigan to Norweiaan to Norwegian Bokmal. - if (!strcmp(language, "no")) return "nb"; - - // Moldavian to Romanian. - if (!strcmp(language, "mo")) return "ro"; - - // Tagalog to Filipino. - if (!strcmp(language, "tl")) return "fil"; - - return language; -} - -// Converts user input from BCP47 locale id format to ICU compatible format. -// Returns false if uloc_forLanguageTag call fails or if extension is too long. -static bool BCP47ToICUFormat(const char* locale_id, char* result) { - UErrorCode status = U_ZERO_ERROR; - int32_t locale_size = 0; - - char locale[ULOC_FULLNAME_CAPACITY]; - I18NUtils::StrNCopy(locale, ULOC_FULLNAME_CAPACITY, locale_id); - - // uloc_forLanguageTag has a bug where long extension can crash the code. - // We need to check if extension part of language id conforms to the length. - // ICU bug: http://bugs.icu-project.org/trac/ticket/8519 - const char* extension = strstr(locale_id, "-u-"); - if (extension != NULL && - strlen(extension) > ULOC_KEYWORD_AND_VALUES_CAPACITY) { - // Truncate to get non-crashing string, but still preserve base language. - int base_length = strlen(locale_id) - strlen(extension); - locale[base_length] = '\0'; - } - - uloc_forLanguageTag(locale, result, ULOC_FULLNAME_CAPACITY, - &locale_size, &status); - return !U_FAILURE(status); -} - -// Compares locale id subtags. -// Returns 1 for match or -1 for mismatch. -static int CompareLocaleSubtags(const char* lsubtag, const char* rsubtag) { - return strcmp(lsubtag, rsubtag) == 0 ? 1 : -1; -} - -// Builds a BCP47 compliant locale id from base name of matched locale and -// full user specified locale. -// Returns false if uloc_toLanguageTag failed to convert locale id. -// Example: -// base_name of matched locale (ICU ID): de_DE -// input_locale_name (ICU ID): de_AT@collation=phonebk -// result (ICU ID): de_DE@collation=phonebk -// result (BCP47 ID): de-DE-u-co-phonebk -static bool BuildLocaleName(const char* base_name, - const char* input_locale_name, - LocaleIDMatch* result) { - I18NUtils::StrNCopy(result->icu_id, ULOC_LANG_CAPACITY, base_name); - - // Get extensions (if any) from the original locale. - const char* extension = strchr(input_locale_name, ULOC_KEYWORD_SEPARATOR); - if (extension != NULL) { - I18NUtils::StrNCopy(result->icu_id + strlen(base_name), - ULOC_KEYWORD_AND_VALUES_CAPACITY, extension); - } else { - I18NUtils::StrNCopy(result->icu_id, ULOC_LANG_CAPACITY, base_name); - } - - // Convert ICU locale name into BCP47 format. - UErrorCode status = U_ZERO_ERROR; - uloc_toLanguageTag(result->icu_id, result->bcp47_id, - ULOC_FULLNAME_CAPACITY, false, &status); - return !U_FAILURE(status); -} - -} } // namespace v8::internal diff --git a/deps/v8/src/extensions/experimental/language-matcher.h b/deps/v8/src/extensions/experimental/language-matcher.h deleted file mode 100644 index dd2930458b..0000000000 --- a/deps/v8/src/extensions/experimental/language-matcher.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef V8_EXTENSIONS_EXPERIMENTAL_LANGUAGE_MATCHER_H_ -#define V8_EXTENSIONS_EXPERIMENTAL_LANGUAGE_MATCHER_H_ - -#include "include/v8.h" - -#include "unicode/uloc.h" - -namespace v8 { -namespace internal { - -struct LocaleIDMatch { - LocaleIDMatch(); - - LocaleIDMatch& operator=(const LocaleIDMatch& rhs); - - // Bcp47 locale id - "de-Latn-DE-u-co-phonebk". - char bcp47_id[ULOC_FULLNAME_CAPACITY]; - - // ICU locale id - "de_Latn_DE@collation=phonebk". - char icu_id[ULOC_FULLNAME_CAPACITY]; - - // Score for this locale. - int score; -}; - -class LanguageMatcher { - public: - // Default locale. - static const char* const kDefaultLocale; - - // Finds best supported locale for a given a list of locale identifiers. - // It preserves the extension for the locale id. - static void GetBestMatchForPriorityList( - v8::Handle locale_list, LocaleIDMatch* result); - - // Finds best supported locale for a single locale identifier. - // It preserves the extension for the locale id. - static void GetBestMatchForString( - v8::Handle locale_id, LocaleIDMatch* result); - - private: - // If langauge subtags match add this amount to the score. - static const unsigned int kLanguageWeight; - - // If script subtags match add this amount to the score. - static const unsigned int kScriptWeight; - - // If region subtags match add this amount to the score. - static const unsigned int kRegionWeight; - - // LocaleID match score has to be over this number to accept the match. - static const unsigned int kThreshold; - - // For breaking ties in priority queue. - static const unsigned int kPositionBonus; - - LanguageMatcher(); - - // Compares locale_id to the supported list of locales and returns best - // match. - // Returns false if it fails to convert locale id from ICU to BCP47 format. - static bool CompareToSupportedLocaleIDList(v8::Handle locale_id, - LocaleIDMatch* result); -}; - -} } // namespace v8::internal - -#endif // V8_EXTENSIONS_EXPERIMENTAL_LANGUAGE_MATCHER_H_ diff --git a/deps/v8/src/extensions/experimental/number-format.cc b/deps/v8/src/extensions/experimental/number-format.cc deleted file mode 100644 index 2932c52854..0000000000 --- a/deps/v8/src/extensions/experimental/number-format.cc +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "src/extensions/experimental/number-format.h" - -#include - -#include "src/extensions/experimental/i18n-utils.h" -#include "unicode/dcfmtsym.h" -#include "unicode/decimfmt.h" -#include "unicode/locid.h" -#include "unicode/numfmt.h" -#include "unicode/uchar.h" -#include "unicode/ucurr.h" -#include "unicode/unum.h" -#include "unicode/uversion.h" - -namespace v8 { -namespace internal { - -const int NumberFormat::kCurrencyCodeLength = 4; - -v8::Persistent NumberFormat::number_format_template_; - -static icu::DecimalFormat* CreateNumberFormat(v8::Handle, - v8::Handle, - v8::Handle); -static icu::DecimalFormat* CreateFormatterFromSkeleton( - const icu::Locale&, const icu::UnicodeString&, UErrorCode*); -static icu::DecimalFormatSymbols* GetFormatSymbols(const icu::Locale&); -static bool GetCurrencyCode(const icu::Locale&, - const char* const, - v8::Handle, - UChar*); -static v8::Handle ThrowUnexpectedObjectError(); - -icu::DecimalFormat* NumberFormat::UnpackNumberFormat( - v8::Handle obj) { - if (number_format_template_->HasInstance(obj)) { - return static_cast( - obj->GetPointerFromInternalField(0)); - } - - return NULL; -} - -void NumberFormat::DeleteNumberFormat(v8::Persistent object, - void* param) { - v8::Persistent persistent_object = - v8::Persistent::Cast(object); - - // First delete the hidden C++ object. - // Unpacking should never return NULL here. That would only happen if - // this method is used as the weak callback for persistent handles not - // pointing to a number formatter. - delete UnpackNumberFormat(persistent_object); - - // Then dispose of the persistent handle to JS object. - persistent_object.Dispose(); -} - -v8::Handle NumberFormat::Format(const v8::Arguments& args) { - v8::HandleScope handle_scope; - - if (args.Length() != 1 || !args[0]->IsNumber()) { - // Just return NaN on invalid input. - return v8::String::New("NaN"); - } - - icu::DecimalFormat* number_format = UnpackNumberFormat(args.Holder()); - if (!number_format) { - return ThrowUnexpectedObjectError(); - } - - // ICU will handle actual NaN value properly and return NaN string. - icu::UnicodeString result; - number_format->format(args[0]->NumberValue(), result); - - return v8::String::New( - reinterpret_cast(result.getBuffer()), result.length()); -} - -v8::Handle NumberFormat::JSNumberFormat(const v8::Arguments& args) { - v8::HandleScope handle_scope; - - // Expect locale id, region id and settings. - if (args.Length() != 3 || - !args[0]->IsString() || !args[1]->IsString() || !args[2]->IsObject()) { - return v8::ThrowException(v8::Exception::SyntaxError( - v8::String::New("Locale, region and number settings are required."))); - } - - icu::DecimalFormat* number_format = CreateNumberFormat( - args[0]->ToString(), args[1]->ToString(), args[2]->ToObject()); - - if (number_format_template_.IsEmpty()) { - v8::Local raw_template(v8::FunctionTemplate::New()); - - raw_template->SetClassName(v8::String::New("v8Locale.NumberFormat")); - - // Define internal field count on instance template. - v8::Local object_template = - raw_template->InstanceTemplate(); - - // Set aside internal field for icu number formatter. - object_template->SetInternalFieldCount(1); - - // Define all of the prototype methods on prototype template. - v8::Local proto = raw_template->PrototypeTemplate(); - proto->Set(v8::String::New("format"), - v8::FunctionTemplate::New(Format)); - - number_format_template_ = - v8::Persistent::New(raw_template); - } - - // Create an empty object wrapper. - v8::Local local_object = - number_format_template_->GetFunction()->NewInstance(); - v8::Persistent wrapper = - v8::Persistent::New(local_object); - - // Set number formatter as internal field of the resulting JS object. - wrapper->SetPointerInInternalField(0, number_format); - - // Create options key. - v8::Local options = v8::Object::New(); - - // Show what ICU decided to use for easier problem tracking. - // Keep it as v8 specific extension. - icu::UnicodeString pattern; - number_format->toPattern(pattern); - options->Set(v8::String::New("v8ResolvedPattern"), - v8::String::New(reinterpret_cast( - pattern.getBuffer()), pattern.length())); - - // Set resolved currency code in options.currency if not empty. - icu::UnicodeString currency(number_format->getCurrency()); - if (!currency.isEmpty()) { - options->Set(v8::String::New("currencyCode"), - v8::String::New(reinterpret_cast( - currency.getBuffer()), currency.length())); - } - - wrapper->Set(v8::String::New("options"), options); - - // Make object handle weak so we can delete iterator once GC kicks in. - wrapper.MakeWeak(NULL, DeleteNumberFormat); - - return wrapper; -} - -// Returns DecimalFormat. -static icu::DecimalFormat* CreateNumberFormat(v8::Handle locale, - v8::Handle region, - v8::Handle settings) { - v8::HandleScope handle_scope; - - v8::String::AsciiValue ascii_locale(locale); - icu::Locale icu_locale(*ascii_locale); - - // Make formatter from skeleton. - icu::DecimalFormat* number_format = NULL; - UErrorCode status = U_ZERO_ERROR; - icu::UnicodeString setting; - - if (I18NUtils::ExtractStringSetting(settings, "skeleton", &setting)) { - // TODO(cira): Use ICU skeleton once - // http://bugs.icu-project.org/trac/ticket/8610 is resolved. - number_format = CreateFormatterFromSkeleton(icu_locale, setting, &status); - } else if (I18NUtils::ExtractStringSetting(settings, "pattern", &setting)) { - number_format = - new icu::DecimalFormat(setting, GetFormatSymbols(icu_locale), status); - } else if (I18NUtils::ExtractStringSetting(settings, "style", &setting)) { - if (setting == UNICODE_STRING_SIMPLE("currency")) { - number_format = static_cast( - icu::NumberFormat::createCurrencyInstance(icu_locale, status)); - } else if (setting == UNICODE_STRING_SIMPLE("percent")) { - number_format = static_cast( - icu::NumberFormat::createPercentInstance(icu_locale, status)); - } else if (setting == UNICODE_STRING_SIMPLE("scientific")) { - number_format = static_cast( - icu::NumberFormat::createScientificInstance(icu_locale, status)); - } else { - // Make it decimal in any other case. - number_format = static_cast( - icu::NumberFormat::createInstance(icu_locale, status)); - } - } - - if (U_FAILURE(status)) { - delete number_format; - status = U_ZERO_ERROR; - number_format = static_cast( - icu::NumberFormat::createInstance(icu_locale, status)); - } - - // Attach appropriate currency code to the formatter. - // It affects currency formatters only. - // Region is full language identifier in form 'und_' + region id. - v8::String::AsciiValue ascii_region(region); - - UChar currency_code[NumberFormat::kCurrencyCodeLength]; - if (GetCurrencyCode(icu_locale, *ascii_region, settings, currency_code)) { - number_format->setCurrency(currency_code, status); - } - - return number_format; -} - -// Generates ICU number format pattern from given skeleton. -// TODO(cira): Remove once ICU includes equivalent method -// (see http://bugs.icu-project.org/trac/ticket/8610). -static icu::DecimalFormat* CreateFormatterFromSkeleton( - const icu::Locale& icu_locale, - const icu::UnicodeString& skeleton, - UErrorCode* status) { - icu::DecimalFormat skeleton_format( - skeleton, GetFormatSymbols(icu_locale), *status); - - // Find out if skeleton contains currency or percent symbol and create - // proper instance to tweak. - icu::DecimalFormat* base_format = NULL; - - // UChar representation of U+00A4 currency symbol. - const UChar currency_symbol = 0xA4u; - - int32_t index = skeleton.indexOf(currency_symbol); - if (index != -1) { - // Find how many U+00A4 are there. There is at least one. - // Case of non-consecutive U+00A4 is taken care of in i18n.js. - int32_t end_index = skeleton.lastIndexOf(currency_symbol, index); - -#if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6) - icu::NumberFormat::EStyles style; - switch (end_index - index) { - case 0: - style = icu::NumberFormat::kCurrencyStyle; - break; - case 1: - style = icu::NumberFormat::kIsoCurrencyStyle; - break; - default: - style = icu::NumberFormat::kPluralCurrencyStyle; - } -#else // ICU version is 4.8 or above (we ignore versions below 4.0). - UNumberFormatStyle style; - switch (end_index - index) { - case 0: - style = UNUM_CURRENCY; - break; - case 1: - style = UNUM_CURRENCY_ISO; - break; - default: - style = UNUM_CURRENCY_PLURAL; - } -#endif - - base_format = static_cast( - icu::NumberFormat::createInstance(icu_locale, style, *status)); - } else if (skeleton.indexOf('%') != -1) { - base_format = static_cast( - icu::NumberFormat::createPercentInstance(icu_locale, *status)); - } else { - // TODO(cira): Handle scientific skeleton. - base_format = static_cast( - icu::NumberFormat::createInstance(icu_locale, *status)); - } - - if (U_FAILURE(*status)) { - delete base_format; - return NULL; - } - - // Copy important information from skeleton to the new formatter. - // TODO(cira): copy rounding information from skeleton? - base_format->setGroupingUsed(skeleton_format.isGroupingUsed()); - - base_format->setMinimumIntegerDigits( - skeleton_format.getMinimumIntegerDigits()); - - base_format->setMinimumFractionDigits( - skeleton_format.getMinimumFractionDigits()); - - base_format->setMaximumFractionDigits( - skeleton_format.getMaximumFractionDigits()); - - return base_format; -} - -// Gets decimal symbols for a locale. -static icu::DecimalFormatSymbols* GetFormatSymbols( - const icu::Locale& icu_locale) { - UErrorCode status = U_ZERO_ERROR; - icu::DecimalFormatSymbols* symbols = - new icu::DecimalFormatSymbols(icu_locale, status); - - if (U_FAILURE(status)) { - delete symbols; - // Use symbols from default locale. - symbols = new icu::DecimalFormatSymbols(status); - } - - return symbols; -} - -// Gets currency ISO 4217 3-letter code. -// Check currencyCode setting first, then @currency=code and in the end -// try to infer currency code from locale in the form 'und_' + region id. -// Returns false in case of error. -static bool GetCurrencyCode(const icu::Locale& icu_locale, - const char* const und_region_locale, - v8::Handle settings, - UChar* code) { - UErrorCode status = U_ZERO_ERROR; - - // If there is user specified currency code, use it. - icu::UnicodeString currency; - if (I18NUtils::ExtractStringSetting(settings, "currencyCode", ¤cy)) { - currency.extract(code, NumberFormat::kCurrencyCodeLength, status); - return true; - } - - // If ICU locale has -cu- currency code use it. - char currency_code[NumberFormat::kCurrencyCodeLength]; - int32_t length = icu_locale.getKeywordValue( - "currency", currency_code, NumberFormat::kCurrencyCodeLength, status); - if (length != 0) { - I18NUtils::AsciiToUChar(currency_code, length + 1, - code, NumberFormat::kCurrencyCodeLength); - return true; - } - - // Otherwise infer currency code from the region id. - ucurr_forLocale( - und_region_locale, code, NumberFormat::kCurrencyCodeLength, &status); - - return !!U_SUCCESS(status); -} - -// Throws a JavaScript exception. -static v8::Handle ThrowUnexpectedObjectError() { - // Returns undefined, and schedules an exception to be thrown. - return v8::ThrowException(v8::Exception::Error( - v8::String::New("NumberFormat method called on an object " - "that is not a NumberFormat."))); -} - -} } // namespace v8::internal diff --git a/deps/v8/src/extensions/experimental/number-format.h b/deps/v8/src/extensions/experimental/number-format.h deleted file mode 100644 index bcfaed6fc1..0000000000 --- a/deps/v8/src/extensions/experimental/number-format.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef V8_EXTENSIONS_EXPERIMENTAL_NUMBER_FORMAT_H_ -#define V8_EXTENSIONS_EXPERIMENTAL_NUMBER_FORMAT_H_ - -#include "include/v8.h" - -#include "unicode/uversion.h" - -namespace U_ICU_NAMESPACE { -class DecimalFormat; -} - -namespace v8 { -namespace internal { - -class NumberFormat { - public: - // 3-letter ISO 4217 currency code plus \0. - static const int kCurrencyCodeLength; - - static v8::Handle JSNumberFormat(const v8::Arguments& args); - - // Helper methods for various bindings. - - // Unpacks date format object from corresponding JavaScript object. - static icu::DecimalFormat* UnpackNumberFormat( - v8::Handle obj); - - // Release memory we allocated for the NumberFormat once the JS object that - // holds the pointer gets garbage collected. - static void DeleteNumberFormat(v8::Persistent object, - void* param); - - // Formats number and returns corresponding string. - static v8::Handle Format(const v8::Arguments& args); - - private: - NumberFormat(); - - static v8::Persistent number_format_template_; -}; - -} } // namespace v8::internal - -#endif // V8_EXTENSIONS_EXPERIMENTAL_NUMBER_FORMAT_H_ diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index 8725b67ec9..e68cc7ed32 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -233,7 +233,7 @@ class Factory { Handle CopyFixedDoubleArray( Handle array); - // Numbers (eg, literals) are pretenured by the parser. + // Numbers (e.g. literals) are pretenured by the parser. Handle NewNumber(double value, PretenureFlag pretenure = NOT_TENURED); diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index fbb6979246..0270e13a1d 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -142,11 +142,13 @@ class FullCodeGenerator: public AstVisitor { return previous_; } - protected: + protected: MacroAssembler* masm() { return codegen_->masm(); } FullCodeGenerator* codegen_; NestedStatement* previous_; + + private: DISALLOW_COPY_AND_ASSIGN(NestedStatement); }; @@ -618,8 +620,8 @@ class FullCodeGenerator: public AstVisitor { Label** if_false, Label** fall_through) const = 0; - // Returns true if we are evaluating only for side effects (ie if the result - // will be discarded). + // Returns true if we are evaluating only for side effects (i.e. if the + // result will be discarded). virtual bool IsEffect() const { return false; } // Returns true if we are evaluating for the value (in accu/on stack). diff --git a/deps/v8/src/global-handles.cc b/deps/v8/src/global-handles.cc index 87066faeaf..471f5a336c 100644 --- a/deps/v8/src/global-handles.cc +++ b/deps/v8/src/global-handles.cc @@ -232,7 +232,7 @@ class GlobalHandles::Node { VMState state(isolate, EXTERNAL); func(object, par); } - // Absense of explicit cleanup or revival of weak handle + // Absence of explicit cleanup or revival of weak handle // in most of the cases would lead to memory leak. ASSERT(state_ != NEAR_DEATH); return true; diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 3c871e2706..d97f337977 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -583,7 +583,9 @@ void Heap::ReserveSpace( PagedSpace* cell_space = Heap::cell_space(); LargeObjectSpace* lo_space = Heap::lo_space(); bool gc_performed = true; - while (gc_performed) { + int counter = 0; + static const int kThreshold = 20; + while (gc_performed && counter++ < kThreshold) { gc_performed = false; if (!new_space->ReserveSpace(new_space_size)) { Heap::CollectGarbage(NEW_SPACE); @@ -622,6 +624,11 @@ void Heap::ReserveSpace( gc_performed = true; } } + + if (gc_performed) { + // Failed to reserve the space after several attempts. + V8::FatalProcessOutOfMemory("Heap::ReserveSpace"); + } } @@ -872,6 +879,8 @@ void Heap::MarkCompact(GCTracer* tracer) { isolate_->counters()->objs_since_last_full()->Set(0); contexts_disposed_ = 0; + + isolate_->set_context_exit_happened(false); } @@ -1552,7 +1561,7 @@ class ScavengingVisitor : public StaticVisitorBase { if (marks_handling == TRANSFER_MARKS) { if (Marking::TransferColor(source, target)) { - MemoryChunk::IncrementLiveBytes(target->address(), size); + MemoryChunk::IncrementLiveBytesFromGC(target->address(), size); } } } @@ -2923,8 +2932,8 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) { bool is_ascii_data_in_two_byte_string = false; if (!is_ascii) { // At least one of the strings uses two-byte representation so we - // can't use the fast case code for short ascii strings below, but - // we can try to save memory if all chars actually fit in ascii. + // can't use the fast case code for short ASCII strings below, but + // we can try to save memory if all chars actually fit in ASCII. is_ascii_data_in_two_byte_string = first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars(); if (is_ascii_data_in_two_byte_string) { @@ -2933,9 +2942,9 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) { } // If the resulting string is small make a flat string. - if (length < String::kMinNonFlatLength) { + if (length < ConsString::kMinLength) { // Note that neither of the two inputs can be a slice because: - STATIC_ASSERT(String::kMinNonFlatLength <= SlicedString::kMinLength); + STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength); ASSERT(first->IsFlat()); ASSERT(second->IsFlat()); if (is_ascii) { @@ -3011,7 +3020,7 @@ MaybeObject* Heap::AllocateSubString(String* buffer, int end, PretenureFlag pretenure) { int length = end - start; - if (length == 0) { + if (length <= 0) { return empty_string(); } else if (length == 1) { return LookupSingleCharacterStringFromCode(buffer->Get(start)); @@ -3635,8 +3644,8 @@ void Heap::InitializeJSObjectFromMap(JSObject* obj, // TODO(1240798): Initialize the object's body using valid initial values // according to the object's initial map. For example, if the map's // instance type is JS_ARRAY_TYPE, the length field should be initialized - // to a number (eg, Smi::FromInt(0)) and the elements initialized to a - // fixed array (eg, Heap::empty_fixed_array()). Currently, the object + // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a + // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object // verification code has to cope with (temporarily) invalid objects. See // for example, JSArray::JSArrayVerify). Object* filler; @@ -4103,7 +4112,7 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, ASSERT(chars >= 0); // Ensure the chars matches the number of characters in the buffer. ASSERT(static_cast(chars) == buffer->Length()); - // Determine whether the string is ascii. + // Determine whether the string is ASCII. bool is_ascii = true; while (buffer->has_more()) { if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) { @@ -5596,7 +5605,7 @@ bool Heap::SetUp(bool create_heap_objects) { // goes wrong, just return false. The caller should check the results and // call Heap::TearDown() to release allocated memory. // - // If the heap is not yet configured (eg, through the API), configure it. + // If the heap is not yet configured (e.g. through the API), configure it. // Configuration is based on the flags new-space-size (really the semispace // size) and old-space-size if set or the initial values of semispace_size_ // and old_generation_size_ otherwise. @@ -6513,11 +6522,17 @@ int KeyedLookupCache::Hash(Map* map, String* name) { int KeyedLookupCache::Lookup(Map* map, String* name) { - int index = Hash(map, name); + int index = (Hash(map, name) & kHashMask); Key& key = keys_[index]; if ((key.map == map) && key.name->Equals(name)) { return field_offsets_[index]; } + ASSERT(kEntriesPerBucket == 2); // There are two entries to check. + // First entry in the bucket missed, check the second. + Key& key2 = keys_[index + 1]; + if ((key2.map == map) && key2.name->Equals(name)) { + return field_offsets_[index + 1]; + } return kNotFound; } @@ -6525,8 +6540,14 @@ int KeyedLookupCache::Lookup(Map* map, String* name) { void KeyedLookupCache::Update(Map* map, String* name, int field_offset) { String* symbol; if (HEAP->LookupSymbolIfExists(name, &symbol)) { - int index = Hash(map, symbol); + int index = (Hash(map, symbol) & kHashMask); Key& key = keys_[index]; + Key& key2 = keys_[index + 1]; // Second entry in the bucket. + // Demote the first entry to the second in the bucket. + key2.map = key.map; + key2.name = key.name; + field_offsets_[index + 1] = field_offsets_[index]; + // Write the new first entry. key.map = map; key.name = symbol; field_offsets_[index] = field_offset; diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index a1a53db4a3..85df55e4b5 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -690,7 +690,7 @@ class Heap { PretenureFlag pretenure = NOT_TENURED); // Computes a single character string where the character has code. - // A cache is used for ascii codes. + // A cache is used for ASCII codes. // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // failed. Please note this does not perform a garbage collection. MUST_USE_RESULT MaybeObject* LookupSingleCharacterStringFromCode( @@ -2135,9 +2135,11 @@ class KeyedLookupCache { // Clear the cache. void Clear(); - static const int kLength = 64; + static const int kLength = 128; static const int kCapacityMask = kLength - 1; - static const int kMapHashShift = 2; + static const int kMapHashShift = 5; + static const int kHashMask = -2; // Zero the last bit. + static const int kEntriesPerBucket = 2; static const int kNotFound = -1; private: @@ -2376,7 +2378,7 @@ class GCTracer BASE_EMBEDDED { intptr_t start_size_; // Size of objects in heap set in constructor. GarbageCollector collector_; // Type of collector. - // A count (including this one, eg, the first collection is 1) of the + // A count (including this one, e.g. the first collection is 1) of the // number of garbage collections. unsigned int gc_count_; @@ -2613,6 +2615,7 @@ class PathTracer : public ObjectVisitor { AssertNoAllocation no_alloc; // i.e. no gc allowed. + private: DISALLOW_IMPLICIT_CONSTRUCTORS(PathTracer); }; #endif // DEBUG || LIVE_OBJECT_LIST diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index 887e80afc4..2d32ad1fed 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/deps/v8/src/hydrogen-instructions.cc @@ -416,18 +416,18 @@ void HValue::PrintRangeTo(StringStream* stream) { void HValue::PrintChangesTo(StringStream* stream) { - int changes_flags = ChangesFlags(); - if (changes_flags == 0) return; + GVNFlagSet changes_flags = ChangesFlags(); + if (changes_flags.IsEmpty()) return; stream->Add(" changes["); - if (changes_flags == AllSideEffects()) { + if (changes_flags == AllSideEffectsFlagSet()) { stream->Add("*"); } else { bool add_comma = false; -#define PRINT_DO(type) \ - if (changes_flags & (1 << kChanges##type)) { \ - if (add_comma) stream->Add(","); \ - add_comma = true; \ - stream->Add(#type); \ +#define PRINT_DO(type) \ + if (changes_flags.Contains(kChanges##type)) { \ + if (add_comma) stream->Add(","); \ + add_comma = true; \ + stream->Add(#type); \ } GVN_FLAG_LIST(PRINT_DO); #undef PRINT_DO @@ -1408,21 +1408,21 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, SetOperandAt(0, context); SetOperandAt(1, object); set_representation(Representation::Tagged()); - SetFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnMaps); for (int i = 0; i < types->length() && types_.length() < kMaxLoadPolymorphism; ++i) { Handle map = types->at(i); LookupResult lookup(map->GetIsolate()); map->LookupInDescriptors(NULL, *name, &lookup); - if (lookup.IsProperty()) { + if (lookup.IsFound()) { switch (lookup.type()) { case FIELD: { int index = lookup.GetLocalFieldIndexFromMap(*map); if (index < 0) { - SetFlag(kDependsOnInobjectFields); + SetGVNFlag(kDependsOnInobjectFields); } else { - SetFlag(kDependsOnBackingStoreFields); + SetGVNFlag(kDependsOnBackingStoreFields); } types_.Add(types->at(i)); break; diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index 5082e4d3ff..9f661d6f03 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -492,18 +492,26 @@ class HUseIterator BASE_EMBEDDED { }; +// There must be one corresponding kDepends flag for every kChanges flag and +// the order of the kChanges flags must be exactly the same as of the kDepends +// flags. +enum GVNFlag { + // Declare global value numbering flags. +#define DECLARE_FLAG(type) kChanges##type, kDependsOn##type, + GVN_FLAG_LIST(DECLARE_FLAG) +#undef DECLARE_FLAG + kAfterLastFlag, + kLastFlag = kAfterLastFlag - 1 +}; + +typedef EnumSet GVNFlagSet; + + class HValue: public ZoneObject { public: static const int kNoNumber = -1; - // There must be one corresponding kDepends flag for every kChanges flag and - // the order of the kChanges flags must be exactly the same as of the kDepends - // flags. enum Flag { - // Declare global value numbering flags. - #define DECLARE_DO(type) kChanges##type, kDependsOn##type, - GVN_FLAG_LIST(DECLARE_DO) - #undef DECLARE_DO kFlexibleRepresentation, // Participate in Global Value Numbering, i.e. elimination of // unnecessary recomputations. If an instruction sets this flag, it must @@ -523,8 +531,8 @@ class HValue: public ZoneObject { static const int kChangesToDependsFlagsLeftShift = 1; - static int ConvertChangesToDependsFlags(int flags) { - return flags << kChangesToDependsFlagsLeftShift; + static GVNFlagSet ConvertChangesToDependsFlags(GVNFlagSet flags) { + return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift); } static HValue* cast(HValue* value) { return value; } @@ -622,16 +630,32 @@ class HValue: public ZoneObject { void ClearFlag(Flag f) { flags_ &= ~(1 << f); } bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; } - void SetAllSideEffects() { flags_ |= AllSideEffects(); } - void ClearAllSideEffects() { flags_ &= ~AllSideEffects(); } - bool HasSideEffects() const { return (flags_ & AllSideEffects()) != 0; } + GVNFlagSet gvn_flags() const { return gvn_flags_; } + void SetGVNFlag(GVNFlag f) { gvn_flags_.Add(f); } + void ClearGVNFlag(GVNFlag f) { gvn_flags_.Remove(f); } + bool CheckGVNFlag(GVNFlag f) const { return gvn_flags_.Contains(f); } + void SetAllSideEffects() { gvn_flags_.Add(AllSideEffectsFlagSet()); } + void ClearAllSideEffects() { + gvn_flags_.Remove(AllSideEffectsFlagSet()); + } + bool HasSideEffects() const { + return gvn_flags_.ContainsAnyOf(AllSideEffectsFlagSet()); + } bool HasObservableSideEffects() const { - return (flags_ & ObservableSideEffects()) != 0; + return gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet()); } - int ChangesFlags() const { return flags_ & ChangesFlagsMask(); } - int ObservableChangesFlags() const { - return flags_ & ChangesFlagsMask() & ObservableSideEffects(); + GVNFlagSet ChangesFlags() const { + GVNFlagSet result = gvn_flags_; + result.Intersect(AllChangesFlagSet()); + return result; + } + + GVNFlagSet ObservableChangesFlags() const { + GVNFlagSet result = gvn_flags_; + result.Intersect(AllChangesFlagSet()); + result.Intersect(AllObservableSideEffectsFlagSet()); + return result; } Range* range() const { return range_; } @@ -697,25 +721,28 @@ class HValue: public ZoneObject { representation_ = r; } - private: - static int ChangesFlagsMask() { - int result = 0; + static GVNFlagSet AllChangesFlagSet() { + GVNFlagSet result; // Create changes mask. -#define ADD_FLAG(type) result |= (1 << kChanges##type); +#define ADD_FLAG(type) result.Add(kChanges##type); GVN_FLAG_LIST(ADD_FLAG) #undef ADD_FLAG return result; } // A flag mask to mark an instruction as having arbitrary side effects. - static int AllSideEffects() { - return ChangesFlagsMask() & ~(1 << kChangesOsrEntries); + static GVNFlagSet AllSideEffectsFlagSet() { + GVNFlagSet result = AllChangesFlagSet(); + result.Remove(kChangesOsrEntries); + return result; } // A flag mask of all side effects that can make observable changes in // an executing program (i.e. are not safe to repeat, move or remove); - static int ObservableSideEffects() { - return ChangesFlagsMask() & ~(1 << kChangesElementsKind); + static GVNFlagSet AllObservableSideEffectsFlagSet() { + GVNFlagSet result = AllChangesFlagSet(); + result.Remove(kChangesElementsKind); + return result; } // Remove the matching use from the use list if present. Returns the @@ -735,6 +762,7 @@ class HValue: public ZoneObject { HUseListNode* use_list_; Range* range_; int flags_; + GVNFlagSet gvn_flags_; DISALLOW_COPY_AND_ASSIGN(HValue); }; @@ -772,7 +800,7 @@ class HInstruction: public HValue { : next_(NULL), previous_(NULL), position_(RelocInfo::kNoPosition) { - SetFlag(kDependsOnOsrEntries); + SetGVNFlag(kDependsOnOsrEntries); } virtual void DeleteFromGraph() { Unlink(); } @@ -1716,8 +1744,8 @@ class HJSArrayLength: public HTemplateInstruction<2> { SetOperandAt(1, typecheck); set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnArrayLengths); - SetFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnArrayLengths); + SetGVNFlag(kDependsOnMaps); } virtual Representation RequiredInputRepresentation(int index) { @@ -1741,7 +1769,7 @@ class HFixedArrayBaseLength: public HUnaryOperation { explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnArrayLengths); + SetGVNFlag(kDependsOnArrayLengths); } virtual Representation RequiredInputRepresentation(int index) { @@ -1760,7 +1788,7 @@ class HElementsKind: public HUnaryOperation { explicit HElementsKind(HValue* value) : HUnaryOperation(value) { set_representation(Representation::Integer32()); SetFlag(kUseGVN); - SetFlag(kDependsOnElementsKind); + SetGVNFlag(kDependsOnElementsKind); } virtual Representation RequiredInputRepresentation(int index) { @@ -1886,8 +1914,8 @@ class HLoadElements: public HUnaryOperation { explicit HLoadElements(HValue* value) : HUnaryOperation(value) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnMaps); - SetFlag(kDependsOnElementsKind); + SetGVNFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnElementsKind); } virtual Representation RequiredInputRepresentation(int index) { @@ -1937,7 +1965,7 @@ class HCheckMap: public HTemplateInstruction<2> { SetOperandAt(1, typecheck != NULL ? typecheck : value); set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnMaps); has_element_transitions_ = map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL) != NULL || map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL) != NULL; @@ -2105,7 +2133,7 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { HCheckPrototypeMaps(Handle prototype, Handle holder) : prototype_(prototype), holder_(holder) { SetFlag(kUseGVN); - SetFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnMaps); } #ifdef DEBUG @@ -3255,7 +3283,7 @@ class HSar: public HBitwiseBinaryOperation { class HOsrEntry: public HTemplateInstruction<0> { public: explicit HOsrEntry(int ast_id) : ast_id_(ast_id) { - SetFlag(kChangesOsrEntries); + SetGVNFlag(kChangesOsrEntries); } int ast_id() const { return ast_id_; } @@ -3343,7 +3371,7 @@ class HLoadGlobalCell: public HTemplateInstruction<0> { : cell_(cell), details_(details) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnGlobalVars); + SetGVNFlag(kDependsOnGlobalVars); } Handle cell() const { return cell_; } @@ -3422,7 +3450,7 @@ class HStoreGlobalCell: public HUnaryOperation { : HUnaryOperation(value), cell_(cell), details_(details) { - SetFlag(kChangesGlobalVars); + SetGVNFlag(kChangesGlobalVars); } Handle cell() const { return cell_; } @@ -3513,7 +3541,7 @@ class HLoadContextSlot: public HUnaryOperation { } set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnContextSlots); + SetGVNFlag(kDependsOnContextSlots); } int slot_index() const { return slot_index_; } @@ -3566,7 +3594,7 @@ class HStoreContextSlot: public HTemplateInstruction<2> { : slot_index_(slot_index), mode_(mode) { SetOperandAt(0, context); SetOperandAt(1, value); - SetFlag(kChangesContextSlots); + SetGVNFlag(kChangesContextSlots); } HValue* context() { return OperandAt(0); } @@ -3608,11 +3636,11 @@ class HLoadNamedField: public HUnaryOperation { offset_(offset) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnMaps); if (is_in_object) { - SetFlag(kDependsOnInobjectFields); + SetGVNFlag(kDependsOnInobjectFields); } else { - SetFlag(kDependsOnBackingStoreFields); + SetGVNFlag(kDependsOnBackingStoreFields); } } @@ -3706,7 +3734,7 @@ class HLoadFunctionPrototype: public HUnaryOperation { : HUnaryOperation(function) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnCalls); + SetGVNFlag(kDependsOnCalls); } HValue* function() { return OperandAt(0); } @@ -3728,7 +3756,7 @@ class HLoadKeyedFastElement: public HTemplateInstruction<2> { SetOperandAt(0, obj); SetOperandAt(1, key); set_representation(Representation::Tagged()); - SetFlag(kDependsOnArrayElements); + SetGVNFlag(kDependsOnArrayElements); SetFlag(kUseGVN); } @@ -3759,7 +3787,7 @@ class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> { SetOperandAt(0, elements); SetOperandAt(1, key); set_representation(Representation::Double()); - SetFlag(kDependsOnDoubleArrayElements); + SetGVNFlag(kDependsOnDoubleArrayElements); SetFlag(kUseGVN); } @@ -3796,9 +3824,9 @@ class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> { } else { set_representation(Representation::Integer32()); } - SetFlag(kDependsOnSpecializedArrayElements); + SetGVNFlag(kDependsOnSpecializedArrayElements); // Native code could change the specialized array. - SetFlag(kDependsOnCalls); + SetGVNFlag(kDependsOnCalls); SetFlag(kUseGVN); } @@ -3868,9 +3896,9 @@ class HStoreNamedField: public HTemplateInstruction<2> { SetOperandAt(0, obj); SetOperandAt(1, val); if (is_in_object_) { - SetFlag(kChangesInobjectFields); + SetGVNFlag(kChangesInobjectFields); } else { - SetFlag(kChangesBackingStoreFields); + SetGVNFlag(kChangesBackingStoreFields); } } @@ -3945,7 +3973,7 @@ class HStoreKeyedFastElement: public HTemplateInstruction<3> { SetOperandAt(0, obj); SetOperandAt(1, key); SetOperandAt(2, val); - SetFlag(kChangesArrayElements); + SetGVNFlag(kChangesArrayElements); } virtual Representation RequiredInputRepresentation(int index) { @@ -3987,7 +4015,7 @@ class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> { SetOperandAt(0, elements); SetOperandAt(1, key); SetOperandAt(2, val); - SetFlag(kChangesDoubleArrayElements); + SetGVNFlag(kChangesDoubleArrayElements); } virtual Representation RequiredInputRepresentation(int index) { @@ -4021,7 +4049,7 @@ class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> { HValue* val, ElementsKind elements_kind) : elements_kind_(elements_kind) { - SetFlag(kChangesSpecializedArrayElements); + SetGVNFlag(kChangesSpecializedArrayElements); SetOperandAt(0, external_elements); SetOperandAt(1, key); SetOperandAt(2, val); @@ -4099,7 +4127,7 @@ class HTransitionElementsKind: public HTemplateInstruction<1> { transitioned_map_(transitioned_map) { SetOperandAt(0, object); SetFlag(kUseGVN); - SetFlag(kChangesElementsKind); + SetGVNFlag(kChangesElementsKind); set_representation(Representation::Tagged()); } @@ -4134,7 +4162,7 @@ class HStringAdd: public HBinaryOperation { : HBinaryOperation(context, left, right) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnMaps); } virtual Representation RequiredInputRepresentation(int index) { @@ -4160,7 +4188,7 @@ class HStringCharCodeAt: public HTemplateInstruction<3> { SetOperandAt(2, index); set_representation(Representation::Integer32()); SetFlag(kUseGVN); - SetFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnMaps); } virtual Representation RequiredInputRepresentation(int index) { @@ -4215,7 +4243,7 @@ class HStringLength: public HUnaryOperation { explicit HStringLength(HValue* string) : HUnaryOperation(string) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); - SetFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnMaps); } virtual Representation RequiredInputRepresentation(int index) { diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 47dcc80536..1a63f1e7aa 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -1110,10 +1110,10 @@ HValueMap::HValueMap(Zone* zone, const HValueMap* other) } -void HValueMap::Kill(int flags) { - int depends_flags = HValue::ConvertChangesToDependsFlags(flags); - if ((present_flags_ & depends_flags) == 0) return; - present_flags_ = 0; +void HValueMap::Kill(GVNFlagSet flags) { + GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(flags); + if (!present_flags_.ContainsAnyOf(depends_flags)) return; + present_flags_.RemoveAll(); for (int i = 0; i < array_size_; ++i) { HValue* value = array_[i].value; if (value != NULL) { @@ -1122,7 +1122,8 @@ void HValueMap::Kill(int flags) { int next; for (int current = array_[i].next; current != kNil; current = next) { next = lists_[current].next; - if ((lists_[current].value->flags() & depends_flags) != 0) { + HValue* value = lists_[current].value; + if (value->gvn_flags().ContainsAnyOf(depends_flags)) { // Drop it. count_--; lists_[current].next = free_list_head_; @@ -1131,13 +1132,14 @@ void HValueMap::Kill(int flags) { // Keep it. lists_[current].next = kept; kept = current; - present_flags_ |= lists_[current].value->flags(); + present_flags_.Add(value->gvn_flags()); } } array_[i].next = kept; // Now possibly drop directly indexed element. - if ((array_[i].value->flags() & depends_flags) != 0) { // Drop it. + value = array_[i].value; + if (value->gvn_flags().ContainsAnyOf(depends_flags)) { // Drop it. count_--; int head = array_[i].next; if (head == kNil) { @@ -1149,7 +1151,7 @@ void HValueMap::Kill(int flags) { free_list_head_ = head; } } else { - present_flags_ |= array_[i].value->flags(); // Keep it. + present_flags_.Add(value->gvn_flags()); // Keep it. } } } @@ -1356,8 +1358,8 @@ class HGlobalValueNumberer BASE_EMBEDDED { loop_side_effects_(graph->blocks()->length()), visited_on_paths_(graph->zone(), graph->blocks()->length()) { ASSERT(info->isolate()->heap()->allow_allocation(false)); - block_side_effects_.AddBlock(0, graph_->blocks()->length()); - loop_side_effects_.AddBlock(0, graph_->blocks()->length()); + block_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length()); + loop_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length()); } ~HGlobalValueNumberer() { ASSERT(!info_->isolate()->heap()->allow_allocation(true)); @@ -1367,14 +1369,15 @@ class HGlobalValueNumberer BASE_EMBEDDED { bool Analyze(); private: - int CollectSideEffectsOnPathsToDominatedBlock(HBasicBlock* dominator, - HBasicBlock* dominated); + GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock( + HBasicBlock* dominator, + HBasicBlock* dominated); void AnalyzeBlock(HBasicBlock* block, HValueMap* map); void ComputeBlockSideEffects(); void LoopInvariantCodeMotion(); void ProcessLoopBlock(HBasicBlock* block, HBasicBlock* before_loop, - int loop_kills); + GVNFlagSet loop_kills); bool AllowCodeMotion(); bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); @@ -1387,10 +1390,10 @@ class HGlobalValueNumberer BASE_EMBEDDED { bool removed_side_effects_; // A map of block IDs to their side effects. - ZoneList block_side_effects_; + ZoneList block_side_effects_; // A map of loop header block IDs to their loop's side effects. - ZoneList loop_side_effects_; + ZoneList loop_side_effects_; // Used when collecting side effects on paths from dominator to // dominated. @@ -1415,23 +1418,24 @@ void HGlobalValueNumberer::ComputeBlockSideEffects() { HBasicBlock* block = graph_->blocks()->at(i); HInstruction* instr = block->first(); int id = block->block_id(); - int side_effects = 0; + GVNFlagSet side_effects; while (instr != NULL) { - side_effects |= instr->ChangesFlags(); + side_effects.Add(instr->ChangesFlags()); instr = instr->next(); } - block_side_effects_[id] |= side_effects; + block_side_effects_[id].Add(side_effects); // Loop headers are part of their loop. if (block->IsLoopHeader()) { - loop_side_effects_[id] |= side_effects; + loop_side_effects_[id].Add(side_effects); } // Propagate loop side effects upwards. if (block->HasParentLoopHeader()) { int header_id = block->parent_loop_header()->block_id(); - loop_side_effects_[header_id] |= - block->IsLoopHeader() ? loop_side_effects_[id] : side_effects; + loop_side_effects_[header_id].Add(block->IsLoopHeader() + ? loop_side_effects_[id] + : side_effects); } } } @@ -1441,10 +1445,10 @@ void HGlobalValueNumberer::LoopInvariantCodeMotion() { for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { HBasicBlock* block = graph_->blocks()->at(i); if (block->IsLoopHeader()) { - int side_effects = loop_side_effects_[block->block_id()]; + GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n", block->block_id(), - side_effects); + side_effects.ToIntegral()); HBasicBlock* last = block->loop_information()->GetLastBackEdge(); for (int j = block->block_id(); j <= last->block_id(); ++j) { @@ -1457,17 +1461,17 @@ void HGlobalValueNumberer::LoopInvariantCodeMotion() { void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block, HBasicBlock* loop_header, - int loop_kills) { + GVNFlagSet loop_kills) { HBasicBlock* pre_header = loop_header->predecessors()->at(0); - int depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); + GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n", block->block_id(), - depends_flags); + depends_flags.ToIntegral()); HInstruction* instr = block->first(); while (instr != NULL) { HInstruction* next = instr->next(); if (instr->CheckFlag(HValue::kUseGVN) && - (instr->flags() & depends_flags) == 0) { + !instr->gvn_flags().ContainsAnyOf(depends_flags)) { TraceGVN("Checking instruction %d (%s)\n", instr->id(), instr->Mnemonic()); @@ -1503,20 +1507,20 @@ bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, } -int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( +GVNFlagSet HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( HBasicBlock* dominator, HBasicBlock* dominated) { - int side_effects = 0; + GVNFlagSet side_effects; for (int i = 0; i < dominated->predecessors()->length(); ++i) { HBasicBlock* block = dominated->predecessors()->at(i); if (dominator->block_id() < block->block_id() && block->block_id() < dominated->block_id() && visited_on_paths_.Add(block->block_id())) { - side_effects |= block_side_effects_[block->block_id()]; + side_effects.Add(block_side_effects_[block->block_id()]); if (block->IsLoopHeader()) { - side_effects |= loop_side_effects_[block->block_id()]; + side_effects.Add(loop_side_effects_[block->block_id()]); } - side_effects |= CollectSideEffectsOnPathsToDominatedBlock( - dominator, block); + side_effects.Add(CollectSideEffectsOnPathsToDominatedBlock( + dominator, block)); } } return side_effects; @@ -1537,8 +1541,8 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { HInstruction* instr = block->first(); while (instr != NULL) { HInstruction* next = instr->next(); - int flags = instr->ChangesFlags(); - if (flags != 0) { + GVNFlagSet flags = instr->ChangesFlags(); + if (!flags.IsEmpty()) { // Clear all instructions in the map that are affected by side effects. map->Kill(flags); TraceGVN("Instruction %d kills\n", instr->id()); @@ -3203,7 +3207,7 @@ HGraphBuilder::GlobalPropertyAccess HGraphBuilder::LookupGlobalProperty( } Handle global(info()->global_object()); global->Lookup(*var->name(), lookup); - if (!lookup->IsProperty() || + if (!lookup->IsFound() || lookup->type() != NORMAL || (is_store && lookup->IsReadOnly()) || lookup->holder() != *global) { @@ -3548,7 +3552,7 @@ static bool ComputeStoredField(Handle type, Handle name, LookupResult* lookup) { type->LookupInDescriptors(NULL, *name, lookup); - if (!lookup->IsPropertyOrTransition()) return false; + if (!lookup->IsFound()) return false; if (lookup->type() == FIELD) return true; return (lookup->type() == MAP_TRANSITION) && (type->unused_property_fields() > 0); @@ -3597,7 +3601,7 @@ HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object, instr->set_transition(transition); // TODO(fschneider): Record the new map type of the object in the IR to // enable elimination of redundant checks after the transition store. - instr->SetFlag(HValue::kChangesMaps); + instr->SetGVNFlag(kChangesMaps); } return instr; } @@ -4155,13 +4159,13 @@ HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, Handle name) { LookupResult lookup(isolate()); map->LookupInDescriptors(NULL, *name, &lookup); - if (lookup.IsProperty() && lookup.type() == FIELD) { + if (lookup.IsFound() && lookup.type() == FIELD) { return BuildLoadNamedField(obj, expr, map, &lookup, true); - } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { + } else if (lookup.IsFound() && lookup.type() == CONSTANT_FUNCTION) { AddInstruction(new(zone()) HCheckNonSmi(obj)); AddInstruction(new(zone()) HCheckMap(obj, map, NULL, ALLOW_ELEMENT_TRANSITION_MAPS)); @@ -4266,14 +4270,6 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); bool fast_smi_only_elements = map->has_fast_smi_only_elements(); bool fast_elements = map->has_fast_elements(); - bool fast_double_elements = map->has_fast_double_elements(); - if (!fast_smi_only_elements && - !fast_elements && - !fast_double_elements && - !map->has_external_array_elements()) { - return is_store ? BuildStoreKeyedGeneric(object, key, val) - : BuildLoadKeyedGeneric(object, key); - } HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); if (is_store && (fast_elements || fast_smi_only_elements)) { AddInstruction(new(zone()) HCheckMap( @@ -4290,7 +4286,9 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, return BuildExternalArrayElementAccess(external_elements, checked_key, val, map->elements_kind(), is_store); } - ASSERT(fast_smi_only_elements || fast_elements || fast_double_elements); + ASSERT(fast_smi_only_elements || + fast_elements || + map->has_fast_double_elements()); if (map->instance_type() == JS_ARRAY_TYPE) { length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck)); } else { @@ -4362,8 +4360,14 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, // If only one map is left after transitioning, handle this case // monomorphically. if (num_untransitionable_maps == 1) { - HInstruction* instr = AddInstruction(BuildMonomorphicElementAccess( - object, key, val, untransitionable_map, is_store)); + HInstruction* instr = NULL; + if (untransitionable_map->has_slow_elements_kind()) { + instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) + : BuildLoadKeyedGeneric(object, key)); + } else { + instr = AddInstruction(BuildMonomorphicElementAccess( + object, key, val, untransitionable_map, is_store)); + } *has_side_effects |= instr->HasObservableSideEffects(); instr->set_position(position); return is_store ? NULL : instr; @@ -4499,8 +4503,13 @@ HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj, HInstruction* instr = NULL; if (expr->IsMonomorphic()) { Handle map = expr->GetMonomorphicReceiverType(); - AddInstruction(new(zone()) HCheckNonSmi(obj)); - instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store); + if (map->has_slow_elements_kind()) { + instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) + : BuildLoadKeyedGeneric(obj, key); + } else { + AddInstruction(new(zone()) HCheckNonSmi(obj)); + instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store); + } } else if (expr->GetReceiverTypes() != NULL && !expr->GetReceiverTypes()->is_empty()) { return HandlePolymorphicElementAccess( @@ -6167,6 +6176,15 @@ static bool IsLiteralCompareNil(HValue* left, } +static bool IsLiteralCompareBool(HValue* left, + Token::Value op, + HValue* right) { + return op == Token::EQ_STRICT && + ((left->IsConstant() && HConstant::cast(left)->handle()->IsBoolean()) || + (right->IsConstant() && HConstant::cast(right)->handle()->IsBoolean())); +} + + void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); @@ -6214,6 +6232,12 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { if (IsLiteralCompareNil(left, op, right, f->null_value(), &sub_expr)) { return HandleLiteralCompareNil(expr, sub_expr, kNullValue); } + if (IsLiteralCompareBool(left, op, right)) { + HCompareObjectEqAndBranch* result = + new(zone()) HCompareObjectEqAndBranch(left, right); + result->set_position(expr->position()); + return ast_context()->ReturnControl(result, expr->id()); + } if (op == Token::INSTANCEOF) { // Check to see if the rhs of the instanceof is a global function not @@ -6229,7 +6253,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { Handle global(info()->global_object()); LookupResult lookup(isolate()); global->Lookup(*name, &lookup); - if (lookup.IsProperty() && + if (lookup.IsFound() && lookup.type() == NORMAL && lookup.GetValue()->IsJSFunction()) { Handle candidate(JSFunction::cast(lookup.GetValue())); diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index 9705859066..b77e97583a 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -1056,10 +1056,10 @@ class HValueMap: public ZoneObject { Resize(kInitialSize); } - void Kill(int flags); + void Kill(GVNFlagSet flags); void Add(HValue* value) { - present_flags_ |= value->flags(); + present_flags_.Add(value->gvn_flags()); Insert(value); } @@ -1092,7 +1092,8 @@ class HValueMap: public ZoneObject { int array_size_; int lists_size_; int count_; // The number of values stored in the HValueMap. - int present_flags_; // All flags that are in any value in the HValueMap. + GVNFlagSet present_flags_; // All flags that are in any value in the + // HValueMap. HValueMapListElement* array_; // Primary store - contains the first value // with a given hash. Colliding elements are stored in linked lists. HValueMapListElement* lists_; // The linked lists containing hash collisions. diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index b654390c2b..eded335e7d 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -749,7 +749,7 @@ static void IntegerConvert(MacroAssembler* masm, // Exponent word in scratch, exponent part of exponent word in scratch2. // Zero in ecx. // We know the exponent is smaller than 30 (biased). If it is less than - // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie + // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e. // it rounds to zero. const uint32_t zero_exponent = (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; @@ -3723,7 +3723,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { kShortExternalStringMask); STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); __ j(zero, &seq_two_byte_string, Label::kNear); - // Any other flat string must be a flat ascii string. None of the following + // Any other flat string must be a flat ASCII string. None of the following // string type tests will succeed if subject is not a string or a short // external string. __ and_(ebx, Immediate(kIsNotStringMask | @@ -3772,16 +3772,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { kStringRepresentationMask | kStringEncodingMask); STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); __ j(zero, &seq_two_byte_string, Label::kNear); - // Any other flat string must be sequential ascii or external. + // Any other flat string must be sequential ASCII or external. __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), kStringRepresentationMask); __ j(not_zero, &external_string); __ bind(&seq_ascii_string); - // eax: subject string (flat ascii) + // eax: subject string (flat ASCII) // ecx: RegExp data (FixedArray) __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset)); - __ Set(ecx, Immediate(1)); // Type is ascii. + __ Set(ecx, Immediate(1)); // Type is ASCII. __ jmp(&check_code, Label::kNear); __ bind(&seq_two_byte_string); @@ -3798,7 +3798,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // eax: subject string // edx: code - // ecx: encoding of subject string (1 if ascii, 0 if two_byte); + // ecx: encoding of subject string (1 if ASCII, 0 if two_byte); // Load used arguments before starting to push arguments for call to native // RegExp code to avoid handling changing stack height. __ mov(ebx, Operand(esp, kPreviousIndexOffset)); @@ -3807,7 +3807,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // eax: subject string // ebx: previous index // edx: code - // ecx: encoding of subject string (1 if ascii 0 if two_byte); + // ecx: encoding of subject string (1 if ASCII 0 if two_byte); // All checks done. Now push arguments for native regexp code. Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->regexp_entry_native(), 1); @@ -3847,7 +3847,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // esi: original subject string // eax: underlying subject string // ebx: previous index - // ecx: encoding of subject string (1 if ascii 0 if two_byte); + // ecx: encoding of subject string (1 if ASCII 0 if two_byte); // edx: code // Argument 4: End of string data // Argument 3: Start of string data @@ -4475,7 +4475,7 @@ void CompareStub::Generate(MacroAssembler* masm) { __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &check_unequal_objects); - // Inline comparison of ascii strings. + // Inline comparison of ASCII strings. if (cc_ == equal) { StringCompareStub::GenerateFlatAsciiStringEquals(masm, edx, @@ -5428,7 +5428,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); STATIC_ASSERT(kSmiShiftSize == 0); - // At this point code register contains smi tagged ascii char code. + // At this point code register contains smi tagged ASCII char code. __ mov(result_, FieldOperand(result_, code_, times_half_pointer_size, FixedArray::kHeaderSize)); @@ -5548,7 +5548,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ cmp(ebx, Immediate(Smi::FromInt(2))); __ j(not_equal, &longer_than_two); - // Check that both strings are non-external ascii strings. + // Check that both strings are non-external ASCII strings. __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime); // Get the two characters forming the new string. @@ -5585,11 +5585,11 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ bind(&longer_than_two); // Check if resulting string will be flat. - __ cmp(ebx, Immediate(Smi::FromInt(String::kMinNonFlatLength))); + __ cmp(ebx, Immediate(Smi::FromInt(ConsString::kMinLength))); __ j(below, &string_add_flat_result); // If result is not supposed to be flat allocate a cons string object. If both - // strings are ascii the result is an ascii cons string. + // strings are ASCII the result is an ASCII cons string. Label non_ascii, allocated, ascii_data; __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); @@ -5601,7 +5601,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ test(ecx, Immediate(kStringEncodingMask)); __ j(zero, &non_ascii); __ bind(&ascii_data); - // Allocate an acsii cons string. + // Allocate an ASCII cons string. __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime); __ bind(&allocated); // Fill the fields of the cons string. @@ -5616,7 +5616,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ ret(2 * kPointerSize); __ bind(&non_ascii); // At least one of the strings is two-byte. Check whether it happens - // to contain only ascii characters. + // to contain only ASCII characters. // ecx: first instance type AND second instance type. // edi: second instance type. __ test(ecx, Immediate(kAsciiDataHintMask)); @@ -5633,7 +5633,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ jmp(&allocated); // We cannot encounter sliced strings or cons strings here since: - STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); + STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); // Handle creating a flat result from either external or sequential strings. // Locate the first characters' locations. // eax: first string @@ -5691,7 +5691,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ test_b(edi, kStringEncodingMask); __ j(zero, &non_ascii_string_add_flat_result); - // Both strings are ascii strings. + // Both strings are ASCII strings. // ebx: length of resulting flat string as a smi __ SmiUntag(ebx); __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); @@ -6001,7 +6001,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, __ push(mask); Register temp = mask; - // Check that the candidate is a non-external ascii string. + // Check that the candidate is a non-external ASCII string. __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); __ JumpIfInstanceTypeIsNotSequentialAscii( @@ -6042,6 +6042,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, __ mov(scratch, Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); + __ SmiUntag(scratch); __ add(scratch, character); __ mov(hash, scratch); __ shl(scratch, 10); @@ -6280,7 +6281,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ test_b(ebx, kStringEncodingMask); __ j(zero, &two_byte_sequential); - // Sequential ascii string. Allocate the result. + // Sequential ASCII string. Allocate the result. __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime_drop_two); // eax: result string @@ -6493,10 +6494,10 @@ void StringCompareStub::Generate(MacroAssembler* masm) { __ bind(¬_same); - // Check that both objects are sequential ascii strings. + // Check that both objects are sequential ASCII strings. __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); - // Compare flat ascii strings. + // Compare flat ASCII strings. // Drop arguments from the stack. __ pop(ecx); __ add(esp, Immediate(2 * kPointerSize)); diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index 4f3274436a..ede810c7b7 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -106,7 +106,7 @@ class JumpPatchSite BASE_EMBEDDED { // formal parameter count expected by the function. // // The live registers are: -// o edi: the JS function object being called (ie, ourselves) +// o edi: the JS function object being called (i.e. ourselves) // o esi: our context // o ebp: our caller's frame pointer // o esp: stack pointer (pointing to return address) @@ -227,7 +227,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); __ push(edx); __ SafePush(Immediate(Smi::FromInt(num_parameters))); - // Arguments to ArgumentsAccessStub and/or New...: + // Arguments to ArgumentsAccessStub: // function, receiver address, parameter count. // The stub will rewrite receiver and parameter count if the previous // stack frame was an arguments adapter frame. @@ -3571,7 +3571,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // One-character separator case __ bind(&one_char_separator); - // Replace separator with its ascii character value. + // Replace separator with its ASCII character value. __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize)); __ mov_b(separator_operand, scratch); diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc index 82bb02a318..bb1d678e0b 100644 --- a/deps/v8/src/ia32/ic-ia32.cc +++ b/deps/v8/src/ia32/ic-ia32.cc @@ -473,7 +473,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { Counters* counters = isolate->counters(); __ IncrementCounter(counters->keyed_load_generic_smi(), 1); __ ret(0); - __ bind(&check_number_dictionary); __ mov(ebx, eax); __ SmiUntag(ebx); @@ -535,15 +534,25 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ mov(edi, FieldOperand(eax, String::kHashFieldOffset)); __ shr(edi, String::kHashShift); __ xor_(ecx, edi); - __ and_(ecx, KeyedLookupCache::kCapacityMask); + __ and_(ecx, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); // Load the key (consisting of map and symbol) from the cache and // check for match. + Label try_second_entry, hit_on_first_entry, load_in_object_property; ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys(masm->isolate()); __ mov(edi, ecx); __ shl(edi, kPointerSizeLog2 + 1); __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); + __ j(not_equal, &try_second_entry); + __ add(edi, Immediate(kPointerSize)); + __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys)); + __ j(equal, &hit_on_first_entry); + + __ bind(&try_second_entry); + __ lea(edi, Operand(ecx, 1)); + __ shl(edi, kPointerSizeLog2 + 1); + __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); __ j(not_equal, &slow); __ add(edi, Immediate(kPointerSize)); __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys)); @@ -556,6 +565,18 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // ecx : lookup cache index ExternalReference cache_field_offsets = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate()); + + // Hit on second entry. + __ add(ecx, Immediate(1)); + __ mov(edi, + Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets)); + __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); + __ sub(edi, ecx); + __ j(above_equal, &property_array_property); + __ jmp(&load_in_object_property); + + // Hit on first entry. + __ bind(&hit_on_first_entry); __ mov(edi, Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets)); __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); @@ -563,6 +584,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ j(above_equal, &property_array_property); // Load in-object property. + __ bind(&load_in_object_property); __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); __ add(ecx, edi); __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0)); diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 8d412fdb53..976b23448d 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -2216,7 +2216,7 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, Handle name) { LookupResult lookup(isolate()); type->LookupInDescriptors(NULL, *name, &lookup); - ASSERT(lookup.IsProperty() && + ASSERT(lookup.IsFound() && (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); if (lookup.type() == FIELD) { int index = lookup.GetLocalFieldIndexFromMap(*type); @@ -2701,41 +2701,53 @@ void LCodeGen::CallKnownFunction(Handle function, int arity, LInstruction* instr, CallKind call_kind) { - // Change context if needed. - bool change_context = - (info()->closure()->context() != function->context()) || - scope()->contains_with() || - (scope()->num_heap_slots() > 0); - if (change_context) { - __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); - } else { - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - } - - // Set eax to arguments count if adaption is not needed. Assumes that eax - // is available to write to at this point. - if (!function->NeedsArgumentsAdaption()) { - __ mov(eax, arity); - } + bool can_invoke_directly = !function->NeedsArgumentsAdaption() || + function->shared()->formal_parameter_count() == arity; LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); - // Invoke function. - __ SetCallKind(ecx, call_kind); - if (*function == *info()->closure()) { - __ CallSelf(); + if (can_invoke_directly) { + __ LoadHeapObject(edi, function); + + // Change context if needed. + bool change_context = + (info()->closure()->context() != function->context()) || + scope()->contains_with() || + (scope()->num_heap_slots() > 0); + + if (change_context) { + __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); + } else { + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + } + + // Set eax to arguments count if adaption is not needed. Assumes that eax + // is available to write to at this point. + if (!function->NeedsArgumentsAdaption()) { + __ mov(eax, arity); + } + + // Invoke function directly. + __ SetCallKind(ecx, call_kind); + if (*function == *info()->closure()) { + __ CallSelf(); + } else { + __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset)); + } + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); } else { - __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset)); + // We need to adapt arguments. + SafepointGenerator generator( + this, pointers, Safepoint::kLazyDeopt); + ParameterCount count(arity); + __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind); } - - RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); } void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { ASSERT(ToRegister(instr->result()).is(eax)); - __ LoadHeapObject(edi, instr->function()); CallKnownFunction(instr->function(), instr->arity(), instr, @@ -3190,7 +3202,6 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { ASSERT(ToRegister(instr->result()).is(eax)); - __ LoadHeapObject(edi, instr->target()); CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); } diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 43f265cf01..d0d9e19c90 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -1387,7 +1387,7 @@ void MacroAssembler::AllocateAsciiString(Register result, add(scratch1, Immediate(kObjectAlignmentMask)); and_(scratch1, Immediate(~kObjectAlignmentMask)); - // Allocate ascii string in new space. + // Allocate ASCII string in new space. AllocateInNewSpace(SeqAsciiString::kHeaderSize, times_1, scratch1, @@ -1415,7 +1415,7 @@ void MacroAssembler::AllocateAsciiString(Register result, Label* gc_required) { ASSERT(length > 0); - // Allocate ascii string in new space. + // Allocate ASCII string in new space. AllocateInNewSpace(SeqAsciiString::SizeFor(length), result, scratch1, @@ -1933,11 +1933,13 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, Handle code_constant, const Operand& code_operand, Label* done, + bool* definitely_mismatches, InvokeFlag flag, Label::Distance done_near, const CallWrapper& call_wrapper, CallKind call_kind) { bool definitely_matches = false; + *definitely_mismatches = false; Label invoke; if (expected.is_immediate()) { ASSERT(actual.is_immediate()); @@ -1953,6 +1955,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, // arguments. definitely_matches = true; } else { + *definitely_mismatches = true; mov(ebx, expected.immediate()); } } @@ -1990,7 +1993,9 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, SetCallKind(ecx, call_kind); call(adaptor, RelocInfo::CODE_TARGET); call_wrapper.AfterCall(); - jmp(done, done_near); + if (!*definitely_mismatches) { + jmp(done, done_near); + } } else { SetCallKind(ecx, call_kind); jmp(adaptor, RelocInfo::CODE_TARGET); @@ -2010,20 +2015,23 @@ void MacroAssembler::InvokeCode(const Operand& code, ASSERT(flag == JUMP_FUNCTION || has_frame()); Label done; + bool definitely_mismatches = false; InvokePrologue(expected, actual, Handle::null(), code, - &done, flag, Label::kNear, call_wrapper, - call_kind); - if (flag == CALL_FUNCTION) { - call_wrapper.BeforeCall(CallSize(code)); - SetCallKind(ecx, call_kind); - call(code); - call_wrapper.AfterCall(); - } else { - ASSERT(flag == JUMP_FUNCTION); - SetCallKind(ecx, call_kind); - jmp(code); + &done, &definitely_mismatches, flag, Label::kNear, + call_wrapper, call_kind); + if (!definitely_mismatches) { + if (flag == CALL_FUNCTION) { + call_wrapper.BeforeCall(CallSize(code)); + SetCallKind(ecx, call_kind); + call(code); + call_wrapper.AfterCall(); + } else { + ASSERT(flag == JUMP_FUNCTION); + SetCallKind(ecx, call_kind); + jmp(code); + } + bind(&done); } - bind(&done); } @@ -2039,19 +2047,22 @@ void MacroAssembler::InvokeCode(Handle code, Label done; Operand dummy(eax, 0); - InvokePrologue(expected, actual, code, dummy, &done, flag, Label::kNear, - call_wrapper, call_kind); - if (flag == CALL_FUNCTION) { - call_wrapper.BeforeCall(CallSize(code, rmode)); - SetCallKind(ecx, call_kind); - call(code, rmode); - call_wrapper.AfterCall(); - } else { - ASSERT(flag == JUMP_FUNCTION); - SetCallKind(ecx, call_kind); - jmp(code, rmode); + bool definitely_mismatches = false; + InvokePrologue(expected, actual, code, dummy, &done, &definitely_mismatches, + flag, Label::kNear, call_wrapper, call_kind); + if (!definitely_mismatches) { + if (flag == CALL_FUNCTION) { + call_wrapper.BeforeCall(CallSize(code, rmode)); + SetCallKind(ecx, call_kind); + call(code, rmode); + call_wrapper.AfterCall(); + } else { + ASSERT(flag == JUMP_FUNCTION); + SetCallKind(ecx, call_kind); + jmp(code, rmode); + } + bind(&done); } - bind(&done); } @@ -2464,7 +2475,7 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1, movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); - // Check that both are flat ascii strings. + // Check that both are flat ASCII strings. const int kFlatAsciiStringMask = kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; const int kFlatAsciiStringTag = ASCII_STRING_TYPE; diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h index c969a6f71b..0fcb94fd10 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -368,7 +368,7 @@ class MacroAssembler: public Assembler { // Check if the map of an object is equal to a specified map and branch to // label if not. Skip the smi check if not required (object is known to be a // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match - // against maps that are ElementsKind transition maps of the specificed map. + // against maps that are ElementsKind transition maps of the specified map. void CheckMap(Register obj, Handle map, Label* fail, @@ -791,7 +791,7 @@ class MacroAssembler: public Assembler { // --------------------------------------------------------------------------- // String utilities. - // Check whether the instance type represents a flat ascii string. Jump to the + // Check whether the instance type represents a flat ASCII string. Jump to the // label if not. If the instance type can be scratched specify same register // for both instance type and scratch. void JumpIfInstanceTypeIsNotSequentialAscii(Register instance_type, @@ -827,6 +827,7 @@ class MacroAssembler: public Assembler { Handle code_constant, const Operand& code_operand, Label* done, + bool* definitely_mismatches, InvokeFlag flag, Label::Distance done_distance, const CallWrapper& call_wrapper = NullCallWrapper(), diff --git a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc index dbf01abff0..e613a06c3c 100644 --- a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc @@ -210,7 +210,7 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector str, bool check_end_of_string) { #ifdef DEBUG // If input is ASCII, don't even bother calling here if the string to - // match contains a non-ascii character. + // match contains a non-ASCII character. if (mode_ == ASCII) { ASSERT(String::IsAscii(str.start(), str.length())); } diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index 0da51c857e..f6f424176b 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -992,7 +992,7 @@ void StubCompiler::GenerateLoadCallback(Handle object, __ push(scratch3); // Restore return address. - // 3 elements array for v8::Agruments::values_, handler for name and pointer + // 3 elements array for v8::Arguments::values_, handler for name and pointer // to the values (it considered as smi in GC). const int kStackSpace = 5; const int kApiArgc = 2; @@ -1053,7 +1053,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle object, // and CALLBACKS, so inline only them, other cases may be added // later. bool compile_followup_inline = false; - if (lookup->IsProperty() && lookup->IsCacheable()) { + if (lookup->IsFound() && lookup->IsCacheable()) { if (lookup->type() == FIELD) { compile_followup_inline = true; } else if (lookup->type() == CALLBACKS && diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index 9024605da5..b084109a71 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -860,7 +860,7 @@ MaybeObject* LoadIC::Load(State state, } PropertyAttributes attr; - if (lookup.IsProperty() && + if (lookup.IsFound() && (lookup.type() == INTERCEPTOR || lookup.type() == HANDLER)) { // Get the property. Handle result = @@ -1083,7 +1083,7 @@ MaybeObject* KeyedLoadIC::Load(State state, } PropertyAttributes attr; - if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { + if (lookup.IsFound() && lookup.type() == INTERCEPTOR) { // Get the property. Handle result = Object::GetProperty(object, object, &lookup, name, &attr); @@ -1206,10 +1206,12 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup, static bool StoreICableLookup(LookupResult* lookup) { // Bail out if we didn't find a result. - if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false; + if (!lookup->IsFound() || lookup->type() == NULL_DESCRIPTOR) return false; - // If the property is read-only, we leave the IC in its current - // state. + // Bail out if inline caching is not allowed. + if (!lookup->IsCacheable()) return false; + + // If the property is read-only, we leave the IC in its current state. if (lookup->IsReadOnly()) return false; return true; diff --git a/deps/v8/src/incremental-marking-inl.h b/deps/v8/src/incremental-marking-inl.h index 7ae2c99a0d..3e3d6c43fd 100644 --- a/deps/v8/src/incremental-marking-inl.h +++ b/deps/v8/src/incremental-marking-inl.h @@ -95,7 +95,7 @@ void IncrementalMarking::BlackToGreyAndUnshift(HeapObject* obj, ASSERT(IsMarking()); Marking::BlackToGrey(mark_bit); int obj_size = obj->Size(); - MemoryChunk::IncrementLiveBytes(obj->address(), -obj_size); + MemoryChunk::IncrementLiveBytesFromGC(obj->address(), -obj_size); bytes_scanned_ -= obj_size; int64_t old_bytes_rescanned = bytes_rescanned_; bytes_rescanned_ = old_bytes_rescanned + obj_size; diff --git a/deps/v8/src/incremental-marking.cc b/deps/v8/src/incremental-marking.cc index f6d5a5963d..6248524668 100644 --- a/deps/v8/src/incremental-marking.cc +++ b/deps/v8/src/incremental-marking.cc @@ -225,8 +225,8 @@ class IncrementalMarkingMarkingVisitor : public ObjectVisitor { MarkBit mark_bit = Marking::MarkBitFrom(heap_object); if (mark_bit.data_only()) { if (incremental_marking_->MarkBlackOrKeepGrey(mark_bit)) { - MemoryChunk::IncrementLiveBytes(heap_object->address(), - heap_object->Size()); + MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), + heap_object->Size()); } } else if (Marking::IsWhite(mark_bit)) { incremental_marking_->WhiteToGreyAndPush(heap_object, mark_bit); @@ -263,8 +263,8 @@ class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor { MarkBit mark_bit = Marking::MarkBitFrom(heap_object); if (mark_bit.data_only()) { if (incremental_marking_->MarkBlackOrKeepGrey(mark_bit)) { - MemoryChunk::IncrementLiveBytes(heap_object->address(), - heap_object->Size()); + MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), + heap_object->Size()); } } else { if (Marking::IsWhite(mark_bit)) { @@ -491,8 +491,8 @@ static void MarkObjectGreyDoNotEnqueue(Object* obj) { HeapObject* heap_obj = HeapObject::cast(obj); MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::cast(obj)); if (Marking::IsBlack(mark_bit)) { - MemoryChunk::IncrementLiveBytes(heap_obj->address(), - -heap_obj->Size()); + MemoryChunk::IncrementLiveBytesFromGC(heap_obj->address(), + -heap_obj->Size()); } Marking::AnyToGrey(mark_bit); } @@ -658,7 +658,7 @@ void IncrementalMarking::Hurry() { MarkBit mark_bit = Marking::MarkBitFrom(obj); ASSERT(!Marking::IsBlack(mark_bit)); Marking::MarkBlack(mark_bit); - MemoryChunk::IncrementLiveBytes(obj->address(), obj->Size()); + MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); } state_ = COMPLETE; if (FLAG_trace_incremental_marking) { @@ -671,8 +671,8 @@ void IncrementalMarking::Hurry() { if (FLAG_cleanup_code_caches_at_gc) { PolymorphicCodeCache* poly_cache = heap_->polymorphic_code_cache(); Marking::GreyToBlack(Marking::MarkBitFrom(poly_cache)); - MemoryChunk::IncrementLiveBytes(poly_cache->address(), - PolymorphicCodeCache::kSize); + MemoryChunk::IncrementLiveBytesFromGC(poly_cache->address(), + PolymorphicCodeCache::kSize); } Object* context = heap_->global_contexts_list(); @@ -685,7 +685,7 @@ void IncrementalMarking::Hurry() { MarkBit mark_bit = Marking::MarkBitFrom(cache); if (Marking::IsGrey(mark_bit)) { Marking::GreyToBlack(mark_bit); - MemoryChunk::IncrementLiveBytes(cache->address(), cache->Size()); + MemoryChunk::IncrementLiveBytesFromGC(cache->address(), cache->Size()); } } context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); @@ -819,7 +819,7 @@ void IncrementalMarking::Step(intptr_t allocated_bytes) { SLOW_ASSERT(Marking::IsGrey(obj_mark_bit) || (obj->IsFiller() && Marking::IsWhite(obj_mark_bit))); Marking::MarkBlack(obj_mark_bit); - MemoryChunk::IncrementLiveBytes(obj->address(), size); + MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size); } if (marking_deque_.IsEmpty()) MarkingComplete(); } diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 35e9e284f9..82af337d90 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -1219,7 +1219,7 @@ bool Isolate::OptionalRescheduleException(bool is_bottom_call) { ASSERT(has_pending_exception()); PropagatePendingExceptionToExternalTryCatch(); - // Allways reschedule out of memory exceptions. + // Always reschedule out of memory exceptions. if (!is_out_of_memory()) { bool is_termination_exception = pending_exception() == heap_.termination_exception(); @@ -1454,7 +1454,8 @@ Isolate::Isolate() has_installed_extensions_(false), string_tracker_(NULL), regexp_stack_(NULL), - embedder_data_(NULL) { + embedder_data_(NULL), + context_exit_happened_(false) { TRACE_ISOLATE(constructor); memset(isolate_addresses_, 0, diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h index 4e5c7dbf51..7e6807b0a9 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -258,7 +258,7 @@ class ThreadLocalTop BASE_EMBEDDED { #endif #endif // USE_SIMULATOR - Address js_entry_sp_; // the stack pointer of the bottom js entry frame + Address js_entry_sp_; // the stack pointer of the bottom JS entry frame Address external_callback_; // the external callback we're currently in StateTag current_vm_state_; @@ -485,7 +485,7 @@ class Isolate { bool IsDefaultIsolate() const { return this == default_isolate_; } // Ensures that process-wide resources and the default isolate have been - // allocated. It is only necessary to call this method in rare casses, for + // allocated. It is only necessary to call this method in rare cases, for // example if you are using V8 from within the body of a static initializer. // Safe to call multiple times. static void EnsureDefaultIsolate(); @@ -635,7 +635,7 @@ class Isolate { void* formal_count_address() { return &thread_local_top_.formal_count_; } // Returns the global object of the current context. It could be - // a builtin object, or a js global object. + // a builtin object, or a JS global object. Handle global() { return Handle(context()->global()); } @@ -1023,6 +1023,13 @@ class Isolate { thread_local_top_.top_lookup_result_ = top; } + bool context_exit_happened() { + return context_exit_happened_; + } + void set_context_exit_happened(bool context_exit_happened) { + context_exit_happened_ = context_exit_happened; + } + private: Isolate(); @@ -1064,6 +1071,7 @@ class Isolate { Isolate* previous_isolate; EntryStackItem* previous_item; + private: DISALLOW_COPY_AND_ASSIGN(EntryStackItem); }; @@ -1188,6 +1196,10 @@ class Isolate { unibrow::Mapping interp_canonicalize_mapping_; void* embedder_data_; + // The garbage collector should be a little more aggressive when it knows + // that a context was recently exited. + bool context_exit_happened_; + #if defined(V8_TARGET_ARCH_ARM) && !defined(__arm__) || \ defined(V8_TARGET_ARCH_MIPS) && !defined(__mips__) bool simulator_initialized_; diff --git a/deps/v8/src/json-parser.h b/deps/v8/src/json-parser.h index 2b7077e194..d22cd0da3a 100644 --- a/deps/v8/src/json-parser.h +++ b/deps/v8/src/json-parser.h @@ -130,7 +130,7 @@ class JsonParser BASE_EMBEDDED { // An object literal is a squiggly-braced and comma separated sequence // (possibly empty) of key/value pairs, where the key is a JSON string // literal, the value is a JSON value, and the two are separated by a colon. - // A JSON array dosn't allow numbers and identifiers as keys, like a + // A JSON array doesn't allow numbers and identifiers as keys, like a // JavaScript array. Handle ParseJsonObject(); @@ -177,7 +177,7 @@ Handle JsonParser::ParseJson(Handle source) { // Set initial position right before the string. position_ = -1; - // Advance to the first character (posibly EOS) + // Advance to the first character (possibly EOS) AdvanceSkipWhitespace(); Handle result = ParseJsonValue(); if (result.is_null() || c0_ != kEndOfString) { diff --git a/deps/v8/src/jsregexp.cc b/deps/v8/src/jsregexp.cc index 15b80d92ce..18b86bafee 100644 --- a/deps/v8/src/jsregexp.cc +++ b/deps/v8/src/jsregexp.cc @@ -704,7 +704,7 @@ Handle RegExpImpl::IrregexpExec(Handle jsregexp, // the virtualized backtrack stack and some register changes. When a node is // to be emitted it can flush the Trace or update it. Flushing the Trace // will emit code to bring the actual state into line with the virtual state. -// Avoiding flushing the state can postpone some work (eg updates of capture +// Avoiding flushing the state can postpone some work (e.g. updates of capture // registers). Postponing work can save time when executing the regular // expression since it may be found that the work never has to be done as a // failure to match can occur. In addition it is much faster to jump to a diff --git a/deps/v8/src/jsregexp.h b/deps/v8/src/jsregexp.h index df110d1c2a..0e0184918b 100644 --- a/deps/v8/src/jsregexp.h +++ b/deps/v8/src/jsregexp.h @@ -634,7 +634,7 @@ class RegExpNode: public ZoneObject { static const int kNodeIsTooComplexForGreedyLoops = -1; virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } Label* label() { return &label_; } - // If non-generic code is generated for a node (ie the node is not at the + // If non-generic code is generated for a node (i.e. the node is not at the // start of the trace) then it cannot be reused. This variable sets a limit // on how often we allow that to happen before we insist on starting a new // trace and generating generic code for a node that can be reused by flushing diff --git a/deps/v8/src/list.h b/deps/v8/src/list.h index 57504e075d..adddea41f0 100644 --- a/deps/v8/src/list.h +++ b/deps/v8/src/list.h @@ -67,7 +67,7 @@ class List { // Returns a reference to the element at index i. This reference is // not safe to use after operations that can change the list's - // backing store (eg, Add). + // backing store (e.g. Add). inline T& operator[](int i) const { ASSERT(0 <= i); ASSERT(i < length_); diff --git a/deps/v8/src/liveedit-debugger.js b/deps/v8/src/liveedit-debugger.js index c94a3ee602..abfb0f69c6 100644 --- a/deps/v8/src/liveedit-debugger.js +++ b/deps/v8/src/liveedit-debugger.js @@ -581,7 +581,7 @@ Debug.LiveEdit = new function() { // children of unchanged functions are ignored. function MarkChangedFunctions(code_info_tree, chunks) { - // A convenient interator over diff chunks that also translates + // A convenient iterator over diff chunks that also translates // positions from old to new in a current non-changed part of script. var chunk_it = new function() { var chunk_index = 0; diff --git a/deps/v8/src/liveobjectlist.cc b/deps/v8/src/liveobjectlist.cc index 436204e3fa..1aabc59814 100644 --- a/deps/v8/src/liveobjectlist.cc +++ b/deps/v8/src/liveobjectlist.cc @@ -462,7 +462,7 @@ static int CompactString(char* str) { char prev_ch = 0; while (*dst != '\0') { char ch = *src++; - // We will treat non-ascii chars as '?'. + // We will treat non-ASCII chars as '?'. if ((ch & 0x80) != 0) { ch = '?'; } diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py index 34b07ab235..8e9c62dbe5 100644 --- a/deps/v8/src/macros.py +++ b/deps/v8/src/macros.py @@ -26,7 +26,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Dictionary that is passed as defines for js2c.py. -# Used for defines that must be defined for all native js files. +# Used for defines that must be defined for all native JS files. const NONE = 0; const READ_ONLY = 1; diff --git a/deps/v8/src/mark-compact-inl.h b/deps/v8/src/mark-compact-inl.h index 573715e286..64faf82dad 100644 --- a/deps/v8/src/mark-compact-inl.h +++ b/deps/v8/src/mark-compact-inl.h @@ -49,11 +49,18 @@ void MarkCompactCollector::SetFlags(int flags) { } +void MarkCompactCollector::ClearCacheOnMap(Map* map) { + if (FLAG_cleanup_code_caches_at_gc) { + map->ClearCodeCache(heap()); + } +} + + void MarkCompactCollector::MarkObject(HeapObject* obj, MarkBit mark_bit) { ASSERT(Marking::MarkBitFrom(obj) == mark_bit); if (!mark_bit.Get()) { mark_bit.Set(); - MemoryChunk::IncrementLiveBytes(obj->address(), obj->Size()); + MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); ProcessNewlyMarkedObject(obj); } } @@ -63,7 +70,10 @@ void MarkCompactCollector::SetMark(HeapObject* obj, MarkBit mark_bit) { ASSERT(!mark_bit.Get()); ASSERT(Marking::MarkBitFrom(obj) == mark_bit); mark_bit.Set(); - MemoryChunk::IncrementLiveBytes(obj->address(), obj->Size()); + MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); + if (obj->IsMap()) { + ClearCacheOnMap(Map::cast(obj)); + } } diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc index 6d7fbdff2b..93614aceba 100644 --- a/deps/v8/src/mark-compact.cc +++ b/deps/v8/src/mark-compact.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -63,6 +63,7 @@ MarkCompactCollector::MarkCompactCollector() : // NOLINT compacting_(false), was_marked_incrementally_(false), collect_maps_(FLAG_collect_maps), + flush_monomorphic_ics_(false), tracer_(NULL), migration_slots_buffer_(NULL), heap_(NULL), @@ -515,6 +516,12 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) { // order which is not implemented for incremental marking. collect_maps_ = FLAG_collect_maps && !was_marked_incrementally_; + // Monomorphic ICs are preserved when possible, but need to be flushed + // when they might be keeping a Context alive, or when the heap is about + // to be serialized. + flush_monomorphic_ics_ = + heap()->isolate()->context_exit_happened() || Serializer::enabled(); + // Rather than passing the tracer around we stash it in a static member // variable. tracer_ = tracer; @@ -737,7 +744,7 @@ static inline HeapObject* ShortCircuitConsString(Object** p) { // it in place to its left substring. Return the updated value. // // Here we assume that if we change *p, we replace it with a heap object - // (ie, the left substring of a cons string is always a heap object). + // (i.e., the left substring of a cons string is always a heap object). // // The check performed is: // object->IsConsString() && !object->IsSymbol() && @@ -881,7 +888,9 @@ class StaticMarkingVisitor : public StaticVisitorBase { static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) { ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); - if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub()) { + if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub() + && (target->ic_state() == MEGAMORPHIC || + heap->mark_compact_collector()->flush_monomorphic_ics_)) { IC::Clear(rinfo->pc()); target = Code::GetCodeFromTargetAddress(rinfo->target_address()); } else { @@ -1196,7 +1205,7 @@ class StaticMarkingVisitor : public StaticVisitorBase { return; } JSRegExp* re = reinterpret_cast(object); - // Flush code or set age on both ascii and two byte code. + // Flush code or set age on both ASCII and two byte code. UpdateRegExpCodeAgeAndFlush(heap, re, true); UpdateRegExpCodeAgeAndFlush(heap, re, false); // Visit the fields of the RegExp, including the updated FixedArray. @@ -1614,9 +1623,7 @@ void MarkCompactCollector::ProcessNewlyMarkedObject(HeapObject* object) { ASSERT(HEAP->Contains(object)); if (object->IsMap()) { Map* map = Map::cast(object); - if (FLAG_cleanup_code_caches_at_gc) { - map->ClearCodeCache(heap()); - } + ClearCacheOnMap(map); // When map collection is enabled we have to mark through map's transitions // in a special way to make transition links weak. @@ -1641,8 +1648,8 @@ void MarkCompactCollector::MarkMapContents(Map* map) { MarkBit mark = Marking::MarkBitFrom(prototype_transitions); if (!mark.Get()) { mark.Set(); - MemoryChunk::IncrementLiveBytes(prototype_transitions->address(), - prototype_transitions->Size()); + MemoryChunk::IncrementLiveBytesFromGC(prototype_transitions->address(), + prototype_transitions->Size()); } Object** raw_descriptor_array_slot = @@ -1756,7 +1763,7 @@ static void DiscoverGreyObjectsWithIterator(Heap* heap, MarkBit markbit = Marking::MarkBitFrom(object); if ((object->map() != filler_map) && Marking::IsGrey(markbit)) { Marking::GreyToBlack(markbit); - MemoryChunk::IncrementLiveBytes(object->address(), object->Size()); + MemoryChunk::IncrementLiveBytesFromGC(object->address(), object->Size()); marking_deque->PushBlack(object); if (marking_deque->IsFull()) return; } @@ -1808,7 +1815,7 @@ static void DiscoverGreyObjectsOnPage(MarkingDeque* marking_deque, Page* p) { Marking::GreyToBlack(markbit); Address addr = cell_base + offset * kPointerSize; HeapObject* object = HeapObject::FromAddress(addr); - MemoryChunk::IncrementLiveBytes(object->address(), object->Size()); + MemoryChunk::IncrementLiveBytesFromGC(object->address(), object->Size()); marking_deque->PushBlack(object); if (marking_deque->IsFull()) return; offset += 2; @@ -2297,40 +2304,39 @@ void MarkCompactCollector::ClearNonLiveTransitions() { Object* prototype = prototype_transitions->get(proto_offset + i * step); Object* cached_map = prototype_transitions->get(map_offset + i * step); if (IsMarked(prototype) && IsMarked(cached_map)) { + int proto_index = proto_offset + new_number_of_transitions * step; + int map_index = map_offset + new_number_of_transitions * step; if (new_number_of_transitions != i) { prototype_transitions->set_unchecked( heap_, - proto_offset + new_number_of_transitions * step, + proto_index, prototype, UPDATE_WRITE_BARRIER); prototype_transitions->set_unchecked( heap_, - map_offset + new_number_of_transitions * step, + map_index, cached_map, SKIP_WRITE_BARRIER); } + Object** slot = + HeapObject::RawField(prototype_transitions, + FixedArray::OffsetOfElementAt(proto_index)); + RecordSlot(slot, slot, prototype); + new_number_of_transitions++; } + } - // Fill slots that became free with undefined value. - Object* undefined = heap()->undefined_value(); - for (int i = new_number_of_transitions * step; - i < number_of_transitions * step; - i++) { - // The undefined object is on a page that is never compacted and never - // in new space so it is OK to skip the write barrier. Also it's a - // root. - prototype_transitions->set_unchecked(heap_, - header + i, - undefined, - SKIP_WRITE_BARRIER); - - Object** undefined_slot = - prototype_transitions->data_start() + i; - RecordSlot(undefined_slot, undefined_slot, undefined); - } + if (new_number_of_transitions != number_of_transitions) { map->SetNumberOfProtoTransitions(new_number_of_transitions); } + // Fill slots that became free with undefined value. + for (int i = new_number_of_transitions * step; + i < number_of_transitions * step; + i++) { + prototype_transitions->set_undefined(heap_, header + i); + } + // Follow the chain of back pointers to find the prototype. Map* current = map; while (current->IsMap()) { @@ -3630,6 +3636,9 @@ void MarkCompactCollector::SweepSpace(PagedSpace* space, SweeperType sweeper) { PrintF("Sweeping 0x%" V8PRIxPTR " released page.\n", reinterpret_cast(p)); } + // Adjust unswept free bytes because releasing a page expects said + // counter to be accurate for unswept pages. + space->IncreaseUnsweptFreeBytes(p); space->ReleasePage(p); continue; } @@ -3641,7 +3650,7 @@ void MarkCompactCollector::SweepSpace(PagedSpace* space, SweeperType sweeper) { PrintF("Sweeping 0x%" V8PRIxPTR " lazily postponed.\n", reinterpret_cast(p)); } - space->MarkPageForLazySweeping(p); + space->IncreaseUnsweptFreeBytes(p); continue; } diff --git a/deps/v8/src/mark-compact.h b/deps/v8/src/mark-compact.h index e0a7d94956..85a4a3b706 100644 --- a/deps/v8/src/mark-compact.h +++ b/deps/v8/src/mark-compact.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -198,7 +198,7 @@ class MarkingDeque { ASSERT(object->IsHeapObject()); if (IsFull()) { Marking::BlackToGrey(object); - MemoryChunk::IncrementLiveBytes(object->address(), -object->Size()); + MemoryChunk::IncrementLiveBytesFromGC(object->address(), -object->Size()); SetOverflowed(); } else { array_[top_] = object; @@ -407,7 +407,7 @@ class MarkCompactCollector { // object from the forwarding address of the previous live object in the // page as input, and is updated to contain the offset to be used for the // next live object in the same page. For spaces using a different - // encoding (ie, contiguous spaces), the offset parameter is ignored. + // encoding (i.e., contiguous spaces), the offset parameter is ignored. typedef void (*EncodingFunction)(Heap* heap, HeapObject* old_object, int object_size, @@ -580,6 +580,8 @@ class MarkCompactCollector { bool collect_maps_; + bool flush_monomorphic_ics_; + // A pointer to the current stack-allocated GC tracer object during a full // collection (NULL before and after). GCTracer* tracer_; @@ -622,10 +624,16 @@ class MarkCompactCollector { void AfterMarking(); + // Marks the object black and pushes it on the marking stack. + // This is for non-incremental marking. INLINE(void MarkObject(HeapObject* obj, MarkBit mark_bit)); + // Marks the object black. This is for non-incremental marking. INLINE(void SetMark(HeapObject* obj, MarkBit mark_bit)); + // Clears the cache of ICs related to this map. + INLINE(void ClearCacheOnMap(Map* map)); + void ProcessNewlyMarkedObject(HeapObject* obj); // Creates back pointers for all map transitions, stores them in diff --git a/deps/v8/src/mips/assembler-mips-inl.h b/deps/v8/src/mips/assembler-mips-inl.h index 0788e73ef6..cc215091e3 100644 --- a/deps/v8/src/mips/assembler-mips-inl.h +++ b/deps/v8/src/mips/assembler-mips-inl.h @@ -30,7 +30,7 @@ // The original source code covered by the above license above has been // modified significantly by Google Inc. -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. #ifndef V8_MIPS_ASSEMBLER_MIPS_INL_H_ @@ -78,6 +78,16 @@ bool Operand::is_reg() const { } +int FPURegister::ToAllocationIndex(FPURegister reg) { + ASSERT(reg.code() % 2 == 0); + ASSERT(reg.code() / 2 < kNumAllocatableRegisters); + ASSERT(reg.is_valid()); + ASSERT(!reg.is(kDoubleRegZero)); + ASSERT(!reg.is(kLithiumScratchDouble)); + return (reg.code() / 2); +} + + // ----------------------------------------------------------------------------- // RelocInfo. diff --git a/deps/v8/src/mips/assembler-mips.h b/deps/v8/src/mips/assembler-mips.h index b66ea0d9f9..b1ffc45c0a 100644 --- a/deps/v8/src/mips/assembler-mips.h +++ b/deps/v8/src/mips/assembler-mips.h @@ -30,7 +30,7 @@ // The original source code covered by the above license above has been // modified significantly by Google Inc. -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. #ifndef V8_MIPS_ASSEMBLER_MIPS_H_ @@ -182,12 +182,7 @@ struct FPURegister { kNumReservedRegisters; - static int ToAllocationIndex(FPURegister reg) { - ASSERT(reg.code() % 2 == 0); - ASSERT(reg.code() / 2 < kNumAllocatableRegisters); - ASSERT(reg.is_valid()); - return (reg.code() / 2); - } + inline static int ToAllocationIndex(FPURegister reg); static FPURegister FromAllocationIndex(int index) { ASSERT(index >= 0 && index < kNumAllocatableRegisters); @@ -302,6 +297,14 @@ const FPURegister f29 = { 29 }; const FPURegister f30 = { 30 }; const FPURegister f31 = { 31 }; +// Register aliases. +// cp is assumed to be a callee saved register. +static const Register& kLithiumScratchReg = s3; // Scratch register. +static const Register& kLithiumScratchReg2 = s4; // Scratch register. +static const Register& kRootRegister = s6; // Roots array pointer. +static const Register& cp = s7; // JavaScript context pointer. +static const Register& fp = s8_fp; // Alias for fp. +static const DoubleRegister& kLithiumScratchDouble = f30; static const FPURegister& kDoubleRegZero = f28; // FPU (coprocessor 1) control registers. @@ -667,7 +670,7 @@ class Assembler : public AssemblerBase { // Never use the int16_t b(l)cond version with a branch offset // instead of using the Label* version. - // Jump targets must be in the current 256 MB-aligned region. ie 28 bits. + // Jump targets must be in the current 256 MB-aligned region. i.e. 28 bits. void j(int32_t target); void jal(int32_t target); void jalr(Register rs, Register rd = ra); diff --git a/deps/v8/src/mips/builtins-mips.cc b/deps/v8/src/mips/builtins-mips.cc index 9e108c9d1f..8461342d00 100644 --- a/deps/v8/src/mips/builtins-mips.cc +++ b/deps/v8/src/mips/builtins-mips.cc @@ -895,7 +895,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // Initialize the FixedArray. // a1: constructor - // a3: number of elements in properties array (un-tagged) + // a3: number of elements in properties array (untagged) // t4: JSObject // t5: start of next object __ LoadRoot(t6, Heap::kFixedArrayMapRootIndex); @@ -1099,7 +1099,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // ----------- S t a t e ------------- // -- a0: code entry // -- a1: function - // -- a2: reveiver_pointer + // -- a2: receiver_pointer // -- a3: argc // -- s0: argv // ----------------------------------- @@ -1121,7 +1121,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // Copy arguments to the stack in a loop. // a3: argc - // s0: argv, ie points to first arg + // s0: argv, i.e. points to first arg Label loop, entry; __ sll(t0, a3, kPointerSizeLog2); __ addu(t2, s0, t0); diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc index 57091ef60b..289e6b8107 100644 --- a/deps/v8/src/mips/code-stubs-mips.cc +++ b/deps/v8/src/mips/code-stubs-mips.cc @@ -4061,7 +4061,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // Registers: // a0: entry address // a1: function - // a2: reveiver + // a2: receiver // a3: argc // // Stack: @@ -4103,7 +4103,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // Registers: // a0: entry_address // a1: function - // a2: reveiver_pointer + // a2: receiver_pointer // a3: argc // s0: argv // @@ -4170,7 +4170,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // Registers: // a0: entry_address // a1: function - // a2: reveiver_pointer + // a2: receiver_pointer // a3: argc // s0: argv // @@ -4252,7 +4252,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { const Register inline_site = t5; const Register scratch = a2; - const int32_t kDeltaToLoadBoolResult = 4 * kPointerSize; + const int32_t kDeltaToLoadBoolResult = 5 * kPointerSize; Label slow, loop, is_instance, is_not_instance, not_js_object; @@ -4296,11 +4296,12 @@ void InstanceofStub::Generate(MacroAssembler* masm) { // Patch the (relocated) inlined map check. // The offset was stored in t0 safepoint slot. - // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal) + // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal). __ LoadFromSafepointRegisterSlot(scratch, t0); __ Subu(inline_site, ra, scratch); - // Patch the relocated value to map. - __ PatchRelocatedValue(inline_site, scratch, map); + // Get the map location in scratch and patch it. + __ GetRelocatedValue(inline_site, scratch, v1); // v1 used as scratch. + __ sw(map, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); } // Register mapping: a3 is object map and t0 is function prototype. @@ -5006,9 +5007,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { STATIC_ASSERT(kAsciiStringTag == 4); STATIC_ASSERT(kTwoByteStringTag == 0); // Find the code object based on the assumptions above. - __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ascii. + __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ASCII. __ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset)); - __ sra(a3, a0, 2); // a3 is 1 for ascii, 0 for UC16 (usyed below). + __ sra(a3, a0, 2); // a3 is 1 for ASCII, 0 for UC16 (used below). __ lw(t1, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset)); __ movz(t9, t1, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset. @@ -6033,7 +6034,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { Label result_longer_than_two; - // Check for special case of two character ascii string, in which case + // Check for special case of two character ASCII string, in which case // we do a lookup in the symbol table first. __ li(t0, 2); __ Branch(&result_longer_than_two, gt, a2, Operand(t0)); @@ -6164,7 +6165,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ And(t0, a1, Operand(kStringEncodingMask)); __ Branch(&two_byte_sequential, eq, t0, Operand(zero_reg)); - // Allocate and copy the resulting ascii string. + // Allocate and copy the resulting ASCII string. __ AllocateAsciiString(v0, a2, t0, t2, t3, &runtime); // Locate first character of substring to copy. @@ -6491,7 +6492,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ bind(&longer_than_two); // Check if resulting string will be flat. __ Branch(&string_add_flat_result, lt, t2, - Operand(String::kMinNonFlatLength)); + Operand(ConsString::kMinLength)); // Handle exceptionally long strings in the runtime system. STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); ASSERT(IsPowerOf2(String::kMaxLength + 1)); @@ -6508,7 +6509,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { } Label non_ascii, allocated, ascii_data; STATIC_ASSERT(kTwoByteStringTag == 0); - // Branch to non_ascii if either string-encoding field is zero (non-ascii). + // Branch to non_ascii if either string-encoding field is zero (non-ASCII). __ And(t4, t0, Operand(t1)); __ And(t4, t4, Operand(kStringEncodingMask)); __ Branch(&non_ascii, eq, t4, Operand(zero_reg)); @@ -6543,7 +6544,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ Branch(&allocated); // We cannot encounter sliced strings or cons strings here since: - STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); + STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); // Handle creating a flat result from either external or sequential strings. // Locate the first characters' locations. // a0: first string diff --git a/deps/v8/src/mips/constants-mips.cc b/deps/v8/src/mips/constants-mips.cc index d0a7af5c35..7d654f6d62 100644 --- a/deps/v8/src/mips/constants-mips.cc +++ b/deps/v8/src/mips/constants-mips.cc @@ -302,7 +302,7 @@ Instruction::Type Instruction::InstructionType() const { return kRegisterType; }; break; - // 16 bits Immediate type instructions. eg: addi dest, src, imm16. + // 16 bits Immediate type instructions. e.g.: addi dest, src, imm16. case REGIMM: case BEQ: case BNE: @@ -337,7 +337,7 @@ Instruction::Type Instruction::InstructionType() const { case SWC1: case SDC1: return kImmediateType; - // 26 bits immediate type instructions. eg: j imm26. + // 26 bits immediate type instructions. e.g.: j imm26. case J: case JAL: return kJumpType; diff --git a/deps/v8/src/mips/constants-mips.h b/deps/v8/src/mips/constants-mips.h index 210becb449..d62a8901f0 100644 --- a/deps/v8/src/mips/constants-mips.h +++ b/deps/v8/src/mips/constants-mips.h @@ -747,7 +747,7 @@ class Instruction { // Say if the instruction should not be used in a branch delay slot. bool IsForbiddenInBranchDelay() const; - // Say if the instruction 'links'. eg: jal, bal. + // Say if the instruction 'links'. e.g. jal, bal. bool IsLinkingInstruction() const; // Say if the instruction is a break or a trap. bool IsTrap() const; diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc index 7394077f0a..da3be4c23e 100644 --- a/deps/v8/src/mips/full-codegen-mips.cc +++ b/deps/v8/src/mips/full-codegen-mips.cc @@ -125,7 +125,7 @@ class JumpPatchSite BASE_EMBEDDED { // function. // // The live registers are: -// o a1: the JS function object being called (ie, ourselves) +// o a1: the JS function object being called (i.e. ourselves) // o cp: our context // o fp: our caller's frame pointer // o sp: stack pointer @@ -3655,7 +3655,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // One-character separator case. __ bind(&one_char_separator); - // Replace separator with its ascii character value. + // Replace separator with its ASCII character value. __ lbu(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize)); // Jump into the loop after the code that copies the separator, so the first // element is not preceded by a separator. @@ -3666,7 +3666,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // result_pos: the position to which we are currently copying characters. // element: Current array element. // elements_end: Array end. - // separator: Single separator ascii char (in lower byte). + // separator: Single separator ASCII char (in lower byte). // Copy the separator character to the result. __ sb(separator, MemOperand(result_pos)); diff --git a/deps/v8/src/mips/ic-mips.cc b/deps/v8/src/mips/ic-mips.cc index 8e78488fd1..d974f08a44 100644 --- a/deps/v8/src/mips/ic-mips.cc +++ b/deps/v8/src/mips/ic-mips.cc @@ -1033,19 +1033,26 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ lw(t0, FieldMemOperand(a0, String::kHashFieldOffset)); __ sra(at, t0, String::kHashShift); __ xor_(a3, a3, at); - __ And(a3, a3, Operand(KeyedLookupCache::kCapacityMask)); + int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask; + __ And(a3, a3, Operand(mask)); // Load the key (consisting of map and symbol) from the cache and // check for match. + Label try_second_entry, hit_on_first_entry, load_in_object_property; ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys(isolate); __ li(t0, Operand(cache_keys)); __ sll(at, a3, kPointerSizeLog2 + 1); __ addu(t0, t0, at); - __ lw(t1, MemOperand(t0)); // Move t0 to symbol. - __ Addu(t0, t0, Operand(kPointerSize)); - __ Branch(&slow, ne, a2, Operand(t1)); __ lw(t1, MemOperand(t0)); + __ Branch(&try_second_entry, ne, a2, Operand(t1)); + __ lw(t1, MemOperand(t0, kPointerSize)); + __ Branch(&hit_on_first_entry, eq, a0, Operand(t1)); + + __ bind(&try_second_entry); + __ lw(t1, MemOperand(t0, kPointerSize * 2)); + __ Branch(&slow, ne, a2, Operand(t1)); + __ lw(t1, MemOperand(t0, kPointerSize * 3)); __ Branch(&slow, ne, a0, Operand(t1)); // Get field offset. @@ -1055,6 +1062,19 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // a3 : lookup cache index ExternalReference cache_field_offsets = ExternalReference::keyed_lookup_cache_field_offsets(isolate); + + // Hit on second entry. + __ li(t0, Operand(cache_field_offsets)); + __ sll(at, a3, kPointerSizeLog2); + __ addu(at, t0, at); + __ lw(t1, MemOperand(at, kPointerSize)); + __ lbu(t2, FieldMemOperand(a2, Map::kInObjectPropertiesOffset)); + __ Subu(t1, t1, t2); + __ Branch(&property_array_property, ge, t1, Operand(zero_reg)); + __ Branch(&load_in_object_property); + + // Hit on first entry. + __ bind(&hit_on_first_entry); __ li(t0, Operand(cache_field_offsets)); __ sll(at, a3, kPointerSizeLog2); __ addu(at, t0, at); @@ -1064,6 +1084,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ Branch(&property_array_property, ge, t1, Operand(zero_reg)); // Load in-object property. + __ bind(&load_in_object_property); __ lbu(t2, FieldMemOperand(a2, Map::kInstanceSizeOffset)); __ addu(t2, t2, t1); // Index from start of object. __ Subu(a1, a1, Operand(kHeapObjectTag)); // Remove the heap tag. diff --git a/deps/v8/src/mips/lithium-codegen-mips.cc b/deps/v8/src/mips/lithium-codegen-mips.cc index de6400708f..7a230c1fac 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.cc +++ b/deps/v8/src/mips/lithium-codegen-mips.cc @@ -1862,9 +1862,8 @@ void LCodeGen::DoHasCachedArrayIndexAndBranch( } -// Branches to a label or falls through with this instance class-name adr -// returned in temp reg, available for comparison by the caller. Trashes the -// temp registers, but not the input. Only input and temp2 may alias. +// Branches to a label or falls through with the answer in flags. Trashes +// the temp registers, but not the input. void LCodeGen::EmitClassOfTest(Label* is_true, Label* is_false, Handleclass_name, @@ -1872,7 +1871,9 @@ void LCodeGen::EmitClassOfTest(Label* is_true, Register temp, Register temp2) { ASSERT(!input.is(temp)); - ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register. + ASSERT(!input.is(temp2)); + ASSERT(!temp.is(temp2)); + __ JumpIfSmi(input, is_false); if (class_name->IsEqualTo(CStrVector("Function"))) { @@ -2018,7 +2019,10 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { // We use Factory::the_hole_value() on purpose instead of loading from the // root array to force relocation to be able to later patch with // the cached map. - __ li(at, Operand(factory()->the_hole_value()), true); + Handle cell = + factory()->NewJSGlobalPropertyCell(factory()->the_hole_value()); + __ li(at, Operand(Handle(cell))); + __ lw(at, FieldMemOperand(at, JSGlobalPropertyCell::kValueOffset)); __ Branch(&cache_miss, ne, map, Operand(at)); // We use Factory::the_hole_value() on purpose instead of loading from the // root array to force relocation to be able to later patch @@ -2265,7 +2269,7 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, Handle name) { LookupResult lookup(isolate()); type->LookupInDescriptors(NULL, *name, &lookup); - ASSERT(lookup.IsProperty() && + ASSERT(lookup.IsFound() && (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); if (lookup.type() == FIELD) { int index = lookup.GetLocalFieldIndexFromMap(*type); @@ -2715,7 +2719,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { this, pointers, Safepoint::kLazyDeopt); // The number of arguments is stored in receiver which is a0, as expected // by InvokeFunction. - v8::internal::ParameterCount actual(receiver); + ParameterCount actual(receiver); __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator, CALL_AS_METHOD); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -2771,31 +2775,41 @@ void LCodeGen::CallKnownFunction(Handle function, int arity, LInstruction* instr, CallKind call_kind) { - // Change context if needed. - bool change_context = - (info()->closure()->context() != function->context()) || - scope()->contains_with() || - (scope()->num_heap_slots() > 0); - if (change_context) { - __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); - } - - // Set a0 to arguments count if adaption is not needed. Assumes that a0 - // is available to write to at this point. - if (!function->NeedsArgumentsAdaption()) { - __ li(a0, Operand(arity)); - } + bool can_invoke_directly = !function->NeedsArgumentsAdaption() || + function->shared()->formal_parameter_count() == arity; LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); - // Invoke function. - __ SetCallKind(t1, call_kind); - __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset)); - __ Call(at); + if (can_invoke_directly) { + __ LoadHeapObject(a1, function); + // Change context if needed. + bool change_context = + (info()->closure()->context() != function->context()) || + scope()->contains_with() || + (scope()->num_heap_slots() > 0); + if (change_context) { + __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); + } - // Set up deoptimization. - RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); + // Set r0 to arguments count if adaption is not needed. Assumes that r0 + // is available to write to at this point. + if (!function->NeedsArgumentsAdaption()) { + __ li(a0, Operand(arity)); + } + + // Invoke function. + __ SetCallKind(t1, call_kind); + __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset)); + __ Call(at); + + // Set up deoptimization. + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); + } else { + SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); + ParameterCount count(arity); + __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind); + } // Restore context. __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -2805,7 +2819,6 @@ void LCodeGen::CallKnownFunction(Handle function, void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { ASSERT(ToRegister(instr->result()).is(v0)); __ mov(a0, v0); - __ LoadHeapObject(a1, instr->function()); CallKnownFunction(instr->function(), instr->arity(), instr, CALL_AS_METHOD); } @@ -2884,7 +2897,7 @@ void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { __ mov(result, input); ASSERT_EQ(2, masm()->InstructionsGeneratedSince(&done)); __ subu(result, zero_reg, input); - // Overflow if result is still negative, ie 0x80000000. + // Overflow if result is still negative, i.e. 0x80000000. DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg)); __ bind(&done); } @@ -3248,7 +3261,6 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { ASSERT(ToRegister(instr->result()).is(v0)); - __ LoadHeapObject(a1, instr->target()); CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); } @@ -3816,6 +3828,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { void LCodeGen::EmitNumberUntagD(Register input_reg, DoubleRegister result_reg, bool deoptimize_on_undefined, + bool deoptimize_on_minus_zero, LEnvironment* env) { Register scratch = scratch0(); @@ -3845,6 +3858,12 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, } // Heap number to double register conversion. __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset)); + if (deoptimize_on_minus_zero) { + __ mfc1(at, result_reg.low()); + __ Branch(&done, ne, at, Operand(zero_reg)); + __ mfc1(scratch, result_reg.high()); + DeoptimizeIf(eq, env, scratch, Operand(HeapNumber::kSignMask)); + } __ Branch(&done); // Smi to double register conversion @@ -3976,6 +3995,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { EmitNumberUntagD(input_reg, result_reg, instr->hydrogen()->deoptimize_on_undefined(), + instr->hydrogen()->deoptimize_on_minus_zero(), instr->environment()); } @@ -4086,16 +4106,26 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { } +void LCodeGen::DoCheckMapCommon(Register reg, + Register scratch, + Handle map, + CompareMapMode mode, + LEnvironment* env) { + Label success; + __ CompareMapAndBranch(reg, scratch, map, &success, eq, &success, mode); + DeoptimizeIf(al, env); + __ bind(&success); +} + + void LCodeGen::DoCheckMap(LCheckMap* instr) { Register scratch = scratch0(); LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister()); Register reg = ToRegister(input); - __ lw(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); - DeoptimizeIf(ne, - instr->environment(), - scratch, - Operand(instr->hydrogen()->map())); + Handle map = instr->hydrogen()->map(); + DoCheckMapCommon(reg, scratch, map, instr->hydrogen()->mode(), + instr->environment()); } @@ -4163,11 +4193,9 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { // Check prototype maps up to the holder. while (!current_prototype.is_identical_to(holder)) { - __ lw(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset)); - DeoptimizeIf(ne, - instr->environment(), - temp2, - Operand(Handle(current_prototype->map()))); + DoCheckMapCommon(temp1, temp2, + Handle(current_prototype->map()), + ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment()); current_prototype = Handle(JSObject::cast(current_prototype->GetPrototype())); // Load next prototype object. @@ -4175,11 +4203,9 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { } // Check the holder map. - __ lw(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset)); - DeoptimizeIf(ne, - instr->environment(), - temp2, - Operand(Handle(current_prototype->map()))); + DoCheckMapCommon(temp1, temp2, + Handle(current_prototype->map()), + ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment()); } diff --git a/deps/v8/src/mips/lithium-codegen-mips.h b/deps/v8/src/mips/lithium-codegen-mips.h index 2a54681990..513992c67a 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.h +++ b/deps/v8/src/mips/lithium-codegen-mips.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -115,6 +115,9 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); + void DoCheckMapCommon(Register reg, Register scratch, Handle map, + CompareMapMode mode, LEnvironment* env); + // Parallel move support. void DoParallelMove(LParallelMove* move); void DoGap(LGap* instr); @@ -223,8 +226,8 @@ class LCodeGen BASE_EMBEDDED { Safepoint::DeoptMode mode); void DeoptimizeIf(Condition cc, LEnvironment* environment, - Register src1, - const Operand& src2); + Register src1 = zero_reg, + const Operand& src2 = Operand(zero_reg)); void AddToTranslation(Translation* translation, LOperand* op, @@ -280,6 +283,7 @@ class LCodeGen BASE_EMBEDDED { void EmitNumberUntagD(Register input, DoubleRegister result, bool deoptimize_on_undefined, + bool deoptimize_on_minus_zero, LEnvironment* env); // Emits optimized code for typeof x == "y". Modifies input register. diff --git a/deps/v8/src/mips/lithium-gap-resolver-mips.cc b/deps/v8/src/mips/lithium-gap-resolver-mips.cc index 279a95ece4..41b060debc 100644 --- a/deps/v8/src/mips/lithium-gap-resolver-mips.cc +++ b/deps/v8/src/mips/lithium-gap-resolver-mips.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -34,7 +34,6 @@ namespace v8 { namespace internal { static const Register kSavedValueRegister = kLithiumScratchReg; -static const DoubleRegister kSavedDoubleValueRegister = kLithiumScratchDouble; LGapResolver::LGapResolver(LCodeGen* owner) : cgen_(owner), @@ -175,9 +174,9 @@ void LGapResolver::BreakCycle(int index) { } else if (source->IsStackSlot()) { __ lw(kSavedValueRegister, cgen_->ToMemOperand(source)); } else if (source->IsDoubleRegister()) { - __ mov_d(kSavedDoubleValueRegister, cgen_->ToDoubleRegister(source)); + __ mov_d(kLithiumScratchDouble, cgen_->ToDoubleRegister(source)); } else if (source->IsDoubleStackSlot()) { - __ ldc1(kSavedDoubleValueRegister, cgen_->ToMemOperand(source)); + __ ldc1(kLithiumScratchDouble, cgen_->ToMemOperand(source)); } else { UNREACHABLE(); } @@ -190,16 +189,16 @@ void LGapResolver::RestoreValue() { ASSERT(in_cycle_); ASSERT(saved_destination_ != NULL); - // Spilled value is in kSavedValueRegister or kSavedDoubleValueRegister. + // Spilled value is in kSavedValueRegister or kLithiumScratchDouble. if (saved_destination_->IsRegister()) { __ mov(cgen_->ToRegister(saved_destination_), kSavedValueRegister); } else if (saved_destination_->IsStackSlot()) { __ sw(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_)); } else if (saved_destination_->IsDoubleRegister()) { __ mov_d(cgen_->ToDoubleRegister(saved_destination_), - kSavedDoubleValueRegister); + kLithiumScratchDouble); } else if (saved_destination_->IsDoubleStackSlot()) { - __ sdc1(kSavedDoubleValueRegister, + __ sdc1(kLithiumScratchDouble, cgen_->ToMemOperand(saved_destination_)); } else { UNREACHABLE(); @@ -239,8 +238,8 @@ void LGapResolver::EmitMove(int index) { // Therefore we can't use 'at'. It is OK if the read from the source // destroys 'at', since that happens before the value is read. // This uses only a single reg of the double reg-pair. - __ lwc1(kSavedDoubleValueRegister, source_operand); - __ swc1(kSavedDoubleValueRegister, destination_operand); + __ lwc1(kLithiumScratchDouble, source_operand); + __ swc1(kLithiumScratchDouble, destination_operand); } else { __ lw(at, source_operand); __ sw(at, destination_operand); @@ -291,7 +290,7 @@ void LGapResolver::EmitMove(int index) { ASSERT(destination->IsDoubleStackSlot()); MemOperand destination_operand = cgen_->ToMemOperand(destination); if (in_cycle_) { - // kSavedDoubleValueRegister was used to break the cycle, + // kLithiumScratchDouble was used to break the cycle, // but kSavedValueRegister is free. MemOperand source_high_operand = cgen_->ToHighMemOperand(source); @@ -302,8 +301,8 @@ void LGapResolver::EmitMove(int index) { __ lw(kSavedValueRegister, source_high_operand); __ sw(kSavedValueRegister, destination_high_operand); } else { - __ ldc1(kSavedDoubleValueRegister, source_operand); - __ sdc1(kSavedDoubleValueRegister, destination_operand); + __ ldc1(kLithiumScratchDouble, source_operand); + __ sdc1(kLithiumScratchDouble, destination_operand); } } } else { diff --git a/deps/v8/src/mips/lithium-mips.cc b/deps/v8/src/mips/lithium-mips.cc index b66b98f208..2c098fe77c 100644 --- a/deps/v8/src/mips/lithium-mips.cc +++ b/deps/v8/src/mips/lithium-mips.cc @@ -1554,7 +1554,7 @@ LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch( LInstruction* LChunkBuilder::DoClassOfTestAndBranch( HClassOfTestAndBranch* instr) { ASSERT(instr->value()->representation().IsTagged()); - return new LClassOfTestAndBranch(UseTempRegister(instr->value()), + return new LClassOfTestAndBranch(UseRegister(instr->value()), TempRegister()); } diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc index 4517fe1818..941c7fe4ea 100644 --- a/deps/v8/src/mips/macro-assembler-mips.cc +++ b/deps/v8/src/mips/macro-assembler-mips.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -444,8 +444,10 @@ void MacroAssembler::GetNumberHash(Register reg0, Register scratch) { xor_(reg0, reg0, at); // hash = hash * 2057; - li(scratch, Operand(2057)); - mul(reg0, reg0, scratch); + sll(scratch, reg0, 11); + sll(at, reg0, 3); + addu(reg0, reg0, at); + addu(reg0, reg0, scratch); // hash = hash ^ (hash >> 16); srl(at, reg0, 16); @@ -1176,7 +1178,7 @@ void MacroAssembler::ConvertToInt32(Register source, Branch(not_int32, gt, scratch2, Operand(non_smi_exponent)); // We know the exponent is smaller than 30 (biased). If it is less than - // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie + // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e. // it rounds to zero. const uint32_t zero_exponent = (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; @@ -3313,17 +3315,51 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, } +void MacroAssembler::CompareMapAndBranch(Register obj, + Register scratch, + Handle map, + Label* early_success, + Condition cond, + Label* branch_to, + CompareMapMode mode) { + lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); + Operand right = Operand(map); + if (mode == ALLOW_ELEMENT_TRANSITION_MAPS) { + Map* transitioned_fast_element_map( + map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL)); + ASSERT(transitioned_fast_element_map == NULL || + map->elements_kind() != FAST_ELEMENTS); + if (transitioned_fast_element_map != NULL) { + Branch(early_success, eq, scratch, right); + right = Operand(Handle(transitioned_fast_element_map)); + } + + Map* transitioned_double_map( + map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL)); + ASSERT(transitioned_double_map == NULL || + map->elements_kind() == FAST_SMI_ONLY_ELEMENTS); + if (transitioned_double_map != NULL) { + Branch(early_success, eq, scratch, right); + right = Operand(Handle(transitioned_double_map)); + } + } + + Branch(branch_to, cond, scratch, right); +} + + void MacroAssembler::CheckMap(Register obj, Register scratch, Handle map, Label* fail, - SmiCheckType smi_check_type) { + SmiCheckType smi_check_type, + CompareMapMode mode) { if (smi_check_type == DO_SMI_CHECK) { JumpIfSmi(obj, fail); } - lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); - li(at, Operand(map)); - Branch(fail, ne, scratch, Operand(at)); + Label success; + CompareMapAndBranch(obj, scratch, map, &success, ne, fail, mode); + bind(&success); } @@ -3430,10 +3466,12 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, Handle code_constant, Register code_reg, Label* done, + bool* definitely_mismatches, InvokeFlag flag, const CallWrapper& call_wrapper, CallKind call_kind) { bool definitely_matches = false; + *definitely_mismatches = false; Label regular_invoke; // Check whether the expected and actual arguments count match. If not, @@ -3464,6 +3502,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, // arguments. definitely_matches = true; } else { + *definitely_mismatches = true; li(a2, Operand(expected.immediate())); } } @@ -3487,7 +3526,9 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, SetCallKind(t1, call_kind); Call(adaptor); call_wrapper.AfterCall(); - jmp(done); + if (!*definitely_mismatches) { + Branch(done); + } } else { SetCallKind(t1, call_kind); Jump(adaptor, RelocInfo::CODE_TARGET); @@ -3508,21 +3549,25 @@ void MacroAssembler::InvokeCode(Register code, Label done; - InvokePrologue(expected, actual, Handle::null(), code, &done, flag, + bool definitely_mismatches = false; + InvokePrologue(expected, actual, Handle::null(), code, + &done, &definitely_mismatches, flag, call_wrapper, call_kind); - if (flag == CALL_FUNCTION) { - call_wrapper.BeforeCall(CallSize(code)); - SetCallKind(t1, call_kind); - Call(code); - call_wrapper.AfterCall(); - } else { - ASSERT(flag == JUMP_FUNCTION); - SetCallKind(t1, call_kind); - Jump(code); + if (!definitely_mismatches) { + if (flag == CALL_FUNCTION) { + call_wrapper.BeforeCall(CallSize(code)); + SetCallKind(t1, call_kind); + Call(code); + call_wrapper.AfterCall(); + } else { + ASSERT(flag == JUMP_FUNCTION); + SetCallKind(t1, call_kind); + Jump(code); + } + // Continue here if InvokePrologue does handle the invocation due to + // mismatched parameter counts. + bind(&done); } - // Continue here if InvokePrologue does handle the invocation due to - // mismatched parameter counts. - bind(&done); } @@ -3537,18 +3582,22 @@ void MacroAssembler::InvokeCode(Handle code, Label done; - InvokePrologue(expected, actual, code, no_reg, &done, flag, + bool definitely_mismatches = false; + InvokePrologue(expected, actual, code, no_reg, + &done, &definitely_mismatches, flag, NullCallWrapper(), call_kind); - if (flag == CALL_FUNCTION) { - SetCallKind(t1, call_kind); - Call(code, rmode); - } else { - SetCallKind(t1, call_kind); - Jump(code, rmode); + if (!definitely_mismatches) { + if (flag == CALL_FUNCTION) { + SetCallKind(t1, call_kind); + Call(code, rmode); + } else { + SetCallKind(t1, call_kind); + Jump(code, rmode); + } + // Continue here if InvokePrologue does handle the invocation due to + // mismatched parameter counts. + bind(&done); } - // Continue here if InvokePrologue does handle the invocation due to - // mismatched parameter counts. - bind(&done); } @@ -3581,6 +3630,7 @@ void MacroAssembler::InvokeFunction(Register function, void MacroAssembler::InvokeFunction(Handle function, const ParameterCount& actual, InvokeFlag flag, + const CallWrapper& call_wrapper, CallKind call_kind) { // You can't call a function without a valid frame. ASSERT(flag == JUMP_FUNCTION || has_frame()); @@ -3594,7 +3644,7 @@ void MacroAssembler::InvokeFunction(Handle function, // allow recompilation to take effect without changing any of the // call sites. lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset)); - InvokeCode(a3, expected, actual, flag, NullCallWrapper(), call_kind); + InvokeCode(a3, expected, actual, flag, call_wrapper, call_kind); } @@ -4731,6 +4781,34 @@ void MacroAssembler::PatchRelocatedValue(Register li_location, FlushICache(li_location, 2); } +void MacroAssembler::GetRelocatedValue(Register li_location, + Register value, + Register scratch) { + lw(value, MemOperand(li_location)); + if (emit_debug_code()) { + And(value, value, kOpcodeMask); + Check(eq, "The instruction should be a lui.", + value, Operand(LUI)); + lw(value, MemOperand(li_location)); + } + + // value now holds a lui instruction. Extract the immediate. + sll(value, value, kImm16Bits); + + lw(scratch, MemOperand(li_location, kInstrSize)); + if (emit_debug_code()) { + And(scratch, scratch, kOpcodeMask); + Check(eq, "The instruction should be an ori.", + scratch, Operand(ORI)); + lw(scratch, MemOperand(li_location, kInstrSize)); + } + // "scratch" now holds an ori instruction. Extract the immediate. + andi(scratch, scratch, kImm16Mask); + + // Merge the results. + or_(value, value, scratch); +} + void MacroAssembler::CheckPageFlag( Register object, diff --git a/deps/v8/src/mips/macro-assembler-mips.h b/deps/v8/src/mips/macro-assembler-mips.h index eb9cf6e574..b976f6ee0c 100644 --- a/deps/v8/src/mips/macro-assembler-mips.h +++ b/deps/v8/src/mips/macro-assembler-mips.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -51,16 +51,6 @@ class JumpTarget; // MIPS generated code calls C code, it must be via t9 register. -// Register aliases. -// cp is assumed to be a callee saved register. -const Register kLithiumScratchReg = s3; // Scratch register. -const Register kLithiumScratchReg2 = s4; // Scratch register. -const Register kCondReg = s5; // Simulated (partial) condition code for mips. -const Register kRootRegister = s6; // Roots array pointer. -const Register cp = s7; // JavaScript context pointer. -const Register fp = s8_fp; // Alias for fp. -const DoubleRegister kLithiumScratchDouble = f30; // Double scratch register. - // Flags used for the AllocateInNewSpace functions. enum AllocationFlags { // No special flags. @@ -340,7 +330,7 @@ class MacroAssembler: public Assembler { Register scratch3, Label* object_is_white_and_not_data); - // Detects conservatively whether an object is data-only, ie it does need to + // Detects conservatively whether an object is data-only, i.e. it does need to // be scanned by the garbage collector. void JumpIfDataObject(Register value, Register scratch, @@ -421,7 +411,7 @@ class MacroAssembler: public Assembler { } // Check if the given instruction is a 'type' marker. - // ie. check if it is a sll zero_reg, zero_reg, (referenced as + // i.e. check if it is a sll zero_reg, zero_reg, (referenced as // nop(type)). These instructions are generated to mark special location in // the code, like some special IC code. static inline bool IsMarkedCode(Instr instr, int type) { @@ -830,6 +820,7 @@ class MacroAssembler: public Assembler { void InvokeFunction(Handle function, const ParameterCount& actual, InvokeFlag flag, + const CallWrapper& call_wrapper, CallKind call_kind); @@ -940,15 +931,29 @@ class MacroAssembler: public Assembler { Register scratch4, Label* fail); - // Check if the map of an object is equal to a specified map (either - // given directly or as an index into the root list) and branch to - // label if not. Skip the smi check if not required (object is known - // to be a heap object). + // Compare an object's map with the specified map and its transitioned + // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Jumps to + // "branch_to" if the result of the comparison is "cond". If multiple map + // compares are required, the compare sequences branches to early_success. + void CompareMapAndBranch(Register obj, + Register scratch, + Handle map, + Label* early_success, + Condition cond, + Label* branch_to, + CompareMapMode mode = REQUIRE_EXACT_MAP); + + // Check if the map of an object is equal to a specified map and branch to + // label if not. Skip the smi check if not required (object is known to be a + // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match + // against maps that are ElementsKind transition maps of the specificed map. void CheckMap(Register obj, Register scratch, Handle map, Label* fail, - SmiCheckType smi_check_type); + SmiCheckType smi_check_type, + CompareMapMode mode = REQUIRE_EXACT_MAP); + void CheckMap(Register obj, Register scratch, @@ -1132,7 +1137,7 @@ class MacroAssembler: public Assembler { // Calls an API function. Allocates HandleScope, extracts returned value // from handle and propagates exceptions. Restores context. stack_space - // - space to be unwound on exit (includes the call js arguments space and + // - space to be unwound on exit (includes the call JS arguments space and // the additional space allocated for the fast call). void CallApiFunctionAndReturn(ExternalReference function, int stack_space); @@ -1337,6 +1342,10 @@ class MacroAssembler: public Assembler { void PatchRelocatedValue(Register li_location, Register scratch, Register new_value); + // Get the relocatad value (loaded data) from the lui/ori pair. + void GetRelocatedValue(Register li_location, + Register value, + Register scratch); private: void CallCFunctionHelper(Register function, @@ -1369,6 +1378,7 @@ class MacroAssembler: public Assembler { Handle code_constant, Register code_reg, Label* done, + bool* definitely_mismatches, InvokeFlag flag, const CallWrapper& call_wrapper, CallKind call_kind); diff --git a/deps/v8/src/mips/simulator-mips.cc b/deps/v8/src/mips/simulator-mips.cc index 191c2cafd5..a158f045f5 100644 --- a/deps/v8/src/mips/simulator-mips.cc +++ b/deps/v8/src/mips/simulator-mips.cc @@ -2291,7 +2291,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { } -// Type 2: instructions using a 16 bytes immediate. (eg: addi, beq). +// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq). void Simulator::DecodeTypeImmediate(Instruction* instr) { // Instruction fields. Opcode op = instr->OpcodeFieldRaw(); @@ -2614,7 +2614,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { } -// Type 3: instructions using a 26 bytes immediate. (eg: j, jal). +// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal). void Simulator::DecodeTypeJump(Instruction* instr) { // Get current pc. int32_t current_pc = get_pc(); diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc index bf01861a61..0051edfb6c 100644 --- a/deps/v8/src/mips/stub-cache-mips.cc +++ b/deps/v8/src/mips/stub-cache-mips.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -377,13 +377,9 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, Label* miss_label) { // a0 : value. Label exit; - - // Check that the receiver isn't a smi. - __ JumpIfSmi(receiver_reg, miss_label, scratch); - - // Check that the map of the receiver hasn't changed. - __ lw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); - __ Branch(miss_label, ne, scratch, Operand(Handle(object->map()))); + // Check that the map of the object hasn't changed. + __ CheckMap(receiver_reg, scratch, Handle(object->map()), miss_label, + DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); // Perform global security token check if needed. if (object->IsJSGlobalProxy()) { @@ -565,11 +561,11 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- // -- sp[0] : holder (set by CheckPrototypes) - // -- sp[4] : callee js function + // -- sp[4] : callee JS function // -- sp[8] : call data - // -- sp[12] : last js argument + // -- sp[12] : last JS argument // -- ... - // -- sp[(argc + 3) * 4] : first js argument + // -- sp[(argc + 3) * 4] : first JS argument // -- sp[(argc + 4) * 4] : receiver // ----------------------------------- // Get the function and setup the context. @@ -587,7 +583,7 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, __ li(t2, call_data); } - // Store js function and call data. + // Store JS function and call data. __ sw(t1, MemOperand(sp, 1 * kPointerSize)); __ sw(t2, MemOperand(sp, 2 * kPointerSize)); @@ -747,7 +743,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(optimization.constant_function(), arguments_, - JUMP_FUNCTION, call_kind); + JUMP_FUNCTION, NullCallWrapper(), call_kind); } // Deferred code for fast API call case---clean preallocated space. @@ -1037,9 +1033,8 @@ Register StubCompiler::CheckPrototypes(Handle object, __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); } else { Handle current_map(current->map()); - __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); - // Branch on the result of the map check. - __ Branch(miss, ne, scratch1, Operand(current_map)); + __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK, + ALLOW_ELEMENT_TRANSITION_MAPS); // Check access rights to the global object. This has to happen after // the map check so that we know that the object is actually a global // object. @@ -1070,8 +1065,8 @@ Register StubCompiler::CheckPrototypes(Handle object, LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1)); // Check the holder map. - __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); - __ Branch(miss, ne, scratch1, Operand(Handle(current->map()))); + __ CheckMap(reg, scratch1, Handle(current->map()), miss, + DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); // Perform security check for access to the global object. ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); @@ -1209,7 +1204,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle object, // and CALLBACKS, so inline only them, other cases may be added // later. bool compile_followup_inline = false; - if (lookup->IsProperty() && lookup->IsCacheable()) { + if (lookup->IsFound() && lookup->IsCacheable()) { if (lookup->type() == FIELD) { compile_followup_inline = true; } else if (lookup->type() == CALLBACKS && @@ -1934,7 +1929,8 @@ Handle CallStubCompiler::CompileStringFromCharCodeCall( // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. __ bind(&slow); - __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD); + __ InvokeFunction( + function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); __ bind(&miss); // a2: function name. @@ -2067,7 +2063,8 @@ Handle CallStubCompiler::CompileMathFloorCall( __ bind(&slow); // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. - __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD); + __ InvokeFunction( + function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); __ bind(&miss); // a2: function name. @@ -2167,7 +2164,8 @@ Handle CallStubCompiler::CompileMathAbsCall( // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. __ bind(&slow); - __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD); + __ InvokeFunction( + function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); __ bind(&miss); // a2: function name. @@ -2346,7 +2344,8 @@ Handle CallStubCompiler::CompileCallConstant(Handle object, CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; - __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind); + __ InvokeFunction( + function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind); // Handle call cache miss. __ bind(&miss); @@ -2493,12 +2492,9 @@ Handle StoreStubCompiler::CompileStoreCallback( // ----------------------------------- Label miss; - // Check that the object isn't a smi. - __ JumpIfSmi(a1, &miss); - // Check that the map of the object hasn't changed. - __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset)); - __ Branch(&miss, ne, a3, Operand(Handle(object->map()))); + __ CheckMap(a1, a3, Handle(object->map()), &miss, + DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); // Perform global security token check if needed. if (object->IsJSGlobalProxy()) { @@ -2540,12 +2536,9 @@ Handle StoreStubCompiler::CompileStoreInterceptor( // ----------------------------------- Label miss; - // Check that the object isn't a smi. - __ JumpIfSmi(a1, &miss); - // Check that the map of the object hasn't changed. - __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset)); - __ Branch(&miss, ne, a3, Operand(Handle(receiver->map()))); + __ CheckMap(a1, a3, Handle(receiver->map()), &miss, + DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); // Perform global security token check if needed. if (receiver->IsJSGlobalProxy()) { diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index 5c68ddff7f..3a667a4398 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -388,7 +388,7 @@ void ConsString::ConsStringVerify() { CHECK(this->first()->IsString()); CHECK(this->second() == GetHeap()->empty_string() || this->second()->IsString()); - CHECK(this->length() >= String::kMinNonFlatLength); + CHECK(this->length() >= ConsString::kMinLength); if (this->IsFlat()) { // A flat cons can only be created by String::SlowTryFlatten. // Afterwards, the first part may be externalized. diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 2e9ccc1fa2..7308fb2bc3 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -1391,11 +1391,11 @@ int JSObject::GetHeaderSize() { case JS_VALUE_TYPE: return JSValue::kSize; case JS_ARRAY_TYPE: - return JSValue::kSize; + return JSArray::kSize; case JS_WEAK_MAP_TYPE: return JSWeakMap::kSize; case JS_REGEXP_TYPE: - return JSValue::kSize; + return JSRegExp::kSize; case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return JSObject::kHeaderSize; case JS_MESSAGE_OBJECT_TYPE: diff --git a/deps/v8/src/objects-printer.cc b/deps/v8/src/objects-printer.cc index e558e583e4..eca9bab822 100644 --- a/deps/v8/src/objects-printer.cc +++ b/deps/v8/src/objects-printer.cc @@ -627,7 +627,7 @@ void String::StringPrint(FILE* out) { // This method is only meant to be called from gdb for debugging purposes. -// Since the string can also be in two-byte encoding, non-ascii characters +// Since the string can also be in two-byte encoding, non-ASCII characters // will be ignored in the output. char* String::ToAsciiArray() { // Static so that subsequent calls frees previously allocated space. diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index abeeec9e2f..426327c9ca 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -993,7 +993,8 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) { int new_size = this->Size(); // Byte size of the external String object. heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); if (Marking::IsBlack(Marking::MarkBitFrom(this))) { - MemoryChunk::IncrementLiveBytes(this->address(), new_size - size); + MemoryChunk::IncrementLiveBytesFromMutator(this->address(), + new_size - size); } return true; } @@ -1037,7 +1038,8 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) { int new_size = this->Size(); // Byte size of the external String object. heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); if (Marking::IsBlack(Marking::MarkBitFrom(this))) { - MemoryChunk::IncrementLiveBytes(this->address(), new_size - size); + MemoryChunk::IncrementLiveBytesFromMutator(this->address(), + new_size - size); } return true; } @@ -3460,7 +3462,8 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, current_heap->CreateFillerObjectAt(this->address() + new_instance_size, instance_size_delta); if (Marking::IsBlack(Marking::MarkBitFrom(this))) { - MemoryChunk::IncrementLiveBytes(this->address(), -instance_size_delta); + MemoryChunk::IncrementLiveBytesFromMutator(this->address(), + -instance_size_delta); } @@ -4350,7 +4353,7 @@ void JSObject::LookupCallback(String* name, LookupResult* result) { current != heap->null_value() && current->IsJSObject(); current = JSObject::cast(current)->GetPrototype()) { JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); - if (result->IsProperty() && result->type() == CALLBACKS) return; + if (result->IsFound() && result->type() == CALLBACKS) return; } result->NotFound(); } @@ -4454,7 +4457,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name, // Lookup the name. LookupResult result(heap->isolate()); LocalLookupRealNamedProperty(name, &result); - if (result.IsProperty()) { + if (result.IsFound()) { // TODO(mstarzinger): We should check for result.IsDontDelete() here once // we only call into the runtime once to set both getter and setter. if (result.type() == CALLBACKS) { @@ -4932,75 +4935,191 @@ void Map::RemoveFromCodeCache(String* name, Code* code, int index) { } -void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { - // Traverse the transition tree without using a stack. We do this by - // reversing the pointers in the maps and descriptor arrays. - Map* current = this; - Map* meta_map = GetHeap()->meta_map(); - Object** map_or_index_field = NULL; - while (current != meta_map) { - DescriptorArray* d = reinterpret_cast( - *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); - if (!d->IsEmpty()) { - FixedArray* contents = reinterpret_cast( - d->get(DescriptorArray::kContentArrayIndex)); - map_or_index_field = RawField(contents, HeapObject::kMapOffset); - Object* map_or_index = *map_or_index_field; - bool map_done = true; // Controls a nested continue statement. - for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0; - i < contents->length(); - i += 2) { - PropertyDetails details(Smi::cast(contents->get(i + 1))); - if (details.IsTransition()) { - // Found a map in the transition array. We record our progress in - // the transition array by recording the current map in the map field - // of the next map and recording the index in the transition array in - // the map field of the array. - Map* next = Map::cast(contents->get(i)); - next->set_map_no_write_barrier(current); - *map_or_index_field = Smi::FromInt(i + 2); - current = next; - map_done = false; - break; - } - } - if (!map_done) continue; - } else { - map_or_index_field = NULL; - } - // That was the regular transitions, now for the prototype transitions. - FixedArray* prototype_transitions = - current->unchecked_prototype_transitions(); - Object** proto_map_or_index_field = - RawField(prototype_transitions, HeapObject::kMapOffset); - Object* map_or_index = *proto_map_or_index_field; - const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; - int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start; - if (i < prototype_transitions->length()) { - // Found a map in the prototype transition array. Record progress in - // an analogous way to the regular transitions array above. - Object* perhaps_map = prototype_transitions->get(i); - if (perhaps_map->IsMap()) { - Map* next = Map::cast(perhaps_map); - next->set_map_no_write_barrier(current); - *proto_map_or_index_field = - Smi::FromInt(i + kProtoTransitionElementsPerEntry); - current = next; - continue; +// An iterator over all map transitions in an descriptor array, reusing the map +// field of the contens array while it is running. +class IntrusiveMapTransitionIterator { + public: + explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array) + : descriptor_array_(descriptor_array) { } + + void Start() { + ASSERT(!IsIterating()); + if (HasContentArray()) *ContentHeader() = Smi::FromInt(0); + } + + bool IsIterating() { + return HasContentArray() && (*ContentHeader())->IsSmi(); + } + + Map* Next() { + ASSERT(IsIterating()); + FixedArray* contents = ContentArray(); + int index = Smi::cast(*ContentHeader())->value(); + while (index < contents->length()) { + int next_index = index + 2; + PropertyDetails details(Smi::cast(contents->get(index + 1))); + if (details.IsTransition()) { + *ContentHeader() = Smi::FromInt(next_index); + return static_cast(contents->get(index)); } + index = next_index; } - *proto_map_or_index_field = GetHeap()->fixed_array_map(); - if (map_or_index_field != NULL) { - *map_or_index_field = GetHeap()->fixed_array_map(); + *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map(); + return NULL; + } + + private: + bool HasContentArray() { + return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex; + } + + FixedArray* ContentArray() { + Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex); + return static_cast(array); + } + + Object** ContentHeader() { + return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset); + } + + DescriptorArray* descriptor_array_; +}; + + +// An iterator over all prototype transitions, reusing the map field of the +// underlying array while it is running. +class IntrusivePrototypeTransitionIterator { + public: + explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans) + : proto_trans_(proto_trans) { } + + void Start() { + ASSERT(!IsIterating()); + if (HasTransitions()) *Header() = Smi::FromInt(0); + } + + bool IsIterating() { + return HasTransitions() && (*Header())->IsSmi(); + } + + Map* Next() { + ASSERT(IsIterating()); + int transitionNumber = Smi::cast(*Header())->value(); + if (transitionNumber < NumberOfTransitions()) { + *Header() = Smi::FromInt(transitionNumber + 1); + return GetTransition(transitionNumber); } + *Header() = proto_trans_->GetHeap()->fixed_array_map(); + return NULL; + } + + private: + bool HasTransitions() { + return proto_trans_->length() >= Map::kProtoTransitionHeaderSize; + } + + Object** Header() { + return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset); + } + + int NumberOfTransitions() { + Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset); + return Smi::cast(num)->value(); + } - // The callback expects a map to have a real map as its map, so we save - // the map field, which is being used to track the traversal and put the - // correct map (the meta_map) in place while we do the callback. - Map* prev = current->map(); - current->set_map_no_write_barrier(meta_map); - callback(current, data); - current = prev; + Map* GetTransition(int transitionNumber) { + return Map::cast(proto_trans_->get(IndexFor(transitionNumber))); + } + + int IndexFor(int transitionNumber) { + return Map::kProtoTransitionHeaderSize + + Map::kProtoTransitionMapOffset + + transitionNumber * Map::kProtoTransitionElementsPerEntry; + } + + FixedArray* proto_trans_; +}; + + +// To traverse the transition tree iteratively, we have to store two kinds of +// information in a map: The parent map in the traversal and which children of a +// node have already been visited. To do this without additional memory, we +// temporarily reuse two maps with known values: +// +// (1) The map of the map temporarily holds the parent, and is restored to the +// meta map afterwards. +// +// (2) The info which children have already been visited depends on which part +// of the map we currently iterate: +// +// (a) If we currently follow normal map transitions, we temporarily store +// the current index in the map of the FixedArray of the desciptor +// array's contents, and restore it to the fixed array map afterwards. +// Note that a single descriptor can have 0, 1, or 2 transitions. +// +// (b) If we currently follow prototype transitions, we temporarily store +// the current index in the map of the FixedArray holding the prototype +// transitions, and restore it to the fixed array map afterwards. +// +// Note that the child iterator is just a concatenation of two iterators: One +// iterating over map transitions and one iterating over prototype transisitons. +class TraversableMap : public Map { + public: + // Record the parent in the traversal within this map. Note that this destroys + // this map's map! + void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); } + + // Reset the current map's map, returning the parent previously stored in it. + TraversableMap* GetAndResetParent() { + TraversableMap* old_parent = static_cast(map()); + set_map_no_write_barrier(GetHeap()->meta_map()); + return old_parent; + } + + // Start iterating over this map's children, possibly destroying a FixedArray + // map (see explanation above). + void ChildIteratorStart() { + IntrusiveMapTransitionIterator(instance_descriptors()).Start(); + IntrusivePrototypeTransitionIterator( + unchecked_prototype_transitions()).Start(); + } + + // If we have an unvisited child map, return that one and advance. If we have + // none, return NULL and reset any destroyed FixedArray maps. + TraversableMap* ChildIteratorNext() { + IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors()); + if (descriptor_iterator.IsIterating()) { + Map* next = descriptor_iterator.Next(); + if (next != NULL) return static_cast(next); + } + IntrusivePrototypeTransitionIterator + proto_iterator(unchecked_prototype_transitions()); + if (proto_iterator.IsIterating()) { + Map* next = proto_iterator.Next(); + if (next != NULL) return static_cast(next); + } + return NULL; + } +}; + + +// Traverse the transition tree in postorder without using the C++ stack by +// doing pointer reversal. +void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { + TraversableMap* current = static_cast(this); + current->ChildIteratorStart(); + while (true) { + TraversableMap* child = current->ChildIteratorNext(); + if (child != NULL) { + child->ChildIteratorStart(); + child->SetParent(current); + current = child; + } else { + TraversableMap* parent = current->GetAndResetParent(); + callback(current, data); + if (current == this) break; + current = parent; + } } } @@ -7469,7 +7588,7 @@ bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) { LookupResult result(heap->isolate()); String* name = GetThisPropertyAssignmentName(i); js_object->LocalLookupRealNamedProperty(name, &result); - if (result.IsProperty() && result.type() == CALLBACKS) { + if (result.IsFound() && result.type() == CALLBACKS) { return false; } } @@ -10143,7 +10262,7 @@ bool JSObject::HasRealNamedCallbackProperty(String* key) { LookupResult result(isolate); LocalLookupRealNamedProperty(key, &result); - return result.IsProperty() && (result.type() == CALLBACKS); + return result.IsFound() && (result.type() == CALLBACKS); } @@ -10885,7 +11004,7 @@ int StringDictionary::FindEntry(String* key) { // Optimized for symbol key. Knowledge of the key type allows: // 1. Move the check if the key is a symbol out of the loop. - // 2. Avoid comparing hash codes in symbol to symbol comparision. + // 2. Avoid comparing hash codes in symbol to symbol comparison. // 3. Detect a case when a dictionary key is not a symbol but the key is. // In case of positive result the dictionary key may be replaced by // the symbol with minimal performance penalty. It gives a chance to diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 791aeb3647..f2e35a6b7c 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -217,7 +217,7 @@ const int kVariableSizeSentinel = 0; // encoding is considered TWO_BYTE. It is not mentioned in the name. ASCII // encoding is mentioned explicitly in the name. Likewise, the default // representation is considered sequential. It is not mentioned in the -// name. The other representations (eg, CONS, EXTERNAL) are explicitly +// name. The other representations (e.g. CONS, EXTERNAL) are explicitly // mentioned. Finally, the string is either a SYMBOL_TYPE (if it is a // symbol) or a STRING_TYPE (if it is not a symbol). // @@ -492,7 +492,7 @@ const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag; STATIC_ASSERT(IS_POWER_OF_TWO(kSlicedNotConsMask) && kSlicedNotConsMask != 0); // If bit 7 is clear, then bit 3 indicates whether this two-byte -// string actually contains ascii data. +// string actually contains ASCII data. const uint32_t kAsciiDataHintMask = 0x08; const uint32_t kAsciiDataHintTag = 0x08; @@ -1086,7 +1086,7 @@ class Failure: public MaybeObject { // Heap objects typically have a map pointer in their first word. However, -// during GC other data (eg, mark bits, forwarding addresses) is sometimes +// during GC other data (e.g. mark bits, forwarding addresses) is sometimes // encoded in the first word. The class MapWord is an abstraction of the // value in a heap object's first word. class MapWord BASE_EMBEDDED { @@ -1105,7 +1105,7 @@ class MapWord BASE_EMBEDDED { // True if this map word is a forwarding address for a scavenge // collection. Only valid during a scavenge collection (specifically, - // when all map words are heap object pointers, ie. not during a full GC). + // when all map words are heap object pointers, i.e. not during a full GC). inline bool IsForwardingAddress(); // Create a map word from a forwarding address. @@ -4492,6 +4492,11 @@ class Map: public HeapObject { return elements_kind() == DICTIONARY_ELEMENTS; } + inline bool has_slow_elements_kind() { + return elements_kind() == DICTIONARY_ELEMENTS + || elements_kind() == NON_STRICT_ARGUMENTS_ELEMENTS; + } + static bool IsValidElementsTransition(ElementsKind from_kind, ElementsKind to_kind); @@ -6489,7 +6494,7 @@ class String: public HeapObject { inline String* GetUnderlying(); // Mark the string as an undetectable object. It only applies to - // ascii and two byte string types. + // ASCII and two byte string types. bool MarkAsUndetectable(); // Return a substring. @@ -6586,14 +6591,11 @@ class String: public HeapObject { // value into an array index. static const int kMaxArrayIndexSize = 10; - // Max ascii char code. + // Max ASCII char code. static const int kMaxAsciiCharCode = unibrow::Utf8::kMaxOneByteChar; static const unsigned kMaxAsciiCharCodeU = unibrow::Utf8::kMaxOneByteChar; static const int kMaxUC16CharCode = 0xffff; - // Minimum length for a cons string. - static const int kMinNonFlatLength = 13; - // Mask constant for checking if a string has a computed hash code // and if it is an array index. The least significant bit indicates // whether a hash code has been computed. If the hash code has been @@ -6772,8 +6774,8 @@ class SeqString: public String { }; -// The AsciiString class captures sequential ascii string objects. -// Each character in the AsciiString is an ascii character. +// The AsciiString class captures sequential ASCII string objects. +// Each character in the AsciiString is an ASCII character. class SeqAsciiString: public SeqString { public: static const bool kHasAsciiEncoding = true; @@ -7804,7 +7806,8 @@ class TemplateInfo: public Struct { static const int kTagOffset = HeapObject::kHeaderSize; static const int kPropertyListOffset = kTagOffset + kPointerSize; static const int kHeaderSize = kPropertyListOffset + kPointerSize; - protected: + + private: DISALLOW_IMPLICIT_CONSTRUCTORS(TemplateInfo); }; diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 777436ee04..35cc1c92d9 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -3757,7 +3757,7 @@ ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter, RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION, CHECK_OK); - // Allow any number of parameters for compatiabilty with JSC. + // Allow any number of parameters for compatibilty with JSC. // Specification only allows zero parameters for get and one for set. ObjectLiteral::Property* property = new(zone()) ObjectLiteral::Property(is_getter, value); diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h index 146d7bb9af..16c2eff6d3 100644 --- a/deps/v8/src/parser.h +++ b/deps/v8/src/parser.h @@ -186,7 +186,7 @@ class ParserApi { // ---------------------------------------------------------------------------- // REGEXP PARSING -// A BuffferedZoneList is an automatically growing list, just like (and backed +// A BufferedZoneList is an automatically growing list, just like (and backed // by) a ZoneList, that is optimized for the case of adding and removing // a single element. The last element added is stored outside the backing list, // and if no more than one element is ever added, the ZoneList isn't even diff --git a/deps/v8/src/platform-cygwin.cc b/deps/v8/src/platform-cygwin.cc index 9b34de91ce..c27e3c982f 100644 --- a/deps/v8/src/platform-cygwin.cc +++ b/deps/v8/src/platform-cygwin.cc @@ -1,4 +1,4 @@ -// Copyright 2006-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: @@ -114,7 +114,7 @@ double OS::LocalTimeOffset() { // We keep the lowest and highest addresses mapped as a quick way of // determining that pointers are outside the heap (used mostly in assertions -// and verification). The estimate is conservative, ie, not all addresses in +// and verification). The estimate is conservative, i.e., not all addresses in // 'allocated' space are actually allocated to our heap. The range is // [lowest, highest), inclusive on the low and and exclusive on the high end. static void* lowest_ever_allocated = reinterpret_cast(-1); @@ -722,6 +722,7 @@ class SamplerThread : public Thread { static Mutex* mutex_; static SamplerThread* instance_; + private: DISALLOW_COPY_AND_ASSIGN(SamplerThread); }; diff --git a/deps/v8/src/platform-freebsd.cc b/deps/v8/src/platform-freebsd.cc index 7d0d8d026d..6d04fb1aaa 100644 --- a/deps/v8/src/platform-freebsd.cc +++ b/deps/v8/src/platform-freebsd.cc @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -128,7 +128,7 @@ double OS::LocalTimeOffset() { // We keep the lowest and highest addresses mapped as a quick way of // determining that pointers are outside the heap (used mostly in assertions -// and verification). The estimate is conservative, ie, not all addresses in +// and verification). The estimate is conservative, i.e., not all addresses in // 'allocated' space are actually allocated to our heap. The range is // [lowest, highest), inclusive on the low and and exclusive on the high end. static void* lowest_ever_allocated = reinterpret_cast(-1); @@ -840,6 +840,7 @@ class SignalSender : public Thread { static bool signal_handler_installed_; static struct sigaction old_signal_handler_; + private: DISALLOW_COPY_AND_ASSIGN(SignalSender); }; diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc index a3cdc031ef..30b6086616 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -326,7 +326,7 @@ double OS::LocalTimeOffset() { // We keep the lowest and highest addresses mapped as a quick way of // determining that pointers are outside the heap (used mostly in assertions -// and verification). The estimate is conservative, ie, not all addresses in +// and verification). The estimate is conservative, i.e., not all addresses in // 'allocated' space are actually allocated to our heap. The range is // [lowest, highest), inclusive on the low and and exclusive on the high end. static void* lowest_ever_allocated = reinterpret_cast(-1); @@ -1151,6 +1151,9 @@ class SignalSender : public Thread { // occuring during signal delivery. useconds_t interval = interval_ * 1000 - 100; if (full_or_half == HALF_INTERVAL) interval /= 2; +#if defined(ANDROID) + usleep(interval); +#else int result = usleep(interval); #ifdef DEBUG if (result != 0 && errno != EINTR) { @@ -1160,8 +1163,9 @@ class SignalSender : public Thread { errno); ASSERT(result == 0 || errno == EINTR); } -#endif +#endif // DEBUG USE(result); +#endif // ANDROID } const int vm_tgid_; @@ -1174,6 +1178,7 @@ class SignalSender : public Thread { static bool signal_handler_installed_; static struct sigaction old_signal_handler_; + private: DISALLOW_COPY_AND_ASSIGN(SignalSender); }; diff --git a/deps/v8/src/platform-macos.cc b/deps/v8/src/platform-macos.cc index 417fb11ae1..9f8fe1209f 100644 --- a/deps/v8/src/platform-macos.cc +++ b/deps/v8/src/platform-macos.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -75,7 +75,7 @@ extern "C" { namespace v8 { namespace internal { -// 0 is never a valid thread id on MacOSX since a ptread_t is +// 0 is never a valid thread id on MacOSX since a pthread_t is // a pointer. static const pthread_t kNoThread = (pthread_t) 0; @@ -103,7 +103,7 @@ void OS::SetUp() { // We keep the lowest and highest addresses mapped as a quick way of // determining that pointers are outside the heap (used mostly in assertions -// and verification). The estimate is conservative, ie, not all addresses in +// and verification). The estimate is conservative, i.e., not all addresses in // 'allocated' space are actually allocated to our heap. The range is // [lowest, highest), inclusive on the low and and exclusive on the high end. static void* lowest_ever_allocated = reinterpret_cast(-1); @@ -854,6 +854,7 @@ class SamplerThread : public Thread { static Mutex* mutex_; static SamplerThread* instance_; + private: DISALLOW_COPY_AND_ASSIGN(SamplerThread); }; diff --git a/deps/v8/src/platform-openbsd.cc b/deps/v8/src/platform-openbsd.cc index 6f582d4341..fda5fb4589 100644 --- a/deps/v8/src/platform-openbsd.cc +++ b/deps/v8/src/platform-openbsd.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -146,7 +146,7 @@ double OS::LocalTimeOffset() { // We keep the lowest and highest addresses mapped as a quick way of // determining that pointers are outside the heap (used mostly in assertions -// and verification). The estimate is conservative, ie, not all addresses in +// and verification). The estimate is conservative, i.e., not all addresses in // 'allocated' space are actually allocated to our heap. The range is // [lowest, highest), inclusive on the low and and exclusive on the high end. static void* lowest_ever_allocated = reinterpret_cast(-1); @@ -923,6 +923,7 @@ class SignalSender : public Thread { static bool signal_handler_installed_; static struct sigaction old_signal_handler_; + private: DISALLOW_COPY_AND_ASSIGN(SignalSender); }; diff --git a/deps/v8/src/platform-win32.cc b/deps/v8/src/platform-win32.cc index c439ab91a0..ffda6606a8 100644 --- a/deps/v8/src/platform-win32.cc +++ b/deps/v8/src/platform-win32.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -198,7 +198,7 @@ double modulo(double x, double y) { // ---------------------------------------------------------------------------- // The Time class represents time on win32. A timestamp is represented as -// a 64-bit integer in 100 nano-seconds since January 1, 1601 (UTC). JavaScript +// a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript // timestamps are represented as a doubles in milliseconds since 00:00:00 UTC, // January 1, 1970. @@ -776,7 +776,7 @@ void OS::StrNCpy(Vector dest, const char* src, size_t n) { // We keep the lowest and highest addresses mapped as a quick way of // determining that pointers are outside the heap (used mostly in assertions -// and verification). The estimate is conservative, ie, not all addresses in +// and verification). The estimate is conservative, i.e., not all addresses in // 'allocated' space are actually allocated to our heap. The range is // [lowest, highest), inclusive on the low and and exclusive on the high end. static void* lowest_ever_allocated = reinterpret_cast(-1); @@ -2006,6 +2006,7 @@ class SamplerThread : public Thread { static Mutex* mutex_; static SamplerThread* instance_; + private: DISALLOW_COPY_AND_ASSIGN(SamplerThread); }; diff --git a/deps/v8/src/property.h b/deps/v8/src/property.h index 3203dd1120..120734df9f 100644 --- a/deps/v8/src/property.h +++ b/deps/v8/src/property.h @@ -265,11 +265,6 @@ class LookupResult BASE_EMBEDDED { return IsFound() && GetPropertyDetails().IsProperty(); } - // Is the result a property or a transition? - bool IsPropertyOrTransition() { - return IsFound() && (type() != NULL_DESCRIPTOR); - } - bool IsCacheable() { return cacheable_; } void DisallowCaching() { cacheable_ = false; } diff --git a/deps/v8/src/regexp-macro-assembler.cc b/deps/v8/src/regexp-macro-assembler.cc index 99f3a37f4c..b6fb3c5214 100644 --- a/deps/v8/src/regexp-macro-assembler.cc +++ b/deps/v8/src/regexp-macro-assembler.cc @@ -133,7 +133,7 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match( subject_ptr = slice->parent(); slice_offset = slice->offset(); } - // Ensure that an underlying string has the same ascii-ness. + // Ensure that an underlying string has the same ASCII-ness. bool is_ascii = subject_ptr->IsAsciiRepresentation(); ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString()); // String is now either Sequential or External diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js index 596c185438..00dd7f15b7 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -436,8 +436,8 @@ function SetUpRegExp() { // value is set in SpiderMonkey, the value it is set to is coerced to a // boolean. We mimic that behavior with a slight difference: in SpiderMonkey // the value of the expression 'RegExp.multiline = null' (for instance) is the - // boolean false (ie, the value after coercion), while in V8 it is the value - // null (ie, the value before coercion). + // boolean false (i.e., the value after coercion), while in V8 it is the value + // null (i.e., the value before coercion). // Getter and setter for multiline. var multiline = false; diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index fb3621341a..2bac30473b 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -1434,7 +1434,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { !object->IsJSContextExtensionObject()) { LookupResult lookup(isolate); object->Lookup(*name, &lookup); - if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) { + if (lookup.IsFound() && (lookup.type() == CALLBACKS)) { return ThrowRedeclarationError(isolate, "const", name); } } @@ -1482,7 +1482,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { JSObject::cast(object)->map()->is_hidden_prototype()) { JSObject* raw_holder = JSObject::cast(object); raw_holder->LocalLookup(*name, &lookup); - if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { + if (lookup.IsFound() && lookup.type() == INTERCEPTOR) { HandleScope handle_scope(isolate); Handle holder(raw_holder); PropertyAttributes intercepted = holder->GetPropertyAttribute(*name); @@ -1648,7 +1648,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { // GetProperty() to get the current value as it 'unholes' the value. LookupResult lookup(isolate); object->LocalLookupRealNamedProperty(*name, &lookup); - ASSERT(lookup.IsProperty()); // the property was declared + ASSERT(lookup.IsFound()); // the property was declared ASSERT(lookup.IsReadOnly()); // and it was declared as read-only PropertyType type = lookup.type(); @@ -1869,9 +1869,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) { RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) { - NoHandleAllocation handle_free; ASSERT(args.length() == 1); - CONVERT_CHECKED(JSFunction, function, args[0]); + CONVERT_CHECKED(JSReceiver, callable, args[0]); + + if (!callable->IsJSFunction()) { + HandleScope scope(isolate); + bool threw = false; + Handle delegate = + Execution::TryGetFunctionDelegate(Handle(callable), &threw); + if (threw) return Failure::Exception(); + callable = JSFunction::cast(*delegate); + } + JSFunction* function = JSFunction::cast(callable); + SharedFunctionInfo* shared = function->shared(); if (shared->native() || !shared->is_classic_mode()) { return isolate->heap()->undefined_value(); @@ -3178,7 +3188,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( Address end_of_string = answer->address() + string_size; isolate->heap()->CreateFillerObjectAt(end_of_string, delta); if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) { - MemoryChunk::IncrementLiveBytes(answer->address(), -delta); + MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta); } return *answer; @@ -3233,6 +3243,79 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) { } +Handle Runtime::StringReplaceOneCharWithString(Isolate* isolate, + Handle subject, + Handle search, + Handle replace, + bool* found, + int recursion_limit) { + if (recursion_limit == 0) return Handle::null(); + if (subject->IsConsString()) { + ConsString* cons = ConsString::cast(*subject); + Handle first = Handle(cons->first()); + Handle second = Handle(cons->second()); + Handle new_first = + StringReplaceOneCharWithString(isolate, + first, + search, + replace, + found, + recursion_limit - 1); + if (*found) return isolate->factory()->NewConsString(new_first, second); + if (new_first.is_null()) return new_first; + + Handle new_second = + StringReplaceOneCharWithString(isolate, + second, + search, + replace, + found, + recursion_limit - 1); + if (*found) return isolate->factory()->NewConsString(first, new_second); + if (new_second.is_null()) return new_second; + + return subject; + } else { + int index = StringMatch(isolate, subject, search, 0); + if (index == -1) return subject; + *found = true; + Handle first = isolate->factory()->NewSubString(subject, 0, index); + Handle cons1 = isolate->factory()->NewConsString(first, replace); + Handle second = + isolate->factory()->NewSubString(subject, index + 1, subject->length()); + return isolate->factory()->NewConsString(cons1, second); + } +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) { + ASSERT(args.length() == 3); + HandleScope scope(isolate); + CONVERT_ARG_CHECKED(String, subject, 0); + CONVERT_ARG_CHECKED(String, search, 1); + CONVERT_ARG_CHECKED(String, replace, 2); + + // If the cons string tree is too deep, we simply abort the recursion and + // retry with a flattened subject string. + const int kRecursionLimit = 0x1000; + bool found = false; + Handle result = + Runtime::StringReplaceOneCharWithString(isolate, + subject, + search, + replace, + &found, + kRecursionLimit); + if (!result.is_null()) return *result; + return *Runtime::StringReplaceOneCharWithString(isolate, + FlattenGetString(subject), + search, + replace, + &found, + kRecursionLimit); +} + + // Perform string match of pattern on subject, starting at start index. // Caller must ensure that 0 <= start_index <= sub->length(), // and should check that pat->length() + start_index <= sub->length(). @@ -4173,7 +4256,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { // appropriate. LookupResult result(isolate); receiver->LocalLookup(key, &result); - if (result.IsProperty() && result.type() == FIELD) { + if (result.IsFound() && result.type() == FIELD) { int offset = result.GetFieldIndex(); keyed_lookup_cache->Update(receiver_map, key, offset); return receiver->FastPropertyAt(offset); @@ -4321,7 +4404,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { js_object->LocalLookupRealNamedProperty(*name, &result); // Special case for callback properties. - if (result.IsProperty() && result.type() == CALLBACKS) { + if (result.IsFound() && result.type() == CALLBACKS) { Object* callback = result.GetCallbackObject(); // To be compatible with Safari we do not change the value on API objects // in Object.defineProperty(). Firefox disagrees here, and actually changes @@ -5926,8 +6009,8 @@ MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( // // Allocate the resulting string. // - // NOTE: This assumes that the upper/lower case of an ascii - // character is also ascii. This is currently the case, but it + // NOTE: This assumes that the upper/lower case of an ASCII + // character is also ASCII. This is currently the case, but it // might break in the future if we implement more context and locale // dependent upper/lower conversions. Object* o; @@ -6027,9 +6110,9 @@ static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF; // This function is only useful when it can be inlined and the // boundaries are statically known. // Requires: all bytes in the input word and the boundaries must be -// ascii (less than 0x7F). +// ASCII (less than 0x7F). static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) { - // Every byte in an ascii string is less than or equal to 0x7F. + // Every byte in an ASCII string is less than or equal to 0x7F. ASSERT((w & (kOneInEveryByte * 0x7F)) == w); // Use strict inequalities since in edge cases the function could be // further simplified. @@ -6157,10 +6240,10 @@ MUST_USE_RESULT static MaybeObject* ConvertCase( // Assume that the string is not empty; we need this assumption later if (length == 0) return s; - // Simpler handling of ascii strings. + // Simpler handling of ASCII strings. // - // NOTE: This assumes that the upper/lower case of an ascii - // character is also ascii. This is currently the case, but it + // NOTE: This assumes that the upper/lower case of an ASCII + // character is also ASCII. This is currently the case, but it // might break in the future if we implement more context and locale // dependent upper/lower conversions. if (s->IsSeqAsciiString()) { @@ -6323,7 +6406,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { } -// Copies ascii characters to the given fixed array looking up +// Copies ASCII characters to the given fixed array looking up // one-char strings in the cache. Gives up on the first char that is // not in the cache and fills the remainder with smi zeros. Returns // the length of the successfully copied prefix. @@ -7422,7 +7505,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { } // Fast version of Math.pow if we know that y is not an integer and y is not -// -0.5 or 0.5. Used as slow case from fullcodegen. +// -0.5 or 0.5. Used as slow case from full codegen. RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) { NoHandleAllocation ha; ASSERT(args.length() == 2); @@ -7465,7 +7548,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) { // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and // should be rounded to 2^30, which is not smi (for 31-bit smis, similar - // agument holds for 32-bit smis). + // argument holds for 32-bit smis). if (!sign && exponent < kSmiValueSize - 2) { return Smi::FromInt(static_cast(value + 0.5)); } @@ -9355,7 +9438,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { CONVERT_ARG_CHECKED(String, source, 0); source = Handle(source->TryFlattenGetString()); - // Optimized fast case where we only have ascii characters. + // Optimized fast case where we only have ASCII characters. Handle result; if (source->IsSeqAsciiString()) { result = JsonParser::Parse(source); @@ -10257,7 +10340,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { // DefineAccessor takes an optional final argument which is the -// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due +// property attributes (e.g. DONT_ENUM, DONT_DELETE). IMPORTANT: due // to the way accessors are implemented, it is set for both the getter // and setter on the first call to DefineAccessor and ignored on // subsequent calls. @@ -11089,7 +11172,7 @@ static Handle MaterializeClosure(Isolate* isolate, Handle shared(context->closure()->shared()); Handle scope_info(shared->scope_info()); - // Allocate and initialize a JSObject with all the content of theis function + // Allocate and initialize a JSObject with all the content of this function // closure. Handle closure_scope = isolate->factory()->NewJSObject(isolate->object_function()); @@ -12257,7 +12340,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) { // because using // instances->set(i, *GetScriptWrapper(script)) // is unsafe as GetScriptWrapper might call GC and the C++ compiler might - // already have deferenced the instances handle. + // already have dereferenced the instances handle. Handle wrapper = GetScriptWrapper(script); instances->set(i, *wrapper); } diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index c915cf38da..c0c7b13bc2 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -197,6 +197,7 @@ namespace internal { F(StringLocaleCompare, 2, 1) \ F(SubString, 3, 1) \ F(StringReplaceRegExpWithString, 4, 1) \ + F(StringReplaceOneCharWithString, 3, 1) \ F(StringMatch, 3, 1) \ F(StringTrim, 3, 1) \ F(StringToArray, 2, 1) \ @@ -629,6 +630,13 @@ class Runtime : public AllStatic { // Get the intrinsic function with the given FunctionId. static const Function* FunctionForId(FunctionId id); + static Handle StringReplaceOneCharWithString(Isolate* isolate, + Handle subject, + Handle search, + Handle replace, + bool* found, + int recursion_limit); + // General-purpose helper functions for runtime system. static int StringMatch(Isolate* isolate, Handle sub, diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc index d0a1a639f3..e9be2492d7 100644 --- a/deps/v8/src/serialize.cc +++ b/deps/v8/src/serialize.cc @@ -1364,6 +1364,13 @@ void PartialSerializer::SerializeObject( CHECK(o->IsHeapObject()); HeapObject* heap_object = HeapObject::cast(o); + if (heap_object->IsMap()) { + // The code-caches link to context-specific code objects, which + // the startup and context serializes cannot currently handle. + ASSERT(Map::cast(heap_object)->code_cache() == + heap_object->GetHeap()->raw_unchecked_empty_fixed_array()); + } + int root_index; if ((root_index = RootIndex(heap_object)) != kInvalidRootIndex) { PutRoot(root_index, heap_object, how_to_code, where_to_point); diff --git a/deps/v8/src/serialize.h b/deps/v8/src/serialize.h index ff10905b9a..839bfc5618 100644 --- a/deps/v8/src/serialize.h +++ b/deps/v8/src/serialize.h @@ -1,4 +1,4 @@ -// Copyright 2006-2009 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: @@ -228,7 +228,7 @@ class SerializerDeserializer: public ObjectVisitor { kFromStart = 0x20, // Object is described relative to start. // 0x21-0x28 One per space. // 0x29-0x2f Free. - // 0x30-0x3f Used by misc tags below. + // 0x30-0x3f Used by misc. tags below. kPointedToMask = 0x3f }; @@ -359,8 +359,8 @@ class Deserializer: public SerializerDeserializer { // Fills in some heap data in an area from start to end (non-inclusive). The // space id is used for the write barrier. The object_address is the address // of the object we are writing into, or NULL if we are not writing into an - // object, ie if we are writing a series of tagged values that are not on the - // heap. + // object, i.e. if we are writing a series of tagged values that are not on + // the heap. void ReadChunk( Object** start, Object** end, int space, Address object_address); HeapObject* GetAddressFromStart(int space); @@ -581,6 +581,7 @@ class Serializer : public SerializerDeserializer { friend class ObjectSerializer; friend class Deserializer; + private: DISALLOW_COPY_AND_ASSIGN(Serializer); }; @@ -632,7 +633,7 @@ class StartupSerializer : public Serializer { // Serialize the current state of the heap. The order is: // 1) Strong references. // 2) Partial snapshot cache. - // 3) Weak references (eg the symbol table). + // 3) Weak references (e.g. the symbol table). virtual void SerializeStrongReferences(); virtual void SerializeObject(Object* o, HowToCode how_to_code, diff --git a/deps/v8/src/spaces-inl.h b/deps/v8/src/spaces-inl.h index 1cfdc138ca..d0cddebf78 100644 --- a/deps/v8/src/spaces-inl.h +++ b/deps/v8/src/spaces-inl.h @@ -248,7 +248,7 @@ void Page::set_prev_page(Page* page) { // Try linear allocation in the page of alloc_info's allocation top. Does -// not contain slow case logic (eg, move to the next page or try free list +// not contain slow case logic (e.g. move to the next page or try free list // allocation) so it can be used by all the allocation functions and for all // the paged spaces. HeapObject* PagedSpace::AllocateLinearly(int size_in_bytes) { @@ -332,7 +332,7 @@ void NewSpace::ShrinkStringAtAllocationBoundary(String* string, int length) { string->set_length(length); if (Marking::IsBlack(Marking::MarkBitFrom(string))) { int delta = static_cast(old_top - allocation_info_.top); - MemoryChunk::IncrementLiveBytes(string->address(), -delta); + MemoryChunk::IncrementLiveBytesFromMutator(string->address(), -delta); } } diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index c8e94ddbe5..d5b4d81322 100644 --- a/deps/v8/src/spaces.cc +++ b/deps/v8/src/spaces.cc @@ -648,6 +648,17 @@ void MemoryAllocator::ReportStatistics() { } #endif +// ----------------------------------------------------------------------------- +// MemoryChunk implementation + +void MemoryChunk::IncrementLiveBytesFromMutator(Address address, int by) { + MemoryChunk* chunk = MemoryChunk::FromAddress(address); + if (!chunk->InNewSpace() && !static_cast(chunk)->WasSwept()) { + static_cast(chunk->owner())->IncrementUnsweptFreeBytes(-by); + } + chunk->IncrementLiveBytes(by); +} + // ----------------------------------------------------------------------------- // PagedSpace implementation @@ -765,6 +776,8 @@ void PagedSpace::ReleasePage(Page* page) { intptr_t size = free_list_.EvictFreeListItems(page); accounting_stats_.AllocateBytes(size); ASSERT_EQ(Page::kObjectAreaSize, static_cast(size)); + } else { + DecreaseUnsweptFreeBytes(page); } if (Page::FromAllocationTop(allocation_info_.top) == page) { @@ -2112,7 +2125,7 @@ bool PagedSpace::AdvanceSweeper(intptr_t bytes_to_sweep) { PrintF("Sweeping 0x%" V8PRIxPTR " lazily advanced.\n", reinterpret_cast(p)); } - unswept_free_bytes_ -= (Page::kObjectAreaSize - p->LiveBytes()); + DecreaseUnsweptFreeBytes(p); freed_bytes += MarkCompactCollector::SweepConservatively(this, p); } p = next_page; @@ -2513,7 +2526,7 @@ void LargeObjectSpace::FreeUnmarkedObjects() { MarkBit mark_bit = Marking::MarkBitFrom(object); if (mark_bit.Get()) { mark_bit.Clear(); - MemoryChunk::IncrementLiveBytes(object->address(), -object->Size()); + MemoryChunk::IncrementLiveBytesFromGC(object->address(), -object->Size()); previous = current; current = current->next_page(); } else { diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h index 41c3ef929f..f49873ac4f 100644 --- a/deps/v8/src/spaces.h +++ b/deps/v8/src/spaces.h @@ -295,7 +295,7 @@ class SlotsBuffer; // MemoryChunk represents a memory region owned by a specific space. // It is divided into the header and the body. Chunk start is always -// 1MB aligned. Start of the body is aligned so it can accomodate +// 1MB aligned. Start of the body is aligned so it can accommodate // any heap object. class MemoryChunk { public: @@ -472,10 +472,13 @@ class MemoryChunk { ASSERT(static_cast(live_byte_count_) <= size_); return live_byte_count_; } - static void IncrementLiveBytes(Address address, int by) { + + static void IncrementLiveBytesFromGC(Address address, int by) { MemoryChunk::FromAddress(address)->IncrementLiveBytes(by); } + static void IncrementLiveBytesFromMutator(Address address, int by); + static const intptr_t kAlignment = (static_cast(1) << kPageSizeBits); @@ -1181,11 +1184,11 @@ class AllocationInfo { // An abstraction of the accounting statistics of a page-structured space. -// The 'capacity' of a space is the number of object-area bytes (ie, not +// The 'capacity' of a space is the number of object-area bytes (i.e., not // including page bookkeeping structures) currently in the space. The 'size' // of a space is the number of allocated bytes, the 'waste' in the space is // the number of bytes that are not allocated and not available to -// allocation without reorganizing the space via a GC (eg, small blocks due +// allocation without reorganizing the space via a GC (e.g. small blocks due // to internal fragmentation, top of page areas in map space), and the bytes // 'available' is the number of unallocated bytes that are not waste. The // capacity is the sum of size, waste, and available. @@ -1198,7 +1201,7 @@ class AllocationStats BASE_EMBEDDED { public: AllocationStats() { Clear(); } - // Zero out all the allocation statistics (ie, no capacity). + // Zero out all the allocation statistics (i.e., no capacity). void Clear() { capacity_ = 0; size_ = 0; @@ -1210,7 +1213,7 @@ class AllocationStats BASE_EMBEDDED { waste_ = 0; } - // Reset the allocation statistics (ie, available = capacity with no + // Reset the allocation statistics (i.e., available = capacity with no // wasted or allocated bytes). void Reset() { size_ = 0; @@ -1341,7 +1344,7 @@ class FreeList BASE_EMBEDDED { // starting at 'start' is placed on the free list. The return value is the // number of bytes that have been lost due to internal fragmentation by // freeing the block. Bookkeeping information will be written to the block, - // ie, its contents will be destroyed. The start address should be word + // i.e., its contents will be destroyed. The start address should be word // aligned, and the size should be a non-zero multiple of the word size. int Free(Address start, int size_in_bytes); @@ -1563,10 +1566,20 @@ class PagedSpace : public Space { first_unswept_page_ = first; } - void MarkPageForLazySweeping(Page* p) { + void IncrementUnsweptFreeBytes(int by) { + unswept_free_bytes_ += by; + } + + void IncreaseUnsweptFreeBytes(Page* p) { + ASSERT(ShouldBeSweptLazily(p)); unswept_free_bytes_ += (Page::kObjectAreaSize - p->LiveBytes()); } + void DecreaseUnsweptFreeBytes(Page* p) { + ASSERT(ShouldBeSweptLazily(p)); + unswept_free_bytes_ -= (Page::kObjectAreaSize - p->LiveBytes()); + } + bool AdvanceSweeper(intptr_t bytes_to_sweep); bool IsSweepingComplete() { diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index 3608bac8fa..2d6896120e 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -244,6 +244,15 @@ function StringReplace(search, replace) { // Convert the search argument to a string and search for it. search = TO_STRING_INLINE(search); + if (search.length == 1 && + subject.length > 0xFF && + IS_STRING(replace) && + %StringIndexOf(replace, '$', 0) < 0) { + // Searching by traversing a cons string tree and replace with cons of + // slices works only when the replaced string is a single character, being + // replaced by a simple string and only pays off for long strings. + return %StringReplaceOneCharWithString(subject, search, replace); + } var start = %StringIndexOf(subject, search, 0); if (start < 0) return subject; var end = start + search.length; diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc index ec8f6bdf25..c7f4f94386 100644 --- a/deps/v8/src/stub-cache.cc +++ b/deps/v8/src/stub-cache.cc @@ -1452,13 +1452,13 @@ Handle ConstructStubCompiler::GetCode() { CallOptimization::CallOptimization(LookupResult* lookup) { - if (!lookup->IsProperty() || - !lookup->IsCacheable() || - lookup->type() != CONSTANT_FUNCTION) { - Initialize(Handle::null()); - } else { + if (lookup->IsFound() && + lookup->IsCacheable() && + lookup->type() == CONSTANT_FUNCTION) { // We only optimize constant function calls. Initialize(Handle(lookup->GetConstantFunction())); + } else { + Initialize(Handle::null()); } } diff --git a/deps/v8/src/unicode.cc b/deps/v8/src/unicode.cc index 6e0ac1a357..147f716c46 100644 --- a/deps/v8/src/unicode.cc +++ b/deps/v8/src/unicode.cc @@ -210,7 +210,7 @@ static int LookupMapping(const int32_t* table, uchar Utf8::CalculateValue(const byte* str, unsigned length, unsigned* cursor) { - // We only get called for non-ascii characters. + // We only get called for non-ASCII characters. if (length == 1) { *cursor += 1; return kBadChar; @@ -286,8 +286,8 @@ const byte* Utf8::ReadBlock(Buffer str, byte* buffer, } const byte* data = reinterpret_cast(str.data()); if (data[offset] <= kMaxOneByteChar) { - // The next character is an ascii char so we scan forward over - // the following ascii characters and return the next pure ascii + // The next character is an ASCII char so we scan forward over + // the following ASCII characters and return the next pure ASCII // substring const byte* result = data + offset; offset++; @@ -297,13 +297,13 @@ const byte* Utf8::ReadBlock(Buffer str, byte* buffer, *offset_ptr = offset; return result; } else { - // The next character is non-ascii so we just fill the buffer + // The next character is non-ASCII so we just fill the buffer unsigned cursor = 0; unsigned chars_read = 0; while (offset < str.length()) { uchar c = data[offset]; if (c <= kMaxOneByteChar) { - // Fast case for ascii characters + // Fast case for ASCII characters if (!CharacterStream::EncodeAsciiCharacter(c, buffer, capacity, diff --git a/deps/v8/src/utils.h b/deps/v8/src/utils.h index 17bf06ffa3..1d40c98b9e 100644 --- a/deps/v8/src/utils.h +++ b/deps/v8/src/utils.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -931,9 +931,17 @@ class EnumSet { explicit EnumSet(T bits = 0) : bits_(bits) {} bool IsEmpty() const { return bits_ == 0; } bool Contains(E element) const { return (bits_ & Mask(element)) != 0; } + bool ContainsAnyOf(const EnumSet& set) const { + return (bits_ & set.bits_) != 0; + } void Add(E element) { bits_ |= Mask(element); } + void Add(const EnumSet& set) { bits_ |= set.bits_; } void Remove(E element) { bits_ &= ~Mask(element); } + void Remove(const EnumSet& set) { bits_ &= ~set.bits_; } + void RemoveAll() { bits_ = 0; } + void Intersect(const EnumSet& set) { bits_ &= set.bits_; } T ToIntegral() const { return bits_; } + bool operator==(const EnumSet& set) { return bits_ == set.bits_; } private: T Mask(E element) const { diff --git a/deps/v8/src/v8threads.cc b/deps/v8/src/v8threads.cc index 3881d66fb0..fd8d536401 100644 --- a/deps/v8/src/v8threads.cc +++ b/deps/v8/src/v8threads.cc @@ -154,7 +154,7 @@ namespace internal { bool ThreadManager::RestoreThread() { ASSERT(IsLockedByCurrentThread()); - // First check whether the current thread has been 'lazily archived', ie + // First check whether the current thread has been 'lazily archived', i.e. // not archived at all. If that is the case we put the state storage we // had prepared back in the free list, since we didn't need it after all. if (lazily_archived_thread_.Equals(ThreadId::Current())) { diff --git a/deps/v8/src/v8utils.cc b/deps/v8/src/v8utils.cc index bf0e05d05b..042a60f0b4 100644 --- a/deps/v8/src/v8utils.cc +++ b/deps/v8/src/v8utils.cc @@ -316,7 +316,7 @@ bool MemoryMappedExternalResource::EnsureIsAscii(bool abort_if_failed) const { for (const char* p = data_; p < end; p++) { char c = *p; if ((c & 0x80) != 0) { - // Non-ascii detected: + // Non-ASCII detected: is_ascii = false; // Report the error and abort if appropriate: @@ -329,7 +329,7 @@ bool MemoryMappedExternalResource::EnsureIsAscii(bool abort_if_failed) const { c, filename_, line_no, char_no); // Allow for some context up to kNumberOfLeadingContextChars chars - // before the offending non-ascii char to help the user see where + // before the offending non-ASCII char to help the user see where // the offending char is. const int kNumberOfLeadingContextChars = 10; const char* err_context = p - kNumberOfLeadingContextChars; @@ -345,7 +345,7 @@ bool MemoryMappedExternalResource::EnsureIsAscii(bool abort_if_failed) const { OS::Abort(); } - break; // Non-ascii detected. No need to continue scanning. + break; // Non-ASCII detected. No need to continue scanning. } if (c == '\n') { start_of_line = p; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 95535851d1..ba531abcb8 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 8 -#define BUILD_NUMBER 6 +#define BUILD_NUMBER 8 #define PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 03a5170bae..d30610101c 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -2357,6 +2357,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { const int kParameterMapHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize; Label no_parameter_map; + __ xor_(r8, r8); __ testq(rbx, rbx); __ j(zero, &no_parameter_map, Label::kNear); __ lea(r8, Operand(rbx, times_pointer_size, kParameterMapHeaderSize)); @@ -2450,16 +2451,13 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { Label parameters_loop, parameters_test; // Load tagged parameter count into r9. - __ movq(r9, Operand(rsp, 1 * kPointerSize)); + __ Integer32ToSmi(r9, rbx); __ Move(r8, Smi::FromInt(Context::MIN_CONTEXT_SLOTS)); - __ addq(r8, Operand(rsp, 3 * kPointerSize)); + __ addq(r8, Operand(rsp, 1 * kPointerSize)); __ subq(r8, r9); __ Move(r11, factory->the_hole_value()); __ movq(rdx, rdi); - __ SmiToInteger64(kScratchRegister, r9); - __ lea(rdi, Operand(rdi, kScratchRegister, - times_pointer_size, - kParameterMapHeaderSize)); + __ lea(rdi, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize)); // r9 = loop variable (tagged) // r8 = mapping index (tagged) // r11 = the hole value @@ -2495,9 +2493,8 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { Label arguments_loop, arguments_test; __ movq(r8, rbx); __ movq(rdx, Operand(rsp, 2 * kPointerSize)); - // Untag rcx and r8 for the loop below. + // Untag rcx for the loop below. __ SmiToInteger64(rcx, rcx); - __ SmiToInteger64(r8, r8); __ lea(kScratchRegister, Operand(r8, times_pointer_size, 0)); __ subq(rdx, kScratchRegister); __ jmp(&arguments_test, Label::kNear); @@ -2771,7 +2768,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { kShortExternalStringMask)); STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); __ j(zero, &seq_two_byte_string, Label::kNear); - // Any other flat string must be a flat ascii string. None of the following + // Any other flat string must be a flat ASCII string. None of the following // string type tests will succeed if subject is not a string or a short // external string. __ andb(rbx, Immediate(kIsNotStringMask | @@ -2822,16 +2819,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { Immediate(kStringRepresentationMask | kStringEncodingMask)); STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); __ j(zero, &seq_two_byte_string, Label::kNear); - // Any other flat string must be sequential ascii or external. + // Any other flat string must be sequential ASCII or external. __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), Immediate(kStringRepresentationMask)); __ j(not_zero, &external_string); __ bind(&seq_ascii_string); - // rdi: subject string (sequential ascii) + // rdi: subject string (sequential ASCII) // rax: RegExp data (FixedArray) __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); - __ Set(rcx, 1); // Type is ascii. + __ Set(rcx, 1); // Type is ASCII. __ jmp(&check_code, Label::kNear); __ bind(&seq_two_byte_string); @@ -2847,7 +2844,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ JumpIfSmi(r11, &runtime); // rdi: subject string - // rcx: encoding of subject string (1 if ascii, 0 if two_byte); + // rcx: encoding of subject string (1 if ASCII, 0 if two_byte); // r11: code // Load used arguments before starting to push arguments for call to native // RegExp code to avoid handling changing stack height. @@ -2855,7 +2852,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // rdi: subject string // rbx: previous index - // rcx: encoding of subject string (1 if ascii 0 if two_byte); + // rcx: encoding of subject string (1 if ASCII 0 if two_byte); // r11: code // All checks done. Now push arguments for native regexp code. Counters* counters = masm->isolate()->counters(); @@ -2912,7 +2909,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Keep track on aliasing between argX defined above and the registers used. // rdi: subject string // rbx: previous index - // rcx: encoding of subject string (1 if ascii 0 if two_byte); + // rcx: encoding of subject string (1 if ASCII 0 if two_byte); // r11: code // r14: slice offset // r15: original subject string @@ -3483,7 +3480,7 @@ void CompareStub::Generate(MacroAssembler* masm) { __ JumpIfNotBothSequentialAsciiStrings( rdx, rax, rcx, rbx, &check_unequal_objects); - // Inline comparison of ascii strings. + // Inline comparison of ASCII strings. if (cc_ == equal) { StringCompareStub::GenerateFlatAsciiStringEquals(masm, rdx, @@ -4518,7 +4515,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ SmiCompare(rbx, Smi::FromInt(2)); __ j(not_equal, &longer_than_two); - // Check that both strings are non-external ascii strings. + // Check that both strings are non-external ASCII strings. __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, &call_runtime); @@ -4550,7 +4547,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ bind(&longer_than_two); // Check if resulting string will be flat. - __ SmiCompare(rbx, Smi::FromInt(String::kMinNonFlatLength)); + __ SmiCompare(rbx, Smi::FromInt(ConsString::kMinLength)); __ j(below, &string_add_flat_result); // Handle exceptionally long strings in the runtime system. STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); @@ -4558,7 +4555,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ j(above, &call_runtime); // If result is not supposed to be flat, allocate a cons string object. If - // both strings are ascii the result is an ascii cons string. + // both strings are ASCII the result is an ASCII cons string. // rax: first string // rbx: length of resulting flat string // rdx: second string @@ -4572,7 +4569,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ testl(rcx, Immediate(kStringEncodingMask)); __ j(zero, &non_ascii); __ bind(&ascii_data); - // Allocate an acsii cons string. + // Allocate an ASCII cons string. __ AllocateAsciiConsString(rcx, rdi, no_reg, &call_runtime); __ bind(&allocated); // Fill the fields of the cons string. @@ -4586,7 +4583,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ ret(2 * kPointerSize); __ bind(&non_ascii); // At least one of the strings is two-byte. Check whether it happens - // to contain only ascii characters. + // to contain only ASCII characters. // rcx: first instance type AND second instance type. // r8: first instance type. // r9: second instance type. @@ -4602,7 +4599,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ jmp(&allocated); // We cannot encounter sliced strings or cons strings here since: - STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); + STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); // Handle creating a flat result from either external or sequential strings. // Locate the first characters' locations. // rax: first string @@ -4660,7 +4657,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ j(zero, &non_ascii_string_add_flat_result); __ bind(&make_flat_ascii_string); - // Both strings are ascii strings. As they are short they are both flat. + // Both strings are ASCII strings. As they are short they are both flat. __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime); // rax: result string // Locate first character of result. @@ -4677,7 +4674,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ ret(2 * kPointerSize); __ bind(&non_ascii_string_add_flat_result); - // Both strings are ascii strings. As they are short they are both flat. + // Both strings are ASCII strings. As they are short they are both flat. __ AllocateTwoByteString(rax, rbx, rdi, r8, r9, &call_runtime); // rax: result string // Locate first character of result. @@ -4931,7 +4928,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly Register temp = kScratchRegister; - // Check that the candidate is a non-external ascii string. + // Check that the candidate is a non-external ASCII string. __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset)); __ JumpIfInstanceTypeIsNotSequentialAscii( temp, temp, &next_probe[i]); @@ -5411,7 +5408,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) { // Check that both are sequential ASCII strings. __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); - // Inline comparison of ascii strings. + // Inline comparison of ASCII strings. __ IncrementCounter(counters->string_compare_native(), 1); // Drop arguments from the stack __ pop(rcx); diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index eeef0e94e8..4387a321a2 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -106,7 +106,7 @@ class JumpPatchSite BASE_EMBEDDED { // formal parameter count expected by the function. // // The live registers are: -// o rdi: the JS function object being called (ie, ourselves) +// o rdi: the JS function object being called (i.e. ourselves) // o rsi: our context // o rbp: our caller's frame pointer // o rsp: stack pointer (pointing to return address) @@ -226,9 +226,15 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // function, receiver address, parameter count. // The stub will rewrite receiver and parameter count if the previous // stack frame was an arguments adapter frame. - ArgumentsAccessStub stub( - is_classic_mode() ? ArgumentsAccessStub::NEW_NON_STRICT_SLOW - : ArgumentsAccessStub::NEW_STRICT); + ArgumentsAccessStub::Type type; + if (!is_classic_mode()) { + type = ArgumentsAccessStub::NEW_STRICT; + } else if (function()->has_duplicate_parameters()) { + type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; + } else { + type = ArgumentsAccessStub::NEW_NON_STRICT_FAST; + } + ArgumentsAccessStub stub(type); __ CallStub(&stub); SetVar(arguments, rax, rbx, rdx); @@ -3530,7 +3536,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // One-character separator case __ bind(&one_char_separator); - // Get the separator ascii character value. + // Get the separator ASCII character value. // Register "string" holds the separator. __ movzxbl(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize)); __ Set(index, 0); diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc index 020446008f..8dca1e1644 100644 --- a/deps/v8/src/x64/ic-x64.cc +++ b/deps/v8/src/x64/ic-x64.cc @@ -462,23 +462,43 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ movl(rdi, FieldOperand(rax, String::kHashFieldOffset)); __ shr(rdi, Immediate(String::kHashShift)); __ xor_(rcx, rdi); - __ and_(rcx, Immediate(KeyedLookupCache::kCapacityMask)); + int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); + __ and_(rcx, Immediate(mask)); // Load the key (consisting of map and symbol) from the cache and // check for match. + Label try_second_entry, hit_on_first_entry, load_in_object_property; ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys(masm->isolate()); __ movq(rdi, rcx); __ shl(rdi, Immediate(kPointerSizeLog2 + 1)); __ LoadAddress(kScratchRegister, cache_keys); __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, 0)); - __ j(not_equal, &slow); + __ j(not_equal, &try_second_entry); __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, kPointerSize)); + __ j(equal, &hit_on_first_entry); + + __ bind(&try_second_entry); + __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, kPointerSize * 2)); + __ j(not_equal, &slow); + __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, kPointerSize * 3)); __ j(not_equal, &slow); // Get field offset, which is a 32-bit integer. ExternalReference cache_field_offsets = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate()); + + // Hit on second entry. + __ LoadAddress(kScratchRegister, cache_field_offsets); + __ addl(rcx, Immediate(1)); + __ movl(rdi, Operand(kScratchRegister, rcx, times_4, 0)); + __ movzxbq(rcx, FieldOperand(rbx, Map::kInObjectPropertiesOffset)); + __ subq(rdi, rcx); + __ j(above_equal, &property_array_property); + __ jmp(&load_in_object_property); + + // Hit on first entry. + __ bind(&hit_on_first_entry); __ LoadAddress(kScratchRegister, cache_field_offsets); __ movl(rdi, Operand(kScratchRegister, rcx, times_4, 0)); __ movzxbq(rcx, FieldOperand(rbx, Map::kInObjectPropertiesOffset)); @@ -486,6 +506,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ j(above_equal, &property_array_property); // Load in-object property. + __ bind(&load_in_object_property); __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset)); __ addq(rcx, rdi); __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0)); diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index 392c74dc23..e051214773 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -2142,7 +2142,7 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, Handle name) { LookupResult lookup(isolate()); type->LookupInDescriptors(NULL, *name, &lookup); - ASSERT(lookup.IsProperty() && + ASSERT(lookup.IsFound() && (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); if (lookup.type() == FIELD) { int index = lookup.GetLocalFieldIndexFromMap(*type); @@ -2565,7 +2565,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { RecordPosition(pointers->position()); SafepointGenerator safepoint_generator( this, pointers, Safepoint::kLazyDeopt); - v8::internal::ParameterCount actual(rax); + ParameterCount actual(rax); __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator, CALL_AS_METHOD); __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); @@ -2615,35 +2615,48 @@ void LCodeGen::CallKnownFunction(Handle function, int arity, LInstruction* instr, CallKind call_kind) { - // Change context if needed. - bool change_context = - (info()->closure()->context() != function->context()) || - scope()->contains_with() || - (scope()->num_heap_slots() > 0); - if (change_context) { - __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); - } - - // Set rax to arguments count if adaption is not needed. Assumes that rax - // is available to write to at this point. - if (!function->NeedsArgumentsAdaption()) { - __ Set(rax, arity); - } + bool can_invoke_directly = !function->NeedsArgumentsAdaption() || + function->shared()->formal_parameter_count() == arity; LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); - // Invoke function. - __ SetCallKind(rcx, call_kind); - if (*function == *info()->closure()) { - __ CallSelf(); + if (can_invoke_directly) { + __ LoadHeapObject(rdi, function); + + // Change context if needed. + bool change_context = + (info()->closure()->context() != function->context()) || + scope()->contains_with() || + (scope()->num_heap_slots() > 0); + if (change_context) { + __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); + } + + // Set rax to arguments count if adaption is not needed. Assumes that rax + // is available to write to at this point. + if (!function->NeedsArgumentsAdaption()) { + __ Set(rax, arity); + } + + // Invoke function. + __ SetCallKind(rcx, call_kind); + if (*function == *info()->closure()) { + __ CallSelf(); + } else { + __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset)); + } + + // Set up deoptimization. + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); } else { - __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset)); + // We need to adapt arguments. + SafepointGenerator generator( + this, pointers, Safepoint::kLazyDeopt); + ParameterCount count(arity); + __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind); } - // Set up deoptimization. - RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); - // Restore context. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); } @@ -2651,7 +2664,6 @@ void LCodeGen::CallKnownFunction(Handle function, void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { ASSERT(ToRegister(instr->result()).is(rax)); - __ LoadHeapObject(rdi, instr->function()); CallKnownFunction(instr->function(), instr->arity(), instr, @@ -2950,6 +2962,7 @@ void LCodeGen::DoRandom(LRandom* instr) { __ movq(global_object, FieldOperand(global_object, GlobalObject::kGlobalContextOffset)); __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); + __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); // Convert 32 random bits in rax to 0.(32 random bits) in a double // by computing: @@ -3094,7 +3107,6 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { ASSERT(ToRegister(instr->result()).is(rax)); - __ LoadHeapObject(rdi, instr->target()); CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); } diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index 47553697ae..2d6bd08139 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -2114,7 +2114,7 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings( movzxbl(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); movzxbl(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); - // Check that both are flat ascii strings. + // Check that both are flat ASCII strings. ASSERT(kNotStringTag != 0); const int kFlatAsciiStringMask = kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; @@ -2160,7 +2160,7 @@ void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii( movq(scratch1, first_object_instance_type); movq(scratch2, second_object_instance_type); - // Check that both are flat ascii strings. + // Check that both are flat ASCII strings. ASSERT(kNotStringTag != 0); const int kFlatAsciiStringMask = kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; @@ -3030,26 +3030,30 @@ void MacroAssembler::InvokeCode(Register code, ASSERT(flag == JUMP_FUNCTION || has_frame()); Label done; + bool definitely_mismatches = false; InvokePrologue(expected, actual, Handle::null(), code, &done, + &definitely_mismatches, flag, Label::kNear, call_wrapper, call_kind); - if (flag == CALL_FUNCTION) { - call_wrapper.BeforeCall(CallSize(code)); - SetCallKind(rcx, call_kind); - call(code); - call_wrapper.AfterCall(); - } else { - ASSERT(flag == JUMP_FUNCTION); - SetCallKind(rcx, call_kind); - jmp(code); + if (!definitely_mismatches) { + if (flag == CALL_FUNCTION) { + call_wrapper.BeforeCall(CallSize(code)); + SetCallKind(rcx, call_kind); + call(code); + call_wrapper.AfterCall(); + } else { + ASSERT(flag == JUMP_FUNCTION); + SetCallKind(rcx, call_kind); + jmp(code); + } + bind(&done); } - bind(&done); } @@ -3064,27 +3068,31 @@ void MacroAssembler::InvokeCode(Handle code, ASSERT(flag == JUMP_FUNCTION || has_frame()); Label done; + bool definitely_mismatches = false; Register dummy = rax; InvokePrologue(expected, actual, code, dummy, &done, + &definitely_mismatches, flag, Label::kNear, call_wrapper, call_kind); - if (flag == CALL_FUNCTION) { - call_wrapper.BeforeCall(CallSize(code)); - SetCallKind(rcx, call_kind); - Call(code, rmode); - call_wrapper.AfterCall(); - } else { - ASSERT(flag == JUMP_FUNCTION); - SetCallKind(rcx, call_kind); - Jump(code, rmode); + if (!definitely_mismatches) { + if (flag == CALL_FUNCTION) { + call_wrapper.BeforeCall(CallSize(code)); + SetCallKind(rcx, call_kind); + Call(code, rmode); + call_wrapper.AfterCall(); + } else { + ASSERT(flag == JUMP_FUNCTION); + SetCallKind(rcx, call_kind); + Jump(code, rmode); + } + bind(&done); } - bind(&done); } @@ -3136,11 +3144,13 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, Handle code_constant, Register code_register, Label* done, + bool* definitely_mismatches, InvokeFlag flag, Label::Distance near_jump, const CallWrapper& call_wrapper, CallKind call_kind) { bool definitely_matches = false; + *definitely_mismatches = false; Label invoke; if (expected.is_immediate()) { ASSERT(actual.is_immediate()); @@ -3156,6 +3166,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, // arguments. definitely_matches = true; } else { + *definitely_mismatches = true; Set(rbx, expected.immediate()); } } @@ -3192,7 +3203,9 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, SetCallKind(rcx, call_kind); Call(adaptor, RelocInfo::CODE_TARGET); call_wrapper.AfterCall(); - jmp(done, near_jump); + if (!*definitely_mismatches) { + jmp(done, near_jump); + } } else { SetCallKind(rcx, call_kind); Jump(adaptor, RelocInfo::CODE_TARGET); @@ -3825,7 +3838,7 @@ void MacroAssembler::AllocateAsciiString(Register result, subq(scratch1, Immediate(kHeaderAlignment)); } - // Allocate ascii string in new space. + // Allocate ASCII string in new space. AllocateInNewSpace(SeqAsciiString::kHeaderSize, times_1, scratch1, diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index 8596852db4..aad76bc102 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -203,7 +203,7 @@ class MacroAssembler: public Assembler { Label* on_black, Label::Distance on_black_distance = Label::kFar); - // Detects conservatively whether an object is data-only, ie it does need to + // Detects conservatively whether an object is data-only, i.e. it does need to // be scanned by the garbage collector. void JumpIfDataObject(Register value, Register scratch, @@ -745,7 +745,7 @@ class MacroAssembler: public Assembler { Label* on_not_both_flat_ascii, Label::Distance near_jump = Label::kFar); - // Check whether the instance type represents a flat ascii string. Jump to the + // Check whether the instance type represents a flat ASCII string. Jump to the // label if not. If the instance type can be scratched specify same register // for both instance type and scratch. void JumpIfInstanceTypeIsNotSequentialAscii( @@ -901,7 +901,7 @@ class MacroAssembler: public Assembler { // Check if the map of an object is equal to a specified map and branch to // label if not. Skip the smi check if not required (object is known to be a // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match - // against maps that are ElementsKind transition maps of the specificed map. + // against maps that are ElementsKind transition maps of the specified map. void CheckMap(Register obj, Handle map, Label* fail, @@ -1309,6 +1309,7 @@ class MacroAssembler: public Assembler { Handle code_constant, Register code_register, Label* done, + bool* definitely_mismatches, InvokeFlag flag, Label::Distance near_jump = Label::kFar, const CallWrapper& call_wrapper = NullCallWrapper(), diff --git a/deps/v8/src/x64/regexp-macro-assembler-x64.cc b/deps/v8/src/x64/regexp-macro-assembler-x64.cc index 1e0cd6a38c..16730d21bf 100644 --- a/deps/v8/src/x64/regexp-macro-assembler-x64.cc +++ b/deps/v8/src/x64/regexp-macro-assembler-x64.cc @@ -226,7 +226,7 @@ void RegExpMacroAssemblerX64::CheckCharacters(Vector str, bool check_end_of_string) { #ifdef DEBUG // If input is ASCII, don't even bother calling here if the string to - // match contains a non-ascii character. + // match contains a non-ASCII character. if (mode_ == ASCII) { ASSERT(String::IsAscii(str.start(), str.length())); } diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index 3633fbbcee..a6e1b833c1 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -982,7 +982,7 @@ void StubCompiler::GenerateLoadCallback(Handle object, __ movq(name_arg, rsp); __ push(scratch2); // Restore return address. - // 3 elements array for v8::Agruments::values_ and handler for name. + // 3 elements array for v8::Arguments::values_ and handler for name. const int kStackSpace = 4; // Allocate v8::AccessorInfo in non-GCed stack space. @@ -1045,7 +1045,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle object, // and CALLBACKS, so inline only them, other cases may be added // later. bool compile_followup_inline = false; - if (lookup->IsProperty() && lookup->IsCacheable()) { + if (lookup->IsFound() && lookup->IsCacheable()) { if (lookup->type() == FIELD) { compile_followup_inline = true; } else if (lookup->type() == CALLBACKS && diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index d001e65263..8525f3876b 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -8912,17 +8912,6 @@ THREADED_TEST(InterceptorCallICInvalidatedCacheable) { } -static v8::Handle call_ic_function5; -static v8::Handle InterceptorCallICGetter5(Local name, - const AccessorInfo& info) { - ApiTestFuzzer::Fuzz(); - if (v8_str("x")->Equals(name)) - return call_ic_function5; - else - return Local(); -} - - // This test checks that if interceptor doesn't provide a function, // cached constant function is used THREADED_TEST(InterceptorCallICConstantFunctionUsed) { @@ -8943,6 +8932,17 @@ THREADED_TEST(InterceptorCallICConstantFunctionUsed) { } +static v8::Handle call_ic_function5; +static v8::Handle InterceptorCallICGetter5(Local name, + const AccessorInfo& info) { + ApiTestFuzzer::Fuzz(); + if (v8_str("x")->Equals(name)) + return call_ic_function5; + else + return Local(); +} + + // This test checks that if interceptor provides a function, // even if we cached constant function, interceptor's function // is invoked @@ -8966,6 +8966,48 @@ THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) { } +static v8::Handle call_ic_function6; +static v8::Handle InterceptorCallICGetter6(Local name, + const AccessorInfo& info) { + ApiTestFuzzer::Fuzz(); + if (v8_str("x")->Equals(name)) + return call_ic_function6; + else + return Local(); +} + + +// Same test as above, except the code is wrapped in a function +// to test the optimized compiler. +THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) { + i::FLAG_allow_natives_syntax = true; + v8::HandleScope scope; + v8::Handle templ = ObjectTemplate::New(); + templ->SetNamedPropertyHandler(InterceptorCallICGetter6); + LocalContext context; + context->Global()->Set(v8_str("o"), templ->NewInstance()); + call_ic_function6 = + v8_compile("function f(x) { return x - 1; }; f")->Run(); + v8::Handle value = CompileRun( + "function inc(x) { return x + 1; };" + "inc(1);" + "o.x = inc;" + "function test() {" + " var result = 0;" + " for (var i = 0; i < 1000; i++) {" + " result = o.x(42);" + " }" + " return result;" + "};" + "test();" + "test();" + "test();" + "%OptimizeFunctionOnNextCall(test);" + "test()"); + CHECK_EQ(41, value->Int32Value()); +} + + // Test the case when we stored constant function into // a stub, but it got invalidated later on THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) { @@ -13725,6 +13767,10 @@ TEST(VisitExternalStrings) { TestResource* resource2 = new TestResource(two_byte_string); v8::Local string2 = v8::String::NewExternal(resource2); + // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7 + CHECK(string1->IsExternal()); + CHECK(string2->IsExternal()); + VisitorImpl visitor(resource1, resource2); v8::V8::VisitExternalResources(&visitor); visitor.CheckVisitedResources(); diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index 1e4e332b4e..eb5f3c605e 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -1572,3 +1572,57 @@ TEST(InstanceOfStubWriteBarrier) { HEAP->incremental_marking()->set_should_hurry(true); HEAP->CollectGarbage(OLD_POINTER_SPACE); } + + +TEST(PrototypeTransitionClearing) { + InitializeVM(); + v8::HandleScope scope; + + CompileRun( + "var base = {};" + "var live = [];" + "for (var i = 0; i < 10; i++) {" + " var object = {};" + " var prototype = {};" + " object.__proto__ = prototype;" + " if (i >= 3) live.push(object, prototype);" + "}"); + + Handle baseObject = + v8::Utils::OpenHandle( + *v8::Handle::Cast( + v8::Context::GetCurrent()->Global()->Get(v8_str("base")))); + + // Verify that only dead prototype transitions are cleared. + CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions()); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + CHECK_EQ(10 - 3, baseObject->map()->NumberOfProtoTransitions()); + + // Verify that prototype transitions array was compacted. + FixedArray* trans = baseObject->map()->prototype_transitions(); + for (int i = 0; i < 10 - 3; i++) { + int j = Map::kProtoTransitionHeaderSize + + i * Map::kProtoTransitionElementsPerEntry; + CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap()); + CHECK(trans->get(j + Map::kProtoTransitionPrototypeOffset)->IsJSObject()); + } + + // Make sure next prototype is placed on an old-space evacuation candidate. + Handle prototype; + PagedSpace* space = HEAP->old_pointer_space(); + do { + prototype = FACTORY->NewJSArray(32 * KB, TENURED); + } while (space->FirstPage() == space->LastPage() || + !space->LastPage()->Contains(prototype->address())); + + // Add a prototype on an evacuation candidate and verify that transition + // clearing correctly records slots in prototype transition array. + i::FLAG_always_compact = true; + Handle map(baseObject->map()); + CHECK(!space->LastPage()->Contains(map->prototype_transitions()->address())); + CHECK(space->LastPage()->Contains(prototype->address())); + baseObject->SetPrototype(*prototype, false)->ToObjectChecked(); + CHECK(map->GetPrototypeTransition(*prototype)->IsMap()); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + CHECK(map->GetPrototypeTransition(*prototype)->IsMap()); +} diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index 93f7588d36..e11349bc85 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -355,7 +355,7 @@ TEST(ExternalShortStringAdd) { // Make sure we cover all always-flat lengths and at least one above. static const int kMaxLength = 20; - CHECK_GT(kMaxLength, i::String::kMinNonFlatLength); + CHECK_GT(kMaxLength, i::ConsString::kMinLength); // Allocate two JavaScript arrays for holding short strings. v8::Handle ascii_external_strings = diff --git a/deps/v8/test/mjsunit/harmony/proxies-function.js b/deps/v8/test/mjsunit/harmony/proxies-function.js index 3f5ace676d..6b8d098442 100644 --- a/deps/v8/test/mjsunit/harmony/proxies-function.js +++ b/deps/v8/test/mjsunit/harmony/proxies-function.js @@ -611,6 +611,22 @@ TestAccessorCall( +// Passing a proxy function to higher-order library functions. + +function TestHigherOrder(f) { + assertEquals(6, [6, 2].map(f)[0]) + assertEquals(4, [5, 2].reduce(f, 4)) + assertTrue([1, 2].some(f)) + assertEquals("a.b.c", "a.b.c".replace(".", f)) +} + +TestHigherOrder(function(x) { return x }) +TestHigherOrder(function(x) { "use strict"; return x }) +TestHigherOrder(Proxy.createFunction({}, function(x) { return x })) +TestHigherOrder(CreateFrozen({}, function(x) { return x })) + + + // TODO(rossberg): Ultimately, I want to have the following test function // run through, but it currently fails on so many cases (some not even // involving proxies), that I leave that for later... diff --git a/deps/v8/src/extensions/experimental/i18n-natives.h b/deps/v8/test/mjsunit/regress/regress-110509.js similarity index 77% rename from deps/v8/src/extensions/experimental/i18n-natives.h rename to deps/v8/test/mjsunit/regress/regress-110509.js index 37362d0ddc..132bd233be 100644 --- a/deps/v8/src/extensions/experimental/i18n-natives.h +++ b/deps/v8/test/mjsunit/regress/regress-110509.js @@ -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: @@ -25,19 +25,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_EXTENSIONS_EXPERIMENTAL_I18N_NATIVES_H_ -#define V8_EXTENSIONS_EXPERIMENTAL_I18N_NATIVES_H_ +// Flags: --allow-natives-syntax -namespace v8 { -namespace internal { +// Verify that LRandom preserves rsi correctly. -class I18Natives { - public: - // Gets script source from generated file. - // Source is statically allocated string. - static const char* GetScriptSource(); -}; +function foo() { + Math.random(); + new Function(""); +} -} } // namespace v8::internal - -#endif // V8_EXTENSIONS_EXPERIMENTAL_I18N_NATIVES_H_ +foo(); +foo(); +foo(); +%OptimizeFunctionOnNextCall(foo); +foo(); diff --git a/deps/v8/test/mjsunit/string-replace-one-char.js b/deps/v8/test/mjsunit/string-replace-one-char.js new file mode 100644 index 0000000000..f153acc0ab --- /dev/null +++ b/deps/v8/test/mjsunit/string-replace-one-char.js @@ -0,0 +1,92 @@ +// 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Make sure the strings are long enough to trigger the one-char string replace. +var prefix1024 = "0123456789ABCDEF"; +for (var i = 0; i < 6; i++) prefix1024 += prefix1024; + +function test_replace(result, expected, search, replace) { + assertEquals(expected, result.replace(search, replace)); +} + +// '$' in the replace string. +test_replace(prefix1024 + "abcdefghijklmnopqrstuvwxyz", + prefix1024 + "abcdefghijk#l#mnopqrstuvwxyz", + "l", "#$&#"); + +test_replace(prefix1024 + "abcdefghijklmnopqrstuvwxyz\u1234", + prefix1024 + "abcdefghijk\u2012l\u2012mnopqrstuvwxyz\u1234", + "l", "\u2012$&\u2012"); + +test_replace(prefix1024 + "abcdefghijklmnopqrstuvwxyz", + prefix1024 + "abcdefghijk$mnopqrstuvwxyz", + "l", "$$"); + +test_replace(prefix1024 + "abcdefghijklmnopqrstuvwxyz\u1234", + prefix1024 + "abcdefghijk$mnopqrstuvwxyz\u1234", + "l", "$$"); + +// Zero length replace string. +test_replace(prefix1024 + "abcdefghijklmnopqrstuvwxyz", + prefix1024 + "abcdefghijklmnopqstuvwxyz", + "r", ""); + +test_replace(prefix1024 + "abcdefghijklmnopq\u1234stuvwxyz", + prefix1024 + "abcdefghijklmnopqstuvwxyz", + "\u1234", ""); + +// Search char not found. +var not_found_1 = prefix1024 + "abcdefghijklmnopqrstuvwxyz"; +test_replace(not_found_1, not_found_1, "+", "-"); + +var not_found_2 = prefix1024 + "abcdefghijklm\u1234nopqrstuvwxyz"; +test_replace(not_found_2, not_found_2, "+", "---"); + +var not_found_3 = prefix1024 + "abcdefghijklmnopqrstuvwxyz"; +test_replace(not_found_3, not_found_3, "\u1234", "ZZZ"); + +// Deep cons tree. +var nested_1 = ""; +for (var i = 0; i < 1000000; i++) nested_1 += "y"; +var nested_1_result = prefix1024 + nested_1 + "aa"; +nested_1 = prefix1024 + nested_1 + "z"; +test_replace(nested_1, nested_1_result, "z", "aa"); + +var nested_2 = "\u2244"; +for (var i = 0; i < 1000000; i++) nested_2 += "y"; +var nested_2_result = prefix1024 + nested_2 + "aa"; +nested_2 = prefix1024 + nested_2 + "\u2012"; +test_replace(nested_2, nested_2_result, "\u2012", "aa"); + +// Sliced string as input. A cons string is always flattened before sliced. +var slice_1 = ("ab" + prefix1024 + "cdefghijklmnopqrstuvwxyz").slice(1, -1); +var slice_1_result = "b" + prefix1024 + "cdefghijklmnopqrstuvwxQ"; +test_replace(slice_1, slice_1_result, "y", "Q"); + +var slice_2 = (prefix1024 + "abcdefghijklmno\u1234\u1234p").slice(1, -1); +var slice_2_result = prefix1024.substr(1) + "abcdefghijklmnoQ\u1234"; +test_replace(slice_2, slice_2_result, "\u1234", "Q"); diff --git a/deps/v8/tools/presubmit.py b/deps/v8/tools/presubmit.py index 7af6e3d0d8..a5f4c614d0 100755 --- a/deps/v8/tools/presubmit.py +++ b/deps/v8/tools/presubmit.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# 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: @@ -42,6 +42,7 @@ import pickle import re import sys import subprocess +import multiprocessing from subprocess import PIPE # Disabled LINT rules and reason. @@ -101,6 +102,33 @@ whitespace/todo """.split() +LINT_OUTPUT_PATTERN = re.compile(r'^.+[:(]\d+[:)]|^Done processing') + + +def CppLintWorker(command): + try: + process = subprocess.Popen(command, stderr=subprocess.PIPE) + process.wait() + out_lines = "" + error_count = -1 + while True: + out_line = process.stderr.readline() + if out_line == '' and process.poll() != None: + break + m = LINT_OUTPUT_PATTERN.match(out_line) + if m: + out_lines += out_line + error_count += 1 + sys.stderr.write(out_lines) + return error_count + except KeyboardInterrupt: + process.kill() + except: + print('Error running cpplint.py. Please make sure you have depot_tools' + + ' in your $PATH. Lint check skipped.') + process.kill() + + class FileContentsCache(object): def __init__(self, sums_file_name): @@ -206,29 +234,28 @@ class CppLintProcessor(SourceFileProcessor): return True filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES]) - command = ['cpplint.py', '--filter', filt] + join(files) + command = ['cpplint.py', '--filter', filt] local_cpplint = join(path, "tools", "cpplint.py") if exists(local_cpplint): - command = ['python', local_cpplint, '--filter', filt] + join(files) + command = ['python', local_cpplint, '--filter', filt] + commands = join([command + [file] for file in files]) + count = multiprocessing.cpu_count() + pool = multiprocessing.Pool(count) try: - process = subprocess.Popen(command, stderr=subprocess.PIPE) - except: - print('Error running cpplint.py. Please make sure you have depot_tools' + - ' in your $PATH. Lint check skipped.') - return True - LINT_ERROR_PATTERN = re.compile(r'^(.+)[:(]\d+[:)]') - while True: - out_line = process.stderr.readline() - if out_line == '' and process.poll() != None: - break - sys.stderr.write(out_line) - m = LINT_ERROR_PATTERN.match(out_line) - if m: - good_files_cache.RemoveFile(m.group(1)) + results = pool.map_async(CppLintWorker, commands).get(999999) + except KeyboardInterrupt: + print "\nCaught KeyboardInterrupt, terminating workers." + sys.exit(1) + + for i in range(len(files)): + if results[i] > 0: + good_files_cache.RemoveFile(files[i]) + total_errors = sum(results) + print "Total errors found: %d" % total_errors good_files_cache.Save() - return process.returncode == 0 + return total_errors == 0 COPYRIGHT_HEADER_PATTERN = re.compile( diff --git a/doc/index.html b/doc/index.html index 3769002f91..c7526beff7 100644 --- a/doc/index.html +++ b/doc/index.html @@ -77,15 +77,15 @@ X