diff options
213 files changed, 5390 insertions, 2908 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 2deff90808..d3e0dc642a 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,46 @@ +2011-09-07: Version 3.6.1 + + Fixed a bug in abrupt exit from with or catch inside finally. + + Fixed possible crash in FixedDoubleArray::Initialize() (Chromium + issue 95113). + + Fixed a bug in Page::GetRegionMaskForSpan (Chromium issue 94425). + + Fixed a few clang warnings (which -Werror treated as errors). + + Performance improvements on all platforms. + + +2011-09-05: Version 3.6.0 + + Fixed a bug when optimizing named function expression (issue 1647). + + Fixed a bug when optimizing f.call.apply (issue 1650). + + Made arguments and caller always be null on native functions + (issues 1548 and 1643). + + Fixed issue 1648 (cross-compiling x64 targeting ia32). + + Fixed issue 371 (d8 printing of strings containing \0). + + Fixed order of evaluation in arguments to parseInt (issue 1649). + + Fixed a problem with large heap snapshots in Chrome DevTools + (issue 1658, chromium issue 89268). + + Upped default maximum heap size from 512M to 700M. + + +2011-08-31: Version 3.5.10 + + Added dependency of v8_base on WinSocket2 Windows library in + the GYP-build. + + Various bugfixes. + + 2011-08-29: Version 3.5.9 Made FromPropertyDescriptor not trigger inherited setters. diff --git a/deps/v8/Makefile b/deps/v8/Makefile index 3008779bb3..618bbef1d0 100644 --- a/deps/v8/Makefile +++ b/deps/v8/Makefile @@ -98,8 +98,9 @@ CHECKS = $(addsuffix .check,$(BUILDS)) # File where previously used GYPFLAGS are stored. ENVFILE = $(OUTDIR)/environment -.PHONY: all clean $(ENVFILE).new \ - $(ARCHES) $(MODES) $(BUILDS) $(addsuffix .clean,$(ARCHES)) +.PHONY: all check clean $(ENVFILE).new \ + $(ARCHES) $(MODES) $(BUILDS) $(CHECKS) $(addsuffix .clean,$(ARCHES)) \ + $(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES)) # Target definitions. "all" is the default. all: $(MODES) diff --git a/deps/v8/benchmarks/crypto.js b/deps/v8/benchmarks/crypto.js index ffa69b53bb..531ad456e0 100644 --- a/deps/v8/benchmarks/crypto.js +++ b/deps/v8/benchmarks/crypto.js @@ -1406,7 +1406,7 @@ function rng_seed_int(x) { // Mix in the current time (w/milliseconds) into the pool function rng_seed_time() { - // Use pre-computed date to avoid making the benchmark + // Use pre-computed date to avoid making the benchmark // results dependent on the current date. rng_seed_int(1122926989487); } diff --git a/deps/v8/benchmarks/earley-boyer.js b/deps/v8/benchmarks/earley-boyer.js index 1be480e8ee..b2328d6ba1 100644 --- a/deps/v8/benchmarks/earley-boyer.js +++ b/deps/v8/benchmarks/earley-boyer.js @@ -134,7 +134,7 @@ function sc_rempropBang(sym, key) { /*** META ((export #t)) */ function sc_any2String(o) { return jsstring2string(sc_toDisplayString(o)); -} +} /*** META ((export #t) (peephole (infix 2 2 "===")) @@ -923,7 +923,7 @@ function sc_dualAppendBang(l1, l2) { tmp.cdr = l2; return l1; } - + /*** META ((export #t)) */ function sc_appendBang() { var res = null; @@ -1163,7 +1163,7 @@ sc_Char.readable2char = { "us": "\037", "sp": "\040", "del": "\177"}; - + sc_Char.prototype.toString = function() { return this.val; }; @@ -1533,7 +1533,7 @@ function sc_mapBang(proc, l1) { } return l1_orig; } - + /*** META ((export #t)) */ function sc_forEach(proc, l1) { if (l1 === undefined) @@ -1871,7 +1871,7 @@ function sc_jsNew(c) { evalStr += ", arguments[" + i + "]"; evalStr +=")"; return eval(evalStr); -} +} // ======================== RegExp ==================== /*** META ((export #t)) */ @@ -1883,9 +1883,9 @@ function sc_pregexp(re) { function sc_pregexpMatch(re, s) { var reg = (re instanceof RegExp) ? re : sc_pregexp(re); var tmp = reg.exec(sc_string2jsstring(s)); - + if (tmp == null) return false; - + var res = null; for (var i = tmp.length-1; i >= 0; i--) { if (tmp[i] !== null) { @@ -1896,7 +1896,7 @@ function sc_pregexpMatch(re, s) { } return res; } - + /*** META ((export #t)) */ function sc_pregexpReplace(re, s1, s2) { var reg; @@ -1914,7 +1914,7 @@ function sc_pregexpReplace(re, s1, s2) { return jss1.replace(reg, jss2); } - + /*** META ((export pregexp-replace*)) */ function sc_pregexpReplaceAll(re, s1, s2) { var reg; @@ -1945,7 +1945,7 @@ function sc_pregexpSplit(re, s) { return sc_vector2list(tmp); } - + /* =========================================================================== */ /* Other library stuff */ @@ -2136,7 +2136,7 @@ sc_ErrorInputPort.prototype.getNextChar = function() { sc_ErrorInputPort.prototype.isCharReady = function() { return false; }; - + /* .............. String port ..........................*/ @@ -2200,7 +2200,7 @@ sc_Tokenizer.prototype.readToken = function() { }; sc_Tokenizer.prototype.nextToken = function() { var port = this.port; - + function isNumberChar(c) { return (c >= "0" && c <= "9"); }; @@ -2280,7 +2280,7 @@ sc_Tokenizer.prototype.nextToken = function() { else return new sc_Token(12/*NUMBER*/, res - 0); }; - + function skipWhitespaceAndComments() { var done = false; while (!done) { @@ -2299,7 +2299,7 @@ sc_Tokenizer.prototype.nextToken = function() { } } }; - + function readDot() { if (isWhitespace(port.peekChar())) return new sc_Token(10/*DOT*/); @@ -2429,7 +2429,7 @@ sc_Reader.prototype.read = function() { while (true) { var token = tokenizer.peekToken(); - + switch (token.type) { case 2/*CLOSE_PAR*/: case 4/*CLOSE_BRACE*/: @@ -2491,7 +2491,7 @@ sc_Reader.prototype.read = function() { else throw "bad reference: " + nb; }; - + var tokenizer = this.tokenizer; var token = tokenizer.readToken(); @@ -2499,7 +2499,7 @@ sc_Reader.prototype.read = function() { // handle error if (token.type === 13/*ERROR*/) throw token.val; - + switch (token.type) { case 1/*OPEN_PAR*/: case 3/*OPEN_BRACE*/: @@ -2550,7 +2550,7 @@ function sc_peekChar(port) { port = SC_DEFAULT_IN; // THREAD: shared var... var t = port.peekChar(); return t === SC_EOF_OBJECT? t: new sc_Char(t); -} +} /*** META ((export #t) (type bool)) */ @@ -2722,7 +2722,7 @@ sc_StringOutputPort.prototype.close = function() { function sc_getOutputString(sp) { return sc_jsstring2string(sp.res); } - + function sc_ErrorOutputPort() { } @@ -2852,7 +2852,7 @@ function sc_newline(p) { p = SC_DEFAULT_OUT; p.appendJSString("\n"); } - + /* ------------------ write-char ---------------------------------------------------*/ /*** META ((export #t)) */ @@ -2927,7 +2927,7 @@ sc_Pair.prototype.sc_toWriteCircleString = function(symb, inList) { } var res = ""; - + if (this[symb] !== undefined) { // implies > 0 this[symb + "use"] = true; if (inList) @@ -2939,10 +2939,10 @@ sc_Pair.prototype.sc_toWriteCircleString = function(symb, inList) { if (!inList) res += "("; - + // print car res += sc_genToWriteCircleString(this.car, symb); - + if (sc_isPair(this.cdr)) { res += " " + this.cdr.sc_toWriteCircleString(symb, true); } else if (this.cdr !== null) { @@ -3072,7 +3072,7 @@ function sc_format(s, args) { p.appendJSString(arguments[j].toString(2)); i += 2; j++; break; - + case 37: case 110: // %, n @@ -3186,7 +3186,7 @@ function sc_isEqual(o1, o2) { function sc_number2symbol(x, radix) { return sc_SYMBOL_PREFIX + sc_number2jsstring(x, radix); } - + /*** META ((export number->string integer->string)) */ var sc_number2string = sc_number2jsstring; diff --git a/deps/v8/benchmarks/regexp.js b/deps/v8/benchmarks/regexp.js index 71b9e6362c..9c83142266 100644 --- a/deps/v8/benchmarks/regexp.js +++ b/deps/v8/benchmarks/regexp.js @@ -33,7 +33,7 @@ // the popularity of the pages where it occurs and the number of times // it is executed while loading each page. Furthermore the literal // letters in the data are encoded using ROT13 in a way that does not -// affect how the regexps match their input. Finally the strings are +// affect how the regexps match their input. Finally the strings are // scrambled to exercise the regexp engine on different input strings. @@ -47,7 +47,7 @@ function RegExpSetup() { regExpBenchmark = new RegExpBenchmark(); RegExpRun(); // run once to get system initialized } - + function RegExpRun() { regExpBenchmark.run(); } @@ -1759,6 +1759,6 @@ function RegExpBenchmark() { runBlock11(); } } - + this.run = run; } diff --git a/deps/v8/build/all.gyp b/deps/v8/build/all.gyp index 9c0f05c913..4b2fe52989 100644 --- a/deps/v8/build/all.gyp +++ b/deps/v8/build/all.gyp @@ -1,4 +1,4 @@ -# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# Copyright 2011 the V8 project authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -11,13 +11,7 @@ '../preparser/preparser.gyp:*', '../samples/samples.gyp:*', '../src/d8.gyp:d8', - ], - 'conditions': [ - [ 'component!="shared_library"', { - 'dependencies': [ - '../test/cctest/cctest.gyp:*', - ], - }] + '../test/cctest/cctest.gyp:*', ], } ] diff --git a/deps/v8/build/common.gypi b/deps/v8/build/common.gypi index 27fddcf338..9b32608178 100644 --- a/deps/v8/build/common.gypi +++ b/deps/v8/build/common.gypi @@ -173,6 +173,14 @@ }, }, }], + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { + 'conditions': [ + [ 'target_arch=="ia32"', { + 'cflags': [ '-m32' ], + 'ldflags': [ '-m32' ], + }], + ], + }], ], 'configurations': { 'Debug': { @@ -207,7 +215,7 @@ 'cflags': [ '-I/usr/local/include' ], }], ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { - 'cflags': [ '-Wall', '-W', '-Wno-unused-parameter', + 'cflags': [ '-Wall', '-Werror', '-W', '-Wno-unused-parameter', '-Wnon-virtual-dtor' ], }], ], diff --git a/deps/v8/build/standalone.gypi b/deps/v8/build/standalone.gypi index 1442789ad1..cb5e133039 100644 --- a/deps/v8/build/standalone.gypi +++ b/deps/v8/build/standalone.gypi @@ -74,15 +74,11 @@ 'conditions': [ [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { 'target_defaults': { - 'cflags': [ '-Wall', '-W', '-Wno-unused-parameter', + 'cflags': [ '-Wall', '-Werror', '-W', '-Wno-unused-parameter', '-Wnon-virtual-dtor', '-pthread', '-fno-rtti', '-fno-exceptions', '-pedantic' ], 'ldflags': [ '-pthread', ], 'conditions': [ - [ 'target_arch=="ia32"', { - 'cflags': [ '-m32' ], - 'ldflags': [ '-m32' ], - }], [ 'OS=="linux"', { 'cflags': [ '-ansi' ], }], @@ -172,6 +168,7 @@ 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics + 'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES', # -Werror 'GCC_VERSION': '4.2', 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof 'MACOSX_DEPLOYMENT_TARGET': '10.4', # -mmacosx-version-min=10.4 diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 5a781607f7..80193c423a 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -1656,7 +1656,7 @@ class Object : public Value { V8EXPORT bool IsCallable(); /** - * Call an Object as a function if a callback is set by the + * Call an Object as a function if a callback is set by the * ObjectTemplate::SetCallAsFunctionHandler method. */ V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv, @@ -3562,7 +3562,7 @@ class V8EXPORT Context { * // V8 Now no longer locked. * \endcode * - * + * */ class V8EXPORT Unlocker { public: diff --git a/deps/v8/samples/shell.cc b/deps/v8/samples/shell.cc index 8ed9d032aa..b40eca2f7c 100644 --- a/deps/v8/samples/shell.cc +++ b/deps/v8/samples/shell.cc @@ -250,16 +250,14 @@ void RunShell(v8::Handle<v8::Context> context) { static const int kBufferSize = 256; // Enter the execution environment before evaluating any code. v8::Context::Scope context_scope(context); + v8::Local<v8::String> name(v8::String::New("(shell)")); while (true) { char buffer[kBufferSize]; printf("> "); char* str = fgets(buffer, kBufferSize, stdin); if (str == NULL) break; v8::HandleScope handle_scope; - ExecuteString(v8::String::New(str), - v8::String::New("(shell)"), - true, - true); + ExecuteString(v8::String::New(str), name, true, true); } printf("\n"); } diff --git a/deps/v8/src/accessors.cc b/deps/v8/src/accessors.cc index e7d6aa0e8b..f02efa55a2 100644 --- a/deps/v8/src/accessors.cc +++ b/deps/v8/src/accessors.cc @@ -599,6 +599,7 @@ MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) { if (!found_it) return isolate->heap()->undefined_value(); Handle<JSFunction> function(holder, isolate); + if (function->shared()->native()) return isolate->heap()->null_value(); // Find the top invocation of the function by traversing frames. List<JSFunction*> functions(2); for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { @@ -732,6 +733,7 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { bool found_it = false; JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); if (!found_it) return isolate->heap()->undefined_value(); + if (holder->shared()->native()) return isolate->heap()->null_value(); Handle<JSFunction> function(holder, isolate); FrameFunctionIterator it(isolate, no_alloc); diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index 89df079f90..0ec36921ab 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -692,11 +692,11 @@ void Assembler::bind(Label* L) { void Assembler::next(Label* L) { ASSERT(L->is_linked()); int link = target_at(L->pos()); - if (link > 0) { - L->link_to(link); - } else { - ASSERT(link == kEndOfChain); + if (link == kEndOfChain) { L->Unuse(); + } else { + ASSERT(link >= 0); + L->link_to(link); } } diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index 328102bb40..a35380c175 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -138,7 +138,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, __ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset)); // Clear the heap tag on the elements array. - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ sub(scratch1, scratch1, Operand(kHeapObjectTag)); // Initialize the FixedArray and fill it with holes. FixedArray length is @@ -207,7 +207,7 @@ static void AllocateJSArray(MacroAssembler* masm, // Allocate the JSArray object together with space for a FixedArray with the // requested number of elements. __ bind(¬_empty); - ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); __ mov(elements_array_end, Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize)); __ add(elements_array_end, @@ -243,7 +243,7 @@ static void AllocateJSArray(MacroAssembler* masm, FieldMemOperand(result, JSArray::kElementsOffset)); // Clear the heap tag on the elements array. - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ sub(elements_array_storage, elements_array_storage, Operand(kHeapObjectTag)); @@ -255,7 +255,7 @@ static void AllocateJSArray(MacroAssembler* masm, __ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex); ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex)); - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ tst(array_size, array_size); // Length of the FixedArray is the number of pre-allocated elements if // the actual JSArray has length 0 and the size of the JSArray for non-empty @@ -272,7 +272,7 @@ static void AllocateJSArray(MacroAssembler* masm, // result: JSObject // elements_array_storage: elements array element storage // array_size: smi-tagged size of elements array - ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); __ add(elements_array_end, elements_array_storage, Operand(array_size, LSL, kPointerSizeLog2 - kSmiTagSize)); @@ -337,14 +337,14 @@ static void ArrayNativeCode(MacroAssembler* masm, __ bind(&argc_one_or_more); __ cmp(r0, Operand(1)); __ b(ne, &argc_two_or_more); - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ ldr(r2, MemOperand(sp)); // Get the argument from the stack. __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC); __ b(ne, call_generic_code); // Handle construction of an empty array of a certain size. Bail out if size // is too large to actually allocate an elements array. - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize)); __ b(ge, call_generic_code); @@ -571,7 +571,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // Is it a String? __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset)); - ASSERT(kNotStringTag != 0); + STATIC_ASSERT(kNotStringTag != 0); __ tst(r3, Operand(kIsNotStringMask)); __ b(ne, &convert_argument); __ mov(argument, r0); diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index ffe32bc60a..c310da88bc 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -4389,8 +4389,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // a sequential string or an external string. // In the case of a sliced string its offset has to be taken into account. Label cons_string, check_encoding; - STATIC_ASSERT((kConsStringTag < kExternalStringTag)); - STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); + STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); __ cmp(r1, Operand(kExternalStringTag)); __ b(lt, &cons_string); __ b(eq, &runtime); @@ -4487,7 +4487,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // frame. Therefore we have to use fp, which points exactly to two pointer // sizes below the previous sp. (Because creating a new stack frame pushes // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) - __ ldr(r0, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); + __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); // If slice offset is not 0, load the length from the original sliced string. // Argument 4, r3: End of string data // Argument 3, r2: Start of string data @@ -4495,7 +4495,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ add(r9, r8, Operand(r9, LSL, r3)); __ add(r2, r9, Operand(r1, LSL, r3)); - __ ldr(r8, FieldMemOperand(r0, String::kLengthOffset)); + __ ldr(r8, FieldMemOperand(subject, String::kLengthOffset)); __ mov(r8, Operand(r8, ASR, kSmiTagSize)); __ add(r3, r9, Operand(r8, LSL, r3)); @@ -4503,7 +4503,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Already there // Argument 1 (r0): Subject string. - // Already there + __ mov(r0, subject); // Locate the code entry and call it. __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); @@ -4520,12 +4520,12 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Check the result. Label success; - __ cmp(subject, Operand(NativeRegExpMacroAssembler::SUCCESS)); + __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS)); __ b(eq, &success); Label failure; - __ cmp(subject, Operand(NativeRegExpMacroAssembler::FAILURE)); + __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE)); __ b(eq, &failure); - __ cmp(subject, Operand(NativeRegExpMacroAssembler::EXCEPTION)); + __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); // If not exception it can only be retry. Handle that in the runtime system. __ b(ne, &runtime); // Result must now be exception. If there is no pending exception already a @@ -4537,18 +4537,18 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address, isolate))); __ ldr(r0, MemOperand(r2, 0)); - __ cmp(subject, r1); + __ cmp(r0, r1); __ b(eq, &runtime); __ str(r1, MemOperand(r2, 0)); // Clear pending exception. // Check if the exception is a termination. If so, throw as uncatchable. - __ LoadRoot(ip, Heap::kTerminationExceptionRootIndex); - __ cmp(subject, ip); + __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex); + Label termination_exception; __ b(eq, &termination_exception); - __ Throw(subject); // Expects thrown value in r0. + __ Throw(r0); // Expects thrown value in r0. __ bind(&termination_exception); __ ThrowUncatchable(TERMINATION, r0); // Expects thrown value in r0. @@ -4857,8 +4857,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // Handle non-flat strings. __ and_(result_, result_, Operand(kStringRepresentationMask)); - STATIC_ASSERT((kConsStringTag < kExternalStringTag)); - STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); + STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); __ cmp(result_, Operand(kExternalStringTag)); __ b(gt, &sliced_string); __ b(eq, &call_runtime_); @@ -4894,7 +4894,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // Check for 1-byte or 2-byte string. __ bind(&flat_string); - STATIC_ASSERT(kAsciiStringTag != 0); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ tst(result_, Operand(kStringEncodingMask)); __ b(ne, &ascii_string); @@ -5468,11 +5469,6 @@ void SubStringStub::Generate(MacroAssembler* masm) { Register to = r6; Register from = r7; - if (FLAG_string_slices) { - __ nop(0); // Jumping as first instruction would crash the code generation. - __ jmp(&runtime); - } - __ Ldrd(to, from, MemOperand(sp, kToOffset)); STATIC_ASSERT(kFromOffset == kToOffset + 4); STATIC_ASSERT(kSmiTag == 0); @@ -5490,64 +5486,79 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ b(mi, &runtime); // Fail if from > to. // Special handling of sub-strings of length 1 and 2. One character strings // are handled in the runtime system (looked up in the single character - // cache). Two character strings are looked for in the symbol cache. + // cache). Two character strings are looked for in the symbol cache in + // generated code. __ cmp(r2, Operand(2)); __ b(lt, &runtime); - // r2: length - // r3: from index (untaged smi) + // r2: result string length + // r3: from index (untagged smi) // r6 (a.k.a. to): to (smi) // r7 (a.k.a. from): from offset (smi) - // Make sure first argument is a sequential (or flat) string. - __ ldr(r5, MemOperand(sp, kStringOffset)); + __ ldr(r0, MemOperand(sp, kStringOffset)); STATIC_ASSERT(kSmiTag == 0); - __ JumpIfSmi(r5, &runtime); - Condition is_string = masm->IsObjectStringType(r5, r1); + __ JumpIfSmi(r0, &runtime); + Condition is_string = masm->IsObjectStringType(r0, r1); __ b(NegateCondition(is_string), &runtime); + // Short-cut for the case of trivial substring. + Label return_r0; + // r0: original string + // r2: result string length + __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset)); + __ cmp(r2, Operand(r4, ASR, 1)); + __ b(eq, &return_r0); + + Label create_slice; + if (FLAG_string_slices) { + __ cmp(r2, Operand(SlicedString::kMinLength)); + __ b(ge, &create_slice); + } + + // r0: original string // r1: instance type - // r2: length + // r2: result string length // r3: from index (untagged smi) - // r5: string // r6 (a.k.a. to): to (smi) // r7 (a.k.a. from): from offset (smi) Label seq_string; __ and_(r4, r1, Operand(kStringRepresentationMask)); STATIC_ASSERT(kSeqStringTag < kConsStringTag); STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kConsStringTag < kSlicedStringTag); __ cmp(r4, Operand(kConsStringTag)); - __ b(gt, &runtime); // External strings go to runtime. + __ b(gt, &runtime); // Slices and external strings go to runtime. __ b(lt, &seq_string); // Sequential strings are handled directly. // Cons string. Try to recurse (once) on the first substring. // (This adds a little more generality than necessary to handle flattened // cons strings, but not much). - __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); - __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); + __ ldr(r0, FieldMemOperand(r0, ConsString::kFirstOffset)); + __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); __ tst(r1, Operand(kStringRepresentationMask)); STATIC_ASSERT(kSeqStringTag == 0); - __ b(ne, &runtime); // Cons and External strings go to runtime. + __ b(ne, &runtime); // Cons, slices and external strings go to runtime. // Definitly a sequential string. __ bind(&seq_string); - // r1: instance type. - // r2: length - // r3: from index (untaged smi) - // r5: string + // r0: original string + // r1: instance type + // r2: result string length + // r3: from index (untagged smi) // r6 (a.k.a. to): to (smi) // r7 (a.k.a. from): from offset (smi) - __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); + __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset)); __ cmp(r4, Operand(to)); __ b(lt, &runtime); // Fail if to > length. to = no_reg; - // r1: instance type. - // r2: result string length. - // r3: from index (untaged smi) - // r5: string. + // r0: original string or left hand side of the original cons string. + // r1: instance type + // r2: result string length + // r3: from index (untagged smi) // r7 (a.k.a. from): from offset (smi) // Check for flat ASCII string. Label non_ascii_flat; @@ -5561,82 +5572,146 @@ void SubStringStub::Generate(MacroAssembler* masm) { // Sub string of length 2 requested. // Get the two characters forming the sub string. - __ add(r5, r5, Operand(r3)); - __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize)); - __ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1)); + __ add(r0, r0, Operand(r3)); + __ ldrb(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); + __ ldrb(r4, FieldMemOperand(r0, SeqAsciiString::kHeaderSize + 1)); // Try to lookup two character string in symbol table. Label make_two_character_string; StringHelper::GenerateTwoCharacterSymbolTableProbe( masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string); Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); - __ add(sp, sp, Operand(3 * kPointerSize)); - __ Ret(); + __ jmp(&return_r0); // r2: result string length. // r3: two characters combined into halfword in little endian byte order. __ bind(&make_two_character_string); __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); - __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); - __ add(sp, sp, Operand(3 * kPointerSize)); - __ Ret(); + __ jmp(&return_r0); __ bind(&result_longer_than_two); + // Locate 'from' character of string. + __ add(r5, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(r5, r5, Operand(from, ASR, 1)); + // Allocate the result. __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); - // r0: result string. - // r2: result string length. - // r5: string. + // r0: result string + // r2: result string length + // r5: first character of substring to copy // r7 (a.k.a. from): from offset (smi) // Locate first character of result. __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); - // Locate 'from' character of string. - __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); - __ add(r5, r5, Operand(from, ASR, 1)); - // r0: result string. - // r1: first character of result string. - // r2: result string length. - // r5: first character of sub string to copy. + // r0: result string + // r1: first character of result string + // r2: result string length + // r5: first character of substring to copy STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, COPY_ASCII | DEST_ALWAYS_ALIGNED); - __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); - __ add(sp, sp, Operand(3 * kPointerSize)); - __ Ret(); + __ jmp(&return_r0); __ bind(&non_ascii_flat); - // r2: result string length. - // r5: string. + // r0: original string + // r2: result string length // r7 (a.k.a. from): from offset (smi) // Check for flat two byte string. + // Locate 'from' character of string. + __ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); + // As "from" is a smi it is 2 times the value which matches the size of a two + // byte character. + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + __ add(r5, r5, Operand(from)); + // Allocate the result. __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime); - // r0: result string. - // r2: result string length. - // r5: string. + // r0: result string + // r2: result string length + // r5: first character of substring to copy // Locate first character of result. __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - // Locate 'from' character of string. - __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - // As "from" is a smi it is 2 times the value which matches the size of a two - // byte character. - __ add(r5, r5, Operand(from)); + from = no_reg; // r0: result string. // r1: first character of result. // r2: result length. - // r5: first character of string to copy. + // r5: first character of substring to copy. STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); StringHelper::GenerateCopyCharactersLong( masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED); + __ jmp(&return_r0); + + if (FLAG_string_slices) { + __ bind(&create_slice); + // r0: original string + // r1: instance type + // r2: length + // r3: from index (untagged smi) + // r6 (a.k.a. to): to (smi) + // r7 (a.k.a. from): from offset (smi) + Label allocate_slice, sliced_string, seq_string; + STATIC_ASSERT(kSeqStringTag == 0); + __ tst(r1, Operand(kStringRepresentationMask)); + __ b(eq, &seq_string); + STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); + STATIC_ASSERT(kIsIndirectStringMask != 0); + __ tst(r1, Operand(kIsIndirectStringMask)); + // External string. Jump to runtime. + __ b(eq, &runtime); + + __ tst(r1, Operand(kSlicedNotConsMask)); + __ b(ne, &sliced_string); + // Cons string. Check whether it is flat, then fetch first part. + __ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset)); + __ LoadRoot(r9, Heap::kEmptyStringRootIndex); + __ cmp(r5, r9); + __ b(ne, &runtime); + __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset)); + __ jmp(&allocate_slice); + + __ bind(&sliced_string); + // Sliced string. Fetch parent and correct start index by offset. + __ ldr(r5, FieldMemOperand(r0, SlicedString::kOffsetOffset)); + __ add(r7, r7, r5); + __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); + __ jmp(&allocate_slice); + + __ bind(&seq_string); + // Sequential string. Just move string to the right register. + __ mov(r5, r0); + + __ bind(&allocate_slice); + // r1: instance type of original string + // r2: length + // r5: underlying subject string + // r7 (a.k.a. from): from offset (smi) + // Allocate new sliced string. At this point we do not reload the instance + // type including the string encoding because we simply rely on the info + // provided by the original string. It does not matter if the original + // string's encoding is wrong because we always have to recheck encoding of + // the newly created string's parent anyways due to externalized strings. + Label two_byte_slice, set_slice_header; + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ tst(r1, Operand(kStringEncodingMask)); + __ b(eq, &two_byte_slice); + __ AllocateAsciiSlicedString(r0, r2, r3, r4, &runtime); + __ jmp(&set_slice_header); + __ bind(&two_byte_slice); + __ AllocateTwoByteSlicedString(r0, r2, r3, r4, &runtime); + __ bind(&set_slice_header); + __ str(r7, FieldMemOperand(r0, SlicedString::kOffsetOffset)); + __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); + } + + __ bind(&return_r0); __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); __ add(sp, sp, Operand(3 * kPointerSize)); __ Ret(); diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index b58743de41..4d27a8d3ca 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -193,14 +193,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // Copy any necessary parameters into the context. int num_parameters = info->scope()->num_parameters(); for (int i = 0; i < num_parameters; i++) { - Slot* slot = scope()->parameter(i)->AsSlot(); - if (slot != NULL && slot->type() == Slot::CONTEXT) { + Variable* var = scope()->parameter(i); + if (var->IsContextSlot()) { int parameter_offset = StandardFrameConstants::kCallerSPOffset + (num_parameters - 1 - i) * kPointerSize; // Load parameter from stack. __ ldr(r0, MemOperand(fp, parameter_offset)); // Store it in the context. - __ mov(r1, Operand(Context::SlotOffset(slot->index()))); + __ mov(r1, Operand(Context::SlotOffset(var->index()))); __ str(r0, MemOperand(cp, r1)); // Update the write barrier. This clobbers all involved // registers, so we have to use two more registers to avoid @@ -244,7 +244,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { ArgumentsAccessStub stub(type); __ CallStub(&stub); - Move(arguments->AsSlot(), r0, r1, r2); + SetVar(arguments, r0, r1, r2); } if (FLAG_trace) { @@ -258,17 +258,19 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { scope()->VisitIllegalRedeclaration(this); } else { + PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); { Comment cmnt(masm_, "[ Declarations"); // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - EmitDeclaration(scope()->function(), Variable::CONST, NULL); + int ignored = 0; + EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored); } VisitDeclarations(scope()->declarations()); } { Comment cmnt(masm_, "[ Stack check"); - PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); + PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); Label ok; __ LoadRoot(ip, Heap::kStackLimitRootIndex); __ cmp(sp, Operand(ip)); @@ -367,24 +369,28 @@ void FullCodeGenerator::EmitReturnSequence() { } -void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { +void FullCodeGenerator::EffectContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); } -void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { - codegen()->Move(result_register(), slot); +void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); + codegen()->GetVar(result_register(), var); } -void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { - codegen()->Move(result_register(), slot); +void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); + codegen()->GetVar(result_register(), var); __ push(result_register()); } -void FullCodeGenerator::TestContext::Plug(Slot* slot) const { +void FullCodeGenerator::TestContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); // For simplicity we always test the accumulator register. - codegen()->Move(result_register(), slot); + codegen()->GetVar(result_register(), var); codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); codegen()->DoTest(this); } @@ -616,45 +622,54 @@ void FullCodeGenerator::Split(Condition cond, } -MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - return MemOperand(fp, SlotOffset(slot)); - case Slot::CONTEXT: { - int context_chain_length = - scope()->ContextChainLength(slot->var()->scope()); - __ LoadContext(scratch, context_chain_length); - return ContextOperand(scratch, slot->index()); - } - case Slot::LOOKUP: - UNREACHABLE(); +MemOperand FullCodeGenerator::StackOperand(Variable* var) { + ASSERT(var->IsStackAllocated()); + // Offset is negative because higher indexes are at lower addresses. + int offset = -var->index() * kPointerSize; + // Adjust by a (parameter or local) base offset. + if (var->IsParameter()) { + offset += (info_->scope()->num_parameters() + 1) * kPointerSize; + } else { + offset += JavaScriptFrameConstants::kLocal0Offset; + } + return MemOperand(fp, offset); +} + + +MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) { + ASSERT(var->IsContextSlot() || var->IsStackAllocated()); + if (var->IsContextSlot()) { + int context_chain_length = scope()->ContextChainLength(var->scope()); + __ LoadContext(scratch, context_chain_length); + return ContextOperand(scratch, var->index()); + } else { + return StackOperand(var); } - UNREACHABLE(); - return MemOperand(r0, 0); } -void FullCodeGenerator::Move(Register destination, Slot* source) { +void FullCodeGenerator::GetVar(Register dest, Variable* var) { // Use destination as scratch. - MemOperand slot_operand = EmitSlotSearch(source, destination); - __ ldr(destination, slot_operand); + MemOperand location = VarOperand(var, dest); + __ ldr(dest, location); } -void FullCodeGenerator::Move(Slot* dst, - Register src, - Register scratch1, - Register scratch2) { - ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. - ASSERT(!scratch1.is(src) && !scratch2.is(src)); - MemOperand location = EmitSlotSearch(dst, scratch1); +void FullCodeGenerator::SetVar(Variable* var, + Register src, + Register scratch0, + Register scratch1) { + ASSERT(var->IsContextSlot() || var->IsStackAllocated()); + ASSERT(!scratch0.is(src)); + ASSERT(!scratch0.is(scratch1)); + ASSERT(!scratch1.is(src)); + MemOperand location = VarOperand(var, scratch0); __ str(src, location); // Emit the write barrier code if the location is in the heap. - if (dst->type() == Slot::CONTEXT) { - __ RecordWrite(scratch1, - Operand(Context::SlotOffset(dst->index())), - scratch2, + if (var->IsContextSlot()) { + __ RecordWrite(scratch0, + Operand(Context::SlotOffset(var->index())), + scratch1, src); } } @@ -687,29 +702,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, } -void FullCodeGenerator::EmitDeclaration(Variable* variable, +void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, Variable::Mode mode, - FunctionLiteral* function) { - Comment cmnt(masm_, "[ Declaration"); - ASSERT(variable != NULL); // Must have been resolved. - Slot* slot = variable->AsSlot(); - ASSERT(slot != NULL); - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - if (mode == Variable::CONST) { - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ str(ip, MemOperand(fp, SlotOffset(slot))); - } else if (function != NULL) { + FunctionLiteral* function, + int* global_count) { + // If it was not possible to allocate the variable at compile time, we + // need to "declare" it at runtime to make sure it actually exists in the + // local context. + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: + ++(*global_count); + break; + + case Variable::PARAMETER: + case Variable::LOCAL: + if (function != NULL) { + Comment cmnt(masm_, "[ Declaration"); VisitForAccumulatorValue(function); - __ str(result_register(), MemOperand(fp, SlotOffset(slot))); + __ str(result_register(), StackOperand(variable)); + } else if (mode == Variable::CONST || mode == Variable::LET) { + Comment cmnt(masm_, "[ Declaration"); + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ str(ip, StackOperand(variable)); } break; - case Slot::CONTEXT: - // We bypass the general EmitSlotSearch because we know more about - // this specific context. - + case Variable::CONTEXT: // The variable in the decl always resides in the current function // context. ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); @@ -721,23 +740,28 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); __ Check(ne, "Declaration in catch context."); } - if (mode == Variable::CONST) { - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ str(ip, ContextOperand(cp, slot->index())); - // No write barrier since the_hole_value is in old space. - } else if (function != NULL) { + if (function != NULL) { + Comment cmnt(masm_, "[ Declaration"); VisitForAccumulatorValue(function); - __ str(result_register(), ContextOperand(cp, slot->index())); - int offset = Context::SlotOffset(slot->index()); + __ str(result_register(), ContextOperand(cp, variable->index())); + int offset = Context::SlotOffset(variable->index()); // We know that we have written a function, which is not a smi. __ mov(r1, Operand(cp)); __ RecordWrite(r1, Operand(offset), r2, result_register()); + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); + } else if (mode == Variable::CONST || mode == Variable::LET) { + Comment cmnt(masm_, "[ Declaration"); + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ str(ip, ContextOperand(cp, variable->index())); + // No write barrier since the_hole_value is in old space. + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); } break; - case Slot::LOOKUP: { + case Variable::LOOKUP: { + Comment cmnt(masm_, "[ Declaration"); __ mov(r2, Operand(variable->name())); - // Declaration nodes are always introduced in one of two modes. + // Declaration nodes are always introduced in one of three modes. ASSERT(mode == Variable::VAR || mode == Variable::CONST || mode == Variable::LET); @@ -747,15 +771,15 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, // Note: For variables we must not push an initial value (such as // 'undefined') because we may have a (legal) redeclaration and we // must not destroy the current value. - if (mode == Variable::CONST) { - __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); - __ Push(cp, r2, r1, r0); - } else if (function != NULL) { + if (function != NULL) { __ Push(cp, r2, r1); // Push initial value for function declaration. VisitForStackValue(function); + } else if (mode == Variable::CONST || mode == Variable::LET) { + __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); + __ Push(cp, r2, r1, r0); } else { - __ mov(r0, Operand(Smi::FromInt(0))); // No initial value! + __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value. __ Push(cp, r2, r1, r0); } __ CallRuntime(Runtime::kDeclareContextSlot, 4); @@ -765,19 +789,16 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, } -void FullCodeGenerator::VisitDeclaration(Declaration* decl) { - EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); -} +void FullCodeGenerator::VisitDeclaration(Declaration* decl) { } void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { // Call the runtime to declare the globals. // The context is the first argument. - __ mov(r2, Operand(pairs)); - __ mov(r1, Operand(Smi::FromInt(is_eval() ? 1 : 0))); - __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); - __ Push(cp, r2, r1, r0); - __ CallRuntime(Runtime::kDeclareGlobals, 4); + __ mov(r1, Operand(pairs)); + __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags()))); + __ Push(cp, r1, r0); + __ CallRuntime(Runtime::kDeclareGlobals, 3); // Return value is ignored. } @@ -1085,10 +1106,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } -void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( - Slot* slot, - TypeofState typeof_state, - Label* slow) { +void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, + TypeofState typeof_state, + Label* slow) { Register current = cp; Register next = r1; Register temp = r2; @@ -1135,7 +1155,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( } __ ldr(r0, GlobalObjectOperand()); - __ mov(r2, Operand(slot->var()->name())); + __ mov(r2, Operand(var->name())); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT; @@ -1144,15 +1164,14 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( } -MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( - Slot* slot, - Label* slow) { - ASSERT(slot->type() == Slot::CONTEXT); +MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, + Label* slow) { + ASSERT(var->IsContextSlot()); Register context = cp; Register next = r3; Register temp = r4; - for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { + for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { if (s->num_heap_slots() > 0) { if (s->calls_eval()) { // Check that extension is NULL. @@ -1173,59 +1192,30 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( // This function is used only for loads, not stores, so it's safe to // return an cp-based operand (the write barrier cannot be allowed to // destroy the cp register). - return ContextOperand(context, slot->index()); + return ContextOperand(context, var->index()); } -void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( - Slot* slot, - TypeofState typeof_state, - Label* slow, - Label* done) { +void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, + TypeofState typeof_state, + Label* slow, + Label* done) { // Generate fast-case code for variables that might be shadowed by // eval-introduced variables. Eval is used a lot without // introducing variables. In those cases, we do not want to // perform a runtime call for all variables in the scope // containing the eval. - if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { - EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); + if (var->mode() == Variable::DYNAMIC_GLOBAL) { + EmitLoadGlobalCheckExtensions(var, typeof_state, slow); __ jmp(done); - } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { - Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); - Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); - if (potential_slot != NULL) { - // Generate fast case for locals that rewrite to slots. - __ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow)); - if (potential_slot->var()->mode() == Variable::CONST) { - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ cmp(r0, ip); - __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); - } - __ jmp(done); - } else if (rewrite != NULL) { - // Generate fast case for calls of an argument function. - Property* property = rewrite->AsProperty(); - if (property != NULL) { - VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); - Literal* key_literal = property->key()->AsLiteral(); - if (obj_proxy != NULL && - key_literal != NULL && - obj_proxy->IsArguments() && - key_literal->handle()->IsSmi()) { - // Load arguments object if there are no eval-introduced - // variables. Then load the argument from the arguments - // object using keyed load. - __ ldr(r1, - ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), - slow)); - __ mov(r0, Operand(key_literal->handle())); - Handle<Code> ic = - isolate()->builtins()->KeyedLoadIC_Initialize(); - __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); - __ jmp(done); - } - } + } else if (var->mode() == Variable::DYNAMIC_LOCAL) { + Variable* local = var->local_if_not_shadowed(); + __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); + if (local->mode() == Variable::CONST) { + __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); + __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); } + __ jmp(done); } } @@ -1235,52 +1225,60 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { SetSourcePosition(proxy->position()); Variable* var = proxy->var(); - // Three cases: non-this global variables, lookup slots, and all other - // types of slots. - Slot* slot = var->AsSlot(); - ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); - - if (slot == NULL) { - Comment cmnt(masm_, "Global variable"); - // Use inline caching. Variable name is passed in r2 and the global - // object (receiver) in r0. - __ ldr(r0, GlobalObjectOperand()); - __ mov(r2, Operand(var->name())); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); - context()->Plug(r0); - - } else if (slot->type() == Slot::LOOKUP) { - Label done, slow; - - // Generate code for loading from variables potentially shadowed - // by eval-introduced variables. - EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); - - __ bind(&slow); - Comment cmnt(masm_, "Lookup slot"); - __ mov(r1, Operand(var->name())); - __ Push(cp, r1); // Context and name. - __ CallRuntime(Runtime::kLoadContextSlot, 2); - __ bind(&done); + // Three cases: global variables, lookup variables, and all other types of + // variables. + switch (var->location()) { + case Variable::UNALLOCATED: { + Comment cmnt(masm_, "Global variable"); + // Use inline caching. Variable name is passed in r2 and the global + // object (receiver) in r0. + __ ldr(r0, GlobalObjectOperand()); + __ mov(r2, Operand(var->name())); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + context()->Plug(r0); + break; + } - context()->Plug(r0); + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::CONTEXT: { + Comment cmnt(masm_, var->IsContextSlot() + ? "Context variable" + : "Stack variable"); + if (var->mode() != Variable::LET && var->mode() != Variable::CONST) { + context()->Plug(var); + } else { + // Let and const need a read barrier. + GetVar(r0, var); + __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); + if (var->mode() == Variable::LET) { + Label done; + __ b(ne, &done); + __ mov(r0, Operand(var->name())); + __ push(r0); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&done); + } else { + __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); + } + context()->Plug(r0); + } + break; + } - } else { - Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) - ? "Context slot" - : "Stack slot"); - if (var->mode() == Variable::CONST) { - // Constants may be the hole value if they have not been initialized. - // Unhole them. - MemOperand slot_operand = EmitSlotSearch(slot, r0); - __ ldr(r0, slot_operand); - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ cmp(r0, ip); - __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); + case Variable::LOOKUP: { + Label done, slow; + // Generate code for loading from variables potentially shadowed + // by eval-introduced variables. + EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); + __ bind(&slow); + Comment cmnt(masm_, "Lookup variable"); + __ mov(r1, Operand(var->name())); + __ Push(cp, r1); // Context and name. + __ CallRuntime(Runtime::kLoadContextSlot, 2); + __ bind(&done); context()->Plug(r0); - } else { - context()->Plug(slot); } } } @@ -1814,14 +1812,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) { - ASSERT(var != NULL); - ASSERT(var->is_global() || var->AsSlot() != NULL); - - if (var->is_global()) { - ASSERT(!var->is_this()); - // Assignment to a global variable. Use inline caching for the - // assignment. Right-hand-side value is passed in r0, variable name in - // r2, and the global object in r1. + if (var->IsUnallocated()) { + // Global var, const, or let. __ mov(r2, Operand(var->name())); __ ldr(r1, GlobalObjectOperand()); Handle<Code> ic = is_strict_mode() @@ -1830,67 +1822,83 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); } else if (op == Token::INIT_CONST) { - // Like var declarations, const declarations are hoisted to function - // scope. However, unlike var initializers, const initializers are able - // to drill a hole to that function context, even from inside a 'with' - // context. We thus bypass the normal static scope lookup. - Slot* slot = var->AsSlot(); - Label skip; - switch (slot->type()) { - case Slot::PARAMETER: - // No const parameters. - UNREACHABLE(); - break; - case Slot::LOCAL: - // Detect const reinitialization by checking for the hole value. - __ ldr(r1, MemOperand(fp, SlotOffset(slot))); - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ cmp(r1, ip); - __ b(ne, &skip); - __ str(result_register(), MemOperand(fp, SlotOffset(slot))); - break; - case Slot::CONTEXT: - case Slot::LOOKUP: - __ push(r0); - __ mov(r0, Operand(slot->var()->name())); - __ Push(cp, r0); // Context and name. - __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); - break; + // Const initializers need a write barrier. + ASSERT(!var->IsParameter()); // No const parameters. + if (var->IsStackLocal()) { + Label skip; + __ ldr(r1, StackOperand(var)); + __ CompareRoot(r1, Heap::kTheHoleValueRootIndex); + __ b(ne, &skip); + __ str(result_register(), StackOperand(var)); + __ bind(&skip); + } else { + ASSERT(var->IsContextSlot() || var->IsLookupSlot()); + // Like var declarations, const declarations are hoisted to function + // scope. However, unlike var initializers, const initializers are + // able to drill a hole to that function context, even from inside a + // 'with' context. We thus bypass the normal static scope lookup for + // var->IsContextSlot(). + __ push(r0); + __ mov(r0, Operand(var->name())); + __ Push(cp, r0); // Context and name. + __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); } - __ bind(&skip); - } else if (var->mode() != Variable::CONST) { - // Perform the assignment for non-const variables. Const assignments - // are simply skipped. - Slot* slot = var->AsSlot(); - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - // Perform the assignment. - __ str(result_register(), MemOperand(fp, SlotOffset(slot))); - break; - - case Slot::CONTEXT: { - MemOperand target = EmitSlotSearch(slot, r1); - // Perform the assignment and issue the write barrier. - __ str(result_register(), target); + } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { + // Non-initializing assignment to let variable needs a write barrier. + if (var->IsLookupSlot()) { + __ push(r0); // Value. + __ mov(r1, Operand(var->name())); + __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); + __ Push(cp, r1, r0); // Context, name, strict mode. + __ CallRuntime(Runtime::kStoreContextSlot, 4); + } else { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); + Label assign; + MemOperand location = VarOperand(var, r1); + __ ldr(r3, location); + __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); + __ b(ne, &assign); + __ mov(r3, Operand(var->name())); + __ push(r3); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + // Perform the assignment. + __ bind(&assign); + __ str(result_register(), location); + if (var->IsContextSlot()) { // RecordWrite may destroy all its register arguments. __ mov(r3, result_register()); - int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; + int offset = Context::SlotOffset(var->index()); __ RecordWrite(r1, Operand(offset), r2, r3); - break; } + } - case Slot::LOOKUP: - // Call the runtime for the assignment. - __ push(r0); // Value. - __ mov(r1, Operand(slot->var()->name())); - __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); - __ Push(cp, r1, r0); // Context, name, strict mode. - __ CallRuntime(Runtime::kStoreContextSlot, 4); - break; + } else if (var->mode() != Variable::CONST) { + // Assignment to var or initializing assignment to let. + if (var->IsStackAllocated() || var->IsContextSlot()) { + MemOperand location = VarOperand(var, r1); + if (FLAG_debug_code && op == Token::INIT_LET) { + // Check for an uninitialized let binding. + __ ldr(r2, location); + __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); + __ Check(eq, "Let binding re-initialization."); + } + // Perform the assignment. + __ str(r0, location); + if (var->IsContextSlot()) { + __ mov(r3, r0); + __ RecordWrite(r1, Operand(Context::SlotOffset(var->index())), r2, r3); + } + } else { + ASSERT(var->IsLookupSlot()); + __ push(r0); // Value. + __ mov(r1, Operand(var->name())); + __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); + __ Push(cp, r1, r0); // Context, name, strict mode. + __ CallRuntime(Runtime::kStoreContextSlot, 4); } } + // Non-initializing assignments to consts are ignored. } @@ -2100,8 +2108,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, int receiver_offset = 2 + info_->scope()->num_parameters(); __ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize)); __ push(r1); - // Push the strict mode flag. - __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); + // Push the strict mode flag. In harmony mode every eval call + // is a strict mode eval call. + StrictModeFlag strict_mode = strict_mode_flag(); + if (FLAG_harmony_block_scoping) { + strict_mode = kStrictMode; + } + __ mov(r1, Operand(Smi::FromInt(strict_mode))); __ push(r1); __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP @@ -2118,10 +2131,11 @@ void FullCodeGenerator::VisitCall(Call* expr) { #endif Comment cmnt(masm_, "[ Call"); - Expression* fun = expr->expression(); - Variable* var = fun->AsVariableProxy()->AsVariable(); + Expression* callee = expr->expression(); + VariableProxy* proxy = callee->AsVariableProxy(); + Property* property = callee->AsProperty(); - if (var != NULL && var->is_possibly_eval()) { + if (proxy != NULL && proxy->var()->is_possibly_eval()) { // In a call to eval, we first call %ResolvePossiblyDirectEval to // resolve the function we need to call and the receiver of the // call. Then we call the resolved function using the given @@ -2130,7 +2144,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { int arg_count = args->length(); { PreservePositionScope pos_scope(masm()->positions_recorder()); - VisitForStackValue(fun); + VisitForStackValue(callee); __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); __ push(r2); // Reserved receiver slot. @@ -2144,11 +2158,10 @@ void FullCodeGenerator::VisitCall(Call* expr) { // in generated code. If we succeed, there is no need to perform a // context lookup in the runtime system. Label done; - if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { + Variable* var = proxy->var(); + if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) { Label slow; - EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), - NOT_INSIDE_TYPEOF, - &slow); + EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); // Push the function and resolve eval. __ push(r0); EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); @@ -2156,14 +2169,12 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ bind(&slow); } - // Push copy of the function (found below the arguments) and + // Push a copy of the function (found below the arguments) and // resolve eval. __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ push(r1); EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); - if (done.is_linked()) { - __ bind(&done); - } + __ bind(&done); // The runtime call returns a pair of values in r0 (function) and // r1 (receiver). Touch up the stack with the right values. @@ -2180,30 +2191,26 @@ void FullCodeGenerator::VisitCall(Call* expr) { // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, r0); - } else if (var != NULL && !var->is_this() && var->is_global()) { + } else if (proxy != NULL && proxy->var()->IsUnallocated()) { // Push global object as receiver for the call IC. __ ldr(r0, GlobalObjectOperand()); __ push(r0); - EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); - } else if (var != NULL && var->AsSlot() != NULL && - var->AsSlot()->type() == Slot::LOOKUP) { + EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); + } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { // Call to a lookup slot (dynamically introduced variable). Label slow, done; { PreservePositionScope scope(masm()->positions_recorder()); // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLoadFromSlotFastCase(var->AsSlot(), - NOT_INSIDE_TYPEOF, - &slow, - &done); + EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); } __ bind(&slow); // Call the runtime to find the function to call (returned in r0) // and the object holding it (returned in edx). __ push(context_register()); - __ mov(r2, Operand(var->name())); + __ mov(r2, Operand(proxy->name())); __ push(r2); __ CallRuntime(Runtime::kLoadContextSlot, 2); __ Push(r0, r1); // Function, receiver. @@ -2228,26 +2235,21 @@ void FullCodeGenerator::VisitCall(Call* expr) { // by LoadContextSlot. That object could be the hole if the // receiver is implicitly the global object. EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); - } else if (fun->AsProperty() != NULL) { - // Call to an object property. - Property* prop = fun->AsProperty(); - Literal* key = prop->key()->AsLiteral(); - if (key != NULL && key->handle()->IsSymbol()) { - // Call to a named property, use call IC. - { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } - EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); + } else if (property != NULL) { + { PreservePositionScope scope(masm()->positions_recorder()); + VisitForStackValue(property->obj()); + } + if (property->key()->IsPropertyName()) { + EmitCallWithIC(expr, + property->key()->AsLiteral()->handle(), + RelocInfo::CODE_TARGET); } else { - // Call to a keyed property. - { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } - EmitKeyedCallWithIC(expr, prop->key()); + EmitKeyedCallWithIC(expr, property->key()); } } else { + // Call to an arbitrary expression not handled specially above. { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(fun); + VisitForStackValue(callee); } // Load global receiver object. __ ldr(r1, GlobalObjectOperand()); @@ -3194,7 +3196,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { Label done, not_found; // tmp now holds finger offset as a smi. - ASSERT(kSmiTag == 0 && kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset)); // r2 now holds finger offset as a smi. __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); @@ -3569,32 +3571,32 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { switch (expr->op()) { case Token::DELETE: { Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); - Property* prop = expr->expression()->AsProperty(); - Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); + Property* property = expr->expression()->AsProperty(); + VariableProxy* proxy = expr->expression()->AsVariableProxy(); - if (prop != NULL) { - VisitForStackValue(prop->obj()); - VisitForStackValue(prop->key()); + if (property != NULL) { + VisitForStackValue(property->obj()); + VisitForStackValue(property->key()); __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); __ push(r1); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(r0); - } else if (var != NULL) { + } else if (proxy != NULL) { + Variable* var = proxy->var(); // Delete of an unqualified identifier is disallowed in strict mode - // but "delete this" is. + // but "delete this" is allowed. ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); - if (var->is_global()) { + if (var->IsUnallocated()) { __ ldr(r2, GlobalObjectOperand()); __ mov(r1, Operand(var->name())); __ mov(r0, Operand(Smi::FromInt(kNonStrictMode))); __ Push(r2, r1, r0); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(r0); - } else if (var->AsSlot() != NULL && - var->AsSlot()->type() != Slot::LOOKUP) { + } else if (var->IsStackAllocated() || var->IsContextSlot()) { // Result of deleting non-global, non-dynamic variables is false. // The subexpression does not have side effects. - context()->Plug(false); + context()->Plug(var->is_this()); } else { // Non-global variable. Call the runtime to try to delete from the // context where the variable was introduced. @@ -3869,7 +3871,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { ASSERT(!context()->IsEffect()); ASSERT(!context()->IsTest()); VariableProxy* proxy = expr->AsVariableProxy(); - if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { + if (proxy != NULL && proxy->var()->IsUnallocated()) { Comment cmnt(masm_, "Global variable"); __ ldr(r0, GlobalObjectOperand()); __ mov(r2, Operand(proxy->name())); @@ -3879,15 +3881,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { __ Call(ic); PrepareForBailout(expr, TOS_REG); context()->Plug(r0); - } else if (proxy != NULL && - proxy->var()->AsSlot() != NULL && - proxy->var()->AsSlot()->type() == Slot::LOOKUP) { + } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { Label done, slow; // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - Slot* slot = proxy->var()->AsSlot(); - EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); __ bind(&slow); __ mov(r0, Operand(proxy->name())); @@ -4182,7 +4181,7 @@ void FullCodeGenerator::EnterFinallyBlock() { // Cook return address in link register to stack (smi encoded Code* delta) __ sub(r1, lr, Operand(masm_->CodeObject())); ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); __ add(r1, r1, Operand(r1)); // Convert to smi. __ push(r1); } @@ -4202,6 +4201,34 @@ void FullCodeGenerator::ExitFinallyBlock() { #undef __ +#define __ ACCESS_MASM(masm()) + +FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( + int* stack_depth, + int* context_length) { + // The macros used here must preserve the result register. + + // Because the handler block contains the context of the finally + // code, we can restore it directly from there for the finally code + // rather than iteratively unwinding contexts via their previous + // links. + __ Drop(*stack_depth); // Down to the handler block. + if (*context_length > 0) { + // Restore the context to its dedicated register and the stack. + __ ldr(cp, MemOperand(sp, StackHandlerConstants::kContextOffset)); + __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ PopTryHandler(); + __ bl(finally_entry_); + + *stack_depth = 0; + *context_length = 0; + return previous_; +} + + +#undef __ + } } // namespace v8::internal #endif // V8_TARGET_ARCH_ARM diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 6038153a1a..6bad5ac03e 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -337,7 +337,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, // Fast case: Do the load. __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); // The key is a smi. - ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); __ ldr(scratch2, MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize)); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); @@ -370,7 +370,7 @@ static void GenerateKeyStringCheck(MacroAssembler* masm, // Is the string a symbol? // map: key map __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); - ASSERT(kSymbolTag != 0); + STATIC_ASSERT(kSymbolTag != 0); __ tst(hash, Operand(kIsSymbolMask)); __ b(eq, not_symbol); } @@ -1333,7 +1333,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ cmp(key, Operand(ip)); __ b(hs, &slow); // Calculate key + 1 as smi. - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); __ add(r4, key, Operand(Smi::FromInt(1))); __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); __ b(&fast); diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 65a6169252..24e51e0681 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -198,14 +198,14 @@ bool LCodeGen::GeneratePrologue() { // Copy any necessary parameters into the context. int num_parameters = scope()->num_parameters(); for (int i = 0; i < num_parameters; i++) { - Slot* slot = scope()->parameter(i)->AsSlot(); - if (slot != NULL && slot->type() == Slot::CONTEXT) { + Variable* var = scope()->parameter(i); + if (var->IsContextSlot()) { int parameter_offset = StandardFrameConstants::kCallerSPOffset + (num_parameters - 1 - i) * kPointerSize; // Load parameter from stack. __ ldr(r0, MemOperand(fp, parameter_offset)); // Store it in the context. - __ mov(r1, Operand(Context::SlotOffset(slot->index()))); + __ mov(r1, Operand(Context::SlotOffset(var->index()))); __ str(r0, MemOperand(cp, r1)); // Update the write barrier. This clobbers all involved // registers, so we have to use two more registers to avoid @@ -3473,8 +3473,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { // Dispatch on the indirect string shape: slice or cons. Label cons_string; - const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag; - ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0); __ tst(result, Operand(kSlicedNotConsMask)); __ b(eq, &cons_string); @@ -3511,7 +3509,8 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { // Dispatch on the encoding: ASCII or two-byte. Label ascii_string; - STATIC_ASSERT(kAsciiStringTag != 0); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ tst(result, Operand(kStringEncodingMask)); __ b(ne, &ascii_string); @@ -3759,7 +3758,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister() && input->Equals(instr->result())); if (instr->needs_check()) { - ASSERT(kHeapObjectTag == 1); + STATIC_ASSERT(kHeapObjectTag == 1); // If the input is a HeapObject, SmiUntag will set the carry flag. __ SmiUntag(ToRegister(input), SetCC); DeoptimizeIf(cs, instr->environment()); @@ -3844,7 +3843,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { // The input was optimistically untagged; revert it. // The carry flag is set when we reach this deferred code as we just executed // SmiUntag(heap_object, SetCC) - ASSERT(kHeapObjectTag == 1); + STATIC_ASSERT(kHeapObjectTag == 1); __ adc(input_reg, input_reg, Operand(input_reg)); // Heap number map check. diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 88477bb7f0..613a1f69f1 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -1725,6 +1725,46 @@ void MacroAssembler::AllocateAsciiConsString(Register result, } +void MacroAssembler::AllocateTwoByteSlicedString(Register result, + Register length, + Register scratch1, + Register scratch2, + Label* gc_required) { + AllocateInNewSpace(SlicedString::kSize, + result, + scratch1, + scratch2, + gc_required, + TAG_OBJECT); + + InitializeNewString(result, + length, + Heap::kSlicedStringMapRootIndex, + scratch1, + scratch2); +} + + +void MacroAssembler::AllocateAsciiSlicedString(Register result, + Register length, + Register scratch1, + Register scratch2, + Label* gc_required) { + AllocateInNewSpace(SlicedString::kSize, + result, + scratch1, + scratch2, + gc_required, + TAG_OBJECT); + + InitializeNewString(result, + length, + Heap::kSlicedAsciiStringMapRootIndex, + scratch1, + scratch2); +} + + void MacroAssembler::CompareObjectType(Register object, Register map, Register type_reg, diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 9c653adbba..9d66359625 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -532,6 +532,16 @@ class MacroAssembler: public Assembler { Register scratch1, Register scratch2, Label* gc_required); + void AllocateTwoByteSlicedString(Register result, + Register length, + Register scratch1, + Register scratch2, + Label* gc_required); + void AllocateAsciiSlicedString(Register result, + Register length, + Register scratch1, + Register scratch2, + Label* gc_required); // Allocates a heap number or jumps to the gc_required label if the young // space is full and a scavenge is needed. All registers are clobbered also diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index 81645c72ea..cd76edbf15 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -1049,7 +1049,7 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, MaybeObject* result = Execution::HandleStackGuardInterrupt(); if (*code_handle != re_code) { // Return address no longer valid - int delta = *code_handle - re_code; + int delta = code_handle->address() - re_code->address(); // Overwrite the return address on the stack. *return_address += delta; } diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 16e6468422..5345892925 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -3497,7 +3497,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // We are not untagging smi key and instead work with it // as if it was premultiplied by 2. - ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); + STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); Register value = r2; switch (elements_kind) { @@ -4147,7 +4147,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { // Load the result and make sure it's not the hole. __ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); __ ldr(r4, MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); @@ -4279,7 +4279,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, __ add(scratch, elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); __ str(value_reg, MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize)); __ RecordWrite(scratch, diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index a12fdc84bc..32a370fda8 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -996,6 +996,9 @@ function ArrayFilter(f, receiver) { if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } + if (IS_NULL_OR_UNDEFINED(receiver)) { + receiver = %GetDefaultReceiver(f) || receiver; + } // Pull out the length so that modifications to the length in the // loop will not affect the looping. var length = ToUint32(this.length); @@ -1004,7 +1007,7 @@ function ArrayFilter(f, receiver) { for (var i = 0; i < length; i++) { var current = this[i]; if (!IS_UNDEFINED(current) || i in this) { - if (f.call(receiver, current, i, this)) { + if (%_CallFunction(receiver, current, i, this, f)) { result[result_length++] = current; } } @@ -1022,13 +1025,16 @@ function ArrayForEach(f, receiver) { if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } + if (IS_NULL_OR_UNDEFINED(receiver)) { + receiver = %GetDefaultReceiver(f) || receiver; + } // Pull out the length so that modifications to the length in the // loop will not affect the looping. var length = TO_UINT32(this.length); for (var i = 0; i < length; i++) { var current = this[i]; if (!IS_UNDEFINED(current) || i in this) { - f.call(receiver, current, i, this); + %_CallFunction(receiver, current, i, this, f); } } } @@ -1045,13 +1051,16 @@ function ArraySome(f, receiver) { if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } + if (IS_NULL_OR_UNDEFINED(receiver)) { + receiver = %GetDefaultReceiver(f) || receiver; + } // Pull out the length so that modifications to the length in the // loop will not affect the looping. var length = TO_UINT32(this.length); for (var i = 0; i < length; i++) { var current = this[i]; if (!IS_UNDEFINED(current) || i in this) { - if (f.call(receiver, current, i, this)) return true; + if (%_CallFunction(receiver, current, i, this, f)) return true; } } return false; @@ -1067,13 +1076,16 @@ function ArrayEvery(f, receiver) { if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } + if (IS_NULL_OR_UNDEFINED(receiver)) { + receiver = %GetDefaultReceiver(f) || receiver; + } // Pull out the length so that modifications to the length in the // loop will not affect the looping. var length = TO_UINT32(this.length); for (var i = 0; i < length; i++) { var current = this[i]; if (!IS_UNDEFINED(current) || i in this) { - if (!f.call(receiver, current, i, this)) return false; + if (!%_CallFunction(receiver, current, i, this, f)) return false; } } return true; @@ -1088,6 +1100,9 @@ function ArrayMap(f, receiver) { if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } + if (IS_NULL_OR_UNDEFINED(receiver)) { + receiver = %GetDefaultReceiver(f) || receiver; + } // Pull out the length so that modifications to the length in the // loop will not affect the looping. var length = TO_UINT32(this.length); @@ -1096,7 +1111,7 @@ function ArrayMap(f, receiver) { for (var i = 0; i < length; i++) { var current = this[i]; if (!IS_UNDEFINED(current) || i in this) { - accumulator[i] = f.call(receiver, current, i, this); + accumulator[i] = %_CallFunction(receiver, current, i, this, f); } } %MoveArrayContents(accumulator, result); @@ -1233,6 +1248,7 @@ function ArrayReduce(callback, current) { if (!IS_FUNCTION(callback)) { throw MakeTypeError('called_non_callable', [callback]); } + // Pull out the length so that modifications to the length in the // loop will not affect the looping. var length = ToUint32(this.length); @@ -1249,10 +1265,11 @@ function ArrayReduce(callback, current) { throw MakeTypeError('reduce_no_initial', []); } + var receiver = %GetDefaultReceiver(callback); for (; i < length; i++) { var element = this[i]; if (!IS_UNDEFINED(element) || i in this) { - current = callback.call(void 0, current, element, i, this); + current = %_CallFunction(receiver, current, element, i, this, callback); } } return current; @@ -1280,10 +1297,11 @@ function ArrayReduceRight(callback, current) { throw MakeTypeError('reduce_no_initial', []); } + var receiver = %GetDefaultReceiver(callback); for (; i >= 0; i--) { var element = this[i]; if (!IS_UNDEFINED(element) || i in this) { - current = callback.call(void 0, current, element, i, this); + current = %_CallFunction(receiver, current, element, i, this, callback); } } return current; @@ -1296,12 +1314,13 @@ function ArrayIsArray(obj) { // ------------------------------------------------------------------- -function SetupArray() { - // Setup non-enumerable constructor property on the Array.prototype +function SetUpArray() { + %CheckIsBootstrapping(); + // Set up non-enumerable constructor property on the Array.prototype // object. %SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM); - // Setup non-enumerable functions on the Array object. + // Set up non-enumerable functions on the Array object. InstallFunctions($Array, DONT_ENUM, $Array( "isArray", ArrayIsArray )); @@ -1319,7 +1338,7 @@ function SetupArray() { return f; } - // Setup non-enumerable functions of the Array.prototype object and + // Set up non-enumerable functions of the Array.prototype object and // set their names. // Manipulate the length of some of the functions to meet // expectations set by ECMA-262 or Mozilla. @@ -1350,19 +1369,13 @@ function SetupArray() { %FinishArrayPrototypeSetup($Array.prototype); // The internal Array prototype doesn't need to be fancy, since it's never - // exposed to user code, so no hidden prototypes or DONT_ENUM attributes - // are necessary. - // The null __proto__ ensures that we never inherit any user created - // getters or setters from, e.g., Object.prototype. - InternalArray.prototype.__proto__ = null; - // Adding only the functions that are actually used, and a toString. - InternalArray.prototype.join = getFunction("join", ArrayJoin); - InternalArray.prototype.pop = getFunction("pop", ArrayPop); - InternalArray.prototype.push = getFunction("push", ArrayPush); - InternalArray.prototype.toString = function() { - return "Internal Array, length " + this.length; - }; + // exposed to user code. + // Adding only the functions that are actually used. + SetUpLockedPrototype(InternalArray, $Array(), $Array( + "join", getFunction("join", ArrayJoin), + "pop", getFunction("pop", ArrayPop), + "push", getFunction("push", ArrayPush) + )); } - -SetupArray(); +SetUpArray(); diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 7319abe6dd..8b8a2a884e 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -36,20 +36,9 @@ namespace v8 { namespace internal { -AstSentinels::AstSentinels() - : this_proxy_(Isolate::Current(), true), - identifier_proxy_(Isolate::Current(), false), - valid_left_hand_side_sentinel_(Isolate::Current()), - this_property_(Isolate::Current(), &this_proxy_, NULL, 0), - call_sentinel_(Isolate::Current(), NULL, NULL, 0) { -} - - // ---------------------------------------------------------------------------- // All the Accept member functions for each syntax tree node type. -void Slot::Accept(AstVisitor* v) { v->VisitSlot(this); } - #define DECL_ACCEPT(type) \ void type::Accept(AstVisitor* v) { v->Visit##type(this); } AST_NODE_LIST(DECL_ACCEPT) @@ -101,15 +90,6 @@ VariableProxy::VariableProxy(Isolate* isolate, } -VariableProxy::VariableProxy(Isolate* isolate, bool is_this) - : Expression(isolate), - var_(NULL), - is_this_(is_this), - inside_with_(false), - is_trivial_(false) { -} - - void VariableProxy::BindTo(Variable* var) { ASSERT(var_ == NULL); // must be bound only once ASSERT(var != NULL); // must bind @@ -414,12 +394,6 @@ bool TargetCollector::IsInlineable() const { } -bool Slot::IsInlineable() const { - UNREACHABLE(); - return false; -} - - bool ForInStatement::IsInlineable() const { return false; } @@ -487,12 +461,6 @@ bool SharedFunctionInfoLiteral::IsInlineable() const { } -bool ValidLeftHandSideSentinel::IsInlineable() const { - UNREACHABLE(); - return false; -} - - bool ForStatement::IsInlineable() const { return (init() == NULL || init()->IsInlineable()) && (cond() == NULL || cond()->IsInlineable()) @@ -566,7 +534,7 @@ bool Conditional::IsInlineable() const { bool VariableProxy::IsInlineable() const { - return var()->is_global() || var()->IsStackAllocated(); + return var()->IsUnallocated() || var()->IsStackAllocated(); } diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 74182d5dc1..0eacb42102 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -134,6 +134,10 @@ class AstNode: public ZoneObject { static const int kNoNumber = -1; static const int kFunctionEntryId = 2; // Using 0 could disguise errors. + // This AST id identifies the point after the declarations have been + // visited. We need it to capture the environment effects of declarations + // that emit code (function declarations). + static const int kDeclarationsId = 3; // Override ZoneObject's new to count allocated AST nodes. void* operator new(size_t size, Zone* zone) { @@ -161,7 +165,6 @@ class AstNode: public ZoneObject { virtual BreakableStatement* AsBreakableStatement() { return NULL; } virtual IterationStatement* AsIterationStatement() { return NULL; } virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; } - virtual Slot* AsSlot() { return NULL; } // True if the node is simple enough for us to inline calls containing it. virtual bool IsInlineable() const = 0; @@ -316,20 +319,6 @@ class Expression: public AstNode { }; -/** - * A sentinel used during pre parsing that represents some expression - * that is a valid left hand side without having to actually build - * the expression. - */ -class ValidLeftHandSideSentinel: public Expression { - public: - explicit ValidLeftHandSideSentinel(Isolate* isolate) : Expression(isolate) {} - virtual bool IsValidLeftHandSide() { return true; } - virtual void Accept(AstVisitor* v) { UNREACHABLE(); } - virtual bool IsInlineable() const; -}; - - class BreakableStatement: public Statement { public: enum Type { @@ -404,10 +393,14 @@ class Block: public BreakableStatement { class Declaration: public AstNode { public: - Declaration(VariableProxy* proxy, Variable::Mode mode, FunctionLiteral* fun) + Declaration(VariableProxy* proxy, + Variable::Mode mode, + FunctionLiteral* fun, + Scope* scope) : proxy_(proxy), mode_(mode), - fun_(fun) { + fun_(fun), + scope_(scope) { ASSERT(mode == Variable::VAR || mode == Variable::CONST || mode == Variable::LET); @@ -421,11 +414,15 @@ class Declaration: public AstNode { Variable::Mode mode() const { return mode_; } FunctionLiteral* fun() const { return fun_; } // may be NULL virtual bool IsInlineable() const; + Scope* scope() const { return scope_; } private: VariableProxy* proxy_; Variable::Mode mode_; FunctionLiteral* fun_; + + // Nested scope from which the declaration originated. + Scope* scope_; }; @@ -1114,9 +1111,6 @@ class VariableProxy: public Expression { DECLARE_NODE_TYPE(VariableProxy) - // Type testing & conversion - Variable* AsVariable() { return (this == NULL) ? NULL : var_; } - virtual bool IsValidLeftHandSide() { return var_ == NULL ? true : var_->IsValidLeftHandSide(); } @@ -1133,10 +1127,7 @@ class VariableProxy: public Expression { return !is_this() && name().is_identical_to(n); } - bool IsArguments() { - Variable* variable = AsVariable(); - return (variable == NULL) ? false : variable->is_arguments(); - } + bool IsArguments() { return var_ != NULL && var_->is_arguments(); } Handle<String> name() const { return name_; } Variable* var() const { return var_; } @@ -1162,73 +1153,11 @@ class VariableProxy: public Expression { bool is_this, bool inside_with, int position = RelocInfo::kNoPosition); - VariableProxy(Isolate* isolate, bool is_this); friend class Scope; }; -class VariableProxySentinel: public VariableProxy { - public: - virtual bool IsValidLeftHandSide() { return !is_this(); } - - private: - VariableProxySentinel(Isolate* isolate, bool is_this) - : VariableProxy(isolate, is_this) { } - - friend class AstSentinels; -}; - - -class Slot: public Expression { - public: - enum Type { - // A slot in the parameter section on the stack. index() is - // the parameter index, counting left-to-right, starting at 0. - PARAMETER, - - // A slot in the local section on the stack. index() is - // the variable index in the stack frame, starting at 0. - LOCAL, - - // An indexed slot in a heap context. index() is the - // variable index in the context object on the heap, - // starting at 0. var()->scope() is the corresponding - // scope. - CONTEXT, - - // A named slot in a heap context. var()->name() is the - // variable name in the context object on the heap, - // with lookup starting at the current context. index() - // is invalid. - LOOKUP - }; - - Slot(Isolate* isolate, Variable* var, Type type, int index) - : Expression(isolate), var_(var), type_(type), index_(index) { - ASSERT(var != NULL); - } - - virtual void Accept(AstVisitor* v); - - virtual Slot* AsSlot() { return this; } - - bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; } - - // Accessors - Variable* var() const { return var_; } - Type type() const { return type_; } - int index() const { return index_; } - bool is_arguments() const { return var_->is_arguments(); } - virtual bool IsInlineable() const; - - private: - Variable* var_; - Type type_; - int index_; -}; - - class Property: public Expression { public: Property(Isolate* isolate, @@ -1337,36 +1266,6 @@ class Call: public Expression { }; -class AstSentinels { - public: - ~AstSentinels() { } - - // Returns a property singleton property access on 'this'. Used - // during preparsing. - Property* this_property() { return &this_property_; } - VariableProxySentinel* this_proxy() { return &this_proxy_; } - VariableProxySentinel* identifier_proxy() { return &identifier_proxy_; } - ValidLeftHandSideSentinel* valid_left_hand_side_sentinel() { - return &valid_left_hand_side_sentinel_; - } - Call* call_sentinel() { return &call_sentinel_; } - EmptyStatement* empty_statement() { return &empty_statement_; } - - private: - AstSentinels(); - VariableProxySentinel this_proxy_; - VariableProxySentinel identifier_proxy_; - ValidLeftHandSideSentinel valid_left_hand_side_sentinel_; - Property this_property_; - Call call_sentinel_; - EmptyStatement empty_statement_; - - friend class Isolate; - - DISALLOW_COPY_AND_ASSIGN(AstSentinels); -}; - - class CallNew: public Expression { public: CallNew(Isolate* isolate, @@ -2239,9 +2138,6 @@ class AstVisitor BASE_EMBEDDED { void SetStackOverflow() { stack_overflow_ = true; } void ClearStackOverflow() { stack_overflow_ = false; } - // Nodes not appearing in the AST, including slots. - virtual void VisitSlot(Slot* node) { UNREACHABLE(); } - // Individual AST nodes. #define DEF_VISIT(type) \ virtual void Visit##type(type* node) = 0; diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 4f7cf40940..7abd45cac0 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -350,7 +350,14 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target, prototype, call_code, is_ecma_native); - SetLocalPropertyNoThrow(target, symbol, function, DONT_ENUM); + PropertyAttributes attributes; + if (target->IsJSBuiltinsObject()) { + attributes = + static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY); + } else { + attributes = DONT_ENUM; + } + SetLocalPropertyNoThrow(target, symbol, function, attributes); if (is_ecma_native) { function->shared()->set_instance_class_name(*symbol); } @@ -1160,7 +1167,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, { - // Setup the call-as-function delegate. + // Set up the call-as-function delegate. Handle<Code> code = Handle<Code>(isolate->builtins()->builtin( Builtins::kHandleApiCallAsFunction)); @@ -1172,7 +1179,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, } { - // Setup the call-as-constructor delegate. + // Set up the call-as-constructor delegate. Handle<Code> code = Handle<Code>(isolate->builtins()->builtin( Builtins::kHandleApiCallAsConstructor)); @@ -1192,15 +1199,15 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, void Genesis::InitializeExperimentalGlobal() { - Isolate* isolate = this->isolate(); Handle<JSObject> global = Handle<JSObject>(global_context()->global()); // TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no // longer need to live behind a flag, so WeakMap gets added to the snapshot. if (FLAG_harmony_weakmaps) { // -- W e a k M a p + Handle<JSObject> prototype = + factory()->NewJSObject(isolate()->object_function(), TENURED); InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize, - isolate->initial_object_prototype(), - Builtins::kIllegal, true); + prototype, Builtins::kIllegal, true); } } @@ -1677,7 +1684,6 @@ bool Genesis::InstallNatives() { global_context()->set_regexp_result_map(*initial_map); } - #ifdef DEBUG builtins->Verify(); #endif diff --git a/deps/v8/src/checks.h b/deps/v8/src/checks.h index a560b2fb15..2f359f6cd8 100644 --- a/deps/v8/src/checks.h +++ b/deps/v8/src/checks.h @@ -251,9 +251,9 @@ template <> class StaticAssertion<true> { }; // actually causes each use to introduce a new defined type with a // name depending on the source line. template <int> class StaticAssertionHelper { }; -#define STATIC_CHECK(test) \ - typedef \ - StaticAssertionHelper<sizeof(StaticAssertion<static_cast<bool>(test)>)> \ +#define STATIC_CHECK(test) \ + typedef \ + StaticAssertionHelper<sizeof(StaticAssertion<static_cast<bool>((test))>)> \ SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__) diff --git a/deps/v8/src/contexts.cc b/deps/v8/src/contexts.cc index c0e724253f..4f93abdff1 100644 --- a/deps/v8/src/contexts.cc +++ b/deps/v8/src/contexts.cc @@ -87,13 +87,15 @@ void Context::set_global_proxy(JSObject* object) { Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, int* index_, - PropertyAttributes* attributes) { + PropertyAttributes* attributes, + BindingFlags* binding_flags) { Isolate* isolate = GetIsolate(); Handle<Context> context(this, isolate); bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; *index_ = -1; *attributes = ABSENT; + *binding_flags = MISSING_BINDING; if (FLAG_trace_contexts) { PrintF("Context::Lookup("); @@ -118,6 +120,7 @@ Handle<Object> Context::Lookup(Handle<String> name, } *index_ = Context::THROWN_OBJECT_INDEX; *attributes = NONE; + *binding_flags = MUTABLE_IS_INITIALIZED; return context; } } else { @@ -180,11 +183,16 @@ Handle<Object> Context::Lookup(Handle<String> name, switch (mode) { case Variable::INTERNAL: // Fall through. case Variable::VAR: + *attributes = NONE; + *binding_flags = MUTABLE_IS_INITIALIZED; + break; case Variable::LET: *attributes = NONE; + *binding_flags = MUTABLE_CHECK_INITIALIZED; break; case Variable::CONST: *attributes = READ_ONLY; + *binding_flags = IMMUTABLE_CHECK_INITIALIZED; break; case Variable::DYNAMIC: case Variable::DYNAMIC_GLOBAL: @@ -207,6 +215,7 @@ Handle<Object> Context::Lookup(Handle<String> name, } *index_ = index; *attributes = READ_ONLY; + *binding_flags = IMMUTABLE_IS_INITIALIZED; return context; } } diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h index 3d9e7f4bfe..505f86c8ca 100644 --- a/deps/v8/src/contexts.h +++ b/deps/v8/src/contexts.h @@ -44,6 +44,30 @@ enum ContextLookupFlags { }; +// ES5 10.2 defines lexical environments with mutable and immutable bindings. +// Immutable bindings have two states, initialized and uninitialized, and +// their state is changed by the InitializeImmutableBinding method. +// +// The harmony proposal for block scoped bindings also introduces the +// uninitialized state for mutable bindings. A 'let' declared variable +// is a mutable binding that is created uninitalized upon activation of its +// lexical environment and it is initialized when evaluating its declaration +// statement. Var declared variables are mutable bindings that are +// immediately initialized upon creation. The BindingFlags enum represents +// information if a binding has definitely been initialized. 'const' declared +// variables are created as uninitialized immutable bindings. + +// In harmony mode accessing an uninitialized binding produces a reference +// error. +enum BindingFlags { + MUTABLE_IS_INITIALIZED, + MUTABLE_CHECK_INITIALIZED, + IMMUTABLE_IS_INITIALIZED, + IMMUTABLE_CHECK_INITIALIZED, + MISSING_BINDING +}; + + // Heap-allocated activation contexts. // // Contexts are implemented as FixedArray objects; the Context @@ -351,8 +375,11 @@ class Context: public FixedArray { // 4) index_ < 0 && result.is_null(): // there was no context found with the corresponding property. // attributes == ABSENT. - Handle<Object> Lookup(Handle<String> name, ContextLookupFlags flags, - int* index_, PropertyAttributes* attributes); + Handle<Object> Lookup(Handle<String> name, + ContextLookupFlags flags, + int* index_, + PropertyAttributes* attributes, + BindingFlags* binding_flags); // Determine if a local variable with the given name exists in a // context. Do not consider context extension objects. This is diff --git a/deps/v8/src/conversions.h b/deps/v8/src/conversions.h index 7b02c47f6a..0f8d5da8ee 100644 --- a/deps/v8/src/conversions.h +++ b/deps/v8/src/conversions.h @@ -45,14 +45,14 @@ namespace internal { const int kMaxSignificantDigits = 772; -static bool isDigit(int x, int radix) { +static inline bool isDigit(int x, int radix) { return (x >= '0' && x <= '9' && x < '0' + radix) || (radix > 10 && x >= 'a' && x < 'a' + radix - 10) || (radix > 10 && x >= 'A' && x < 'A' + radix - 10); } -static double SignedZero(bool negative) { +static inline double SignedZero(bool negative) { return negative ? -0.0 : 0.0; } diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index 120496eccc..5c60436892 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -176,8 +176,8 @@ bool Shell::ExecuteString(Handle<String> source, // If all went well and the result wasn't undefined then print // the returned value. v8::String::Utf8Value str(result); - const char* cstr = ToCString(str); - printf("%s\n", cstr); + fwrite(*str, sizeof(**str), str.length(), stdout); + printf("\n"); } return true; } @@ -678,12 +678,12 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { FunctionTemplate::New(PixelArray)); #ifdef LIVE_OBJECT_LIST - global_template->Set(String::New("lol_is_enabled"), Boolean::New(true)); + global_template->Set(String::New("lol_is_enabled"), True()); #else - global_template->Set(String::New("lol_is_enabled"), Boolean::New(false)); + global_template->Set(String::New("lol_is_enabled"), False()); #endif -#ifndef V8_SHARED +#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64) Handle<ObjectTemplate> os_templ = ObjectTemplate::New(); AddOSMethods(os_templ); global_template->Set(String::New("os"), os_templ); @@ -864,7 +864,7 @@ Handle<String> Shell::ReadFile(const char* name) { void Shell::RunShell() { Locker locker; Context::Scope context_scope(evaluation_context_); - HandleScope handle_scope; + HandleScope outer_scope; Handle<String> name = String::New("(d8)"); #ifndef V8_SHARED LineEditor* editor = LineEditor::Get(); @@ -877,6 +877,7 @@ void Shell::RunShell() { i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt); if (input.is_empty()) break; editor->AddHistory(*input); + HandleScope inner_scope; ExecuteString(String::New(*input), name, true, true); } editor->Close(); @@ -887,6 +888,7 @@ void Shell::RunShell() { 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 diff --git a/deps/v8/src/d8.js b/deps/v8/src/d8.js index a2b9585ce8..3009037e78 100644 --- a/deps/v8/src/d8.js +++ b/deps/v8/src/d8.js @@ -1786,7 +1786,7 @@ function decodeLolInfoResponse(body) { function decodeLolListResponse(body, title) { - + var result; var total_count = body.count; var total_size = body.size; diff --git a/deps/v8/src/date.js b/deps/v8/src/date.js index 79b846d4a7..ccefce5763 100644 --- a/deps/v8/src/date.js +++ b/deps/v8/src/date.js @@ -1048,18 +1048,19 @@ function ResetDateCache() { // ------------------------------------------------------------------- -function SetupDate() { - // Setup non-enumerable properties of the Date object itself. +function SetUpDate() { + %CheckIsBootstrapping(); + // Set up non-enumerable properties of the Date object itself. InstallFunctions($Date, DONT_ENUM, $Array( "UTC", DateUTC, "parse", DateParse, "now", DateNow )); - // Setup non-enumerable constructor property of the Date prototype object. + // Set up non-enumerable constructor property of the Date prototype object. %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM); - // Setup non-enumerable functions of the Date prototype object and + // Set up non-enumerable functions of the Date prototype object and // set their names. InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array( "toString", DateToString, @@ -1111,4 +1112,4 @@ function SetupDate() { )); } -SetupDate(); +SetUpDate(); diff --git a/deps/v8/src/elements.cc b/deps/v8/src/elements.cc index 70d58b31ac..1afc5dad5e 100644 --- a/deps/v8/src/elements.cc +++ b/deps/v8/src/elements.cc @@ -590,7 +590,6 @@ ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) { default: UNREACHABLE(); return NULL; - break; } } diff --git a/deps/v8/src/extensions/externalize-string-extension.cc b/deps/v8/src/extensions/externalize-string-extension.cc index b3f83fe98d..9fbf329818 100644 --- a/deps/v8/src/extensions/externalize-string-extension.cc +++ b/deps/v8/src/extensions/externalize-string-extension.cc @@ -133,9 +133,11 @@ v8::Handle<v8::Value> ExternalizeStringExtension::IsAscii( void ExternalizeStringExtension::Register() { - static ExternalizeStringExtension externalize_extension; + static ExternalizeStringExtension* externalize_extension = NULL; + if (externalize_extension == NULL) + externalize_extension = new ExternalizeStringExtension; static v8::DeclareExtension externalize_extension_declaration( - &externalize_extension); + externalize_extension); } } } // namespace v8::internal diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index fc7b6899bc..d810bb3dc0 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -190,9 +190,9 @@ void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) { void BreakableStatementChecker::VisitAssignment(Assignment* expr) { // If assigning to a property (including a global property) the assignment is // breakable. - Variable* var = expr->target()->AsVariableProxy()->AsVariable(); + VariableProxy* proxy = expr->target()->AsVariableProxy(); Property* prop = expr->target()->AsProperty(); - if (prop != NULL || (var != NULL && var->is_global())) { + if (prop != NULL || (proxy != NULL && proxy->var()->IsUnallocated())) { is_breakable_ = true; return; } @@ -395,26 +395,6 @@ void FullCodeGenerator::RecordStackCheck(int ast_id) { } -int FullCodeGenerator::SlotOffset(Slot* slot) { - ASSERT(slot != NULL); - // Offset is negative because higher indexes are at lower addresses. - int offset = -slot->index() * kPointerSize; - // Adjust by a (parameter or local) base offset. - switch (slot->type()) { - case Slot::PARAMETER: - offset += (info_->scope()->num_parameters() + 1) * kPointerSize; - break; - case Slot::LOCAL: - offset += JavaScriptFrameConstants::kLocal0Offset; - break; - case Slot::CONTEXT: - case Slot::LOOKUP: - UNREACHABLE(); - } - return offset; -} - - bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) { // Inline smi case inside loops, but not division and modulo which // are too complicated and take up too much space. @@ -529,34 +509,21 @@ void FullCodeGenerator::DoTest(const TestContext* context) { void FullCodeGenerator::VisitDeclarations( ZoneList<Declaration*>* declarations) { int length = declarations->length(); - int globals = 0; + int global_count = 0; for (int i = 0; i < length; i++) { Declaration* decl = declarations->at(i); - Variable* var = decl->proxy()->var(); - Slot* slot = var->AsSlot(); - - // If it was not possible to allocate the variable at compile - // time, we need to "declare" it at runtime to make sure it - // actually exists in the local context. - if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) { - VisitDeclaration(decl); - } else { - // Count global variables and functions for later processing - globals++; - } + EmitDeclaration(decl->proxy(), decl->mode(), decl->fun(), &global_count); } - // Compute array of global variable and function declarations. - // Do nothing in case of no declared global functions or variables. - if (globals > 0) { + // Batch declare global functions and variables. + if (global_count > 0) { Handle<FixedArray> array = - isolate()->factory()->NewFixedArray(2 * globals, TENURED); + isolate()->factory()->NewFixedArray(2 * global_count, TENURED); for (int j = 0, i = 0; i < length; i++) { Declaration* decl = declarations->at(i); Variable* var = decl->proxy()->var(); - Slot* slot = var->AsSlot(); - if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) { + if (var->IsUnallocated()) { array->set(j++, *(var->name())); if (decl->fun() == NULL) { if (var->mode() == Variable::CONST) { @@ -578,12 +545,21 @@ void FullCodeGenerator::VisitDeclarations( } } // Invoke the platform-dependent code generator to do the actual - // declaration the global variables and functions. + // declaration the global functions and variables. DeclareGlobals(array); } } +int FullCodeGenerator::DeclareGlobalsFlags() { + int flags = 0; + if (is_eval()) flags |= kDeclareGlobalsEvalFlag; + if (is_strict_mode()) flags |= kDeclareGlobalsStrictModeFlag; + if (is_native()) flags |= kDeclareGlobalsNativeFlag; + return flags; +} + + void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) { CodeGenerator::RecordPositions(masm_, fun->start_position()); } @@ -842,10 +818,11 @@ void FullCodeGenerator::VisitInCurrentContext(Expression* expr) { void FullCodeGenerator::VisitBlock(Block* stmt) { Comment cmnt(masm_, "[ Block"); - Breakable nested_statement(this, stmt); + NestedBlock nested_block(this, stmt); SetStatementPosition(stmt); Scope* saved_scope = scope(); + // Push a block context when entering a block with block scoped variables. if (stmt->block_scope() != NULL) { { Comment cmnt(masm_, "[ Extend block context"); scope_ = stmt->block_scope(); @@ -862,8 +839,16 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); VisitStatements(stmt->statements()); scope_ = saved_scope; - __ bind(nested_statement.break_label()); + __ bind(nested_block.break_label()); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); + + // Pop block context if necessary. + if (stmt->block_scope() != NULL) { + LoadContextField(context_register(), Context::PREVIOUS_INDEX); + // Update local stack frame context field. + StoreToFrameField(StandardFrameConstants::kContextOffset, + context_register()); + } } @@ -1336,25 +1321,6 @@ void FullCodeGenerator::VisitThrow(Throw* expr) { } -FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( - int* stack_depth, - int* context_length) { - // The macros used here must preserve the result register. - __ Drop(*stack_depth); - __ PopTryHandler(); - *stack_depth = 0; - - Register context = FullCodeGenerator::context_register(); - while (*context_length > 0) { - codegen_->LoadContextField(context, Context::PREVIOUS_INDEX); - --(*context_length); - } - - __ Call(finally_entry_); - return previous_; -} - - FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit( int* stack_depth, int* context_length) { diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index 0ed26a149e..803c618732 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -191,6 +191,22 @@ class FullCodeGenerator: public AstVisitor { Label continue_label_; }; + // A nested block statement. + class NestedBlock : public Breakable { + public: + NestedBlock(FullCodeGenerator* codegen, Block* block) + : Breakable(codegen, block) { + } + virtual ~NestedBlock() {} + + virtual NestedStatement* Exit(int* stack_depth, int* context_length) { + if (statement()->AsBlock()->block_scope() != NULL) { + ++(*context_length); + } + return previous_; + }; + }; + // The try block of a try/catch statement. class TryCatch : public NestedStatement { public: @@ -288,10 +304,6 @@ class FullCodeGenerator: public AstVisitor { // with a GC-safe value. void ClearAccumulator(); - // Compute the frame pointer relative offset for a given local or - // parameter slot. - int SlotOffset(Slot* slot); - // Determine whether or not to inline the smi case for the given // operation. bool ShouldInlineSmiCase(Token::Value op); @@ -321,13 +333,29 @@ class FullCodeGenerator: public AstVisitor { Label* fall_through); #endif // V8_TARGET_ARCH_MIPS - void Move(Slot* dst, Register source, Register scratch1, Register scratch2); - void Move(Register dst, Slot* source); - - // Return an operand used to read/write to a known (ie, non-LOOKUP) slot. - // May emit code to traverse the context chain, destroying the scratch - // register. - MemOperand EmitSlotSearch(Slot* slot, Register scratch); + // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into + // a register. Emits a context chain walk if if necessary (so does + // SetVar) so avoid calling both on the same variable. + void GetVar(Register destination, Variable* var); + + // Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable. If it's in + // the context, the write barrier will be emitted and source, scratch0, + // scratch1 will be clobbered. Emits a context chain walk if if necessary + // (so does GetVar) so avoid calling both on the same variable. + void SetVar(Variable* var, + Register source, + Register scratch0, + Register scratch1); + + // An operand used to read/write a stack-allocated (PARAMETER or LOCAL) + // variable. Writing does not need the write barrier. + MemOperand StackOperand(Variable* var); + + // An operand used to read/write a known (PARAMETER, LOCAL, or CONTEXT) + // variable. May emit code to traverse the context chain, loading the + // found context into the scratch register. Writing to this operand will + // need the write barrier if location is CONTEXT. + MemOperand VarOperand(Variable* var, Register scratch); // Forward the bailout responsibility for the given expression to // the next child visited (which must be in a test context). @@ -358,6 +386,7 @@ class FullCodeGenerator: public AstVisitor { void VisitDeclarations(ZoneList<Declaration*>* declarations); void DeclareGlobals(Handle<FixedArray> pairs); + int DeclareGlobalsFlags(); // Try to perform a comparison as a fast inlined literal compare if // the operands allow it. Returns true if the compare operations @@ -402,9 +431,10 @@ class FullCodeGenerator: public AstVisitor { // Platform-specific code for a variable, constant, or function // declaration. Functions have an initial value. - void EmitDeclaration(Variable* variable, + void EmitDeclaration(VariableProxy* proxy, Variable::Mode mode, - FunctionLiteral* function); + FunctionLiteral* function, + int* global_count); // Platform-specific code for checking the stack limit at the back edge of // a loop. @@ -435,14 +465,14 @@ class FullCodeGenerator: public AstVisitor { #undef EMIT_INLINE_RUNTIME_CALL // Platform-specific code for loading variables. - void EmitLoadGlobalSlotCheckExtensions(Slot* slot, - TypeofState typeof_state, - Label* slow); - MemOperand ContextSlotOperandCheckExtensions(Slot* slot, Label* slow); - void EmitDynamicLoadFromSlotFastCase(Slot* slot, - TypeofState typeof_state, - Label* slow, - Label* done); + void EmitLoadGlobalCheckExtensions(Variable* var, + TypeofState typeof_state, + Label* slow); + MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow); + void EmitDynamicLookupFastCase(Variable* var, + TypeofState typeof_state, + Label* slow, + Label* done); void EmitVariableLoad(VariableProxy* proxy); enum ResolveEvalFlag { @@ -555,6 +585,7 @@ class FullCodeGenerator: public AstVisitor { Handle<Script> script() { return info_->script(); } bool is_eval() { return info_->is_eval(); } + bool is_native() { return info_->is_native(); } bool is_strict_mode() { return function()->strict_mode(); } StrictModeFlag strict_mode_flag() { return is_strict_mode() ? kStrictMode : kNonStrictMode; @@ -618,11 +649,11 @@ class FullCodeGenerator: public AstVisitor { // this expression context. virtual void Plug(bool flag) const = 0; - // Emit code to convert a pure value (in a register, slot, as a literal, - // or on top of the stack) into the result expected according to this - // expression context. + // Emit code to convert a pure value (in a register, known variable + // location, as a literal, or on top of the stack) into the result + // expected according to this expression context. virtual void Plug(Register reg) const = 0; - virtual void Plug(Slot* slot) const = 0; + virtual void Plug(Variable* var) const = 0; virtual void Plug(Handle<Object> lit) const = 0; virtual void Plug(Heap::RootListIndex index) const = 0; virtual void PlugTOS() const = 0; @@ -680,7 +711,7 @@ class FullCodeGenerator: public AstVisitor { virtual void Plug(bool flag) const; virtual void Plug(Register reg) const; virtual void Plug(Label* materialize_true, Label* materialize_false) const; - virtual void Plug(Slot* slot) const; + virtual void Plug(Variable* var) const; virtual void Plug(Handle<Object> lit) const; virtual void Plug(Heap::RootListIndex) const; virtual void PlugTOS() const; @@ -703,7 +734,7 @@ class FullCodeGenerator: public AstVisitor { virtual void Plug(bool flag) const; virtual void Plug(Register reg) const; virtual void Plug(Label* materialize_true, Label* materialize_false) const; - virtual void Plug(Slot* slot) const; + virtual void Plug(Variable* var) const; virtual void Plug(Handle<Object> lit) const; virtual void Plug(Heap::RootListIndex) const; virtual void PlugTOS() const; @@ -744,7 +775,7 @@ class FullCodeGenerator: public AstVisitor { virtual void Plug(bool flag) const; virtual void Plug(Register reg) const; virtual void Plug(Label* materialize_true, Label* materialize_false) const; - virtual void Plug(Slot* slot) const; + virtual void Plug(Variable* var) const; virtual void Plug(Handle<Object> lit) const; virtual void Plug(Heap::RootListIndex) const; virtual void PlugTOS() const; @@ -774,7 +805,7 @@ class FullCodeGenerator: public AstVisitor { virtual void Plug(bool flag) const; virtual void Plug(Register reg) const; virtual void Plug(Label* materialize_true, Label* materialize_false) const; - virtual void Plug(Slot* slot) const; + virtual void Plug(Variable* var) const; virtual void Plug(Handle<Object> lit) const; virtual void Plug(Heap::RootListIndex) const; virtual void PlugTOS() const; diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 90d0e11edd..a480e9e331 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -81,14 +81,14 @@ Heap::Heap() reserved_semispace_size_(16*MB), max_semispace_size_(16*MB), initial_semispace_size_(1*MB), - max_old_generation_size_(1*GB), + max_old_generation_size_(1400*MB), max_executable_size_(256*MB), code_range_size_(512*MB), #else reserved_semispace_size_(8*MB), max_semispace_size_(8*MB), initial_semispace_size_(512*KB), - max_old_generation_size_(512*MB), + max_old_generation_size_(700*MB), max_executable_size_(128*MB), code_range_size_(0), #endif @@ -842,6 +842,7 @@ void Heap::MarkCompactPrologue(bool is_compacting) { isolate_->keyed_lookup_cache()->Clear(); isolate_->context_slot_cache()->Clear(); isolate_->descriptor_lookup_cache()->Clear(); + StringSplitCache::Clear(string_split_cache()); isolate_->compilation_cache()->MarkCompactPrologue(); @@ -2223,6 +2224,13 @@ bool Heap::CreateInitialObjects() { } set_single_character_string_cache(FixedArray::cast(obj)); + // Allocate cache for string split. + { MaybeObject* maybe_obj = + AllocateFixedArray(StringSplitCache::kStringSplitCacheSize, TENURED); + if (!maybe_obj->ToObject(&obj)) return false; + } + set_string_split_cache(FixedArray::cast(obj)); + // Allocate cache for external strings pointing to native source code. { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount()); if (!maybe_obj->ToObject(&obj)) return false; @@ -2248,6 +2256,75 @@ bool Heap::CreateInitialObjects() { } +Object* StringSplitCache::Lookup( + FixedArray* cache, String* string, String* pattern) { + if (!string->IsSymbol() || !pattern->IsSymbol()) return Smi::FromInt(0); + uintptr_t hash = string->Hash(); + uintptr_t index = ((hash & (kStringSplitCacheSize - 1)) & + ~(kArrayEntriesPerCacheEntry - 1)); + if (cache->get(index + kStringOffset) == string && + cache->get(index + kPatternOffset) == pattern) { + return cache->get(index + kArrayOffset); + } + index = ((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1)); + if (cache->get(index + kStringOffset) == string && + cache->get(index + kPatternOffset) == pattern) { + return cache->get(index + kArrayOffset); + } + return Smi::FromInt(0); +} + + +void StringSplitCache::Enter(Heap* heap, + FixedArray* cache, + String* string, + String* pattern, + FixedArray* array) { + if (!string->IsSymbol() || !pattern->IsSymbol()) return; + uintptr_t hash = string->Hash(); + array->set_map(heap->fixed_cow_array_map()); + uintptr_t index = ((hash & (kStringSplitCacheSize - 1)) & + ~(kArrayEntriesPerCacheEntry - 1)); + if (cache->get(index + kStringOffset) == Smi::FromInt(0)) { + cache->set(index + kStringOffset, string); + cache->set(index + kPatternOffset, pattern); + cache->set(index + kArrayOffset, array); + return; + } + uintptr_t index2 = + ((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1)); + if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) { + cache->set(index2 + kStringOffset, string); + cache->set(index2 + kPatternOffset, pattern); + cache->set(index2 + kArrayOffset, array); + return; + } + cache->set(index2 + kStringOffset, Smi::FromInt(0)); + cache->set(index2 + kPatternOffset, Smi::FromInt(0)); + cache->set(index2 + kArrayOffset, Smi::FromInt(0)); + cache->set(index + kStringOffset, string); + cache->set(index + kPatternOffset, pattern); + cache->set(index + kArrayOffset, array); + if (array->length() < 100) { // Limit how many new symbols we want to make. + for (int i = 0; i < array->length(); i++) { + String* str = String::cast(array->get(i)); + Object* symbol; + MaybeObject* maybe_symbol = heap->LookupSymbol(str); + if (maybe_symbol->ToObject(&symbol)) { + array->set(i, symbol); + } + } + } +} + + +void StringSplitCache::Clear(FixedArray* cache) { + for (int i = 0; i < kStringSplitCacheSize; i++) { + cache->set(i, Smi::FromInt(0)); + } +} + + MaybeObject* Heap::InitializeNumberStringCache() { // Compute the size of the number string cache based on the max heap size. // max_semispace_size_ == 512 KB => number_string_cache_size = 32. @@ -4085,10 +4162,9 @@ MaybeObject* Heap::AllocateBlockContext(JSFunction* function, SerializedScopeInfo* scope_info) { Object* result; { MaybeObject* maybe_result = - AllocateFixedArray(scope_info->NumberOfContextSlots()); + AllocateFixedArrayWithHoles(scope_info->NumberOfContextSlots()); if (!maybe_result->ToObject(&result)) return maybe_result; } - // TODO(keuchel): properly initialize context slots. Context* context = reinterpret_cast<Context*>(result); context->set_map(block_context_map()); context->set_closure(function); diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index 0f69fab391..cc689df17b 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -77,6 +77,7 @@ inline Heap* _inline_get_heap_(); V(Object, instanceof_cache_map, InstanceofCacheMap) \ V(Object, instanceof_cache_answer, InstanceofCacheAnswer) \ V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \ + V(FixedArray, string_split_cache, StringSplitCache) \ V(Object, termination_exception, TerminationException) \ V(FixedArray, empty_fixed_array, EmptyFixedArray) \ V(ByteArray, empty_byte_array, EmptyByteArray) \ @@ -225,8 +226,7 @@ inline Heap* _inline_get_heap_(); V(closure_symbol, "(closure)") \ V(use_strict, "use strict") \ V(dot_symbol, ".") \ - V(anonymous_function_symbol, "(anonymous function)") \ - V(block_scope_symbol, ".block") + V(anonymous_function_symbol, "(anonymous function)") // Forward declarations. class GCTracer; @@ -2177,6 +2177,27 @@ class GCTracer BASE_EMBEDDED { }; +class StringSplitCache { + public: + static Object* Lookup(FixedArray* cache, String* string, String* pattern); + static void Enter(Heap* heap, + FixedArray* cache, + String* string, + String* pattern, + FixedArray* array); + static void Clear(FixedArray* cache); + static const int kStringSplitCacheSize = 0x100; + + private: + static const int kArrayEntriesPerCacheEntry = 4; + static const int kStringOffset = 0; + static const int kPatternOffset = 1; + static const int kArrayOffset = 2; + + static MaybeObject* WrapFixedArrayInJSArray(Object* fixed_array); +}; + + class TranscendentalCache { public: enum Type {ACOS, ASIN, ATAN, COS, EXP, LOG, SIN, TAN, kNumberOfCaches}; diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index d3cc8a62b4..14e1bc8a46 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/deps/v8/src/hydrogen-instructions.cc @@ -425,7 +425,7 @@ void HValue::PrintRangeTo(StringStream* stream) { void HValue::PrintChangesTo(StringStream* stream) { - int changes_flags = (flags() & HValue::ChangesFlagsMask()); + int changes_flags = ChangesFlags(); if (changes_flags == 0) return; stream->Add(" changes["); if (changes_flags == AllSideEffects()) { @@ -512,9 +512,7 @@ void HInstruction::PrintTo(StringStream* stream) { void HInstruction::PrintMnemonicTo(StringStream* stream) { - stream->Add("%s", Mnemonic()); - if (HasSideEffects()) stream->Add("*"); - stream->Add(" "); + stream->Add("%s ", Mnemonic()); } @@ -791,6 +789,13 @@ void HChange::PrintDataTo(StringStream* stream) { } +void HJSArrayLength::PrintDataTo(StringStream* stream) { + value()->PrintNameTo(stream); + stream->Add(" "); + typecheck()->PrintNameTo(stream); +} + + HValue* HCheckInstanceType::Canonicalize() { if (check_ == IS_STRING && !value()->type().IsUninitialized() && @@ -1020,11 +1025,14 @@ void HPhi::PrintTo(StringStream* stream) { value->PrintNameTo(stream); stream->Add(" "); } - stream->Add(" uses%d_%di_%dd_%dt]", + stream->Add(" uses%d_%di_%dd_%dt", UseCount(), int32_non_phi_uses() + int32_indirect_uses(), double_non_phi_uses() + double_indirect_uses(), tagged_non_phi_uses() + tagged_indirect_uses()); + stream->Add("%s%s]", + is_live() ? "_live" : "", + IsConvertibleToInteger() ? "" : "_ncti"); } diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index 76007d764e..3ccf302e40 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -513,19 +513,6 @@ class HValue: public ZoneObject { static const int kChangesToDependsFlagsLeftShift = 1; - static int ChangesFlagsMask() { - int result = 0; - // Create changes mask. -#define DECLARE_DO(type) result |= (1 << kChanges##type); - GVN_FLAG_LIST(DECLARE_DO) -#undef DECLARE_DO - return result; - } - - static int DependsFlagsMask() { - return ConvertChangesToDependsFlags(ChangesFlagsMask()); - } - static int ConvertChangesToDependsFlags(int flags) { return flags << kChangesToDependsFlagsLeftShift; } @@ -629,6 +616,8 @@ class HValue: public ZoneObject { void ClearAllSideEffects() { flags_ &= ~AllSideEffects(); } bool HasSideEffects() const { return (flags_ & AllSideEffects()) != 0; } + int ChangesFlags() const { return flags_ & ChangesFlagsMask(); } + Range* range() const { return range_; } bool HasRange() const { return range_ != NULL; } void AddNewRange(Range* r); @@ -693,6 +682,15 @@ class HValue: public ZoneObject { } private: + static int ChangesFlagsMask() { + int result = 0; + // Create changes mask. +#define ADD_FLAG(type) result |= (1 << 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); @@ -1696,7 +1694,10 @@ class HJSArrayLength: public HTemplateInstruction<2> { return Representation::Tagged(); } + virtual void PrintDataTo(StringStream* stream); + HValue* value() { return OperandAt(0); } + HValue* typecheck() { return OperandAt(1); } DECLARE_CONCRETE_INSTRUCTION(JSArrayLength) diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index dd3a591d60..01046bf9bf 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -1382,7 +1382,7 @@ void HGlobalValueNumberer::ComputeBlockSideEffects() { int id = block->block_id(); int side_effects = 0; while (instr != NULL) { - side_effects |= (instr->flags() & HValue::ChangesFlagsMask()); + side_effects |= instr->ChangesFlags(); instr = instr->next(); } block_side_effects_[id] |= side_effects; @@ -1499,7 +1499,7 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { HInstruction* instr = block->first(); while (instr != NULL) { HInstruction* next = instr->next(); - int flags = (instr->flags() & HValue::ChangesFlagsMask()); + int flags = instr->ChangesFlags(); if (flags != 0) { ASSERT(!instr->CheckFlag(HValue::kUseGVN)); // Clear all instructions in the map that are affected by side effects. @@ -2273,10 +2273,6 @@ HGraph* HGraphBuilder::CreateGraph() { return NULL; } SetupScope(scope); - VisitDeclarations(scope->declarations()); - HValue* context = environment()->LookupContext(); - AddInstruction( - new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry)); // Add an edge to the body entry. This is warty: the graph's start // environment will be used by the Lithium translation as the initial @@ -2298,6 +2294,19 @@ HGraph* HGraphBuilder::CreateGraph() { current_block()->Goto(body_entry); body_entry->SetJoinId(AstNode::kFunctionEntryId); set_current_block(body_entry); + + // Handle implicit declaration of the function name in named function + // expressions before other declarations. + if (scope->is_function_scope() && scope->function() != NULL) { + HandleDeclaration(scope->function(), Variable::CONST, NULL); + } + VisitDeclarations(scope->declarations()); + AddSimulate(AstNode::kDeclarationsId); + + HValue* context = environment()->LookupContext(); + AddInstruction( + new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry)); + VisitStatements(info()->function()->body()); if (HasStackOverflow()) return NULL; @@ -3119,54 +3128,63 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - Variable* variable = expr->AsVariable(); - if (variable == NULL) { - return Bailout("reference to rewritten variable"); - } else if (variable->IsStackAllocated()) { - HValue* value = environment()->Lookup(variable); - if (variable->mode() == Variable::CONST && - value == graph()->GetConstantHole()) { - return Bailout("reference to uninitialized const variable"); - } - return ast_context()->ReturnValue(value); - } else if (variable->IsContextSlot()) { - if (variable->mode() == Variable::CONST) { - return Bailout("reference to const context slot"); - } - HValue* context = BuildContextChainWalk(variable); - int index = variable->AsSlot()->index(); - HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index); - return ast_context()->ReturnInstruction(instr, expr->id()); - } else if (variable->is_global()) { - LookupResult lookup; - GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false); + Variable* variable = expr->var(); + if (variable->mode() == Variable::LET) { + return Bailout("reference to let variable"); + } + switch (variable->location()) { + case Variable::UNALLOCATED: { + LookupResult lookup; + GlobalPropertyAccess type = + LookupGlobalProperty(variable, &lookup, false); + + if (type == kUseCell && + info()->global_object()->IsAccessCheckNeeded()) { + type = kUseGeneric; + } - if (type == kUseCell && - info()->global_object()->IsAccessCheckNeeded()) { - type = kUseGeneric; + if (type == kUseCell) { + Handle<GlobalObject> global(info()->global_object()); + Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); + bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); + HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); + return ast_context()->ReturnInstruction(instr, expr->id()); + } else { + HValue* context = environment()->LookupContext(); + HGlobalObject* global_object = new(zone()) HGlobalObject(context); + AddInstruction(global_object); + HLoadGlobalGeneric* instr = + new(zone()) HLoadGlobalGeneric(context, + global_object, + variable->name(), + ast_context()->is_for_typeof()); + instr->set_position(expr->position()); + return ast_context()->ReturnInstruction(instr, expr->id()); + } } - if (type == kUseCell) { - Handle<GlobalObject> global(info()->global_object()); - Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); - bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); - HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); - return ast_context()->ReturnInstruction(instr, expr->id()); - } else { - HValue* context = environment()->LookupContext(); - HGlobalObject* global_object = new(zone()) HGlobalObject(context); - AddInstruction(global_object); - HLoadGlobalGeneric* instr = - new(zone()) HLoadGlobalGeneric(context, - global_object, - variable->name(), - ast_context()->is_for_typeof()); - instr->set_position(expr->position()); - ASSERT(instr->HasSideEffects()); + case Variable::PARAMETER: + case Variable::LOCAL: { + HValue* value = environment()->Lookup(variable); + if (variable->mode() == Variable::CONST && + value == graph()->GetConstantHole()) { + return Bailout("reference to uninitialized const variable"); + } + return ast_context()->ReturnValue(value); + } + + case Variable::CONTEXT: { + if (variable->mode() == Variable::CONST) { + return Bailout("reference to const context slot"); + } + HValue* context = BuildContextChainWalk(variable); + HLoadContextSlot* instr = + new(zone()) HLoadContextSlot(context, variable->index()); return ast_context()->ReturnInstruction(instr, expr->id()); } - } else { - return Bailout("reference to a variable which requires dynamic lookup"); + + case Variable::LOOKUP: + return Bailout("reference to a variable which requires dynamic lookup"); } } @@ -3578,51 +3596,61 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { Expression* target = expr->target(); VariableProxy* proxy = target->AsVariableProxy(); - Variable* var = proxy->AsVariable(); Property* prop = target->AsProperty(); - ASSERT(var == NULL || prop == NULL); + ASSERT(proxy == NULL || prop == NULL); // We have a second position recorded in the FullCodeGenerator to have // type feedback for the binary operation. BinaryOperation* operation = expr->binary_operation(); - if (var != NULL) { - if (var->mode() == Variable::CONST) { - return Bailout("unsupported const compound assignment"); + if (proxy != NULL) { + Variable* var = proxy->var(); + if (var->mode() == Variable::CONST || var->mode() == Variable::LET) { + return Bailout("unsupported let or const compound assignment"); } CHECK_ALIVE(VisitForValue(operation)); - if (var->is_global()) { - HandleGlobalVariableAssignment(var, - Top(), - expr->position(), - expr->AssignmentId()); - } else if (var->IsStackAllocated()) { - Bind(var, Top()); - } else if (var->IsContextSlot()) { - // Bail out if we try to mutate a parameter value in a function using - // the arguments object. We do not (yet) correctly handle the - // arguments property of the function. - if (info()->scope()->arguments() != NULL) { - // Parameters will rewrite to context slots. We have no direct way - // to detect that the variable is a parameter. - int count = info()->scope()->num_parameters(); - for (int i = 0; i < count; ++i) { - if (var == info()->scope()->parameter(i)) { - Bailout("assignment to parameter, function uses arguments object"); + switch (var->location()) { + case Variable::UNALLOCATED: + HandleGlobalVariableAssignment(var, + Top(), + expr->position(), + expr->AssignmentId()); + break; + + case Variable::PARAMETER: + case Variable::LOCAL: + Bind(var, Top()); + break; + + case Variable::CONTEXT: { + // Bail out if we try to mutate a parameter value in a function + // using the arguments object. We do not (yet) correctly handle the + // arguments property of the function. + if (info()->scope()->arguments() != NULL) { + // Parameters will be allocated to context slots. We have no + // direct way to detect that the variable is a parameter so we do + // a linear search of the parameter variables. + int count = info()->scope()->num_parameters(); + for (int i = 0; i < count; ++i) { + if (var == info()->scope()->parameter(i)) { + Bailout( + "assignment to parameter, function uses arguments object"); + } } } + + HValue* context = BuildContextChainWalk(var); + HStoreContextSlot* instr = + new(zone()) HStoreContextSlot(context, var->index(), Top()); + AddInstruction(instr); + if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); + break; } - HValue* context = BuildContextChainWalk(var); - int index = var->AsSlot()->index(); - HStoreContextSlot* instr = - new(zone()) HStoreContextSlot(context, index, Top()); - AddInstruction(instr); - if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); - } else { - return Bailout("compound assignment to lookup slot"); + case Variable::LOOKUP: + return Bailout("compound assignment to lookup slot"); } return ast_context()->ReturnValue(Pop()); @@ -3710,16 +3738,18 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); VariableProxy* proxy = expr->target()->AsVariableProxy(); - Variable* var = proxy->AsVariable(); Property* prop = expr->target()->AsProperty(); - ASSERT(var == NULL || prop == NULL); + ASSERT(proxy == NULL || prop == NULL); if (expr->is_compound()) { HandleCompoundAssignment(expr); return; } - if (var != NULL) { + if (prop != NULL) { + HandlePropertyAssignment(expr); + } else if (proxy != NULL) { + Variable* var = proxy->var(); if (var->mode() == Variable::CONST) { if (expr->op() != Token::INIT_CONST) { return Bailout("non-initializer assignment to const"); @@ -3731,59 +3761,61 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { // variables (e.g. initialization inside a loop). HValue* old_value = environment()->Lookup(var); AddInstruction(new HUseConst(old_value)); + } else if (var->mode() == Variable::LET) { + return Bailout("unsupported assignment to let"); } if (proxy->IsArguments()) return Bailout("assignment to arguments"); // Handle the assignment. - if (var->IsStackAllocated()) { - // We do not allow the arguments object to occur in a context where it - // may escape, but assignments to stack-allocated locals are - // permitted. - CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); - HValue* value = Pop(); - Bind(var, value); - return ast_context()->ReturnValue(value); + switch (var->location()) { + case Variable::UNALLOCATED: + CHECK_ALIVE(VisitForValue(expr->value())); + HandleGlobalVariableAssignment(var, + Top(), + expr->position(), + expr->AssignmentId()); + return ast_context()->ReturnValue(Pop()); + + case Variable::PARAMETER: + case Variable::LOCAL: { + // We do not allow the arguments object to occur in a context where it + // may escape, but assignments to stack-allocated locals are + // permitted. + CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); + HValue* value = Pop(); + Bind(var, value); + return ast_context()->ReturnValue(value); + } - } else if (var->IsContextSlot()) { - ASSERT(var->mode() != Variable::CONST); - // Bail out if we try to mutate a parameter value in a function using - // the arguments object. We do not (yet) correctly handle the - // arguments property of the function. - if (info()->scope()->arguments() != NULL) { - // Parameters will rewrite to context slots. We have no direct way - // to detect that the variable is a parameter. - int count = info()->scope()->num_parameters(); - for (int i = 0; i < count; ++i) { - if (var == info()->scope()->parameter(i)) { - Bailout("assignment to parameter, function uses arguments object"); + case Variable::CONTEXT: { + ASSERT(var->mode() != Variable::CONST); + // Bail out if we try to mutate a parameter value in a function using + // the arguments object. We do not (yet) correctly handle the + // arguments property of the function. + if (info()->scope()->arguments() != NULL) { + // Parameters will rewrite to context slots. We have no direct way + // to detect that the variable is a parameter. + int count = info()->scope()->num_parameters(); + for (int i = 0; i < count; ++i) { + if (var == info()->scope()->parameter(i)) { + return Bailout("assignment to parameter in arguments object"); + } } } - } - - CHECK_ALIVE(VisitForValue(expr->value())); - HValue* context = BuildContextChainWalk(var); - int index = var->AsSlot()->index(); - HStoreContextSlot* instr = - new(zone()) HStoreContextSlot(context, index, Top()); - AddInstruction(instr); - if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); - return ast_context()->ReturnValue(Pop()); - } else if (var->is_global()) { - CHECK_ALIVE(VisitForValue(expr->value())); - HandleGlobalVariableAssignment(var, - Top(), - expr->position(), - expr->AssignmentId()); - return ast_context()->ReturnValue(Pop()); + CHECK_ALIVE(VisitForValue(expr->value())); + HValue* context = BuildContextChainWalk(var); + HStoreContextSlot* instr = + new(zone()) HStoreContextSlot(context, var->index(), Top()); + AddInstruction(instr); + if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); + return ast_context()->ReturnValue(Pop()); + } - } else { - return Bailout("assignment to LOOKUP or const CONTEXT variable"); + case Variable::LOOKUP: + return Bailout("assignment to LOOKUP variable"); } - - } else if (prop != NULL) { - HandlePropertyAssignment(expr); } else { return Bailout("invalid left-hand side in assignment"); } @@ -4795,13 +4827,15 @@ bool HGraphBuilder::TryCallApply(Call* expr) { // Found pattern f.apply(receiver, arguments). VisitForValue(prop->obj()); if (HasStackOverflow() || current_block() == NULL) return true; - HValue* function = Pop(); + HValue* function = Top(); + AddCheckConstantFunction(expr, function, function_map, true); + Drop(1); + VisitForValue(args->at(0)); if (HasStackOverflow() || current_block() == NULL) return true; HValue* receiver = Pop(); HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); - AddCheckConstantFunction(expr, function, function_map, true); HInstruction* result = new(zone()) HApplyArguments(function, receiver, length, elements); result->set_position(expr->position()); @@ -4893,10 +4927,12 @@ void HGraphBuilder::VisitCall(Call* expr) { } } else { - Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); - bool global_call = (var != NULL) && var->is_global() && !var->is_this(); + VariableProxy* proxy = expr->expression()->AsVariableProxy(); + // FIXME. + bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); if (global_call) { + Variable* var = proxy->var(); bool known_global_function = false; // If there is a global property cell for the name at compile time and // access check is not enabled we assume that the function will not change @@ -5060,20 +5096,8 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { void HGraphBuilder::VisitDelete(UnaryOperation* expr) { Property* prop = expr->expression()->AsProperty(); - Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); - if (prop == NULL && var == NULL) { - // Result of deleting non-property, non-variable reference is true. - // Evaluate the subexpression for side effects. - CHECK_ALIVE(VisitForEffect(expr->expression())); - return ast_context()->ReturnValue(graph()->GetConstantTrue()); - } else if (var != NULL && - !var->is_global() && - var->AsSlot() != NULL && - var->AsSlot()->type() != Slot::LOOKUP) { - // Result of deleting non-global, non-dynamic variables is false. - // The subexpression does not have side effects. - return ast_context()->ReturnValue(graph()->GetConstantFalse()); - } else if (prop != NULL) { + VariableProxy* proxy = expr->expression()->AsVariableProxy(); + if (prop != NULL) { CHECK_ALIVE(VisitForValue(prop->obj())); CHECK_ALIVE(VisitForValue(prop->key())); HValue* key = Pop(); @@ -5081,10 +5105,26 @@ void HGraphBuilder::VisitDelete(UnaryOperation* expr) { HValue* context = environment()->LookupContext(); HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key); return ast_context()->ReturnInstruction(instr, expr->id()); - } else if (var->is_global()) { - Bailout("delete with global variable"); + } else if (proxy != NULL) { + Variable* var = proxy->var(); + if (var->IsUnallocated()) { + Bailout("delete with global variable"); + } else if (var->IsStackAllocated() || var->IsContextSlot()) { + // Result of deleting non-global variables is false. 'this' is not + // really a variable, though we implement it as one. The + // subexpression does not have side effects. + HValue* value = var->is_this() + ? graph()->GetConstantTrue() + : graph()->GetConstantFalse(); + return ast_context()->ReturnValue(value); + } else { + Bailout("delete with non-global variable"); + } } else { - Bailout("delete with non-global variable"); + // Result of deleting non-property, non-variable reference is true. + // Evaluate the subexpression for side effects. + CHECK_ALIVE(VisitForEffect(expr->expression())); + return ast_context()->ReturnValue(graph()->GetConstantTrue()); } } @@ -5231,9 +5271,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { ASSERT(current_block()->HasPredecessor()); Expression* target = expr->expression(); VariableProxy* proxy = target->AsVariableProxy(); - Variable* var = proxy->AsVariable(); Property* prop = target->AsProperty(); - if (var == NULL && prop == NULL) { + if (proxy == NULL && prop == NULL) { return Bailout("invalid lhs in count operation"); } @@ -5245,7 +5284,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { HValue* input = NULL; // ToNumber(original_input). HValue* after = NULL; // The result after incrementing or decrementing. - if (var != NULL) { + if (proxy != NULL) { + Variable* var = proxy->var(); if (var->mode() == Variable::CONST) { return Bailout("unsupported count operation with const"); } @@ -5257,36 +5297,45 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { input = returns_original_input ? Top() : Pop(); Push(after); - if (var->is_global()) { - HandleGlobalVariableAssignment(var, - after, - expr->position(), - expr->AssignmentId()); - } else if (var->IsStackAllocated()) { - Bind(var, after); - } else if (var->IsContextSlot()) { - // Bail out if we try to mutate a parameter value in a function using - // the arguments object. We do not (yet) correctly handle the - // arguments property of the function. - if (info()->scope()->arguments() != NULL) { - // Parameters will rewrite to context slots. We have no direct way - // to detect that the variable is a parameter. - int count = info()->scope()->num_parameters(); - for (int i = 0; i < count; ++i) { - if (var == info()->scope()->parameter(i)) { - Bailout("assignment to parameter, function uses arguments object"); + switch (var->location()) { + case Variable::UNALLOCATED: + HandleGlobalVariableAssignment(var, + after, + expr->position(), + expr->AssignmentId()); + break; + + case Variable::PARAMETER: + case Variable::LOCAL: + Bind(var, after); + break; + + case Variable::CONTEXT: { + // Bail out if we try to mutate a parameter value in a function + // using the arguments object. We do not (yet) correctly handle the + // arguments property of the function. + if (info()->scope()->arguments() != NULL) { + // Parameters will rewrite to context slots. We have no direct + // way to detect that the variable is a parameter so we use a + // linear search of the parameter list. + int count = info()->scope()->num_parameters(); + for (int i = 0; i < count; ++i) { + if (var == info()->scope()->parameter(i)) { + return Bailout("assignment to parameter in arguments object"); + } } } + + HValue* context = BuildContextChainWalk(var); + HStoreContextSlot* instr = + new(zone()) HStoreContextSlot(context, var->index(), after); + AddInstruction(instr); + if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); + break; } - HValue* context = BuildContextChainWalk(var); - int index = var->AsSlot()->index(); - HStoreContextSlot* instr = - new(zone()) HStoreContextSlot(context, index, after); - AddInstruction(instr); - if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); - } else { - return Bailout("lookup variable in count operation"); + case Variable::LOOKUP: + return Bailout("lookup variable in count operation"); } } else { @@ -5698,12 +5747,12 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { // residing in new space. If it is we assume that the function will stay the // same. Handle<JSFunction> target = Handle<JSFunction>::null(); - Variable* var = expr->right()->AsVariableProxy()->AsVariable(); - bool global_function = (var != NULL) && var->is_global() && !var->is_this(); + VariableProxy* proxy = expr->right()->AsVariableProxy(); + bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated(); if (global_function && info()->has_global_object() && !info()->global_object()->IsAccessCheckNeeded()) { - Handle<String> name = var->name(); + Handle<String> name = proxy->name(); Handle<GlobalObject> global(info()->global_object()); LookupResult lookup; global->Lookup(*name, &lookup); @@ -5802,15 +5851,42 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { void HGraphBuilder::VisitDeclaration(Declaration* decl) { - // We support only declarations that do not require code generation. - Variable* var = decl->proxy()->var(); - if (!var->IsStackAllocated() || decl->fun() != NULL) { - return Bailout("unsupported declaration"); - } - - if (decl->mode() == Variable::CONST) { - ASSERT(var->IsStackAllocated()); - environment()->Bind(var, graph()->GetConstantHole()); + HandleDeclaration(decl->proxy(), decl->mode(), decl->fun()); +} + + +void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, + Variable::Mode mode, + FunctionLiteral* function) { + if (mode == Variable::LET) return Bailout("unsupported let declaration"); + Variable* var = proxy->var(); + switch (var->location()) { + case Variable::UNALLOCATED: + return Bailout("unsupported global declaration"); + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::CONTEXT: + if (mode == Variable::CONST || function != NULL) { + HValue* value = NULL; + if (mode == Variable::CONST) { + value = graph()->GetConstantHole(); + } else { + VisitForValue(function); + value = Pop(); + } + if (var->IsContextSlot()) { + HValue* context = environment()->LookupContext(); + HStoreContextSlot* store = + new HStoreContextSlot(context, var->index(), value); + AddInstruction(store); + if (store->HasSideEffects()) AddSimulate(proxy->id()); + } else { + environment()->Bind(var, value); + } + } + break; + case Variable::LOOKUP: + return Bailout("unsupported lookup slot in declaration"); } } diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index c18ba58153..614991f7c2 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -455,12 +455,11 @@ class HEnvironment: public ZoneObject { // by 1 (receiver is parameter index -1 but environment index 0). // Stack-allocated local indices are shifted by the number of parameters. int IndexFor(Variable* variable) const { - Slot* slot = variable->AsSlot(); - ASSERT(slot != NULL && slot->IsStackAllocated()); - int shift = (slot->type() == Slot::PARAMETER) + ASSERT(variable->IsStackAllocated()); + int shift = variable->IsParameter() ? 1 : parameter_count_ + specials_count_; - return slot->index() + shift; + return variable->index() + shift; } Handle<JSFunction> closure_; @@ -779,6 +778,10 @@ class HGraphBuilder: public AstVisitor { INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) #undef INLINE_FUNCTION_GENERATOR_DECLARATION + void HandleDeclaration(VariableProxy* proxy, + Variable::Mode mode, + FunctionLiteral* function); + void VisitDelete(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr); void VisitTypeof(UnaryOperation* expr); @@ -851,7 +854,6 @@ class HGraphBuilder: public AstVisitor { TypeInfo info, HValue* value, Representation rep); - void AssumeRepresentation(HValue* value, Representation rep); static Representation ToRepresentation(TypeInfo info); void SetupScope(Scope* scope); diff --git a/deps/v8/src/ia32/builtins-ia32.cc b/deps/v8/src/ia32/builtins-ia32.cc index f8a85de98c..845a073c40 100644 --- a/deps/v8/src/ia32/builtins-ia32.cc +++ b/deps/v8/src/ia32/builtins-ia32.cc @@ -373,7 +373,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ LeaveConstructFrame(); // Remove caller arguments from the stack and return. - ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); __ pop(ecx); __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver __ push(ecx); @@ -923,7 +923,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, // Fill the FixedArray with the hole value. Inline the code if short. // Reconsider loop unfolding if kPreallocatedArrayElements gets changed. static const int kLoopUnfoldLimit = 4; - ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit); + STATIC_ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit); if (initial_capacity <= kLoopUnfoldLimit) { // Use a scratch register here to have only one reloc info when unfolding // the loop. @@ -975,7 +975,7 @@ static void AllocateJSArray(MacroAssembler* masm, // Allocate the JSArray object together with space for a FixedArray with the // requested elements. - ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, times_half_pointer_size, // array_size is a smi. array_size, @@ -1100,7 +1100,7 @@ static void ArrayNativeCode(MacroAssembler* masm, __ bind(&argc_one_or_more); __ cmp(eax, 1); __ j(not_equal, &argc_two_or_more); - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize)); __ test(ecx, Operand(ecx)); __ j(not_zero, ¬_empty_array); @@ -1155,7 +1155,7 @@ static void ArrayNativeCode(MacroAssembler* masm, // Handle construction of an array from a list of arguments. __ bind(&argc_two_or_more); - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ SmiTag(eax); // Convet argc to a smi. // eax: array_size (smi) // edi: constructor @@ -1437,7 +1437,7 @@ static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { // Preserve the number of arguments on the stack. Must preserve eax, // ebx and ecx because these registers are used when copying the // arguments and the receiver. - ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTagSize == 1); __ lea(edi, Operand(eax, eax, times_1, kSmiTag)); __ push(edi); } @@ -1451,7 +1451,7 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { __ leave(); // Remove caller arguments from the stack. - ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); __ pop(ecx); __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver __ push(ecx); diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index d76e4bf1f4..f3eb09fa51 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -3396,8 +3396,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // a sequential string or an external string. // In the case of a sliced string its offset has to be taken into account. Label cons_string, check_encoding; - STATIC_ASSERT((kConsStringTag < kExternalStringTag)); - STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); + STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); __ cmp(Operand(ebx), Immediate(kExternalStringTag)); __ j(less, &cons_string); __ j(equal, &runtime); @@ -4872,8 +4872,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // Handle non-flat strings. __ and_(result_, kStringRepresentationMask); - STATIC_ASSERT((kConsStringTag < kExternalStringTag)); - STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); + STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); __ cmp(result_, kExternalStringTag); __ j(greater, &sliced_string, Label::kNear); __ j(equal, &call_runtime_); @@ -4907,7 +4907,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // Check for 1-byte or 2-byte string. __ bind(&flat_string); - STATIC_ASSERT(kAsciiStringTag != 0); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ test(result_, Immediate(kStringEncodingMask)); __ j(not_zero, &ascii_string, Label::kNear); @@ -5178,8 +5179,9 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); __ and_(ecx, Operand(edi)); - STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); - __ test(ecx, Immediate(kAsciiStringTag)); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ test(ecx, Immediate(kStringEncodingMask)); __ j(zero, &non_ascii); __ bind(&ascii_data); // Allocate an acsii cons string. @@ -5210,7 +5212,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); __ j(equal, &ascii_data); // Allocate a two byte cons string. - __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); + __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime); __ jmp(&allocated); // Handle creating a flat result. First check that both strings are not @@ -5236,12 +5238,13 @@ void StringAddStub::Generate(MacroAssembler* masm) { // ebx: length of resulting flat string as a smi // edx: second string Label non_ascii_string_add_flat_result; - STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); - __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); + __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); __ j(zero, &non_ascii_string_add_flat_result); __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); - __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); + __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); __ j(zero, &string_add_runtime); // Both strings are ascii strings. As they are short they are both flat. @@ -5281,7 +5284,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { // edx: second string __ bind(&non_ascii_string_add_flat_result); __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); - __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); + __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); __ j(not_zero, &string_add_runtime); // Both strings are two byte strings. As they are short they are both // flat. @@ -5642,9 +5645,6 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, void SubStringStub::Generate(MacroAssembler* masm) { Label runtime; - if (FLAG_string_slices) { - __ jmp(&runtime); - } // Stack frame on entry. // esp[0]: return address // esp[4]: to @@ -5706,7 +5706,84 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); __ Set(ecx, Immediate(2)); - __ bind(&result_longer_than_two); + if (FLAG_string_slices) { + Label copy_routine; + // If coming from the make_two_character_string path, the string + // is too short to be sliced anyways. + STATIC_ASSERT(2 < SlicedString::kMinLength); + __ jmp(©_routine); + __ bind(&result_longer_than_two); + + // eax: string + // ebx: instance type + // ecx: sub string length + // edx: from index (smi) + Label allocate_slice, sliced_string, seq_string; + __ cmp(ecx, SlicedString::kMinLength); + // Short slice. Copy instead of slicing. + __ j(less, ©_routine); + STATIC_ASSERT(kSeqStringTag == 0); + __ test(ebx, Immediate(kStringRepresentationMask)); + __ j(zero, &seq_string, Label::kNear); + STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); + STATIC_ASSERT(kIsIndirectStringMask != 0); + __ test(ebx, Immediate(kIsIndirectStringMask)); + // External string. Jump to runtime. + __ j(zero, &runtime); + + Factory* factory = masm->isolate()->factory(); + __ test(ebx, Immediate(kSlicedNotConsMask)); + __ j(not_zero, &sliced_string, Label::kNear); + // Cons string. Check whether it is flat, then fetch first part. + __ cmp(FieldOperand(eax, ConsString::kSecondOffset), + factory->empty_string()); + __ j(not_equal, &runtime); + __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset)); + __ jmp(&allocate_slice, Label::kNear); + + __ bind(&sliced_string); + // Sliced string. Fetch parent and correct start index by offset. + __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset)); + __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset)); + __ jmp(&allocate_slice, Label::kNear); + + __ bind(&seq_string); + // Sequential string. Just move string to the right register. + __ mov(edi, eax); + + __ bind(&allocate_slice); + // edi: underlying subject string + // ebx: instance type of original subject string + // edx: offset + // ecx: length + // Allocate new sliced string. At this point we do not reload the instance + // type including the string encoding because we simply rely on the info + // provided by the original string. It does not matter if the original + // string's encoding is wrong because we always have to recheck encoding of + // the newly created string's parent anyways due to externalized strings. + Label two_byte_slice, set_slice_header; + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ test(ebx, Immediate(kStringEncodingMask)); + __ j(zero, &two_byte_slice, Label::kNear); + __ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime); + __ jmp(&set_slice_header, Label::kNear); + __ bind(&two_byte_slice); + __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime); + __ bind(&set_slice_header); + __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx); + __ SmiTag(ecx); + __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx); + __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi); + __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset), + Immediate(String::kEmptyHashField)); + __ jmp(&return_eax); + + __ bind(©_routine); + } else { + __ bind(&result_longer_than_two); + } + // eax: string // ebx: instance type // ecx: result string length diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index 799ba73a26..59f7b9c7b3 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -41,7 +41,6 @@ namespace v8 { namespace internal { - #define __ ACCESS_MASM(masm_) @@ -192,14 +191,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // Copy parameters into context if necessary. int num_parameters = info->scope()->num_parameters(); for (int i = 0; i < num_parameters; i++) { - Slot* slot = scope()->parameter(i)->AsSlot(); - if (slot != NULL && slot->type() == Slot::CONTEXT) { + Variable* var = scope()->parameter(i); + if (var->IsContextSlot()) { int parameter_offset = StandardFrameConstants::kCallerSPOffset + (num_parameters - 1 - i) * kPointerSize; // Load parameter from stack. __ mov(eax, Operand(ebp, parameter_offset)); // Store it in the context. - int context_offset = Context::SlotOffset(slot->index()); + int context_offset = Context::SlotOffset(var->index()); __ mov(Operand(esi, context_offset), eax); // Update the write barrier. This clobbers all involved // registers, so we have use a third register to avoid @@ -241,7 +240,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { ArgumentsAccessStub stub(type); __ CallStub(&stub); - Move(arguments->AsSlot(), eax, ebx, edx); + SetVar(arguments, eax, ebx, edx); } if (FLAG_trace) { @@ -255,17 +254,19 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { scope()->VisitIllegalRedeclaration(this); } else { + PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); { Comment cmnt(masm_, "[ Declarations"); // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - EmitDeclaration(scope()->function(), Variable::CONST, NULL); + int ignored = 0; + EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored); } VisitDeclarations(scope()->declarations()); } { Comment cmnt(masm_, "[ Stack check"); - PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); + PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); Label ok; ExternalReference stack_limit = ExternalReference::address_of_stack_limit(isolate()); @@ -371,27 +372,29 @@ void FullCodeGenerator::verify_stack_height() { } -void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { +void FullCodeGenerator::EffectContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); } -void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { - MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); - __ mov(result_register(), slot_operand); +void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); + codegen()->GetVar(result_register(), var); } -void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { - MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); +void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); + MemOperand operand = codegen()->VarOperand(var, result_register()); // Memory operands can be pushed directly. - __ push(slot_operand); + __ push(operand); codegen()->increment_stack_height(); } -void FullCodeGenerator::TestContext::Plug(Slot* slot) const { +void FullCodeGenerator::TestContext::Plug(Variable* var) const { // For simplicity we always test the accumulator register. - codegen()->Move(result_register(), slot); + codegen()->GetVar(result_register(), var); codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); codegen()->DoTest(this); } @@ -615,44 +618,54 @@ void FullCodeGenerator::Split(Condition cc, } -MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - return Operand(ebp, SlotOffset(slot)); - case Slot::CONTEXT: { - int context_chain_length = - scope()->ContextChainLength(slot->var()->scope()); - __ LoadContext(scratch, context_chain_length); - return ContextOperand(scratch, slot->index()); - } - case Slot::LOOKUP: - UNREACHABLE(); +MemOperand FullCodeGenerator::StackOperand(Variable* var) { + ASSERT(var->IsStackAllocated()); + // Offset is negative because higher indexes are at lower addresses. + int offset = -var->index() * kPointerSize; + // Adjust by a (parameter or local) base offset. + if (var->IsParameter()) { + offset += (info_->scope()->num_parameters() + 1) * kPointerSize; + } else { + offset += JavaScriptFrameConstants::kLocal0Offset; } - UNREACHABLE(); - return Operand(eax, 0); + return Operand(ebp, offset); } -void FullCodeGenerator::Move(Register destination, Slot* source) { - MemOperand location = EmitSlotSearch(source, destination); - __ mov(destination, location); +MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) { + ASSERT(var->IsContextSlot() || var->IsStackAllocated()); + if (var->IsContextSlot()) { + int context_chain_length = scope()->ContextChainLength(var->scope()); + __ LoadContext(scratch, context_chain_length); + return ContextOperand(scratch, var->index()); + } else { + return StackOperand(var); + } } -void FullCodeGenerator::Move(Slot* dst, - Register src, - Register scratch1, - Register scratch2) { - ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. - ASSERT(!scratch1.is(src) && !scratch2.is(src)); - MemOperand location = EmitSlotSearch(dst, scratch1); +void FullCodeGenerator::GetVar(Register dest, Variable* var) { + ASSERT(var->IsContextSlot() || var->IsStackAllocated()); + MemOperand location = VarOperand(var, dest); + __ mov(dest, location); +} + + +void FullCodeGenerator::SetVar(Variable* var, + Register src, + Register scratch0, + Register scratch1) { + ASSERT(var->IsContextSlot() || var->IsStackAllocated()); + ASSERT(!scratch0.is(src)); + ASSERT(!scratch0.is(scratch1)); + ASSERT(!scratch1.is(src)); + MemOperand location = VarOperand(var, scratch0); __ mov(location, src); // Emit the write barrier code if the location is in the heap. - if (dst->type() == Slot::CONTEXT) { - int offset = Context::SlotOffset(dst->index()); - ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi)); - __ RecordWrite(scratch1, offset, src, scratch2); + if (var->IsContextSlot()) { + int offset = Context::SlotOffset(var->index()); + ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi)); + __ RecordWrite(scratch0, offset, src, scratch1); } } @@ -683,29 +696,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, } -void FullCodeGenerator::EmitDeclaration(Variable* variable, +void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, Variable::Mode mode, - FunctionLiteral* function) { - Comment cmnt(masm_, "[ Declaration"); - ASSERT(variable != NULL); // Must have been resolved. - Slot* slot = variable->AsSlot(); - ASSERT(slot != NULL); - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - if (mode == Variable::CONST) { - __ mov(Operand(ebp, SlotOffset(slot)), - Immediate(isolate()->factory()->the_hole_value())); - } else if (function != NULL) { + FunctionLiteral* function, + int* global_count) { + // If it was not possible to allocate the variable at compile time, we + // need to "declare" it at runtime to make sure it actually exists in the + // local context. + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: + ++(*global_count); + break; + + case Variable::PARAMETER: + case Variable::LOCAL: + if (function != NULL) { + Comment cmnt(masm_, "[ Declaration"); VisitForAccumulatorValue(function); - __ mov(Operand(ebp, SlotOffset(slot)), result_register()); + __ mov(StackOperand(variable), result_register()); + } else if (mode == Variable::CONST || mode == Variable::LET) { + Comment cmnt(masm_, "[ Declaration"); + __ mov(StackOperand(variable), + Immediate(isolate()->factory()->the_hole_value())); } break; - case Slot::CONTEXT: - // We bypass the general EmitSlotSearch because we know more about - // this specific context. - + case Variable::CONTEXT: // The variable in the decl always resides in the current function // context. ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); @@ -717,23 +734,28 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ cmp(ebx, isolate()->factory()->catch_context_map()); __ Check(not_equal, "Declaration in catch context."); } - if (mode == Variable::CONST) { - __ mov(ContextOperand(esi, slot->index()), - Immediate(isolate()->factory()->the_hole_value())); - // No write barrier since the hole value is in old space. - } else if (function != NULL) { + if (function != NULL) { + Comment cmnt(masm_, "[ Declaration"); VisitForAccumulatorValue(function); - __ mov(ContextOperand(esi, slot->index()), result_register()); - int offset = Context::SlotOffset(slot->index()); + __ mov(ContextOperand(esi, variable->index()), result_register()); + int offset = Context::SlotOffset(variable->index()); __ mov(ebx, esi); __ RecordWrite(ebx, offset, result_register(), ecx); + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); + } else if (mode == Variable::CONST || mode == Variable::LET) { + Comment cmnt(masm_, "[ Declaration"); + __ mov(ContextOperand(esi, variable->index()), + Immediate(isolate()->factory()->the_hole_value())); + // No write barrier since the hole value is in old space. + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); } break; - case Slot::LOOKUP: { + case Variable::LOOKUP: { + Comment cmnt(masm_, "[ Declaration"); __ push(esi); __ push(Immediate(variable->name())); - // Declaration nodes are always introduced in one of two modes. + // Declaration nodes are always introduced in one of three modes. ASSERT(mode == Variable::VAR || mode == Variable::CONST || mode == Variable::LET); @@ -744,13 +766,13 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, // 'undefined') because we may have a (legal) redeclaration and we // must not destroy the current value. increment_stack_height(3); - if (mode == Variable::CONST) { + if (function != NULL) { + VisitForStackValue(function); + } else if (mode == Variable::CONST || mode == Variable::LET) { __ push(Immediate(isolate()->factory()->the_hole_value())); increment_stack_height(); - } else if (function != NULL) { - VisitForStackValue(function); } else { - __ push(Immediate(Smi::FromInt(0))); // No initial value! + __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. increment_stack_height(); } __ CallRuntime(Runtime::kDeclareContextSlot, 4); @@ -761,18 +783,15 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, } -void FullCodeGenerator::VisitDeclaration(Declaration* decl) { - EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); -} +void FullCodeGenerator::VisitDeclaration(Declaration* decl) { } void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { // Call the runtime to declare the globals. __ push(esi); // The context is the first argument. __ push(Immediate(pairs)); - __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); - __ push(Immediate(Smi::FromInt(strict_mode_flag()))); - __ CallRuntime(Runtime::kDeclareGlobals, 4); + __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags()))); + __ CallRuntime(Runtime::kDeclareGlobals, 3); // Return value is ignored. } @@ -1071,10 +1090,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } -void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( - Slot* slot, - TypeofState typeof_state, - Label* slow) { +void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, + TypeofState typeof_state, + Label* slow) { Register context = esi; Register temp = edx; @@ -1123,7 +1141,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( // All extension objects were empty and it is safe to use a global // load IC call. __ mov(eax, GlobalObjectOperand()); - __ mov(ecx, slot->var()->name()); + __ mov(ecx, var->name()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ? RelocInfo::CODE_TARGET @@ -1132,14 +1150,13 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( } -MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( - Slot* slot, - Label* slow) { - ASSERT(slot->type() == Slot::CONTEXT); +MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, + Label* slow) { + ASSERT(var->IsContextSlot()); Register context = esi; Register temp = ebx; - for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { + for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { if (s->num_heap_slots() > 0) { if (s->calls_eval()) { // Check that extension is NULL. @@ -1159,60 +1176,31 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( // This function is used only for loads, not stores, so it's safe to // return an esi-based operand (the write barrier cannot be allowed to // destroy the esi register). - return ContextOperand(context, slot->index()); + return ContextOperand(context, var->index()); } -void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( - Slot* slot, - TypeofState typeof_state, - Label* slow, - Label* done) { +void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, + TypeofState typeof_state, + Label* slow, + Label* done) { // Generate fast-case code for variables that might be shadowed by // eval-introduced variables. Eval is used a lot without // introducing variables. In those cases, we do not want to // perform a runtime call for all variables in the scope // containing the eval. - if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { - EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); + if (var->mode() == Variable::DYNAMIC_GLOBAL) { + EmitLoadGlobalCheckExtensions(var, typeof_state, slow); __ jmp(done); - } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { - Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); - Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); - if (potential_slot != NULL) { - // Generate fast case for locals that rewrite to slots. - __ mov(eax, - ContextSlotOperandCheckExtensions(potential_slot, slow)); - if (potential_slot->var()->mode() == Variable::CONST) { - __ cmp(eax, isolate()->factory()->the_hole_value()); - __ j(not_equal, done); - __ mov(eax, isolate()->factory()->undefined_value()); - } - __ jmp(done); - } else if (rewrite != NULL) { - // Generate fast case for calls of an argument function. - Property* property = rewrite->AsProperty(); - if (property != NULL) { - VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); - Literal* key_literal = property->key()->AsLiteral(); - if (obj_proxy != NULL && - key_literal != NULL && - obj_proxy->IsArguments() && - key_literal->handle()->IsSmi()) { - // Load arguments object if there are no eval-introduced - // variables. Then load the argument from the arguments - // object using keyed load. - __ mov(edx, - ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), - slow)); - __ SafeSet(eax, Immediate(key_literal->handle())); - Handle<Code> ic = - isolate()->builtins()->KeyedLoadIC_Initialize(); - __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); - __ jmp(done); - } - } + } else if (var->mode() == Variable::DYNAMIC_LOCAL) { + Variable* local = var->local_if_not_shadowed(); + __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); + if (local->mode() == Variable::CONST) { + __ cmp(eax, isolate()->factory()->the_hole_value()); + __ j(not_equal, done); + __ mov(eax, isolate()->factory()->undefined_value()); } + __ jmp(done); } } @@ -1222,54 +1210,60 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { SetSourcePosition(proxy->position()); Variable* var = proxy->var(); - // Three cases: non-this global variables, lookup slots, and all other - // types of slots. - Slot* slot = var->AsSlot(); - ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); - - if (slot == NULL) { - Comment cmnt(masm_, "Global variable"); - // Use inline caching. Variable name is passed in ecx and the global - // object on the stack. - __ mov(eax, GlobalObjectOperand()); - __ mov(ecx, var->name()); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); - context()->Plug(eax); - - } else if (slot->type() == Slot::LOOKUP) { - Label done, slow; - - // Generate code for loading from variables potentially shadowed - // by eval-introduced variables. - EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); - - __ bind(&slow); - Comment cmnt(masm_, "Lookup slot"); - __ push(esi); // Context. - __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kLoadContextSlot, 2); - __ bind(&done); + // Three cases: global variables, lookup variables, and all other types of + // variables. + switch (var->location()) { + case Variable::UNALLOCATED: { + Comment cmnt(masm_, "Global variable"); + // Use inline caching. Variable name is passed in ecx and the global + // object in eax. + __ mov(eax, GlobalObjectOperand()); + __ mov(ecx, var->name()); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); + context()->Plug(eax); + break; + } - context()->Plug(eax); + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::CONTEXT: { + Comment cmnt(masm_, var->IsContextSlot() + ? "Context variable" + : "Stack variable"); + if (var->mode() != Variable::LET && var->mode() != Variable::CONST) { + context()->Plug(var); + } else { + // Let and const need a read barrier. + Label done; + GetVar(eax, var); + __ cmp(eax, isolate()->factory()->the_hole_value()); + __ j(not_equal, &done, Label::kNear); + if (var->mode() == Variable::LET) { + __ push(Immediate(var->name())); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + } else { // Variable::CONST + __ mov(eax, isolate()->factory()->undefined_value()); + } + __ bind(&done); + context()->Plug(eax); + } + break; + } - } else { - Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) - ? "Context slot" - : "Stack slot"); - if (var->mode() == Variable::CONST) { - // Constants may be the hole value if they have not been initialized. - // Unhole them. - Label done; - MemOperand slot_operand = EmitSlotSearch(slot, eax); - __ mov(eax, slot_operand); - __ cmp(eax, isolate()->factory()->the_hole_value()); - __ j(not_equal, &done, Label::kNear); - __ mov(eax, isolate()->factory()->undefined_value()); + case Variable::LOOKUP: { + Label done, slow; + // Generate code for loading from variables potentially shadowed + // by eval-introduced variables. + EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); + __ bind(&slow); + Comment cmnt(masm_, "Lookup variable"); + __ push(esi); // Context. + __ push(Immediate(var->name())); + __ CallRuntime(Runtime::kLoadContextSlot, 2); __ bind(&done); context()->Plug(eax); - } else { - context()->Plug(slot); + break; } } } @@ -1812,14 +1806,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) { - ASSERT(var != NULL); - ASSERT(var->is_global() || var->AsSlot() != NULL); - - if (var->is_global()) { - ASSERT(!var->is_this()); - // Assignment to a global variable. Use inline caching for the - // assignment. Right-hand-side value is passed in eax, variable name in - // ecx, and the global object on the stack. + if (var->IsUnallocated()) { + // Global var, const, or let. __ mov(ecx, var->name()); __ mov(edx, GlobalObjectOperand()); Handle<Code> ic = is_strict_mode() @@ -1828,66 +1816,79 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); } else if (op == Token::INIT_CONST) { - // Like var declarations, const declarations are hoisted to function - // scope. However, unlike var initializers, const initializers are able - // to drill a hole to that function context, even from inside a 'with' - // context. We thus bypass the normal static scope lookup. - Slot* slot = var->AsSlot(); - Label skip; - switch (slot->type()) { - case Slot::PARAMETER: - // No const parameters. - UNREACHABLE(); - break; - case Slot::LOCAL: - __ mov(edx, Operand(ebp, SlotOffset(slot))); - __ cmp(edx, isolate()->factory()->the_hole_value()); - __ j(not_equal, &skip); - __ mov(Operand(ebp, SlotOffset(slot)), eax); - break; - case Slot::CONTEXT: - case Slot::LOOKUP: - __ push(eax); - __ push(esi); - __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); - break; + // Const initializers need a write barrier. + ASSERT(!var->IsParameter()); // No const parameters. + if (var->IsStackLocal()) { + Label skip; + __ mov(edx, StackOperand(var)); + __ cmp(edx, isolate()->factory()->the_hole_value()); + __ j(not_equal, &skip); + __ mov(StackOperand(var), eax); + __ bind(&skip); + } else { + ASSERT(var->IsContextSlot() || var->IsLookupSlot()); + // Like var declarations, const declarations are hoisted to function + // scope. However, unlike var initializers, const initializers are + // able to drill a hole to that function context, even from inside a + // 'with' context. We thus bypass the normal static scope lookup for + // var->IsContextSlot(). + __ push(eax); + __ push(esi); + __ push(Immediate(var->name())); + __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); } - __ bind(&skip); - } else if (var->mode() != Variable::CONST) { - // Perform the assignment for non-const variables. Const assignments - // are simply skipped. - Slot* slot = var->AsSlot(); - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - // Perform the assignment. - __ mov(Operand(ebp, SlotOffset(slot)), eax); - break; - - case Slot::CONTEXT: { - MemOperand target = EmitSlotSearch(slot, ecx); - // Perform the assignment and issue the write barrier. - __ mov(target, eax); - // The value of the assignment is in eax. RecordWrite clobbers its - // register arguments. + } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { + // Non-initializing assignment to let variable needs a write barrier. + if (var->IsLookupSlot()) { + __ push(eax); // Value. + __ push(esi); // Context. + __ push(Immediate(var->name())); + __ push(Immediate(Smi::FromInt(strict_mode_flag()))); + __ CallRuntime(Runtime::kStoreContextSlot, 4); + } else { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); + Label assign; + MemOperand location = VarOperand(var, ecx); + __ mov(edx, location); + __ cmp(edx, isolate()->factory()->the_hole_value()); + __ j(not_equal, &assign, Label::kNear); + __ push(Immediate(var->name())); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&assign); + __ mov(location, eax); + if (var->IsContextSlot()) { __ mov(edx, eax); - int offset = Context::SlotOffset(slot->index()); - __ RecordWrite(ecx, offset, edx, ebx); - break; + __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx); } + } - case Slot::LOOKUP: - // Call the runtime for the assignment. - __ push(eax); // Value. - __ push(esi); // Context. - __ push(Immediate(var->name())); - __ push(Immediate(Smi::FromInt(strict_mode_flag()))); - __ CallRuntime(Runtime::kStoreContextSlot, 4); - break; + } else if (var->mode() != Variable::CONST) { + // Assignment to var or initializing assignment to let. + if (var->IsStackAllocated() || var->IsContextSlot()) { + MemOperand location = VarOperand(var, ecx); + if (FLAG_debug_code && op == Token::INIT_LET) { + // Check for an uninitialized let binding. + __ mov(edx, location); + __ cmp(edx, isolate()->factory()->the_hole_value()); + __ Check(equal, "Let binding re-initialization."); + } + // Perform the assignment. + __ mov(location, eax); + if (var->IsContextSlot()) { + __ mov(edx, eax); + __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx); + } + } else { + ASSERT(var->IsLookupSlot()); + __ push(eax); // Value. + __ push(esi); // Context. + __ push(Immediate(var->name())); + __ push(Immediate(Smi::FromInt(strict_mode_flag()))); + __ CallRuntime(Runtime::kStoreContextSlot, 4); } } + // Non-initializing assignments to consts are ignored. } @@ -2094,8 +2095,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, // Push the receiver of the enclosing function. __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize)); - // Push the strict mode flag. - __ push(Immediate(Smi::FromInt(strict_mode_flag()))); + // Push the strict mode flag. In harmony mode every eval call + // is a strict mode eval call. + StrictModeFlag strict_mode = strict_mode_flag(); + if (FLAG_harmony_block_scoping) { + strict_mode = kStrictMode; + } + __ push(Immediate(Smi::FromInt(strict_mode))); __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP ? Runtime::kResolvePossiblyDirectEvalNoLookup @@ -2111,18 +2117,18 @@ void FullCodeGenerator::VisitCall(Call* expr) { #endif Comment cmnt(masm_, "[ Call"); - Expression* fun = expr->expression(); - Variable* var = fun->AsVariableProxy()->AsVariable(); + Expression* callee = expr->expression(); + VariableProxy* proxy = callee->AsVariableProxy(); + Property* property = callee->AsProperty(); - if (var != NULL && var->is_possibly_eval()) { + if (proxy != NULL && proxy->var()->is_possibly_eval()) { // In a call to eval, we first call %ResolvePossiblyDirectEval to - // resolve the function we need to call and the receiver of the - // call. Then we call the resolved function using the given - // arguments. + // resolve the function we need to call and the receiver of the call. + // Then we call the resolved function using the given arguments. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); { PreservePositionScope pos_scope(masm()->positions_recorder()); - VisitForStackValue(fun); + VisitForStackValue(callee); // Reserved receiver slot. __ push(Immediate(isolate()->factory()->undefined_value())); increment_stack_height(); @@ -2132,15 +2138,14 @@ void FullCodeGenerator::VisitCall(Call* expr) { } // If we know that eval can only be shadowed by eval-introduced - // variables we attempt to load the global eval function directly - // in generated code. If we succeed, there is no need to perform a + // variables we attempt to load the global eval function directly in + // generated code. If we succeed, there is no need to perform a // context lookup in the runtime system. Label done; - if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { + Variable* var = proxy->var(); + if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) { Label slow; - EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), - NOT_INSIDE_TYPEOF, - &slow); + EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); // Push the function and resolve eval. __ push(eax); EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); @@ -2148,13 +2153,11 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ bind(&slow); } - // Push copy of the function (found below the arguments) and + // Push a copy of the function (found below the arguments) and // resolve eval. __ push(Operand(esp, (arg_count + 1) * kPointerSize)); EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); - if (done.is_linked()) { - __ bind(&done); - } + __ bind(&done); // The runtime call returns a pair of values in eax (function) and // edx (receiver). Touch up the stack with the right values. @@ -2171,75 +2174,67 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); decrement_stack_height(arg_count + 1); // Function is left on the stack. context()->DropAndPlug(1, eax); - } else if (var != NULL && !var->is_this() && var->is_global()) { + + } else if (proxy != NULL && proxy->var()->IsUnallocated()) { // Push global object as receiver for the call IC. __ push(GlobalObjectOperand()); increment_stack_height(); - EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); - } else if (var != NULL && var->AsSlot() != NULL && - var->AsSlot()->type() == Slot::LOOKUP) { + EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); + + } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { // Call to a lookup slot (dynamically introduced variable). Label slow, done; - { PreservePositionScope scope(masm()->positions_recorder()); - // Generate code for loading from variables potentially shadowed - // by eval-introduced variables. - EmitDynamicLoadFromSlotFastCase(var->AsSlot(), - NOT_INSIDE_TYPEOF, - &slow, - &done); + // Generate code for loading from variables potentially shadowed by + // eval-introduced variables. + EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); } - __ bind(&slow); - // Call the runtime to find the function to call (returned in eax) - // and the object holding it (returned in edx). + // Call the runtime to find the function to call (returned in eax) and + // the object holding it (returned in edx). __ push(context_register()); - __ push(Immediate(var->name())); + __ push(Immediate(proxy->name())); __ CallRuntime(Runtime::kLoadContextSlot, 2); __ push(eax); // Function. - increment_stack_height(); __ push(edx); // Receiver. - increment_stack_height(); + increment_stack_height(2); - // If fast case code has been generated, emit code to push the - // function and receiver and have the slow path jump around this - // code. + // If fast case code has been generated, emit code to push the function + // and receiver and have the slow path jump around this code. if (done.is_linked()) { Label call; - __ jmp(&call); + __ jmp(&call, Label::kNear); __ bind(&done); - // Push function. Stack height already incremented in slow case above. + // Push function. Stack height already incremented in slow case + // above. __ push(eax); - // The receiver is implicitly the global receiver. Indicate this - // by passing the hole to the call function stub. + // The receiver is implicitly the global receiver. Indicate this by + // passing the hole to the call function stub. __ push(Immediate(isolate()->factory()->the_hole_value())); __ bind(&call); } - // The receiver is either the global receiver or an object found - // by LoadContextSlot. That object could be the hole if the - // receiver is implicitly the global object. + // The receiver is either the global receiver or an object found by + // LoadContextSlot. That object could be the hole if the receiver is + // implicitly the global object. EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); - } else if (fun->AsProperty() != NULL) { - // Call to an object property. - Property* prop = fun->AsProperty(); - Literal* key = prop->key()->AsLiteral(); - if (key != NULL && key->handle()->IsSymbol()) { - // Call to a named property, use call IC. - { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } - EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); + + } else if (property != NULL) { + { PreservePositionScope scope(masm()->positions_recorder()); + VisitForStackValue(property->obj()); + } + if (property->key()->IsPropertyName()) { + EmitCallWithIC(expr, + property->key()->AsLiteral()->handle(), + RelocInfo::CODE_TARGET); } else { - // Call to a keyed property. - { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } - EmitKeyedCallWithIC(expr, prop->key()); + EmitKeyedCallWithIC(expr, property->key()); } + } else { + // Call to an arbitrary expression not handled specially above. { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(fun); + VisitForStackValue(callee); } // Load global receiver object. __ mov(ebx, GlobalObjectOperand()); @@ -3199,7 +3194,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { Label done, not_found; // tmp now holds finger offset as a smi. - ASSERT(kSmiTag == 0 && kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp)); __ j(not_equal, ¬_found); @@ -3611,31 +3606,32 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { switch (expr->op()) { case Token::DELETE: { Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); - Property* prop = expr->expression()->AsProperty(); - Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); + Property* property = expr->expression()->AsProperty(); + VariableProxy* proxy = expr->expression()->AsVariableProxy(); - if (prop != NULL) { - VisitForStackValue(prop->obj()); - VisitForStackValue(prop->key()); + if (property != NULL) { + VisitForStackValue(property->obj()); + VisitForStackValue(property->key()); __ push(Immediate(Smi::FromInt(strict_mode_flag()))); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); decrement_stack_height(2); context()->Plug(eax); - } else if (var != NULL) { + } else if (proxy != NULL) { + Variable* var = proxy->var(); // Delete of an unqualified identifier is disallowed in strict mode - // but "delete this" is. + // but "delete this" is allowed. ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); - if (var->is_global()) { + if (var->IsUnallocated()) { __ push(GlobalObjectOperand()); __ push(Immediate(var->name())); __ push(Immediate(Smi::FromInt(kNonStrictMode))); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(eax); - } else if (var->AsSlot() != NULL && - var->AsSlot()->type() != Slot::LOOKUP) { - // Result of deleting non-global, non-dynamic variables is false. - // The subexpression does not have side effects. - context()->Plug(false); + } else if (var->IsStackAllocated() || var->IsContextSlot()) { + // Result of deleting non-global variables is false. 'this' is + // not really a variable, though we implement it as one. The + // subexpression does not have side effects. + context()->Plug(var->is_this()); } else { // Non-global variable. Call the runtime to try to delete from the // context where the variable was introduced. @@ -3932,7 +3928,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { ASSERT(!context()->IsEffect()); ASSERT(!context()->IsTest()); - if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { + if (proxy != NULL && proxy->var()->IsUnallocated()) { Comment cmnt(masm_, "Global variable"); __ mov(eax, GlobalObjectOperand()); __ mov(ecx, Immediate(proxy->name())); @@ -3942,15 +3938,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { __ call(ic); PrepareForBailout(expr, TOS_REG); context()->Plug(eax); - } else if (proxy != NULL && - proxy->var()->AsSlot() != NULL && - proxy->var()->AsSlot()->type() == Slot::LOOKUP) { + } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { Label done, slow; // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - Slot* slot = proxy->var()->AsSlot(); - EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); __ bind(&slow); __ push(esi); @@ -4242,8 +4235,8 @@ void FullCodeGenerator::EnterFinallyBlock() { ASSERT(!result_register().is(edx)); __ pop(edx); __ sub(Operand(edx), Immediate(masm_->CodeObject())); - ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); + STATIC_ASSERT(kSmiTag == 0); __ SmiTag(edx); __ push(edx); // Store result register while executing finally block. @@ -4264,6 +4257,34 @@ void FullCodeGenerator::ExitFinallyBlock() { #undef __ +#define __ ACCESS_MASM(masm()) + +FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( + int* stack_depth, + int* context_length) { + // The macros used here must preserve the result register. + + // Because the handler block contains the context of the finally + // code, we can restore it directly from there for the finally code + // rather than iteratively unwinding contexts via their previous + // links. + __ Drop(*stack_depth); // Down to the handler block. + if (*context_length > 0) { + // Restore the context to its dedicated register and the stack. + __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset)); + __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); + } + __ PopTryHandler(); + __ call(finally_entry_); + + *stack_depth = 0; + *context_length = 0; + return previous_; +} + + +#undef __ + } } // namespace v8::internal #endif // V8_TARGET_ARCH_IA32 diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc index 5f143b104f..7d3ead2eac 100644 --- a/deps/v8/src/ia32/ic-ia32.cc +++ b/deps/v8/src/ia32/ic-ia32.cc @@ -324,7 +324,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); __ j(above_equal, out_of_range); // Fast case: Do the load. - ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); + STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); __ cmp(Operand(scratch), Immediate(FACTORY->the_hole_value())); // In case the loaded value is the_hole we have to consult GetProperty @@ -358,7 +358,7 @@ static void GenerateKeyStringCheck(MacroAssembler* masm, __ j(zero, index_string); // Is the string a symbol? - ASSERT(kSymbolTag != 0); + STATIC_ASSERT(kSymbolTag != 0); __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); __ j(zero, not_symbol); } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 5f670387f6..31e9dd82e2 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -194,14 +194,14 @@ bool LCodeGen::GeneratePrologue() { // Copy parameters into context if necessary. int num_parameters = scope()->num_parameters(); for (int i = 0; i < num_parameters; i++) { - Slot* slot = scope()->parameter(i)->AsSlot(); - if (slot != NULL && slot->type() == Slot::CONTEXT) { + Variable* var = scope()->parameter(i); + if (var->IsContextSlot()) { int parameter_offset = StandardFrameConstants::kCallerSPOffset + (num_parameters - 1 - i) * kPointerSize; // Load parameter from stack. __ mov(eax, Operand(ebp, parameter_offset)); // Store it in the context. - int context_offset = Context::SlotOffset(slot->index()); + int context_offset = Context::SlotOffset(var->index()); __ mov(Operand(esi, context_offset), eax); // Update the write barrier. This clobbers all involved // registers, so we have to use a third register to avoid @@ -3175,7 +3175,6 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { void LCodeGen::DoStoreKeyedFastDoubleElement( LStoreKeyedFastDoubleElement* instr) { XMMRegister value = ToDoubleRegister(instr->value()); - Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; Label have_value; __ ucomisd(value, value); @@ -3234,8 +3233,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { // Dispatch on the indirect string shape: slice or cons. Label cons_string; - const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag; - ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0); __ test(result, Immediate(kSlicedNotConsMask)); __ j(zero, &cons_string, Label::kNear); @@ -3271,7 +3268,8 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { // Dispatch on the encoding: ASCII or two-byte. Label ascii_string; - STATIC_ASSERT(kAsciiStringTag != 0); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ test(result, Immediate(kStringEncodingMask)); __ j(not_zero, &ascii_string, Label::kNear); diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 9df5cad915..6d3ce2bcd9 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -148,7 +148,7 @@ void MacroAssembler::RecordWrite(Register object, Label done; // Skip barrier if writing a smi. - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); JumpIfSmi(value, &done, Label::kNear); InNewSpace(object, value, equal, &done, Label::kNear); @@ -166,8 +166,8 @@ void MacroAssembler::RecordWrite(Register object, // Array access: calculate the destination address in the same manner as // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset // into an array of words. - ASSERT_EQ(1, kSmiTagSize); - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0); lea(dst, Operand(object, dst, times_half_pointer_size, FixedArray::kHeaderSize - kHeapObjectTag)); } @@ -193,7 +193,7 @@ void MacroAssembler::RecordWrite(Register object, Label done; // Skip barrier if writing a smi. - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); JumpIfSmi(value, &done, Label::kNear); InNewSpace(object, value, equal, &done); @@ -326,7 +326,7 @@ Condition MacroAssembler::IsObjectStringType(Register heap_object, Register instance_type) { mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); - ASSERT(kNotStringTag != 0); + STATIC_ASSERT(kNotStringTag != 0); test(instance_type, Immediate(kIsNotStringMask)); return zero; } @@ -1172,7 +1172,7 @@ void MacroAssembler::AllocateAsciiString(Register result, } -void MacroAssembler::AllocateConsString(Register result, +void MacroAssembler::AllocateTwoByteConsString(Register result, Register scratch1, Register scratch2, Label* gc_required) { @@ -1208,6 +1208,42 @@ void MacroAssembler::AllocateAsciiConsString(Register result, } +void MacroAssembler::AllocateTwoByteSlicedString(Register result, + Register scratch1, + Register scratch2, + Label* gc_required) { + // Allocate heap number in new space. + AllocateInNewSpace(SlicedString::kSize, + result, + scratch1, + scratch2, + gc_required, + TAG_OBJECT); + + // Set the map. The other fields are left uninitialized. + mov(FieldOperand(result, HeapObject::kMapOffset), + Immediate(isolate()->factory()->sliced_string_map())); +} + + +void MacroAssembler::AllocateAsciiSlicedString(Register result, + Register scratch1, + Register scratch2, + Label* gc_required) { + // Allocate heap number in new space. + AllocateInNewSpace(SlicedString::kSize, + result, + scratch1, + scratch2, + gc_required, + TAG_OBJECT); + + // Set the map. The other fields are left uninitialized. + mov(FieldOperand(result, HeapObject::kMapOffset), + Immediate(isolate()->factory()->sliced_ascii_string_map())); +} + + // Copy memory, byte-by-byte, from source to destination. Not optimized for // long or aligned copies. The contents of scratch and length are destroyed. // Source and destination are incremented by length. @@ -2166,7 +2202,7 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1, Register scratch2, Label* failure) { // Check that both objects are not smis. - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); mov(scratch1, Operand(object1)); and_(scratch1, Operand(object2)); JumpIfSmi(scratch1, failure); diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h index d79df5ea55..1906644c35 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -275,8 +275,8 @@ class MacroAssembler: public Assembler { // Smi tagging support. void SmiTag(Register reg) { - ASSERT(kSmiTag == 0); - ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTagSize == 1); add(reg, Operand(reg)); } void SmiUntag(Register reg) { @@ -285,9 +285,9 @@ class MacroAssembler: public Assembler { // Modifies the register even if it does not contain a Smi! void SmiUntag(Register reg, Label* is_smi) { - ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTagSize == 1); sar(reg, kSmiTagSize); - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); j(not_carry, is_smi); } @@ -437,7 +437,7 @@ class MacroAssembler: public Assembler { // Allocate a raw cons string object. Only the map field of the result is // initialized. - void AllocateConsString(Register result, + void AllocateTwoByteConsString(Register result, Register scratch1, Register scratch2, Label* gc_required); @@ -446,6 +446,17 @@ class MacroAssembler: public Assembler { Register scratch2, Label* gc_required); + // Allocate a raw sliced string object. Only the map field of the result is + // initialized. + void AllocateTwoByteSlicedString(Register result, + Register scratch1, + Register scratch2, + Label* gc_required); + void AllocateAsciiSlicedString(Register result, + Register scratch1, + Register scratch2, + Label* gc_required); + // Copy memory, byte-by-byte, from source to destination. Not optimized for // long or aligned copies. // The contents of index and scratch are destroyed. diff --git a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc index 7d7de0ef44..d175d9e036 100644 --- a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc @@ -1080,7 +1080,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, MaybeObject* result = Execution::HandleStackGuardInterrupt(); if (*code_handle != re_code) { // Return address no longer valid - int delta = *code_handle - re_code; + int delta = code_handle->address() - re_code->address(); // Overwrite the return address on the stack. *return_address += delta; } diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index 4a37b07c71..621a9bbfa2 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -273,7 +273,7 @@ static void GenerateStringCheck(MacroAssembler* masm, // Check that the object is a string. __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); - ASSERT(kNotStringTag != 0); + STATIC_ASSERT(kNotStringTag != 0); __ test(scratch, Immediate(kNotStringTag)); __ j(not_zero, non_string_object); } diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 09cbc8a1e6..d366902977 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -1409,7 +1409,6 @@ Isolate::Isolate() global_handles_(NULL), context_switcher_(NULL), thread_manager_(NULL), - ast_sentinels_(NULL), string_tracker_(NULL), regexp_stack_(NULL), embedder_data_(NULL) { @@ -1546,9 +1545,6 @@ Isolate::~Isolate() { delete regexp_stack_; regexp_stack_ = NULL; - delete ast_sentinels_; - ast_sentinels_ = NULL; - delete descriptor_lookup_cache_; descriptor_lookup_cache_ = NULL; delete context_slot_cache_; @@ -1710,7 +1706,6 @@ bool Isolate::Init(Deserializer* des) { bootstrapper_ = new Bootstrapper(); handle_scope_implementer_ = new HandleScopeImplementer(this); stub_cache_ = new StubCache(this); - ast_sentinels_ = new AstSentinels(); regexp_stack_ = new RegExpStack(); regexp_stack_->isolate_ = this; diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h index 5bb504d2da..7c690d26ba 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -47,7 +47,6 @@ namespace v8 { namespace internal { -class AstSentinels; class Bootstrapper; class CodeGenerator; class CodeRange; @@ -878,8 +877,6 @@ class Isolate { return &objects_string_input_buffer_; } - AstSentinels* ast_sentinels() { return ast_sentinels_; } - RuntimeState* runtime_state() { return &runtime_state_; } StaticResource<SafeStringInputBuffer>* compiler_safe_string_input_buffer() { @@ -1138,7 +1135,6 @@ class Isolate { GlobalHandles* global_handles_; ContextSwitcher* context_switcher_; ThreadManager* thread_manager_; - AstSentinels* ast_sentinels_; RuntimeState runtime_state_; StaticResource<SafeStringInputBuffer> compiler_safe_string_input_buffer_; Builtins builtins_; diff --git a/deps/v8/src/json.js b/deps/v8/src/json.js index 8fd410fa4d..a491bcc151 100644 --- a/deps/v8/src/json.js +++ b/deps/v8/src/json.js @@ -337,11 +337,12 @@ function JSONStringify(value, replacer, space) { return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap); } -function SetupJSON() { +function SetUpJSON() { + %CheckIsBootstrapping(); InstallFunctions($JSON, DONT_ENUM, $Array( "parse", JSONParse, "stringify", JSONStringify )); } -SetupJSON(); +SetUpJSON() diff --git a/deps/v8/src/jsregexp.cc b/deps/v8/src/jsregexp.cc index 4ca83a4769..3ebfbdfc98 100644 --- a/deps/v8/src/jsregexp.cc +++ b/deps/v8/src/jsregexp.cc @@ -2661,7 +2661,8 @@ int TextNode::GreedyLoopTextLength() { // this alternative and back to this choice node. If there are variable // length nodes or other complications in the way then return a sentinel // value indicating that a greedy loop cannot be constructed. -int ChoiceNode::GreedyLoopTextLength(GuardedAlternative* alternative) { +int ChoiceNode::GreedyLoopTextLengthForAlternative( + GuardedAlternative* alternative) { int length = 0; RegExpNode* node = alternative->node(); // Later we will generate code for all these text nodes using recursion @@ -2700,7 +2701,8 @@ void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); if (trace->stop_node() == this) { - int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); + int text_length = + GreedyLoopTextLengthForAlternative(&(alternatives_->at(0))); ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); // Update the counter-based backtracking info on the stack. This is an // optimization for greedy loops (see below). @@ -2893,7 +2895,7 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { Trace* current_trace = trace; - int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); + int text_length = GreedyLoopTextLengthForAlternative(&(alternatives_->at(0))); bool greedy_loop = false; Label greedy_loop_label; Trace counter_backtrack_trace; diff --git a/deps/v8/src/jsregexp.h b/deps/v8/src/jsregexp.h index 13f9e2ea06..3bd5e00893 100644 --- a/deps/v8/src/jsregexp.h +++ b/deps/v8/src/jsregexp.h @@ -1071,7 +1071,7 @@ class ChoiceNode: public RegExpNode { virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; } protected: - int GreedyLoopTextLength(GuardedAlternative* alternative); + int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative); ZoneList<GuardedAlternative>* alternatives_; private: diff --git a/deps/v8/src/liveedit.cc b/deps/v8/src/liveedit.cc index 0b01e8af15..07c9fdde05 100644 --- a/deps/v8/src/liveedit.cc +++ b/deps/v8/src/liveedit.cc @@ -860,8 +860,7 @@ class FunctionInfoListener { int j = 0; for (int i = 0; i < list.length(); i++) { Variable* var1 = list[i]; - Slot* slot = var1->AsSlot(); - if (slot != NULL && slot->type() == Slot::CONTEXT) { + if (var1->IsContextSlot()) { if (j != i) { list[j] = var1; } @@ -873,7 +872,7 @@ class FunctionInfoListener { for (int k = 1; k < j; k++) { int l = k; for (int m = k + 1; m < j; m++) { - if (list[l]->AsSlot()->index() > list[m]->AsSlot()->index()) { + if (list[l]->index() > list[m]->index()) { l = m; } } @@ -887,7 +886,7 @@ class FunctionInfoListener { SetElementNonStrict( scope_info_list, scope_info_length, - Handle<Smi>(Smi::FromInt(list[i]->AsSlot()->index()))); + Handle<Smi>(Smi::FromInt(list[i]->index()))); scope_info_length++; } SetElementNonStrict(scope_info_list, diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py index 5ba7ac3afa..e3d1e03871 100644 --- a/deps/v8/src/macros.py +++ b/deps/v8/src/macros.py @@ -122,7 +122,7 @@ macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg)); # Inline macros. Use %IS_VAR to make sure arg is evaluated only once. macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg)); -macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || arg - arg == 0); +macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0))); macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg))); macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg))); macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0)); @@ -170,7 +170,7 @@ macro CAPTURE(index) = (3 + (index)); const CAPTURE0 = 3; const CAPTURE1 = 4; -# PropertyDescriptor return value indices - must match +# PropertyDescriptor return value indices - must match # PropertyDescriptorIndices in runtime.cc. const IS_ACCESSOR_INDEX = 0; const VALUE_INDEX = 1; @@ -179,3 +179,17 @@ const SETTER_INDEX = 3; const WRITABLE_INDEX = 4; const ENUMERABLE_INDEX = 5; const CONFIGURABLE_INDEX = 6; + +# For messages.js +# Matches Script::Type from objects.h +const TYPE_NATIVE = 0; +const TYPE_EXTENSION = 1; +const TYPE_NORMAL = 2; + +# Matches Script::CompilationType from objects.h +const COMPILATION_TYPE_HOST = 0; +const COMPILATION_TYPE_EVAL = 1; +const COMPILATION_TYPE_JSON = 2; + +# Matches Messages::kNoLineNumberInfo from v8.h +const kNoLineNumberInfo = 0; diff --git a/deps/v8/src/math.js b/deps/v8/src/math.js index 70b8c57cae..b5a6d18117 100644 --- a/deps/v8/src/math.js +++ b/deps/v8/src/math.js @@ -38,7 +38,7 @@ const $abs = MathAbs; function MathConstructor() {} %FunctionSetInstanceClassName(MathConstructor, 'Math'); const $Math = new MathConstructor(); -$Math.__proto__ = global.Object.prototype; +$Math.__proto__ = $Object.prototype; %SetProperty(global, "Math", $Math, DONT_ENUM); // ECMA 262 - 15.8.2.1 @@ -195,8 +195,9 @@ function MathTan(x) { // ------------------------------------------------------------------- -function SetupMath() { - // Setup math constants. +function SetUpMath() { + %CheckIsBootstrapping(); + // Set up math constants. // ECMA-262, section 15.8.1.1. %OptimizeObjectForAddingMultipleProperties($Math, 8); %SetProperty($Math, @@ -236,7 +237,7 @@ function SetupMath() { DONT_ENUM | DONT_DELETE | READ_ONLY); %ToFastProperties($Math); - // Setup non-enumerable functions of the Math object and + // Set up non-enumerable functions of the Math object and // set their names. InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array( "random", MathRandom, @@ -258,7 +259,6 @@ function SetupMath() { "max", MathMax, "min", MathMin )); -}; - +} -SetupMath(); +SetUpMath(); diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index cbbb70eb1a..3c85d9416a 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -28,27 +28,14 @@ // ------------------------------------------------------------------- // -// Matches Script::Type from objects.h -var TYPE_NATIVE = 0; -var TYPE_EXTENSION = 1; -var TYPE_NORMAL = 2; - -// Matches Script::CompilationType from objects.h -var COMPILATION_TYPE_HOST = 0; -var COMPILATION_TYPE_EVAL = 1; -var COMPILATION_TYPE_JSON = 2; - -// Matches Messages::kNoLineNumberInfo from v8.h -var kNoLineNumberInfo = 0; - // If this object gets passed to an error constructor the error will // get an accessor for .message that constructs a descriptive error // message on access. -var kAddMessageAccessorsMarker = { }; +const kAddMessageAccessorsMarker = { }; -var kMessages = 0; - -var kReplacementMarkers = [ "%0", "%1", "%2", "%3" ]; +// This will be lazily initialized when first needed (and forcibly +// overwritten even though it's const). +const kMessages = 0; function FormatString(format, message) { var args = %MessageGetArguments(message); @@ -56,14 +43,16 @@ function FormatString(format, message) { var arg_num = 0; for (var i = 0; i < format.length; i++) { var str = format[i]; - for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) { - if (str == kReplacementMarkers[arg_num]) { + if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) { + // Two-char string starts with "%". + var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0; + if (arg_num < 4) { + // str is one of %0, %1, %2 or %3. try { str = ToDetailString(args[arg_num]); } catch (e) { str = "#<error>"; } - break; } } result += str; @@ -102,18 +91,16 @@ function ToStringCheckErrorObject(obj) { function ToDetailString(obj) { - if (obj != null && IS_OBJECT(obj) && - obj.toString === $Object.prototype.toString) { + if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) { var constructor = obj.constructor; - if (!constructor) return ToStringCheckErrorObject(obj); - var constructorName = constructor.name; - if (!constructorName || !IS_STRING(constructorName)) { - return ToStringCheckErrorObject(obj); + if (typeof constructor == "function") { + var constructorName = constructor.name; + if (IS_STRING(constructorName) && constructorName !== "") { + return "#<" + constructorName + ">"; + } } - return "#<" + constructorName + ">"; - } else { - return ToStringCheckErrorObject(obj); } + return ToStringCheckErrorObject(obj); } @@ -129,10 +116,11 @@ function MakeGenericError(constructor, type, args) { /** - * Setup the Script function and constructor. + * Set up the Script function and constructor. */ %FunctionSetInstanceClassName(Script, 'Script'); -%SetProperty(Script.prototype, 'constructor', Script, DONT_ENUM); +%SetProperty(Script.prototype, 'constructor', Script, + DONT_ENUM | DONT_DELETE | READ_ONLY); %SetCode(Script, function(x) { // Script objects can only be created by the VM. throw new $Error("Not supported"); @@ -142,116 +130,132 @@ function MakeGenericError(constructor, type, args) { // Helper functions; called from the runtime system. function FormatMessage(message) { if (kMessages === 0) { - kMessages = { + var messagesDictionary = [ // Error - cyclic_proto: ["Cyclic __proto__ value"], - code_gen_from_strings: ["Code generation from strings disallowed for this context"], + "cyclic_proto", ["Cyclic __proto__ value"], + "code_gen_from_strings", ["Code generation from strings disallowed for this context"], // TypeError - unexpected_token: ["Unexpected token ", "%0"], - unexpected_token_number: ["Unexpected number"], - unexpected_token_string: ["Unexpected string"], - unexpected_token_identifier: ["Unexpected identifier"], - unexpected_reserved: ["Unexpected reserved word"], - unexpected_strict_reserved: ["Unexpected strict mode reserved word"], - unexpected_eos: ["Unexpected end of input"], - malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"], - unterminated_regexp: ["Invalid regular expression: missing /"], - regexp_flags: ["Cannot supply flags when constructing one RegExp from another"], - incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"], - invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"], - invalid_lhs_in_for_in: ["Invalid left-hand side in for-in"], - invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"], - invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"], - multiple_defaults_in_switch: ["More than one default clause in switch statement"], - newline_after_throw: ["Illegal newline after throw"], - redeclaration: ["%0", " '", "%1", "' has already been declared"], - no_catch_or_finally: ["Missing catch or finally after try"], - unknown_label: ["Undefined label '", "%0", "'"], - uncaught_exception: ["Uncaught ", "%0"], - stack_trace: ["Stack Trace:\n", "%0"], - called_non_callable: ["%0", " is not a function"], - undefined_method: ["Object ", "%1", " has no method '", "%0", "'"], - property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"], - cannot_convert_to_primitive: ["Cannot convert object to primitive value"], - not_constructor: ["%0", " is not a constructor"], - not_defined: ["%0", " is not defined"], - non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"], - non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"], - non_object_property_call: ["Cannot call method '", "%0", "' of ", "%1"], - with_expression: ["%0", " has no properties"], - illegal_invocation: ["Illegal invocation"], - no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"], - apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"], - apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"], - invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"], - instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"], - instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"], - null_to_object: ["Cannot convert null to object"], - reduce_no_initial: ["Reduce of empty array with no initial value"], - getter_must_be_callable: ["Getter must be a function: ", "%0"], - setter_must_be_callable: ["Setter must be a function: ", "%0"], - value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value: ", "%0"], - proto_object_or_null: ["Object prototype may only be an Object or null"], - property_desc_object: ["Property description must be an object: ", "%0"], - redefine_disallowed: ["Cannot redefine property: ", "%0"], - define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."], - non_extensible_proto: ["%0", " is not extensible"], - handler_non_object: ["Proxy.", "%0", " called with non-object as handler"], - handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"], - handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"], - handler_returned_false: ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"], - handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"], - proxy_prop_not_configurable: ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"], - proxy_non_object_prop_names: ["Trap ", "%1", " returned non-object ", "%0"], - proxy_repeated_prop_name: ["Trap ", "%1", " returned repeated property name ", "%2"], - invalid_weakmap_key: ["Invalid value used as weak map key"], + "unexpected_token", ["Unexpected token ", "%0"], + "unexpected_token_number", ["Unexpected number"], + "unexpected_token_string", ["Unexpected string"], + "unexpected_token_identifier", ["Unexpected identifier"], + "unexpected_reserved", ["Unexpected reserved word"], + "unexpected_strict_reserved", ["Unexpected strict mode reserved word"], + "unexpected_eos", ["Unexpected end of input"], + "malformed_regexp", ["Invalid regular expression: /", "%0", "/: ", "%1"], + "unterminated_regexp", ["Invalid regular expression: missing /"], + "regexp_flags", ["Cannot supply flags when constructing one RegExp from another"], + "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"], + "invalid_lhs_in_assignment", ["Invalid left-hand side in assignment"], + "invalid_lhs_in_for_in", ["Invalid left-hand side in for-in"], + "invalid_lhs_in_postfix_op", ["Invalid left-hand side expression in postfix operation"], + "invalid_lhs_in_prefix_op", ["Invalid left-hand side expression in prefix operation"], + "multiple_defaults_in_switch", ["More than one default clause in switch statement"], + "newline_after_throw", ["Illegal newline after throw"], + "redeclaration", ["%0", " '", "%1", "' has already been declared"], + "no_catch_or_finally", ["Missing catch or finally after try"], + "unknown_label", ["Undefined label '", "%0", "'"], + "uncaught_exception", ["Uncaught ", "%0"], + "stack_trace", ["Stack Trace:\n", "%0"], + "called_non_callable", ["%0", " is not a function"], + "undefined_method", ["Object ", "%1", " has no method '", "%0", "'"], + "property_not_function", ["Property '", "%0", "' of object ", "%1", " is not a function"], + "cannot_convert_to_primitive", ["Cannot convert object to primitive value"], + "not_constructor", ["%0", " is not a constructor"], + "not_defined", ["%0", " is not defined"], + "non_object_property_load", ["Cannot read property '", "%0", "' of ", "%1"], + "non_object_property_store", ["Cannot set property '", "%0", "' of ", "%1"], + "non_object_property_call", ["Cannot call method '", "%0", "' of ", "%1"], + "with_expression", ["%0", " has no properties"], + "illegal_invocation", ["Illegal invocation"], + "no_setter_in_callback", ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"], + "apply_non_function", ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"], + "apply_wrong_args", ["Function.prototype.apply: Arguments list has wrong type"], + "invalid_in_operator_use", ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"], + "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"], + "instanceof_nonobject_proto", ["Function has non-object prototype '", "%0", "' in instanceof check"], + "null_to_object", ["Cannot convert null to object"], + "reduce_no_initial", ["Reduce of empty array with no initial value"], + "getter_must_be_callable", ["Getter must be a function: ", "%0"], + "setter_must_be_callable", ["Setter must be a function: ", "%0"], + "value_and_accessor", ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"], + "proto_object_or_null", ["Object prototype may only be an Object or null"], + "property_desc_object", ["Property description must be an object: ", "%0"], + "redefine_disallowed", ["Cannot redefine property: ", "%0"], + "define_disallowed", ["Cannot define property:", "%0", ", object is not extensible."], + "non_extensible_proto", ["%0", " is not extensible"], + "handler_non_object", ["Proxy.", "%0", " called with non-object as handler"], + "handler_trap_missing", ["Proxy handler ", "%0", " has no '", "%1", "' trap"], + "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"], + "handler_returned_false", ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"], + "handler_returned_undefined", ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"], + "proxy_prop_not_configurable", ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"], + "proxy_non_object_prop_names", ["Trap ", "%1", " returned non-object ", "%0"], + "proxy_repeated_prop_name", ["Trap ", "%1", " returned repeated property name ", "%2"], + "invalid_weakmap_key", ["Invalid value used as weak map key"], // RangeError - invalid_array_length: ["Invalid array length"], - stack_overflow: ["Maximum call stack size exceeded"], + "invalid_array_length", ["Invalid array length"], + "stack_overflow", ["Maximum call stack size exceeded"], // SyntaxError - unable_to_parse: ["Parse error"], - invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"], - invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"], - illegal_break: ["Illegal break statement"], - illegal_continue: ["Illegal continue statement"], - illegal_return: ["Illegal return statement"], - error_loading_debugger: ["Error loading debugger"], - no_input_to_regexp: ["No input to ", "%0"], - invalid_json: ["String '", "%0", "' is not valid JSON"], - circular_structure: ["Converting circular structure to JSON"], - obj_ctor_property_non_object: ["Object.", "%0", " called on non-object"], - called_on_null_or_undefined: ["%0", " called on null or undefined"], - array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"], - object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"], - illegal_access: ["Illegal access"], - invalid_preparser_data: ["Invalid preparser data for function ", "%0"], - strict_mode_with: ["Strict mode code may not include a with statement"], - strict_catch_variable: ["Catch variable may not be eval or arguments in strict mode"], - too_many_arguments: ["Too many arguments in function call (only 32766 allowed)"], - too_many_parameters: ["Too many parameters in function definition (only 32766 allowed)"], - too_many_variables: ["Too many variables declared (only 32767 allowed)"], - strict_param_name: ["Parameter name eval or arguments is not allowed in strict mode"], - strict_param_dupe: ["Strict mode function may not have duplicate parameter names"], - strict_var_name: ["Variable name may not be eval or arguments in strict mode"], - strict_function_name: ["Function name may not be eval or arguments in strict mode"], - strict_octal_literal: ["Octal literals are not allowed in strict mode."], - strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"], - accessor_data_property: ["Object literal may not have data and accessor property with the same name"], - accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"], - strict_lhs_assignment: ["Assignment to eval or arguments is not allowed in strict mode"], - strict_lhs_postfix: ["Postfix increment/decrement may not have eval or arguments operand in strict mode"], - strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"], - strict_reserved_word: ["Use of future reserved word in strict mode"], - strict_delete: ["Delete of an unqualified identifier in strict mode."], - strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"], - strict_const: ["Use of const in strict mode."], - strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ], - strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"], - strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"], - strict_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"], - strict_caller: ["Illegal access to a strict mode caller function."], - unprotected_let: ["Illegal let declaration in unprotected statement context."], - }; + "unable_to_parse", ["Parse error"], + "invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"], + "invalid_regexp", ["Invalid RegExp pattern /", "%0", "/"], + "illegal_break", ["Illegal break statement"], + "illegal_continue", ["Illegal continue statement"], + "illegal_return", ["Illegal return statement"], + "error_loading_debugger", ["Error loading debugger"], + "no_input_to_regexp", ["No input to ", "%0"], + "invalid_json", ["String '", "%0", "' is not valid JSON"], + "circular_structure", ["Converting circular structure to JSON"], + "obj_ctor_property_non_object", ["Object.", "%0", " called on non-object"], + "called_on_null_or_undefined", ["%0", " called on null or undefined"], + "array_indexof_not_defined", ["Array.getIndexOf: Argument undefined"], + "object_not_extensible", ["Can't add property ", "%0", ", object is not extensible"], + "illegal_access", ["Illegal access"], + "invalid_preparser_data", ["Invalid preparser data for function ", "%0"], + "strict_mode_with", ["Strict mode code may not include a with statement"], + "strict_catch_variable", ["Catch variable may not be eval or arguments in strict mode"], + "too_many_arguments", ["Too many arguments in function call (only 32766 allowed)"], + "too_many_parameters", ["Too many parameters in function definition (only 32766 allowed)"], + "too_many_variables", ["Too many variables declared (only 32767 allowed)"], + "strict_param_name", ["Parameter name eval or arguments is not allowed in strict mode"], + "strict_param_dupe", ["Strict mode function may not have duplicate parameter names"], + "strict_var_name", ["Variable name may not be eval or arguments in strict mode"], + "strict_function_name", ["Function name may not be eval or arguments in strict mode"], + "strict_octal_literal", ["Octal literals are not allowed in strict mode."], + "strict_duplicate_property", ["Duplicate data property in object literal not allowed in strict mode"], + "accessor_data_property", ["Object literal may not have data and accessor property with the same name"], + "accessor_get_set", ["Object literal may not have multiple get/set accessors with the same name"], + "strict_lhs_assignment", ["Assignment to eval or arguments is not allowed in strict mode"], + "strict_lhs_postfix", ["Postfix increment/decrement may not have eval or arguments operand in strict mode"], + "strict_lhs_prefix", ["Prefix increment/decrement may not have eval or arguments operand in strict mode"], + "strict_reserved_word", ["Use of future reserved word in strict mode"], + "strict_delete", ["Delete of an unqualified identifier in strict mode."], + "strict_delete_property", ["Cannot delete property '", "%0", "' of ", "%1"], + "strict_const", ["Use of const in strict mode."], + "strict_function", ["In strict mode code, functions can only be declared at top level or immediately within another function." ], + "strict_read_only_property", ["Cannot assign to read only property '", "%0", "' of ", "%1"], + "strict_cannot_assign", ["Cannot assign to read only '", "%0", "' in strict mode"], + "strict_poison_pill", ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"], + "strict_caller", ["Illegal access to a strict mode caller function."], + "unprotected_let", ["Illegal let declaration in unprotected statement context."], + ]; + var messages = { __proto__ : null }; + var desc = new PropertyDescriptor(); + desc.setConfigurable(false); + desc.setEnumerable(false); + desc.setWritable(false); + for (var i = 0; i < messagesDictionary.length; i += 2) { + var key = messagesDictionary[i]; + var format = messagesDictionary[i + 1]; + ObjectFreeze(format); + desc.setValue(format); + DefineOwnProperty(messages, key, desc); + } + %PreventExtensions(messages); + %IgnoreAttributesAndSetProperty(builtins, "kMessages", + messages, + DONT_DELETE | DONT_ENUM | READ_ONLY); } var message_type = %MessageGetType(message); var format = kMessages[message_type]; @@ -317,7 +321,7 @@ function MakeError(type, args) { * @return {number} 0 if input too small, -1 if input too large, else the line number. */ -Script.prototype.lineFromPosition = function(position) { +function ScriptLineFromPosition(position) { var lower = 0; var upper = this.lineCount() - 1; var line_ends = this.line_ends; @@ -356,8 +360,8 @@ Script.prototype.lineFromPosition = function(position) { * @return {SourceLocation} * If line is negative or not in the source null is returned. */ -Script.prototype.locationFromPosition = function (position, - include_resource_offset) { +function ScriptLocationFromPosition(position, + include_resource_offset) { var line = this.lineFromPosition(position); if (line == -1) return null; @@ -365,7 +369,9 @@ Script.prototype.locationFromPosition = function (position, var line_ends = this.line_ends; var start = line == 0 ? 0 : line_ends[line - 1] + 1; var end = line_ends[line]; - if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') end--; + if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') { + end--; + } var column = position - start; // Adjust according to the offset within the resource. @@ -390,11 +396,12 @@ Script.prototype.locationFromPosition = function (position, * @param {number} opt_line The line within the source. Default value is 0 * @param {number} opt_column The column in within the line. Default value is 0 * @param {number} opt_offset_position The offset from the begining of the - * source from where the line and column calculation starts. Default value is 0 + * source from where the line and column calculation starts. + * Default value is 0 * @return {SourceLocation} * If line is negative or not in the source null is returned. */ -Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_position) { +function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) { // Default is the first line in the script. Lines in the script is relative // to the offset within the resource. var line = 0; @@ -436,7 +443,7 @@ Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_p * @return {SourceSlice} The source slice or null of the parameters where * invalid */ -Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) { +function ScriptSourceSlice(opt_from_line, opt_to_line) { var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset : opt_from_line; var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount() : opt_to_line @@ -463,7 +470,7 @@ Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) { } -Script.prototype.sourceLine = function (opt_line) { +function ScriptSourceLine(opt_line) { // Default is the first line in the script. Lines in the script are relative // to the offset within the resource. var line = 0; @@ -489,7 +496,7 @@ Script.prototype.sourceLine = function (opt_line) { * @return {number} * Number of source lines. */ -Script.prototype.lineCount = function() { +function ScriptLineCount() { // Return number of source lines. return this.line_ends.length; }; @@ -505,9 +512,10 @@ Script.prototype.lineCount = function() { * @return {?string} script name if present, value for //@ sourceURL comment * otherwise. */ -Script.prototype.nameOrSourceURL = function() { - if (this.name) +function ScriptNameOrSourceURL() { + if (this.name) { return this.name; + } // TODO(608): the spaces in a regexp below had to be escaped as \040 // because this file is being processed by js2c whose handling of spaces // in regexps is broken. Also, ['"] are excluded from allowed URLs to @@ -533,6 +541,20 @@ Script.prototype.nameOrSourceURL = function() { } +SetUpLockedPrototype(Script, + $Array("source", "name", "line_ends", "line_offset", "column_offset"), + $Array( + "lineFromPosition", ScriptLineFromPosition, + "locationFromPosition", ScriptLocationFromPosition, + "locationFromLine", ScriptLocationFromLine, + "sourceSlice", ScriptSourceSlice, + "sourceLine", ScriptSourceLine, + "lineCount", ScriptLineCount, + "nameOrSourceURL", ScriptNameOrSourceURL + ) +); + + /** * Class for source location. A source location is a position within some * source with the following properties: @@ -563,8 +585,6 @@ function SourceLocation(script, position, line, column, start, end) { this.end = end; } -SourceLocation.prototype.__proto__ = null; - const kLineLengthLimit = 78; /** @@ -575,7 +595,7 @@ const kLineLengthLimit = 78; * @param {number} opt_before The number of characters to prefer before the * position with a default value of 10 less that the limit */ -SourceLocation.prototype.restrict = function (opt_limit, opt_before) { +function SourceLocationRestrict(opt_limit, opt_before) { // Find the actual limit to use. var limit; var before; @@ -622,11 +642,20 @@ SourceLocation.prototype.restrict = function (opt_limit, opt_before) { * @return {String} * Source text for this location. */ -SourceLocation.prototype.sourceText = function () { +function SourceLocationSourceText() { return %_CallFunction(this.script.source, this.start, this.end, StringSubstring); }; +SetUpLockedPrototype(SourceLocation, + $Array("script", "position", "line", "column", "start", "end"), + $Array( + "restrict", SourceLocationRestrict, + "sourceText", SourceLocationSourceText + ) +); + + /** * Class for a source slice. A source slice is a part of a script source with * the following properties: @@ -653,20 +682,23 @@ function SourceSlice(script, from_line, to_line, from_position, to_position) { this.to_position = to_position; } -SourceSlice.prototype.__proto__ = null; - /** * Get the source text for a SourceSlice * @return {String} Source text for this slice. The last line will include * the line terminating characters (if any) */ -SourceSlice.prototype.sourceText = function () { +function SourceSliceSourceText() { return %_CallFunction(this.script.source, this.from_position, this.to_position, StringSubstring); }; +SetUpLockedPrototype(SourceSlice, + $Array("script", "from_line", "to_line", "from_position", "to_position"), + $Array("sourceText", SourceSliceSourceText) +); + // Returns the offset of the given position within the containing // line. @@ -721,13 +753,11 @@ function CallSite(receiver, fun, pos) { this.pos = pos; } -CallSite.prototype.__proto__ = null; - -CallSite.prototype.getThis = function () { +function CallSiteGetThis() { return this.receiver; }; -CallSite.prototype.getTypeName = function () { +function CallSiteGetTypeName() { var constructor = this.receiver.constructor; if (!constructor) { return %_CallFunction(this.receiver, ObjectToString); @@ -739,33 +769,33 @@ CallSite.prototype.getTypeName = function () { return constructorName; }; -CallSite.prototype.isToplevel = function () { +function CallSiteIsToplevel() { if (this.receiver == null) { return true; } return IS_GLOBAL(this.receiver); }; -CallSite.prototype.isEval = function () { +function CallSiteIsEval() { var script = %FunctionGetScript(this.fun); return script && script.compilation_type == COMPILATION_TYPE_EVAL; }; -CallSite.prototype.getEvalOrigin = function () { +function CallSiteGetEvalOrigin() { var script = %FunctionGetScript(this.fun); return FormatEvalOrigin(script); }; -CallSite.prototype.getScriptNameOrSourceURL = function () { +function CallSiteGetScriptNameOrSourceURL() { var script = %FunctionGetScript(this.fun); return script ? script.nameOrSourceURL() : null; }; -CallSite.prototype.getFunction = function () { +function CallSiteGetFunction() { return this.fun; }; -CallSite.prototype.getFunctionName = function () { +function CallSiteGetFunctionName() { // See if the function knows its own name var name = this.fun.name; if (name) { @@ -781,7 +811,7 @@ CallSite.prototype.getFunctionName = function () { return null; }; -CallSite.prototype.getMethodName = function () { +function CallSiteGetMethodName() { // See if we can find a unique property on the receiver that holds // this function. var ownName = this.fun.name; @@ -811,12 +841,12 @@ CallSite.prototype.getMethodName = function () { return null; }; -CallSite.prototype.getFileName = function () { +function CallSiteGetFileName() { var script = %FunctionGetScript(this.fun); return script ? script.name : null; }; -CallSite.prototype.getLineNumber = function () { +function CallSiteGetLineNumber() { if (this.pos == -1) { return null; } @@ -828,7 +858,7 @@ CallSite.prototype.getLineNumber = function () { return location ? location.line + 1 : null; }; -CallSite.prototype.getColumnNumber = function () { +function CallSiteGetColumnNumber() { if (this.pos == -1) { return null; } @@ -840,16 +870,16 @@ CallSite.prototype.getColumnNumber = function () { return location ? location.column + 1: null; }; -CallSite.prototype.isNative = function () { +function CallSiteIsNative() { var script = %FunctionGetScript(this.fun); return script ? (script.type == TYPE_NATIVE) : false; }; -CallSite.prototype.getPosition = function () { +function CallSiteGetPosition() { return this.pos; }; -CallSite.prototype.isConstructor = function () { +function CallSiteIsConstructor() { var constructor = this.receiver ? this.receiver.constructor : null; if (!constructor) { return false; @@ -857,6 +887,25 @@ CallSite.prototype.isConstructor = function () { return this.fun === constructor; }; +SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array( + "getThis", CallSiteGetThis, + "getTypeName", CallSiteGetTypeName, + "isToplevel", CallSiteIsToplevel, + "isEval", CallSiteIsEval, + "getEvalOrigin", CallSiteGetEvalOrigin, + "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL, + "getFunction", CallSiteGetFunction, + "getFunctionName", CallSiteGetFunctionName, + "getMethodName", CallSiteGetMethodName, + "getFileName", CallSiteGetFileName, + "getLineNumber", CallSiteGetLineNumber, + "getColumnNumber", CallSiteGetColumnNumber, + "isNative", CallSiteIsNative, + "getPosition", CallSiteGetPosition, + "isConstructor", CallSiteIsConstructor +)); + + function FormatEvalOrigin(script) { var sourceURL = script.nameOrSourceURL(); if (sourceURL) { @@ -998,63 +1047,6 @@ function FormatRawStackTrace(error, raw_stack) { } } -function DefineError(f) { - // Store the error function in both the global object - // and the runtime object. The function is fetched - // from the runtime object when throwing errors from - // within the runtime system to avoid strange side - // effects when overwriting the error functions from - // user code. - var name = f.name; - %SetProperty(global, name, f, DONT_ENUM); - this['$' + name] = f; - // Configure the error function. - if (name == 'Error') { - // The prototype of the Error object must itself be an error. - // However, it can't be an instance of the Error object because - // it hasn't been properly configured yet. Instead we create a - // special not-a-true-error-but-close-enough object. - function ErrorPrototype() {} - %FunctionSetPrototype(ErrorPrototype, $Object.prototype); - %FunctionSetInstanceClassName(ErrorPrototype, 'Error'); - %FunctionSetPrototype(f, new ErrorPrototype()); - } else { - %FunctionSetPrototype(f, new $Error()); - } - %FunctionSetInstanceClassName(f, 'Error'); - %SetProperty(f.prototype, 'constructor', f, DONT_ENUM); - // The name property on the prototype of error objects is not - // specified as being read-one and dont-delete. However, allowing - // overwriting allows leaks of error objects between script blocks - // in the same context in a browser setting. Therefore we fix the - // name. - %SetProperty(f.prototype, "name", name, DONT_ENUM | DONT_DELETE | READ_ONLY); - %SetCode(f, function(m) { - if (%_IsConstructCall()) { - // Define all the expected properties directly on the error - // object. This avoids going through getters and setters defined - // on prototype objects. - %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM); - %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM); - %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM); - if (m === kAddMessageAccessorsMarker) { - // DefineOneShotAccessor always inserts a message property and - // ignores setters. - DefineOneShotAccessor(this, 'message', function (obj) { - return FormatMessage(%NewMessageObject(obj.type, obj.arguments)); - }); - } else if (!IS_UNDEFINED(m)) { - %IgnoreAttributesAndSetProperty(this, - 'message', - ToString(m), - DONT_ENUM); - } - captureStackTrace(this, f); - } else { - return new f(m); - } - }); -} function captureStackTrace(obj, cons_opt) { var stackTraceLimit = $Error.stackTraceLimit; @@ -1070,52 +1062,100 @@ function captureStackTrace(obj, cons_opt) { }); }; -$Math.__proto__ = global.Object.prototype; -// DefineError is a native function. Use explicit receiver. Otherwise -// the receiver will be 'undefined'. -this.DefineError(function Error() { }); -this.DefineError(function TypeError() { }); -this.DefineError(function RangeError() { }); -this.DefineError(function SyntaxError() { }); -this.DefineError(function ReferenceError() { }); -this.DefineError(function EvalError() { }); -this.DefineError(function URIError() { }); +function SetUpError() { + // Define special error type constructors. + + function DefineError(f) { + // Store the error function in both the global object + // and the runtime object. The function is fetched + // from the runtime object when throwing errors from + // within the runtime system to avoid strange side + // effects when overwriting the error functions from + // user code. + var name = f.name; + %SetProperty(global, name, f, DONT_ENUM); + %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY); + // Configure the error function. + if (name == 'Error') { + // The prototype of the Error object must itself be an error. + // However, it can't be an instance of the Error object because + // it hasn't been properly configured yet. Instead we create a + // special not-a-true-error-but-close-enough object. + function ErrorPrototype() {} + %FunctionSetPrototype(ErrorPrototype, $Object.prototype); + %FunctionSetInstanceClassName(ErrorPrototype, 'Error'); + %FunctionSetPrototype(f, new ErrorPrototype()); + } else { + %FunctionSetPrototype(f, new $Error()); + } + %FunctionSetInstanceClassName(f, 'Error'); + %SetProperty(f.prototype, 'constructor', f, DONT_ENUM); + // The name property on the prototype of error objects is not + // specified as being read-one and dont-delete. However, allowing + // overwriting allows leaks of error objects between script blocks + // in the same context in a browser setting. Therefore we fix the + // name. + %SetProperty(f.prototype, "name", name, + DONT_ENUM | DONT_DELETE | READ_ONLY) ; + %SetCode(f, function(m) { + if (%_IsConstructCall()) { + // Define all the expected properties directly on the error + // object. This avoids going through getters and setters defined + // on prototype objects. + %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM); + %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM); + %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM); + if (m === kAddMessageAccessorsMarker) { + // DefineOneShotAccessor always inserts a message property and + // ignores setters. + DefineOneShotAccessor(this, 'message', function (obj) { + return FormatMessage(%NewMessageObject(obj.type, obj.arguments)); + }); + } else if (!IS_UNDEFINED(m)) { + %IgnoreAttributesAndSetProperty(this, + 'message', + ToString(m), + DONT_ENUM); + } + captureStackTrace(this, f); + } else { + return new f(m); + } + }); + } -$Error.captureStackTrace = captureStackTrace; + DefineError(function Error() { }); + DefineError(function TypeError() { }); + DefineError(function RangeError() { }); + DefineError(function SyntaxError() { }); + DefineError(function ReferenceError() { }); + DefineError(function EvalError() { }); + DefineError(function URIError() { }); +} -// Setup extra properties of the Error.prototype object. -function setErrorMessage() { - var desc = {value: '', - enumerable: false, - configurable: true, - writable: true }; - DefineOwnProperty($Error.prototype, - 'message', - ToPropertyDescriptor(desc), - true); +SetUpError(); -} +$Error.captureStackTrace = captureStackTrace; -setErrorMessage(); +%SetProperty($Error.prototype, 'message', '', DONT_ENUM); // Global list of error objects visited during errorToString. This is // used to detect cycles in error toString formatting. -var visited_errors = new $Array(); -var cyclic_error_marker = new $Object(); +const visited_errors = new InternalArray(); +const cyclic_error_marker = new $Object(); -function errorToStringDetectCycle() { - if (!%PushIfAbsent(visited_errors, this)) throw cyclic_error_marker; +function errorToStringDetectCycle(error) { + if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker; try { - var type = this.type; - if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) { - var formatted = FormatMessage(%NewMessageObject(type, this.arguments)); - return this.name + ": " + formatted; + var type = error.type; + var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty); + if (type && !hasMessage) { + var formatted = FormatMessage(%NewMessageObject(type, error.arguments)); + return error.name + ": " + formatted; } - var message = %_CallFunction(this, "message", ObjectHasOwnProperty) - ? (": " + this.message) - : ""; - return this.name + message; + var message = hasMessage ? (": " + error.message) : ""; + return error.name + message; } finally { visited_errors.length = visited_errors.length - 1; } @@ -1131,7 +1171,7 @@ function errorToString() { function isCyclicErrorMarker(o) { return o === cyclic_error_marker; } try { - return %_CallFunction(this, errorToStringDetectCycle); + return errorToStringDetectCycle(this); } catch(e) { // If this error message was encountered already return the empty // string for it instead of recursively formatting it. diff --git a/deps/v8/src/mips/assembler-mips.cc b/deps/v8/src/mips/assembler-mips.cc index 51642e05c3..f30f38bb75 100644 --- a/deps/v8/src/mips/assembler-mips.cc +++ b/deps/v8/src/mips/assembler-mips.cc @@ -49,11 +49,47 @@ bool CpuFeatures::initialized_ = false; unsigned CpuFeatures::supported_ = 0; unsigned CpuFeatures::found_by_runtime_probing_ = 0; + +// Get the CPU features enabled by the build. For cross compilation the +// preprocessor symbols CAN_USE_FPU_INSTRUCTIONS +// can be defined to enable FPU instructions when building the +// snapshot. +static uint64_t CpuFeaturesImpliedByCompiler() { + uint64_t answer = 0; +#ifdef CAN_USE_FPU_INSTRUCTIONS + answer |= 1u << FPU; +#endif // def CAN_USE_FPU_INSTRUCTIONS + +#ifdef __mips__ + // If the compiler is allowed to use FPU then we can use FPU too in our code + // generation even when generating snapshots. This won't work for cross + // compilation. +#if(defined(__mips_hard_float) && __mips_hard_float != 0) + answer |= 1u << FPU; +#endif // defined(__mips_hard_float) && __mips_hard_float != 0 +#endif // def __mips__ + + return answer; +} + + void CpuFeatures::Probe() { ASSERT(!initialized_); #ifdef DEBUG initialized_ = true; #endif + + // Get the features implied by the OS and the compiler settings. This is the + // minimal set of features which is also allowed for generated code in the + // snapshot. + supported_ |= OS::CpuFeaturesImpliedByPlatform(); + supported_ |= CpuFeaturesImpliedByCompiler(); + + if (Serializer::enabled()) { + // No probing for features if we might serialize (generate snapshot). + return; + } + // If the compiler is allowed to use fpu then we can use fpu too in our // code generation. #if !defined(__mips__) @@ -62,11 +98,7 @@ void CpuFeatures::Probe() { supported_ |= 1u << FPU; } #else - if (Serializer::enabled()) { - supported_ |= OS::CpuFeaturesImpliedByPlatform(); - return; // No features if we might serialize. - } - + // Probe for additional features not already known to be available. if (OS::MipsCpuHasFeature(FPU)) { // This implementation also sets the FPU flags if // runtime detection of FPU returns true. @@ -780,10 +812,10 @@ void Assembler::bind(Label* L) { void Assembler::next(Label* L) { ASSERT(L->is_linked()); int link = target_at(L->pos()); - ASSERT(link > 0 || link == kEndOfChain); if (link == kEndOfChain) { L->Unuse(); - } else if (link > 0) { + } else { + ASSERT(link >= 0); L->link_to(link); } } diff --git a/deps/v8/src/mips/builtins-mips.cc b/deps/v8/src/mips/builtins-mips.cc index 1555653f0a..d77230448f 100644 --- a/deps/v8/src/mips/builtins-mips.cc +++ b/deps/v8/src/mips/builtins-mips.cc @@ -210,7 +210,7 @@ static void AllocateJSArray(MacroAssembler* masm, // Allocate the JSArray object together with space for a FixedArray with the // requested number of elements. __ bind(¬_empty); - ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); __ li(elements_array_end, (JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize); __ sra(scratch1, array_size, kSmiTagSize); @@ -261,7 +261,7 @@ static void AllocateJSArray(MacroAssembler* masm, // Length of the FixedArray is the number of pre-allocated elements if // the actual JSArray has length 0 and the size of the JSArray for non-empty // JSArrays. The length of a FixedArray is stored as a smi. - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ li(at, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements))); __ movz(array_size, at, array_size); @@ -273,7 +273,7 @@ static void AllocateJSArray(MacroAssembler* masm, // result: JSObject // elements_array_storage: elements array element storage // array_size: smi-tagged size of elements array - ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); __ sll(elements_array_end, array_size, kPointerSizeLog2 - kSmiTagSize); __ Addu(elements_array_end, elements_array_storage, elements_array_end); @@ -336,14 +336,14 @@ static void ArrayNativeCode(MacroAssembler* masm, __ bind(&argc_one_or_more); __ Branch(&argc_two_or_more, ne, a0, Operand(1)); - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ lw(a2, MemOperand(sp)); // Get the argument from the stack. __ And(a3, a2, Operand(kIntptrSignBit | kSmiTagMask)); __ Branch(call_generic_code, eq, a3, Operand(zero_reg)); // Handle construction of an empty array of a certain size. Bail out if size // is too large to actually allocate an elements array. - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ Branch(call_generic_code, Ugreater_equal, a2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize)); @@ -576,7 +576,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // Is it a String? __ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset)); __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset)); - ASSERT(kNotStringTag != 0); + STATIC_ASSERT(kNotStringTag != 0); __ And(t0, a3, Operand(kIsNotStringMask)); __ Branch(&convert_argument, ne, t0, Operand(zero_reg)); __ mov(argument, a0); diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc index 2526a6a28b..1d528946c3 100644 --- a/deps/v8/src/mips/code-stubs-mips.cc +++ b/deps/v8/src/mips/code-stubs-mips.cc @@ -3538,7 +3538,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, const int kNumInstructionsToJump = 6; masm->Addu(ra, ra, kNumInstructionsToJump * kPointerSize); masm->sw(ra, MemOperand(sp)); // This spot was reserved in EnterExitFrame. - masm->Subu(sp, sp, StandardFrameConstants::kCArgsSlotsSize); + masm->Subu(sp, sp, kCArgsSlotsSize); // Stack is still aligned. // Call the C routine. @@ -3551,7 +3551,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, } // Restore stack (remove arg slots). - __ Addu(sp, sp, StandardFrameConstants::kCArgsSlotsSize); + __ Addu(sp, sp, kCArgsSlotsSize); if (always_allocate) { // It's okay to clobber a2 and a3 here. v0 & v1 contain result. @@ -3695,9 +3695,19 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // Save callee saved registers on the stack. __ MultiPush(kCalleeSaved | ra.bit()); + if (CpuFeatures::IsSupported(FPU)) { + CpuFeatures::Scope scope(FPU); + // Save callee-saved FPU registers. + __ MultiPushFPU(kCalleeSavedFPU); + } + // Load argv in s0 register. - __ lw(s0, MemOperand(sp, (kNumCalleeSaved + 1) * kPointerSize + - StandardFrameConstants::kCArgsSlotsSize)); + int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize; + if (CpuFeatures::IsSupported(FPU)) { + offset_to_argv += kNumCalleeSavedFPU * kDoubleSize; + } + + __ lw(s0, MemOperand(sp, offset_to_argv + kCArgsSlotsSize)); // We build an EntryFrame. __ li(t3, Operand(-1)); // Push a bad frame pointer to fail if it is used. @@ -3829,6 +3839,12 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // Reset the stack to the callee saved registers. __ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset); + if (CpuFeatures::IsSupported(FPU)) { + CpuFeatures::Scope scope(FPU); + // Restore callee-saved fpu registers. + __ MultiPopFPU(kCalleeSavedFPU); + } + // Restore callee saved registers from the stack. __ MultiPop(kCalleeSaved | ra.bit()); // Return. @@ -4527,9 +4543,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset)); // First check for flat string. - __ And(at, a0, Operand(kIsNotStringMask | kStringRepresentationMask)); + __ And(a1, a0, Operand(kIsNotStringMask | kStringRepresentationMask)); STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); - __ Branch(&seq_string, eq, at, Operand(zero_reg)); + __ Branch(&seq_string, eq, a1, Operand(zero_reg)); // subject: Subject string // a0: instance type if Subject string @@ -4541,10 +4557,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // a sequential string or an external string. // In the case of a sliced string its offset has to be taken into account. Label cons_string, check_encoding; - STATIC_ASSERT((kConsStringTag < kExternalStringTag)); - STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); - __ Branch(&cons_string, lt, at, Operand(kExternalStringTag)); - __ Branch(&runtime, eq, at, Operand(kExternalStringTag)); + STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); + __ Branch(&cons_string, lt, a1, Operand(kExternalStringTag)); + __ Branch(&runtime, eq, a1, Operand(kExternalStringTag)); // String is sliced. __ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset)); @@ -4652,7 +4668,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // frame. Therefore we have to use fp, which points exactly to two pointer // sizes below the previous sp. (Because creating a new stack frame pushes // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) - __ lw(a0, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); + __ lw(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); // If slice offset is not 0, load the length from the original sliced string. // Argument 4, a3: End of string data // Argument 3, a2: Start of string data @@ -4662,7 +4678,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ sllv(t1, a1, a3); __ addu(a2, t0, t1); - __ lw(t2, FieldMemOperand(a0, String::kLengthOffset)); + __ lw(t2, FieldMemOperand(subject, String::kLengthOffset)); __ sra(t2, t2, kSmiTagSize); __ sllv(t1, t2, a3); __ addu(a3, t0, t1); @@ -4670,7 +4686,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Already there // Argument 1 (a0): Subject string. - // Already there + __ mov(a0, subject); // Locate the code entry and call it. __ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag)); @@ -4688,13 +4704,13 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { Label success; __ Branch(&success, eq, - subject, Operand(NativeRegExpMacroAssembler::SUCCESS)); + v0, Operand(NativeRegExpMacroAssembler::SUCCESS)); Label failure; __ Branch(&failure, eq, - subject, Operand(NativeRegExpMacroAssembler::FAILURE)); + v0, Operand(NativeRegExpMacroAssembler::FAILURE)); // If not exception it can only be retry. Handle that in the runtime system. __ Branch(&runtime, ne, - subject, Operand(NativeRegExpMacroAssembler::EXCEPTION)); + v0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); // Result must now be exception. If there is no pending exception already a // stack overflow (on the backtrack stack) was detected in RegExp code but // haven't created the exception yet. Handle that in the runtime system. @@ -4705,16 +4721,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address, masm->isolate()))); __ lw(v0, MemOperand(a2, 0)); - __ Branch(&runtime, eq, subject, Operand(a1)); + __ Branch(&runtime, eq, v0, Operand(a1)); __ sw(a1, MemOperand(a2, 0)); // Clear pending exception. // Check if the exception is a termination. If so, throw as uncatchable. __ LoadRoot(a0, Heap::kTerminationExceptionRootIndex); Label termination_exception; - __ Branch(&termination_exception, eq, subject, Operand(a0)); + __ Branch(&termination_exception, eq, v0, Operand(a0)); - __ Throw(subject); // Expects thrown value in v0. + __ Throw(v0); // Expects thrown value in v0. __ bind(&termination_exception); __ ThrowUncatchable(TERMINATION, v0); // Expects thrown value in v0. @@ -5025,8 +5041,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // Handle non-flat strings. __ And(result_, result_, Operand(kStringRepresentationMask)); - STATIC_ASSERT((kConsStringTag < kExternalStringTag)); - STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); + STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); __ Branch(&sliced_string, gt, result_, Operand(kExternalStringTag)); __ Branch(&call_runtime_, eq, result_, Operand(kExternalStringTag)); @@ -5062,7 +5078,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // Check for 1-byte or 2-byte string. __ bind(&flat_string); - STATIC_ASSERT(kAsciiStringTag != 0); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ And(t0, result_, Operand(kStringEncodingMask)); __ Branch(&ascii_string, ne, t0, Operand(zero_reg)); @@ -5625,11 +5642,6 @@ void SubStringStub::Generate(MacroAssembler* masm) { Register to = t2; Register from = t3; - if (FLAG_string_slices) { - __ nop(); // Jumping as first instruction would crash the code generation. - __ jmp(&sub_string_runtime); - } - // Check bounds and smi-ness. __ lw(to, MemOperand(sp, kToOffset)); __ lw(from, MemOperand(sp, kFromOffset)); @@ -5653,7 +5665,8 @@ void SubStringStub::Generate(MacroAssembler* masm) { // Special handling of sub-strings of length 1 and 2. One character strings // are handled in the runtime system (looked up in the single character - // cache). Two character strings are looked for in the symbol cache. + // cache). Two character strings are looked for in the symbol cache in + // generated code. __ Branch(&sub_string_runtime, lt, a2, Operand(2)); // Both to and from are smis. @@ -5665,19 +5678,32 @@ void SubStringStub::Generate(MacroAssembler* masm) { // t5: to index (untagged smi) // Make sure first argument is a sequential (or flat) string. - __ lw(t1, MemOperand(sp, kStringOffset)); - __ Branch(&sub_string_runtime, eq, t1, Operand(kSmiTagMask)); + __ lw(v0, MemOperand(sp, kStringOffset)); + __ Branch(&sub_string_runtime, eq, v0, Operand(kSmiTagMask)); - __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset)); + __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); - __ And(t4, a1, Operand(kIsNotStringMask)); + __ And(t4, v0, Operand(kIsNotStringMask)); __ Branch(&sub_string_runtime, ne, t4, Operand(zero_reg)); + // Short-cut for the case of trivial substring. + Label return_v0; + // v0: original string + // a2: result string length + __ lw(t0, FieldMemOperand(v0, String::kLengthOffset)); + __ sra(t0, t0, 1); + __ Branch(&return_v0, eq, a2, Operand(t0)); + + Label create_slice; + if (FLAG_string_slices) { + __ Branch(&create_slice, ge, a2, Operand(SlicedString::kMinLength)); + } + + // v0: original string // a1: instance type // a2: result string length // a3: from index (untagged smi) - // t1: string // t2: (a.k.a. to): to (smi) // t3: (a.k.a. from): from offset (smi) // t5: to index (untagged smi) @@ -5686,8 +5712,9 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ And(t0, a1, Operand(kStringRepresentationMask)); STATIC_ASSERT(kSeqStringTag < kConsStringTag); STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kConsStringTag < kSlicedStringTag); - // External strings go to runtime. + // Slices and external strings go to runtime. __ Branch(&sub_string_runtime, gt, t0, Operand(kConsStringTag)); // Sequential strings are handled directly. @@ -5696,32 +5723,32 @@ void SubStringStub::Generate(MacroAssembler* masm) { // Cons string. Try to recurse (once) on the first substring. // (This adds a little more generality than necessary to handle flattened // cons strings, but not much). - __ lw(t1, FieldMemOperand(t1, ConsString::kFirstOffset)); - __ lw(t0, FieldMemOperand(t1, HeapObject::kMapOffset)); + __ lw(v0, FieldMemOperand(v0, ConsString::kFirstOffset)); + __ lw(t0, FieldMemOperand(v0, HeapObject::kMapOffset)); __ lbu(a1, FieldMemOperand(t0, Map::kInstanceTypeOffset)); STATIC_ASSERT(kSeqStringTag == 0); - // Cons and External strings go to runtime. + // Cons, slices and external strings go to runtime. __ Branch(&sub_string_runtime, ne, a1, Operand(kStringRepresentationMask)); // Definitly a sequential string. __ bind(&seq_string); + // v0: original string // a1: instance type // a2: result string length // a3: from index (untagged smi) - // t1: string // t2: (a.k.a. to): to (smi) // t3: (a.k.a. from): from offset (smi) // t5: to index (untagged smi) - __ lw(t0, FieldMemOperand(t1, String::kLengthOffset)); + __ lw(t0, FieldMemOperand(v0, String::kLengthOffset)); __ Branch(&sub_string_runtime, lt, t0, Operand(to)); // Fail if to > length. to = no_reg; + // v0: original string or left hand side of the original cons string. // a1: instance type // a2: result string length // a3: from index (untagged smi) - // t1: string // t3: (a.k.a. from): from offset (smi) // t5: to index (untagged smi) @@ -5737,84 +5764,147 @@ void SubStringStub::Generate(MacroAssembler* masm) { // Sub string of length 2 requested. // Get the two characters forming the sub string. - __ Addu(t1, t1, Operand(a3)); - __ lbu(a3, FieldMemOperand(t1, SeqAsciiString::kHeaderSize)); - __ lbu(t0, FieldMemOperand(t1, SeqAsciiString::kHeaderSize + 1)); + __ Addu(v0, v0, Operand(a3)); + __ lbu(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); + __ lbu(t0, FieldMemOperand(v0, SeqAsciiString::kHeaderSize + 1)); // Try to lookup two character string in symbol table. Label make_two_character_string; StringHelper::GenerateTwoCharacterSymbolTableProbe( masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string); Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1, a3, t0); - __ Addu(sp, sp, Operand(3 * kPointerSize)); - __ Ret(); - + __ jmp(&return_v0); // a2: result string length. // a3: two characters combined into halfword in little endian byte order. __ bind(&make_two_character_string); __ AllocateAsciiString(v0, a2, t0, t1, t4, &sub_string_runtime); __ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); - __ IncrementCounter(counters->sub_string_native(), 1, a3, t0); - __ Addu(sp, sp, Operand(3 * kPointerSize)); - __ Ret(); + __ jmp(&return_v0); __ bind(&result_longer_than_two); + // Locate 'from' character of string. + __ Addu(t1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ sra(t4, from, 1); + __ Addu(t1, t1, t4); + // Allocate the result. __ AllocateAsciiString(v0, a2, t4, t0, a1, &sub_string_runtime); - // v0: result string. - // a2: result string length. + // v0: result string + // a2: result string length // a3: from index (untagged smi) - // t1: string. + // t1: first character of substring to copy // t3: (a.k.a. from): from offset (smi) // Locate first character of result. __ Addu(a1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); - // Locate 'from' character of string. - __ Addu(t1, t1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); - __ Addu(t1, t1, Operand(a3)); - // v0: result string. - // a1: first character of result string. - // a2: result string length. - // t1: first character of sub string to copy. + // v0: result string + // a1: first character of result string + // a2: result string length + // t1: first character of substring to copy STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); StringHelper::GenerateCopyCharactersLong( masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED); - __ IncrementCounter(counters->sub_string_native(), 1, a3, t0); - __ Addu(sp, sp, Operand(3 * kPointerSize)); - __ Ret(); + __ jmp(&return_v0); __ bind(&non_ascii_flat); - // a2: result string length. - // t1: string. + // a2: result string length + // t1: string // t3: (a.k.a. from): from offset (smi) // Check for flat two byte string. + // Locate 'from' character of string. + __ Addu(t1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); + // As "from" is a smi it is 2 times the value which matches the size of a two + // byte character. + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + __ Addu(t1, t1, Operand(from)); + // Allocate the result. __ AllocateTwoByteString(v0, a2, a1, a3, t0, &sub_string_runtime); - // v0: result string. - // a2: result string length. - // t1: string. + // v0: result string + // a2: result string length + // t1: first character of substring to copy // Locate first character of result. __ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - // Locate 'from' character of string. - __ Addu(t1, t1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - // As "from" is a smi it is 2 times the value which matches the size of a two - // byte character. - __ Addu(t1, t1, Operand(from)); + from = no_reg; // v0: result string. // a1: first character of result. // a2: result length. - // t1: first character of string to copy. + // t1: first character of substring to copy. STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); StringHelper::GenerateCopyCharactersLong( masm, a1, t1, a2, a3, t0, t2, t3, t4, DEST_ALWAYS_ALIGNED); + __ jmp(&return_v0); + + if (FLAG_string_slices) { + __ bind(&create_slice); + // v0: original string + // a1: instance type + // a2: length + // a3: from index (untagged smi) + // t2 (a.k.a. to): to (smi) + // t3 (a.k.a. from): from offset (smi) + Label allocate_slice, sliced_string, seq_string; + STATIC_ASSERT(kSeqStringTag == 0); + __ And(t4, a1, Operand(kStringRepresentationMask)); + __ Branch(&seq_string, eq, t4, Operand(zero_reg)); + STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); + STATIC_ASSERT(kIsIndirectStringMask != 0); + __ And(t4, a1, Operand(kIsIndirectStringMask)); + // External string. Jump to runtime. + __ Branch(&sub_string_runtime, eq, t4, Operand(zero_reg)); + + __ And(t4, a1, Operand(kSlicedNotConsMask)); + __ Branch(&sliced_string, ne, t4, Operand(zero_reg)); + // Cons string. Check whether it is flat, then fetch first part. + __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset)); + __ LoadRoot(t5, Heap::kEmptyStringRootIndex); + __ Branch(&sub_string_runtime, ne, t1, Operand(t5)); + __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset)); + __ jmp(&allocate_slice); + + __ bind(&sliced_string); + // Sliced string. Fetch parent and correct start index by offset. + __ lw(t1, FieldMemOperand(v0, SlicedString::kOffsetOffset)); + __ addu(t3, t3, t1); + __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset)); + __ jmp(&allocate_slice); + + __ bind(&seq_string); + // Sequential string. Just move string to the right register. + __ mov(t1, v0); + + __ bind(&allocate_slice); + // a1: instance type of original string + // a2: length + // t1: underlying subject string + // t3 (a.k.a. from): from offset (smi) + // Allocate new sliced string. At this point we do not reload the instance + // type including the string encoding because we simply rely on the info + // provided by the original string. It does not matter if the original + // string's encoding is wrong because we always have to recheck encoding of + // the newly created string's parent anyways due to externalized strings. + Label two_byte_slice, set_slice_header; + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ And(t4, a1, Operand(kStringEncodingMask)); + __ Branch(&two_byte_slice, eq, t4, Operand(zero_reg)); + __ AllocateAsciiSlicedString(v0, a2, a3, t0, &sub_string_runtime); + __ jmp(&set_slice_header); + __ bind(&two_byte_slice); + __ AllocateTwoByteSlicedString(v0, a2, a3, t0, &sub_string_runtime); + __ bind(&set_slice_header); + __ sw(t3, FieldMemOperand(v0, SlicedString::kOffsetOffset)); + __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset)); + } + + __ bind(&return_v0); __ IncrementCounter(counters->sub_string_native(), 1, a3, t0); __ Addu(sp, sp, Operand(3 * kPointerSize)); __ Ret(); diff --git a/deps/v8/src/mips/constants-mips.h b/deps/v8/src/mips/constants-mips.h index 6bf2570ebd..ede9688a68 100644 --- a/deps/v8/src/mips/constants-mips.h +++ b/deps/v8/src/mips/constants-mips.h @@ -743,11 +743,9 @@ class Instruction { // ----------------------------------------------------------------------------- // MIPS assembly various constants. - -static const int kArgsSlotsSize = 4 * Instruction::kInstrSize; -static const int kArgsSlotsNum = 4; // C/C++ argument slots size. -static const int kCArgsSlotsSize = 4 * Instruction::kInstrSize; +static const int kCArgSlotCount = 4; +static const int kCArgsSlotsSize = kCArgSlotCount * Instruction::kInstrSize; // JS argument slots size. static const int kJSArgsSlotsSize = 0 * Instruction::kInstrSize; // Assembly builtins argument slots size. diff --git a/deps/v8/src/mips/frames-mips.h b/deps/v8/src/mips/frames-mips.h index 1899843a19..798ef23b2e 100644 --- a/deps/v8/src/mips/frames-mips.h +++ b/deps/v8/src/mips/frames-mips.h @@ -30,7 +30,6 @@ #ifndef V8_MIPS_FRAMES_MIPS_H_ #define V8_MIPS_FRAMES_MIPS_H_ - namespace v8 { namespace internal { @@ -40,13 +39,22 @@ namespace internal { static const int kNumRegs = 32; static const RegList kJSCallerSaved = - 1 << 2 | // v0 - 1 << 4 | // a0 - 1 << 5 | // a1 - 1 << 6 | // a2 - 1 << 7; // a3 - -static const int kNumJSCallerSaved = 5; + 1 << 2 | // v0 + 1 << 3 | // v1 + 1 << 4 | // a0 + 1 << 5 | // a1 + 1 << 6 | // a2 + 1 << 7 | // a3 + 1 << 8 | // t0 + 1 << 9 | // t1 + 1 << 10 | // t2 + 1 << 11 | // t3 + 1 << 12 | // t4 + 1 << 13 | // t5 + 1 << 14 | // t6 + 1 << 15; // t7 + +static const int kNumJSCallerSaved = 14; // Return the code of the n-th caller-saved register available to JavaScript @@ -56,19 +64,31 @@ int JSCallerSavedCode(int n); // Callee-saved registers preserved when switching from C to JavaScript. static const RegList kCalleeSaved = - // Saved temporaries. - 1 << 16 | 1 << 17 | 1 << 18 | 1 << 19 | - 1 << 20 | 1 << 21 | 1 << 22 | 1 << 23 | - // fp. - 1 << 30; + 1 << 16 | // s0 + 1 << 17 | // s1 + 1 << 18 | // s2 + 1 << 19 | // s3 + 1 << 20 | // s4 + 1 << 21 | // s5 + 1 << 22 | // s6 (roots in Javascript code) + 1 << 23 | // s7 (cp in Javascript code) + 1 << 30; // fp/s8 static const int kNumCalleeSaved = 9; +static const RegList kCalleeSavedFPU = + 1 << 20 | // f20 + 1 << 22 | // f22 + 1 << 24 | // f24 + 1 << 26 | // f26 + 1 << 28 | // f28 + 1 << 30; // f30 +static const int kNumCalleeSavedFPU = 6; // Number of registers for which space is reserved in safepoints. Must be a // multiple of 8. // TODO(mips): Only 8 registers may actually be sufficient. Revisit. -static const int kNumSafepointRegisters = 16; +static const int kNumSafepointRegisters = 24; // Define the list of registers actually saved at safepoints. // Note that the number of saved registers may be smaller than the reserved @@ -82,37 +102,37 @@ typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved]; static const int kUndefIndex = -1; // Map with indexes on stack that corresponds to codes of saved registers. static const int kSafepointRegisterStackIndexMap[kNumRegs] = { - kUndefIndex, - kUndefIndex, - 0, // v0 - kUndefIndex, - 1, // a0 - 2, // a1 - 3, // a2 - 4, // a3 - kUndefIndex, - kUndefIndex, - kUndefIndex, - kUndefIndex, - kUndefIndex, - kUndefIndex, - kUndefIndex, - kUndefIndex, - 5, // Saved temporaries. - 6, - 7, - 8, - 9, - 10, - 11, - 12, - kUndefIndex, - kUndefIndex, - kUndefIndex, - kUndefIndex, - 13, // gp - 14, // sp - 15, // fp + kUndefIndex, // zero_reg + kUndefIndex, // at + 0, // v0 + 1, // v1 + 2, // a0 + 3, // a1 + 4, // a2 + 5, // a3 + 6, // t0 + 7, // t1 + 8, // t2 + 9, // t3 + 10, // t4 + 11, // t5 + 12, // t6 + 13, // t7 + 14, // s0 + 15, // s1 + 16, // s2 + 17, // s3 + 18, // s4 + 19, // s5 + 20, // s6 + 21, // s7 + kUndefIndex, // t8 + kUndefIndex, // t9 + kUndefIndex, // k0 + kUndefIndex, // k1 + kUndefIndex, // gp + kUndefIndex, // sp + 22, // fp kUndefIndex }; @@ -174,9 +194,6 @@ class StandardFrameConstants : public AllStatic { static const int kRArgsSlotsSize = 4 * kPointerSize; static const int kRegularArgsSlotsSize = kRArgsSlotsSize; - // C/C++ argument slots size. - static const int kCArgSlotCount = 4; - static const int kCArgsSlotsSize = kCArgSlotCount * kPointerSize; // JS argument slots size. static const int kJSArgsSlotsSize = 0 * kPointerSize; // Assembly builtins argument slots size. diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc index cf48ccfd4f..385e57ae66 100644 --- a/deps/v8/src/mips/full-codegen-mips.cc +++ b/deps/v8/src/mips/full-codegen-mips.cc @@ -200,7 +200,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // Copy any necessary parameters into the context. int num_parameters = info->scope()->num_parameters(); for (int i = 0; i < num_parameters; i++) { - Slot* slot = scope()->parameter(i)->AsSlot(); + Slot* slot = scope()->parameter(i)->rewrite(); if (slot != NULL && slot->type() == Slot::CONTEXT) { int parameter_offset = StandardFrameConstants::kCallerSPOffset + (num_parameters - 1 - i) * kPointerSize; @@ -252,7 +252,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { ArgumentsAccessStub stub(type); __ CallStub(&stub); - Move(arguments->AsSlot(), v0, a1, a2); + Move(arguments->rewrite(), v0, a1, a2); } if (FLAG_trace) { @@ -266,6 +266,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { scope()->VisitIllegalRedeclaration(this); } else { + PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); { Comment cmnt(masm_, "[ Declarations"); // For named function expressions, declare the function name as a // constant. @@ -276,7 +277,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { } { Comment cmnt(masm_, "[ Stack check"); - PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); + PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); Label ok; __ LoadRoot(t0, Heap::kStackLimitRootIndex); __ Branch(&ok, hs, sp, Operand(t0)); @@ -632,6 +633,7 @@ MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { return ContextOperand(scratch, slot->index()); } case Slot::LOOKUP: + case Slot::GLOBAL: UNREACHABLE(); } UNREACHABLE(); @@ -690,22 +692,23 @@ void FullCodeGenerator::Move(Slot* dst, } -void FullCodeGenerator::EmitDeclaration(Variable* variable, +void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, Variable::Mode mode, FunctionLiteral* function) { Comment cmnt(masm_, "[ Declaration"); + Variable* variable = proxy->var(); ASSERT(variable != NULL); // Must have been resolved. - Slot* slot = variable->AsSlot(); + Slot* slot = variable->rewrite(); ASSERT(slot != NULL); switch (slot->type()) { case Slot::PARAMETER: case Slot::LOCAL: - if (mode == Variable::CONST) { - __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); - __ sw(t0, MemOperand(fp, SlotOffset(slot))); - } else if (function != NULL) { + if (function != NULL) { VisitForAccumulatorValue(function); __ sw(result_register(), MemOperand(fp, SlotOffset(slot))); + } else if (mode == Variable::CONST || mode == Variable::LET) { + __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); + __ sw(t0, MemOperand(fp, SlotOffset(slot))); } break; @@ -726,17 +729,19 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ Check(ne, "Declaration in catch context.", a1, Operand(t0)); } - if (mode == Variable::CONST) { - __ LoadRoot(at, Heap::kTheHoleValueRootIndex); - __ sw(at, ContextOperand(cp, slot->index())); - // No write barrier since the_hole_value is in old space. - } else if (function != NULL) { + if (function != NULL) { VisitForAccumulatorValue(function); __ sw(result_register(), ContextOperand(cp, slot->index())); int offset = Context::SlotOffset(slot->index()); // We know that we have written a function, which is not a smi. __ mov(a1, cp); __ RecordWrite(a1, Operand(offset), a2, result_register()); + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); + } else if (mode == Variable::CONST || mode == Variable::LET) { + __ LoadRoot(at, Heap::kTheHoleValueRootIndex); + __ sw(at, ContextOperand(cp, slot->index())); + // No write barrier since the_hole_value is in old space. + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); } break; @@ -752,13 +757,13 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, // Note: For variables we must not push an initial value (such as // 'undefined') because we may have a (legal) redeclaration and we // must not destroy the current value. - if (mode == Variable::CONST) { - __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); - __ Push(cp, a2, a1, a0); - } else if (function != NULL) { + if (function != NULL) { __ Push(cp, a2, a1); // Push initial value for function declaration. VisitForStackValue(function); + } else if (mode == Variable::CONST || mode == Variable::LET) { + __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); + __ Push(cp, a2, a1, a0); } else { ASSERT(Smi::FromInt(0) == 0); // No initial value! @@ -768,23 +773,25 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ CallRuntime(Runtime::kDeclareContextSlot, 4); break; } + + case Slot::GLOBAL: + UNREACHABLE(); } } void FullCodeGenerator::VisitDeclaration(Declaration* decl) { - EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); + EmitDeclaration(decl->proxy(), decl->mode(), decl->fun()); } void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { // Call the runtime to declare the globals. // The context is the first argument. - __ li(a2, Operand(pairs)); - __ li(a1, Operand(Smi::FromInt(is_eval() ? 1 : 0))); - __ li(a0, Operand(Smi::FromInt(strict_mode_flag()))); - __ Push(cp, a2, a1, a0); - __ CallRuntime(Runtime::kDeclareGlobals, 4); + __ li(a1, Operand(pairs)); + __ li(a0, Operand(Smi::FromInt(DeclareGlobalsFlags()))); + __ Push(cp, a1, a0); + __ CallRuntime(Runtime::kDeclareGlobals, 3); // Return value is ignored. } @@ -1189,7 +1196,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); __ Branch(done); } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { - Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); + Slot* potential_slot = slot->var()->local_if_not_shadowed()->rewrite(); Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); if (potential_slot != NULL) { // Generate fast case for locals that rewrite to slots. @@ -1215,7 +1222,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( // variables. Then load the argument from the arguments // object using keyed load. __ lw(a1, - ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), + ContextSlotOperandCheckExtensions(obj_proxy->var()->rewrite(), slow)); __ li(a0, Operand(key_literal->handle())); Handle<Code> ic = @@ -1236,7 +1243,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { // Three cases: non-this global variables, lookup slots, and all other // types of slots. - Slot* slot = var->AsSlot(); + Slot* slot = var->rewrite(); ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); if (slot == NULL) { @@ -1279,9 +1286,22 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); __ movz(v0, a0, at); // Conditional move. context()->Plug(v0); - } else { - context()->Plug(slot); - } + } else if (var->mode() == Variable::LET) { + // Let bindings may be the hole value if they have not been initialized. + // Throw a type error in this case. + Label done; + MemOperand slot_operand = EmitSlotSearch(slot, a0); + __ lw(v0, slot_operand); + __ LoadRoot(a1, Heap::kTheHoleValueRootIndex); + __ Branch(&done, ne, v0, Operand(a1)); + __ li(v0, Operand(var->name())); + __ push(v0); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&done); + context()->Plug(v0); + } else { + context()->Plug(slot); + } } } @@ -1500,9 +1520,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { // Update the write barrier for the array store with v0 as the scratch // register. - __ li(a2, Operand(offset)); - // TODO(PJ): double check this RecordWrite call. - __ RecordWrite(a1, a2, result_register()); + __ RecordWrite(a1, Operand(offset), a2, result_register()); PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); } @@ -1822,7 +1840,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) { ASSERT(var != NULL); - ASSERT(var->is_global() || var->AsSlot() != NULL); + ASSERT(var->is_global() || var->rewrite() != NULL); if (var->is_global()) { ASSERT(!var->is_this()); @@ -1842,7 +1860,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // scope. However, unlike var initializers, const initializers are able // to drill a hole to that function context, even from inside a 'with' // context. We thus bypass the normal static scope lookup. - Slot* slot = var->AsSlot(); + Slot* slot = var->rewrite(); Label skip; switch (slot->type()) { case Slot::PARAMETER: @@ -1863,13 +1881,65 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ Push(cp, a0); // Context and name. __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); break; + case Slot::GLOBAL: + UNREACHABLE(); } __ bind(&skip); + } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { + // Perform the assignment for non-const variables. Const assignments + // are simply skipped. + Slot* slot = var->AsSlot(); + switch (slot->type()) { + case Slot::PARAMETER: + case Slot::LOCAL: { + Label assign; + // Check for an initialized let binding. + __ lw(a1, MemOperand(fp, SlotOffset(slot))); + __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); + __ Branch(&assign, ne, a1, Operand(t0)); + __ li(a1, Operand(var->name())); + __ push(a1); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + // Perform the assignment. + __ bind(&assign); + __ sw(result_register(), MemOperand(fp, SlotOffset(slot))); + break; + } + case Slot::CONTEXT: { + // Let variables may be the hole value if they have not been + // initialized. Throw a type error in this case. + Label assign; + MemOperand target = EmitSlotSearch(slot, a1); + // Check for an initialized let binding. + __ lw(a3, target); + __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); + __ Branch(&assign, ne, a3, Operand(t0)); + __ li(a3, Operand(var->name())); + __ push(a3); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + // Perform the assignment. + __ bind(&assign); + __ sw(result_register(), target); + // RecordWrite may destroy all its register arguments. + __ mov(a3, result_register()); + int offset = Context::SlotOffset(slot->index()); + __ RecordWrite(a1, Operand(offset), a2, a3); + break; + } + case Slot::LOOKUP: + // Call the runtime for the assignment. + __ push(v0); // Value. + __ li(a1, Operand(slot->var()->name())); + __ li(a0, Operand(Smi::FromInt(strict_mode_flag()))); + __ Push(cp, a1, a0); // Context, name, strict mode. + __ CallRuntime(Runtime::kStoreContextSlot, 4); + break; + } } else if (var->mode() != Variable::CONST) { // Perform the assignment for non-const variables. Const assignments // are simply skipped. - Slot* slot = var->AsSlot(); + Slot* slot = var->rewrite(); switch (slot->type()) { case Slot::PARAMETER: case Slot::LOCAL: @@ -1896,6 +1966,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ Push(cp, a1, a0); // Context, name, strict mode. __ CallRuntime(Runtime::kStoreContextSlot, 4); break; + + case Slot::GLOBAL: + UNREACHABLE(); } } } @@ -2115,8 +2188,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, int receiver_offset = 2 + info_->scope()->num_parameters(); __ lw(a1, MemOperand(fp, receiver_offset * kPointerSize)); __ push(a1); - // Push the strict mode flag. - __ li(a1, Operand(Smi::FromInt(strict_mode_flag()))); + // Push the strict mode flag. In harmony mode every eval call + // is a strict mode eval call. + StrictModeFlag strict_mode = strict_mode_flag(); + if (FLAG_harmony_block_scoping) { + strict_mode = kStrictMode; + } + __ li(a1, Operand(Smi::FromInt(strict_mode))); __ push(a1); __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP @@ -2158,9 +2236,9 @@ void FullCodeGenerator::VisitCall(Call* expr) { // in generated code. If we succeed, there is no need to perform a // context lookup in the runtime system. Label done; - if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { + if (var->rewrite() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { Label slow; - EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), + EmitLoadGlobalSlotCheckExtensions(var->rewrite(), NOT_INSIDE_TYPEOF, &slow); // Push the function and resolve eval. @@ -2198,15 +2276,15 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ lw(a0, GlobalObjectOperand()); __ push(a0); EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); - } else if (var != NULL && var->AsSlot() != NULL && - var->AsSlot()->type() == Slot::LOOKUP) { + } else if (var != NULL && var->rewrite() != NULL && + var->rewrite()->type() == Slot::LOOKUP) { // Call to a lookup slot (dynamically introduced variable). Label slow, done; { PreservePositionScope scope(masm()->positions_recorder()); // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLoadFromSlotFastCase(var->AsSlot(), + EmitDynamicLoadFromSlotFastCase(var->rewrite(), NOT_INSIDE_TYPEOF, &slow, &done); @@ -3208,7 +3286,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { Label done, not_found; - ASSERT(kSmiTag == 0 && kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); __ lw(a2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset)); // a2 now holds finger offset as a smi. __ Addu(a3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); @@ -3611,8 +3689,8 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { __ Push(a2, a1, a0); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(v0); - } else if (var->AsSlot() != NULL && - var->AsSlot()->type() != Slot::LOOKUP) { + } else if (var->rewrite() != NULL && + var->rewrite()->type() != Slot::LOOKUP) { // Result of deleting non-global, non-dynamic variables is false. // The subexpression does not have side effects. context()->Plug(false); @@ -3902,13 +3980,13 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { PrepareForBailout(expr, TOS_REG); context()->Plug(v0); } else if (proxy != NULL && - proxy->var()->AsSlot() != NULL && - proxy->var()->AsSlot()->type() == Slot::LOOKUP) { + proxy->var()->rewrite() != NULL && + proxy->var()->rewrite()->type() == Slot::LOOKUP) { Label done, slow; // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - Slot* slot = proxy->var()->AsSlot(); + Slot* slot = proxy->var()->rewrite(); EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); __ bind(&slow); @@ -4203,7 +4281,7 @@ void FullCodeGenerator::EnterFinallyBlock() { // Cook return address in link register to stack (smi encoded Code* delta). __ Subu(a1, ra, Operand(masm_->CodeObject())); ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(0 == kSmiTag); __ Addu(a1, a1, Operand(a1)); // Convert to smi. __ push(a1); } @@ -4224,6 +4302,34 @@ void FullCodeGenerator::ExitFinallyBlock() { #undef __ +#define __ ACCESS_MASM(masm()) + +FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( + int* stack_depth, + int* context_length) { + // The macros used here must preserve the result register. + + // Because the handler block contains the context of the finally + // code, we can restore it directly from there for the finally code + // rather than iteratively unwinding contexts via their previous + // links. + __ Drop(*stack_depth); // Down to the handler block. + if (*context_length > 0) { + // Restore the context to its dedicated register and the stack. + __ lw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset)); + __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ PopTryHandler(); + __ Call(finally_entry_); + + *stack_depth = 0; + *context_length = 0; + return previous_; +} + + +#undef __ + } } // namespace v8::internal #endif // V8_TARGET_ARCH_MIPS diff --git a/deps/v8/src/mips/ic-mips.cc b/deps/v8/src/mips/ic-mips.cc index 85cb916488..5ef35548d6 100644 --- a/deps/v8/src/mips/ic-mips.cc +++ b/deps/v8/src/mips/ic-mips.cc @@ -338,7 +338,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, __ Addu(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); // The key is a smi. - ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); __ sll(at, key, kPointerSizeLog2 - kSmiTagSize); __ addu(at, at, scratch1); __ lw(scratch2, MemOperand(at)); @@ -372,7 +372,7 @@ static void GenerateKeyStringCheck(MacroAssembler* masm, // Is the string a symbol? // map: key map __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); - ASSERT(kSymbolTag != 0); + STATIC_ASSERT(kSymbolTag != 0); __ And(at, hash, Operand(kIsSymbolMask)); __ Branch(not_symbol, eq, at, Operand(zero_reg)); } @@ -1269,7 +1269,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); __ Branch(&slow, hs, key, Operand(t0)); // Calculate key + 1 as smi. - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(0 == kSmiTag); __ Addu(t3, key, Operand(Smi::FromInt(1))); __ sw(t3, FieldMemOperand(receiver, JSArray::kLengthOffset)); __ Branch(&fast); diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc index 8e4b8ef973..1a37d65927 100644 --- a/deps/v8/src/mips/macro-assembler-mips.cc +++ b/deps/v8/src/mips/macro-assembler-mips.cc @@ -703,52 +703,114 @@ void MacroAssembler::li(Register rd, Operand j, bool gen2instr) { void MacroAssembler::MultiPush(RegList regs) { - int16_t NumSaved = 0; - int16_t NumToPush = NumberOfBitsSet(regs); + int16_t num_to_push = NumberOfBitsSet(regs); + int16_t stack_offset = num_to_push * kPointerSize; - addiu(sp, sp, -4 * NumToPush); + Subu(sp, sp, Operand(stack_offset)); for (int16_t i = kNumRegisters; i > 0; i--) { if ((regs & (1 << i)) != 0) { - sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved))); + stack_offset -= kPointerSize; + sw(ToRegister(i), MemOperand(sp, stack_offset)); } } } void MacroAssembler::MultiPushReversed(RegList regs) { - int16_t NumSaved = 0; - int16_t NumToPush = NumberOfBitsSet(regs); + int16_t num_to_push = NumberOfBitsSet(regs); + int16_t stack_offset = num_to_push * kPointerSize; - addiu(sp, sp, -4 * NumToPush); + Subu(sp, sp, Operand(stack_offset)); for (int16_t i = 0; i < kNumRegisters; i++) { if ((regs & (1 << i)) != 0) { - sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved))); + stack_offset -= kPointerSize; + sw(ToRegister(i), MemOperand(sp, stack_offset)); } } } void MacroAssembler::MultiPop(RegList regs) { - int16_t NumSaved = 0; + int16_t stack_offset = 0; for (int16_t i = 0; i < kNumRegisters; i++) { if ((regs & (1 << i)) != 0) { - lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++))); + lw(ToRegister(i), MemOperand(sp, stack_offset)); + stack_offset += kPointerSize; } } - addiu(sp, sp, 4 * NumSaved); + addiu(sp, sp, stack_offset); } void MacroAssembler::MultiPopReversed(RegList regs) { - int16_t NumSaved = 0; + int16_t stack_offset = 0; for (int16_t i = kNumRegisters; i > 0; i--) { if ((regs & (1 << i)) != 0) { - lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++))); + lw(ToRegister(i), MemOperand(sp, stack_offset)); + stack_offset += kPointerSize; } } - addiu(sp, sp, 4 * NumSaved); + addiu(sp, sp, stack_offset); +} + + +void MacroAssembler::MultiPushFPU(RegList regs) { + CpuFeatures::Scope scope(FPU); + int16_t num_to_push = NumberOfBitsSet(regs); + int16_t stack_offset = num_to_push * kDoubleSize; + + Subu(sp, sp, Operand(stack_offset)); + for (int16_t i = kNumRegisters; i > 0; i--) { + if ((regs & (1 << i)) != 0) { + stack_offset -= kDoubleSize; + sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); + } + } +} + + +void MacroAssembler::MultiPushReversedFPU(RegList regs) { + CpuFeatures::Scope scope(FPU); + int16_t num_to_push = NumberOfBitsSet(regs); + int16_t stack_offset = num_to_push * kDoubleSize; + + Subu(sp, sp, Operand(stack_offset)); + for (int16_t i = 0; i < kNumRegisters; i++) { + if ((regs & (1 << i)) != 0) { + stack_offset -= kDoubleSize; + sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); + } + } +} + + +void MacroAssembler::MultiPopFPU(RegList regs) { + CpuFeatures::Scope scope(FPU); + int16_t stack_offset = 0; + + for (int16_t i = 0; i < kNumRegisters; i++) { + if ((regs & (1 << i)) != 0) { + ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); + stack_offset += kDoubleSize; + } + } + addiu(sp, sp, stack_offset); +} + + +void MacroAssembler::MultiPopReversedFPU(RegList regs) { + CpuFeatures::Scope scope(FPU); + int16_t stack_offset = 0; + + for (int16_t i = kNumRegisters; i > 0; i--) { + if ((regs & (1 << i)) != 0) { + ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset)); + stack_offset += kDoubleSize; + } + } + addiu(sp, sp, stack_offset); } @@ -1557,12 +1619,14 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, b(offset); break; case eq: + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); offset = shifted_branch_offset(L, false); beq(rs, r2, offset); break; case ne: + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); offset = shifted_branch_offset(L, false); @@ -1574,6 +1638,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, offset = shifted_branch_offset(L, false); bgtz(rs, offset); } else { + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); slt(scratch, r2, rs); @@ -1590,6 +1655,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, offset = shifted_branch_offset(L, false); beq(scratch, zero_reg, offset); } else { + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); slt(scratch, rs, r2); @@ -1606,6 +1672,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, offset = shifted_branch_offset(L, false); bne(scratch, zero_reg, offset); } else { + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); slt(scratch, rs, r2); @@ -1618,6 +1685,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, offset = shifted_branch_offset(L, false); blez(rs, offset); } else { + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); slt(scratch, r2, rs); @@ -1631,6 +1699,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, offset = shifted_branch_offset(L, false); bgtz(rs, offset); } else { + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); sltu(scratch, r2, rs); @@ -1647,6 +1716,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, offset = shifted_branch_offset(L, false); beq(scratch, zero_reg, offset); } else { + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); sltu(scratch, rs, r2); @@ -1663,6 +1733,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, offset = shifted_branch_offset(L, false); bne(scratch, zero_reg, offset); } else { + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); sltu(scratch, rs, r2); @@ -1675,6 +1746,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, offset = shifted_branch_offset(L, false); b(offset); } else { + ASSERT(!scratch.is(rs)); r2 = scratch; li(r2, rt); sltu(scratch, r2, rs); @@ -2743,6 +2815,46 @@ void MacroAssembler::AllocateAsciiConsString(Register result, } +void MacroAssembler::AllocateTwoByteSlicedString(Register result, + Register length, + Register scratch1, + Register scratch2, + Label* gc_required) { + AllocateInNewSpace(SlicedString::kSize, + result, + scratch1, + scratch2, + gc_required, + TAG_OBJECT); + + InitializeNewString(result, + length, + Heap::kSlicedStringMapRootIndex, + scratch1, + scratch2); +} + + +void MacroAssembler::AllocateAsciiSlicedString(Register result, + Register length, + Register scratch1, + Register scratch2, + Label* gc_required) { + AllocateInNewSpace(SlicedString::kSize, + result, + scratch1, + scratch2, + gc_required, + TAG_OBJECT); + + InitializeNewString(result, + length, + Heap::kSlicedAsciiStringMapRootIndex, + scratch1, + scratch2); +} + + // Allocates a heap number or jumps to the label if the young space is full and // a scavenge is needed. void MacroAssembler::AllocateHeapNumber(Register result, @@ -4141,11 +4253,9 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { // mips, even though those argument slots are not normally used. // Remaining arguments are pushed on the stack, above (higher address than) // the argument slots. - ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0); int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? 0 : num_arguments - kRegisterPassedArguments) + - (StandardFrameConstants::kCArgsSlotsSize / - kPointerSize); + kCArgSlotCount; if (frame_alignment > kPointerSize) { // Make stack end at alignment and make room for num_arguments - 4 words // and the original value of sp. @@ -4217,11 +4327,9 @@ void MacroAssembler::CallCFunctionHelper(Register function, Call(function); - ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0); int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? 0 : num_arguments - kRegisterPassedArguments) + - (StandardFrameConstants::kCArgsSlotsSize / - kPointerSize); + kCArgSlotCount; if (OS::ActivationFrameAlignment() > kPointerSize) { lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); diff --git a/deps/v8/src/mips/macro-assembler-mips.h b/deps/v8/src/mips/macro-assembler-mips.h index 0fcf6f1d85..5dd012e93e 100644 --- a/deps/v8/src/mips/macro-assembler-mips.h +++ b/deps/v8/src/mips/macro-assembler-mips.h @@ -362,6 +362,16 @@ class MacroAssembler: public Assembler { Register scratch1, Register scratch2, Label* gc_required); + void AllocateTwoByteSlicedString(Register result, + Register length, + Register scratch1, + Register scratch2, + Label* gc_required); + void AllocateAsciiSlicedString(Register result, + Register length, + Register scratch1, + Register scratch2, + Label* gc_required); // Allocates a heap number or jumps to the gc_required label if the young // space is full and a scavenge is needed. All registers are clobbered also @@ -442,6 +452,9 @@ class MacroAssembler: public Assembler { void MultiPush(RegList regs); void MultiPushReversed(RegList regs); + void MultiPushFPU(RegList regs); + void MultiPushReversedFPU(RegList regs); + // Lower case push() for compatibility with arch-independent code. void push(Register src) { Addu(sp, sp, Operand(-kPointerSize)); @@ -487,6 +500,9 @@ class MacroAssembler: public Assembler { void MultiPop(RegList regs); void MultiPopReversed(RegList regs); + void MultiPopFPU(RegList regs); + void MultiPopReversedFPU(RegList regs); + // Lower case pop() for compatibility with arch-independent code. void pop(Register dst) { lw(dst, MemOperand(sp, 0)); @@ -1197,10 +1213,9 @@ static inline MemOperand FieldMemOperand(Register object, int offset) { // Generate a MemOperand for storing arguments 5..N on the stack // when calling CallCFunction(). static inline MemOperand CFunctionArgumentOperand(int index) { - ASSERT(index > StandardFrameConstants::kCArgSlotCount); + ASSERT(index > kCArgSlotCount); // Argument 5 takes the slot just past the four Arg-slots. - int offset = - (index - 5) * kPointerSize + StandardFrameConstants::kCArgsSlotsSize; + int offset = (index - 5) * kPointerSize + kCArgsSlotsSize; return MemOperand(sp, offset); } diff --git a/deps/v8/src/mips/regexp-macro-assembler-mips.cc b/deps/v8/src/mips/regexp-macro-assembler-mips.cc index 45d3963972..63e836f22f 100644 --- a/deps/v8/src/mips/regexp-macro-assembler-mips.cc +++ b/deps/v8/src/mips/regexp-macro-assembler-mips.cc @@ -1050,7 +1050,7 @@ int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address, MaybeObject* result = Execution::HandleStackGuardInterrupt(); if (*code_handle != re_code) { // Return address no longer valid. - int delta = *code_handle - re_code; + int delta = code_handle->address() - re_code->address(); // Overwrite the return address on the stack. *return_address += delta; } diff --git a/deps/v8/src/mips/simulator-mips.cc b/deps/v8/src/mips/simulator-mips.cc index 30e12e75b1..7628237037 100644 --- a/deps/v8/src/mips/simulator-mips.cc +++ b/deps/v8/src/mips/simulator-mips.cc @@ -1409,20 +1409,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { int32_t arg1 = get_register(a1); int32_t arg2 = get_register(a2); int32_t arg3 = get_register(a3); - int32_t arg4 = 0; - int32_t arg5 = 0; - // Need to check if sp is valid before assigning arg4, arg5. - // This is a fix for cctest test-api/CatchStackOverflow which causes - // the stack to overflow. For some reason arm doesn't need this - // stack check here. int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp)); - int32_t* stack = reinterpret_cast<int32_t*>(stack_); - if (stack_pointer >= stack && stack_pointer < stack + stack_size_ - 5) { - // Args 4 and 5 are on the stack after the reserved space for args 0..3. - arg4 = stack_pointer[4]; - arg5 = stack_pointer[5]; - } + // Args 4 and 5 are on the stack after the reserved space for args 0..3. + int32_t arg4 = stack_pointer[4]; + int32_t arg5 = stack_pointer[5]; bool fp_call = (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) || @@ -2725,7 +2716,7 @@ int32_t Simulator::Call(byte* entry, int argument_count, ...) { // Store remaining arguments on stack, from low to high memory. intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); for (int i = 4; i < argument_count; i++) { - stack_argument[i - 4 + kArgsSlotsNum] = va_arg(parameters, int32_t); + stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t); } va_end(parameters); set_register(sp, entry_stack); diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc index c17a658d1d..d0f06e4710 100644 --- a/deps/v8/src/mips/stub-cache-mips.cc +++ b/deps/v8/src/mips/stub-cache-mips.cc @@ -3501,7 +3501,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // We are not untagging smi key and instead work with it // as if it was premultiplied by 2. - ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); + STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); Register value = a2; switch (elements_kind) { @@ -4213,7 +4213,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { // Load the result and make sure it's not the hole. __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize); __ Addu(t0, t0, a3); __ lw(t0, MemOperand(t0)); @@ -4344,7 +4344,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, __ Addu(scratch, elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize); __ Addu(scratch3, scratch2, scratch); __ sw(value_reg, MemOperand(scratch3)); diff --git a/deps/v8/src/mksnapshot.cc b/deps/v8/src/mksnapshot.cc index 4f5fe96a90..a791dbba28 100644 --- a/deps/v8/src/mksnapshot.cc +++ b/deps/v8/src/mksnapshot.cc @@ -29,8 +29,6 @@ #include <bzlib.h> #endif #include <signal.h> -#include <string> -#include <map> #include "v8.h" @@ -86,16 +84,6 @@ class CounterCollection { }; -// We statically allocate a set of local counters to be used if we -// don't want to store the stats in a memory-mapped file -static CounterCollection local_counters; - - -typedef std::map<std::string, int*> CounterMap; -typedef std::map<std::string, int*>::iterator CounterMapIterator; -static CounterMap counter_table_; - - class Compressor { public: virtual ~Compressor() {} diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index b4c6a3a03e..588b0f63a8 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -171,7 +171,7 @@ bool Object::IsSymbol() { // Because the symbol tag is non-zero and no non-string types have the // symbol bit set we can test for symbols with a very simple test // operation. - ASSERT(kSymbolTag != 0); + STATIC_ASSERT(kSymbolTag != 0); ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE); return (type & kIsSymbolMask) != 0; } @@ -256,7 +256,7 @@ StringShape::StringShape(InstanceType t) bool StringShape::IsSymbol() { ASSERT(valid()); - ASSERT(kSymbolTag != 0); + STATIC_ASSERT(kSymbolTag != 0); return (type_ & kIsSymbolMask) != 0; } @@ -1749,9 +1749,15 @@ bool FixedDoubleArray::is_the_hole(int index) { void FixedDoubleArray::Initialize(FixedDoubleArray* from) { int old_length = from->length(); ASSERT(old_length < length()); - OS::MemCopy(FIELD_ADDR(this, kHeaderSize), - FIELD_ADDR(from, kHeaderSize), - old_length * kDoubleSize); + if (old_length * kDoubleSize >= OS::kMinComplexMemCopy) { + OS::MemCopy(FIELD_ADDR(this, kHeaderSize), + FIELD_ADDR(from, kHeaderSize), + old_length * kDoubleSize); + } else { + for (int i = 0; i < old_length; ++i) { + set(i, from->get_scalar(i)); + } + } int offset = kHeaderSize + old_length * kDoubleSize; for (int current = from->length(); current < length(); ++current) { WRITE_DOUBLE_FIELD(this, offset, hole_nan_as_double()); diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 0a9598cfd8..76b57d86aa 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -7009,7 +7009,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { JSFunction* function = JSFunction::cast(LiteralArray()->get(function_id)); unsigned height = iterator.Next(); - PrintF(out, "{ast_id=%d, \nfunction=", ast_id); + PrintF(out, "{ast_id=%d, function=", ast_id); function->PrintName(out); PrintF(out, ", height=%u}", height); break; diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 6c8888bf14..53ba981c85 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -496,6 +496,11 @@ STATIC_ASSERT( STATIC_ASSERT( (kSlicedStringTag & kIsIndirectStringMask) == kIsIndirectStringTag); +// Use this mask to distinguish between cons and slice only after making +// sure that the string is one of the two (an indirect string). +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. const uint32_t kAsciiDataHintMask = 0x08; diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 844dd7060c..056133449c 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -30,6 +30,7 @@ #include "api.h" #include "ast-inl.h" #include "bootstrapper.h" +#include "char-predicates-inl.h" #include "codegen.h" #include "compiler.h" #include "func-name-inferrer.h" @@ -532,7 +533,7 @@ LexicalScope::LexicalScope(Parser* parser, Scope* scope, Isolate* isolate) parser->top_scope_ = scope; parser->lexical_scope_ = this; parser->with_nesting_level_ = 0; - isolate->set_ast_node_id(AstNode::kFunctionEntryId + 1); + isolate->set_ast_node_id(AstNode::kDeclarationsId + 1); } @@ -647,6 +648,11 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source, if (ok && top_scope_->is_strict_mode()) { CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok); } + + if (ok && harmony_block_scoping_) { + CheckConflictingVarDeclarations(scope, &ok); + } + if (ok) { result = new(zone()) FunctionLiteral( isolate(), @@ -1343,14 +1349,32 @@ VariableProxy* Parser::Declare(Handle<String> name, // Declare the name. var = declaration_scope->DeclareLocal(name, mode); } else { - // The name was declared before; check for conflicting re-declarations. - // We have a conflict if either of the declarations is not a var. There - // is similar code in runtime.cc in the Declare functions. + // The name was declared in this scope before; check for conflicting + // re-declarations. We have a conflict if either of the declarations is + // not a var. There is similar code in runtime.cc in the Declare + // functions. The function CheckNonConflictingScope checks for conflicting + // var and let bindings from different scopes whereas this is a check for + // conflicting declarations within the same scope. This check also covers + // + // function () { let x; { var x; } } + // + // because the var declaration is hoisted to the function scope where 'x' + // is already bound. if ((mode != Variable::VAR) || (var->mode() != Variable::VAR)) { // We only have vars, consts and lets in declarations. ASSERT(var->mode() == Variable::VAR || var->mode() == Variable::CONST || var->mode() == Variable::LET); + if (harmony_block_scoping_) { + // In harmony mode we treat re-declarations as early errors. See + // ES5 16 for a definition of early errors. + SmartPointer<char> c_string = name->ToCString(DISALLOW_NULLS); + const char* elms[2] = { "Variable", *c_string }; + Vector<const char*> args(elms, 2); + ReportMessage("redeclaration", args); + *ok = false; + return NULL; + } const char* type = (var->mode() == Variable::VAR) ? "var" : (var->mode() == Variable::CONST) ? "const" : "let"; Handle<String> type_string = @@ -1379,8 +1403,10 @@ VariableProxy* Parser::Declare(Handle<String> name, // semantic issue as long as we keep the source order, but it may be // a performance issue since it may lead to repeated // Runtime::DeclareContextSlot() calls. - VariableProxy* proxy = declaration_scope->NewUnresolved(name, false); - declaration_scope->AddDeclaration(new(zone()) Declaration(proxy, mode, fun)); + VariableProxy* proxy = declaration_scope->NewUnresolved( + name, false, scanner().location().beg_pos); + declaration_scope->AddDeclaration( + new(zone()) Declaration(proxy, mode, fun, top_scope_)); // For global const variables we bind the proxy to a variable. if (mode == Variable::CONST && declaration_scope->is_global_scope()) { @@ -1534,9 +1560,6 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { Scope* block_scope = NewScope(top_scope_, Scope::BLOCK_SCOPE, inside_with()); - body->set_block_scope(block_scope); - block_scope->DeclareLocal(isolate()->factory()->block_scope_symbol(), - Variable::VAR); if (top_scope_->is_strict_mode()) { block_scope->EnableStrictMode(); } @@ -1559,21 +1582,11 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { } } Expect(Token::RBRACE, CHECK_OK); - - // Create exit block. - Block* exit = new(zone()) Block(isolate(), NULL, 1, false); - exit->AddStatement(new(zone()) ExitContextStatement()); - - // Create a try-finally statement. - TryFinallyStatement* try_finally = - new(zone()) TryFinallyStatement(body, exit); - try_finally->set_escaping_targets(collector.targets()); top_scope_ = saved_scope; - // Create a result block. - Block* result = new(zone()) Block(isolate(), NULL, 1, false); - result->AddStatement(try_finally); - return result; + block_scope = block_scope->FinalizeBlockScope(); + body->set_block_scope(block_scope); + return body; } @@ -1609,7 +1622,13 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] Variable::Mode mode = Variable::VAR; + // True if the binding needs initialization. 'let' and 'const' declared + // bindings are created uninitialized by their declaration nodes and + // need initialization. 'var' declared bindings are always initialized + // immediately by their declaration nodes. + bool needs_init = false; bool is_const = false; + Token::Value init_op = Token::INIT_VAR; if (peek() == Token::VAR) { Consume(Token::VAR); } else if (peek() == Token::CONST) { @@ -1621,6 +1640,8 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, } mode = Variable::CONST; is_const = true; + needs_init = true; + init_op = Token::INIT_CONST; } else if (peek() == Token::LET) { Consume(Token::LET); if (var_context != kSourceElement && @@ -1631,6 +1652,8 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, return NULL; } mode = Variable::LET; + needs_init = true; + init_op = Token::INIT_LET; } else { UNREACHABLE(); // by current callers } @@ -1732,9 +1755,8 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, } } - // Make sure that 'const c' actually initializes 'c' to undefined - // even though it seems like a stupid thing to do. - if (value == NULL && is_const) { + // Make sure that 'const x' and 'let x' initialize 'x' to undefined. + if (value == NULL && needs_init) { value = GetLiteralUndefined(); } @@ -1811,23 +1833,25 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, block->AddStatement(new(zone()) ExpressionStatement(initialize)); } - // Add an assignment node to the initialization statement block if - // we still have a pending initialization value. We must distinguish - // between variables and constants: Variable initializations are simply + // Add an assignment node to the initialization statement block if we still + // have a pending initialization value. We must distinguish between + // different kinds of declarations: 'var' initializations are simply // assignments (with all the consequences if they are inside a 'with' // statement - they may change a 'with' object property). Constant // initializations always assign to the declared constant which is // always at the function scope level. This is only relevant for // dynamically looked-up variables and constants (the start context // for constant lookups is always the function context, while it is - // the top context for variables). Sigh... + // the top context for var declared variables). Sigh... + // For 'let' declared variables the initialization is in the same scope + // as the declaration. Thus dynamic lookups are unnecessary even if the + // block scope is inside a with. if (value != NULL) { - Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR); - bool in_with = is_const ? false : inside_with(); + bool in_with = mode == Variable::VAR ? inside_with() : false; VariableProxy* proxy = initialization_scope->NewUnresolved(name, in_with); Assignment* assignment = - new(zone()) Assignment(isolate(), op, proxy, value, position); + new(zone()) Assignment(isolate(), init_op, proxy, value, position); if (block) { block->AddStatement(new(zone()) ExpressionStatement(assignment)); } @@ -2199,7 +2223,9 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { if (top_scope_->is_strict_mode()) { catch_scope->EnableStrictMode(); } - catch_variable = catch_scope->DeclareLocal(name, Variable::VAR); + Variable::Mode mode = harmony_block_scoping_ + ? Variable::LET : Variable::VAR; + catch_variable = catch_scope->DeclareLocal(name, mode); catch_block = new(zone()) Block(isolate(), NULL, 2, false); Scope* saved_scope = top_scope_; @@ -3728,7 +3754,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, reserved_loc = scanner().location(); } - top_scope_->DeclareParameter(param_name); + top_scope_->DeclareParameter(param_name, + harmony_block_scoping_ + ? Variable::LET + : Variable::VAR); num_parameters++; if (num_parameters > kMaxNumFunctionParameters) { ReportMessageAt(scanner().location(), "too_many_parameters", @@ -3855,6 +3884,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, } } + if (harmony_block_scoping_) { + CheckConflictingVarDeclarations(scope, CHECK_OK); + } + FunctionLiteral* function_literal = new(zone()) FunctionLiteral(isolate(), function_name, @@ -4061,6 +4094,25 @@ void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { } +void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) { + Declaration* decl = scope->CheckConflictingVarDeclarations(); + if (decl != NULL) { + // In harmony mode we treat conflicting variable bindinds as early + // errors. See ES5 16 for a definition of early errors. + Handle<String> name = decl->proxy()->name(); + SmartPointer<char> c_string = name->ToCString(DISALLOW_NULLS); + const char* elms[2] = { "Variable", *c_string }; + Vector<const char*> args(elms, 2); + int position = decl->proxy()->position(); + Scanner::Location location = position == RelocInfo::kNoPosition + ? Scanner::Location::invalid() + : Scanner::Location(position, position + 1); + ReportMessageAt(location, "redeclaration", args); + *ok = false; + } +} + + // This function reads an identifier name and determines whether or not it // is 'get' or 'set'. Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get, diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h index 686dac85af..381ff27143 100644 --- a/deps/v8/src/parser.h +++ b/deps/v8/src/parser.h @@ -645,6 +645,17 @@ class Parser { // Strict mode octal literal validation. void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); + // For harmony block scoping mode: Check if the scope has conflicting var/let + // declarations from different scopes. It covers for example + // + // function f() { { { var x; } let x; } } + // function g() { { var x; let x; } } + // + // The var declarations are hoisted to the function scope, but originate from + // a scope where the name has also been let bound or the var declaration is + // hoisted over such a scope. + void CheckConflictingVarDeclarations(Scope* scope, bool* ok); + // Parser support VariableProxy* Declare(Handle<String> name, Variable::Mode mode, FunctionLiteral* fun, diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc index 362bf47cc1..b152dae9a6 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -130,13 +130,7 @@ void OS::Setup() { uint64_t OS::CpuFeaturesImpliedByPlatform() { -#if(defined(__mips_hard_float) && __mips_hard_float != 0) - // Here gcc is telling us that we are on an MIPS and gcc is assuming that we - // have FPU instructions. If gcc can assume it then so can we. - return 1u << FPU; -#else return 0; // Linux runs on anything. -#endif } diff --git a/deps/v8/src/prettyprinter.cc b/deps/v8/src/prettyprinter.cc index b03429341e..2a41592331 100644 --- a/deps/v8/src/prettyprinter.cc +++ b/deps/v8/src/prettyprinter.cc @@ -284,28 +284,6 @@ void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) { } -void PrettyPrinter::VisitSlot(Slot* node) { - switch (node->type()) { - case Slot::PARAMETER: - Print("parameter[%d]", node->index()); - break; - case Slot::LOCAL: - Print("local[%d]", node->index()); - break; - case Slot::CONTEXT: - Print("context[%d]", node->index()); - break; - case Slot::LOOKUP: - Print("lookup["); - PrintLiteral(node->var()->name(), false); - Print("]"); - break; - default: - UNREACHABLE(); - } -} - - void PrettyPrinter::VisitVariableProxy(VariableProxy* node) { PrintLiteral(node->name(), false); } @@ -751,7 +729,7 @@ void AstPrinter::VisitDeclaration(Declaration* node) { if (node->fun() == NULL) { // var or const declarations PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()), - node->proxy()->AsVariable(), + node->proxy()->var(), node->proxy()->name()); } else { // function declarations @@ -959,19 +937,26 @@ void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) { } -void AstPrinter::VisitSlot(Slot* node) { - PrintIndented("SLOT "); - PrettyPrinter::VisitSlot(node); - Print("\n"); -} - - void AstPrinter::VisitVariableProxy(VariableProxy* node) { - PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name()); Variable* var = node->var(); - if (var != NULL && var->rewrite() != NULL) { - IndentedScope indent(this); - Visit(var->rewrite()); + PrintLiteralWithModeIndented("VAR PROXY", var, node->name()); + { IndentedScope indent(this); + switch (var->location()) { + case Variable::UNALLOCATED: + break; + case Variable::PARAMETER: + Print("parameter[%d]", var->index()); + break; + case Variable::LOCAL: + Print("local[%d]", var->index()); + break; + case Variable::CONTEXT: + Print("context[%d]", var->index()); + break; + case Variable::LOOKUP: + Print("lookup"); + break; + } } } @@ -1287,39 +1272,32 @@ void JsonAstBuilder::VisitConditional(Conditional* expr) { } -void JsonAstBuilder::VisitSlot(Slot* expr) { - TagScope tag(this, "Slot"); +void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) { + TagScope tag(this, "Variable"); { AttributesScope attributes(this); - switch (expr->type()) { - case Slot::PARAMETER: - AddAttribute("type", "PARAMETER"); + Variable* var = expr->var(); + AddAttribute("name", var->name()); + switch (var->location()) { + case Variable::UNALLOCATED: + AddAttribute("location", "UNALLOCATED"); break; - case Slot::LOCAL: - AddAttribute("type", "LOCAL"); + case Variable::PARAMETER: + AddAttribute("location", "PARAMETER"); + AddAttribute("index", var->index()); break; - case Slot::CONTEXT: - AddAttribute("type", "CONTEXT"); + case Variable::LOCAL: + AddAttribute("location", "LOCAL"); + AddAttribute("index", var->index()); break; - case Slot::LOOKUP: - AddAttribute("type", "LOOKUP"); + case Variable::CONTEXT: + AddAttribute("location", "CONTEXT"); + AddAttribute("index", var->index()); + break; + case Variable::LOOKUP: + AddAttribute("location", "LOOKUP"); break; } - AddAttribute("index", expr->index()); - } -} - - -void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) { - if (expr->var()->rewrite() == NULL) { - TagScope tag(this, "VariableProxy"); - { - AttributesScope attributes(this); - AddAttribute("name", expr->name()); - AddAttribute("mode", Variable::Mode2String(expr->var()->mode())); - } - } else { - Visit(expr->var()->rewrite()); } } diff --git a/deps/v8/src/prettyprinter.h b/deps/v8/src/prettyprinter.h index 080081dd30..a26c48e490 100644 --- a/deps/v8/src/prettyprinter.h +++ b/deps/v8/src/prettyprinter.h @@ -52,7 +52,6 @@ class PrettyPrinter: public AstVisitor { // Print a node to stdout. static void PrintOut(AstNode* node); - virtual void VisitSlot(Slot* node); // Individual nodes #define DECLARE_VISIT(type) virtual void Visit##type(type* node); AST_NODE_LIST(DECLARE_VISIT) @@ -87,7 +86,6 @@ class AstPrinter: public PrettyPrinter { const char* PrintProgram(FunctionLiteral* program); // Individual nodes - virtual void VisitSlot(Slot* node); #define DECLARE_VISIT(type) virtual void Visit##type(type* node); AST_NODE_LIST(DECLARE_VISIT) #undef DECLARE_VISIT @@ -163,7 +161,6 @@ class JsonAstBuilder: public PrettyPrinter { void AddAttribute(const char* name, bool value); // AST node visit functions. - virtual void VisitSlot(Slot* node); #define DECLARE_VISIT(type) virtual void Visit##type(type* node); AST_NODE_LIST(DECLARE_VISIT) #undef DECLARE_VISIT diff --git a/deps/v8/src/profile-generator.cc b/deps/v8/src/profile-generator.cc index db9f8928de..74dfbf445c 100644 --- a/deps/v8/src/profile-generator.cc +++ b/deps/v8/src/profile-generator.cc @@ -1195,12 +1195,9 @@ void HeapSnapshot::AllocateEntries(int entries_count, int children_count, int retainers_count) { ASSERT(raw_entries_ == NULL); - raw_entries_ = NewArray<char>( - HeapEntry::EntriesSize(entries_count, children_count, retainers_count)); -#ifdef DEBUG raw_entries_size_ = HeapEntry::EntriesSize(entries_count, children_count, retainers_count); -#endif + raw_entries_ = NewArray<char>(raw_entries_size_); } @@ -2984,10 +2981,19 @@ class OutputStreamWriter { bool aborted_; }; +const int HeapSnapshotJSONSerializer::kMaxSerializableSnapshotRawSize = + 256 * MB; + void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { ASSERT(writer_ == NULL); writer_ = new OutputStreamWriter(stream); + HeapSnapshot* original_snapshot = NULL; + if (snapshot_->raw_entries_size() >= kMaxSerializableSnapshotRawSize) { + // The snapshot is too big. Serialize a fake snapshot. + original_snapshot = snapshot_; + snapshot_ = CreateFakeSnapshot(); + } // Since nodes graph is cyclic, we need the first pass to enumerate // them. Strings can be serialized in one pass. EnumerateNodes(); @@ -2995,6 +3001,26 @@ void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { delete writer_; writer_ = NULL; + + if (original_snapshot != NULL) { + delete snapshot_; + snapshot_ = original_snapshot; + } +} + + +HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() { + HeapSnapshot* result = new HeapSnapshot(snapshot_->collection(), + HeapSnapshot::kFull, + snapshot_->title(), + snapshot_->uid()); + result->AllocateEntries(2, 1, 0); + HeapEntry* root = result->AddRootEntry(1); + HeapEntry* message = result->AddEntry( + HeapEntry::kString, "The snapshot is too big", 0, 4, 0, 0); + root->SetUnidirElementReference(0, 1, message); + result->SetDominatorsToSelf(); + return result; } diff --git a/deps/v8/src/profile-generator.h b/deps/v8/src/profile-generator.h index 9ab44a1e21..6bada36d57 100644 --- a/deps/v8/src/profile-generator.h +++ b/deps/v8/src/profile-generator.h @@ -654,6 +654,7 @@ class HeapSnapshot { HeapEntry* gc_roots() { return gc_roots_entry_; } HeapEntry* natives_root() { return natives_root_entry_; } List<HeapEntry*>* entries() { return &entries_; } + int raw_entries_size() { return raw_entries_size_; } void AllocateEntries( int entries_count, int children_count, int retainers_count); @@ -689,9 +690,7 @@ class HeapSnapshot { char* raw_entries_; List<HeapEntry*> entries_; bool entries_sorted_; -#ifdef DEBUG int raw_entries_size_; -#endif friend class HeapSnapshotTester; @@ -1097,6 +1096,7 @@ class HeapSnapshotJSONSerializer { } void EnumerateNodes(); + HeapSnapshot* CreateFakeSnapshot(); int GetNodeId(HeapEntry* entry); int GetStringId(const char* s); void SerializeEdge(HeapGraphEdge* edge); @@ -1108,6 +1108,8 @@ class HeapSnapshotJSONSerializer { void SerializeStrings(); void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries); + static const int kMaxSerializableSnapshotRawSize; + HeapSnapshot* snapshot_; HashMap nodes_; HashMap strings_; diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js index a7f42d59c2..38d4496153 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -405,7 +405,8 @@ var lastMatchInfoOverride = null; // ------------------------------------------------------------------- -function SetupRegExp() { +function SetUpRegExp() { + %CheckIsBootstrapping(); %FunctionSetInstanceClassName($RegExp, 'RegExp'); %FunctionSetPrototype($RegExp, new $Object()); %SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM); @@ -484,5 +485,4 @@ function SetupRegExp() { } } - -SetupRegExp(); +SetUpRegExp(); diff --git a/deps/v8/src/runtime-profiler.cc b/deps/v8/src/runtime-profiler.cc index 917f6d0d66..26d8846107 100644 --- a/deps/v8/src/runtime-profiler.cc +++ b/deps/v8/src/runtime-profiler.cc @@ -115,10 +115,8 @@ void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) { } SharedFunctionInfo* shared = function->shared(); - // If the code is not optimizable or references context slots, don't try OSR. - if (!shared->code()->optimizable() || !shared->allows_lazy_compilation()) { - return; - } + // If the code is not optimizable, don't try OSR. + if (!shared->code()->optimizable()) return; // We are not prepared to do OSR for a function that already has an // allocated arguments object. The optimized code would bypass it for diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 802fd6845d..3e07b99823 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -32,6 +32,7 @@ #include "accessors.h" #include "api.h" #include "arguments.h" +#include "bootstrapper.h" #include "codegen.h" #include "compilation-cache.h" #include "compiler.h" @@ -1149,22 +1150,14 @@ static Failure* ThrowRedeclarationError(Isolate* isolate, RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { - ASSERT(args.length() == 4); + ASSERT(args.length() == 3); HandleScope scope(isolate); Handle<GlobalObject> global = Handle<GlobalObject>( isolate->context()->global()); Handle<Context> context = args.at<Context>(0); CONVERT_ARG_CHECKED(FixedArray, pairs, 1); - bool is_eval = args.smi_at(2) == 1; - StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3)); - ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); - - // Compute the property attributes. According to ECMA-262, section - // 13, page 71, the property must be read-only and - // non-deletable. However, neither SpiderMonkey nor KJS creates the - // property as read-only, so we don't either. - PropertyAttributes base = is_eval ? NONE : DONT_DELETE; + CONVERT_SMI_ARG_CHECKED(flags, 2); // Traverse the name/value pairs and set the properties. int length = pairs->length(); @@ -1177,7 +1170,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { // assign to it when evaluating the assignment for "const x = // <expr>" the initial value is the hole. bool is_const_property = value->IsTheHole(); - + bool is_function_declaration = false; if (value->IsUndefined() || is_const_property) { // Lookup the property in the global object, and don't set the // value of the variable if the property is already there. @@ -1226,6 +1219,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { } } } else { + is_function_declaration = true; // Copy the function and update its context. Use it as value. Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(value); @@ -1239,10 +1233,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { LookupResult lookup; global->LocalLookup(*name, &lookup); - PropertyAttributes attributes = is_const_property - ? static_cast<PropertyAttributes>(base | READ_ONLY) - : base; - // There's a local property that we need to overwrite because // we're either declaring a function or there's an interceptor // that claims the property is absent. @@ -1257,6 +1247,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { return ThrowRedeclarationError(isolate, type, name); } + // Compute the property attributes. According to ECMA-262, section + // 13, page 71, the property must be read-only and + // non-deletable. However, neither SpiderMonkey nor KJS creates the + // property as read-only, so we don't either. + int attr = NONE; + if ((flags & kDeclareGlobalsEvalFlag) == 0) { + attr |= DONT_DELETE; + } + bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0; + if (is_const_property || (is_native && is_function_declaration)) { + attr |= READ_ONLY; + } + // Safari does not allow the invocation of callback setters for // function declarations. To mimic this behavior, we do not allow // the invocation of setters for function values. This makes a @@ -1267,20 +1270,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { if (value->IsJSFunction()) { // Do not change DONT_DELETE to false from true. if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) { - attributes = static_cast<PropertyAttributes>( - attributes | (lookup.GetAttributes() & DONT_DELETE)); + attr |= lookup.GetAttributes() & DONT_DELETE; } + PropertyAttributes attributes = static_cast<PropertyAttributes>(attr); + RETURN_IF_EMPTY_HANDLE(isolate, SetLocalPropertyIgnoreAttributes(global, name, value, attributes)); } else { + StrictModeFlag strict_mode = + ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode + : kNonStrictMode; RETURN_IF_EMPTY_HANDLE(isolate, SetProperty(global, name, value, - attributes, + static_cast<PropertyAttributes>(attr), strict_mode)); } } @@ -1306,8 +1313,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { int index; PropertyAttributes attributes; ContextLookupFlags flags = DONT_FOLLOW_CHAINS; + BindingFlags binding_flags; Handle<Object> holder = - context->Lookup(name, flags, &index, &attributes); + context->Lookup(name, flags, &index, &attributes, &binding_flags); if (attributes != ABSENT) { // The name was declared before; check for conflicting @@ -1594,8 +1602,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { int index; PropertyAttributes attributes; ContextLookupFlags flags = FOLLOW_CHAINS; + BindingFlags binding_flags; Handle<Object> holder = - context->Lookup(name, flags, &index, &attributes); + context->Lookup(name, flags, &index, &attributes, &binding_flags); // In most situations, the property introduced by the const // declaration should be present in the context extension object. @@ -2145,6 +2154,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) { RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { + RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -5974,6 +5984,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { int pattern_length = pattern->length(); RUNTIME_ASSERT(pattern_length > 0); + if (limit == 0xffffffffu) { + Handle<Object> cached_answer(StringSplitCache::Lookup( + isolate->heap()->string_split_cache(), + *subject, + *pattern)); + if (*cached_answer != Smi::FromInt(0)) { + Handle<JSArray> result = + isolate->factory()->NewJSArrayWithElements( + Handle<FixedArray>::cast(cached_answer)); + return *result; + } + } + // The limit can be very large (0xffffffffu), but since the pattern // isn't empty, we can never create more parts than ~half the length // of the subject. @@ -6067,6 +6090,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { part_start = part_end + pattern_length; } + if (limit == 0xffffffffu) { + StringSplitCache::Enter(isolate->heap(), + isolate->heap()->string_split_cache(), + *subject, + *pattern, + *elements); + } + return *result; } @@ -8248,6 +8279,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) { + RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); + return isolate->heap()->undefined_value(); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -8386,7 +8423,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { int index; PropertyAttributes attributes; ContextLookupFlags flags = FOLLOW_CHAINS; - Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); + BindingFlags binding_flags; + Handle<Object> holder = context->Lookup(name, + flags, + &index, + &attributes, + &binding_flags); // If the slot was not found the result is true. if (holder.is_null()) { @@ -8488,7 +8530,12 @@ static ObjectPair LoadContextSlotHelper(Arguments args, int index; PropertyAttributes attributes; ContextLookupFlags flags = FOLLOW_CHAINS; - Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); + BindingFlags binding_flags; + Handle<Object> holder = context->Lookup(name, + flags, + &index, + &attributes, + &binding_flags); // If the index is non-negative, the slot has been found in a local // variable or a parameter. Read it from the context object or the @@ -8504,7 +8551,17 @@ static ObjectPair LoadContextSlotHelper(Arguments args, MaybeObject* value = (holder->IsContext()) ? Context::cast(*holder)->get(index) : JSObject::cast(*holder)->GetElement(index); - return MakePair(Unhole(isolate->heap(), value, attributes), *receiver); + // Check for uninitialized bindings. + if (holder->IsContext() && + binding_flags == MUTABLE_CHECK_INITIALIZED && + value->IsTheHole()) { + Handle<Object> reference_error = + isolate->factory()->NewReferenceError("not_defined", + HandleVector(&name, 1)); + return MakePair(isolate->Throw(*reference_error), NULL); + } else { + return MakePair(Unhole(isolate->heap(), value, attributes), *receiver); + } } // If the holder is found, we read the property from it. @@ -8570,14 +8627,27 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { int index; PropertyAttributes attributes; ContextLookupFlags flags = FOLLOW_CHAINS; - Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); + BindingFlags binding_flags; + Handle<Object> holder = context->Lookup(name, + flags, + &index, + &attributes, + &binding_flags); if (index >= 0) { if (holder->IsContext()) { + Handle<Context> context = Handle<Context>::cast(holder); + if (binding_flags == MUTABLE_CHECK_INITIALIZED && + context->get(index)->IsTheHole()) { + Handle<Object> error = + isolate->factory()->NewReferenceError("not_defined", + HandleVector(&name, 1)); + return isolate->Throw(*error); + } // Ignore if read_only variable. if ((attributes & READ_ONLY) == 0) { // Context is a fixed array and set cannot fail. - Context::cast(*holder)->set(index, *value); + context->set(index, *value); } else if (strict_mode == kStrictMode) { // Setting read only property in strict mode. Handle<Object> error = @@ -9029,10 +9099,13 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { // it is bound in the global context. int index = -1; PropertyAttributes attributes = ABSENT; + BindingFlags binding_flags; while (true) { receiver = context->Lookup(isolate->factory()->eval_symbol(), FOLLOW_PROTOTYPE_CHAIN, - &index, &attributes); + &index, + &attributes, + &binding_flags); // Stop search when eval is found or when the global context is // reached. if (attributes != ABSENT || context->IsGlobalContext()) break; diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index 91a19dfd45..ddd529588b 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -79,6 +79,7 @@ namespace internal { F(PreventExtensions, 1, 1)\ \ /* Utilities */ \ + F(CheckIsBootstrapping, 0, 1) \ F(GetFunctionDelegate, 1, 1) \ F(GetConstructorDelegate, 1, 1) \ F(NewArgumentsFast, 3, 1) \ @@ -317,7 +318,7 @@ namespace internal { F(StoreContextSlot, 4, 1) \ \ /* Declarations and initialization */ \ - F(DeclareGlobals, 4, 1) \ + F(DeclareGlobals, 3, 1) \ F(DeclareContextSlot, 4, 1) \ F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \ F(InitializeConstGlobal, 2, 1) \ @@ -663,6 +664,16 @@ class Runtime : public AllStatic { static void PerformGC(Object* result); }; + +//--------------------------------------------------------------------------- +// Constants used by interface to runtime functions. + +enum kDeclareGlobalsFlags { + kDeclareGlobalsEvalFlag = 1 << 0, + kDeclareGlobalsStrictModeFlag = 1 << 1, + kDeclareGlobalsNativeFlag = 1 << 2 +}; + } } // namespace v8::internal #endif // V8_RUNTIME_H_ diff --git a/deps/v8/src/runtime.js b/deps/v8/src/runtime.js index 4b600df736..61deb9baa0 100644 --- a/deps/v8/src/runtime.js +++ b/deps/v8/src/runtime.js @@ -48,6 +48,7 @@ const $Number = global.Number; const $Function = global.Function; const $Boolean = global.Boolean; const $NaN = 0/0; +const builtins = this; // ECMA-262 Section 11.9.3. function EQUALS(y) { diff --git a/deps/v8/src/scanner-base.h b/deps/v8/src/scanner-base.h index a7062a34af..d68d240e90 100644 --- a/deps/v8/src/scanner-base.h +++ b/deps/v8/src/scanner-base.h @@ -362,7 +362,7 @@ class Scanner { // Call this after setting source_ to the input. void Init() { // Set c0_ (one character ahead) - ASSERT(kCharacterLookaheadBufferSize == 1); + STATIC_ASSERT(kCharacterLookaheadBufferSize == 1); Advance(); // Initialize current_ to not refer to a literal. current_.literal_chars = NULL; diff --git a/deps/v8/src/scanner.h b/deps/v8/src/scanner.h index e66dd60d84..6422ee8cab 100644 --- a/deps/v8/src/scanner.h +++ b/deps/v8/src/scanner.h @@ -28,8 +28,6 @@ #ifndef V8_SCANNER_H_ #define V8_SCANNER_H_ -#include "token.h" -#include "char-predicates-inl.h" #include "scanner-base.h" namespace v8 { diff --git a/deps/v8/src/scopeinfo.cc b/deps/v8/src/scopeinfo.cc index 0eacc83c79..ad31ca47c6 100644 --- a/deps/v8/src/scopeinfo.cc +++ b/deps/v8/src/scopeinfo.cc @@ -39,12 +39,8 @@ namespace internal { static int CompareLocal(Variable* const* v, Variable* const* w) { - Slot* s = (*v)->AsSlot(); - Slot* t = (*w)->AsSlot(); - // We may have rewritten parameters (that are in the arguments object) - // and which may have a NULL slot... - find a better solution... - int x = (s != NULL ? s->index() : 0); - int y = (t != NULL ? t->index() : 0); + int x = (*v)->index(); + int y = (*w)->index(); // Consider sorting them according to type as well? return x - y; } @@ -86,27 +82,24 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope) for (int i = 0; i < locals.length(); i++) { Variable* var = locals[i]; if (var->is_used()) { - Slot* slot = var->AsSlot(); - if (slot != NULL) { - switch (slot->type()) { - case Slot::PARAMETER: - // explicitly added to parameters_ above - ignore - break; - - case Slot::LOCAL: - ASSERT(stack_slots_.length() == slot->index()); - stack_slots_.Add(var->name()); - break; - - case Slot::CONTEXT: - heap_locals.Add(var); - break; - - case Slot::LOOKUP: - // This is currently not used. - UNREACHABLE(); - break; - } + switch (var->location()) { + case Variable::UNALLOCATED: + case Variable::PARAMETER: + break; + + case Variable::LOCAL: + ASSERT(stack_slots_.length() == var->index()); + stack_slots_.Add(var->name()); + break; + + case Variable::CONTEXT: + heap_locals.Add(var); + break; + + case Variable::LOOKUP: + // We don't expect lookup variables in the locals list. + UNREACHABLE(); + break; } } } @@ -115,9 +108,9 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope) if (scope->num_heap_slots() > 0) { // Add user-defined slots. for (int i = 0; i < heap_locals.length(); i++) { - ASSERT(heap_locals[i]->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS == + ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS == context_slots_.length()); - ASSERT(heap_locals[i]->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS == + ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS == context_modes_.length()); context_slots_.Add(heap_locals[i]->name()); context_modes_.Add(heap_locals[i]->mode()); @@ -131,18 +124,18 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope) // For now, this must happen at the very end because of the // ordering of the scope info slots and the respective slot indices. if (scope->is_function_scope()) { - Variable* var = scope->function(); - if (var != NULL && - var->is_used() && - var->AsSlot()->type() == Slot::CONTEXT) { - function_name_ = var->name(); + VariableProxy* proxy = scope->function(); + if (proxy != NULL && + proxy->var()->is_used() && + proxy->var()->IsContextSlot()) { + function_name_ = proxy->name(); // Note that we must not find the function name in the context slot // list - instead it must be handled separately in the // Contexts::Lookup() function. Thus record an empty symbol here so we // get the correct number of context slots. - ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS == + ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS == context_slots_.length()); - ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS == + ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS == context_modes_.length()); context_slots_.Add(FACTORY->empty_symbol()); context_modes_.Add(Variable::INTERNAL); diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc index ddde48a77c..4e87b25e11 100644 --- a/deps/v8/src/scopes.cc +++ b/deps/v8/src/scopes.cc @@ -31,7 +31,6 @@ #include "bootstrapper.h" #include "compiler.h" -#include "prettyprinter.h" #include "scopeinfo.h" #include "allocation-inl.h" @@ -314,7 +313,7 @@ void Scope::Initialize(bool inside_with) { Variable::VAR, false, Variable::THIS); - var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1)); + var->AllocateTo(Variable::PARAMETER, -1); receiver_ = var; } @@ -331,6 +330,35 @@ void Scope::Initialize(bool inside_with) { } +Scope* Scope::FinalizeBlockScope() { + ASSERT(is_block_scope()); + ASSERT(temps_.is_empty()); + ASSERT(params_.is_empty()); + + if (num_var_or_const() > 0) return this; + + // Remove this scope from outer scope. + for (int i = 0; i < outer_scope_->inner_scopes_.length(); i++) { + if (outer_scope_->inner_scopes_[i] == this) { + outer_scope_->inner_scopes_.Remove(i); + break; + } + } + + // Reparent inner scopes. + for (int i = 0; i < inner_scopes_.length(); i++) { + outer_scope()->AddInnerScope(inner_scopes_[i]); + } + + // Move unresolved variables + for (int i = 0; i < unresolved_.length(); i++) { + outer_scope()->unresolved_.Add(unresolved_[i]); + } + + return NULL; +} + + Variable* Scope::LocalLookup(Handle<String> name) { Variable* result = variables_.Lookup(name); if (result != NULL || scope_info_.is_null()) { @@ -360,7 +388,7 @@ Variable* Scope::LocalLookup(Handle<String> name) { Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL); - var->set_rewrite(NewSlot(var, Slot::CONTEXT, index)); + var->AllocateTo(Variable::CONTEXT, index); return var; } @@ -378,16 +406,18 @@ Variable* Scope::Lookup(Handle<String> name) { Variable* Scope::DeclareFunctionVar(Handle<String> name) { ASSERT(is_function_scope() && function_ == NULL); - function_ = new Variable(this, name, Variable::CONST, true, Variable::NORMAL); - return function_; + Variable* function_var = + new Variable(this, name, Variable::CONST, true, Variable::NORMAL); + function_ = new(isolate_->zone()) VariableProxy(isolate_, function_var); + return function_var; } -void Scope::DeclareParameter(Handle<String> name) { +void Scope::DeclareParameter(Handle<String> name, Variable::Mode mode) { ASSERT(!already_resolved()); ASSERT(is_function_scope()); Variable* var = - variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL); + variables_.Declare(this, name, mode, true, Variable::NORMAL); params_.Add(var); } @@ -407,7 +437,8 @@ Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) { Variable* Scope::DeclareGlobal(Handle<String> name) { ASSERT(is_global_scope()); - return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL, true, + return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL, + true, Variable::NORMAL); } @@ -440,8 +471,11 @@ void Scope::RemoveUnresolved(VariableProxy* var) { Variable* Scope::NewTemporary(Handle<String> name) { ASSERT(!already_resolved()); - Variable* var = - new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL); + Variable* var = new Variable(this, + name, + Variable::TEMPORARY, + true, + Variable::NORMAL); temps_.Add(var); return var; } @@ -467,6 +501,28 @@ void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) { } +Declaration* Scope::CheckConflictingVarDeclarations() { + int length = decls_.length(); + for (int i = 0; i < length; i++) { + Declaration* decl = decls_[i]; + if (decl->mode() != Variable::VAR) continue; + Handle<String> name = decl->proxy()->name(); + bool cond = true; + for (Scope* scope = decl->scope(); cond ; scope = scope->outer_scope_) { + // There is a conflict if there exists a non-VAR binding. + Variable* other_var = scope->variables_.Lookup(name); + if (other_var != NULL && other_var->mode() != Variable::VAR) { + return decl; + } + + // Include declaration scope in the iteration but stop after. + if (!scope->is_block_scope() && !scope->is_catch_scope()) cond = false; + } + } + return NULL; +} + + template<class Allocator> void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) { // Collect variables in this scope. @@ -612,17 +668,35 @@ static void PrintName(Handle<String> name) { } -static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) { - if (var->is_used() || var->rewrite() != NULL) { +static void PrintLocation(Variable* var) { + switch (var->location()) { + case Variable::UNALLOCATED: + break; + case Variable::PARAMETER: + PrintF("parameter[%d]", var->index()); + break; + case Variable::LOCAL: + PrintF("local[%d]", var->index()); + break; + case Variable::CONTEXT: + PrintF("context[%d]", var->index()); + break; + case Variable::LOOKUP: + PrintF("lookup"); + break; + } +} + + +static void PrintVar(int indent, Variable* var) { + if (var->is_used() || !var->IsUnallocated()) { Indent(indent, Variable::Mode2String(var->mode())); PrintF(" "); PrintName(var->name()); PrintF("; // "); - if (var->rewrite() != NULL) { - PrintF("%s, ", printer->Print(var->rewrite())); - if (var->is_accessed_from_inner_function_scope()) PrintF(", "); - } + PrintLocation(var); if (var->is_accessed_from_inner_function_scope()) { + if (!var->IsUnallocated()) PrintF(", "); PrintF("inner scope access"); } PrintF("\n"); @@ -630,10 +704,10 @@ static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) { } -static void PrintMap(PrettyPrinter* printer, int indent, VariableMap* map) { +static void PrintMap(int indent, VariableMap* map) { for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) { Variable* var = reinterpret_cast<Variable*>(p->value); - PrintVar(printer, indent, var); + PrintVar(indent, var); } } @@ -690,25 +764,24 @@ void Scope::Print(int n) { PrintF("%d heap slots\n", num_heap_slots_); } // Print locals. - PrettyPrinter printer; Indent(n1, "// function var\n"); if (function_ != NULL) { - PrintVar(&printer, n1, function_); + PrintVar(n1, function_->var()); } Indent(n1, "// temporary vars\n"); for (int i = 0; i < temps_.length(); i++) { - PrintVar(&printer, n1, temps_[i]); + PrintVar(n1, temps_[i]); } Indent(n1, "// local vars\n"); - PrintMap(&printer, n1, &variables_); + PrintMap(n1, &variables_); Indent(n1, "// dynamic vars\n"); if (dynamics_ != NULL) { - PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC)); - PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL)); - PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL)); + PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC)); + PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL)); + PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL)); } // Print inner scopes (disable by providing negative n). @@ -732,7 +805,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) { // Declare a new non-local. var = map->Declare(NULL, name, mode, true, Variable::NORMAL); // Allocate it by giving it a dynamic lookup. - var->set_rewrite(NewSlot(var, Slot::LOOKUP, -1)); + var->AllocateTo(Variable::LOOKUP, -1); } return var; } @@ -774,7 +847,7 @@ Variable* Scope::LookupRecursive(Handle<String> name, // the name of named function literal is kept in an intermediate scope // in between this scope and the next outer scope.) if (function_ != NULL && function_->name().is_identical_to(name)) { - var = function_; + var = function_->var(); } else if (outer_scope_ != NULL) { var = outer_scope_->LookupRecursive( @@ -992,12 +1065,12 @@ bool Scope::HasArgumentsParameter() { void Scope::AllocateStackSlot(Variable* var) { - var->set_rewrite(NewSlot(var, Slot::LOCAL, num_stack_slots_++)); + var->AllocateTo(Variable::LOCAL, num_stack_slots_++); } void Scope::AllocateHeapSlot(Variable* var) { - var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++)); + var->AllocateTo(Variable::CONTEXT, num_heap_slots_++); } @@ -1043,14 +1116,14 @@ void Scope::AllocateParameterLocals() { if (MustAllocate(var)) { if (MustAllocateInContext(var)) { - ASSERT(var->rewrite() == NULL || var->IsContextSlot()); - if (var->rewrite() == NULL) { + ASSERT(var->IsUnallocated() || var->IsContextSlot()); + if (var->IsUnallocated()) { AllocateHeapSlot(var); } } else { - ASSERT(var->rewrite() == NULL || var->IsParameter()); - if (var->rewrite() == NULL) { - var->set_rewrite(NewSlot(var, Slot::PARAMETER, i)); + ASSERT(var->IsUnallocated() || var->IsParameter()); + if (var->IsUnallocated()) { + var->AllocateTo(Variable::PARAMETER, i); } } } @@ -1060,11 +1133,9 @@ void Scope::AllocateParameterLocals() { void Scope::AllocateNonParameterLocal(Variable* var) { ASSERT(var->scope() == this); - ASSERT(var->rewrite() == NULL || - !var->IsVariable(isolate_->factory()->result_symbol()) || - var->AsSlot() == NULL || - var->AsSlot()->type() != Slot::LOCAL); - if (var->rewrite() == NULL && MustAllocate(var)) { + ASSERT(!var->IsVariable(isolate_->factory()->result_symbol()) || + !var->IsStackLocal()); + if (var->IsUnallocated() && MustAllocate(var)) { if (MustAllocateInContext(var)) { AllocateHeapSlot(var); } else { @@ -1092,7 +1163,7 @@ void Scope::AllocateNonParameterLocals() { // because of the current ScopeInfo implementation (see // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor). if (function_ != NULL) { - AllocateNonParameterLocal(function_); + AllocateNonParameterLocal(function_->var()); } } diff --git a/deps/v8/src/scopes.h b/deps/v8/src/scopes.h index c2c41799b9..2917a63bba 100644 --- a/deps/v8/src/scopes.h +++ b/deps/v8/src/scopes.h @@ -112,6 +112,11 @@ class Scope: public ZoneObject { void Initialize(bool inside_with); + // Checks if the block scope is redundant, i.e. it does not contain any + // block scoped declarations. In that case it is removed from the scope + // tree and its children are reparented. + Scope* FinalizeBlockScope(); + // --------------------------------------------------------------------------- // Declarations @@ -130,7 +135,7 @@ class Scope: public ZoneObject { // Declare a parameter in this scope. When there are duplicated // parameters the rightmost one 'wins'. However, the implementation // expects all parameters to be declared and from left to right. - void DeclareParameter(Handle<String> name); + void DeclareParameter(Handle<String> name, Variable::Mode mode); // Declare a local variable in this scope. If the variable has been // declared before, the previously declared variable is returned. @@ -182,6 +187,10 @@ class Scope: public ZoneObject { // Check if the scope has (at least) one illegal redeclaration. bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; } + // For harmony block scoping mode: Check if the scope has conflicting var + // declarations, i.e. a var declaration that has been hoisted from a nested + // scope over a let binding of the same name. + Declaration* CheckConflictingVarDeclarations(); // --------------------------------------------------------------------------- // Scope-specific info. @@ -235,7 +244,7 @@ class Scope: public ZoneObject { // The variable holding the function literal for named function // literals, or NULL. // Only valid for function scopes. - Variable* function() const { + VariableProxy* function() const { ASSERT(is_function_scope()); return function_; } @@ -354,7 +363,7 @@ class Scope: public ZoneObject { // Convenience variable. Variable* receiver_; // Function variable, if any; function scopes only. - Variable* function_; + VariableProxy* function_; // Convenience variable; function scopes only. Variable* arguments_; @@ -435,10 +444,6 @@ class Scope: public ZoneObject { // Construct a catch scope with a binding for the name. Scope(Scope* inner_scope, Handle<String> catch_variable_name); - inline Slot* NewSlot(Variable* var, Slot::Type type, int index) { - return new(isolate_->zone()) Slot(isolate_, var, type, index); - } - void AddInnerScope(Scope* inner_scope) { if (inner_scope != NULL) { inner_scopes_.Add(inner_scope); diff --git a/deps/v8/src/spaces-inl.h b/deps/v8/src/spaces-inl.h index 069d01db24..35d7224099 100644 --- a/deps/v8/src/spaces-inl.h +++ b/deps/v8/src/spaces-inl.h @@ -155,7 +155,8 @@ uint32_t Page::GetRegionMaskForAddress(Address addr) { uint32_t Page::GetRegionMaskForSpan(Address start, int length_in_bytes) { uint32_t result = 0; - if (length_in_bytes >= kPageSize) { + static const intptr_t kRegionMask = (1 << kRegionSizeLog2) - 1; + if (length_in_bytes + (OffsetFrom(start) & kRegionMask) >= kPageSize) { result = kAllRegionsDirtyMarks; } else if (length_in_bytes > 0) { int start_region = GetRegionNumberForAddress(start); diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index a70eeade83..6f68ce0890 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -911,50 +911,47 @@ function ReplaceResultBuilder(str) { this.special_string = str; } -ReplaceResultBuilder.prototype.__proto__ = null; - - -ReplaceResultBuilder.prototype.add = function(str) { - str = TO_STRING_INLINE(str); - if (str.length > 0) this.elements.push(str); -} - - -ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) { - var len = end - start; - if (start < 0 || len <= 0) return; - if (start < 0x80000 && len < 0x800) { - this.elements.push((start << 11) | len); - } else { - // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength, - // so -len is a smi. +SetUpLockedPrototype(ReplaceResultBuilder, + $Array("elements", "special_string"), $Array( + "add", function(str) { + str = TO_STRING_INLINE(str); + if (str.length > 0) this.elements.push(str); + }, + "addSpecialSlice", function(start, end) { + var len = end - start; + if (start < 0 || len <= 0) return; + if (start < 0x80000 && len < 0x800) { + this.elements.push((start << 11) | len); + } else { + // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength, + // so -len is a smi. + var elements = this.elements; + elements.push(-len); + elements.push(start); + } + }, + "generate", function() { var elements = this.elements; - elements.push(-len); - elements.push(start); + return %StringBuilderConcat(elements, elements.length, this.special_string); } -} - - -ReplaceResultBuilder.prototype.generate = function() { - var elements = this.elements; - return %StringBuilderConcat(elements, elements.length, this.special_string); -} +)); // ------------------------------------------------------------------- -function SetupString() { - // Setup the constructor property on the String prototype object. +function SetUpString() { + %CheckIsBootstrapping(); + // Set up the constructor property on the String prototype object. %SetProperty($String.prototype, "constructor", $String, DONT_ENUM); - // Setup the non-enumerable functions on the String object. + // Set up the non-enumerable functions on the String object. InstallFunctions($String, DONT_ENUM, $Array( "fromCharCode", StringFromCharCode )); - // Setup the non-enumerable functions on the String prototype object. + // Set up the non-enumerable functions on the String prototype object. InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array( "valueOf", StringValueOf, "toString", StringToString, @@ -994,5 +991,4 @@ function SetupString() { )); } - -SetupString(); +SetUpString(); diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h index a97a4cdab2..dd06a1c078 100644 --- a/deps/v8/src/stub-cache.h +++ b/deps/v8/src/stub-cache.h @@ -357,7 +357,7 @@ class StubCache { // shift are equal. Shifting down the length field to get the // hash code would effectively throw away two bits of the hash // code. - ASSERT(kHeapObjectTagSize == String::kHashShift); + STATIC_ASSERT(kHeapObjectTagSize == String::kHashShift); // Compute the hash of the name (use entire hash field). ASSERT(name->HasHashCode()); uint32_t field = name->hash_field(); diff --git a/deps/v8/src/token.h b/deps/v8/src/token.h index 33af7fe6bf..eb825c1a74 100644 --- a/deps/v8/src/token.h +++ b/deps/v8/src/token.h @@ -71,6 +71,7 @@ namespace internal { /* this block of enum values being contiguous and sorted in the */ \ /* same order! */ \ T(INIT_VAR, "=init_var", 2) /* AST-use only. */ \ + T(INIT_LET, "=init_let", 2) /* AST-use only. */ \ T(INIT_CONST, "=init_const", 2) /* AST-use only. */ \ T(ASSIGN, "=", 2) \ T(ASSIGN_BIT_OR, "|=", 2) \ diff --git a/deps/v8/src/uri.js b/deps/v8/src/uri.js index 72ca6f1565..c910d756b4 100644 --- a/deps/v8/src/uri.js +++ b/deps/v8/src/uri.js @@ -392,8 +392,9 @@ function URIUnescape(str) { // ------------------------------------------------------------------- -function SetupURI() { - // Setup non-enumerable URI functions on the global object and set +function SetUpUri() { + %CheckIsBootstrapping(); + // Set up non-enumerable URI functions on the global object and set // their names. InstallFunctions(global, DONT_ENUM, $Array( "escape", URIEscape, @@ -405,4 +406,4 @@ function SetupURI() { )); } -SetupURI(); +SetUpUri(); diff --git a/deps/v8/src/v8natives.js b/deps/v8/src/v8natives.js index 035fd2e2be..1616ac366b 100644 --- a/deps/v8/src/v8natives.js +++ b/deps/v8/src/v8natives.js @@ -41,7 +41,6 @@ const $isNaN = GlobalIsNaN; const $isFinite = GlobalIsFinite; - // ---------------------------------------------------------------------------- @@ -66,28 +65,56 @@ function InstallFunctions(object, attributes, functions) { // functions on String.prototype etc. and then restore the old function // with delete. See http://code.google.com/p/chromium/issues/detail?id=1717 function InstallFunctionsOnHiddenPrototype(object, attributes, functions) { + %CheckIsBootstrapping(); var hidden_prototype = new $Object(); %SetHiddenPrototype(object, hidden_prototype); InstallFunctions(hidden_prototype, attributes, functions); } +// Prevents changes to the prototype of a built-infunction. +// The "prototype" property of the function object is made non-configurable, +// and the prototype object is made non-extensible. The latter prevents +// changing the __proto__ property. +function SetUpLockedPrototype(constructor, fields, methods) { + %CheckIsBootstrapping(); + var prototype = constructor.prototype; + // Install functions first, because this function is used to initialize + // PropertyDescriptor itself. + var property_count = (methods.length >> 1) + (fields ? fields.length : 0); + if (property_count >= 4) { + %OptimizeObjectForAddingMultipleProperties(prototype, property_count); + } + if (fields) { + for (var i = 0; i < fields.length; i++) { + %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE); + } + } + for (var i = 0; i < methods.length; i += 2) { + var key = methods[i]; + var f = methods[i + 1]; + %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetNativeFlag(f); + } + prototype.__proto__ = null; + %ToFastProperties(prototype); +} + + // ---------------------------------------------------------------------------- // ECMA 262 - 15.1.4 function GlobalIsNaN(number) { - var n = ToNumber(number); - return NUMBER_IS_NAN(n); + if (!IS_NUMBER(number)) number = NonNumberToNumber(number); + return NUMBER_IS_NAN(number); } // ECMA 262 - 15.1.5 function GlobalIsFinite(number) { if (!IS_NUMBER(number)) number = NonNumberToNumber(number); - - // NaN - NaN == NaN, Infinity - Infinity == NaN, -Infinity - -Infinity == NaN. - return %_IsSmi(number) || number - number == 0; + return NUMBER_IS_FINITE(number); } @@ -106,13 +133,16 @@ function GlobalParseInt(string, radix) { // Truncate number. return string | 0; } + string = TO_STRING_INLINE(string); radix = radix | 0; } else { + // The spec says ToString should be evaluated before ToInt32. + string = TO_STRING_INLINE(string); radix = TO_INT32(radix); if (!(radix == 0 || (2 <= radix && radix <= 36))) return $NaN; } - string = TO_STRING_INLINE(string); + if (%_HasCachedArrayIndex(string) && (radix == 0 || radix == 10)) { return %_GetCachedArrayIndex(string); @@ -159,8 +189,9 @@ function GlobalEval(x) { // ---------------------------------------------------------------------------- - -function SetupGlobal() { +// Set up global object. +function SetUpGlobal() { + %CheckIsBootstrapping(); // ECMA 262 - 15.1.1.1. %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE); @@ -170,7 +201,7 @@ function SetupGlobal() { // ECMA-262 - 15.1.1.3. %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE); - // Setup non-enumerable function on the global object. + // Set up non-enumerable function on the global object. InstallFunctions(global, DONT_ENUM, $Array( "isNaN", GlobalIsNaN, "isFinite", GlobalIsFinite, @@ -180,8 +211,7 @@ function SetupGlobal() { )); } -SetupGlobal(); - +SetUpGlobal(); // ---------------------------------------------------------------------------- // Boolean (first part of definition) @@ -478,106 +508,83 @@ function PropertyDescriptor() { this.hasSetter_ = false; } -PropertyDescriptor.prototype.__proto__ = null; - -PropertyDescriptor.prototype.toString = function() { - return "[object PropertyDescriptor]"; -}; - -PropertyDescriptor.prototype.setValue = function(value) { - this.value_ = value; - this.hasValue_ = true; -} - - -PropertyDescriptor.prototype.getValue = function() { - return this.value_; -} - - -PropertyDescriptor.prototype.hasValue = function() { - return this.hasValue_; -} - - -PropertyDescriptor.prototype.setEnumerable = function(enumerable) { - this.enumerable_ = enumerable; - this.hasEnumerable_ = true; -} - - -PropertyDescriptor.prototype.isEnumerable = function () { - return this.enumerable_; -} - - -PropertyDescriptor.prototype.hasEnumerable = function() { - return this.hasEnumerable_; -} - - -PropertyDescriptor.prototype.setWritable = function(writable) { - this.writable_ = writable; - this.hasWritable_ = true; -} - - -PropertyDescriptor.prototype.isWritable = function() { - return this.writable_; -} - - -PropertyDescriptor.prototype.hasWritable = function() { - return this.hasWritable_; -} - - -PropertyDescriptor.prototype.setConfigurable = function(configurable) { - this.configurable_ = configurable; - this.hasConfigurable_ = true; -} - - -PropertyDescriptor.prototype.hasConfigurable = function() { - return this.hasConfigurable_; -} - - -PropertyDescriptor.prototype.isConfigurable = function() { - return this.configurable_; -} - - -PropertyDescriptor.prototype.setGet = function(get) { - this.get_ = get; - this.hasGetter_ = true; -} - - -PropertyDescriptor.prototype.getGet = function() { - return this.get_; -} - - -PropertyDescriptor.prototype.hasGetter = function() { - return this.hasGetter_; -} - - -PropertyDescriptor.prototype.setSet = function(set) { - this.set_ = set; - this.hasSetter_ = true; -} - - -PropertyDescriptor.prototype.getSet = function() { - return this.set_; -} - - -PropertyDescriptor.prototype.hasSetter = function() { - return this.hasSetter_; -} +SetUpLockedPrototype(PropertyDescriptor, $Array( + "value_", + "hasValue_", + "writable_", + "hasWritable_", + "enumerable_", + "hasEnumerable_", + "configurable_", + "hasConfigurable_", + "get_", + "hasGetter_", + "set_", + "hasSetter_" + ), $Array( + "toString", function() { + return "[object PropertyDescriptor]"; + }, + "setValue", function(value) { + this.value_ = value; + this.hasValue_ = true; + }, + "getValue", function() { + return this.value_; + }, + "hasValue", function() { + return this.hasValue_; + }, + "setEnumerable", function(enumerable) { + this.enumerable_ = enumerable; + this.hasEnumerable_ = true; + }, + "isEnumerable", function () { + return this.enumerable_; + }, + "hasEnumerable", function() { + return this.hasEnumerable_; + }, + "setWritable", function(writable) { + this.writable_ = writable; + this.hasWritable_ = true; + }, + "isWritable", function() { + return this.writable_; + }, + "hasWritable", function() { + return this.hasWritable_; + }, + "setConfigurable", function(configurable) { + this.configurable_ = configurable; + this.hasConfigurable_ = true; + }, + "hasConfigurable", function() { + return this.hasConfigurable_; + }, + "isConfigurable", function() { + return this.configurable_; + }, + "setGet", function(get) { + this.get_ = get; + this.hasGetter_ = true; + }, + "getGet", function() { + return this.get_; + }, + "hasGetter", function() { + return this.hasGetter_; + }, + "setSet", function(set) { + this.set_ = set; + this.hasSetter_ = true; + }, + "getSet", function() { + return this.set_; + }, + "hasSetter", function() { + return this.hasSetter_; + })); // Converts an array returned from Runtime_GetOwnProperty to an actual @@ -1165,10 +1172,11 @@ function ObjectIsExtensible(obj) { %SetExpectedNumberOfProperties($Object, 4); // ---------------------------------------------------------------------------- +// Object - -function SetupObject() { - // Setup non-enumerable functions on the Object.prototype object. +function SetUpObject() { + %CheckIsBootstrapping(); + // Set Up non-enumerable functions on the Object.prototype object. InstallFunctions($Object.prototype, DONT_ENUM, $Array( "toString", ObjectToString, "toLocaleString", ObjectToLocaleString, @@ -1198,8 +1206,7 @@ function SetupObject() { )); } -SetupObject(); - +SetUpObject(); // ---------------------------------------------------------------------------- // Boolean @@ -1230,14 +1237,16 @@ function BooleanValueOf() { // ---------------------------------------------------------------------------- -function SetupBoolean() { +function SetUpBoolean () { + %CheckIsBootstrapping(); InstallFunctions($Boolean.prototype, DONT_ENUM, $Array( "toString", BooleanToString, "valueOf", BooleanValueOf )); } -SetupBoolean(); +SetUpBoolean(); + // ---------------------------------------------------------------------------- // Number @@ -1351,9 +1360,10 @@ function NumberToPrecision(precision) { // ---------------------------------------------------------------------------- -function SetupNumber() { +function SetUpNumber() { + %CheckIsBootstrapping(); %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8); - // Setup the constructor property on the Number prototype object. + // Set up the constructor property on the Number prototype object. %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM); %OptimizeObjectForAddingMultipleProperties($Number, 5); @@ -1382,7 +1392,7 @@ function SetupNumber() { DONT_ENUM | DONT_DELETE | READ_ONLY); %ToFastProperties($Number); - // Setup non-enumerable functions on the Number prototype object. + // Set up non-enumerable functions on the Number prototype object. InstallFunctions($Number.prototype, DONT_ENUM, $Array( "toString", NumberToString, "toLocaleString", NumberToLocaleString, @@ -1393,7 +1403,7 @@ function SetupNumber() { )); } -SetupNumber(); +SetUpNumber(); // ---------------------------------------------------------------------------- @@ -1522,11 +1532,12 @@ function NewFunction(arg1) { // length == 1 // ---------------------------------------------------------------------------- -function SetupFunction() { +function SetUpFunction() { + %CheckIsBootstrapping(); InstallFunctions($Function.prototype, DONT_ENUM, $Array( "bind", FunctionBind, "toString", FunctionToString )); } -SetupFunction(); +SetUpFunction(); diff --git a/deps/v8/src/variables.cc b/deps/v8/src/variables.cc index 69495bb40f..6cf6e0b04a 100644 --- a/deps/v8/src/variables.cc +++ b/deps/v8/src/variables.cc @@ -53,34 +53,6 @@ const char* Variable::Mode2String(Mode mode) { } -Property* Variable::AsProperty() const { - return rewrite_ == NULL ? NULL : rewrite_->AsProperty(); -} - - -Slot* Variable::AsSlot() const { return rewrite_; } - - -bool Variable::IsStackAllocated() const { - return rewrite_ != NULL && rewrite_->IsStackAllocated(); -} - - -bool Variable::IsParameter() const { - return rewrite_ != NULL && rewrite_->type() == Slot::PARAMETER; -} - - -bool Variable::IsStackLocal() const { - return rewrite_ != NULL && rewrite_->type() == Slot::LOCAL; -} - - -bool Variable::IsContextSlot() const { - return rewrite_ != NULL && rewrite_->type() == Slot::CONTEXT; -} - - Variable::Variable(Scope* scope, Handle<String> name, Mode mode, @@ -90,8 +62,9 @@ Variable::Variable(Scope* scope, name_(name), mode_(mode), kind_(kind), + location_(UNALLOCATED), + index_(-1), local_if_not_shadowed_(NULL), - rewrite_(NULL), is_valid_LHS_(is_valid_LHS), is_accessed_from_inner_function_scope_(false), is_used_(false) { diff --git a/deps/v8/src/variables.h b/deps/v8/src/variables.h index e92ba6d39a..a4ead51b89 100644 --- a/deps/v8/src/variables.h +++ b/deps/v8/src/variables.h @@ -74,6 +74,33 @@ class Variable: public ZoneObject { ARGUMENTS }; + enum Location { + // Before and during variable allocation, a variable whose location is + // not yet determined. After allocation, a variable looked up as a + // property on the global object (and possibly absent). name() is the + // variable name, index() is invalid. + UNALLOCATED, + + // A slot in the parameter section on the stack. index() is the + // parameter index, counting left-to-right. The reciever is index -1; + // the first parameter is index 0. + PARAMETER, + + // A slot in the local section on the stack. index() is the variable + // index in the stack frame, starting at 0. + LOCAL, + + // An indexed slot in a heap context. index() is the variable index in + // the context object on the heap, starting at 0. scope() is the + // corresponding scope. + CONTEXT, + + // A named slot in a heap context. name() is the variable name in the + // context object on the heap, with lookup starting at the current + // context. index() is invalid. + LOOKUP + }; + Variable(Scope* scope, Handle<String> name, Mode mode, @@ -83,10 +110,6 @@ class Variable: public ZoneObject { // Printing support static const char* Mode2String(Mode mode); - // Type testing & conversion. Global variables are not slots. - Property* AsProperty() const; - Slot* AsSlot() const; - bool IsValidLeftHandSide() { return is_valid_LHS_; } // The source code for an eval() call may refer to a variable that is @@ -111,10 +134,12 @@ class Variable: public ZoneObject { return !is_this() && name().is_identical_to(n); } - bool IsStackAllocated() const; - bool IsParameter() const; // Includes 'this'. - bool IsStackLocal() const; - bool IsContextSlot() const; + bool IsUnallocated() const { return location_ == UNALLOCATED; } + bool IsParameter() const { return location_ == PARAMETER; } + bool IsStackLocal() const { return location_ == LOCAL; } + bool IsStackAllocated() const { return IsParameter() || IsStackLocal(); } + bool IsContextSlot() const { return location_ == CONTEXT; } + bool IsLookupSlot() const { return location_ == LOOKUP; } bool is_dynamic() const { return (mode_ == DYNAMIC || @@ -141,20 +166,24 @@ class Variable: public ZoneObject { local_if_not_shadowed_ = local; } - Slot* rewrite() const { return rewrite_; } - void set_rewrite(Slot* slot) { rewrite_ = slot; } + Location location() const { return location_; } + int index() const { return index_; } + + void AllocateTo(Location location, int index) { + location_ = location; + index_ = index; + } private: Scope* scope_; Handle<String> name_; Mode mode_; Kind kind_; + Location location_; + int index_; Variable* local_if_not_shadowed_; - // Code generation. - Slot* rewrite_; - // Valid as a LHS? (const and this are not valid LHS, for example) bool is_valid_LHS_; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 3fd0fd564e..aeab053f0f 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -33,9 +33,9 @@ // NOTE these macros are used by the SCons build script so their names // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 -#define MINOR_VERSION 5 -#define BUILD_NUMBER 9 -#define PATCH_LEVEL 1 +#define MINOR_VERSION 6 +#define BUILD_NUMBER 1 +#define PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 diff --git a/deps/v8/src/weakmap.js b/deps/v8/src/weakmap.js index 70210b98de..6c15e30fb6 100644 --- a/deps/v8/src/weakmap.js +++ b/deps/v8/src/weakmap.js @@ -80,21 +80,22 @@ function WeakMapDelete(key) { // ------------------------------------------------------------------- -function SetupWeakMap() { - // Setup the WeakMap constructor function. +(function () { + %CheckIsBootstrapping(); + // Set up the WeakMap constructor function. %SetCode($WeakMap, WeakMapConstructor); - // Setup the WeakMap prototype object. + // Set up the WeakMap prototype object. %FunctionSetPrototype($WeakMap, new $WeakMap()); - // Setup the non-enumerable functions on the WeakMap prototype object. + // Set up the constructor property on the WeakMap prototype object. + %SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM); + + // Set up the non-enumerable functions on the WeakMap prototype object. InstallFunctionsOnHiddenPrototype($WeakMap.prototype, DONT_ENUM, $Array( "get", WeakMapGet, "set", WeakMapSet, "has", WeakMapHas, "delete", WeakMapDelete )); -} - - -SetupWeakMap(); +})(); diff --git a/deps/v8/src/x64/builtins-x64.cc b/deps/v8/src/x64/builtins-x64.cc index 076398906c..7c6f7e327c 100644 --- a/deps/v8/src/x64/builtins-x64.cc +++ b/deps/v8/src/x64/builtins-x64.cc @@ -139,7 +139,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // rdi: constructor __ movq(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ JumpIfSmi(rax, &rt_call); // rdi: constructor // rax: initial map (if proven valid below) @@ -1283,7 +1283,7 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { // Initial map for the builtin Array functions should be maps. __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); Condition not_smi = NegateCondition(masm->CheckSmi(rbx)); __ Check(not_smi, "Unexpected initial map for Array function"); __ CmpObjectType(rbx, MAP_TYPE, rcx); @@ -1317,7 +1317,7 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) { // Initial map for the builtin Array function should be a map. __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); Condition not_smi = NegateCondition(masm->CheckSmi(rbx)); __ Check(not_smi, "Unexpected initial map for Array function"); __ CmpObjectType(rbx, MAP_TYPE, rcx); diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 0b785c5dd6..2ae4d9f7ab 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -2470,8 +2470,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // a sequential string or an external string. // In the case of a sliced string its offset has to be taken into account. Label cons_string, check_encoding; - STATIC_ASSERT((kConsStringTag < kExternalStringTag)); - STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); + STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); __ cmpq(rbx, Immediate(kExternalStringTag)); __ j(less, &cons_string, Label::kNear); __ j(equal, &runtime); @@ -3903,8 +3903,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // Handle non-flat strings. __ and_(result_, Immediate(kStringRepresentationMask)); - STATIC_ASSERT((kConsStringTag < kExternalStringTag)); - STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); + STATIC_ASSERT(kConsStringTag < kExternalStringTag); + STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); __ cmpb(result_, Immediate(kExternalStringTag)); __ j(greater, &sliced_string); __ j(equal, &call_runtime_); @@ -3938,7 +3938,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // Check for 1-byte or 2-byte string. __ bind(&flat_string); - STATIC_ASSERT(kAsciiStringTag != 0); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ testb(result_, Immediate(kStringEncodingMask)); __ j(not_zero, &ascii_string); @@ -4195,8 +4196,9 @@ void StringAddStub::Generate(MacroAssembler* masm) { Label non_ascii, allocated, ascii_data; __ movl(rcx, r8); __ and_(rcx, r9); - STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); - __ testl(rcx, Immediate(kAsciiStringTag)); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ testl(rcx, Immediate(kStringEncodingMask)); __ j(zero, &non_ascii); __ bind(&ascii_data); // Allocate an acsii cons string. @@ -4225,7 +4227,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); __ j(equal, &ascii_data); // Allocate a two byte cons string. - __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime); + __ AllocateTwoByteConsString(rcx, rdi, no_reg, &string_add_runtime); __ jmp(&allocated); // Handle creating a flat result. First check that both strings are not @@ -4254,10 +4256,11 @@ void StringAddStub::Generate(MacroAssembler* masm) { // r8: instance type of first string // r9: instance type of second string Label non_ascii_string_add_flat_result; - STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); - __ testl(r8, Immediate(kAsciiStringTag)); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ testl(r8, Immediate(kStringEncodingMask)); __ j(zero, &non_ascii_string_add_flat_result); - __ testl(r9, Immediate(kAsciiStringTag)); + __ testl(r9, Immediate(kStringEncodingMask)); __ j(zero, &string_add_runtime); __ bind(&make_flat_ascii_string); @@ -4295,7 +4298,9 @@ void StringAddStub::Generate(MacroAssembler* masm) { // r8: instance type of first string // r9: instance type of first string __ bind(&non_ascii_string_add_flat_result); - __ and_(r9, Immediate(kAsciiStringTag)); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ and_(r9, Immediate(kStringEncodingMask)); __ j(not_zero, &string_add_runtime); // Both strings are two byte strings. As they are short they are both // flat. @@ -4639,9 +4644,6 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, void SubStringStub::Generate(MacroAssembler* masm) { Label runtime; - if (FLAG_string_slices) { - __ jmp(&runtime); - } // Stack frame on entry. // rsp[0]: return address // rsp[8]: to @@ -4707,7 +4709,82 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); __ Set(rcx, 2); - __ bind(&result_longer_than_two); + if (FLAG_string_slices) { + Label copy_routine; + // If coming from the make_two_character_string path, the string + // is too short to be sliced anyways. + STATIC_ASSERT(2 < SlicedString::kMinLength); + __ jmp(©_routine); + __ bind(&result_longer_than_two); + + // rax: string + // rbx: instance type + // rcx: sub string length + // rdx: from index (smi) + Label allocate_slice, sliced_string, seq_string; + __ cmpq(rcx, Immediate(SlicedString::kMinLength)); + // Short slice. Copy instead of slicing. + __ j(less, ©_routine); + STATIC_ASSERT(kSeqStringTag == 0); + __ testb(rbx, Immediate(kStringRepresentationMask)); + __ j(zero, &seq_string, Label::kNear); + STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); + STATIC_ASSERT(kIsIndirectStringMask != 0); + __ testb(rbx, Immediate(kIsIndirectStringMask)); + // External string. Jump to runtime. + __ j(zero, &runtime); + + __ testb(rbx, Immediate(kSlicedNotConsMask)); + __ j(not_zero, &sliced_string, Label::kNear); + // Cons string. Check whether it is flat, then fetch first part. + __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset), + Heap::kEmptyStringRootIndex); + __ j(not_equal, &runtime); + __ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset)); + __ jmp(&allocate_slice, Label::kNear); + + __ bind(&sliced_string); + // Sliced string. Fetch parent and correct start index by offset. + __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset)); + __ movq(rdi, FieldOperand(rax, SlicedString::kParentOffset)); + __ jmp(&allocate_slice, Label::kNear); + + __ bind(&seq_string); + // Sequential string. Just move string to the right register. + __ movq(rdi, rax); + + __ bind(&allocate_slice); + // edi: underlying subject string + // ebx: instance type of original subject string + // edx: offset + // ecx: length + // Allocate new sliced string. At this point we do not reload the instance + // type including the string encoding because we simply rely on the info + // provided by the original string. It does not matter if the original + // string's encoding is wrong because we always have to recheck encoding of + // the newly created string's parent anyways due to externalized strings. + Label two_byte_slice, set_slice_header; + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ testb(rbx, Immediate(kStringEncodingMask)); + __ j(zero, &two_byte_slice, Label::kNear); + __ AllocateAsciiSlicedString(rax, rbx, no_reg, &runtime); + __ jmp(&set_slice_header, Label::kNear); + __ bind(&two_byte_slice); + __ AllocateTwoByteSlicedString(rax, rbx, no_reg, &runtime); + __ bind(&set_slice_header); + __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); + __ Integer32ToSmi(rcx, rcx); + __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx); + __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi); + __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset), + Immediate(String::kEmptyHashField)); + __ jmp(&return_rax); + + __ bind(©_routine); + } else { + __ bind(&result_longer_than_two); + } // rax: string // rbx: instance type diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index dd35053a65..ba8e0f627e 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -51,8 +51,7 @@ static unsigned GetPropertyId(Property* property) { class JumpPatchSite BASE_EMBEDDED { public: - explicit JumpPatchSite(MacroAssembler* masm) - : masm_(masm) { + explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { #ifdef DEBUG info_emitted_ = false; #endif @@ -187,14 +186,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // Copy any necessary parameters into the context. int num_parameters = info->scope()->num_parameters(); for (int i = 0; i < num_parameters; i++) { - Slot* slot = scope()->parameter(i)->AsSlot(); - if (slot != NULL && slot->type() == Slot::CONTEXT) { + Variable* var = scope()->parameter(i); + if (var->IsContextSlot()) { int parameter_offset = StandardFrameConstants::kCallerSPOffset + (num_parameters - 1 - i) * kPointerSize; // Load parameter from stack. __ movq(rax, Operand(rbp, parameter_offset)); // Store it in the context. - int context_offset = Context::SlotOffset(slot->index()); + int context_offset = Context::SlotOffset(var->index()); __ movq(Operand(rsi, context_offset), rax); // Update the write barrier. This clobbers all involved // registers, so we have use a third register to avoid @@ -232,7 +231,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { : ArgumentsAccessStub::NEW_NON_STRICT_SLOW); __ CallStub(&stub); - Move(arguments->AsSlot(), rax, rbx, rdx); + SetVar(arguments, rax, rbx, rdx); } if (FLAG_trace) { @@ -244,18 +243,21 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { if (scope()->HasIllegalRedeclaration()) { Comment cmnt(masm_, "[ Declarations"); scope()->VisitIllegalRedeclaration(this); + } else { + PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); { Comment cmnt(masm_, "[ Declarations"); // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - EmitDeclaration(scope()->function(), Variable::CONST, NULL); + int ignored = 0; + EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored); } VisitDeclarations(scope()->declarations()); } { Comment cmnt(masm_, "[ Stack check"); - PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); + PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); Label ok; __ CompareRoot(rsp, Heap::kStackLimitRootIndex); __ j(above_equal, &ok, Label::kNear); @@ -355,24 +357,26 @@ void FullCodeGenerator::EmitReturnSequence() { } -void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { +void FullCodeGenerator::EffectContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); } -void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { - MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); - __ movq(result_register(), slot_operand); +void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); + codegen()->GetVar(result_register(), var); } -void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { - MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); - __ push(slot_operand); +void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); + MemOperand operand = codegen()->VarOperand(var, result_register()); + __ push(operand); } -void FullCodeGenerator::TestContext::Plug(Slot* slot) const { - codegen()->Move(result_register(), slot); +void FullCodeGenerator::TestContext::Plug(Variable* var) const { + codegen()->GetVar(result_register(), var); codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); codegen()->DoTest(this); } @@ -591,43 +595,53 @@ void FullCodeGenerator::Split(Condition cc, } -MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - return Operand(rbp, SlotOffset(slot)); - case Slot::CONTEXT: { - int context_chain_length = - scope()->ContextChainLength(slot->var()->scope()); - __ LoadContext(scratch, context_chain_length); - return ContextOperand(scratch, slot->index()); - } - case Slot::LOOKUP: - UNREACHABLE(); +MemOperand FullCodeGenerator::StackOperand(Variable* var) { + ASSERT(var->IsStackAllocated()); + // Offset is negative because higher indexes are at lower addresses. + int offset = -var->index() * kPointerSize; + // Adjust by a (parameter or local) base offset. + if (var->IsParameter()) { + offset += (info_->scope()->num_parameters() + 1) * kPointerSize; + } else { + offset += JavaScriptFrameConstants::kLocal0Offset; } - UNREACHABLE(); - return Operand(rax, 0); + return Operand(rbp, offset); } -void FullCodeGenerator::Move(Register destination, Slot* source) { - MemOperand location = EmitSlotSearch(source, destination); - __ movq(destination, location); +MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) { + ASSERT(var->IsContextSlot() || var->IsStackAllocated()); + if (var->IsContextSlot()) { + int context_chain_length = scope()->ContextChainLength(var->scope()); + __ LoadContext(scratch, context_chain_length); + return ContextOperand(scratch, var->index()); + } else { + return StackOperand(var); + } } -void FullCodeGenerator::Move(Slot* dst, - Register src, - Register scratch1, - Register scratch2) { - ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. - ASSERT(!scratch1.is(src) && !scratch2.is(src)); - MemOperand location = EmitSlotSearch(dst, scratch1); +void FullCodeGenerator::GetVar(Register dest, Variable* var) { + ASSERT(var->IsContextSlot() || var->IsStackAllocated()); + MemOperand location = VarOperand(var, dest); + __ movq(dest, location); +} + + +void FullCodeGenerator::SetVar(Variable* var, + Register src, + Register scratch0, + Register scratch1) { + ASSERT(var->IsContextSlot() || var->IsStackAllocated()); + ASSERT(!scratch0.is(src)); + ASSERT(!scratch0.is(scratch1)); + ASSERT(!scratch1.is(src)); + MemOperand location = VarOperand(var, scratch0); __ movq(location, src); // Emit the write barrier code if the location is in the heap. - if (dst->type() == Slot::CONTEXT) { - int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; - __ RecordWrite(scratch1, offset, src, scratch2); + if (var->IsContextSlot()) { + int offset = Context::SlotOffset(var->index()); + __ RecordWrite(scratch0, offset, src, scratch1); } } @@ -658,29 +672,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, } -void FullCodeGenerator::EmitDeclaration(Variable* variable, +void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, Variable::Mode mode, - FunctionLiteral* function) { - Comment cmnt(masm_, "[ Declaration"); - ASSERT(variable != NULL); // Must have been resolved. - Slot* slot = variable->AsSlot(); - ASSERT(slot != NULL); - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - if (mode == Variable::CONST) { - __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); - __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); - } else if (function != NULL) { + FunctionLiteral* function, + int* global_count) { + // If it was not possible to allocate the variable at compile time, we + // need to "declare" it at runtime to make sure it actually exists in the + // local context. + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: + ++(*global_count); + break; + + case Variable::PARAMETER: + case Variable::LOCAL: + if (function != NULL) { + Comment cmnt(masm_, "[ Declaration"); VisitForAccumulatorValue(function); - __ movq(Operand(rbp, SlotOffset(slot)), result_register()); + __ movq(StackOperand(variable), result_register()); + } else if (mode == Variable::CONST || mode == Variable::LET) { + Comment cmnt(masm_, "[ Declaration"); + __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); + __ movq(StackOperand(variable), kScratchRegister); } break; - case Slot::CONTEXT: - // We bypass the general EmitSlotSearch because we know more about - // this specific context. - + case Variable::CONTEXT: // The variable in the decl always resides in the current function // context. ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); @@ -692,23 +710,28 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); __ Check(not_equal, "Declaration in catch context."); } - if (mode == Variable::CONST) { - __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); - __ movq(ContextOperand(rsi, slot->index()), kScratchRegister); - // No write barrier since the hole value is in old space. - } else if (function != NULL) { + if (function != NULL) { + Comment cmnt(masm_, "[ Declaration"); VisitForAccumulatorValue(function); - __ movq(ContextOperand(rsi, slot->index()), result_register()); - int offset = Context::SlotOffset(slot->index()); + __ movq(ContextOperand(rsi, variable->index()), result_register()); + int offset = Context::SlotOffset(variable->index()); __ movq(rbx, rsi); __ RecordWrite(rbx, offset, result_register(), rcx); + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); + } else if (mode == Variable::CONST || mode == Variable::LET) { + Comment cmnt(masm_, "[ Declaration"); + __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); + __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); + // No write barrier since the hole value is in old space. + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); } break; - case Slot::LOOKUP: { + case Variable::LOOKUP: { + Comment cmnt(masm_, "[ Declaration"); __ push(rsi); __ Push(variable->name()); - // Declaration nodes are always introduced in one of two modes. + // Declaration nodes are always introduced in one of three modes. ASSERT(mode == Variable::VAR || mode == Variable::CONST || mode == Variable::LET); @@ -718,12 +741,12 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, // Note: For variables we must not push an initial value (such as // 'undefined') because we may have a (legal) redeclaration and we // must not destroy the current value. - if (mode == Variable::CONST) { - __ PushRoot(Heap::kTheHoleValueRootIndex); - } else if (function != NULL) { + if (function != NULL) { VisitForStackValue(function); + } else if (mode == Variable::CONST || mode == Variable::LET) { + __ PushRoot(Heap::kTheHoleValueRootIndex); } else { - __ Push(Smi::FromInt(0)); // no initial value! + __ Push(Smi::FromInt(0)); // Indicates no initial value. } __ CallRuntime(Runtime::kDeclareContextSlot, 4); break; @@ -732,18 +755,15 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, } -void FullCodeGenerator::VisitDeclaration(Declaration* decl) { - EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); -} +void FullCodeGenerator::VisitDeclaration(Declaration* decl) { } void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { // Call the runtime to declare the globals. __ push(rsi); // The context is the first argument. __ Push(pairs); - __ Push(Smi::FromInt(is_eval() ? 1 : 0)); - __ Push(Smi::FromInt(strict_mode_flag())); - __ CallRuntime(Runtime::kDeclareGlobals, 4); + __ Push(Smi::FromInt(DeclareGlobalsFlags())); + __ CallRuntime(Runtime::kDeclareGlobals, 3); // Return value is ignored. } @@ -1048,10 +1068,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } -void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( - Slot* slot, - TypeofState typeof_state, - Label* slow) { +void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, + TypeofState typeof_state, + Label* slow) { Register context = rsi; Register temp = rdx; @@ -1101,7 +1120,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( // All extension objects were empty and it is safe to use a global // load IC call. __ movq(rax, GlobalObjectOperand()); - __ Move(rcx, slot->var()->name()); + __ Move(rcx, var->name()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ? RelocInfo::CODE_TARGET @@ -1110,14 +1129,13 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( } -MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( - Slot* slot, - Label* slow) { - ASSERT(slot->type() == Slot::CONTEXT); +MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, + Label* slow) { + ASSERT(var->IsContextSlot()); Register context = rsi; Register temp = rbx; - for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { + for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { if (s->num_heap_slots() > 0) { if (s->calls_eval()) { // Check that extension is NULL. @@ -1137,60 +1155,31 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( // This function is used only for loads, not stores, so it's safe to // return an rsi-based operand (the write barrier cannot be allowed to // destroy the rsi register). - return ContextOperand(context, slot->index()); + return ContextOperand(context, var->index()); } -void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( - Slot* slot, - TypeofState typeof_state, - Label* slow, - Label* done) { +void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, + TypeofState typeof_state, + Label* slow, + Label* done) { // Generate fast-case code for variables that might be shadowed by // eval-introduced variables. Eval is used a lot without // introducing variables. In those cases, we do not want to // perform a runtime call for all variables in the scope // containing the eval. - if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { - EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); + if (var->mode() == Variable::DYNAMIC_GLOBAL) { + EmitLoadGlobalCheckExtensions(var, typeof_state, slow); __ jmp(done); - } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { - Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); - Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); - if (potential_slot != NULL) { - // Generate fast case for locals that rewrite to slots. - __ movq(rax, - ContextSlotOperandCheckExtensions(potential_slot, slow)); - if (potential_slot->var()->mode() == Variable::CONST) { - __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); - __ j(not_equal, done); - __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); - } - __ jmp(done); - } else if (rewrite != NULL) { - // Generate fast case for calls of an argument function. - Property* property = rewrite->AsProperty(); - if (property != NULL) { - VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); - Literal* key_literal = property->key()->AsLiteral(); - if (obj_proxy != NULL && - key_literal != NULL && - obj_proxy->IsArguments() && - key_literal->handle()->IsSmi()) { - // Load arguments object if there are no eval-introduced - // variables. Then load the argument from the arguments - // object using keyed load. - __ movq(rdx, - ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), - slow)); - __ Move(rax, key_literal->handle()); - Handle<Code> ic = - isolate()->builtins()->KeyedLoadIC_Initialize(); - __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); - __ jmp(done); - } - } + } else if (var->mode() == Variable::DYNAMIC_LOCAL) { + Variable* local = var->local_if_not_shadowed(); + __ movq(rax, ContextSlotOperandCheckExtensions(local, slow)); + if (local->mode() == Variable::CONST) { + __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); + __ j(not_equal, done); + __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); } + __ jmp(done); } } @@ -1200,54 +1189,58 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { SetSourcePosition(proxy->position()); Variable* var = proxy->var(); - // Three cases: non-this global variables, lookup slots, and all other - // types of slots. - Slot* slot = var->AsSlot(); - ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); - - if (slot == NULL) { - Comment cmnt(masm_, "Global variable"); - // Use inline caching. Variable name is passed in rcx and the global - // object on the stack. - __ Move(rcx, var->name()); - __ movq(rax, GlobalObjectOperand()); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); - context()->Plug(rax); - - } else if (slot != NULL && slot->type() == Slot::LOOKUP) { - Label done, slow; - - // Generate code for loading from variables potentially shadowed - // by eval-introduced variables. - EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); - - __ bind(&slow); - Comment cmnt(masm_, "Lookup slot"); - __ push(rsi); // Context. - __ Push(var->name()); - __ CallRuntime(Runtime::kLoadContextSlot, 2); - __ bind(&done); + // Three cases: global variables, lookup variables, and all other types of + // variables. + switch (var->location()) { + case Variable::UNALLOCATED: { + Comment cmnt(masm_, "Global variable"); + // Use inline caching. Variable name is passed in rcx and the global + // object on the stack. + __ Move(rcx, var->name()); + __ movq(rax, GlobalObjectOperand()); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); + context()->Plug(rax); + break; + } - context()->Plug(rax); + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::CONTEXT: { + Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot"); + if (var->mode() != Variable::LET && var->mode() != Variable::CONST) { + context()->Plug(var); + } else { + // Let and const need a read barrier. + Label done; + GetVar(rax, var); + __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); + __ j(not_equal, &done, Label::kNear); + if (var->mode() == Variable::LET) { + __ Push(var->name()); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + } else { // Variable::CONST + __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); + } + __ bind(&done); + context()->Plug(rax); + } + break; + } - } else { - Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) - ? "Context slot" - : "Stack slot"); - if (var->mode() == Variable::CONST) { - // Constants may be the hole value if they have not been initialized. - // Unhole them. - Label done; - MemOperand slot_operand = EmitSlotSearch(slot, rax); - __ movq(rax, slot_operand); - __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); - __ j(not_equal, &done, Label::kNear); - __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); + case Variable::LOOKUP: { + Label done, slow; + // Generate code for loading from variables potentially shadowed + // by eval-introduced variables. + EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); + __ bind(&slow); + Comment cmnt(masm_, "Lookup slot"); + __ push(rsi); // Context. + __ Push(var->name()); + __ CallRuntime(Runtime::kLoadContextSlot, 2); __ bind(&done); context()->Plug(rax); - } else { - context()->Plug(slot); + break; } } } @@ -1267,7 +1260,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; __ movq(rbx, FieldOperand(rcx, literal_offset)); __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); - __ j(not_equal, &materialized); + __ j(not_equal, &materialized, Label::kNear); // Create regexp literal using runtime function // Result will be in rax. @@ -1732,82 +1725,88 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) { - ASSERT(var != NULL); - ASSERT(var->is_global() || var->AsSlot() != NULL); - - if (var->is_global()) { - ASSERT(!var->is_this()); - // Assignment to a global variable. Use inline caching for the - // assignment. Right-hand-side value is passed in rax, variable name in - // rcx, and the global object on the stack. + if (var->IsUnallocated()) { + // Global var, const, or let. __ Move(rcx, var->name()); __ movq(rdx, GlobalObjectOperand()); Handle<Code> ic = is_strict_mode() ? isolate()->builtins()->StoreIC_Initialize_Strict() : isolate()->builtins()->StoreIC_Initialize(); __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); - } else if (op == Token::INIT_CONST) { - // Like var declarations, const declarations are hoisted to function - // scope. However, unlike var initializers, const initializers are able - // to drill a hole to that function context, even from inside a 'with' - // context. We thus bypass the normal static scope lookup. - Slot* slot = var->AsSlot(); - Label skip; - switch (slot->type()) { - case Slot::PARAMETER: - // No const parameters. - UNREACHABLE(); - break; - case Slot::LOCAL: - __ movq(rdx, Operand(rbp, SlotOffset(slot))); - __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); - __ j(not_equal, &skip); - __ movq(Operand(rbp, SlotOffset(slot)), rax); - break; - case Slot::CONTEXT: - case Slot::LOOKUP: - __ push(rax); - __ push(rsi); - __ Push(var->name()); - __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); - break; + // Const initializers need a write barrier. + ASSERT(!var->IsParameter()); // No const parameters. + if (var->IsStackLocal()) { + Label skip; + __ movq(rdx, StackOperand(var)); + __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); + __ j(not_equal, &skip); + __ movq(StackOperand(var), rax); + __ bind(&skip); + } else { + ASSERT(var->IsContextSlot() || var->IsLookupSlot()); + // Like var declarations, const declarations are hoisted to function + // scope. However, unlike var initializers, const initializers are + // able to drill a hole to that function context, even from inside a + // 'with' context. We thus bypass the normal static scope lookup for + // var->IsContextSlot(). + __ push(rax); + __ push(rsi); + __ Push(var->name()); + __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); } - __ bind(&skip); - - } else if (var->mode() != Variable::CONST) { - // Perform the assignment for non-const variables. Const assignments - // are simply skipped. - Slot* slot = var->AsSlot(); - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - // Perform the assignment. - __ movq(Operand(rbp, SlotOffset(slot)), rax); - break; - case Slot::CONTEXT: { - MemOperand target = EmitSlotSearch(slot, rcx); - // Perform the assignment and issue the write barrier. - __ movq(target, rax); - // The value of the assignment is in rax. RecordWrite clobbers its - // register arguments. + } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { + // Non-initializing assignment to let variable needs a write barrier. + if (var->IsLookupSlot()) { + __ push(rax); // Value. + __ push(rsi); // Context. + __ Push(var->name()); + __ Push(Smi::FromInt(strict_mode_flag())); + __ CallRuntime(Runtime::kStoreContextSlot, 4); + } else { + ASSERT(var->IsStackAllocated() || var->IsContextSlot()); + Label assign; + MemOperand location = VarOperand(var, rcx); + __ movq(rdx, location); + __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); + __ j(not_equal, &assign, Label::kNear); + __ Push(var->name()); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&assign); + __ movq(location, rax); + if (var->IsContextSlot()) { __ movq(rdx, rax); - int offset = Context::SlotOffset(slot->index()); - __ RecordWrite(rcx, offset, rdx, rbx); - break; + __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx); } + } - case Slot::LOOKUP: - // Call the runtime for the assignment. - __ push(rax); // Value. - __ push(rsi); // Context. - __ Push(var->name()); - __ Push(Smi::FromInt(strict_mode_flag())); - __ CallRuntime(Runtime::kStoreContextSlot, 4); - break; + } else if (var->mode() != Variable::CONST) { + // Assignment to var or initializing assignment to let. + if (var->IsStackAllocated() || var->IsContextSlot()) { + MemOperand location = VarOperand(var, rcx); + if (FLAG_debug_code && op == Token::INIT_LET) { + // Check for an uninitialized let binding. + __ movq(rdx, location); + __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); + __ Check(equal, "Let binding re-initialization."); + } + // Perform the assignment. + __ movq(location, rax); + if (var->IsContextSlot()) { + __ movq(rdx, rax); + __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx); + } + } else { + ASSERT(var->IsLookupSlot()); + __ push(rax); // Value. + __ push(rsi); // Context. + __ Push(var->name()); + __ Push(Smi::FromInt(strict_mode_flag())); + __ CallRuntime(Runtime::kStoreContextSlot, 4); } } + // Non-initializing assignments to consts are ignored. } @@ -2006,8 +2005,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, // Push the receiver of the enclosing function and do runtime call. __ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize)); - // Push the strict mode flag. - __ Push(Smi::FromInt(strict_mode_flag())); + // Push the strict mode flag. In harmony mode every eval call + // is a strict mode eval call. + StrictModeFlag strict_mode = strict_mode_flag(); + if (FLAG_harmony_block_scoping) { + strict_mode = kStrictMode; + } + __ Push(Smi::FromInt(strict_mode)); __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP ? Runtime::kResolvePossiblyDirectEvalNoLookup @@ -2023,18 +2027,18 @@ void FullCodeGenerator::VisitCall(Call* expr) { #endif Comment cmnt(masm_, "[ Call"); - Expression* fun = expr->expression(); - Variable* var = fun->AsVariableProxy()->AsVariable(); + Expression* callee = expr->expression(); + VariableProxy* proxy = callee->AsVariableProxy(); + Property* property = callee->AsProperty(); - if (var != NULL && var->is_possibly_eval()) { + if (proxy != NULL && proxy->var()->is_possibly_eval()) { // In a call to eval, we first call %ResolvePossiblyDirectEval to - // resolve the function we need to call and the receiver of the - // call. Then we call the resolved function using the given - // arguments. + // resolve the function we need to call and the receiver of the call. + // Then we call the resolved function using the given arguments. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); { PreservePositionScope pos_scope(masm()->positions_recorder()); - VisitForStackValue(fun); + VisitForStackValue(callee); __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. // Push the arguments. @@ -2043,15 +2047,14 @@ void FullCodeGenerator::VisitCall(Call* expr) { } // If we know that eval can only be shadowed by eval-introduced - // variables we attempt to load the global eval function directly - // in generated code. If we succeed, there is no need to perform a + // variables we attempt to load the global eval function directly in + // generated code. If we succeed, there is no need to perform a // context lookup in the runtime system. Label done; - if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { + Variable* var = proxy->var(); + if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) { Label slow; - EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), - NOT_INSIDE_TYPEOF, - &slow); + EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); // Push the function and resolve eval. __ push(rax); EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); @@ -2059,13 +2062,11 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ bind(&slow); } - // Push copy of the function (found below the arguments) and - // resolve eval. + // Push a copy of the function (found below the arguments) and resolve + // eval. __ push(Operand(rsp, (arg_count + 1) * kPointerSize)); EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); - if (done.is_linked()) { - __ bind(&done); - } + __ bind(&done); // The runtime call returns a pair of values in rax (function) and // rdx (receiver). Touch up the stack with the right values. @@ -2081,73 +2082,62 @@ void FullCodeGenerator::VisitCall(Call* expr) { // Restore context register. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, rax); - } else if (var != NULL && !var->is_this() && var->is_global()) { - // Call to a global variable. - // Push global object as receiver for the call IC lookup. + } else if (proxy != NULL && proxy->var()->IsUnallocated()) { + // Call to a global variable. Push global object as receiver for the + // call IC lookup. __ push(GlobalObjectOperand()); - EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); - } else if (var != NULL && var->AsSlot() != NULL && - var->AsSlot()->type() == Slot::LOOKUP) { + EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); + } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { // Call to a lookup slot (dynamically introduced variable). Label slow, done; { PreservePositionScope scope(masm()->positions_recorder()); - // Generate code for loading from variables potentially shadowed - // by eval-introduced variables. - EmitDynamicLoadFromSlotFastCase(var->AsSlot(), - NOT_INSIDE_TYPEOF, - &slow, - &done); - - __ bind(&slow); + // Generate code for loading from variables potentially shadowed by + // eval-introduced variables. + EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); } - // Call the runtime to find the function to call (returned in rax) - // and the object holding it (returned in rdx). + __ bind(&slow); + // Call the runtime to find the function to call (returned in rax) and + // the object holding it (returned in rdx). __ push(context_register()); - __ Push(var->name()); + __ Push(proxy->name()); __ CallRuntime(Runtime::kLoadContextSlot, 2); __ push(rax); // Function. __ push(rdx); // Receiver. - // If fast case code has been generated, emit code to push the - // function and receiver and have the slow path jump around this - // code. + // If fast case code has been generated, emit code to push the function + // and receiver and have the slow path jump around this code. if (done.is_linked()) { Label call; __ jmp(&call, Label::kNear); __ bind(&done); // Push function. __ push(rax); - // The receiver is implicitly the global receiver. Indicate this - // by passing the hole to the call function stub. + // The receiver is implicitly the global receiver. Indicate this by + // passing the hole to the call function stub. __ PushRoot(Heap::kTheHoleValueRootIndex); __ bind(&call); } - // The receiver is either the global receiver or an object found - // by LoadContextSlot. That object could be the hole if the - // receiver is implicitly the global object. + // The receiver is either the global receiver or an object found by + // LoadContextSlot. That object could be the hole if the receiver is + // implicitly the global object. EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); - } else if (fun->AsProperty() != NULL) { - // Call to an object property. - Property* prop = fun->AsProperty(); - Literal* key = prop->key()->AsLiteral(); - if (key != NULL && key->handle()->IsSymbol()) { - // Call to a named property, use call IC. - { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } - EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); + } else if (property != NULL) { + { PreservePositionScope scope(masm()->positions_recorder()); + VisitForStackValue(property->obj()); + } + if (property->key()->IsPropertyName()) { + EmitCallWithIC(expr, + property->key()->AsLiteral()->handle(), + RelocInfo::CODE_TARGET); } else { - // Call to a keyed property. - { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } - EmitKeyedCallWithIC(expr, prop->key()); + EmitKeyedCallWithIC(expr, property->key()); } } else { + // Call to an arbitrary expression not handled specially above. { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(fun); + VisitForStackValue(callee); } // Load global receiver object. __ movq(rbx, GlobalObjectOperand()); @@ -3075,7 +3065,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { Label done, not_found; // tmp now holds finger offset as a smi. - ASSERT(kSmiTag == 0 && kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); SmiIndex index = __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2); @@ -3505,30 +3495,31 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { switch (expr->op()) { case Token::DELETE: { Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); - Property* prop = expr->expression()->AsProperty(); - Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); + Property* property = expr->expression()->AsProperty(); + VariableProxy* proxy = expr->expression()->AsVariableProxy(); - if (prop != NULL) { - VisitForStackValue(prop->obj()); - VisitForStackValue(prop->key()); + if (property != NULL) { + VisitForStackValue(property->obj()); + VisitForStackValue(property->key()); __ Push(Smi::FromInt(strict_mode_flag())); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(rax); - } else if (var != NULL) { + } else if (proxy != NULL) { + Variable* var = proxy->var(); // Delete of an unqualified identifier is disallowed in strict mode - // but "delete this" is. + // but "delete this" is allowed. ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); - if (var->is_global()) { + if (var->IsUnallocated()) { __ push(GlobalObjectOperand()); __ Push(var->name()); __ Push(Smi::FromInt(kNonStrictMode)); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(rax); - } else if (var->AsSlot() != NULL && - var->AsSlot()->type() != Slot::LOOKUP) { - // Result of deleting non-global, non-dynamic variables is false. - // The subexpression does not have side effects. - context()->Plug(false); + } else if (var->IsStackAllocated() || var->IsContextSlot()) { + // Result of deleting non-global variables is false. 'this' is + // not really a variable, though we implement it as one. The + // subexpression does not have side effects. + context()->Plug(var->is_this()); } else { // Non-global variable. Call the runtime to try to delete from the // context where the variable was introduced. @@ -3814,7 +3805,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { ASSERT(!context()->IsEffect()); ASSERT(!context()->IsTest()); - if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { + if (proxy != NULL && proxy->var()->IsUnallocated()) { Comment cmnt(masm_, "Global variable"); __ Move(rcx, proxy->name()); __ movq(rax, GlobalObjectOperand()); @@ -3824,15 +3815,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { __ call(ic); PrepareForBailout(expr, TOS_REG); context()->Plug(rax); - } else if (proxy != NULL && - proxy->var()->AsSlot() != NULL && - proxy->var()->AsSlot()->type() == Slot::LOOKUP) { + } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { Label done, slow; // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - Slot* slot = proxy->var()->AsSlot(); - EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); __ bind(&slow); __ push(rsi); @@ -4144,6 +4132,33 @@ void FullCodeGenerator::ExitFinallyBlock() { #undef __ +#define __ ACCESS_MASM(masm()) + +FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( + int* stack_depth, + int* context_length) { + // The macros used here must preserve the result register. + + // Because the handler block contains the context of the finally + // code, we can restore it directly from there for the finally code + // rather than iteratively unwinding contexts via their previous + // links. + __ Drop(*stack_depth); // Down to the handler block. + if (*context_length > 0) { + // Restore the context to its dedicated register and the stack. + __ movq(rsi, Operand(rsp, StackHandlerConstants::kContextOffset)); + __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); + } + __ PopTryHandler(); + __ call(finally_entry_); + + *stack_depth = 0; + *context_length = 0; + return previous_; +} + + +#undef __ } } // namespace v8::internal diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc index 339d2c19ce..990c171bed 100644 --- a/deps/v8/src/x64/ic-x64.cc +++ b/deps/v8/src/x64/ic-x64.cc @@ -378,7 +378,7 @@ static void GenerateKeyStringCheck(MacroAssembler* masm, __ j(zero, index_string); // The value in hash is used at jump target. // Is the string a symbol? - ASSERT(kSymbolTag != 0); + STATIC_ASSERT(kSymbolTag != 0); __ testb(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(kIsSymbolMask)); __ j(zero, not_symbol); diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index 76a9453b79..bedf1be437 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -207,14 +207,14 @@ bool LCodeGen::GeneratePrologue() { // Copy any necessary parameters into the context. int num_parameters = scope()->num_parameters(); for (int i = 0; i < num_parameters; i++) { - Slot* slot = scope()->parameter(i)->AsSlot(); - if (slot != NULL && slot->type() == Slot::CONTEXT) { + Variable* var = scope()->parameter(i); + if (var->IsContextSlot()) { int parameter_offset = StandardFrameConstants::kCallerSPOffset + (num_parameters - 1 - i) * kPointerSize; // Load parameter from stack. __ movq(rax, Operand(rbp, parameter_offset)); // Store it in the context. - int context_offset = Context::SlotOffset(slot->index()); + int context_offset = Context::SlotOffset(var->index()); __ movq(Operand(rsi, context_offset), rax); // Update the write barrier. This clobbers all involved // registers, so we have use a third register to avoid @@ -3217,8 +3217,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { // Dispatch on the indirect string shape: slice or cons. Label cons_string; - const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag; - ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0); __ testb(result, Immediate(kSlicedNotConsMask)); __ j(zero, &cons_string, Label::kNear); @@ -3253,7 +3251,8 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { // Dispatch on the encoding: ASCII or two-byte. Label ascii_string; - STATIC_ASSERT(kAsciiStringTag != 0); + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ testb(result, Immediate(kStringEncodingMask)); __ j(not_zero, &ascii_string, Label::kNear); diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index e4a76270a2..2ee506d7c3 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -923,7 +923,7 @@ void MacroAssembler::LoadSmiConstant(Register dst, Smi* source) { void MacroAssembler::Integer32ToSmi(Register dst, Register src) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); if (!dst.is(src)) { movl(dst, src); } @@ -961,7 +961,7 @@ void MacroAssembler::Integer64PlusConstantToSmi(Register dst, void MacroAssembler::SmiToInteger32(Register dst, Register src) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); if (!dst.is(src)) { movq(dst, src); } @@ -975,7 +975,7 @@ void MacroAssembler::SmiToInteger32(Register dst, const Operand& src) { void MacroAssembler::SmiToInteger64(Register dst, Register src) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); if (!dst.is(src)) { movq(dst, src); } @@ -1111,21 +1111,21 @@ void MacroAssembler::SmiOrIfSmis(Register dst, Register src1, Register src2, Condition MacroAssembler::CheckSmi(Register src) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); testb(src, Immediate(kSmiTagMask)); return zero; } Condition MacroAssembler::CheckSmi(const Operand& src) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); testb(src, Immediate(kSmiTagMask)); return zero; } Condition MacroAssembler::CheckNonNegativeSmi(Register src) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); // Test that both bits of the mask 0x8000000000000001 are zero. movq(kScratchRegister, src); rol(kScratchRegister, Immediate(1)); @@ -1138,7 +1138,7 @@ Condition MacroAssembler::CheckBothSmi(Register first, Register second) { if (first.is(second)) { return CheckSmi(first); } - ASSERT(kSmiTag == 0 && kHeapObjectTag == 1 && kHeapObjectTagMask == 3); + STATIC_ASSERT(kSmiTag == 0 && kHeapObjectTag == 1 && kHeapObjectTagMask == 3); leal(kScratchRegister, Operand(first, second, times_1, 0)); testb(kScratchRegister, Immediate(0x03)); return zero; @@ -1294,7 +1294,7 @@ void MacroAssembler::SmiTryAddConstant(Register dst, Label::Distance near_jump) { // Does not assume that src is a smi. ASSERT_EQ(static_cast<int>(1), static_cast<int>(kSmiTagMask)); - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); ASSERT(!dst.is(kScratchRegister)); ASSERT(!src.is(kScratchRegister)); @@ -1998,7 +1998,7 @@ void MacroAssembler::SelectNonSmi(Register dst, Check(not_both_smis, "Both registers were smis in SelectNonSmi."); } #endif - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); ASSERT_EQ(0, Smi::FromInt(0)); movl(kScratchRegister, Immediate(kSmiTagMask)); and_(kScratchRegister, src1); @@ -2699,7 +2699,7 @@ Condition MacroAssembler::IsObjectStringType(Register heap_object, Register instance_type) { movq(map, FieldOperand(heap_object, HeapObject::kMapOffset)); movzxbl(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); - ASSERT(kNotStringTag != 0); + STATIC_ASSERT(kNotStringTag != 0); testb(instance_type, Immediate(kIsNotStringMask)); return zero; } @@ -3623,7 +3623,7 @@ void MacroAssembler::AllocateAsciiString(Register result, } -void MacroAssembler::AllocateConsString(Register result, +void MacroAssembler::AllocateTwoByteConsString(Register result, Register scratch1, Register scratch2, Label* gc_required) { @@ -3659,6 +3659,42 @@ void MacroAssembler::AllocateAsciiConsString(Register result, } +void MacroAssembler::AllocateTwoByteSlicedString(Register result, + Register scratch1, + Register scratch2, + Label* gc_required) { + // Allocate heap number in new space. + AllocateInNewSpace(SlicedString::kSize, + result, + scratch1, + scratch2, + gc_required, + TAG_OBJECT); + + // Set the map. The other fields are left uninitialized. + LoadRoot(kScratchRegister, Heap::kSlicedStringMapRootIndex); + movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); +} + + +void MacroAssembler::AllocateAsciiSlicedString(Register result, + Register scratch1, + Register scratch2, + Label* gc_required) { + // Allocate heap number in new space. + AllocateInNewSpace(SlicedString::kSize, + result, + scratch1, + scratch2, + gc_required, + TAG_OBJECT); + + // Set the map. The other fields are left uninitialized. + LoadRoot(kScratchRegister, Heap::kSlicedAsciiStringMapRootIndex); + movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); +} + + // Copy memory, byte-by-byte, from source to destination. Not optimized for // long or aligned copies. The contents of scratch and length are destroyed. // Destination is incremented by length, source, length and scratch are diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index 47ce01bd0c..e7eb104c0b 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -921,7 +921,7 @@ class MacroAssembler: public Assembler { // Allocate a raw cons string object. Only the map field of the result is // initialized. - void AllocateConsString(Register result, + void AllocateTwoByteConsString(Register result, Register scratch1, Register scratch2, Label* gc_required); @@ -930,6 +930,17 @@ class MacroAssembler: public Assembler { Register scratch2, Label* gc_required); + // Allocate a raw sliced string object. Only the map field of the result is + // initialized. + void AllocateTwoByteSlicedString(Register result, + Register scratch1, + Register scratch2, + Label* gc_required); + void AllocateAsciiSlicedString(Register result, + Register scratch1, + Register scratch2, + Label* gc_required); + // --------------------------------------------------------------------------- // Support functions. diff --git a/deps/v8/src/x64/regexp-macro-assembler-x64.cc b/deps/v8/src/x64/regexp-macro-assembler-x64.cc index 7f804477f3..a782bd7052 100644 --- a/deps/v8/src/x64/regexp-macro-assembler-x64.cc +++ b/deps/v8/src/x64/regexp-macro-assembler-x64.cc @@ -1185,7 +1185,7 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address, MaybeObject* result = Execution::HandleStackGuardInterrupt(); if (*code_handle != re_code) { // Return address no longer valid - intptr_t delta = *code_handle - re_code; + intptr_t delta = code_handle->address() - re_code->address(); // Overwrite the return address on the stack. *return_address += delta; } diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index cfd19bf146..5ea72579b4 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -258,7 +258,7 @@ static void GenerateStringCheck(MacroAssembler* masm, // Check that the object is a string. __ movq(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); __ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); - ASSERT(kNotStringTag != 0); + STATIC_ASSERT(kNotStringTag != 0); __ testl(scratch, Immediate(kNotStringTag)); __ j(not_zero, non_string_object); } @@ -3070,7 +3070,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { // Load the initial map and verify that it is in fact a map. __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. - ASSERT(kSmiTag == 0); + STATIC_ASSERT(kSmiTag == 0); __ JumpIfSmi(rbx, &generic_stub_call); __ CmpObjectType(rbx, MAP_TYPE, rcx); __ j(not_equal, &generic_stub_call); diff --git a/deps/v8/test/cctest/cctest.gyp b/deps/v8/test/cctest/cctest.gyp index c0b531636c..5d0cab3e98 100644 --- a/deps/v8/test/cctest/cctest.gyp +++ b/deps/v8/test/cctest/cctest.gyp @@ -35,7 +35,6 @@ 'target_name': 'cctest', 'type': 'executable', 'dependencies': [ - '../../tools/gyp/v8.gyp:v8', 'resources', ], 'include_dirs': [ @@ -136,6 +135,20 @@ 'test-platform-win32.cc', ], }], + ['component=="shared_library"', { + # cctest can't be built against a shared library, so we need to + # depend on the underlying static target in that case. + 'conditions': [ + ['v8_use_snapshot=="true"', { + 'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'], + }, + { + 'dependencies': ['../../tools/gyp/v8.gyp:v8_nosnapshot'], + }], + ], + }, { + 'dependencies': ['../../tools/gyp/v8.gyp:v8'], + }], ], }, { diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index 78f3756195..5122da5ae3 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -76,3 +76,7 @@ test-debug/DebugBreakLoop: SKIP [ $arch == mips ] test-deoptimization: SKIP test-serialize: SKIP + +# Tests that may time out. +test-api/ExternalArrays: PASS || TIMEOUT +test-api/Threading: PASS || TIMEOUT diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index f2af81eb71..f9f08a6641 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -823,7 +823,7 @@ static void* expected_ptr; static v8::Handle<v8::Value> callback(const v8::Arguments& args) { void* ptr = v8::External::Unwrap(args.Data()); CHECK_EQ(expected_ptr, ptr); - return v8::Boolean::New(true); + return v8::True(); } @@ -2609,7 +2609,7 @@ v8::Handle<Value> ThrowFromC(const v8::Arguments& args) { v8::Handle<Value> CCatcher(const v8::Arguments& args) { - if (args.Length() < 1) return v8::Boolean::New(false); + if (args.Length() < 1) return v8::False(); v8::HandleScope scope; v8::TryCatch try_catch; Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run(); @@ -4226,7 +4226,7 @@ template <typename T> static void USE(T) { } // This test is not intended to be run, just type checked. -static void PersistentHandles() { +static inline void PersistentHandles() { USE(PersistentHandles); Local<String> str = v8_str("foo"); v8::Persistent<String> p_str = v8::Persistent<String>::New(str); @@ -7296,7 +7296,7 @@ THREADED_TEST(ConstructorForObject) { CHECK(value->IsBoolean()); CHECK_EQ(true, value->BooleanValue()); - Handle<Value> args3[] = { v8::Boolean::New(true) }; + Handle<Value> args3[] = { v8::True() }; Local<Value> value_obj3 = instance->CallAsConstructor(1, args3); CHECK(value_obj3->IsObject()); Local<Object> object3 = Local<Object>::Cast(value_obj3); @@ -9567,10 +9567,7 @@ THREADED_TEST(Overriding) { static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) { ApiTestFuzzer::Fuzz(); - if (args.IsConstructCall()) { - return v8::Boolean::New(true); - } - return v8::Boolean::New(false); + return v8::Boolean::New(args.IsConstructCall()); } @@ -11796,14 +11793,21 @@ THREADED_TEST(PixelArray) { CHECK_EQ(28, result->Int32Value()); i::Handle<i::Smi> value(i::Smi::FromInt(2)); - i::SetElement(jsobj, 1, value, i::kNonStrictMode); + i::Handle<i::Object> no_failure; + no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode); + ASSERT(!no_failure.is_null()); + i::USE(no_failure); CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); *value.location() = i::Smi::FromInt(256); - i::SetElement(jsobj, 1, value, i::kNonStrictMode); + no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode); + ASSERT(!no_failure.is_null()); + i::USE(no_failure); CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); *value.location() = i::Smi::FromInt(-1); - i::SetElement(jsobj, 1, value, i::kNonStrictMode); + no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode); + ASSERT(!no_failure.is_null()); + i::USE(no_failure); CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); result = CompileRun("for (var i = 0; i < 8; i++) {" diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc index 17032035c4..ecbf956916 100644 --- a/deps/v8/test/cctest/test-assembler-arm.cc +++ b/deps/v8/test/cctest/test-assembler-arm.cc @@ -1010,4 +1010,18 @@ TEST(11) { CHECK_EQ(0xffffffff, i.d); } + +TEST(12) { + // Test chaining of label usages within instructions (issue 1644). + InitializeVM(); + v8::HandleScope scope; + Assembler assm(Isolate::Current(), NULL, 0); + + Label target; + __ b(eq, &target); + __ b(ne, &target); + __ bind(&target); + __ nop(); +} + #undef __ diff --git a/deps/v8/test/cctest/test-assembler-ia32.cc b/deps/v8/test/cctest/test-assembler-ia32.cc index e9d799b548..839b7f562e 100644 --- a/deps/v8/test/cctest/test-assembler-ia32.cc +++ b/deps/v8/test/cctest/test-assembler-ia32.cc @@ -394,4 +394,18 @@ TEST(AssemblerIa329) { CHECK_EQ(kNaN, f(OS::nan_value(), 1.1)); } + +TEST(AssemblerIa3210) { + // Test chaining of label usages within instructions (issue 1644). + InitializeVM(); + v8::HandleScope scope; + Assembler assm(Isolate::Current(), NULL, 0); + + Label target; + __ j(equal, &target); + __ j(not_equal, &target); + __ bind(&target); + __ nop(); +} + #undef __ diff --git a/deps/v8/test/cctest/test-assembler-mips.cc b/deps/v8/test/cctest/test-assembler-mips.cc index 065569dd10..a6c76f03ed 100644 --- a/deps/v8/test/cctest/test-assembler-mips.cc +++ b/deps/v8/test/cctest/test-assembler-mips.cc @@ -774,7 +774,7 @@ TEST(MIPS10) { Assembler assm(Isolate::Current(), NULL, 0); Label L, C; - if (CpuFeatures::IsSupported(FPU)) { + if (CpuFeatures::IsSupported(FPU) && mips32r2) { CpuFeatures::Scope scope(FPU); // Load all structure elements to registers. @@ -1259,4 +1259,20 @@ TEST(MIPS14) { } } + +TEST(MIPS15) { + // Test chaining of label usages within instructions (issue 1644). + InitializeVM(); + v8::HandleScope scope; + Assembler assm(Isolate::Current(), NULL, 0); + + Label target; + __ beq(v0, v1, &target); + __ nop(); + __ bne(v0, v1, &target); + __ nop(); + __ bind(&target); + __ nop(); +} + #undef __ diff --git a/deps/v8/test/cctest/test-assembler-x64.cc b/deps/v8/test/cctest/test-assembler-x64.cc index ea70f54205..28f7c9b703 100644 --- a/deps/v8/test/cctest/test-assembler-x64.cc +++ b/deps/v8/test/cctest/test-assembler-x64.cc @@ -46,6 +46,7 @@ using v8::internal::Operand; using v8::internal::byte; using v8::internal::greater; using v8::internal::less_equal; +using v8::internal::equal; using v8::internal::not_equal; using v8::internal::r13; using v8::internal::r15; @@ -345,4 +346,17 @@ TEST(OperandRegisterDependency) { } } + +TEST(AssemblerX64LabelChaining) { + // Test chaining of label usages within instructions (issue 1644). + v8::HandleScope scope; + Assembler assm(Isolate::Current(), NULL, 0); + + Label target; + __ j(equal, &target); + __ j(not_equal, &target); + __ bind(&target); + __ nop(); +} + #undef __ diff --git a/deps/v8/test/cctest/test-compiler.cc b/deps/v8/test/cctest/test-compiler.cc index 8f226f6cde..2d9b01204a 100644 --- a/deps/v8/test/cctest/test-compiler.cc +++ b/deps/v8/test/cctest/test-compiler.cc @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stdlib.h> -#include <wchar.h> // wint_t +#include <wchar.h> #include "v8.h" @@ -75,7 +75,7 @@ v8::Handle<v8::Value> PrintExtension::Print(const v8::Arguments& args) { uint16_t* string = NewArray<uint16_t>(length + 1); string_obj->Write(string); for (int j = 0; j < length; j++) - printf("%lc", static_cast<wint_t>(string[j])); + printf("%lc", static_cast<wchar_t>(string[j])); DeleteArray(string); } printf("\n"); diff --git a/deps/v8/test/cctest/test-disasm-mips.cc b/deps/v8/test/cctest/test-disasm-mips.cc index 901dbc1bf5..5ad99d7a39 100644 --- a/deps/v8/test/cctest/test-disasm-mips.cc +++ b/deps/v8/test/cctest/test-disasm-mips.cc @@ -274,23 +274,25 @@ TEST(Type0) { COMPARE(srav(v0, v1, fp), "03c31007 srav v0, v1, fp"); - COMPARE(rotr(a0, a1, 0), - "00252002 rotr a0, a1, 0"); - COMPARE(rotr(s0, s1, 8), - "00318202 rotr s0, s1, 8"); - COMPARE(rotr(t2, t3, 24), - "002b5602 rotr t2, t3, 24"); - COMPARE(rotr(v0, v1, 31), - "002317c2 rotr v0, v1, 31"); - - COMPARE(rotrv(a0, a1, a2), - "00c52046 rotrv a0, a1, a2"); - COMPARE(rotrv(s0, s1, s2), - "02518046 rotrv s0, s1, s2"); - COMPARE(rotrv(t2, t3, t4), - "018b5046 rotrv t2, t3, t4"); - COMPARE(rotrv(v0, v1, fp), - "03c31046 rotrv v0, v1, fp"); + if (mips32r2) { + COMPARE(rotr(a0, a1, 0), + "00252002 rotr a0, a1, 0"); + COMPARE(rotr(s0, s1, 8), + "00318202 rotr s0, s1, 8"); + COMPARE(rotr(t2, t3, 24), + "002b5602 rotr t2, t3, 24"); + COMPARE(rotr(v0, v1, 31), + "002317c2 rotr v0, v1, 31"); + + COMPARE(rotrv(a0, a1, a2), + "00c52046 rotrv a0, a1, a2"); + COMPARE(rotrv(s0, s1, s2), + "02518046 rotrv s0, s1, s2"); + COMPARE(rotrv(t2, t3, t4), + "018b5046 rotrv t2, t3, t4"); + COMPARE(rotrv(v0, v1, fp), + "03c31046 rotrv v0, v1, fp"); + } COMPARE(break_(0), "0000000d break, code: 0x00000 (0)"); @@ -415,18 +417,21 @@ TEST(Type0) { "72f6b020 clz s6, s7"); COMPARE(clz(v0, v1), "70621020 clz v0, v1"); - COMPARE(ins_(a0, a1, 31, 1), - "7ca4ffc4 ins a0, a1, 31, 1"); - COMPARE(ins_(s6, s7, 30, 2), - "7ef6ff84 ins s6, s7, 30, 2"); - COMPARE(ins_(v0, v1, 0, 32), - "7c62f804 ins v0, v1, 0, 32"); - COMPARE(ext_(a0, a1, 31, 1), - "7ca407c0 ext a0, a1, 31, 1"); - COMPARE(ext_(s6, s7, 30, 2), - "7ef60f80 ext s6, s7, 30, 2"); - COMPARE(ext_(v0, v1, 0, 32), - "7c62f800 ext v0, v1, 0, 32"); + + if (mips32r2) { + COMPARE(ins_(a0, a1, 31, 1), + "7ca4ffc4 ins a0, a1, 31, 1"); + COMPARE(ins_(s6, s7, 30, 2), + "7ef6ff84 ins s6, s7, 30, 2"); + COMPARE(ins_(v0, v1, 0, 32), + "7c62f804 ins v0, v1, 0, 32"); + COMPARE(ext_(a0, a1, 31, 1), + "7ca407c0 ext a0, a1, 31, 1"); + COMPARE(ext_(s6, s7, 30, 2), + "7ef60f80 ext s6, s7, 30, 2"); + COMPARE(ext_(v0, v1, 0, 32), + "7c62f800 ext v0, v1, 0, 32"); + } VERIFY_RUN(); } diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index 9f18b600b2..46ac88cd92 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -30,14 +30,15 @@ #include "v8.h" -#include "string-stream.h" -#include "cctest.h" -#include "zone-inl.h" -#include "parser.h" #include "ast.h" +#include "char-predicates-inl.h" +#include "cctest.h" #include "jsregexp.h" +#include "parser.h" #include "regexp-macro-assembler.h" #include "regexp-macro-assembler-irregexp.h" +#include "string-stream.h" +#include "zone-inl.h" #ifdef V8_INTERPRETED_REGEXP #include "interpreter-irregexp.h" #else // V8_INTERPRETED_REGEXP diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index 17020a3254..55c21417d0 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -529,3 +529,32 @@ TEST(TrivialSlice) { CHECK(string->IsSlicedString()); CHECK_EQ("bcdefghijklmnopqrstuvwxy", *(string->ToCString())); } + + +TEST(SliceFromSlice) { + // This tests whether a slice that contains the entire parent string + // actually creates a new string (it should not). + FLAG_string_slices = true; + InitializeVM(); + HandleScope scope; + v8::Local<v8::Value> result; + Handle<String> string; + const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';"; + const char* slice = "var slice = str.slice(1,-1); slice"; + const char* slice_from_slice = "slice.slice(1,-1);"; + + CompileRun(init); + result = CompileRun(slice); + CHECK(result->IsString()); + string = v8::Utils::OpenHandle(v8::String::Cast(*result)); + CHECK(string->IsSlicedString()); + CHECK(SlicedString::cast(*string)->parent()->IsSeqString()); + CHECK_EQ("bcdefghijklmnopqrstuvwxy", *(string->ToCString())); + + result = CompileRun(slice_from_slice); + CHECK(result->IsString()); + string = v8::Utils::OpenHandle(v8::String::Cast(*result)); + CHECK(string->IsSlicedString()); + CHECK(SlicedString::cast(*string)->parent()->IsSeqString()); + CHECK_EQ("cdefghijklmnopqrstuvwx", *(string->ToCString())); +} diff --git a/deps/v8/test/es5conform/es5conform.status b/deps/v8/test/es5conform/es5conform.status index 55712baf69..d095a2471d 100644 --- a/deps/v8/test/es5conform/es5conform.status +++ b/deps/v8/test/es5conform/es5conform.status @@ -75,11 +75,11 @@ chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-214: UNIMPLEMENTED # NOT IMPLEMENTED: RegExp.prototype.multiline chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215: UNIMPLEMENTED -# All of the tests below marked SUBSETFAIL (in 15.2.3.4) fail because +# All of the tests below marked SUBSETFAIL (in 15.2.3.4) fail because # the tests assumes that objects can not have more properties -# than those described in the spec - but according to spec they can +# than those described in the spec - but according to spec they can # have additional properties. -# All compareArray calls in these tests could be exchanged with a +# All compareArray calls in these tests could be exchanged with a # isSubsetOfArray call (I will upload a patch to the es5conform site). # SUBSETFAIL diff --git a/deps/v8/test/mjsunit/array-constructor.js b/deps/v8/test/mjsunit/array-constructor.js index 063ccde583..bf5d3d611a 100644 --- a/deps/v8/test/mjsunit/array-constructor.js +++ b/deps/v8/test/mjsunit/array-constructor.js @@ -73,7 +73,7 @@ for (var i = 0; i < loop_count; i++) { a = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8); assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7, 8], a); a = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); - assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], a); + assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], a); } @@ -91,9 +91,9 @@ function testConstructOfSizeSize(n) { var a = eval('[' + str + ']'); var b = eval('new Array(' + str + ')') var c = eval('Array(' + str + ')') - assertEquals(n, a.length); - assertArrayEquals(a, b); - assertArrayEquals(a, c); + assertEquals(n, a.length); + assertArrayEquals(a, b); + assertArrayEquals(a, c); } diff --git a/deps/v8/test/mjsunit/array-iteration.js b/deps/v8/test/mjsunit/array-iteration.js index f11b51cb8f..0ee2e6e9ac 100644 --- a/deps/v8/test/mjsunit/array-iteration.js +++ b/deps/v8/test/mjsunit/array-iteration.js @@ -134,7 +134,7 @@ a = [0,1]; assertFalse(a.every(function(n, index, array) { array[index] = n + 1; return n == 1;})); assertArrayEquals([1,1], a); - + // Only loop through initial part of array eventhough elements are // added. a = [1,1]; @@ -156,23 +156,23 @@ // (function() { var a = [0,1,2,3,4]; - + // Simple use. var result = [1,2,3,4,5]; assertArrayEquals(result, a.map(function(n) { return n + 1; })); assertEquals(a, a); - + // Use specified object as this object when calling the function. var o = { delta: 42 } result = [42,43,44,45,46]; assertArrayEquals(result, a.map(function(n) { return this.delta + n; }, o)); - + // Modify original array. a = [0,1,2,3,4]; result = [1,2,3,4,5]; assertArrayEquals(result, a.map(function(n, index, array) { array[index] = n + 1; return n + 1;})); assertArrayEquals(result, a); - + // Only loop through initial part of array eventhough elements are // added. a = [0,1,2,3,4]; @@ -197,7 +197,7 @@ // Simple use. assertTrue(a.some(function(n) { return n == 3})); assertFalse(a.some(function(n) { return n == 5})); - + // Use specified object as this object when calling the function. var o = { element: 42 }; a = [1,42,3]; diff --git a/deps/v8/test/mjsunit/array-sort.js b/deps/v8/test/mjsunit/array-sort.js index fd18a5b2d9..3fa623a656 100644 --- a/deps/v8/test/mjsunit/array-sort.js +++ b/deps/v8/test/mjsunit/array-sort.js @@ -392,7 +392,7 @@ TestSpecialCasesInheritedElementSort(); // Test that sort calls compare function with global object as receiver, // and with only elements of the array as arguments. -function o(v) { +function o(v) { return {__proto__: o.prototype, val: v}; } var arr = [o(1), o(2), o(4), o(8), o(16), o(32), o(64), o(128), o(256), o(-0)]; diff --git a/deps/v8/test/mjsunit/bugs/618.js b/deps/v8/test/mjsunit/bugs/618.js index afa9929a60..ddc0c19c88 100644 --- a/deps/v8/test/mjsunit/bugs/618.js +++ b/deps/v8/test/mjsunit/bugs/618.js @@ -32,14 +32,14 @@ function C1() { var c1 = new C1(); assertEquals(23, c1.x); assertEquals("undefined", typeof c1.y); - + // Add setter somewhere on the prototype chain after having constructed the // first instance. C1.prototype = { set x(value) { this.y = 23; } }; var c1 = new C1(); assertEquals("undefined", typeof c1.x); assertEquals(23, c1.y); - + // Simple class using inline constructor. function C2() { this.x = 23; diff --git a/deps/v8/test/mjsunit/bugs/bug-618.js b/deps/v8/test/mjsunit/bugs/bug-618.js index 8f47440354..ae843267ff 100644 --- a/deps/v8/test/mjsunit/bugs/bug-618.js +++ b/deps/v8/test/mjsunit/bugs/bug-618.js @@ -33,11 +33,11 @@ function C() { this.x = 23; } -// If a setter is added to the prototype chain of a simple constructor setting -// one of the properties assigned in the constructor then this setter is +// If a setter is added to the prototype chain of a simple constructor setting +// one of the properties assigned in the constructor then this setter is // ignored when constructing new objects from the constructor. -// This only happens if the setter is added _after_ an instance has been +// This only happens if the setter is added _after_ an instance has been // created. assertEquals(23, new C().x); diff --git a/deps/v8/test/mjsunit/builtins.js b/deps/v8/test/mjsunit/builtins.js new file mode 100644 index 0000000000..f2ad5446a0 --- /dev/null +++ b/deps/v8/test/mjsunit/builtins.js @@ -0,0 +1,82 @@ +// 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. + +// Flags: --expose-natives-as=builtins + +// Checks that all function properties of the builtin object are neither +// writable nor configurable. Also, theose functions that are actually +// constructors (recognized by having properties on their .prototype object), +// have only unconfigurable properties on the prototype, and the methods +// are also non-writable. + +var names = Object.getOwnPropertyNames(builtins); + +function isFunction(obj) { + return typeof obj == "function"; +} + +function checkConstructor(func, name) { + // A constructor is a function with a prototype and properties on the + // prototype object besides "constructor"; + if (name.charAt(0) == "$") return; + if (typeof func.prototype != "object") return; + var propNames = Object.getOwnPropertyNames(func.prototype); + if (propNames.length == 0 || + (propNames.length == 1 && propNames[0] == "constructor")) { + // Not a constructor. + return; + } + var proto_desc = Object.getOwnPropertyDescriptor(func, "prototype"); + assertTrue(proto_desc.hasOwnProperty("value"), name); + assertFalse(proto_desc.writable, name); + assertFalse(proto_desc.configurable, name); + var prototype = proto_desc.value; + assertEquals(null, prototype.__proto__, name); + for (var i = 0; i < propNames.length; i++) { + var propName = propNames[i]; + if (propName == "constructor") continue; + var testName = name + "-" + propName; + var propDesc = Object.getOwnPropertyDescriptor(prototype, propName); + assertTrue(propDesc.hasOwnProperty("value"), testName); + assertFalse(propDesc.configurable, testName); + if (isFunction(propDesc.value)) { + assertFalse(propDesc.writable, testName); + } + } +} + +for (var i = 0; i < names.length; i++) { + var name = names[i]; + var desc = Object.getOwnPropertyDescriptor(builtins, name); + assertTrue(desc.hasOwnProperty("value")); + var value = desc.value; + if (isFunction(value)) { + assertFalse(desc.writable, name); + assertFalse(desc.configurable, name); + checkConstructor(value, name); + } +} diff --git a/deps/v8/test/mjsunit/compiler/delete.js b/deps/v8/test/mjsunit/compiler/delete.js index 373a1cbcf3..2aaecb25b6 100644 --- a/deps/v8/test/mjsunit/compiler/delete.js +++ b/deps/v8/test/mjsunit/compiler/delete.js @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// 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: @@ -66,6 +66,7 @@ assertEquals(2, ((delete 0) || 2) + 1); assertEquals(3, (function (x) { return ((delete x) || 2) + 1; })(0)); -// 'this' at toplevel is different from all other global variables---not -// deletable. +// 'this' is not a Reference so delete returns true (see section 11.4.1, +// step 2 of ES 5.1). assertEquals(true, delete this); +assertEquals(true, (function () { return delete this; })()); diff --git a/deps/v8/test/mjsunit/compiler/global-accessors.js b/deps/v8/test/mjsunit/compiler/global-accessors.js index bd031a8329..337424dc41 100644 --- a/deps/v8/test/mjsunit/compiler/global-accessors.js +++ b/deps/v8/test/mjsunit/compiler/global-accessors.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This test tests that no bailouts are missing by not hitting asserts in debug -// mode. +// mode. test_count_operation() test_compound_assignment() diff --git a/deps/v8/test/mjsunit/const-redecl.js b/deps/v8/test/mjsunit/const-redecl.js index 26d765b97a..945970891b 100644 --- a/deps/v8/test/mjsunit/const-redecl.js +++ b/deps/v8/test/mjsunit/const-redecl.js @@ -55,7 +55,7 @@ function TestLocal(s,e) { function TestGlobal(s,e) { // Collect the global properties before the call. var properties = []; - for (var key in this) properties.push(key); + for (var key in this) properties.push(key); // Compute the result. var result; try { @@ -113,7 +113,7 @@ function TestConflict(def0, def1) { // Eval second definition. TestAll("TypeError", def0 + '; eval("' + def1 + '")'); // Eval both definitions separately. - TestAll("TypeError", 'eval("' + def0 +'"); eval("' + def1 + '")'); + TestAll("TypeError", 'eval("' + def0 +'"); eval("' + def1 + '")'); } diff --git a/deps/v8/test/mjsunit/d8-os.js b/deps/v8/test/mjsunit/d8-os.js index fd6fb774ea..5640326856 100644 --- a/deps/v8/test/mjsunit/d8-os.js +++ b/deps/v8/test/mjsunit/d8-os.js @@ -30,7 +30,7 @@ // implemented on Windows, and even if it were then many of the things // we are calling would not be available. -var TEST_DIR = "d8-os-test-directory-" + ((Math.random() * (1<<30)) | 0); +var TEST_DIR = "/tmp/d8-os-test-directory-" + ((Math.random() * (1<<30)) | 0); function arg_error(str) { @@ -64,7 +64,7 @@ if (this.os && os.system) { os.chdir(TEST_DIR); try { // Check the chdir worked. - os.system('ls', ['../' + TEST_DIR]); + os.system('ls', [TEST_DIR]); // Simple create dir. os.mkdirp("dir"); // Create dir in dir. @@ -144,7 +144,6 @@ if (this.os && os.system) { //} } } finally { - os.chdir(".."); os.system("rm", ["-r", TEST_DIR]); } diff --git a/deps/v8/test/mjsunit/date-parse.js b/deps/v8/test/mjsunit/date-parse.js index a1eef663b9..b46e39ab61 100644 --- a/deps/v8/test/mjsunit/date-parse.js +++ b/deps/v8/test/mjsunit/date-parse.js @@ -286,7 +286,7 @@ for (var i = 0; i < 24 * 365 * 100; i += 150) { // Negative tests. var testCasesNegative = [ 'May 25 2008 1:30 (PM)) UTC', // Bad unmatched ')' after number. - 'May 25 2008 1:30( )AM (PM)', // + 'May 25 2008 1:30( )AM (PM)', // 'May 25 2008 AAA (GMT)']; // Unknown word after number. testCasesNegative.forEach(function (s) { diff --git a/deps/v8/test/mjsunit/debug-compile-event.js b/deps/v8/test/mjsunit/debug-compile-event.js index b00a907a3c..94dddfa104 100644 --- a/deps/v8/test/mjsunit/debug-compile-event.js +++ b/deps/v8/test/mjsunit/debug-compile-event.js @@ -81,7 +81,7 @@ function listener(event, exec_state, event_data, data) { assertTrue('context' in msg.body.script); // Check that we pick script name from //@ sourceURL, iff present - assertEquals(current_source.indexOf('sourceURL') >= 0 ? + assertEquals(current_source.indexOf('sourceURL') >= 0 ? 'myscript.js' : undefined, event_data.script().name()); } diff --git a/deps/v8/test/mjsunit/debug-evaluate-recursive.js b/deps/v8/test/mjsunit/debug-evaluate-recursive.js index 6ee391b63b..f34943e5f4 100644 --- a/deps/v8/test/mjsunit/debug-evaluate-recursive.js +++ b/deps/v8/test/mjsunit/debug-evaluate-recursive.js @@ -110,7 +110,7 @@ function listener_recurse(event, exec_state, event_data, data) { if (event == Debug.DebugEvent.Break) { break_count++; - + // Call functions with break using the FrameMirror directly. if (break_count == 1) { // First break event evaluates with break enabled. diff --git a/deps/v8/test/mjsunit/debug-handle.js b/deps/v8/test/mjsunit/debug-handle.js index 98875ceb41..1582b9f121 100644 --- a/deps/v8/test/mjsunit/debug-handle.js +++ b/deps/v8/test/mjsunit/debug-handle.js @@ -72,7 +72,7 @@ function lookupRequest(exec_state, arguments, success) { // The base part of all lookup requests. var base_request = '"seq":0,"type":"request","command":"lookup"' - + // Generate request with the supplied arguments. var request; if (arguments) { @@ -214,7 +214,7 @@ function listener(event, exec_state, event_data, data) { 'Handle not in the request: ' + handle); count++; } - assertEquals(count, obj.properties.length, + assertEquals(count, obj.properties.length, 'Unexpected number of resolved objects'); diff --git a/deps/v8/test/mjsunit/debug-listbreakpoints.js b/deps/v8/test/mjsunit/debug-listbreakpoints.js index de0114fe09..1d4755fd1b 100644 --- a/deps/v8/test/mjsunit/debug-listbreakpoints.js +++ b/deps/v8/test/mjsunit/debug-listbreakpoints.js @@ -39,7 +39,7 @@ Debug = debug.Debug // below. The test checks for these line numbers. function g() { // line 40 - var x = 5; + var x = 5; var y = 6; var z = 7; }; diff --git a/deps/v8/test/mjsunit/debug-references.js b/deps/v8/test/mjsunit/debug-references.js index ab6c6292e3..763e354fc8 100644 --- a/deps/v8/test/mjsunit/debug-references.js +++ b/deps/v8/test/mjsunit/debug-references.js @@ -52,7 +52,7 @@ function testRequest(dcp, arguments, success, count) { } else { request = '{' + base_request + '}' } - + // Process the request and check expectation. var response = safeEval(dcp.processDebugJSONRequest(request)); if (success) { @@ -88,7 +88,7 @@ function listener(event, exec_state, event_data, data) { var response = safeEval(dcp.processDebugJSONRequest(evaluate_point)); assertTrue(response.success, "Evaluation of Point failed"); var handle = response.body.handle; - + // Test some legal references requests. testRequest(dcp, '{"handle":' + handle + ',"type":"referencedBy"}', true); testRequest(dcp, '{"handle":' + handle + ',"type":"constructedBy"}', diff --git a/deps/v8/test/mjsunit/debug-return-value.js b/deps/v8/test/mjsunit/debug-return-value.js index 3982ea91b3..02d6a7cbc9 100644 --- a/deps/v8/test/mjsunit/debug-return-value.js +++ b/deps/v8/test/mjsunit/debug-return-value.js @@ -103,12 +103,12 @@ function listener(event, exec_state, event_data, data) { // Position at the end of the function. assertEquals(debugger_source_position + 50, exec_state.frame(0).sourcePosition()); - + // Just about to return from the function. assertTrue(exec_state.frame(0).isAtReturn()) assertEquals(expected_return_value, exec_state.frame(0).returnValue().value()); - + // Check the same using the JSON commands. var dcp = exec_state.debugCommandProcessor(false); var request = '{"seq":0,"type":"request","command":"backtrace"}'; @@ -118,7 +118,7 @@ function listener(event, exec_state, event_data, data) { assertTrue(frames[0].atReturn); assertEquals(expected_return_value, response.lookup(frames[0].returnValue.ref).value); - + listener_complete = true; } } @@ -132,7 +132,7 @@ Debug.setListener(listener); // Four steps from the debugger statement in this function will position us at // the function return. -// 0 1 2 3 4 5 +// 0 1 2 3 4 5 // 0123456789012345678901234567890123456789012345678901 function f(x) {debugger; if (x) { return 1; } else { return 2; } }; diff --git a/deps/v8/test/mjsunit/debug-stepin-call-function-stub.js b/deps/v8/test/mjsunit/debug-stepin-call-function-stub.js index c5cf8fdf3a..053b8bfe8a 100644 --- a/deps/v8/test/mjsunit/debug-stepin-call-function-stub.js +++ b/deps/v8/test/mjsunit/debug-stepin-call-function-stub.js @@ -62,7 +62,7 @@ function listener(event, exec_state, event_data, data) { Debug.setListener(listener); -function g() { +function g() { return "s"; // expected line } @@ -71,7 +71,7 @@ function testFunction() { var s = 1 +f(10); } -function g2() { +function g2() { return "s2"; // expected line } diff --git a/deps/v8/test/mjsunit/debug-stepin-constructor.js b/deps/v8/test/mjsunit/debug-stepin-constructor.js index 6ee3347352..5549814a65 100644 --- a/deps/v8/test/mjsunit/debug-stepin-constructor.js +++ b/deps/v8/test/mjsunit/debug-stepin-constructor.js @@ -38,7 +38,7 @@ function listener(event, exec_state, event_data, data) { if (exec_state.frameCount() > 1) { exec_state.prepareStep(Debug.StepAction.StepIn); } - + // Test that there is a script. assertTrue(typeof(event_data.func().script()) == 'object'); } diff --git a/deps/v8/test/mjsunit/delete-in-with.js b/deps/v8/test/mjsunit/delete-in-with.js index 1efc18de11..cbcfe991b8 100644 --- a/deps/v8/test/mjsunit/delete-in-with.js +++ b/deps/v8/test/mjsunit/delete-in-with.js @@ -29,6 +29,6 @@ // objects from within 'with' statements. (function(){ var tmp = { x: 12 }; - with (tmp) { assertTrue(delete x); } + with (tmp) { assertTrue(delete x); } assertFalse("x" in tmp); })(); diff --git a/deps/v8/test/mjsunit/function-source.js b/deps/v8/test/mjsunit/function-source.js index 75257756d6..8f2fc2265c 100644 --- a/deps/v8/test/mjsunit/function-source.js +++ b/deps/v8/test/mjsunit/function-source.js @@ -36,7 +36,7 @@ function f() { } h(); } - + function g() { function h() { assertEquals(Debug.scriptSource(f), Debug.scriptSource(h)); diff --git a/deps/v8/test/mjsunit/get-own-property-descriptor.js b/deps/v8/test/mjsunit/get-own-property-descriptor.js index 79c1fac6ae..abb2420034 100644 --- a/deps/v8/test/mjsunit/get-own-property-descriptor.js +++ b/deps/v8/test/mjsunit/get-own-property-descriptor.js @@ -27,7 +27,7 @@ // This file only tests very simple descriptors that always have // configurable, enumerable, and writable set to true. -// A range of more elaborate tests are performed in +// A range of more elaborate tests are performed in // object-define-property.js function get() { return x; } diff --git a/deps/v8/test/mjsunit/global-deleted-property-keyed.js b/deps/v8/test/mjsunit/global-deleted-property-keyed.js index 1a1d3cb99b..dba3a4d405 100644 --- a/deps/v8/test/mjsunit/global-deleted-property-keyed.js +++ b/deps/v8/test/mjsunit/global-deleted-property-keyed.js @@ -33,6 +33,6 @@ var name = "fisk"; natives[name] = name; function foo() { natives[name] + 12; } -for(var i = 0; i < 3; i++) foo(); +for(var i = 0; i < 3; i++) foo(); delete natives[name]; for(var i = 0; i < 3; i++) foo(); diff --git a/deps/v8/test/mjsunit/harmony/block-conflicts.js b/deps/v8/test/mjsunit/harmony/block-conflicts.js new file mode 100644 index 0000000000..8d3de6f9d6 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/block-conflicts.js @@ -0,0 +1,126 @@ +// 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. + +// Flags: --harmony-block-scoping + +// Test for conflicting variable bindings. + +function CheckException(e) { + var string = e.toString(); + assertTrue(string.indexOf("has already been declared") >= 0 || + string.indexOf("redeclaration") >= 0); return 'Conflict'; +} + + +function TestFunction(s,e) { + try { + return eval("(function(){" + s + ";return " + e + "})")(); + } catch (x) { + return CheckException(x); + } +} + + +function TestBlock(s,e) { + try { + return eval("(function(){ if (true) { " + s + "; }; return " + e + "})")(); + } catch (x) { + return CheckException(x); + } +} + +function TestAll(expected,s,opt_e) { + var e = ""; + var msg = s; + if (opt_e) { e = opt_e; msg += "; " + opt_e; } + assertEquals(expected, TestFunction(s,e), "function:'" + msg + "'"); + assertEquals(expected, TestBlock(s,e), "block:'" + msg + "'"); +} + + +function TestConflict(s) { + TestAll('Conflict', s); + TestAll('Conflict', 'eval("' + s + '")'); +} + + +function TestNoConflict(s) { + TestAll('NoConflict', s, "'NoConflict'"); + TestAll('NoConflict', 'eval("' + s + '")', "'NoConflict'"); +} + +var letbinds = [ "let x", + "let x = 0", + "let x = undefined", + "function x() { }", + "let x = function() {}", + "let x, y", + "let y, x", + ]; +var varbinds = [ "var x", + "var x = 0", + "var x = undefined", + "var x = function() {}", + "var x, y", + "var y, x", + ]; + + +for (var l = 0; l < letbinds.length; ++l) { + // Test conflicting let/var bindings. + for (var v = 0; v < varbinds.length; ++v) { + // Same level. + TestConflict(letbinds[l] +'; ' + varbinds[v]); + TestConflict(varbinds[v] +'; ' + letbinds[l]); + // Different level. + TestConflict(letbinds[l] +'; {' + varbinds[v] + '; }'); + TestConflict('{ ' + varbinds[v] +'; }' + letbinds[l]); + } + + // Test conflicting let/let bindings. + for (var k = 0; k < letbinds.length; ++k) { + // Same level. + TestConflict(letbinds[l] +'; ' + letbinds[k]); + TestConflict(letbinds[k] +'; ' + letbinds[l]); + // Different level. + TestNoConflict(letbinds[l] +'; { ' + letbinds[k] + '; }'); + TestNoConflict('{ ' + letbinds[k] +'; } ' + letbinds[l]); + } + + // Test conflicting parameter/let bindings. + TestConflict('(function (x) { ' + letbinds[l] + '; })()'); +} + +// Test conflicting catch/var bindings. +for (var v = 0; v < varbinds.length; ++v) { + TestConflict('try {} catch (x) { ' + varbinds[v] + '; }'); +} + +// Test conflicting parameter/var bindings. +for (var v = 0; v < varbinds.length; ++v) { + TestConflict('(function (x) { ' + varbinds[v] + '; })()'); +} diff --git a/deps/v8/test/mjsunit/harmony/block-leave.js b/deps/v8/test/mjsunit/harmony/block-leave.js new file mode 100644 index 0000000000..73eaf29449 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/block-leave.js @@ -0,0 +1,225 @@ +// 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. + +// Flags: --harmony-block-scoping + +// We want to test the context chain shape. In each of the tests cases +// below, the outer with is to force a runtime lookup of the identifier 'x' +// to actually verify that the inner context has been discarded. A static +// lookup of 'x' might accidentally succeed. + +{ + let x = 2; + L: { + let x = 3; + assertEquals(3, x); + break L; + assertTrue(false); + } + assertEquals(2, x); +} + +do { + let x = 4; + assertEquals(4,x); + { + let x = 5; + assertEquals(5, x); + continue; + assertTrue(false); + } +} while (false); + +var caught = false; +try { + { + let xx = 18; + throw 25; + assertTrue(false); + } +} catch (e) { + caught = true; + assertEquals(25, e); + with ({y:19}) { + assertEquals(19, y); + try { + // NOTE: This checks that the block scope containing xx has been + // removed from the context chain. + xx; + assertTrue(false); // should not reach here + } catch (e2) { + assertTrue(e2 instanceof ReferenceError); + } + } +} +assertTrue(caught); + + +with ({x: 'outer'}) { + label: { + let x = 'inner'; + break label; + } + assertEquals('outer', x); +} + + +with ({x: 'outer'}) { + label: { + let x = 'middle'; + { + let x = 'inner'; + break label; + } + } + assertEquals('outer', x); +} + + +with ({x: 'outer'}) { + for (var i = 0; i < 10; ++i) { + let x = 'inner' + i; + continue; + } + assertEquals('outer', x); +} + + +with ({x: 'outer'}) { + label: for (var i = 0; i < 10; ++i) { + let x = 'middle' + i; + for (var j = 0; j < 10; ++j) { + let x = 'inner' + j; + continue label; + } + } + assertEquals('outer', x); +} + + +with ({x: 'outer'}) { + try { + let x = 'inner'; + throw 0; + } catch (e) { + assertEquals('outer', x); + } +} + + +with ({x: 'outer'}) { + try { + let x = 'middle'; + { + let x = 'inner'; + throw 0; + } + } catch (e) { + assertEquals('outer', x); + } +} + + +try { + with ({x: 'outer'}) { + try { + let x = 'inner'; + throw 0; + } finally { + assertEquals('outer', x); + } + } +} catch (e) { + if (e instanceof MjsUnitAssertionError) throw e; +} + + +try { + with ({x: 'outer'}) { + try { + let x = 'middle'; + { + let x = 'inner'; + throw 0; + } + } finally { + assertEquals('outer', x); + } + } +} catch (e) { + if (e instanceof MjsUnitAssertionError) throw e; +} + + +// Verify that the context is correctly set in the stack frame after exiting +// from with. +function f() {} + +with ({x: 'outer'}) { + label: { + let x = 'inner'; + break label; + } + f(); // The context could be restored from the stack after the call. + assertEquals('outer', x); +} + + +with ({x: 'outer'}) { + for (var i = 0; i < 10; ++i) { + let x = 'inner'; + continue; + } + f(); + assertEquals('outer', x); +} + + +with ({x: 'outer'}) { + try { + let x = 'inner'; + throw 0; + } catch (e) { + f(); + assertEquals('outer', x); + } +} + + +try { + with ({x: 'outer'}) { + try { + let x = 'inner'; + throw 0; + } finally { + f(); + assertEquals('outer', x); + } + } +} catch (e) { + if (e instanceof MjsUnitAssertionError) throw e; +} diff --git a/deps/v8/test/mjsunit/harmony/block-let-crankshaft.js b/deps/v8/test/mjsunit/harmony/block-let-crankshaft.js new file mode 100644 index 0000000000..c2fb96b6a4 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/block-let-crankshaft.js @@ -0,0 +1,63 @@ +// 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. + +// Flags: --harmony-block-scoping --allow-natives-syntax + +// Test that temporal dead zone semantics for function and block scoped +// ket bindings are handled by the optimizing compiler. + +function f(x, b) { + let y = (b ? y : x) + 42; + return y; +} + +function g(x, b) { + { + let y = (b ? y : x) + 42; + return y; + } +} + +for (var i=0; i<10; i++) { + f(i, false); + g(i, false); +} + +%OptimizeFunctionOnNextCall(f); +%OptimizeFunctionOnNextCall(g); + +try { + f(42, true); +} catch (e) { + assertInstanceof(e, ReferenceError); +} + +try { + g(42, true); +} catch (e) { + assertInstanceof(e, ReferenceError); +} diff --git a/deps/v8/test/mjsunit/harmony/block-let-declaration.js b/deps/v8/test/mjsunit/harmony/block-let-declaration.js index 19c943f14c..49b63481a0 100644 --- a/deps/v8/test/mjsunit/harmony/block-let-declaration.js +++ b/deps/v8/test/mjsunit/harmony/block-let-declaration.js @@ -57,11 +57,9 @@ function TestLocalDoesNotThrow(str) { // Unprotected statement TestLocalThrows("if (true) let x;", SyntaxError); -TestLocalThrows("with ({}) let x;", SyntaxError); TestLocalThrows("do let x; while (false)", SyntaxError); TestLocalThrows("while (false) let x;", SyntaxError); TestLocalDoesNotThrow("if (true) var x;"); -TestLocalDoesNotThrow("with ({}) var x;"); TestLocalDoesNotThrow("do var x; while (false)"); TestLocalDoesNotThrow("while (false) var x;"); diff --git a/deps/v8/test/mjsunit/harmony/block-let-semantics.js b/deps/v8/test/mjsunit/harmony/block-let-semantics.js new file mode 100644 index 0000000000..198c3b4fb9 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/block-let-semantics.js @@ -0,0 +1,138 @@ +// 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. + +// Flags: --harmony-block-scoping + +// Test temporal dead zone semantics of let bound variables in +// function and block scopes. + +function TestFunctionLocal(s) { + try { + eval("(function(){" + s + "; })")(); + } catch (e) { + assertInstanceof(e, ReferenceError); + return; + } + assertUnreachable(); +} + +function TestBlockLocal(s,e) { + try { + eval("(function(){ {" + s + ";} })")(); + } catch (e) { + assertInstanceof(e, ReferenceError); + return; + } + assertUnreachable(); +} + + +function TestAll(s) { + TestBlockLocal(s); + TestFunctionLocal(s); +} + +// Use before initialization in declaration statement. +TestAll('let x = x + 1'); +TestAll('let x = x += 1'); +TestAll('let x = x++'); +TestAll('let x = ++x'); + +// Use before initialization in prior statement. +TestAll('x + 1; let x;'); +TestAll('x = 1; let x;'); +TestAll('x += 1; let x;'); +TestAll('++x; let x;'); +TestAll('x++; let x;'); + +TestAll('f(); let x; function f() { return x + 1; }'); +TestAll('f(); let x; function f() { x = 1; }'); +TestAll('f(); let x; function f() { x += 1; }'); +TestAll('f(); let x; function f() { ++x; }'); +TestAll('f(); let x; function f() { x++; }'); + +TestAll('f()(); let x; function f() { return function() { return x + 1; } }'); +TestAll('f()(); let x; function f() { return function() { x = 1; } }'); +TestAll('f()(); let x; function f() { return function() { x += 1; } }'); +TestAll('f()(); let x; function f() { return function() { ++x; } }'); +TestAll('f()(); let x; function f() { return function() { x++; } }'); + +// Use in before initialization with a dynamic lookup. +TestAll('eval("x + 1;"); let x;'); +TestAll('eval("x = 1;"); let x;'); +TestAll('eval("x += 1;"); let x;'); +TestAll('eval("++x;"); let x;'); +TestAll('eval("x++;"); let x;'); + +// Test that variables introduced by function declarations are created and +// initialized upon entering a function / block scope. +function f() { + { + assertEquals(2, g1()); + assertEquals(2, eval("g1()")); + + // block scoped function declaration + function g1() { + return 2; + } + } + + assertEquals(3, g2()); + assertEquals(3, eval("g2()")); + // function scoped function declaration + function g2() { + return 3; + } +} +f(); + +// Test that a function declaration introduces a block scoped variable. +TestAll('{ function k() { return 0; } }; k(); '); + +// Test that a function declaration sees the scope it resides in. +function f2() { + let m, n; + { + m = g; + function g() { + return a; + } + let a = 1; + } + assertEquals(1, m()); + + try { + throw 2; + } catch(b) { + n = h; + function h() { + return b + c; + } + let b = 3; + } + assertEquals(5, n()); +} diff --git a/deps/v8/test/mjsunit/harmony/debug-blockscopes.js b/deps/v8/test/mjsunit/harmony/debug-blockscopes.js index e0df71b2df..0230e84b5e 100644 --- a/deps/v8/test/mjsunit/harmony/debug-blockscopes.js +++ b/deps/v8/test/mjsunit/harmony/debug-blockscopes.js @@ -202,17 +202,15 @@ function local_block_1() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.Local, + CheckScopeChain([debug.ScopeType.Local, debug.ScopeType.Global], exec_state); CheckScopeContent({}, 0, exec_state); - CheckScopeContent({}, 1, exec_state); }; local_block_1(); EndTest(); -// Local scope with a parameter. +// Simple empty block scope in local scope with a parameter. BeginTest("Local 2"); function local_2(a) { @@ -222,10 +220,9 @@ function local_2(a) { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.Local, + CheckScopeChain([debug.ScopeType.Local, debug.ScopeType.Global], exec_state); - CheckScopeContent({a:1}, 1, exec_state); + CheckScopeContent({a:1}, 0, exec_state); }; local_2(1); EndTest(); @@ -266,6 +263,72 @@ local_4(1, 2); EndTest(); +// Single variable in a block scope. +BeginTest("Local 5"); + +function local_5(a) { + { + let x = 5; + debugger; + } +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Global], exec_state); + CheckScopeContent({x:5}, 0, exec_state); + CheckScopeContent({a:1}, 1, exec_state); +}; +local_5(1); +EndTest(); + + +// Two variables in a block scope. +BeginTest("Local 6"); + +function local_6(a) { + { + let x = 6; + let y = 7; + debugger; + } +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Global], exec_state); + CheckScopeContent({x:6,y:7}, 0, exec_state); + CheckScopeContent({a:1}, 1, exec_state); +}; +local_6(1); +EndTest(); + + +// Two variables in a block scope. +BeginTest("Local 7"); + +function local_7(a) { + { + { + let x = 8; + debugger; + } + } +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Global], exec_state); + CheckScopeContent({x:8}, 0, exec_state); + CheckScopeContent({a:1}, 1, exec_state); +}; +local_7(1); +EndTest(); + + // Single empty with block. BeginTest("With block 1"); @@ -276,8 +339,7 @@ function with_block_1() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.With, + CheckScopeChain([debug.ScopeType.With, debug.ScopeType.Local, debug.ScopeType.Global], exec_state); CheckScopeContent({}, 0, exec_state); @@ -299,16 +361,13 @@ function with_block_2() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.With, - debug.ScopeType.Block, + CheckScopeChain([debug.ScopeType.With, debug.ScopeType.With, debug.ScopeType.Local, debug.ScopeType.Global], exec_state); CheckScopeContent({}, 0, exec_state); CheckScopeContent({}, 1, exec_state); CheckScopeContent({}, 2, exec_state); - CheckScopeContent({}, 3, exec_state); }; with_block_2(); EndTest(); @@ -324,12 +383,10 @@ function with_block_3() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.With, + CheckScopeChain([debug.ScopeType.With, debug.ScopeType.Local, debug.ScopeType.Global], exec_state); - CheckScopeContent({}, 0, exec_state); - CheckScopeContent({a:1,b:2}, 1, exec_state); + CheckScopeContent({a:1,b:2}, 0, exec_state); }; with_block_3(); EndTest(); @@ -347,19 +404,39 @@ function with_block_4() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.With, - debug.ScopeType.Block, + CheckScopeChain([debug.ScopeType.With, debug.ScopeType.With, debug.ScopeType.Local, debug.ScopeType.Global], exec_state); - CheckScopeContent({a:2,b:1}, 1, exec_state); - CheckScopeContent({a:1,b:2}, 3, exec_state); + CheckScopeContent({a:2,b:1}, 0, exec_state); + CheckScopeContent({a:1,b:2}, 1, exec_state); }; with_block_4(); EndTest(); +// With block and a block local variable. +BeginTest("With block 5"); + +function with_block_5() { + with({a:1}) { + let a = 2; + debugger; + } +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.With, + debug.ScopeType.Local, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:2}, 0, exec_state); + CheckScopeContent({a:1}, 1, exec_state); +}; +with_block_5(); +EndTest(); + + // Simple closure formed by returning an inner function referering to an outer // block local variable and an outer function's parameter. BeginTest("Closure 1"); diff --git a/deps/v8/test/mjsunit/harmony/weakmaps.js b/deps/v8/test/mjsunit/harmony/weakmaps.js index 97f553cf29..e43f9167e6 100644 --- a/deps/v8/test/mjsunit/harmony/weakmaps.js +++ b/deps/v8/test/mjsunit/harmony/weakmaps.js @@ -137,6 +137,7 @@ assertTrue(WeakMap.prototype.set instanceof Function) assertTrue(WeakMap.prototype.get instanceof Function) assertTrue(WeakMap.prototype.has instanceof Function) assertTrue(WeakMap.prototype.delete instanceof Function) +assertTrue(WeakMap.prototype.constructor === WeakMap) // Regression test for issue 1617: The prototype of the WeakMap constructor diff --git a/deps/v8/test/mjsunit/html-string-funcs.js b/deps/v8/test/mjsunit/html-string-funcs.js index 213b7f3412..b640639d8a 100644 --- a/deps/v8/test/mjsunit/html-string-funcs.js +++ b/deps/v8/test/mjsunit/html-string-funcs.js @@ -29,7 +29,7 @@ // HTML. function CheckSimple(f, tag) { assertEquals('<' + tag + '>foo</' + tag + '>', - "foo"[f]().toLowerCase()); + "foo"[f]().toLowerCase()); }; var simple = { big: 'big', blink: 'blink', bold: 'b', fixed: 'tt', italics: 'i', small: 'small', diff --git a/deps/v8/test/mjsunit/in.js b/deps/v8/test/mjsunit/in.js index f98db42f61..cca6187827 100644 --- a/deps/v8/test/mjsunit/in.js +++ b/deps/v8/test/mjsunit/in.js @@ -86,7 +86,7 @@ a[1] = 2; assertFalse(0 in a); assertTrue(1 in a); assertFalse(2 in a); -assertFalse('0' in a); +assertFalse('0' in a); assertTrue('1' in a); assertFalse('2' in a); assertTrue('toString' in a, "toString"); diff --git a/deps/v8/test/mjsunit/instanceof.js b/deps/v8/test/mjsunit/instanceof.js index 01ea4268e6..050ef2d9d7 100644 --- a/deps/v8/test/mjsunit/instanceof.js +++ b/deps/v8/test/mjsunit/instanceof.js @@ -60,10 +60,10 @@ TestChains(); function TestExceptions() { function F() { } - var items = [ 1, new Number(42), - true, + var items = [ 1, new Number(42), + true, 'string', new String('hest'), - {}, [], + {}, [], F, new F(), Object, String ]; diff --git a/deps/v8/test/mjsunit/keyed-storage-extend.js b/deps/v8/test/mjsunit/keyed-storage-extend.js index 04d2f0477a..d7e157b846 100644 --- a/deps/v8/test/mjsunit/keyed-storage-extend.js +++ b/deps/v8/test/mjsunit/keyed-storage-extend.js @@ -37,7 +37,7 @@ function GrowNamed(o) { } function GrowKeyed(o) { - var names = ['a','b','c','d','e','f']; + var names = ['a','b','c','d','e','f']; var i = 0; o[names[i++]] = i; o[names[i++]] = i; diff --git a/deps/v8/test/mjsunit/mirror-array.js b/deps/v8/test/mjsunit/mirror-array.js index eb8f72a8c9..92e3913f31 100644 --- a/deps/v8/test/mjsunit/mirror-array.js +++ b/deps/v8/test/mjsunit/mirror-array.js @@ -64,7 +64,7 @@ function testArrayMirror(a, names) { assertTrue(mirror.protoObject() instanceof debug.Mirror, 'Unexpected mirror hierachy'); assertTrue(mirror.prototypeObject() instanceof debug.Mirror, 'Unexpected mirror hierachy'); assertEquals(mirror.length(), a.length, "Length mismatch"); - + var indexedProperties = mirror.indexedPropertiesFromRange(); assertEquals(indexedProperties.length, a.length); for (var i = 0; i < indexedProperties.length; i++) { @@ -110,7 +110,7 @@ function testArrayMirror(a, names) { var found = false; for (var j = 0; j < fromJSON.properties.length; j++) { if (names[i] == fromJSON.properties[j].name) { - found = true; + found = true; } } assertTrue(found, names[i]) diff --git a/deps/v8/test/mjsunit/mirror-function.js b/deps/v8/test/mjsunit/mirror-function.js index 58aee3dae8..cda815df68 100644 --- a/deps/v8/test/mjsunit/mirror-function.js +++ b/deps/v8/test/mjsunit/mirror-function.js @@ -65,7 +65,7 @@ function testFunctionMirror(f) { assertTrue(mirror.constructorFunction() instanceof debug.ObjectMirror); assertTrue(mirror.protoObject() instanceof debug.Mirror); assertTrue(mirror.prototypeObject() instanceof debug.Mirror); - + // Test text representation assertEquals(f.toString(), mirror.toText()); diff --git a/deps/v8/test/mjsunit/mirror-script.js b/deps/v8/test/mjsunit/mirror-script.js index 71561701a2..1d64ac26bf 100644 --- a/deps/v8/test/mjsunit/mirror-script.js +++ b/deps/v8/test/mjsunit/mirror-script.js @@ -62,7 +62,7 @@ function testScriptMirror(f, file_name, file_lines, type, compilation_type, if (eval_from_line) { assertEquals(eval_from_line, mirror.evalFromLocation().line); } - + // Parse JSON representation and check. var fromJSON = JSON.parse(json); assertEquals('script', fromJSON.type); diff --git a/deps/v8/test/mjsunit/mirror-unresolved-function.js b/deps/v8/test/mjsunit/mirror-unresolved-function.js index c1fe4a3ef0..46f22a08a7 100644 --- a/deps/v8/test/mjsunit/mirror-unresolved-function.js +++ b/deps/v8/test/mjsunit/mirror-unresolved-function.js @@ -64,7 +64,7 @@ assertEquals(void 0, mirror.source()); assertEquals('undefined', mirror.constructorFunction().type()); assertEquals('undefined', mirror.protoObject().type()); assertEquals('undefined', mirror.prototypeObject().type()); - + // Parse JSON representation of unresolved functions and check. var fromJSON = eval('(' + json + ')'); assertEquals('function', fromJSON.type, 'Unexpected mirror type in JSON'); diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index b7b0c774c4..027da584b4 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -115,6 +115,9 @@ regress/regress-1132: SKIP ############################################################################## [ $arch == mips ] +# Run those tests, but expect them to time out. +array-sort: PASS || TIMEOUT +mirror-object: PASS || TIMEOUT # Skip long-running tests. compiler/alloc-number: SKIP @@ -141,8 +144,11 @@ regress/regress-634: SKIP regress/regress-create-exception: SKIP regress/regress-3218915: SKIP regress/regress-3247124: SKIP +regress/regress-1132: SKIP +regress/regress-1257: SKIP +regress/regress-91008: SKIP - +############################################################################## [ $isolates ] # d8-os writes temporary files that might interfer with each other when running # in multible threads. Skip this if running with isolates testing. diff --git a/deps/v8/test/mjsunit/no-semicolon.js b/deps/v8/test/mjsunit/no-semicolon.js index fa6ccba89d..273ec4bccb 100644 --- a/deps/v8/test/mjsunit/no-semicolon.js +++ b/deps/v8/test/mjsunit/no-semicolon.js @@ -30,7 +30,7 @@ function f() { return } -function g() { +function g() { return 4; } @@ -42,4 +42,4 @@ for (var i = 0; i < 10; i++) { break } assertEquals(0, i); for (var i = 0; i < 10; i++) { continue } -assertEquals(10, i);
\ No newline at end of file +assertEquals(10, i); diff --git a/deps/v8/test/mjsunit/object-define-properties.js b/deps/v8/test/mjsunit/object-define-properties.js index 6b3725b392..128df694d3 100644 --- a/deps/v8/test/mjsunit/object-define-properties.js +++ b/deps/v8/test/mjsunit/object-define-properties.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Tests the Object.defineProperties method - ES 15.2.3.7 -// Note that the internal DefineOwnProperty method is tested through +// Note that the internal DefineOwnProperty method is tested through // object-define-property.js, this file only contains tests specific for // Object.defineProperties. Also note that object-create.js contains // a range of indirect tests on this method since Object.create uses diff --git a/deps/v8/test/mjsunit/object-literal-conversions.js b/deps/v8/test/mjsunit/object-literal-conversions.js index 8540d93082..742f814ba3 100644 --- a/deps/v8/test/mjsunit/object-literal-conversions.js +++ b/deps/v8/test/mjsunit/object-literal-conversions.js @@ -43,4 +43,4 @@ var test6 = { 17.31: function() {}, "17.31": 7 }; assertEquals(7, test5[13]); assertEquals(7, test6[17.31]); -
\ No newline at end of file + diff --git a/deps/v8/test/mjsunit/object-literal-overwrite.js b/deps/v8/test/mjsunit/object-literal-overwrite.js index 5c58a2ddb6..5a3584df8a 100644 --- a/deps/v8/test/mjsunit/object-literal-overwrite.js +++ b/deps/v8/test/mjsunit/object-literal-overwrite.js @@ -79,7 +79,7 @@ assertEquals(7, foo7[15]); // Test for the classic code generator. function fun(x) { - var inner = { j: function(x) { return x; }, j: 7 }; + var inner = { j: function(x) { return x; }, j: 7 }; return inner.j; } @@ -115,4 +115,4 @@ function fun3() { var y = fun3(); assertEquals(7, y); -assertEquals(3, glob3);
\ No newline at end of file +assertEquals(3, glob3); diff --git a/deps/v8/test/mjsunit/object-prevent-extensions.js b/deps/v8/test/mjsunit/object-prevent-extensions.js index dc32342c0e..322a2cb543 100644 --- a/deps/v8/test/mjsunit/object-prevent-extensions.js +++ b/deps/v8/test/mjsunit/object-prevent-extensions.js @@ -33,7 +33,7 @@ var obj1 = {}; assertTrue(Object.isExtensible(obj1)); Object.preventExtensions(obj1); -// Make sure the is_extensible flag is set. +// Make sure the is_extensible flag is set. assertFalse(Object.isExtensible(obj1)); obj1.x = 42; assertEquals(undefined, obj1.x); diff --git a/deps/v8/test/mjsunit/parse-int-float.js b/deps/v8/test/mjsunit/parse-int-float.js index a4f09df9b4..2e4f648437 100644 --- a/deps/v8/test/mjsunit/parse-int-float.js +++ b/deps/v8/test/mjsunit/parse-int-float.js @@ -100,4 +100,17 @@ assertTrue(isNaN(parseFloat(0/0))); assertEquals(Infinity, parseFloat(1/0), "parseFloat Infinity"); assertEquals(-Infinity, parseFloat(-1/0), "parseFloat -Infinity"); +var state; +var throwingRadix = { valueOf: function() { state = "throwingRadix"; throw null; } }; +var throwingString = { toString: function() { state = "throwingString"; throw null; } }; +state = null; +try { parseInt('123', throwingRadix); } catch (e) {} +assertEquals(state, "throwingRadix"); +state = null; +try { parseInt(throwingString, 10); } catch (e) {} +assertEquals(state, "throwingString"); + +state = null; +try { parseInt(throwingString, throwingRadix); } catch (e) {} +assertEquals(state, "throwingString"); diff --git a/deps/v8/test/mjsunit/regress/regress-1081309.js b/deps/v8/test/mjsunit/regress/regress-1081309.js index 009ede1516..5a6c52412e 100644 --- a/deps/v8/test/mjsunit/regress/regress-1081309.js +++ b/deps/v8/test/mjsunit/regress/regress-1081309.js @@ -67,7 +67,7 @@ function listener(event, exec_state, event_data, data) { // The expected backtrace is // 1: g // 0: [anonymous] - + // Get the debug command processor. var dcp = exec_state.debugCommandProcessor(false); diff --git a/deps/v8/test/mjsunit/regress/regress-1092.js b/deps/v8/test/mjsunit/regress/regress-1092.js index 0b29231a4b..00422cb452 100644 --- a/deps/v8/test/mjsunit/regress/regress-1092.js +++ b/deps/v8/test/mjsunit/regress/regress-1092.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Test that CodeGenerator::EmitKeyedPropertyAssignment for the start +// Test that CodeGenerator::EmitKeyedPropertyAssignment for the start // of an initialization block doesn't normalize the properties of the // JSGlobalProxy. this.w = 0; diff --git a/deps/v8/test/mjsunit/regress/regress-1110.js b/deps/v8/test/mjsunit/regress/regress-1110.js index 204a87ba3d..43b8d77aeb 100644 --- a/deps/v8/test/mjsunit/regress/regress-1110.js +++ b/deps/v8/test/mjsunit/regress/regress-1110.js @@ -29,7 +29,7 @@ try { function Crash() { continue;if (Crash) { - } } + } } Crash(); assertTrue(false); } catch (e) { diff --git a/deps/v8/test/mjsunit/regress/regress-1213575.js b/deps/v8/test/mjsunit/regress/regress-1213575.js index 0c3dcc28c6..9d82064e47 100644 --- a/deps/v8/test/mjsunit/regress/regress-1213575.js +++ b/deps/v8/test/mjsunit/regress/regress-1213575.js @@ -33,7 +33,7 @@ this.__defineSetter__('x', function(value) { assertTrue(false); }); var caught = false; try { - eval('const x'); + eval('const x'); } catch(e) { assertTrue(e instanceof TypeError); caught = true; diff --git a/deps/v8/test/mjsunit/regress/regress-1215.js b/deps/v8/test/mjsunit/regress/regress-1215.js new file mode 100644 index 0000000000..93a89f6a3f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-1215.js @@ -0,0 +1,36 @@ +// 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. + +// Make sure that the "message" property on Error.prototype +// has the following descriptor: +// {writable: true, enumerable: false, and configurable: true} + +var desc = Object.getOwnPropertyDescriptor(Error.prototype, 'message'); + +assertEquals(desc.writable, true); +assertEquals(desc.enumerable, false); +assertEquals(desc.configurable, true); diff --git a/deps/v8/test/mjsunit/regress/regress-1447.js b/deps/v8/test/mjsunit/regress/regress-1447.js index 3c64929d1d..2c1ee5917d 100644 --- a/deps/v8/test/mjsunit/regress/regress-1447.js +++ b/deps/v8/test/mjsunit/regress/regress-1447.js @@ -27,3 +27,11 @@ [0].forEach(function(){ Object.freeze(Array.prototype.forEach); }); [0].every(function(){ Object.seal(Array.prototype.every); }); + +function testStrict(){ + "use strict"; + [0].forEach(function(){ Object.freeze(Array.prototype.forEach); }); + [0].every(function(){ Object.seal(Array.prototype.every); }); +} + +testStrict(); diff --git a/deps/v8/test/mjsunit/regress/regress-1548.js b/deps/v8/test/mjsunit/regress/regress-1548.js new file mode 100644 index 0000000000..074007b916 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-1548.js @@ -0,0 +1,48 @@ +// 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. + +// Test that the caller and arguments objects are not available on native +// functions. + +function testfn(f) { return [1].map(f)[0]; } +function foo() { return [].map.caller; } +assertEquals(null, testfn(foo)); + +// Try to delete the caller property (to make sure that we can't get to the +// caller accessor on the prototype. +delete Array.prototype.map.caller; +assertEquals(null, testfn(foo)); + +// Redo tests with arguments object. +function testarguments(f) { return [1].map(f)[0]; } +function bar() { return [].map.arguments; } +assertEquals(null, testfn(bar)); + +// Try to delete the arguments property (to make sure that we can't get to the +// caller accessor on the prototype. +delete Array.prototype.map.arguments; +assertEquals(null, testarguments(bar)); diff --git a/deps/v8/test/mjsunit/regress/regress-1647.js b/deps/v8/test/mjsunit/regress/regress-1647.js new file mode 100644 index 0000000000..a6afcc0be2 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-1647.js @@ -0,0 +1,43 @@ +// 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. + +// Flags: --allow-natives-syntax + +// Test for correct deoptimization in named function expressions. + +var t = { foo: function() {} }; + +var f = (function bar() { + t.foo(); + assertEquals("function", typeof bar); +}); + +for (var i = 0; i < 10; i++) f(); +%OptimizeFunctionOnNextCall(f); +t.number = 2; +f(); + diff --git a/deps/v8/test/mjsunit/regress/regress-1650.js b/deps/v8/test/mjsunit/regress/regress-1650.js new file mode 100644 index 0000000000..fb6a17814d --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-1650.js @@ -0,0 +1,60 @@ +// 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. + +// Flags: --allow-natives-syntax + +function g(f) { return f.call.apply(f.bind, arguments); } + +var x = new Object; + +function t() { } + +g(t, x); +g(t, x); +g(t, x); +%OptimizeFunctionOnNextCall(g); + +function Fake() {} + +var fakeCallInvoked = false; + +Fake.prototype.call = function () { + assertSame(Fake.prototype.bind, this); + assertEquals(2, arguments.length); + assertSame(fake, arguments[0]); + assertSame(x, arguments[1]); + fakeCallInvoked = true; +}; + +Fake.prototype.bind = function () { +}; + +var fake = new Fake; + +g(fake, x); + +assertTrue(fakeCallInvoked); diff --git a/deps/v8/test/mjsunit/regress/regress-1919169.js b/deps/v8/test/mjsunit/regress/regress-1919169.js index 774f26558d..a73231289f 100644 --- a/deps/v8/test/mjsunit/regress/regress-1919169.js +++ b/deps/v8/test/mjsunit/regress/regress-1919169.js @@ -30,7 +30,7 @@ function test() { var s2 = "s2"; for (var i = 0; i < 2; i++) { // Crashes in round i==1 with IllegalAccess in %StringAdd(x,y) - var res = 1 + s2; + var res = 1 + s2; s2 = 2; } } diff --git a/deps/v8/test/mjsunit/regress/regress-20070207.js b/deps/v8/test/mjsunit/regress/regress-20070207.js index e90b2ec589..b7f7a5cc6f 100644 --- a/deps/v8/test/mjsunit/regress/regress-20070207.js +++ b/deps/v8/test/mjsunit/regress/regress-20070207.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // The following regression test illustrates a problem in using the -// value of setting a property in the arguments object. +// value of setting a property in the arguments object. function f(s) { arguments.length; diff --git a/deps/v8/test/mjsunit/regress/regress-269.js b/deps/v8/test/mjsunit/regress/regress-269.js index 49b24c0b43..ce165e0abf 100644 --- a/deps/v8/test/mjsunit/regress/regress-269.js +++ b/deps/v8/test/mjsunit/regress/regress-269.js @@ -40,10 +40,10 @@ Debug.setListener(listener); function g() { } - + function f() { debugger; g.apply(null, ['']); } -f()
\ No newline at end of file +f() diff --git a/deps/v8/test/mjsunit/regress/regress-619.js b/deps/v8/test/mjsunit/regress/regress-619.js index 24bdbc1879..4d3e66b298 100644 --- a/deps/v8/test/mjsunit/regress/regress-619.js +++ b/deps/v8/test/mjsunit/regress/regress-619.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Tests that Object.defineProperty works correctly on array indices. +// Tests that Object.defineProperty works correctly on array indices. // Please see http://code.google.com/p/v8/issues/detail?id=619 for details. var obj = {}; diff --git a/deps/v8/test/mjsunit/regress/regress-678525.js b/deps/v8/test/mjsunit/regress/regress-678525.js index 5ff9c3d9e4..11eaf74fc8 100644 --- a/deps/v8/test/mjsunit/regress/regress-678525.js +++ b/deps/v8/test/mjsunit/regress/regress-678525.js @@ -36,16 +36,16 @@ assertEquals(7, '\7'.charCodeAt(0)); assertEquals(56, '\8'.charCodeAt(0)); assertEquals('\010', '\10'); -assertEquals('\011', '\11'); +assertEquals('\011', '\11'); assertEquals('\012', '\12'); assertEquals('\013', '\13'); assertEquals('\014', '\14'); assertEquals('\015', '\15'); assertEquals('\016', '\16'); assertEquals('\017', '\17'); - + assertEquals('\020', '\20'); -assertEquals('\021', '\21'); +assertEquals('\021', '\21'); assertEquals('\022', '\22'); assertEquals('\023', '\23'); assertEquals('\024', '\24'); @@ -56,4 +56,4 @@ assertEquals('\027', '\27'); assertEquals(73, '\111'.charCodeAt(0)); assertEquals(105, '\151'.charCodeAt(0)); - + diff --git a/deps/v8/test/mjsunit/regress/regress-696.js b/deps/v8/test/mjsunit/regress/regress-696.js index 21977e1c82..e443c4243d 100644 --- a/deps/v8/test/mjsunit/regress/regress-696.js +++ b/deps/v8/test/mjsunit/regress/regress-696.js @@ -28,7 +28,7 @@ // See: http://code.google.com/p/v8/issues/detail?id=696 // Because of the change in dateparser in revision 4557 to support time // only strings in Date.parse we also misleadingly supported strings with non -// leading numbers. +// leading numbers. assertTrue(isNaN(Date.parse('x'))); assertTrue(isNaN(Date.parse('1x'))); diff --git a/deps/v8/test/mjsunit/regress/regress-720.js b/deps/v8/test/mjsunit/regress/regress-720.js index 97e1284e09..267b32d088 100644 --- a/deps/v8/test/mjsunit/regress/regress-720.js +++ b/deps/v8/test/mjsunit/regress/regress-720.js @@ -27,7 +27,7 @@ // This regression test is used to ensure that Object.defineProperty // keeps the existing value of the writable flag if none is given -// in the provided descriptor. +// in the provided descriptor. // See: http://code.google.com/p/v8/issues/detail?id=720 var o = {x: 10}; diff --git a/deps/v8/test/mjsunit/regress/regress-747.js b/deps/v8/test/mjsunit/regress/regress-747.js index 6fcc0000a6..648c36684c 100644 --- a/deps/v8/test/mjsunit/regress/regress-747.js +++ b/deps/v8/test/mjsunit/regress/regress-747.js @@ -40,7 +40,7 @@ try { callEval(); } catch (e) { assertUnreachable(); -} +} gc(); gc(); @@ -53,4 +53,4 @@ try { callEval(); } catch (e) { assertUnreachable(); -} +} diff --git a/deps/v8/test/mjsunit/regress/regress-760-1.js b/deps/v8/test/mjsunit/regress/regress-760-1.js index 2e0cee5f8f..081c99309d 100644 --- a/deps/v8/test/mjsunit/regress/regress-760-1.js +++ b/deps/v8/test/mjsunit/regress/regress-760-1.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Check that when valueOf for a String object is overwritten it is called and -// the result used when that object is added with a string. +// the result used when that object is added with a string. // See: http://code.google.com/p/v8/issues/detail?id=760 diff --git a/deps/v8/test/mjsunit/regress/regress-760-2.js b/deps/v8/test/mjsunit/regress/regress-760-2.js index 1b1cbfebed..549ed4ee41 100644 --- a/deps/v8/test/mjsunit/regress/regress-760-2.js +++ b/deps/v8/test/mjsunit/regress/regress-760-2.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Check that when valueOf for a String object is overwritten it is called and -// the result used when that object is added with a string. +// the result used when that object is added with a string. // See: http://code.google.com/p/v8/issues/detail?id=760 diff --git a/deps/v8/test/mjsunit/regress/regress-798.js b/deps/v8/test/mjsunit/regress/regress-798.js index ffee5da915..182eb4da77 100644 --- a/deps/v8/test/mjsunit/regress/regress-798.js +++ b/deps/v8/test/mjsunit/regress/regress-798.js @@ -32,7 +32,7 @@ x.__defineGetter__("a", function() { try { y.x = 40; } catch (e) { - assertEquals(3, e.stack.split('\n').length); + assertEquals(3, e.stack.split('\n').length); } return 40; }); @@ -41,7 +41,7 @@ x.__defineSetter__("a", function(val) { try { y.x = 40; } catch(e) { - assertEquals(3, e.stack.split('\n').length); + assertEquals(3, e.stack.split('\n').length); } }); @@ -50,7 +50,7 @@ function getB() { try { y.x = 30; } catch (e) { - assertEquals(3, e.stack.split('\n').length); + assertEquals(3, e.stack.split('\n').length); } return 30; } @@ -59,7 +59,7 @@ function setB(val) { try { y.x = 30; } catch(e) { - assertEquals(3, e.stack.split('\n').length); + assertEquals(3, e.stack.split('\n').length); } } @@ -72,7 +72,7 @@ var descriptor = { try { y.x = 40; } catch (e) { - assertEquals(3, e.stack.split('\n').length); + assertEquals(3, e.stack.split('\n').length); } return 40; }, @@ -80,7 +80,7 @@ var descriptor = { try { y.x = 40; } catch(e) { - assertEquals(3, e.stack.split('\n').length); + assertEquals(3, e.stack.split('\n').length); } } } @@ -88,7 +88,7 @@ var descriptor = { Object.defineProperty(x, 'c', descriptor) // Check that the stack for an exception in a getter and setter produce the -// expected stack height. +// expected stack height. x.a; x.b; x.c; diff --git a/deps/v8/test/mjsunit/regress/regress-918.js b/deps/v8/test/mjsunit/regress/regress-918.js index 4b6ddbacf8..871e9d9f3d 100644 --- a/deps/v8/test/mjsunit/regress/regress-918.js +++ b/deps/v8/test/mjsunit/regress/regress-918.js @@ -28,6 +28,6 @@ // Parser should not accept parentheses around labels. // See http://code.google.com/p/v8/issues/detail?id=918 -// The label was parsed as an expression and then tested for being a +// The label was parsed as an expression and then tested for being a // single identifier. This threw away the parentheses. assertThrows("(label):42;"); diff --git a/deps/v8/test/mjsunit/regress/regress-925537.js b/deps/v8/test/mjsunit/regress/regress-925537.js index 11582eaf90..d50c5689a5 100644 --- a/deps/v8/test/mjsunit/regress/regress-925537.js +++ b/deps/v8/test/mjsunit/regress/regress-925537.js @@ -28,8 +28,8 @@ function assertClose(expected, actual) { var delta = 0.00001; if (Math.abs(expected - actual) > delta) { - print('Failure: Expected <' + actual + '> to be close to <' + - expected + '>'); + print('Failure: Expected <' + actual + '> to be close to <' + + expected + '>'); } } diff --git a/deps/v8/test/mjsunit/regress/regress-937896.js b/deps/v8/test/mjsunit/regress/regress-937896.js index e8e5ef21b7..e7831da3c8 100644 --- a/deps/v8/test/mjsunit/regress/regress-937896.js +++ b/deps/v8/test/mjsunit/regress/regress-937896.js @@ -41,7 +41,7 @@ function f() { } } } catch (e) { - // Empty. + // Empty. } return 42; } diff --git a/deps/v8/test/mjsunit/regress/regress-94425.js b/deps/v8/test/mjsunit/regress/regress-94425.js new file mode 100644 index 0000000000..4a48f4ad5c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-94425.js @@ -0,0 +1,46 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --expose-gc + +var N = 2040 - 2 + 10; +var arr = new Array(N); + +gc(); +gc(); +gc(); + +// arr is in the large object space now. +// Write new space object into it. +arr[arr.length - 2] = new Object; + +// Shift array multiple times to ensure that young +// object crosses region boundary. +for (var i = 0; i < 9; i++) arr.shift(); + +// Do a GC to verify region dirty marks. +gc(); diff --git a/deps/v8/test/mjsunit/regress/regress-95113.js b/deps/v8/test/mjsunit/regress/regress-95113.js new file mode 100644 index 0000000000..f01b27004c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-95113.js @@ -0,0 +1,48 @@ +// 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. + +// Flags: --allow-natives-syntax + +function get_double_array() { + var a = new Array(100000); + var i = 0; + while (!%HasFastDoubleElements(a)) { + a[i] = i; + i++; + } + assertTrue(%HasFastDoubleElements(a)); + a.length = 1; + a[0] = 1.5; + a.length = 2; + a[1] = 2.5; + assertEquals(a[0], 1.5); + assertEquals(a[1], 2.5); + assertTrue(%HasFastDoubleElements(a)); + return a; +} + +var a = get_double_array(); diff --git a/deps/v8/test/mjsunit/regress/regress-95485.js b/deps/v8/test/mjsunit/regress/regress-95485.js new file mode 100644 index 0000000000..2510072e0b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-95485.js @@ -0,0 +1,42 @@ +// 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. + +function Test() { + var left = 'XXX'; + var right = 'YYY'; + for (var i = 0; i < 3; i++) { + var cons = left + right; + var substring = cons.substring(2, 4); + try { + with ({Test: i}) + continue; + } finally { } + } + return substring; +} + +assertEquals('XY', Test()); diff --git a/deps/v8/test/mjsunit/regress/regress-fundecl.js b/deps/v8/test/mjsunit/regress/regress-fundecl.js new file mode 100644 index 0000000000..fddb5895eb --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-fundecl.js @@ -0,0 +1,44 @@ +// 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. + +// Flags: --allow-natives-syntax + +// Test hoisting of function declarations in the optimizing +// compiler in case of deoptimization. + +function h(a, b) { + var r = a + b; + function X() { return 42; } + return r + X(); +} + +for (var i = 0; i < 5; i++) h(1,2); + +%OptimizeFunctionOnNextCall(h); + +assertEquals(45, h(1,2)); +assertEquals("foo742", h("foo", 7)); diff --git a/deps/v8/test/mjsunit/setter-on-constructor-prototype.js b/deps/v8/test/mjsunit/setter-on-constructor-prototype.js index d5718f9c9b..a74f7da7b3 100644 --- a/deps/v8/test/mjsunit/setter-on-constructor-prototype.js +++ b/deps/v8/test/mjsunit/setter-on-constructor-prototype.js @@ -35,14 +35,14 @@ function RunTest(ensure_fast_case) { if (ensure_fast_case) { %ToFastProperties(C1.prototype); } - + for (var i = 0; i < 10; i++) { var c1 = new C1(); assertEquals("undefined", typeof c1.x); assertEquals(23, c1.y); } - - + + function C2() { this.x = 23; }; @@ -51,14 +51,14 @@ function RunTest(ensure_fast_case) { if (ensure_fast_case) { %ToFastProperties(C2.prototype.__proto__) } - + for (var i = 0; i < 10; i++) { var c2 = new C2(); assertEquals("undefined", typeof c2.x); assertEquals(23, c2.y); } - - + + function C3() { this.x = 23; }; @@ -67,14 +67,14 @@ function RunTest(ensure_fast_case) { if (ensure_fast_case) { %ToFastProperties(C3.prototype); } - + for (var i = 0; i < 10; i++) { var c3 = new C3(); assertEquals("undefined", typeof c3.x); assertEquals(23, c3.y); } - - + + function C4() { this.x = 23; }; @@ -84,14 +84,14 @@ function RunTest(ensure_fast_case) { if (ensure_fast_case) { %ToFastProperties(C4.prototype.__proto__); } - + for (var i = 0; i < 10; i++) { var c4 = new C4(); assertEquals("undefined", typeof c4.x); assertEquals(23, c4.y); } - - + + function D() { this.x = 23; }; @@ -99,7 +99,7 @@ function RunTest(ensure_fast_case) { if (ensure_fast_case) { %ToFastProperties(D.prototype); } - + for (var i = 0; i < 10; i++) { var d = new D(); assertEquals(23, d.x); diff --git a/deps/v8/test/mjsunit/string-compare-alignment.js b/deps/v8/test/mjsunit/string-compare-alignment.js index a291417ba5..0ae8eb7910 100644 --- a/deps/v8/test/mjsunit/string-compare-alignment.js +++ b/deps/v8/test/mjsunit/string-compare-alignment.js @@ -29,8 +29,9 @@ // This situation can arise with sliced strings. This tests for an ARM bug // that was fixed in r554. -var base = "Now is the time for all good men to come to the aid of the party. " + - "Now is the time for all good men to come to the aid of the party." +var base = + "Now is the time for all good men to come to the aid of the party. " + + "Now is the time for all good men to come to the aid of the party." var s1 = base.substring(0, 64); var s2 = base.substring(66, 130); diff --git a/deps/v8/test/mjsunit/string-indexof-1.js b/deps/v8/test/mjsunit/string-indexof-1.js index c5ae4b898a..db3623f7c0 100644 --- a/deps/v8/test/mjsunit/string-indexof-1.js +++ b/deps/v8/test/mjsunit/string-indexof-1.js @@ -63,7 +63,7 @@ assertEquals(1, twoByteString.indexOf("\u0391"), "Alpha"); assertEquals(2, twoByteString.indexOf("\u03a3"), "First Sigma"); assertEquals(3, twoByteString.indexOf("\u03a3",3), "Second Sigma"); assertEquals(4, twoByteString.indexOf("\u0395"), "Epsilon"); -assertEquals(-1, twoByteString.indexOf("\u0392"), "Not beta"); +assertEquals(-1, twoByteString.indexOf("\u0392"), "Not beta"); // Test multi-char pattern assertEquals(0, twoByteString.indexOf("\u039a\u0391"), "lambda Alpha"); @@ -71,7 +71,7 @@ assertEquals(1, twoByteString.indexOf("\u0391\u03a3"), "Alpha Sigma"); assertEquals(2, twoByteString.indexOf("\u03a3\u03a3"), "Sigma Sigma"); assertEquals(3, twoByteString.indexOf("\u03a3\u0395"), "Sigma Epsilon"); -assertEquals(-1, twoByteString.indexOf("\u0391\u03a3\u0395"), +assertEquals(-1, twoByteString.indexOf("\u0391\u03a3\u0395"), "Not Alpha Sigma Epsilon"); //single char pattern diff --git a/deps/v8/test/mjsunit/string-indexof-2.js b/deps/v8/test/mjsunit/string-indexof-2.js index a7c3f600a1..48db84d26e 100644 --- a/deps/v8/test/mjsunit/string-indexof-2.js +++ b/deps/v8/test/mjsunit/string-indexof-2.js @@ -57,10 +57,10 @@ for(var i = 0; i < lipsum.length; i += 3) { var index = -1; do { index = lipsum.indexOf(substring, index + 1); - assertTrue(index != -1, + assertTrue(index != -1, "Lipsum substring " + i + ".." + (i + len-1) + " not found"); - assertEquals(lipsum.substring(index, index + len), substring, - "Wrong lipsum substring found: " + i + ".." + (i + len - 1) + "/" + + assertEquals(lipsum.substring(index, index + len), substring, + "Wrong lipsum substring found: " + i + ".." + (i + len - 1) + "/" + index + ".." + (index + len - 1)); } while (index >= 0 && index < i); assertEquals(i, index, "Lipsum match at " + i + ".." + (i + len - 1)); diff --git a/deps/v8/test/mjsunit/string-slices.js b/deps/v8/test/mjsunit/string-slices.js index b0b05eca36..8cc1f81e77 100755 --- a/deps/v8/test/mjsunit/string-slices.js +++ b/deps/v8/test/mjsunit/string-slices.js @@ -57,7 +57,7 @@ assertEquals(s, s.substr(-100)); assertEquals('abc', s.substr(-100, 3)); assertEquals(s1, s.substr(-s.length + 1)); -// assertEquals('', s.substr(0, void 0)); // smjs and rhino +// assertEquals('', s.substr(0, void 0)); // smjs and rhino assertEquals('abcdefghijklmn', s.substr(0, void 0)); // kjs and v8 assertEquals('', s.substr(0, null)); assertEquals(s, s.substr(0, String(s.length))); @@ -72,7 +72,7 @@ for (var i = 0; i < 25; i++) { } /x/.exec(x); // Try to force a flatten. for (var i = 5; i < 25; i++) { - for (var j = 12; j < 25; j++) { + for (var j = 0; j < 25; j++) { var z = x.substring(i, i+j); var w = Math.random() * 42; // Allocate something new in new-space. assertEquals(j, z.length); @@ -110,7 +110,7 @@ x += x; x += x; var xl = x.length; var cache = []; -for (var i = 0; i < 10000; i++) { +for (var i = 0; i < 1000; i++) { var z = x.substring(i % xl); assertEquals(xl - (i % xl), z.length); cache.push(z); @@ -129,7 +129,7 @@ x += x; x += x; var xl = x.length; var cache = []; -for (var i = 0; i < 10000; i++) { +for (var i = 0; i < 1000; i++) { var z = x.substring(i % xl); assertEquals(xl - (i % xl), z.length); cache.push(z); @@ -149,6 +149,7 @@ for (var i = 63; i >= 0; i--) { var z = cache.pop(); assertTrue(/\u2028123456789ABCDEF/.test(z)); assertEquals(xl - offset, z.length); + assertEquals(x.charAt(i*(i+1)/2), z.charAt(0)); offset -= i; } @@ -195,4 +196,4 @@ var b = a.slice(1,-1); assertEquals(a.slice(1,-1), b); externalizeString(a); assertEquals(a.slice(1,-1), b); -*/
\ No newline at end of file +*/ diff --git a/deps/v8/test/mjsunit/string-split.js b/deps/v8/test/mjsunit/string-split.js index bc50945135..d8412f0eed 100644 --- a/deps/v8/test/mjsunit/string-split.js +++ b/deps/v8/test/mjsunit/string-split.js @@ -68,13 +68,13 @@ assertArrayEquals(["a", "b", "c"], "abc".split(/(?=.)/)); /* "ab".split(/((?=.))/) - * + * * KJS: ,a,,b * SM: a,,b, * IE: a,b * Opera: a,,b * V8: a,,b - * + * * Opera seems to have this right. The others make no sense. */ assertArrayEquals(["a", "", "b"], "ab".split(/((?=.))/)); diff --git a/deps/v8/test/mjsunit/substr.js b/deps/v8/test/mjsunit/substr.js index cffaf94da2..cab8b1bf6d 100755 --- a/deps/v8/test/mjsunit/substr.js +++ b/deps/v8/test/mjsunit/substr.js @@ -55,7 +55,7 @@ assertEquals(s, s.substr(-100)); assertEquals('abc', s.substr(-100, 3)); assertEquals(s1, s.substr(-s.length + 1)); -// assertEquals('', s.substr(0, void 0)); // smjs and rhino +// assertEquals('', s.substr(0, void 0)); // smjs and rhino assertEquals('abcdefghijklmn', s.substr(0, void 0)); // kjs and v8 assertEquals('', s.substr(0, null)); assertEquals(s, s.substr(0, String(s.length))); diff --git a/deps/v8/test/mjsunit/this-property-assignment.js b/deps/v8/test/mjsunit/this-property-assignment.js index c6819996c0..54c6537256 100644 --- a/deps/v8/test/mjsunit/this-property-assignment.js +++ b/deps/v8/test/mjsunit/this-property-assignment.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Tests the handling of multiple assignments to the same property in a +// Tests the handling of multiple assignments to the same property in a // constructor that only has simple this property assignments. function Node() { diff --git a/deps/v8/test/mjsunit/try.js b/deps/v8/test/mjsunit/try.js index 794860a7c6..86afdf7f08 100644 --- a/deps/v8/test/mjsunit/try.js +++ b/deps/v8/test/mjsunit/try.js @@ -250,7 +250,7 @@ function break_from_nested_catch(x) { } catch (o) { x--; } - } + } return x; } @@ -274,7 +274,7 @@ function break_from_nested_finally(x) { x--; } x--; // should not happen - } + } return x; } diff --git a/deps/v8/test/mjsunit/unicode-test.js b/deps/v8/test/mjsunit/unicode-test.js index 59a684e053..66a029a7ef 100644 --- a/deps/v8/test/mjsunit/unicode-test.js +++ b/deps/v8/test/mjsunit/unicode-test.js @@ -807,7 +807,7 @@ var cyrillic = " * Васильев Л.С. Древний Китай: в 3 т. Т. 3. Период Чжаньго (V–III вв. до н.э.). М.: Восточная литература, 2006. ISBN 502018103X\n" + " * Непомнин О.Е. История Китая: Эпоха Цин. XVII – начало XX века. М.: Восточная литература, 2005. ISBN 5020184004\n"; -var devanagari = +var devanagari = "भारत\n" + "विकिपीडिया, एक मुक्त ज्ञानकोष से\n" + "Jump to: navigation, search\n" + @@ -1417,7 +1417,7 @@ var english = "There are many words of French origin in English, such as competition, art, table, publicity, police, role, routine, machine, force, and many others that have been and are being anglicised; they are now pronounced according to English rules of phonology, rather than French. A large portion of English vocabulary is of French or Oïl language origin, most derived from, or transmitted via, the Anglo-Norman spoken by the upper classes in England for several hundred years after the Norman Conquest.\n"; -var greek = +var greek = "Ελλάδα\n" + "Από τη Βικιπαίδεια, την ελεύθερη εγκυκλοπαίδεια\n" + "Ελληνική Δημοκρατία\n" + diff --git a/deps/v8/test/mjsunit/value-wrapper.js b/deps/v8/test/mjsunit/value-wrapper.js index 88330b4497..76e200f36e 100644 --- a/deps/v8/test/mjsunit/value-wrapper.js +++ b/deps/v8/test/mjsunit/value-wrapper.js @@ -39,7 +39,7 @@ function RunTests() { assertEquals('object', (42).TypeOfThis()); assertEquals('object', (3.14).TypeOfThis()); } - + for (var i = 0; i < 10; i++) { assertEquals('object', 'xxx'['TypeOfThis']()); assertEquals('object', true['TypeOfThis']()); @@ -47,11 +47,11 @@ function RunTests() { assertEquals('object', (42)['TypeOfThis']()); assertEquals('object', (3.14)['TypeOfThis']()); } - + function CallTypeOfThis(obj) { assertEquals('object', obj.TypeOfThis()); } - + for (var i = 0; i < 10; i++) { CallTypeOfThis('xxx'); CallTypeOfThis(true); @@ -59,7 +59,7 @@ function RunTests() { CallTypeOfThis(42); CallTypeOfThis(3.14); } - + function TestWithWith(obj) { with (obj) { for (var i = 0; i < 10; i++) { @@ -67,13 +67,13 @@ function RunTests() { } } } - + TestWithWith('xxx'); TestWithWith(true); TestWithWith(false); TestWithWith(42); TestWithWith(3.14); - + for (var i = 0; i < 10; i++) { assertEquals('object', true[7]()); assertEquals('object', false[7]()); @@ -100,7 +100,7 @@ function RunTests() { function TypeOfThis() { return typeof this; } -// Test with normal setup of prototype. +// Test with normal setup of prototype. String.prototype.TypeOfThis = TypeOfThis; Boolean.prototype.TypeOfThis = TypeOfThis; Number.prototype.TypeOfThis = TypeOfThis; diff --git a/deps/v8/test/mozilla/mozilla.status b/deps/v8/test/mozilla/mozilla.status index f6d69257c6..3a27130990 100644 --- a/deps/v8/test/mozilla/mozilla.status +++ b/deps/v8/test/mozilla/mozilla.status @@ -201,6 +201,10 @@ js1_5/extensions/regress-363258: PASS || FAIL ecma_3/RegExp/regress-85721: PASS || FAIL if $mode == debug +# Test that assumes specific execution time, flaky in debug mode. +js1_5/Array/regress-101964: PASS || FAIL if $mode == debug + + ##################### INCOMPATIBLE TESTS ##################### # This section is for tests that fail in both V8 and JSC. Thus they @@ -245,7 +249,7 @@ ecma_3/Number/15.7.4.7-1: FAIL_OK # toExponential argument restricted to range 0..20 in JSC/V8 ecma_3/Number/15.7.4.6-1: FAIL_OK -#:=== RegExp:=== +#:=== RegExp:=== # We don't match the syntax error message of Mozilla for invalid # RegExp flags. ecma_3/RegExp/15.10.4.1-6: FAIL_OK @@ -578,7 +582,7 @@ js1_5/Regress/regress-352604: FAIL_OK js1_5/Regress/regress-417893: FAIL_OK -# Unsupported use of "[]" as function parameter. We match JSC. +# Unsupported use of "[]" as function parameter. We match JSC. js1_5/Regress/regress-416737-01: FAIL_OK js1_5/Regress/regress-416737-02: FAIL_OK diff --git a/deps/v8/tools/gdb-v8-support.py b/deps/v8/tools/gdb-v8-support.py index 0aa1d49467..9cc046c7a5 100644 --- a/deps/v8/tools/gdb-v8-support.py +++ b/deps/v8/tools/gdb-v8-support.py @@ -138,7 +138,7 @@ def v8_to_int(v): else: return '?' - + def v8_get_value(vstring): v = gdb.parse_and_eval(vstring) return v8_to_int(v) diff --git a/deps/v8/tools/presubmit.py b/deps/v8/tools/presubmit.py index c191fc7497..50d2620162 100755 --- a/deps/v8/tools/presubmit.py +++ b/deps/v8/tools/presubmit.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2008 the V8 project authors. All rights reserved. +# 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: @@ -42,6 +42,7 @@ import pickle import re import sys import subprocess +from subprocess import PIPE # Disabled LINT rules and reason. # build/include_what_you_use: Started giving false positives for variables @@ -88,7 +89,6 @@ whitespace/blank_line whitespace/braces whitespace/comma whitespace/comments -whitespace/end_of_line whitespace/ending_newline whitespace/indent whitespace/labels @@ -231,11 +231,29 @@ COPYRIGHT_HEADER_PATTERN = re.compile( class SourceProcessor(SourceFileProcessor): """ - Check that all files include a copyright notice. + Check that all files include a copyright notice and no trailing whitespaces. """ RELEVANT_EXTENSIONS = ['.js', '.cc', '.h', '.py', '.c', 'SConscript', - 'SConstruct', '.status'] + 'SConstruct', '.status', '.gyp', '.gypi'] + + # Overwriting the one in the parent class. + def FindFilesIn(self, path): + if os.path.exists(path+'/.git'): + output = subprocess.Popen('git ls-files --full-name', + stdout=PIPE, cwd=path, shell=True) + result = [] + for file in output.stdout.read().split(): + for dir_part in os.path.dirname(file).split(os.sep): + if self.IgnoreDir(dir_part): + break + else: + if self.IsRelevant(file) and not self.IgnoreFile(file): + result.append(join(path, file)) + if output.wait() == 0: + return result + return super(SourceProcessor, self).FindFilesIn(path) + def IsRelevant(self, name): for ext in SourceProcessor.RELEVANT_EXTENSIONS: if name.endswith(ext): @@ -273,6 +291,22 @@ class SourceProcessor(SourceFileProcessor): if not COPYRIGHT_HEADER_PATTERN.search(contents): print "%s is missing a correct copyright header." % name result = False + ext = base.split('.').pop() + if ' \n' in contents or contents.endswith(' '): + line = 0 + lines = [] + parts = contents.split(' \n') + if not contents.endswith(' '): + parts.pop() + for part in parts: + line += part.count('\n') + 1 + lines.append(str(line)) + linenumbers = ', '.join(lines) + if len(lines) > 1: + print "%s has trailing whitespaces in lines %s." % (name, linenumbers) + else: + print "%s has trailing whitespaces in line %s." % (name, linenumbers) + result = False return result def ProcessFiles(self, files, path): diff --git a/deps/v8/tools/process-heap-prof.py b/deps/v8/tools/process-heap-prof.py index 6a2c3978d2..a26cbf1589 100755 --- a/deps/v8/tools/process-heap-prof.py +++ b/deps/v8/tools/process-heap-prof.py @@ -47,7 +47,7 @@ def ProcessLogFile(filename, options): itemname = 'heap-js-cons-item' else: itemname = 'heap-sample-item' - + first_call_time = None sample_time = 0.0 sampling = False @@ -108,11 +108,11 @@ def Main(): if not ProcessOptions(options): parser.print_help() sys.exit(); - + if not args: print "Missing logfile" sys.exit(); - + ProcessLogFile(args[0], options) diff --git a/deps/v8/tools/test-wrapper-gypbuild.py b/deps/v8/tools/test-wrapper-gypbuild.py index 9bc6bf6ac7..ad5449a404 100755 --- a/deps/v8/tools/test-wrapper-gypbuild.py +++ b/deps/v8/tools/test-wrapper-gypbuild.py @@ -53,6 +53,9 @@ def BuildOptions(): result.add_option("--outdir", help='Base output directory', default='out') + result.add_option("--no-presubmit", + help='Skip presubmit checks', + default=False, action="store_true") # Flags this wrapper script handles itself: result.add_option("-m", "--mode", @@ -202,22 +205,31 @@ def Main(): return 1 workspace = abspath(join(dirname(sys.argv[0]), '..')) + + if not options.no_presubmit: + print ">>> running presubmit tests" + subprocess.call([workspace + '/tools/presubmit.py']) + args_for_children = [workspace + '/tools/test.py'] + PassOnOptions(options) args_for_children += ['--no-build', '--build-system=gyp'] for arg in args: args_for_children += [arg] returncodes = 0 + env = os.environ for mode in options.mode: for arch in options.arch: print ">>> running tests for %s.%s" % (arch, mode) - shell = workspace + '/' + options.outdir + '/' + arch + '.' + mode + "/d8" + shellpath = workspace + '/' + options.outdir + '/' + arch + '.' + mode + env['LD_LIBRARY_PATH'] = shellpath + '/lib.target' + shell = shellpath + "/d8" child = subprocess.Popen(' '.join(args_for_children + ['--arch=' + arch] + ['--mode=' + mode] + ['--shell=' + shell]), shell=True, - cwd=workspace) + cwd=workspace, + env=env) returncodes += child.wait() return returncodes diff --git a/deps/v8/tools/test.py b/deps/v8/tools/test.py index d40159c6f2..ecc0062da5 100755 --- a/deps/v8/tools/test.py +++ b/deps/v8/tools/test.py @@ -1164,6 +1164,7 @@ def ReadConfigurationInto(path, sections, defs): ARCH_GUESS = utils.GuessArchitecture() +TIMEOUT_DEFAULT = 60; def BuildOptions(): @@ -1188,7 +1189,7 @@ def BuildOptions(): result.add_option("-s", "--suite", help="A test suite", default=[], action="append") result.add_option("-t", "--timeout", help="Timeout in seconds", - default=60, type="int") + default=-1, type="int") result.add_option("--arch", help='The architecture to run tests for', default='none') result.add_option("--snapshot", help="Run the tests with snapshot turned on", @@ -1262,6 +1263,12 @@ def ProcessOptions(options): if options.arch == 'none': options.arch = ARCH_GUESS options.scons_flags.append("arch=" + options.arch) + # Simulators are slow, therefore allow a longer default timeout. + if options.timeout == -1: + if options.arch == 'arm' or options.arch == 'mips': + options.timeout = 2 * TIMEOUT_DEFAULT; + else: + options.timeout = TIMEOUT_DEFAULT; if options.snapshot: options.scons_flags.append("snapshot=on") global VARIANT_FLAGS |