From 05e6f318c6ecccea73698367010e51812c5b3862 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 18 Aug 2011 16:59:21 -0700 Subject: [PATCH] Upgrade V8 to 3.5.6 --- deps/v8/.gitignore | 1 + deps/v8/ChangeLog | 28 ++ deps/v8/include/v8.h | 18 +- deps/v8/src/api.cc | 12 +- deps/v8/src/apinatives.js | 14 +- deps/v8/src/arm/code-stubs-arm.cc | 68 +-- deps/v8/src/arm/deoptimizer-arm.cc | 2 + deps/v8/src/arm/frames-arm.h | 11 +- deps/v8/src/arm/full-codegen-arm.cc | 16 +- deps/v8/src/arm/lithium-arm.cc | 20 +- deps/v8/src/arm/lithium-arm.h | 23 +- deps/v8/src/arm/lithium-codegen-arm.cc | 108 ++--- deps/v8/src/arm/macro-assembler-arm.cc | 86 ++-- deps/v8/src/arm/stub-cache-arm.cc | 46 +-- deps/v8/src/ast-inl.h | 3 +- deps/v8/src/ast.cc | 2 +- deps/v8/src/ast.h | 22 +- deps/v8/src/bootstrapper.cc | 11 +- deps/v8/src/code-stubs.cc | 20 +- deps/v8/src/code-stubs.h | 6 +- deps/v8/src/compiler.cc | 10 +- deps/v8/src/contexts.cc | 23 +- deps/v8/src/contexts.h | 4 + deps/v8/src/d8.cc | 1 + deps/v8/src/d8.h | 4 - deps/v8/src/d8.js | 3 +- deps/v8/src/disassembler.cc | 36 +- deps/v8/src/elements.cc | 80 ++-- deps/v8/src/elements.h | 4 +- .../experimental/datetime-format.cc | 2 +- deps/v8/src/factory.cc | 22 + deps/v8/src/factory.h | 7 + deps/v8/src/flag-definitions.h | 2 + deps/v8/src/frames-inl.h | 9 +- deps/v8/src/frames.h | 3 +- deps/v8/src/full-codegen.cc | 96 ++++- deps/v8/src/full-codegen.h | 53 ++- deps/v8/src/heap.cc | 43 ++ deps/v8/src/heap.h | 14 +- deps/v8/src/hydrogen-instructions.cc | 37 +- deps/v8/src/hydrogen-instructions.h | 36 +- deps/v8/src/hydrogen.cc | 37 +- deps/v8/src/hydrogen.h | 3 + deps/v8/src/ia32/assembler-ia32.cc | 12 + deps/v8/src/ia32/assembler-ia32.h | 10 + deps/v8/src/ia32/code-stubs-ia32.cc | 80 ++-- deps/v8/src/ia32/disasm-ia32.cc | 12 +- deps/v8/src/ia32/frames-ia32.h | 11 +- deps/v8/src/ia32/full-codegen-ia32.cc | 17 +- deps/v8/src/ia32/lithium-codegen-ia32.cc | 162 ++++---- deps/v8/src/ia32/lithium-codegen-ia32.h | 2 +- deps/v8/src/ia32/lithium-ia32.cc | 26 +- deps/v8/src/ia32/lithium-ia32.h | 33 +- deps/v8/src/ia32/macro-assembler-ia32.cc | 53 ++- deps/v8/src/ia32/stub-cache-ia32.cc | 97 ++--- deps/v8/src/isolate.cc | 6 + deps/v8/src/liveobjectlist.cc | 194 +++++---- deps/v8/src/liveobjectlist.h | 4 +- deps/v8/src/messages.js | 1 + deps/v8/src/mips/frames-mips.h | 9 +- deps/v8/src/mips/full-codegen-mips.cc | 10 +- deps/v8/src/mips/macro-assembler-mips.cc | 92 ++--- deps/v8/src/mips/stub-cache-mips.cc | 10 +- deps/v8/src/mirror-debugger.js | 3 +- deps/v8/src/mksnapshot.cc | 2 - deps/v8/src/objects-inl.h | 22 +- deps/v8/src/objects.cc | 39 +- deps/v8/src/objects.h | 49 +-- deps/v8/src/parser.cc | 282 +++++++------ deps/v8/src/parser.h | 22 +- deps/v8/src/platform-linux.cc | 2 + deps/v8/src/preparser-api.cc | 1 + deps/v8/src/preparser.cc | 56 ++- deps/v8/src/preparser.h | 18 +- deps/v8/src/prettyprinter.cc | 19 +- deps/v8/src/rewriter.cc | 10 +- deps/v8/src/runtime-profiler.h | 6 - deps/v8/src/runtime.cc | 83 +++- deps/v8/src/runtime.h | 1 + deps/v8/src/scanner-base.cc | 136 +++--- deps/v8/src/scanner-base.h | 11 + deps/v8/src/scopeinfo.cc | 2 +- deps/v8/src/scopeinfo.h | 2 +- deps/v8/src/scopes.cc | 66 ++- deps/v8/src/scopes.h | 12 +- deps/v8/src/serialize.cc | 58 +-- deps/v8/src/serialize.h | 47 +++ deps/v8/src/token.h | 1 + deps/v8/src/variables.cc | 3 +- deps/v8/src/variables.h | 13 +- deps/v8/src/version.cc | 4 +- deps/v8/src/weakmap.js | 11 +- deps/v8/src/x64/code-stubs-x64.cc | 78 ++-- deps/v8/src/x64/frames-x64.h | 13 +- deps/v8/src/x64/full-codegen-x64.cc | 16 +- deps/v8/src/x64/lithium-codegen-x64.cc | 129 +++--- deps/v8/src/x64/lithium-codegen-x64.h | 2 +- deps/v8/src/x64/lithium-x64.cc | 27 +- deps/v8/src/x64/lithium-x64.h | 33 +- deps/v8/src/x64/macro-assembler-x64.cc | 69 ++-- deps/v8/src/x64/stub-cache-x64.cc | 4 +- deps/v8/src/zone.cc | 53 ++- deps/v8/src/zone.h | 6 +- deps/v8/test/cctest/test-accessors.cc | 2 - deps/v8/test/cctest/test-api.cc | 113 ++--- deps/v8/test/cctest/test-circular-queue.cc | 2 - deps/v8/test/cctest/test-cpu-profiler.cc | 2 - deps/v8/test/cctest/test-heap-profiler.cc | 2 - deps/v8/test/cctest/test-lockers.cc | 4 - deps/v8/test/cctest/test-log-stack-tracer.cc | 2 - deps/v8/test/cctest/test-log.cc | 2 - deps/v8/test/cctest/test-parsing.cc | 8 +- deps/v8/test/cctest/test-profile-generator.cc | 2 - deps/v8/test/cctest/test-unbound-queue.cc | 2 - .../mjsunit/bugs/harmony/debug-blockscopes.js | 224 ++++++++++ deps/v8/test/mjsunit/external-array.js | 20 + deps/v8/test/mjsunit/fuzz-natives.js | 1 + .../mjsunit/harmony/block-lazy-compile.js | 50 +++ .../mjsunit/harmony/block-let-declaration.js | 67 +++ deps/v8/test/mjsunit/harmony/block-scoping.js | 216 ++++++++++ .../test/mjsunit/harmony/debug-blockscopes.js | 389 ++++++++++++++++++ .../harmony/debug-evaluate-blockscopes.js | 64 +++ deps/v8/test/mjsunit/harmony/typeof.js | 35 ++ deps/v8/test/mjsunit/harmony/weakmaps.js | 17 + deps/v8/test/mjsunit/math-floor.js | 34 +- deps/v8/test/mjsunit/math-round.js | 25 +- deps/v8/test/mjsunit/regress/regress-1592.js | 45 ++ deps/v8/test/mjsunit/with-leave.js | 161 +++++++- deps/v8/tools/gyp/v8.gyp | 1 - 129 files changed, 3261 insertions(+), 1527 deletions(-) create mode 100644 deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js create mode 100644 deps/v8/test/mjsunit/harmony/block-lazy-compile.js create mode 100644 deps/v8/test/mjsunit/harmony/block-let-declaration.js create mode 100644 deps/v8/test/mjsunit/harmony/block-scoping.js create mode 100644 deps/v8/test/mjsunit/harmony/debug-blockscopes.js create mode 100644 deps/v8/test/mjsunit/harmony/debug-evaluate-blockscopes.js create mode 100644 deps/v8/test/mjsunit/harmony/typeof.js create mode 100644 deps/v8/test/mjsunit/regress/regress-1592.js diff --git a/deps/v8/.gitignore b/deps/v8/.gitignore index d09889b90e..253639dc5d 100644 --- a/deps/v8/.gitignore +++ b/deps/v8/.gitignore @@ -21,6 +21,7 @@ shell shell_g /build/gyp /obj/ +/out/ /test/es5conform/data/ /test/mozilla/data/ /test/sputnik/sputniktests/ diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index d05b70eae7..6d188b89d1 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,31 @@ +2011-08-17: Version 3.5.6 + + Fixed issue that could cause crashes when running with --heap-stats. + + Fixed compilation on Linux 2.6.9 and older. + + Fixed live-object-list to work with isolates. + + Fixed memory leaks in zones and isolates. + + Fixed a performance regression for TypedArrays on x64. + + Stability improvements on all platforms. + + +2011-08-15: Version 3.5.5 + + Fixed bugs involving negative zero and the optimizing compiler. + + Fixed optimized version of Function.apply(x, arguments). (issue 1592) + + Eliminated uses of deprecated ARM instructions. + + Sped up Math.floor by using SSE 4.1 roundsd instruction on ia32. + + Removed restriction on the size of disassembled code that is printed. + + 2011-08-10: Version 3.5.4 Added a preliminary implementation of ES Harmony weak maps. Weak diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index d1bceca3f6..e722d34e67 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -171,12 +171,12 @@ template class Handle { /** * Creates an empty handle. */ - inline Handle(); + inline Handle() : val_(0) {} /** * Creates a new handle for the specified value. */ - inline explicit Handle(T* val) : val_(val) { } + inline explicit Handle(T* val) : val_(val) {} /** * Creates a handle for the contents of the specified handle. This @@ -203,14 +203,14 @@ template class Handle { */ inline bool IsEmpty() const { return val_ == 0; } - inline T* operator->() const { return val_; } - - inline T* operator*() const { return val_; } - /** * Sets the handle to be empty. IsEmpty() will then return true. */ - inline void Clear() { this->val_ = 0; } + inline void Clear() { val_ = 0; } + + inline T* operator->() const { return val_; } + + inline T* operator*() const { return val_; } /** * Checks whether two handles are the same. @@ -3826,10 +3826,6 @@ class Internals { } // namespace internal -template -Handle::Handle() : val_(0) { } - - template Local::Local() : Handle() { } diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 7355cd61c5..5a5f14dc65 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -35,6 +35,7 @@ #include "debug.h" #include "deoptimizer.h" #include "execution.h" +#include "flags.h" #include "global-handles.h" #include "heap-profiler.h" #include "messages.h" @@ -1405,7 +1406,7 @@ void ObjectTemplate::SetInternalFieldCount(int value) { ScriptData* ScriptData::PreCompile(const char* input, int length) { i::Utf8ToUC16CharacterStream stream( reinterpret_cast(input), length); - return i::ParserApi::PreParse(&stream, NULL); + return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping); } @@ -1414,10 +1415,10 @@ ScriptData* ScriptData::PreCompile(v8::Handle source) { if (str->IsExternalTwoByteString()) { i::ExternalTwoByteStringUC16CharacterStream stream( i::Handle::cast(str), 0, str->length()); - return i::ParserApi::PreParse(&stream, NULL); + return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping); } else { i::GenericStringUC16CharacterStream stream(str, 0, str->length()); - return i::ParserApi::PreParse(&stream, NULL); + return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping); } } @@ -3163,10 +3164,9 @@ static i::Context* GetCreationContext(i::JSObject* object) { i::Object* constructor = object->map()->constructor(); i::JSFunction* function; if (!constructor->IsJSFunction()) { - // API functions have null as a constructor, + // Functions have null as a constructor, // but any JSFunction knows its context immediately. - ASSERT(object->IsJSFunction() && - i::JSFunction::cast(object)->shared()->IsApiFunction()); + ASSERT(object->IsJSFunction()); function = i::JSFunction::cast(object); } else { function = i::JSFunction::cast(constructor); diff --git a/deps/v8/src/apinatives.js b/deps/v8/src/apinatives.js index c00195d831..e94da9f065 100644 --- a/deps/v8/src/apinatives.js +++ b/deps/v8/src/apinatives.js @@ -49,7 +49,10 @@ function Instantiate(data, name) { return InstantiateFunction(data, name); case kNewObjectTag: var Constructor = %GetTemplateField(data, kApiConstructorOffset); - var result = Constructor ? new (Instantiate(Constructor))() : {}; + // Note: Do not directly use a function template as a condition, our + // internal ToBoolean doesn't handle that! + var result = typeof Constructor === 'undefined' ? + {} : new (Instantiate(Constructor))(); ConfigureTemplateInstance(result, data); result = %ToFastProperties(result); return result; @@ -74,13 +77,18 @@ function InstantiateFunction(data, name) { cache[serialNumber] = fun; var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset); var flags = %GetTemplateField(data, kApiFlagOffset); - fun.prototype = prototype ? Instantiate(prototype) : {}; + // Note: Do not directly use an object template as a condition, our + // internal ToBoolean doesn't handle that! + fun.prototype = typeof prototype === 'undefined' ? + {} : Instantiate(prototype); if (flags & (1 << kReadOnlyPrototypeBit)) { %FunctionSetReadOnlyPrototype(fun); } %SetProperty(fun.prototype, "constructor", fun, DONT_ENUM); var parent = %GetTemplateField(data, kApiParentTemplateOffset); - if (parent) { + // Note: Do not directly use a function template as a condition, our + // internal ToBoolean doesn't handle that! + if (!(typeof parent === 'undefined')) { var parent_fun = Instantiate(parent); fun.prototype.__proto__ = parent_fun.prototype; } diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 161421e346..82fa8ceaf3 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -1613,14 +1613,14 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { const Register map = r9.is(tos_) ? r7 : r9; // undefined -> false. - CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch); + CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); // Boolean -> its value. - CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch); - CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch); + CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false); + CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true); // 'null' -> false. - CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch); + CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false); if (types_.Contains(SMI)) { // Smis: 0 -> false, all other -> true @@ -1635,12 +1635,13 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { if (types_.NeedsMap()) { __ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset)); - // Everything with a map could be undetectable, so check this now. - __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); - __ tst(ip, Operand(1 << Map::kIsUndetectable)); - // Undetectable -> false. - __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne); - __ Ret(ne); + if (types_.CanBeUndetectable()) { + __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); + __ tst(ip, Operand(1 << Map::kIsUndetectable)); + // Undetectable -> false. + __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne); + __ Ret(ne); + } } if (types_.Contains(SPEC_OBJECT)) { @@ -1648,10 +1649,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE); // tos_ contains the correct non-zero return value already. __ Ret(ge); - } else if (types_.Contains(INTERNAL_OBJECT)) { - // We've seen a spec object for the first time -> patch. - __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE); - __ b(ge, &patch); } if (types_.Contains(STRING)) { @@ -1659,10 +1656,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE); __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt); __ Ret(lt); // the string length is OK as the return value - } else if (types_.Contains(INTERNAL_OBJECT)) { - // We've seen a string for the first time -> patch - __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE); - __ b(lt, &patch); } if (types_.Contains(HEAP_NUMBER)) { @@ -1679,30 +1672,17 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN __ Ret(); __ bind(¬_heap_number); - } else if (types_.Contains(INTERNAL_OBJECT)) { - // We've seen a heap number for the first time -> patch - __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); - __ b(eq, &patch); - } - - if (types_.Contains(INTERNAL_OBJECT)) { - // Internal objects -> true. - __ mov(tos_, Operand(1, RelocInfo::NONE)); - __ Ret(); } - if (!types_.IsAll()) { - __ bind(&patch); - GenerateTypeTransition(masm); - } + __ bind(&patch); + GenerateTypeTransition(masm); } void ToBooleanStub::CheckOddball(MacroAssembler* masm, Type type, Heap::RootListIndex value, - bool result, - Label* patch) { + bool result) { if (types_.Contains(type)) { // If we see an expected oddball, return its ToBoolean value tos_. __ LoadRoot(ip, value); @@ -1713,12 +1693,6 @@ void ToBooleanStub::CheckOddball(MacroAssembler* masm, __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq); } __ Ret(eq); - } else if (types_.Contains(INTERNAL_OBJECT)) { - // If we see an unexpected oddball and handle internal objects, we must - // patch because the code for internal objects doesn't handle it explictly. - __ LoadRoot(ip, value); - __ cmp(tos_, ip); - __ b(eq, patch); } } @@ -6341,12 +6315,8 @@ void DirectCEntryStub::Generate(MacroAssembler* masm) { void DirectCEntryStub::GenerateCall(MacroAssembler* masm, ExternalReference function) { - __ mov(lr, Operand(reinterpret_cast(GetCode().location()), - RelocInfo::CODE_TARGET)); __ mov(r2, Operand(function)); - // Push return address (accessible to GC through exit frame pc). - __ str(pc, MemOperand(sp, 0)); - __ Jump(r2); // Call the api function. + GenerateCall(masm, r2); } @@ -6355,8 +6325,14 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm, __ mov(lr, Operand(reinterpret_cast(GetCode().location()), RelocInfo::CODE_TARGET)); // Push return address (accessible to GC through exit frame pc). - __ str(pc, MemOperand(sp, 0)); + // Note that using pc with str is deprecated. + Label start; + __ bind(&start); + __ add(ip, pc, Operand(Assembler::kInstrSize)); + __ str(ip, MemOperand(sp, 0)); __ Jump(target); // Call the C++ function. + ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta, + masm->SizeOfCodeGeneratedSince(&start)); } diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index 9d9c045ff1..00357f76db 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -593,6 +593,8 @@ void Deoptimizer::EntryGenerator::Generate() { __ vstm(db_w, sp, first, last); // Push all 16 registers (needed to populate FrameDescription::registers_). + // TODO(1588) Note that using pc with stm is deprecated, so we should perhaps + // handle this a bit differently. __ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit()); const int kSavedRegistersAreaSize = diff --git a/deps/v8/src/arm/frames-arm.h b/deps/v8/src/arm/frames-arm.h index 84e108b3dc..26bbd82d00 100644 --- a/deps/v8/src/arm/frames-arm.h +++ b/deps/v8/src/arm/frames-arm.h @@ -1,4 +1,4 @@ -// Copyright 2006-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: @@ -93,10 +93,11 @@ static const int kNumSafepointSavedRegisters = class StackHandlerConstants : public AllStatic { public: - static const int kNextOffset = 0 * kPointerSize; - static const int kStateOffset = 1 * kPointerSize; - static const int kFPOffset = 2 * kPointerSize; - static const int kPCOffset = 3 * kPointerSize; + static const int kNextOffset = 0 * kPointerSize; + static const int kStateOffset = 1 * kPointerSize; + static const int kContextOffset = 2 * kPointerSize; + static const int kFPOffset = 3 * kPointerSize; + static const int kPCOffset = 4 * kPointerSize; static const int kSize = kPCOffset + kPointerSize; }; diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index cdfc0a9acf..3116ca455b 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -742,9 +742,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ mov(r2, Operand(variable->name())); // Declaration nodes are always introduced in one of two modes. ASSERT(mode == Variable::VAR || - mode == Variable::CONST); - PropertyAttributes attr = - (mode == Variable::VAR) ? NONE : READ_ONLY; + mode == Variable::CONST || + mode == Variable::LET); + PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; __ mov(r1, Operand(Smi::FromInt(attr))); // Push initial value, if any. // Note: For variables we must not push an initial value (such as @@ -4030,6 +4030,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ b(eq, if_true); __ CompareRoot(r0, Heap::kFalseValueRootIndex); Split(eq, if_true, if_false, fall_through); + } else if (FLAG_harmony_typeof && + check->Equals(isolate()->heap()->null_symbol())) { + __ CompareRoot(r0, Heap::kNullValueRootIndex); + Split(eq, if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->undefined_symbol())) { __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); __ b(eq, if_true); @@ -4047,8 +4051,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } else if (check->Equals(isolate()->heap()->object_symbol())) { __ JumpIfSmi(r0, if_false); - __ CompareRoot(r0, Heap::kNullValueRootIndex); - __ b(eq, if_true); + if (!FLAG_harmony_typeof) { + __ CompareRoot(r0, Heap::kNullValueRootIndex); + __ b(eq, if_true); + } // Check for JS objects => true. __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); __ b(lt, if_false); diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index 1eb4aff2bc..65ef3e6e1f 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -1039,13 +1039,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { : instr->SecondSuccessor(); return new LGoto(successor->block_id()); } - LInstruction* branch = new LBranch(UseRegister(v)); - // When we handle all cases, we never deopt, so we don't need to assign the - // environment then. Note that we map the "empty" case to the "all" case in - // the code generator. - ToBooleanStub::Types types = instr->expected_input_types(); - bool all_cases_handled = types.IsAll() || types.IsEmpty(); - return all_cases_handled ? branch : AssignEnvironment(branch); + return AssignEnvironment(new LBranch(UseRegister(v))); } @@ -1515,16 +1509,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { } -LInstruction* LChunkBuilder::DoExternalArrayLength( - HExternalArrayLength* instr) { +LInstruction* LChunkBuilder::DoFixedArrayBaseLength( + HFixedArrayBaseLength* instr) { LOperand* array = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new LExternalArrayLength(array)); -} - - -LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { - LOperand* array = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new LFixedArrayLength(array)); + return DefineAsRegister(new LFixedArrayBaseLength(array)); } diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index 70c348de69..3632c8cf48 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -92,8 +92,7 @@ class LCodeGen; V(DivI) \ V(DoubleToI) \ V(ElementsKind) \ - V(ExternalArrayLength) \ - V(FixedArrayLength) \ + V(FixedArrayBaseLength) \ V(FunctionLiteral) \ V(GetCachedArrayIndex) \ V(GlobalObject) \ @@ -915,25 +914,15 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { }; -class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> { +class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { public: - explicit LExternalArrayLength(LOperand* value) { + explicit LFixedArrayBaseLength(LOperand* value) { inputs_[0] = value; } - DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length") - DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength) -}; - - -class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> { - public: - explicit LFixedArrayLength(LOperand* value) { - inputs_[0] = value; - } - - DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length") - DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength) + DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength, + "fixed-array-base-length") + DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength) }; diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 3f3f31acca..4e135d66b5 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -1378,17 +1378,10 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { } -void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) { +void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); Register array = ToRegister(instr->InputAt(0)); - __ ldr(result, FieldMemOperand(array, ExternalArray::kLengthOffset)); -} - - -void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { - Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); - __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset)); + __ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset)); } @@ -1583,46 +1576,18 @@ void LCodeGen::DoBranch(LBranch* instr) { // undefined -> false. __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); __ b(eq, false_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen undefined for the first time -> deopt. - __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); - DeoptimizeIf(eq, instr->environment()); } - if (expected.Contains(ToBooleanStub::BOOLEAN)) { // Boolean -> its value. __ CompareRoot(reg, Heap::kTrueValueRootIndex); __ b(eq, true_label); __ CompareRoot(reg, Heap::kFalseValueRootIndex); __ b(eq, false_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a boolean for the first time -> deopt. - __ CompareRoot(reg, Heap::kTrueValueRootIndex); - DeoptimizeIf(eq, instr->environment()); - __ CompareRoot(reg, Heap::kFalseValueRootIndex); - DeoptimizeIf(eq, instr->environment()); } - -#if 0 - if (expected.Contains(ToBooleanStub::BOOLEAN)) { - // false -> false. - __ CompareRoot(reg, Heap::kFalseValueRootIndex); - __ b(eq, false_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a boolean for the first time -> deopt. - __ CompareRoot(reg, Heap::kFalseValueRootIndex); - DeoptimizeIf(eq, instr->environment()); - } -#endif - if (expected.Contains(ToBooleanStub::NULL_TYPE)) { // 'null' -> false. __ CompareRoot(reg, Heap::kNullValueRootIndex); __ b(eq, false_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen null for the first time -> deopt. - __ CompareRoot(reg, Heap::kNullValueRootIndex); - DeoptimizeIf(eq, instr->environment()); } if (expected.Contains(ToBooleanStub::SMI)) { @@ -1639,20 +1604,19 @@ void LCodeGen::DoBranch(LBranch* instr) { const Register map = scratch0(); if (expected.NeedsMap()) { __ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset)); - // Everything with a map could be undetectable, so check this now. - __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); - __ tst(ip, Operand(1 << Map::kIsUndetectable)); - __ b(ne, false_label); + + if (expected.CanBeUndetectable()) { + // Undetectable -> false. + __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); + __ tst(ip, Operand(1 << Map::kIsUndetectable)); + __ b(ne, false_label); + } } if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { // spec object -> true. __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE); __ b(ge, true_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a spec object for the first time -> deopt. - __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE); - DeoptimizeIf(ge, instr->environment()); } if (expected.Contains(ToBooleanStub::STRING)) { @@ -1665,10 +1629,6 @@ void LCodeGen::DoBranch(LBranch* instr) { __ b(ne, true_label); __ b(false_label); __ bind(¬_string); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a string for the first time -> deopt - __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE); - DeoptimizeIf(lt, instr->environment()); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -1683,19 +1643,10 @@ void LCodeGen::DoBranch(LBranch* instr) { __ b(eq, false_label); // +0, -0 -> false. __ b(true_label); __ bind(¬_heap_number); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a heap number for the first time -> deopt. - __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); - DeoptimizeIf(eq, instr->environment()); } - if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // internal objects -> true - __ b(true_label); - } else { - // We've seen something for the first time -> deopt. - DeoptimizeIf(al, instr->environment()); - } + // We've seen something for the first time -> deopt. + DeoptimizeIf(al, instr->environment()); } } } @@ -3014,19 +2965,18 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); - Register scratch1 = result; - Register scratch2 = scratch0(); + Register scratch = scratch0(); Label done, check_sign_on_zero; // Extract exponent bits. - __ vmov(scratch1, input.high()); - __ ubfx(scratch2, - scratch1, + __ vmov(result, input.high()); + __ ubfx(scratch, + result, HeapNumber::kExponentShift, HeapNumber::kExponentBits); // If the number is in ]-0.5, +0.5[, the result is +/- 0. - __ cmp(scratch2, Operand(HeapNumber::kExponentBias - 2)); + __ cmp(scratch, Operand(HeapNumber::kExponentBias - 2)); __ mov(result, Operand(0), LeaveCC, le); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { __ b(le, &check_sign_on_zero); @@ -3036,19 +2986,19 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { // The following conversion will not work with numbers // outside of ]-2^32, 2^32[. - __ cmp(scratch2, Operand(HeapNumber::kExponentBias + 32)); + __ cmp(scratch, Operand(HeapNumber::kExponentBias + 32)); DeoptimizeIf(ge, instr->environment()); // Save the original sign for later comparison. - __ and_(scratch2, scratch1, Operand(HeapNumber::kSignMask)); + __ and_(scratch, result, Operand(HeapNumber::kSignMask)); __ Vmov(double_scratch0(), 0.5); __ vadd(input, input, double_scratch0()); // Check sign of the result: if the sign changed, the input // value was in ]0.5, 0[ and the result should be -0. - __ vmov(scratch1, input.high()); - __ eor(scratch1, scratch1, Operand(scratch2), SetCC); + __ vmov(result, input.high()); + __ eor(result, result, Operand(scratch), SetCC); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { DeoptimizeIf(mi, instr->environment()); } else { @@ -3059,8 +3009,8 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { __ EmitVFPTruncate(kRoundToMinusInf, double_scratch0().low(), input, - scratch1, - scratch2); + result, + scratch); DeoptimizeIf(ne, instr->environment()); __ vmov(result, double_scratch0().low()); @@ -3069,8 +3019,8 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { __ cmp(result, Operand(0)); __ b(ne, &done); __ bind(&check_sign_on_zero); - __ vmov(scratch1, input.high()); - __ tst(scratch1, Operand(HeapNumber::kSignMask)); + __ vmov(scratch, input.high()); + __ tst(scratch, Operand(HeapNumber::kSignMask)); DeoptimizeIf(ne, instr->environment()); } __ bind(&done); @@ -4395,6 +4345,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ CompareRoot(input, Heap::kFalseValueRootIndex); final_branch_condition = eq; + } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) { + __ CompareRoot(input, Heap::kNullValueRootIndex); + final_branch_condition = eq; + } else if (type_name->Equals(heap()->undefined_symbol())) { __ CompareRoot(input, Heap::kUndefinedValueRootIndex); __ b(eq, true_label); @@ -4413,8 +4367,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, } else if (type_name->Equals(heap()->object_symbol())) { __ JumpIfSmi(input, false_label); - __ CompareRoot(input, Heap::kNullValueRootIndex); - __ b(eq, true_label); + if (!FLAG_harmony_typeof) { + __ CompareRoot(input, Heap::kNullValueRootIndex); + __ b(eq, true_label); + } __ CompareObjectType(input, input, scratch, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); __ b(lt, false_label); diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index c34a57920a..88477bb7f0 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -1102,7 +1102,13 @@ void MacroAssembler::DebugBreak() { void MacroAssembler::PushTryHandler(CodeLocation try_location, HandlerType type) { // Adjust this code if not the case. - ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); + // The pc (return address) is passed in register lr. if (try_location == IN_JAVASCRIPT) { if (type == TRY_CATCH_HANDLER) { @@ -1110,14 +1116,10 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, } else { mov(r3, Operand(StackHandler::TRY_FINALLY)); } - ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize - && StackHandlerConstants::kFPOffset == 2 * kPointerSize - && StackHandlerConstants::kPCOffset == 3 * kPointerSize); - stm(db_w, sp, r3.bit() | fp.bit() | lr.bit()); + stm(db_w, sp, r3.bit() | cp.bit() | fp.bit() | lr.bit()); // Save the current handler as the next handler. mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); ldr(r1, MemOperand(r3)); - ASSERT(StackHandlerConstants::kNextOffset == 0); push(r1); // Link this handler as the new current one. str(sp, MemOperand(r3)); @@ -1127,16 +1129,13 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, // The frame pointer does not point to a JS frame so we save NULL // for fp. We expect the code throwing an exception to check fp // before dereferencing it to restore the context. - mov(ip, Operand(0, RelocInfo::NONE)); // To save a NULL frame pointer. - mov(r6, Operand(StackHandler::ENTRY)); - ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize - && StackHandlerConstants::kFPOffset == 2 * kPointerSize - && StackHandlerConstants::kPCOffset == 3 * kPointerSize); - stm(db_w, sp, r6.bit() | ip.bit() | lr.bit()); + mov(r5, Operand(StackHandler::ENTRY)); // State. + mov(r6, Operand(Smi::FromInt(0))); // Indicates no context. + mov(r7, Operand(0, RelocInfo::NONE)); // NULL frame pointer. + stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | lr.bit()); // Save the current handler as the next handler. mov(r7, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); ldr(r6, MemOperand(r7)); - ASSERT(StackHandlerConstants::kNextOffset == 0); push(r6); // Link this handler as the new current one. str(sp, MemOperand(r7)); @@ -1145,7 +1144,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, void MacroAssembler::PopTryHandler() { - ASSERT_EQ(0, StackHandlerConstants::kNextOffset); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); pop(r1); mov(ip, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); @@ -1154,39 +1153,40 @@ void MacroAssembler::PopTryHandler() { void MacroAssembler::Throw(Register value) { + // Adjust this code if not the case. + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); // r0 is expected to hold the exception. if (!value.is(r0)) { mov(r0, value); } - // Adjust this code if not the case. - STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); - // Drop the sp to the top of the handler. mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); ldr(sp, MemOperand(r3)); - // Restore the next handler and frame pointer, discard handler state. - STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); + // Restore the next handler. pop(r2); str(r2, MemOperand(r3)); - STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); - ldm(ia_w, sp, r3.bit() | fp.bit()); // r3: discarded state. - - // Before returning we restore the context from the frame pointer if - // not NULL. The frame pointer is NULL in the exception handler of a - // JS entry frame. - cmp(fp, Operand(0, RelocInfo::NONE)); - // Set cp to NULL if fp is NULL. - mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); - // Restore cp otherwise. - ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); + + // Restore context and frame pointer, discard state (r3). + ldm(ia_w, sp, r3.bit() | cp.bit() | fp.bit()); + + // If the handler is a JS frame, restore the context to the frame. + // (r3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any + // of them. + cmp(r3, Operand(StackHandler::ENTRY)); + str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); + #ifdef DEBUG if (emit_debug_code()) { mov(lr, Operand(pc)); } #endif - STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); pop(pc); } @@ -1194,8 +1194,12 @@ void MacroAssembler::Throw(Register value) { void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, Register value) { // Adjust this code if not the case. - STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); - + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); // r0 is expected to hold the exception. if (!value.is(r0)) { mov(r0, value); @@ -1220,7 +1224,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, bind(&done); // Set the top handler address to next handler past the current ENTRY handler. - STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); pop(r2); str(r2, MemOperand(r3)); @@ -1242,26 +1245,17 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, // Stack layout at this point. See also StackHandlerConstants. // sp -> state (ENTRY) + // cp // fp // lr - // Discard handler state (r2 is not used) and restore frame pointer. - STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); - ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state. - // Before returning we restore the context from the frame pointer if - // not NULL. The frame pointer is NULL in the exception handler of a - // JS entry frame. - cmp(fp, Operand(0, RelocInfo::NONE)); - // Set cp to NULL if fp is NULL. - mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); - // Restore cp otherwise. - ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); + // Restore context and frame pointer, discard state (r2). + ldm(ia_w, sp, r2.bit() | cp.bit() | fp.bit()); #ifdef DEBUG if (emit_debug_code()) { mov(lr, Operand(pc)); } #endif - STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); pop(pc); } diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 2c60b28a5d..1767b9d5b2 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -3489,9 +3489,9 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // Check that the index is in range. __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); - __ cmp(ip, Operand(key, ASR, kSmiTagSize)); + __ cmp(key, ip); // Unsigned comparison catches both negative and too-large values. - __ b(lo, &miss_force_generic); + __ b(hs, &miss_force_generic); __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); // r3: base pointer of external storage @@ -3811,22 +3811,20 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); - // Check that the key is a smi. __ JumpIfNotSmi(key, &miss_force_generic); + __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); + // Check that the index is in range - __ SmiUntag(r4, key); __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); - __ cmp(r4, ip); + __ cmp(key, ip); // Unsigned comparison catches both negative and too-large values. __ b(hs, &miss_force_generic); // Handle both smis and HeapNumbers in the fast path. Go to the // runtime for all other kinds of values. // r3: external array. - // r4: key (integer). if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) { // Double to pixel conversion is only implemented in the runtime for now. __ JumpIfNotSmi(value, &slow); @@ -3837,32 +3835,32 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); // r3: base pointer of external storage. - // r4: key (integer). // r5: value (integer). switch (elements_kind) { case JSObject::EXTERNAL_PIXEL_ELEMENTS: // Clamp the value to [0..255]. __ Usat(r5, 8, Operand(r5)); - __ strb(r5, MemOperand(r3, r4, LSL, 0)); + __ strb(r5, MemOperand(r3, key, LSR, 1)); break; case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ strb(r5, MemOperand(r3, r4, LSL, 0)); + __ strb(r5, MemOperand(r3, key, LSR, 1)); break; case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ strh(r5, MemOperand(r3, r4, LSL, 1)); + __ strh(r5, MemOperand(r3, key, LSL, 0)); break; case JSObject::EXTERNAL_INT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ str(r5, MemOperand(r3, r4, LSL, 2)); + __ str(r5, MemOperand(r3, key, LSL, 1)); break; case JSObject::EXTERNAL_FLOAT_ELEMENTS: // Perform int-to-float conversion and store to memory. + __ SmiUntag(r4, key); StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9); break; case JSObject::EXTERNAL_DOUBLE_ELEMENTS: - __ add(r3, r3, Operand(r4, LSL, 3)); + __ add(r3, r3, Operand(key, LSL, 2)); // r3: effective address of the double element FloatingPointHelper::Destination destination; if (CpuFeatures::IsSupported(VFP3)) { @@ -3895,7 +3893,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) { // r3: external array. - // r4: index (integer). __ bind(&check_heap_number); __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE); __ b(ne, &slow); @@ -3903,7 +3900,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); // r3: base pointer of external storage. - // r4: key (integer). // The WebGL specification leaves the behavior of storing NaN and // +/-Infinity into integer arrays basically undefined. For more @@ -3916,13 +3912,13 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // include -kHeapObjectTag into it. __ sub(r5, r0, Operand(kHeapObjectTag)); __ vldr(d0, r5, HeapNumber::kValueOffset); - __ add(r5, r3, Operand(r4, LSL, 2)); + __ add(r5, r3, Operand(key, LSL, 1)); __ vcvt_f32_f64(s0, d0); __ vstr(s0, r5, 0); } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { __ sub(r5, r0, Operand(kHeapObjectTag)); __ vldr(d0, r5, HeapNumber::kValueOffset); - __ add(r5, r3, Operand(r4, LSL, 3)); + __ add(r5, r3, Operand(key, LSL, 2)); __ vstr(d0, r5, 0); } else { // Hoisted load. vldr requires offset to be a multiple of 4 so we can @@ -3934,15 +3930,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( switch (elements_kind) { case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ strb(r5, MemOperand(r3, r4, LSL, 0)); + __ strb(r5, MemOperand(r3, key, LSR, 1)); break; case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ strh(r5, MemOperand(r3, r4, LSL, 1)); + __ strh(r5, MemOperand(r3, key, LSL, 0)); break; case JSObject::EXTERNAL_INT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ str(r5, MemOperand(r3, r4, LSL, 2)); + __ str(r5, MemOperand(r3, key, LSL, 1)); break; case JSObject::EXTERNAL_PIXEL_ELEMENTS: case JSObject::EXTERNAL_FLOAT_ELEMENTS: @@ -4004,7 +4000,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift)); __ bind(&done); - __ str(r5, MemOperand(r3, r4, LSL, 2)); + __ str(r5, MemOperand(r3, key, LSL, 1)); // Entry registers are intact, r0 holds the value which is the return // value. __ Ret(); @@ -4017,7 +4013,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift)); __ b(&done); } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { - __ add(r7, r3, Operand(r4, LSL, 3)); + __ add(r7, r3, Operand(key, LSL, 2)); // r7: effective address of destination element. __ str(r6, MemOperand(r7, 0)); __ str(r5, MemOperand(r7, Register::kSizeInBytes)); @@ -4073,15 +4069,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( switch (elements_kind) { case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ strb(r5, MemOperand(r3, r4, LSL, 0)); + __ strb(r5, MemOperand(r3, key, LSR, 1)); break; case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ strh(r5, MemOperand(r3, r4, LSL, 1)); + __ strh(r5, MemOperand(r3, key, LSL, 0)); break; case JSObject::EXTERNAL_INT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ str(r5, MemOperand(r3, r4, LSL, 2)); + __ str(r5, MemOperand(r3, key, LSL, 1)); break; case JSObject::EXTERNAL_PIXEL_ELEMENTS: case JSObject::EXTERNAL_FLOAT_ELEMENTS: diff --git a/deps/v8/src/ast-inl.h b/deps/v8/src/ast-inl.h index c750e6b03c..731ad2ff3f 100644 --- a/deps/v8/src/ast-inl.h +++ b/deps/v8/src/ast-inl.h @@ -50,7 +50,8 @@ Block::Block(Isolate* isolate, bool is_initializer_block) : BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY), statements_(capacity), - is_initializer_block_(is_initializer_block) { + is_initializer_block_(is_initializer_block), + block_scope_(NULL) { } diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 2df62ee96a..3e6d856ce4 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -426,7 +426,7 @@ bool ForInStatement::IsInlineable() const { } -bool EnterWithContextStatement::IsInlineable() const { +bool WithStatement::IsInlineable() const { return false; } diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index b4705f6ab8..4031b7d810 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -60,7 +60,7 @@ namespace internal { V(ContinueStatement) \ V(BreakStatement) \ V(ReturnStatement) \ - V(EnterWithContextStatement) \ + V(WithStatement) \ V(ExitContextStatement) \ V(SwitchStatement) \ V(DoWhileStatement) \ @@ -359,9 +359,13 @@ class Block: public BreakableStatement { ZoneList* statements() { return &statements_; } bool is_initializer_block() const { return is_initializer_block_; } + Scope* block_scope() const { return block_scope_; } + void set_block_scope(Scope* block_scope) { block_scope_ = block_scope; } + private: ZoneList statements_; bool is_initializer_block_; + Scope* block_scope_; }; @@ -371,9 +375,11 @@ class Declaration: public AstNode { : proxy_(proxy), mode_(mode), fun_(fun) { - ASSERT(mode == Variable::VAR || mode == Variable::CONST); + ASSERT(mode == Variable::VAR || + mode == Variable::CONST || + mode == Variable::LET); // At the moment there are no "const functions"'s in JavaScript... - ASSERT(fun == NULL || mode == Variable::VAR); + ASSERT(fun == NULL || mode == Variable::VAR || mode == Variable::LET); } DECLARE_NODE_TYPE(Declaration) @@ -627,19 +633,21 @@ class ReturnStatement: public Statement { }; -class EnterWithContextStatement: public Statement { +class WithStatement: public Statement { public: - explicit EnterWithContextStatement(Expression* expression) - : expression_(expression) { } + WithStatement(Expression* expression, Statement* statement) + : expression_(expression), statement_(statement) { } - DECLARE_NODE_TYPE(EnterWithContextStatement) + DECLARE_NODE_TYPE(WithStatement) Expression* expression() const { return expression_; } + Statement* statement() const { return statement_; } virtual bool IsInlineable() const; private: Expression* expression_; + Statement* statement_; }; diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index a5cb555252..4f7cf40940 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -1198,10 +1198,9 @@ void Genesis::InitializeExperimentalGlobal() { // 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 weakmap_fun = - InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize, - isolate->initial_object_prototype(), - Builtins::kIllegal, true); + InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize, + isolate->initial_object_prototype(), + Builtins::kIllegal, true); } } @@ -1587,8 +1586,6 @@ bool Genesis::InstallNatives() { global_context()->set_string_function_prototype_map( HeapObject::cast(string_function->initial_map()->prototype())->map()); - InstallBuiltinFunctionIds(); - // Install Function.prototype.call and apply. { Handle key = factory()->function_class_symbol(); Handle function = @@ -1622,6 +1619,8 @@ bool Genesis::InstallNatives() { apply->shared()->set_length(2); } + InstallBuiltinFunctionIds(); + // Create a constructor for RegExp results (a variant of Array that // predefines the two properties index and match). { diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index 0cba275c3e..5535d171be 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -340,12 +340,11 @@ void ToBooleanStub::Types::Print(StringStream* stream) const { if (IsEmpty()) stream->Add("None"); if (Contains(UNDEFINED)) stream->Add("Undefined"); if (Contains(BOOLEAN)) stream->Add("Bool"); - if (Contains(SMI)) stream->Add("Smi"); if (Contains(NULL_TYPE)) stream->Add("Null"); + if (Contains(SMI)) stream->Add("Smi"); if (Contains(SPEC_OBJECT)) stream->Add("SpecObject"); if (Contains(STRING)) stream->Add("String"); if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber"); - if (Contains(INTERNAL_OBJECT)) stream->Add("InternalObject"); } @@ -385,12 +384,14 @@ bool ToBooleanStub::Types::Record(Handle object) { return !object->IsUndetectableObject() && String::cast(*object)->length() != 0; } else if (object->IsHeapNumber()) { + ASSERT(!object->IsUndetectableObject()); Add(HEAP_NUMBER); double value = HeapNumber::cast(*object)->value(); - return !object->IsUndetectableObject() && value != 0 && !isnan(value); + return value != 0 && !isnan(value); } else { - Add(INTERNAL_OBJECT); - return !object->IsUndetectableObject(); + // We should never see an internal object at runtime here! + UNREACHABLE(); + return true; } } @@ -398,8 +399,13 @@ bool ToBooleanStub::Types::Record(Handle object) { bool ToBooleanStub::Types::NeedsMap() const { return Contains(ToBooleanStub::SPEC_OBJECT) || Contains(ToBooleanStub::STRING) - || Contains(ToBooleanStub::HEAP_NUMBER) - || Contains(ToBooleanStub::INTERNAL_OBJECT); + || Contains(ToBooleanStub::HEAP_NUMBER); +} + + +bool ToBooleanStub::Types::CanBeUndetectable() const { + return Contains(ToBooleanStub::SPEC_OBJECT) + || Contains(ToBooleanStub::STRING); } diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index 43b958b439..89e99a8d08 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -908,7 +908,6 @@ class ToBooleanStub: public CodeStub { SPEC_OBJECT, STRING, HEAP_NUMBER, - INTERNAL_OBJECT, NUMBER_OF_TYPES }; @@ -922,7 +921,6 @@ class ToBooleanStub: public CodeStub { explicit Types(byte bits) : set_(bits) {} bool IsEmpty() const { return set_.IsEmpty(); } - bool IsAll() const { return ToByte() == ((1 << NUMBER_OF_TYPES) - 1); } bool Contains(Type type) const { return set_.Contains(type); } void Add(Type type) { set_.Add(type); } byte ToByte() const { return set_.ToIntegral(); } @@ -930,6 +928,7 @@ class ToBooleanStub: public CodeStub { void TraceTransition(Types to) const; bool Record(Handle object); bool NeedsMap() const; + bool CanBeUndetectable() const; private: EnumSet set_; @@ -956,8 +955,7 @@ class ToBooleanStub: public CodeStub { void CheckOddball(MacroAssembler* masm, Type type, Heap::RootListIndex value, - bool result, - Label* patch); + bool result); void GenerateTypeTransition(MacroAssembler* masm); Register tos_; diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index a87eecc3c5..c7e78067cf 100755 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -478,15 +478,21 @@ Handle Compiler::Compile(Handle source, // that would be compiled lazily anyway, so we skip the preparse step // in that case too. ScriptDataImpl* pre_data = input_pre_data; + bool harmony_block_scoping = natives != NATIVES_CODE && + FLAG_harmony_block_scoping; if (pre_data == NULL && source_length >= FLAG_min_preparse_length) { if (source->IsExternalTwoByteString()) { ExternalTwoByteStringUC16CharacterStream stream( Handle::cast(source), 0, source->length()); - pre_data = ParserApi::PartialPreParse(&stream, extension); + pre_data = ParserApi::PartialPreParse(&stream, + extension, + harmony_block_scoping); } else { GenericStringUC16CharacterStream stream(source, 0, source->length()); - pre_data = ParserApi::PartialPreParse(&stream, extension); + pre_data = ParserApi::PartialPreParse(&stream, + extension, + harmony_block_scoping); } } diff --git a/deps/v8/src/contexts.cc b/deps/v8/src/contexts.cc index d066d34769..c0e724253f 100644 --- a/deps/v8/src/contexts.cc +++ b/deps/v8/src/contexts.cc @@ -109,7 +109,7 @@ Handle Context::Lookup(Handle name, } // Check extension/with/global object. - if (context->has_extension()) { + if (!context->IsBlockContext() && context->has_extension()) { if (context->IsCatchContext()) { // Catch contexts have the variable name in the extension slot. if (name->Equals(String::cast(context->extension()))) { @@ -121,6 +121,9 @@ Handle Context::Lookup(Handle name, return context; } } else { + ASSERT(context->IsGlobalContext() || + context->IsFunctionContext() || + context->IsWithContext()); // Global, function, and with contexts may have an object in the // extension slot. Handle extension(JSObject::cast(context->extension()), @@ -145,11 +148,20 @@ Handle Context::Lookup(Handle name, } } - // Only functions can have locals, parameters, and a function name. - if (context->IsFunctionContext()) { + // Check serialized scope information of functions and blocks. Only + // functions can have parameters, and a function name. + if (context->IsFunctionContext() || context->IsBlockContext()) { // We may have context-local slots. Check locals in the context. - Handle scope_info( - context->closure()->shared()->scope_info(), isolate); + Handle scope_info; + if (context->IsFunctionContext()) { + scope_info = Handle( + context->closure()->shared()->scope_info(), isolate); + } else { + ASSERT(context->IsBlockContext()); + scope_info = Handle( + SerializedScopeInfo::cast(context->extension()), isolate); + } + Variable::Mode mode; int index = scope_info->ContextSlotIndex(*name, &mode); ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS); @@ -168,6 +180,7 @@ Handle Context::Lookup(Handle name, switch (mode) { case Variable::INTERNAL: // Fall through. case Variable::VAR: + case Variable::LET: *attributes = NONE; break; case Variable::CONST: diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h index 53b40f127d..3d9e7f4bfe 100644 --- a/deps/v8/src/contexts.h +++ b/deps/v8/src/contexts.h @@ -295,6 +295,10 @@ class Context: public FixedArray { Map* map = this->map(); return map == map->GetHeap()->with_context_map(); } + bool IsBlockContext() { + Map* map = this->map(); + return map == map->GetHeap()->block_context_map(); + } // Tells whether the global context is marked with out of memory. inline bool has_out_of_memory(); diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index 3b9c183c2a..780b0c0716 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -740,6 +740,7 @@ Persistent Shell::CreateEvaluationContext() { // Initialize the global objects Handle global_template = CreateGlobalTemplate(); Persistent context = Context::New(NULL, global_template); + ASSERT(!context.IsEmpty()); Context::Scope scope(context); #ifndef V8_SHARED diff --git a/deps/v8/src/d8.h b/deps/v8/src/d8.h index 40cc83b055..28321f56da 100644 --- a/deps/v8/src/d8.h +++ b/deps/v8/src/d8.h @@ -39,10 +39,6 @@ namespace v8 { -#ifndef V8_SHARED -namespace i = v8::internal; -#endif // V8_SHARED - #ifndef V8_SHARED // A single counter in a counter collection. diff --git a/deps/v8/src/d8.js b/deps/v8/src/d8.js index 033455e9df..3523e54abd 100644 --- a/deps/v8/src/d8.js +++ b/deps/v8/src/d8.js @@ -103,7 +103,8 @@ Debug.ScopeType = { Global: 0, Local: 1, With: 2, Closure: 3, - Catch: 4 }; + Catch: 4, + Block: 5 }; // Current debug state. diff --git a/deps/v8/src/disassembler.cc b/deps/v8/src/disassembler.cc index 368c3a89c1..79076d6abc 100644 --- a/deps/v8/src/disassembler.cc +++ b/deps/v8/src/disassembler.cc @@ -97,14 +97,17 @@ const char* V8NameConverter::NameInCode(byte* addr) const { } -static void DumpBuffer(FILE* f, char* buff) { +static void DumpBuffer(FILE* f, StringBuilder* out) { if (f == NULL) { - PrintF("%s", buff); + PrintF("%s\n", out->Finalize()); } else { - fprintf(f, "%s", buff); + fprintf(f, "%s\n", out->Finalize()); } + out->Reset(); } + + static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength; static const int kRelocInfoPosition = 57; @@ -119,6 +122,7 @@ static int DecodeIt(FILE* f, v8::internal::EmbeddedVector decode_buffer; v8::internal::EmbeddedVector out_buffer; + StringBuilder out(out_buffer.start(), out_buffer.length()); byte* pc = begin; disasm::Disassembler d(converter); RelocIterator* it = NULL; @@ -181,17 +185,12 @@ static int DecodeIt(FILE* f, } } - StringBuilder out(out_buffer.start(), out_buffer.length()); - // Comments. for (int i = 0; i < comments.length(); i++) { - out.AddFormatted(" %s\n", comments[i]); + out.AddFormatted(" %s", comments[i]); + DumpBuffer(f, &out); } - // Write out comments, resets outp so that we can format the next line. - DumpBuffer(f, out.Finalize()); - out.Reset(); - // Instruction address and instruction offset. out.AddFormatted("%p %4d ", prev_pc, prev_pc - begin); @@ -209,7 +208,7 @@ static int DecodeIt(FILE* f, out.AddPadding(' ', kRelocInfoPosition - out.position()); } else { // Additional reloc infos are printed on separate lines. - out.AddFormatted("\n"); + DumpBuffer(f, &out); out.AddPadding(' ', kRelocInfoPosition); } @@ -299,9 +298,18 @@ static int DecodeIt(FILE* f, out.AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode)); } } - out.AddString("\n"); - DumpBuffer(f, out.Finalize()); - out.Reset(); + DumpBuffer(f, &out); + } + + // Emit comments following the last instruction (if any). + if (it != NULL) { + for ( ; !it->done(); it->next()) { + if (RelocInfo::IsComment(it->rinfo()->rmode())) { + out.AddFormatted(" %s", + reinterpret_cast(it->rinfo()->data())); + DumpBuffer(f, &out); + } + } } delete it; diff --git a/deps/v8/src/elements.cc b/deps/v8/src/elements.cc index 9cfcceec24..9927cd5ced 100644 --- a/deps/v8/src/elements.cc +++ b/deps/v8/src/elements.cc @@ -75,9 +75,8 @@ class ElementsAccessorBase : public ElementsAccessor { virtual MaybeObject* GetWithReceiver(JSObject* obj, Object* receiver, uint32_t index) { - if (index < ElementsAccessorSubclass::GetLength(obj)) { - BackingStoreClass* backing_store = - ElementsAccessorSubclass::GetBackingStore(obj); + BackingStoreClass* backing_store = BackingStoreClass::cast(obj->elements()); + if (index < ElementsAccessorSubclass::GetLength(backing_store)) { return backing_store->get(index); } return obj->GetHeap()->the_hole_value(); @@ -87,39 +86,39 @@ class ElementsAccessorBase : public ElementsAccessor { uint32_t index, JSReceiver::DeleteMode mode) = 0; - virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other, - FixedArray* keys) { - int len0 = keys->length(); + virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, + FixedArray* to) { + int len0 = to->length(); #ifdef DEBUG if (FLAG_enable_slow_asserts) { for (int i = 0; i < len0; i++) { - ASSERT(keys->get(i)->IsString() || keys->get(i)->IsNumber()); + ASSERT(!to->get(i)->IsTheHole()); } } #endif - int len1 = ElementsAccessorSubclass::GetCapacity(other); + BackingStoreClass* backing_store = BackingStoreClass::cast(from); + int len1 = ElementsAccessorSubclass::GetCapacity(backing_store); // Optimize if 'other' is empty. - // We cannot optimize if 'this' is empty, as other may have holes - // or non keys. - if (len1 == 0) return keys; + // We cannot optimize if 'this' is empty, as other may have holes. + if (len1 == 0) return to; // Compute how many elements are not in other. int extra = 0; for (int y = 0; y < len1; y++) { Object* value; MaybeObject* maybe_value = - ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y); + ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); if (!maybe_value->ToObject(&value)) return maybe_value; - if (!value->IsTheHole() && !HasKey(keys, value)) extra++; + if (!value->IsTheHole() && !HasKey(to, value)) extra++; } - if (extra == 0) return keys; + if (extra == 0) return to; // Allocate the result FixedArray* result; MaybeObject* maybe_obj = - other->GetHeap()->AllocateFixedArray(len0 + extra); + backing_store->GetHeap()->AllocateFixedArray(len0 + extra); if (!maybe_obj->To(&result)) return maybe_obj; // Fill in the content @@ -127,20 +126,19 @@ class ElementsAccessorBase : public ElementsAccessor { AssertNoAllocation no_gc; WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); for (int i = 0; i < len0; i++) { - Object* e = keys->get(i); + Object* e = to->get(i); ASSERT(e->IsString() || e->IsNumber()); result->set(i, e, mode); } } - // Fill in the extra keys. + // Fill in the extra values. int index = 0; for (int y = 0; y < len1; y++) { MaybeObject* maybe_value = - ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y); + ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); Object* value; if (!maybe_value->ToObject(&value)) return maybe_value; - if (!value->IsTheHole() && !HasKey(keys, value)) { - ASSERT(value->IsString() || value->IsNumber()); + if (!value->IsTheHole() && !HasKey(to, value)) { result->set(len0 + index, value); index++; } @@ -149,23 +147,18 @@ class ElementsAccessorBase : public ElementsAccessor { return result; } - static uint32_t GetCapacity(JSObject* obj) { - return ElementsAccessorSubclass::GetBackingStore(obj)->length(); + static uint32_t GetLength(BackingStoreClass* backing_store) { + return backing_store->length(); } - static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { - BackingStoreClass* backing_store = - ElementsAccessorSubclass::GetBackingStore(obj); - return backing_store->get(index); - } - - protected: - static BackingStoreClass* GetBackingStore(JSObject* obj) { - return BackingStoreClass::cast(obj->elements()); + static uint32_t GetCapacity(BackingStoreClass* backing_store) { + return GetLength(backing_store); } - static uint32_t GetLength(JSObject* obj) { - return ElementsAccessorSubclass::GetBackingStore(obj)->length(); + static MaybeObject* GetElementAtCapacityIndex( + BackingStoreClass* backing_store, + int index) { + return backing_store->get(index); } private: @@ -255,9 +248,8 @@ class ExternalElementsAccessor virtual MaybeObject* GetWithReceiver(JSObject* obj, Object* receiver, uint32_t index) { - if (index < ExternalElementsAccessorSubclass::GetLength(obj)) { - ExternalArray* backing_store = - ExternalElementsAccessorSubclass::GetBackingStore(obj); + ExternalArray* backing_store = ExternalArray::cast(obj->elements()); + if (index < ExternalElementsAccessorSubclass::GetLength(backing_store)) { return backing_store->get(index); } else { return obj->GetHeap()->undefined_value(); @@ -412,16 +404,16 @@ class DictionaryElementsAccessor index); } - static uint32_t GetCapacity(JSObject* obj) { - return obj->element_dictionary()->Capacity(); + static uint32_t GetCapacity(NumberDictionary* dict) { + return dict->Capacity(); } - static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { - NumberDictionary* dict = obj->element_dictionary(); + static MaybeObject* GetElementAtCapacityIndex(NumberDictionary* dict, + int index) { if (dict->IsKey(dict->KeyAt(index))) { return dict->ValueAt(index); } else { - return obj->GetHeap()->the_hole_value(); + return dict->GetHeap()->the_hole_value(); } } }; @@ -434,7 +426,7 @@ class NonStrictArgumentsElementsAccessor virtual MaybeObject* GetWithReceiver(JSObject* obj, Object* receiver, uint32_t index) { - FixedArray* parameter_map = GetBackingStore(obj); + FixedArray* parameter_map = FixedArray::cast(obj->elements()); uint32_t length = parameter_map->length(); Object* probe = (index < length - 2) ? parameter_map->get(index + 2) : NULL; @@ -482,13 +474,13 @@ class NonStrictArgumentsElementsAccessor return obj->GetHeap()->true_value(); } - static uint32_t GetCapacity(JSObject* obj) { + static uint32_t GetCapacity(FixedArray* obj) { // TODO(danno): Return max of parameter map length or backing store // capacity. return 0; } - static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { + static MaybeObject* GetElementAtCapacityIndex(FixedArray* obj, int index) { // TODO(danno): Return either value from parameter map of backing // store value at index. return obj->GetHeap()->the_hole_value(); diff --git a/deps/v8/src/elements.h b/deps/v8/src/elements.h index f64244e958..74e4ad6659 100644 --- a/deps/v8/src/elements.h +++ b/deps/v8/src/elements.h @@ -47,8 +47,8 @@ class ElementsAccessor { uint32_t index, JSReceiver::DeleteMode mode) = 0; - virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other, - FixedArray* keys) = 0; + virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, + FixedArray* to) = 0; // Returns a shared ElementsAccessor for the specified ElementsKind. static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) { diff --git a/deps/v8/src/extensions/experimental/datetime-format.cc b/deps/v8/src/extensions/experimental/datetime-format.cc index 7f46302973..94a29ac0ae 100644 --- a/deps/v8/src/extensions/experimental/datetime-format.cc +++ b/deps/v8/src/extensions/experimental/datetime-format.cc @@ -135,7 +135,7 @@ v8::Handle DateTimeFormat::GetMonths(const v8::Arguments& args) { v8::Handle DateTimeFormat::GetWeekdays(const v8::Arguments& args) { icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder()); if (!date_format) { - ThrowUnexpectedObjectError(); + return ThrowUnexpectedObjectError(); } const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols(); diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index 05dd5c9661..ee5c37bf08 100644 --- a/deps/v8/src/factory.cc +++ b/deps/v8/src/factory.cc @@ -34,6 +34,7 @@ #include "macro-assembler.h" #include "objects.h" #include "objects-visiting.h" +#include "scopeinfo.h" namespace v8 { namespace internal { @@ -291,6 +292,19 @@ Handle Factory::NewWithContext(Handle function, } +Handle Factory::NewBlockContext( + Handle function, + Handle previous, + Handle scope_info) { + CALL_HEAP_FUNCTION( + isolate(), + isolate()->heap()->AllocateBlockContext(*function, + *previous, + *scope_info), + Context); +} + + Handle Factory::NewStruct(InstanceType type) { CALL_HEAP_FUNCTION( isolate(), @@ -734,6 +748,14 @@ Handle Factory::NewFunctionWithoutPrototype(Handle name, } +Handle Factory::NewSerializedScopeInfo(int length) { + CALL_HEAP_FUNCTION( + isolate(), + isolate()->heap()->AllocateSerializedScopeInfo(length), + SerializedScopeInfo); +} + + Handle Factory::NewCode(const CodeDesc& desc, Code::Flags flags, Handle self_ref, diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index 3217ca906b..a69b05b38f 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -167,6 +167,11 @@ class Factory { Handle previous, Handle extension); + // Create a 'block' context. + Handle NewBlockContext(Handle function, + Handle previous, + Handle scope_info); + // Return the Symbol matching the passed in string. Handle SymbolFromString(Handle value); @@ -277,6 +282,8 @@ class Factory { Handle context, PretenureFlag pretenure = TENURED); + Handle NewSerializedScopeInfo(int length); + Handle NewCode(const CodeDesc& desc, Code::Flags flags, Handle self_reference, diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index 2ea9651b64..2d8f6fa95a 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -97,8 +97,10 @@ private: #define FLAG FLAG_FULL // Flags for experimental language features. +DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof") DEFINE_bool(harmony_proxies, false, "enable harmony proxies") DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps") +DEFINE_bool(harmony_block_scoping, false, "enable harmony block scoping") // Flags for experimental implementation features. DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles") diff --git a/deps/v8/src/frames-inl.h b/deps/v8/src/frames-inl.h index 5951806245..7ba79bf1b5 100644 --- a/deps/v8/src/frames-inl.h +++ b/deps/v8/src/frames-inl.h @@ -1,4 +1,4 @@ -// Copyright 2006-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: @@ -67,6 +67,7 @@ inline bool StackHandler::includes(Address address) const { inline void StackHandler::Iterate(ObjectVisitor* v, Code* holder) const { + v->VisitPointer(context_address()); StackFrame::IteratePc(v, pc_address(), holder); } @@ -82,6 +83,12 @@ inline StackHandler::State StackHandler::state() const { } +inline Object** StackHandler::context_address() const { + const int offset = StackHandlerConstants::kContextOffset; + return reinterpret_cast(address() + offset); +} + + inline Address* StackHandler::pc_address() const { const int offset = StackHandlerConstants::kPCOffset; return reinterpret_cast(address() + offset); diff --git a/deps/v8/src/frames.h b/deps/v8/src/frames.h index f542a92d96..4f94ebc7d1 100644 --- a/deps/v8/src/frames.h +++ b/deps/v8/src/frames.h @@ -1,4 +1,4 @@ -// Copyright 2006-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: @@ -114,6 +114,7 @@ class StackHandler BASE_EMBEDDED { // Accessors. inline State state() const; + inline Object** context_address() const; inline Address* pc_address() const; DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler); diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index e5375fc3ae..732a8fe7d0 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -35,6 +35,7 @@ #include "macro-assembler.h" #include "prettyprinter.h" #include "scopes.h" +#include "scopeinfo.h" #include "stub-cache.h" namespace v8 { @@ -90,8 +91,7 @@ void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) { } -void BreakableStatementChecker::VisitEnterWithContextStatement( - EnterWithContextStatement* stmt) { +void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) { Visit(stmt->expression()); } @@ -317,7 +317,6 @@ unsigned FullCodeGenerator::EmitStackCheckTable() { // field, and then a sequence of entries. Each entry is a pair of AST id // and code-relative pc offset. masm()->Align(kIntSize); - masm()->RecordComment("[ Stack check table"); unsigned offset = masm()->pc_offset(); unsigned length = stack_checks_.length(); __ dd(length); @@ -325,7 +324,6 @@ unsigned FullCodeGenerator::EmitStackCheckTable() { __ dd(stack_checks_[i].id); __ dd(stack_checks_[i].pc_and_state); } - masm()->RecordComment("]"); return offset; } @@ -847,8 +845,23 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { Breakable nested_statement(this, stmt); SetStatementPosition(stmt); + Scope* saved_scope = scope(); + if (stmt->block_scope() != NULL) { + { Comment cmnt(masm_, "[ Extend block context"); + scope_ = stmt->block_scope(); + __ Push(scope_->GetSerializedScopeInfo()); + PushFunctionArgumentForContextAllocation(); + __ CallRuntime(Runtime::kPushBlockContext, 2); + StoreToFrameField(StandardFrameConstants::kContextOffset, + context_register()); + } + { Comment cmnt(masm_, "[ Declarations"); + VisitDeclarations(scope_->declarations()); + } + } PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); VisitStatements(stmt->statements()); + scope_ = saved_scope; __ bind(nested_statement.break_target()); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); } @@ -900,16 +913,24 @@ void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { SetStatementPosition(stmt); NestedStatement* current = nesting_stack_; int stack_depth = 0; + int context_length = 0; // When continuing, we clobber the unpredictable value in the accumulator // with one that's safe for GC. If we hit an exit from the try block of // try...finally on our way out, we will unconditionally preserve the // accumulator on the stack. ClearAccumulator(); while (!current->IsContinueTarget(stmt->target())) { - stack_depth = current->Exit(stack_depth); - current = current->outer(); + current = current->Exit(&stack_depth, &context_length); } __ Drop(stack_depth); + if (context_length > 0) { + while (context_length > 0) { + LoadContextField(context_register(), Context::PREVIOUS_INDEX); + --context_length; + } + StoreToFrameField(StandardFrameConstants::kContextOffset, + context_register()); + } Iteration* loop = current->AsIteration(); __ jmp(loop->continue_target()); @@ -921,16 +942,24 @@ void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { SetStatementPosition(stmt); NestedStatement* current = nesting_stack_; int stack_depth = 0; + int context_length = 0; // When breaking, we clobber the unpredictable value in the accumulator // with one that's safe for GC. If we hit an exit from the try block of // try...finally on our way out, we will unconditionally preserve the // accumulator on the stack. ClearAccumulator(); while (!current->IsBreakTarget(stmt->target())) { - stack_depth = current->Exit(stack_depth); - current = current->outer(); + current = current->Exit(&stack_depth, &context_length); } __ Drop(stack_depth); + if (context_length > 0) { + while (context_length > 0) { + LoadContextField(context_register(), Context::PREVIOUS_INDEX); + --context_length; + } + StoreToFrameField(StandardFrameConstants::kContextOffset, + context_register()); + } Breakable* target = current->AsBreakable(); __ jmp(target->break_target()); @@ -946,9 +975,9 @@ void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { // Exit all nested statements. NestedStatement* current = nesting_stack_; int stack_depth = 0; + int context_length = 0; while (current != NULL) { - stack_depth = current->Exit(stack_depth); - current = current->outer(); + current = current->Exit(&stack_depth, &context_length); } __ Drop(stack_depth); @@ -956,9 +985,8 @@ void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { } -void FullCodeGenerator::VisitEnterWithContextStatement( - EnterWithContextStatement* stmt) { - Comment cmnt(masm_, "[ EnterWithContextStatement"); +void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) { + Comment cmnt(masm_, "[ WithStatement"); SetStatementPosition(stmt); VisitForStackValue(stmt->expression()); @@ -966,6 +994,15 @@ void FullCodeGenerator::VisitEnterWithContextStatement( __ CallRuntime(Runtime::kPushWithContext, 2); decrement_stack_height(); StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); + + { WithOrCatch body(this); + Visit(stmt->statement()); + } + + // Pop context. + LoadContextField(context_register(), Context::PREVIOUS_INDEX); + // Update local stack frame context field. + StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); } @@ -1124,7 +1161,9 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { Scope* saved_scope = scope(); scope_ = stmt->scope(); ASSERT(scope_->declarations()->is_empty()); - Visit(stmt->catch_block()); + { WithOrCatch body(this); + Visit(stmt->catch_block()); + } scope_ = saved_scope; __ jmp(&done); @@ -1170,8 +1209,8 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { Label try_handler_setup; const int original_stack_height = stack_height(); const int finally_block_stack_height = original_stack_height + 2; - const int try_block_stack_height = original_stack_height + 4; - STATIC_ASSERT(StackHandlerConstants::kSize / kPointerSize == 4); + const int try_block_stack_height = original_stack_height + 5; + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); // Setup the try-handler chain. Use a call to // Jump to try-handler setup and try-block code. Use call to put try-handler @@ -1300,20 +1339,33 @@ void FullCodeGenerator::VisitThrow(Throw* expr) { } -int FullCodeGenerator::TryFinally::Exit(int stack_depth) { +FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( + int* stack_depth, + int* context_length) { // The macros used here must preserve the result register. - __ Drop(stack_depth); + __ 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 0; + return previous_; } -int FullCodeGenerator::TryCatch::Exit(int stack_depth) { +FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit( + int* stack_depth, + int* context_length) { // The macros used here must preserve the result register. - __ Drop(stack_depth); + __ Drop(*stack_depth); __ PopTryHandler(); - return 0; + *stack_depth = 0; + return previous_; } diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index 9bd6e5e4dc..2fc0553661 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -140,25 +140,19 @@ class FullCodeGenerator: public AstVisitor { virtual bool IsContinueTarget(Statement* target) { return false; } virtual bool IsBreakTarget(Statement* target) { return false; } - // Generate code to leave the nested statement. This includes - // cleaning up any stack elements in use and restoring the - // stack to the expectations of the surrounding statements. - // Takes a number of stack elements currently on top of the - // nested statement's stack, and returns a number of stack - // elements left on top of the surrounding statement's stack. - // The generated code must preserve the result register (which - // contains the value in case of a return). - virtual int Exit(int stack_depth) { - // Default implementation for the case where there is - // nothing to clean up. - return stack_depth; + // Notify the statement that we are exiting it via break, continue, or + // return and give it a chance to generate cleanup code. Return the + // next outer statement in the nesting stack. We accumulate in + // *stack_depth the amount to drop the stack and in *context_length the + // number of context chain links to unwind as we traverse the nesting + // stack from an exit to its target. + virtual NestedStatement* Exit(int* stack_depth, int* context_length) { + return previous_; } - NestedStatement* outer() { return previous_; } protected: MacroAssembler* masm() { return codegen_->masm(); } - private: FullCodeGenerator* codegen_; NestedStatement* previous_; DISALLOW_COPY_AND_ASSIGN(NestedStatement); @@ -207,7 +201,7 @@ class FullCodeGenerator: public AstVisitor { virtual ~TryCatch() {} virtual TryCatch* AsTryCatch() { return this; } Label* catch_entry() { return catch_entry_; } - virtual int Exit(int stack_depth); + virtual NestedStatement* Exit(int* stack_depth, int* context_length); private: Label* catch_entry_; DISALLOW_COPY_AND_ASSIGN(TryCatch); @@ -221,7 +215,7 @@ class FullCodeGenerator: public AstVisitor { virtual ~TryFinally() {} virtual TryFinally* AsTryFinally() { return this; } Label* finally_entry() { return finally_entry_; } - virtual int Exit(int stack_depth); + virtual NestedStatement* Exit(int* stack_depth, int* context_length); private: Label* finally_entry_; DISALLOW_COPY_AND_ASSIGN(TryFinally); @@ -235,8 +229,9 @@ class FullCodeGenerator: public AstVisitor { explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { } virtual ~Finally() {} virtual Finally* AsFinally() { return this; } - virtual int Exit(int stack_depth) { - return stack_depth + kFinallyStackElementCount; + virtual NestedStatement* Exit(int* stack_depth, int* context_length) { + *stack_depth += kFinallyStackElementCount; + return previous_; } private: // Number of extra stack slots occupied during a finally block. @@ -254,14 +249,32 @@ class FullCodeGenerator: public AstVisitor { : Iteration(codegen, statement) { } virtual ~ForIn() {} virtual ForIn* AsForIn() { return this; } - virtual int Exit(int stack_depth) { - return stack_depth + kForInStackElementCount; + virtual NestedStatement* Exit(int* stack_depth, int* context_length) { + *stack_depth += kForInStackElementCount; + return previous_; } private: static const int kForInStackElementCount = 5; DISALLOW_COPY_AND_ASSIGN(ForIn); }; + + // A WithOrCatch represents being inside the body of a with or catch + // statement. Exiting the body needs to remove a link from the context + // chain. + class WithOrCatch : public NestedStatement { + public: + explicit WithOrCatch(FullCodeGenerator* codegen) + : NestedStatement(codegen) { + } + virtual ~WithOrCatch() {} + + virtual NestedStatement* Exit(int* stack_depth, int* context_length) { + ++(*context_length); + return previous_; + } + }; + // The forward bailout stack keeps track of the expressions that can // bail out to just before the control flow is split in a child // node. The stack elements are linked together through the parent diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index dbf3b95a94..e080cde325 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -1745,6 +1745,12 @@ bool Heap::CreateInitialMaps() { set_fixed_cow_array_map(Map::cast(obj)); ASSERT(fixed_array_map() != fixed_cow_array_map()); + { MaybeObject* maybe_obj = + AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); + if (!maybe_obj->ToObject(&obj)) return false; + } + set_serialized_scope_info_map(Map::cast(obj)); + { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize); if (!maybe_obj->ToObject(&obj)) return false; } @@ -1906,6 +1912,12 @@ bool Heap::CreateInitialMaps() { } set_with_context_map(Map::cast(obj)); + { MaybeObject* maybe_obj = + AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); + if (!maybe_obj->ToObject(&obj)) return false; + } + set_block_context_map(Map::cast(obj)); + { MaybeObject* maybe_obj = AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); if (!maybe_obj->ToObject(&obj)) return false; @@ -4017,6 +4029,37 @@ MaybeObject* Heap::AllocateWithContext(JSFunction* function, } +MaybeObject* Heap::AllocateBlockContext(JSFunction* function, + Context* previous, + SerializedScopeInfo* scope_info) { + Object* result; + { MaybeObject* maybe_result = + AllocateFixedArray(scope_info->NumberOfContextSlots()); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + // TODO(keuchel): properly initialize context slots. + Context* context = reinterpret_cast(result); + context->set_map(block_context_map()); + context->set_closure(function); + context->set_previous(previous); + context->set_extension(scope_info); + context->set_global(previous->global()); + return context; +} + + +MaybeObject* Heap::AllocateSerializedScopeInfo(int length) { + Object* result; + { MaybeObject* maybe_result = AllocateFixedArray(length, TENURED); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + SerializedScopeInfo* scope_info = + reinterpret_cast(result); + scope_info->set_map(serialized_scope_info_map()); + return scope_info; +} + + MaybeObject* Heap::AllocateStruct(InstanceType type) { Map* map; switch (type) { diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index 4f4ef14ddf..c4ee4dbe2b 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -65,6 +65,7 @@ inline Heap* _inline_get_heap_(); V(Map, heap_number_map, HeapNumberMap) \ V(Map, global_context_map, GlobalContextMap) \ V(Map, fixed_array_map, FixedArrayMap) \ + V(Map, serialized_scope_info_map, SerializedScopeInfoMap) \ V(Map, fixed_cow_array_map, FixedCOWArrayMap) \ V(Map, fixed_double_array_map, FixedDoubleArrayMap) \ V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \ @@ -111,6 +112,7 @@ inline Heap* _inline_get_heap_(); V(Map, function_context_map, FunctionContextMap) \ V(Map, catch_context_map, CatchContextMap) \ V(Map, with_context_map, WithContextMap) \ + V(Map, block_context_map, BlockContextMap) \ V(Map, code_map, CodeMap) \ V(Map, oddball_map, OddballMap) \ V(Map, global_property_cell_map, GlobalPropertyCellMap) \ @@ -160,6 +162,7 @@ inline Heap* _inline_get_heap_(); V(length_symbol, "length") \ V(name_symbol, "name") \ V(native_symbol, "native") \ + V(null_symbol, "null") \ V(number_symbol, "number") \ V(Number_symbol, "Number") \ V(nan_symbol, "NaN") \ @@ -220,7 +223,8 @@ inline Heap* _inline_get_heap_(); V(closure_symbol, "(closure)") \ V(use_strict, "use strict") \ V(dot_symbol, ".") \ - V(anonymous_function_symbol, "(anonymous function)") + V(anonymous_function_symbol, "(anonymous function)") \ + V(block_scope_symbol, ".block") // Forward declarations. class GCTracer; @@ -483,6 +487,9 @@ class Heap { // Allocates an empty code cache. MUST_USE_RESULT MaybeObject* AllocateCodeCache(); + // Allocates a serialized scope info. + MUST_USE_RESULT MaybeObject* AllocateSerializedScopeInfo(int length); + // Allocates an empty PolymorphicCodeCache. MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache(); @@ -668,6 +675,11 @@ class Heap { Context* previous, JSObject* extension); + // Allocate a block context. + MUST_USE_RESULT MaybeObject* AllocateBlockContext(JSFunction* function, + Context* previous, + SerializedScopeInfo* info); + // Allocates a new utility object in the old generation. MUST_USE_RESULT MaybeObject* AllocateStruct(InstanceType type); diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index 2be2a03257..71c59b5d9e 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/deps/v8/src/hydrogen-instructions.cc @@ -635,6 +635,12 @@ void HBinaryCall::PrintDataTo(StringStream* stream) { } +void HBoundsCheck::PrintDataTo(StringStream* stream) { + index()->PrintNameTo(stream); + stream->Add(" "); + length()->PrintNameTo(stream); +} + void HCallConstantFunction::PrintDataTo(StringStream* stream) { if (IsApplyFunction()) { stream->Add("optimized apply "); @@ -862,19 +868,10 @@ void HInstanceOf::PrintDataTo(StringStream* stream) { Range* HValue::InferRange() { - if (representation().IsTagged()) { - // Tagged values are always in int32 range when converted to integer, - // but they can contain -0. - Range* result = new Range(); - result->set_can_be_minus_zero(true); - return result; - } else if (representation().IsNone()) { - return NULL; - } else { - // Untagged integer32 cannot be -0 and we don't compute ranges for - // untagged doubles. - return new Range(); - } + // Untagged integer32 cannot be -0, all other representations can. + Range* result = new Range(); + result->set_can_be_minus_zero(!representation().IsInteger32()); + return result; } @@ -1373,6 +1370,20 @@ bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) { } +void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) { + object()->PrintNameTo(stream); + stream->Add(" ."); + stream->Add(*String::cast(*name())->ToCString()); +} + + +void HLoadNamedGeneric::PrintDataTo(StringStream* stream) { + object()->PrintNameTo(stream); + stream->Add(" ."); + stream->Add(*String::cast(*name())->ToCString()); +} + + void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) { object()->PrintNameTo(stream); stream->Add("["); diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index 23c0ae664c..e7a9104e87 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -104,8 +104,7 @@ class LChunkBuilder; V(Div) \ V(ElementsKind) \ V(EnterInlined) \ - V(ExternalArrayLength) \ - V(FixedArrayLength) \ + V(FixedArrayBaseLength) \ V(ForceRepresentation) \ V(FunctionLiteral) \ V(GetCachedArrayIndex) \ @@ -1702,9 +1701,9 @@ class HJSArrayLength: public HTemplateInstruction<2> { }; -class HFixedArrayLength: public HUnaryOperation { +class HFixedArrayBaseLength: public HUnaryOperation { public: - explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) { + explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetFlag(kDependsOnArrayLengths); @@ -1714,28 +1713,7 @@ class HFixedArrayLength: public HUnaryOperation { return Representation::Tagged(); } - DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength) - - protected: - virtual bool DataEquals(HValue* other) { return true; } -}; - - -class HExternalArrayLength: public HUnaryOperation { - public: - explicit HExternalArrayLength(HValue* value) : HUnaryOperation(value) { - set_representation(Representation::Integer32()); - // The result of this instruction is idempotent as long as its inputs don't - // change. The length of a pixel array cannot change once set, so it's not - // necessary to introduce a kDependsOnArrayLengths or any other dependency. - SetFlag(kUseGVN); - } - - virtual Representation RequiredInputRepresentation(int index) const { - return Representation::Tagged(); - } - - DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength) + DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength) protected: virtual bool DataEquals(HValue* other) { return true; } @@ -2471,6 +2449,8 @@ class HBoundsCheck: public HTemplateInstruction<2> { return Representation::Integer32(); } + virtual void PrintDataTo(StringStream* stream); + HValue* index() { return OperandAt(0); } HValue* length() { return OperandAt(1); } @@ -3438,6 +3418,8 @@ class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> { return Representation::Tagged(); } + virtual void PrintDataTo(StringStream* stream); + DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic) static const int kMaxLoadPolymorphism = 4; @@ -3471,6 +3453,8 @@ class HLoadNamedGeneric: public HTemplateInstruction<2> { return Representation::Tagged(); } + virtual void PrintDataTo(StringStream* stream); + DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric) private: diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index be56c673b9..ca0aebbbb9 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -2480,6 +2480,9 @@ void HGraphBuilder::VisitBlock(Block* stmt) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); + if (stmt->block_scope() != NULL) { + return Bailout("ScopedBlock"); + } BreakAndContinueInfo break_info(stmt); { BreakAndContinueScope push(&break_info, this); CHECK_BAILOUT(VisitStatements(stmt->statements())); @@ -2631,12 +2634,11 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { } -void HGraphBuilder::VisitEnterWithContextStatement( - EnterWithContextStatement* stmt) { +void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - return Bailout("EnterWithContextStatement"); + return Bailout("WithStatement"); } @@ -3940,7 +3942,7 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, HInstruction* length = NULL; HInstruction* checked_key = NULL; if (map->has_external_array_elements()) { - length = AddInstruction(new(zone()) HExternalArrayLength(elements)); + length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); HLoadExternalArrayPointer* external_elements = new(zone()) HLoadExternalArrayPointer(elements); @@ -3952,7 +3954,7 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, if (map->instance_type() == JS_ARRAY_TYPE) { length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck)); } else { - length = AddInstruction(new(zone()) HFixedArrayLength(elements)); + length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); } checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); if (is_store) { @@ -4024,7 +4026,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND && todo_external_array) { HInstruction* length = - AddInstruction(new(zone()) HExternalArrayLength(elements)); + AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); external_elements = new(zone()) HLoadExternalArrayPointer(elements); AddInstruction(external_elements); @@ -4088,7 +4090,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, if_jsarray->Goto(join); set_current_block(if_fastobject); - length = AddInstruction(new(zone()) HFixedArrayLength(elements)); + length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); if (is_store) { if (fast_double_elements) { @@ -4762,10 +4764,17 @@ bool HGraphBuilder::TryCallApply(Call* expr) { Property* prop = callee->AsProperty(); ASSERT(prop != NULL); - if (info()->scope()->arguments() == NULL) return false; + if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { + return false; + } + Handle function_map = expr->GetReceiverTypes()->first(); + if (function_map->instance_type() != JS_FUNCTION_TYPE || + !expr->target()->shared()->HasBuiltinFunctionId() || + expr->target()->shared()->builtin_function_id() != kFunctionApply) { + return false; + } - Handle name = prop->key()->AsLiteral()->AsPropertyName(); - if (!name->IsEqualTo(CStrVector("apply"))) return false; + if (info()->scope()->arguments() == NULL) return false; ZoneList* args = expr->arguments(); if (args->length() != 2) return false; @@ -4775,9 +4784,6 @@ bool HGraphBuilder::TryCallApply(Call* expr) { HValue* arg_two_value = environment()->Lookup(arg_two->var()); if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; - if (!expr->IsMonomorphic() || - expr->check_type() != RECEIVER_MAP_CHECK) return false; - // Our implementation of arguments (based on this stack frame or an // adapter below it) does not work for inlined functions. if (function_state()->outer() != NULL) { @@ -4794,10 +4800,7 @@ bool HGraphBuilder::TryCallApply(Call* expr) { HValue* receiver = Pop(); HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); - AddCheckConstantFunction(expr, - function, - expr->GetReceiverTypes()->first(), - true); + AddCheckConstantFunction(expr, function, function_map, true); HInstruction* result = new(zone()) HApplyArguments(function, receiver, length, elements); result->set_position(expr->position()); diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index 05c42dd7f0..99225511c5 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -874,7 +874,10 @@ class HGraphBuilder: public AstVisitor { bool is_store); bool TryArgumentsAccess(Property* expr); + + // Try to optimize fun.apply(receiver, arguments) pattern. bool TryCallApply(Call* expr); + bool TryInline(Call* expr); bool TryInlineBuiltinFunction(Call* expr, HValue* receiver, diff --git a/deps/v8/src/ia32/assembler-ia32.cc b/deps/v8/src/ia32/assembler-ia32.cc index 0dc519407c..999647487e 100644 --- a/deps/v8/src/ia32/assembler-ia32.cc +++ b/deps/v8/src/ia32/assembler-ia32.cc @@ -1957,6 +1957,18 @@ void Assembler::ucomisd(XMMRegister dst, XMMRegister src) { } +void Assembler::roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode) { + ASSERT(CpuFeatures::IsEnabled(SSE4_1)); + EnsureSpace ensure_space(this); + EMIT(0x66); + EMIT(0x0F); + EMIT(0x3A); + EMIT(0x0B); + emit_sse_operand(dst, src); + // Mask precision exeption. + EMIT(static_cast(mode) | 0x8); +} + void Assembler::movmskpd(Register dst, XMMRegister src) { ASSERT(CpuFeatures::IsEnabled(SSE2)); EnsureSpace ensure_space(this); diff --git a/deps/v8/src/ia32/assembler-ia32.h b/deps/v8/src/ia32/assembler-ia32.h index da38e138da..c186094b39 100644 --- a/deps/v8/src/ia32/assembler-ia32.h +++ b/deps/v8/src/ia32/assembler-ia32.h @@ -941,6 +941,16 @@ class Assembler : public AssemblerBase { void andpd(XMMRegister dst, XMMRegister src); void ucomisd(XMMRegister dst, XMMRegister src); + + enum RoundingMode { + kRoundToNearest = 0x0, + kRoundDown = 0x1, + kRoundUp = 0x2, + kRoundToZero = 0x3 + }; + + void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode); + void movmskpd(Register dst, XMMRegister src); void cmpltsd(XMMRegister dst, XMMRegister src); diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index ed7e56c110..e39d114451 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -249,20 +249,20 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { } // undefined -> false - CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch); + CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); // Boolean -> its value - CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch); - CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch); + CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false); + CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true); // 'null' -> false. - CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch); + CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false); if (types_.Contains(SMI)) { // Smis: 0 -> false, all other -> true Label not_smi; __ JumpIfNotSmi(argument, ¬_smi, Label::kNear); - // argument contains the correct return value already + // argument contains the correct return value already. if (!tos_.is(argument)) { __ mov(tos_, argument); } @@ -276,15 +276,16 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { if (types_.NeedsMap()) { __ mov(map, FieldOperand(argument, HeapObject::kMapOffset)); - // Everything with a map could be undetectable, so check this now. - __ test_b(FieldOperand(map, Map::kBitFieldOffset), - 1 << Map::kIsUndetectable); - // Undetectable -> false. - Label not_undetectable; - __ j(zero, ¬_undetectable, Label::kNear); - __ Set(tos_, Immediate(0)); - __ ret(1 * kPointerSize); - __ bind(¬_undetectable); + if (types_.CanBeUndetectable()) { + __ test_b(FieldOperand(map, Map::kBitFieldOffset), + 1 << Map::kIsUndetectable); + // Undetectable -> false. + Label not_undetectable; + __ j(zero, ¬_undetectable, Label::kNear); + __ Set(tos_, Immediate(0)); + __ ret(1 * kPointerSize); + __ bind(¬_undetectable); + } } if (types_.Contains(SPEC_OBJECT)) { @@ -292,13 +293,12 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { Label not_js_object; __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); __ j(below, ¬_js_object, Label::kNear); - __ Set(tos_, Immediate(1)); + // argument contains the correct return value already. + if (!tos_.is(argument)) { + __ Set(tos_, Immediate(1)); + } __ ret(1 * kPointerSize); __ bind(¬_js_object); - } else if (types_.Contains(INTERNAL_OBJECT)) { - // We've seen a spec object for the first time -> patch. - __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); - __ j(above_equal, &patch, Label::kNear); } if (types_.Contains(STRING)) { @@ -309,10 +309,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { __ mov(tos_, FieldOperand(argument, String::kLengthOffset)); __ ret(1 * kPointerSize); // the string length is OK as the return value __ bind(¬_string); - } else if (types_.Contains(INTERNAL_OBJECT)) { - // We've seen a string for the first time -> patch - __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); - __ j(below, &patch, Label::kNear); } if (types_.Contains(HEAP_NUMBER)) { @@ -324,50 +320,42 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset)); __ FCmp(); __ j(zero, &false_result, Label::kNear); - __ Set(tos_, Immediate(1)); + // argument contains the correct return value already. + if (!tos_.is(argument)) { + __ Set(tos_, Immediate(1)); + } __ ret(1 * kPointerSize); __ bind(&false_result); __ Set(tos_, Immediate(0)); __ ret(1 * kPointerSize); __ bind(¬_heap_number); - } else if (types_.Contains(INTERNAL_OBJECT)) { - // We've seen a heap number for the first time -> patch - __ cmp(map, factory->heap_number_map()); - __ j(equal, &patch, Label::kNear); - } - - if (types_.Contains(INTERNAL_OBJECT)) { - // internal objects -> true - __ Set(tos_, Immediate(1)); - __ ret(1 * kPointerSize); } - if (!types_.IsAll()) { - __ bind(&patch); - GenerateTypeTransition(masm); - } + __ bind(&patch); + GenerateTypeTransition(masm); } void ToBooleanStub::CheckOddball(MacroAssembler* masm, Type type, Heap::RootListIndex value, - bool result, - Label* patch) { + bool result) { const Register argument = eax; if (types_.Contains(type)) { // If we see an expected oddball, return its ToBoolean value tos_. Label different_value; __ CompareRoot(argument, value); __ j(not_equal, &different_value, Label::kNear); - __ Set(tos_, Immediate(result ? 1 : 0)); + if (!result) { + // If we have to return zero, there is no way around clearing tos_. + __ Set(tos_, Immediate(0)); + } else if (!tos_.is(argument)) { + // If we have to return non-zero, we can re-use the argument if it is the + // same register as the result, because we never see Smi-zero here. + __ Set(tos_, Immediate(1)); + } __ ret(1 * kPointerSize); __ bind(&different_value); - } else if (types_.Contains(INTERNAL_OBJECT)) { - // If we see an unexpected oddball and handle internal objects, we must - // patch because the code for internal objects doesn't handle it explictly. - __ CompareRoot(argument, value); - __ j(equal, patch); } } diff --git a/deps/v8/src/ia32/disasm-ia32.cc b/deps/v8/src/ia32/disasm-ia32.cc index 900668fbdc..a936277b2f 100644 --- a/deps/v8/src/ia32/disasm-ia32.cc +++ b/deps/v8/src/ia32/disasm-ia32.cc @@ -1141,7 +1141,17 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector out_buffer, } } else if (*data == 0x3A) { data++; - if (*data == 0x16) { + if (*data == 0x0B) { + data++; + int mod, regop, rm; + get_modrm(*data, &mod, ®op, &rm); + int8_t imm8 = static_cast(data[1]); + AppendToBuffer("roundsd %s,%s,%d", + NameOfXMMRegister(regop), + NameOfXMMRegister(rm), + static_cast(imm8)); + data += 2; + } else if (*data == 0x16) { data++; int mod, regop, rm; get_modrm(*data, &mod, ®op, &rm); diff --git a/deps/v8/src/ia32/frames-ia32.h b/deps/v8/src/ia32/frames-ia32.h index bc65ddfadd..2f1b2a96d3 100644 --- a/deps/v8/src/ia32/frames-ia32.h +++ b/deps/v8/src/ia32/frames-ia32.h @@ -1,4 +1,4 @@ -// Copyright 2006-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: @@ -58,10 +58,11 @@ static const int kNumSafepointRegisters = 8; class StackHandlerConstants : public AllStatic { public: - static const int kNextOffset = 0 * kPointerSize; - static const int kFPOffset = 1 * kPointerSize; - static const int kStateOffset = 2 * kPointerSize; - static const int kPCOffset = 3 * kPointerSize; + static const int kNextOffset = 0 * kPointerSize; + static const int kContextOffset = 1 * kPointerSize; + static const int kFPOffset = 2 * kPointerSize; + static const int kStateOffset = 3 * kPointerSize; + static const int kPCOffset = 4 * kPointerSize; static const int kSize = kPCOffset + kPointerSize; }; diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index 994c9ff61e..bb75b1e6ac 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -737,8 +737,10 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ push(esi); __ push(Immediate(variable->name())); // Declaration nodes are always introduced in one of two modes. - ASSERT(mode == Variable::VAR || mode == Variable::CONST); - PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; + ASSERT(mode == Variable::VAR || + mode == Variable::CONST || + mode == Variable::LET); + PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; __ push(Immediate(Smi::FromInt(attr))); // Push initial value, if any. // Note: For variables we must not push an initial value (such as @@ -3830,7 +3832,6 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, const char* comment) { - // TODO(svenpanne): Allowing format strings in Comment would be nice here... Comment cmt(masm_, comment); bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); UnaryOverwriteMode overwrite = @@ -4105,6 +4106,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ j(equal, if_true); __ cmp(eax, isolate()->factory()->false_value()); Split(equal, if_true, if_false, fall_through); + } else if (FLAG_harmony_typeof && + check->Equals(isolate()->heap()->null_symbol())) { + __ cmp(eax, isolate()->factory()->null_value()); + Split(equal, if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->undefined_symbol())) { __ cmp(eax, isolate()->factory()->undefined_value()); __ j(equal, if_true); @@ -4120,8 +4125,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, Split(above_equal, if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->object_symbol())) { __ JumpIfSmi(eax, if_false); - __ cmp(eax, isolate()->factory()->null_value()); - __ j(equal, if_true); + if (!FLAG_harmony_typeof) { + __ cmp(eax, isolate()->factory()->null_value()); + __ j(equal, if_true); + } __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx); __ j(below, if_false); __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index c0f4e71caa..71fe8d95ed 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -1211,17 +1211,11 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { } -void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { +void LCodeGen::DoFixedArrayBaseLength( + LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); Register array = ToRegister(instr->InputAt(0)); - __ mov(result, FieldOperand(array, FixedArray::kLengthOffset)); -} - - -void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) { - Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); - __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset)); + __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset)); } @@ -1412,40 +1406,19 @@ void LCodeGen::DoBranch(LBranch* instr) { // undefined -> false. __ cmp(reg, factory()->undefined_value()); __ j(equal, false_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen undefined for the first time -> deopt. - __ cmp(reg, factory()->undefined_value()); - DeoptimizeIf(equal, instr->environment()); } - if (expected.Contains(ToBooleanStub::BOOLEAN)) { // true -> true. __ cmp(reg, factory()->true_value()); __ j(equal, true_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a boolean for the first time -> deopt. - __ cmp(reg, factory()->true_value()); - DeoptimizeIf(equal, instr->environment()); - } - - if (expected.Contains(ToBooleanStub::BOOLEAN)) { // false -> false. __ cmp(reg, factory()->false_value()); __ j(equal, false_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a boolean for the first time -> deopt. - __ cmp(reg, factory()->false_value()); - DeoptimizeIf(equal, instr->environment()); } - if (expected.Contains(ToBooleanStub::NULL_TYPE)) { // 'null' -> false. __ cmp(reg, factory()->null_value()); __ j(equal, false_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen null for the first time -> deopt. - __ cmp(reg, factory()->null_value()); - DeoptimizeIf(equal, instr->environment()); } if (expected.Contains(ToBooleanStub::SMI)) { @@ -1459,26 +1432,24 @@ void LCodeGen::DoBranch(LBranch* instr) { DeoptimizeIf(zero, instr->environment()); } - Register map = no_reg; + Register map = no_reg; // Keep the compiler happy. if (expected.NeedsMap()) { map = ToRegister(instr->TempAt(0)); ASSERT(!map.is(reg)); __ mov(map, FieldOperand(reg, HeapObject::kMapOffset)); - // Everything with a map could be undetectable, so check this now. - __ test_b(FieldOperand(map, Map::kBitFieldOffset), - 1 << Map::kIsUndetectable); - // Undetectable -> false. - __ j(not_zero, false_label); + + if (expected.CanBeUndetectable()) { + // Undetectable -> false. + __ test_b(FieldOperand(map, Map::kBitFieldOffset), + 1 << Map::kIsUndetectable); + __ j(not_zero, false_label); + } } if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { // spec object -> true. __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); __ j(above_equal, true_label); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a spec object for the first time -> deopt. - __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); - DeoptimizeIf(above_equal, instr->environment()); } if (expected.Contains(ToBooleanStub::STRING)) { @@ -1490,10 +1461,6 @@ void LCodeGen::DoBranch(LBranch* instr) { __ j(not_zero, true_label); __ jmp(false_label); __ bind(¬_string); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a string for the first time -> deopt - __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); - DeoptimizeIf(below, instr->environment()); } if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -1508,20 +1475,10 @@ void LCodeGen::DoBranch(LBranch* instr) { __ j(zero, false_label); __ jmp(true_label); __ bind(¬_heap_number); - } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // We've seen a heap number for the first time -> deopt. - __ cmp(FieldOperand(reg, HeapObject::kMapOffset), - factory()->heap_number_map()); - DeoptimizeIf(equal, instr->environment()); } - if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) { - // internal objects -> true - __ jmp(true_label); - } else { - // We've seen something for the first time -> deopt. - DeoptimizeIf(no_condition, instr->environment()); - } + // We've seen something for the first time -> deopt. + DeoptimizeIf(no_condition, instr->environment()); } } } @@ -2302,16 +2259,13 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { - Register elements = ToRegister(instr->elements()); - Register key = ToRegister(instr->key()); Register result = ToRegister(instr->result()); - ASSERT(result.is(elements)); // Load the result. - __ mov(result, FieldOperand(elements, - key, - times_pointer_size, - FixedArray::kHeaderSize)); + __ mov(result, + BuildFastArrayOperand(instr->elements(), instr->key(), + JSObject::FAST_ELEMENTS, + FixedArray::kHeaderSize - kHeapObjectTag)); // Check for the hole value. if (instr->hydrogen()->RequiresHoleCheck()) { @@ -2344,22 +2298,22 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( Operand LCodeGen::BuildFastArrayOperand( - LOperand* external_pointer, + LOperand* elements_pointer, LOperand* key, JSObject::ElementsKind elements_kind, uint32_t offset) { - Register external_pointer_reg = ToRegister(external_pointer); + Register elements_pointer_reg = ToRegister(elements_pointer); int shift_size = ElementsKindToShiftSize(elements_kind); if (key->IsConstantOperand()) { int constant_value = ToInteger32(LConstantOperand::cast(key)); if (constant_value & 0xF0000000) { Abort("array index constant value too big"); } - return Operand(external_pointer_reg, + return Operand(elements_pointer_reg, constant_value * (1 << shift_size) + offset); } else { ScaleFactor scale_factor = static_cast(shift_size); - return Operand(external_pointer_reg, ToRegister(key), scale_factor, offset); + return Operand(elements_pointer_reg, ToRegister(key), scale_factor, offset); } } @@ -2756,23 +2710,53 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { XMMRegister xmm_scratch = xmm0; Register output_reg = ToRegister(instr->result()); XMMRegister input_reg = ToDoubleRegister(instr->value()); - __ xorps(xmm_scratch, xmm_scratch); // Zero the register. - __ ucomisd(input_reg, xmm_scratch); - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { - DeoptimizeIf(below_equal, instr->environment()); + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatures::Scope scope(SSE4_1); + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { + // Deoptimize on negative zero. + Label non_zero; + __ xorps(xmm_scratch, xmm_scratch); // Zero the register. + __ ucomisd(input_reg, xmm_scratch); + __ j(not_equal, &non_zero, Label::kNear); + __ movmskpd(output_reg, input_reg); + __ test(output_reg, Immediate(1)); + DeoptimizeIf(not_zero, instr->environment()); + __ bind(&non_zero); + } + __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown); + __ cvttsd2si(output_reg, Operand(xmm_scratch)); + // Overflow is signalled with minint. + __ cmp(output_reg, 0x80000000u); + DeoptimizeIf(equal, instr->environment()); } else { + Label done; + // Deoptimize on negative numbers. + __ xorps(xmm_scratch, xmm_scratch); // Zero the register. + __ ucomisd(input_reg, xmm_scratch); DeoptimizeIf(below, instr->environment()); - } - // Use truncating instruction (OK because input is positive). - __ cvttsd2si(output_reg, Operand(input_reg)); + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { + // Check for negative zero. + Label positive_sign; + __ j(above, &positive_sign, Label::kNear); + __ movmskpd(output_reg, input_reg); + __ test(output_reg, Immediate(1)); + DeoptimizeIf(not_zero, instr->environment()); + __ Set(output_reg, Immediate(0)); + __ jmp(&done, Label::kNear); + __ bind(&positive_sign); + } - // Overflow is signalled with minint. - __ cmp(output_reg, 0x80000000u); - DeoptimizeIf(equal, instr->environment()); -} + // Use truncating instruction (OK because input is positive). + __ cvttsd2si(output_reg, Operand(input_reg)); + // Overflow is signalled with minint. + __ cmp(output_reg, 0x80000000u); + DeoptimizeIf(equal, instr->environment()); + __ bind(&done); + } +} void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { XMMRegister xmm_scratch = xmm0; @@ -2783,13 +2767,11 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { // xmm_scratch = 0.5 ExternalReference one_half = ExternalReference::address_of_one_half(); __ movdbl(xmm_scratch, Operand::StaticVariable(one_half)); - __ ucomisd(xmm_scratch, input_reg); __ j(above, &below_half); // input = input + 0.5 __ addsd(input_reg, xmm_scratch); - // Compute Math.floor(value + 0.5). // Use truncating instruction (OK because input is positive). __ cvttsd2si(output_reg, Operand(input_reg)); @@ -3108,8 +3090,14 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { - __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); - DeoptimizeIf(above_equal, instr->environment()); + if (instr->index()->IsConstantOperand()) { + __ cmp(ToOperand(instr->length()), + ToImmediate(LConstantOperand::cast(instr->index()))); + DeoptimizeIf(below_equal, instr->environment()); + } else { + __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); + DeoptimizeIf(above_equal, instr->environment()); + } } @@ -4200,6 +4188,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ cmp(input, factory()->false_value()); final_branch_condition = equal; + } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) { + __ cmp(input, factory()->null_value()); + final_branch_condition = equal; + } else if (type_name->Equals(heap()->undefined_symbol())) { __ cmp(input, factory()->undefined_value()); __ j(equal, true_label); @@ -4218,8 +4210,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, } else if (type_name->Equals(heap()->object_symbol())) { __ JumpIfSmi(input, false_label); - __ cmp(input, factory()->null_value()); - __ j(equal, true_label); + if (!FLAG_harmony_typeof) { + __ cmp(input, factory()->null_value()); + __ j(equal, true_label); + } __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); __ j(below, false_label); __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index c568bef5bb..d26f245553 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -222,7 +222,7 @@ class LCodeGen BASE_EMBEDDED { Register ToRegister(int index) const; XMMRegister ToDoubleRegister(int index) const; int ToInteger32(LConstantOperand* op) const; - Operand BuildFastArrayOperand(LOperand* external_pointer, + Operand BuildFastArrayOperand(LOperand* elements_pointer, LOperand* key, JSObject::ElementsKind elements_kind, uint32_t offset); diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index 07867c70f2..bb92e89d34 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/deps/v8/src/ia32/lithium-ia32.cc @@ -1047,10 +1047,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { // involving maps). bool needs_temp = expected.NeedsMap() || expected.IsEmpty(); LOperand* temp = needs_temp ? TempRegister() : NULL; - LInstruction* branch = new LBranch(UseRegister(v), temp); - // When we handle all cases, we never deopt, so we don't need to assign the - // environment then. - return expected.IsAll() ? branch : AssignEnvironment(branch); + return AssignEnvironment(new LBranch(UseRegister(v), temp)); } @@ -1541,16 +1538,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { } -LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { +LInstruction* LChunkBuilder::DoFixedArrayBaseLength( + HFixedArrayBaseLength* instr) { LOperand* array = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new LFixedArrayLength(array)); -} - - -LInstruction* LChunkBuilder::DoExternalArrayLength( - HExternalArrayLength* instr) { - LOperand* array = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new LExternalArrayLength(array)); + return DefineAsRegister(new LFixedArrayBaseLength(array)); } @@ -1568,8 +1559,9 @@ LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) { LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { - return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()), - UseAtStart(instr->length()))); + return AssignEnvironment(new LBoundsCheck( + UseRegisterOrConstantAtStart(instr->index()), + UseAtStart(instr->length()))); } @@ -1890,9 +1882,9 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement( ASSERT(instr->representation().IsTagged()); ASSERT(instr->key()->representation().IsInteger32()); LOperand* obj = UseRegisterAtStart(instr->object()); - LOperand* key = UseRegisterAtStart(instr->key()); + LOperand* key = UseRegisterOrConstantAtStart(instr->key()); LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key); - return AssignEnvironment(DefineSameAsFirst(result)); + return AssignEnvironment(DefineAsRegister(result)); } diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h index efa048dd24..e752b714e4 100644 --- a/deps/v8/src/ia32/lithium-ia32.h +++ b/deps/v8/src/ia32/lithium-ia32.h @@ -86,8 +86,7 @@ class LCodeGen; V(DivI) \ V(DoubleToI) \ V(ElementsKind) \ - V(ExternalArrayLength) \ - V(FixedArrayLength) \ + V(FixedArrayBaseLength) \ V(FunctionLiteral) \ V(GetCachedArrayIndex) \ V(GlobalObject) \ @@ -922,25 +921,15 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { }; -class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> { +class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { public: - explicit LExternalArrayLength(LOperand* value) { + explicit LFixedArrayBaseLength(LOperand* value) { inputs_[0] = value; } - DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length") - DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength) -}; - - -class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> { - public: - explicit LFixedArrayLength(LOperand* value) { - inputs_[0] = value; - } - - DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length") - DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength) + DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength, + "fixed-array-base-length") + DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength) }; @@ -2248,14 +2237,18 @@ class LChunkBuilder BASE_EMBEDDED { template LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr, XMMRegister reg); + // Assigns an environment to an instruction. An instruction which can + // deoptimize must have an environment. LInstruction* AssignEnvironment(LInstruction* instr); + // Assigns a pointer map to an instruction. An instruction which can + // trigger a GC or a lazy deoptimization must have a pointer map. LInstruction* AssignPointerMap(LInstruction* instr); enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY }; - // By default we assume that instruction sequences generated for calls - // cannot deoptimize eagerly and we do not attach environment to this - // instruction. + // Marks a call for the register allocator. Assigns a pointer map to + // support GC and lazy deoptimization. Assigns an environment to support + // eager deoptimization if CAN_DEOPTIMIZE_EAGERLY. LInstruction* MarkAsCall( LInstruction* instr, HInstruction* hinstr, diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index acb670b700..04e6cde4ed 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -542,7 +542,12 @@ void MacroAssembler::LeaveApiExitFrame() { void MacroAssembler::PushTryHandler(CodeLocation try_location, HandlerType type) { // Adjust this code if not the case. - ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); // The pc (return address) is already on TOS. if (try_location == IN_JAVASCRIPT) { if (type == TRY_CATCH_HANDLER) { @@ -551,6 +556,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, push(Immediate(StackHandler::TRY_FINALLY)); } push(ebp); + push(esi); } else { ASSERT(try_location == IN_JS_ENTRY); // The frame pointer does not point to a JS frame so we save NULL @@ -558,6 +564,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, // before dereferencing it to restore the context. push(Immediate(StackHandler::ENTRY)); push(Immediate(0)); // NULL frame pointer. + push(Immediate(Smi::FromInt(0))); // No context. } // Save the current handler as the next handler. push(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address, @@ -570,7 +577,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, void MacroAssembler::PopTryHandler() { - ASSERT_EQ(0, StackHandlerConstants::kNextOffset); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); pop(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address, isolate()))); add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize)); @@ -579,8 +586,12 @@ void MacroAssembler::PopTryHandler() { void MacroAssembler::Throw(Register value) { // Adjust this code if not the case. - STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); - + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); // eax must hold the exception. if (!value.is(eax)) { mov(eax, value); @@ -591,24 +602,21 @@ void MacroAssembler::Throw(Register value) { isolate()); mov(esp, Operand::StaticVariable(handler_address)); - // Restore next handler and frame pointer, discard handler state. - STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); + // Restore next handler, context, and frame pointer; discard handler state. pop(Operand::StaticVariable(handler_address)); - STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize); - pop(ebp); - pop(edx); // Remove state. + pop(esi); // Context. + pop(ebp); // Frame pointer. + pop(edx); // State. - // Before returning we restore the context from the frame pointer if - // not NULL. The frame pointer is NULL in the exception handler of - // a JS entry frame. - Set(esi, Immediate(0)); // Tentatively set context pointer to NULL. + // If the handler is a JS frame, restore the context to the frame. + // (edx == ENTRY) == (ebp == 0) == (esi == 0), so we could test any + // of them. Label skip; - cmp(ebp, 0); + cmp(Operand(edx), Immediate(StackHandler::ENTRY)); j(equal, &skip, Label::kNear); - mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); bind(&skip); - STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); ret(0); } @@ -616,7 +624,12 @@ void MacroAssembler::Throw(Register value) { void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, Register value) { // Adjust this code if not the case. - STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); // eax must hold the exception. if (!value.is(eax)) { @@ -642,7 +655,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, bind(&done); // Set the top handler address to next handler past the current ENTRY handler. - STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); pop(Operand::StaticVariable(handler_address)); if (type == OUT_OF_MEMORY) { @@ -660,15 +672,14 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, mov(Operand::StaticVariable(pending_exception), eax); } - // Clear the context pointer. + // Discard the context saved in the handler and clear the context pointer. + pop(edx); Set(esi, Immediate(0)); // Restore fp from handler and discard handler state. - STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize); pop(ebp); pop(edx); // State. - STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); ret(0); } diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index 73f42a3d18..4a37b07c71 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -3400,37 +3400,37 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ JumpIfNotSmi(eax, &miss_force_generic); // Check that the index is in range. - __ mov(ecx, eax); - __ SmiUntag(ecx); // Untag the index. __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); - __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); + __ cmp(eax, FieldOperand(ebx, ExternalArray::kLengthOffset)); // Unsigned comparison catches both negative and too-large values. __ j(above_equal, &miss_force_generic); __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); // ebx: base pointer of external storage switch (elements_kind) { case JSObject::EXTERNAL_BYTE_ELEMENTS: - __ movsx_b(eax, Operand(ebx, ecx, times_1, 0)); + __ SmiUntag(eax); // Untag the index. + __ movsx_b(eax, Operand(ebx, eax, times_1, 0)); break; case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case JSObject::EXTERNAL_PIXEL_ELEMENTS: - __ movzx_b(eax, Operand(ebx, ecx, times_1, 0)); + __ SmiUntag(eax); // Untag the index. + __ movzx_b(eax, Operand(ebx, eax, times_1, 0)); break; case JSObject::EXTERNAL_SHORT_ELEMENTS: - __ movsx_w(eax, Operand(ebx, ecx, times_2, 0)); + __ movsx_w(eax, Operand(ebx, eax, times_1, 0)); break; case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ movzx_w(eax, Operand(ebx, ecx, times_2, 0)); + __ movzx_w(eax, Operand(ebx, eax, times_1, 0)); break; case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: case JSObject::EXTERNAL_INT_ELEMENTS: - __ mov(ecx, Operand(ebx, ecx, times_4, 0)); + __ mov(ecx, Operand(ebx, eax, times_2, 0)); break; case JSObject::EXTERNAL_FLOAT_ELEMENTS: - __ fld_s(Operand(ebx, ecx, times_4, 0)); + __ fld_s(Operand(ebx, eax, times_2, 0)); break; case JSObject::EXTERNAL_DOUBLE_ELEMENTS: - __ fld_d(Operand(ebx, ecx, times_8, 0)); + __ fld_d(Operand(ebx, eax, times_4, 0)); break; default: UNREACHABLE(); @@ -3556,9 +3556,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // Check that the index is in range. __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); - __ mov(ebx, ecx); - __ SmiUntag(ebx); - __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); + __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset)); // Unsigned comparison catches both negative and too-large values. __ j(above_equal, &slow); @@ -3568,7 +3566,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // edx: receiver // ecx: key // edi: elements array - // ebx: untagged index if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) { __ JumpIfNotSmi(eax, &slow); } else { @@ -3576,44 +3573,39 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( } // smi case - __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. - __ SmiUntag(ecx); + __ mov(ebx, eax); // Preserve the value in eax as the return value. + __ SmiUntag(ebx); __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); - // ecx: base pointer of external storage + // edi: base pointer of external storage switch (elements_kind) { case JSObject::EXTERNAL_PIXEL_ELEMENTS: - { // Clamp the value to [0..255]. - Label done; - __ test(ecx, Immediate(0xFFFFFF00)); - __ j(zero, &done, Label::kNear); - __ setcc(negative, ecx); // 1 if negative, 0 if positive. - __ dec_b(ecx); // 0 if negative, 255 if positive. - __ bind(&done); - } - __ mov_b(Operand(edi, ebx, times_1, 0), ecx); + __ ClampUint8(ebx); + __ SmiUntag(ecx); + __ mov_b(Operand(edi, ecx, times_1, 0), ebx); break; case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ mov_b(Operand(edi, ebx, times_1, 0), ecx); + __ SmiUntag(ecx); + __ mov_b(Operand(edi, ecx, times_1, 0), ebx); break; case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ mov_w(Operand(edi, ebx, times_2, 0), ecx); + __ mov_w(Operand(edi, ecx, times_1, 0), ebx); break; case JSObject::EXTERNAL_INT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ mov(Operand(edi, ebx, times_4, 0), ecx); + __ mov(Operand(edi, ecx, times_2, 0), ebx); break; case JSObject::EXTERNAL_FLOAT_ELEMENTS: case JSObject::EXTERNAL_DOUBLE_ELEMENTS: // Need to perform int-to-float conversion. - __ push(ecx); + __ push(ebx); __ fild_s(Operand(esp, 0)); - __ pop(ecx); + __ pop(ebx); if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { - __ fstp_s(Operand(edi, ebx, times_4, 0)); + __ fstp_s(Operand(edi, ecx, times_2, 0)); } else { // elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS. - __ fstp_d(Operand(edi, ebx, times_8, 0)); + __ fstp_d(Operand(edi, ecx, times_4, 0)); } break; default: @@ -3629,7 +3621,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // edx: receiver // ecx: key // edi: elements array - // ebx: untagged index __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Immediate(masm->isolate()->factory()->heap_number_map())); __ j(not_equal, &slow); @@ -3638,15 +3629,14 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // +/-Infinity into integer arrays basically undefined. For more // reproducible behavior, convert these to zero. __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); - // ebx: untagged index // edi: base pointer of external storage if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); - __ fstp_s(Operand(edi, ebx, times_4, 0)); + __ fstp_s(Operand(edi, ecx, times_2, 0)); __ ret(0); } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); - __ fstp_d(Operand(edi, ebx, times_8, 0)); + __ fstp_d(Operand(edi, ecx, times_4, 0)); __ ret(0); } else { // Perform float-to-int conversion with truncation (round-to-zero) @@ -3661,27 +3651,20 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( elements_kind != JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) { ASSERT(CpuFeatures::IsSupported(SSE2)); CpuFeatures::Scope scope(SSE2); - __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); + __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset)); // ecx: untagged integer value switch (elements_kind) { case JSObject::EXTERNAL_PIXEL_ELEMENTS: - { // Clamp the value to [0..255]. - Label done; - __ test(ecx, Immediate(0xFFFFFF00)); - __ j(zero, &done, Label::kNear); - __ setcc(negative, ecx); // 1 if negative, 0 if positive. - __ dec_b(ecx); // 0 if negative, 255 if positive. - __ bind(&done); - } - __ mov_b(Operand(edi, ebx, times_1, 0), ecx); - break; + __ ClampUint8(ebx); + // Fall through. case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ mov_b(Operand(edi, ebx, times_1, 0), ecx); + __ SmiUntag(ecx); + __ mov_b(Operand(edi, ecx, times_1, 0), ebx); break; case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ mov_w(Operand(edi, ebx, times_2, 0), ecx); + __ mov_w(Operand(edi, ecx, times_1, 0), ebx); break; default: UNREACHABLE(); @@ -3698,7 +3681,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ sub(Operand(esp), Immediate(2 * kPointerSize)); __ fisttp_d(Operand(esp, 0)); - __ pop(ecx); + __ pop(ebx); __ add(Operand(esp), Immediate(kPointerSize)); } else { ASSERT(CpuFeatures::IsSupported(SSE2)); @@ -3709,15 +3692,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // Note: we could do better for signed int arrays. __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); // We will need the key if we have to make the slow runtime call. - __ push(ecx); - __ LoadPowerOf2(xmm1, ecx, 31); - __ pop(ecx); + __ push(ebx); + __ LoadPowerOf2(xmm1, ebx, 31); + __ pop(ebx); __ ucomisd(xmm1, xmm0); __ j(above_equal, &slow); - __ cvttsd2si(ecx, Operand(xmm0)); + __ cvttsd2si(ebx, Operand(xmm0)); } - // ecx: untagged integer value - __ mov(Operand(edi, ebx, times_4, 0), ecx); + // ebx: untagged integer value + __ mov(Operand(edi, ecx, times_2, 0), ebx); } __ ret(0); // Return original value. } diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 9ca61177ba..eae812bcd9 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -1533,6 +1533,9 @@ void Isolate::SetIsolateThreadLocals(Isolate* isolate, Isolate::~Isolate() { TRACE_ISOLATE(destructor); + // Has to be called while counters_ are still alive. + zone_.DeleteKeptSegment(); + delete unicode_cache_; unicode_cache_ = NULL; @@ -1591,6 +1594,9 @@ Isolate::~Isolate() { delete global_handles_; global_handles_ = NULL; + delete external_reference_table_; + external_reference_table_ = NULL; + #ifdef ENABLE_DEBUGGER_SUPPORT delete debugger_; debugger_ = NULL; diff --git a/deps/v8/src/liveobjectlist.cc b/deps/v8/src/liveobjectlist.cc index e382a06456..451a28ab70 100644 --- a/deps/v8/src/liveobjectlist.cc +++ b/deps/v8/src/liveobjectlist.cc @@ -36,11 +36,12 @@ #include "global-handles.h" #include "heap.h" #include "inspector.h" +#include "isolate.h" #include "list-inl.h" #include "liveobjectlist-inl.h" #include "string-stream.h" -#include "top.h" #include "v8utils.h" +#include "v8conversions.h" namespace v8 { namespace internal { @@ -109,7 +110,7 @@ typedef int (*RawComparer)(const void*, const void*); \ v(Context, "meta: Context") \ v(ByteArray, "meta: ByteArray") \ - v(PixelArray, "meta: PixelArray") \ + v(ExternalPixelArray, "meta: PixelArray") \ v(ExternalArray, "meta: ExternalArray") \ v(FixedArray, "meta: FixedArray") \ v(String, "String") \ @@ -211,8 +212,9 @@ static AllocationSpace FindSpaceFor(String* space_str) { static bool InSpace(AllocationSpace space, HeapObject *heap_obj) { + Heap* heap = ISOLATE->heap(); if (space != LO_SPACE) { - return Heap::InSpace(heap_obj, space); + return heap->InSpace(heap_obj, space); } // This is an optimization to speed up the check for an object in the LO @@ -224,11 +226,11 @@ static bool InSpace(AllocationSpace space, HeapObject *heap_obj) { int first_space = static_cast(FIRST_SPACE); int last_space = static_cast(LO_SPACE); for (int sp = first_space; sp < last_space; sp++) { - if (Heap::InSpace(heap_obj, static_cast(sp))) { + if (heap->InSpace(heap_obj, static_cast(sp))) { return false; } } - SLOW_ASSERT(Heap::InSpace(heap_obj, LO_SPACE)); + SLOW_ASSERT(heap->InSpace(heap_obj, LO_SPACE)); return true; } @@ -285,7 +287,7 @@ LolFilter::LolFilter(Handle filter_obj) void LolFilter::InitTypeFilter(Handle filter_obj) { - Handle type_sym = Factory::LookupAsciiSymbol("type"); + Handle type_sym = FACTORY->LookupAsciiSymbol("type"); MaybeObject* maybe_result = filter_obj->GetProperty(*type_sym); Object* type_obj; if (maybe_result->ToObject(&type_obj)) { @@ -301,7 +303,7 @@ void LolFilter::InitTypeFilter(Handle filter_obj) { void LolFilter::InitSpaceFilter(Handle filter_obj) { - Handle space_sym = Factory::LookupAsciiSymbol("space"); + Handle space_sym = FACTORY->LookupAsciiSymbol("space"); MaybeObject* maybe_result = filter_obj->GetProperty(*space_sym); Object* space_obj; if (maybe_result->ToObject(&space_obj)) { @@ -317,7 +319,7 @@ void LolFilter::InitSpaceFilter(Handle filter_obj) { void LolFilter::InitPropertyFilter(Handle filter_obj) { - Handle prop_sym = Factory::LookupAsciiSymbol("prop"); + Handle prop_sym = FACTORY->LookupAsciiSymbol("prop"); MaybeObject* maybe_result = filter_obj->GetProperty(*prop_sym); Object* prop_obj; if (maybe_result->ToObject(&prop_obj)) { @@ -571,7 +573,9 @@ static bool AddObjDetail(Handle arr, Handle detail, Handle desc, Handle error) { - detail = Factory::NewJSObject(Top::object_function()); + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + detail = factory->NewJSObject(isolate->object_function()); if (detail->IsFailure()) { error = detail; return false; @@ -586,7 +590,7 @@ static bool AddObjDetail(Handle arr, desc_str = buffer; size = obj->Size(); } - desc = Factory::NewStringFromAscii(CStrVector(desc_str)); + desc = factory->NewStringFromAscii(CStrVector(desc_str)); if (desc->IsFailure()) { error = desc; return false; @@ -663,10 +667,13 @@ class LolDumpWriter: public DumpWriter { int index = 0; int count = 0; + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + // Prefetch some needed symbols. - Handle id_sym = Factory::LookupAsciiSymbol("id"); - Handle desc_sym = Factory::LookupAsciiSymbol("desc"); - Handle size_sym = Factory::LookupAsciiSymbol("size"); + Handle id_sym = factory->LookupAsciiSymbol("id"); + Handle desc_sym = factory->LookupAsciiSymbol("desc"); + Handle size_sym = factory->LookupAsciiSymbol("size"); // Fill the array with the lol object details. Handle detail; @@ -1089,7 +1096,9 @@ static int CountHeapObjects() { // Captures a current snapshot of all objects in the heap. MaybeObject* LiveObjectList::Capture() { - HandleScope scope; + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + HandleScope scope(isolate); // Count the number of objects in the heap. int total_count = CountHeapObjects(); @@ -1139,11 +1148,11 @@ MaybeObject* LiveObjectList::Capture() { #endif } - Handle id_sym = Factory::LookupAsciiSymbol("id"); - Handle count_sym = Factory::LookupAsciiSymbol("count"); - Handle size_sym = Factory::LookupAsciiSymbol("size"); + Handle id_sym = factory->LookupAsciiSymbol("id"); + Handle count_sym = factory->LookupAsciiSymbol("count"); + Handle size_sym = factory->LookupAsciiSymbol("size"); - Handle result = Factory::NewJSObject(Top::object_function()); + Handle result = factory->NewJSObject(isolate->object_function()); if (result->IsFailure()) return Object::cast(*result); { MaybeObject* maybe_result = result->SetProperty(*id_sym, @@ -1259,7 +1268,10 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer, int start, int dump_limit, LolFilter* filter) { - HandleScope scope; + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + + HandleScope scope(isolate); // Calculate the number of entries of the dump. int count = -1; @@ -1277,7 +1289,7 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer, } // Allocate an array to hold the result. - Handle elements_arr = Factory::NewFixedArray(dump_limit); + Handle elements_arr = factory->NewFixedArray(dump_limit); if (elements_arr->IsFailure()) return Object::cast(*elements_arr); // Fill in the dump. @@ -1292,11 +1304,11 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer, MaybeObject* maybe_result; // Allocate the result body. - Handle body = Factory::NewJSObject(Top::object_function()); + Handle body = factory->NewJSObject(isolate->object_function()); if (body->IsFailure()) return Object::cast(*body); // Set the updated body.count. - Handle count_sym = Factory::LookupAsciiSymbol("count"); + Handle count_sym = factory->LookupAsciiSymbol("count"); maybe_result = body->SetProperty(*count_sym, Smi::FromInt(count), NONE, @@ -1305,7 +1317,7 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer, // Set the updated body.size if appropriate. if (size >= 0) { - Handle size_sym = Factory::LookupAsciiSymbol("size"); + Handle size_sym = factory->LookupAsciiSymbol("size"); maybe_result = body->SetProperty(*size_sym, Smi::FromInt(size), NONE, @@ -1314,7 +1326,7 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer, } // Set body.first_index. - Handle first_sym = Factory::LookupAsciiSymbol("first_index"); + Handle first_sym = factory->LookupAsciiSymbol("first_index"); maybe_result = body->SetProperty(*first_sym, Smi::FromInt(start), NONE, @@ -1322,12 +1334,12 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer, if (maybe_result->IsFailure()) return maybe_result; // Allocate the JSArray of the elements. - Handle elements = Factory::NewJSObject(Top::array_function()); + Handle elements = factory->NewJSObject(isolate->array_function()); if (elements->IsFailure()) return Object::cast(*elements); Handle::cast(elements)->SetContent(*elements_arr); // Set body.elements. - Handle elements_sym = Factory::LookupAsciiSymbol("elements"); + Handle elements_sym = factory->LookupAsciiSymbol("elements"); maybe_result = body->SetProperty(*elements_sym, *elements, NONE, @@ -1381,6 +1393,9 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer, LiveObjectSummary summary(filter); writer->Write(&summary); + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + // The result body will look like this: // body: { // count: , @@ -1398,21 +1413,21 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer, // } // Prefetch some needed symbols. - Handle desc_sym = Factory::LookupAsciiSymbol("desc"); - Handle count_sym = Factory::LookupAsciiSymbol("count"); - Handle size_sym = Factory::LookupAsciiSymbol("size"); - Handle summary_sym = Factory::LookupAsciiSymbol("summary"); + Handle desc_sym = factory->LookupAsciiSymbol("desc"); + Handle count_sym = factory->LookupAsciiSymbol("count"); + Handle size_sym = factory->LookupAsciiSymbol("size"); + Handle summary_sym = factory->LookupAsciiSymbol("summary"); // Allocate the summary array. int entries_count = summary.GetNumberOfEntries(); Handle summary_arr = - Factory::NewFixedArray(entries_count); + factory->NewFixedArray(entries_count); if (summary_arr->IsFailure()) return Object::cast(*summary_arr); int idx = 0; for (int i = 0; i < LiveObjectSummary::kNumberOfEntries; i++) { // Allocate the summary record. - Handle detail = Factory::NewJSObject(Top::object_function()); + Handle detail = factory->NewJSObject(isolate->object_function()); if (detail->IsFailure()) return Object::cast(*detail); // Fill in the summary record. @@ -1420,7 +1435,7 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer, int count = summary.Count(type); if (count) { const char* desc_cstr = GetObjectTypeDesc(type); - Handle desc = Factory::LookupAsciiSymbol(desc_cstr); + Handle desc = factory->LookupAsciiSymbol(desc_cstr); int size = summary.Size(type); maybe_result = detail->SetProperty(*desc_sym, @@ -1444,12 +1459,13 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer, } // Wrap the summary fixed array in a JS array. - Handle summary_obj = Factory::NewJSObject(Top::array_function()); + Handle summary_obj = + factory->NewJSObject(isolate->array_function()); if (summary_obj->IsFailure()) return Object::cast(*summary_obj); Handle::cast(summary_obj)->SetContent(*summary_arr); // Create the body object. - Handle body = Factory::NewJSObject(Top::object_function()); + Handle body = factory->NewJSObject(isolate->object_function()); if (body->IsFailure()) return Object::cast(*body); // Fill out the body object. @@ -1470,9 +1486,9 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer, if (is_tracking_roots) { int found_root = summary.found_root(); int found_weak_root = summary.found_weak_root(); - Handle root_sym = Factory::LookupAsciiSymbol("found_root"); + Handle root_sym = factory->LookupAsciiSymbol("found_root"); Handle weak_root_sym = - Factory::LookupAsciiSymbol("found_weak_root"); + factory->LookupAsciiSymbol("found_weak_root"); maybe_result = body->SetProperty(*root_sym, Smi::FromInt(found_root), NONE, @@ -1499,7 +1515,10 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer, // Note: only dumps the section starting at start_idx and only up to // dump_limit entries. MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) { - HandleScope scope; + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + + HandleScope scope(isolate); MaybeObject* maybe_result; int total_count = LiveObjectList::list_count(); @@ -1519,13 +1538,13 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) { } // Allocate an array to hold the result. - Handle list = Factory::NewFixedArray(dump_count); + Handle list = factory->NewFixedArray(dump_count); if (list->IsFailure()) return Object::cast(*list); // Prefetch some needed symbols. - Handle id_sym = Factory::LookupAsciiSymbol("id"); - Handle count_sym = Factory::LookupAsciiSymbol("count"); - Handle size_sym = Factory::LookupAsciiSymbol("size"); + Handle id_sym = factory->LookupAsciiSymbol("id"); + Handle count_sym = factory->LookupAsciiSymbol("count"); + Handle size_sym = factory->LookupAsciiSymbol("size"); // Fill the array with the lol details. int idx = 0; @@ -1543,7 +1562,8 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) { int size; count = lol->GetTotalObjCountAndSize(&size); - Handle detail = Factory::NewJSObject(Top::object_function()); + Handle detail = + factory->NewJSObject(isolate->object_function()); if (detail->IsFailure()) return Object::cast(*detail); maybe_result = detail->SetProperty(*id_sym, @@ -1568,10 +1588,10 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) { } // Return the result as a JS array. - Handle lols = Factory::NewJSObject(Top::array_function()); + Handle lols = factory->NewJSObject(isolate->array_function()); Handle::cast(lols)->SetContent(*list); - Handle result = Factory::NewJSObject(Top::object_function()); + Handle result = factory->NewJSObject(isolate->object_function()); if (result->IsFailure()) return Object::cast(*result); maybe_result = result->SetProperty(*count_sym, @@ -1580,14 +1600,14 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) { kNonStrictMode); if (maybe_result->IsFailure()) return maybe_result; - Handle first_sym = Factory::LookupAsciiSymbol("first_index"); + Handle first_sym = factory->LookupAsciiSymbol("first_index"); maybe_result = result->SetProperty(*first_sym, Smi::FromInt(start_idx), NONE, kNonStrictMode); if (maybe_result->IsFailure()) return maybe_result; - Handle lists_sym = Factory::LookupAsciiSymbol("lists"); + Handle lists_sym = factory->LookupAsciiSymbol("lists"); maybe_result = result->SetProperty(*lists_sym, *lols, NONE, @@ -1618,7 +1638,7 @@ Object* LiveObjectList::GetObj(int obj_id) { if (element != NULL) { return Object::cast(element->obj_); } - return Heap::undefined_value(); + return HEAP->undefined_value(); } @@ -1639,8 +1659,11 @@ Object* LiveObjectList::GetObjId(Handle address) { SmartPointer addr_str = address->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); + Isolate* isolate = Isolate::Current(); + // Extract the address value from the string. - int value = static_cast(StringToInt(*address, 16)); + int value = + static_cast(StringToInt(isolate->unicode_cache(), *address, 16)); Object* obj = reinterpret_cast(value); return Smi::FromInt(GetObjId(obj)); } @@ -1760,10 +1783,13 @@ int LiveObjectList::GetRetainers(Handle target, Handle desc; Handle retainer; + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + // Prefetch some needed symbols. - Handle id_sym = Factory::LookupAsciiSymbol("id"); - Handle desc_sym = Factory::LookupAsciiSymbol("desc"); - Handle size_sym = Factory::LookupAsciiSymbol("size"); + Handle id_sym = factory->LookupAsciiSymbol("id"); + Handle desc_sym = factory->LookupAsciiSymbol("desc"); + Handle size_sym = factory->LookupAsciiSymbol("size"); NoHandleAllocation ha; int count = 0; @@ -1774,7 +1800,7 @@ int LiveObjectList::GetRetainers(Handle target, // Iterate roots. LolVisitor lol_visitor(*target, target); - Heap::IterateStrongRoots(&lol_visitor, VISIT_ALL); + isolate->heap()->IterateStrongRoots(&lol_visitor, VISIT_ALL); if (!AddRootRetainerIfFound(lol_visitor, filter, summary, @@ -1794,7 +1820,7 @@ int LiveObjectList::GetRetainers(Handle target, } lol_visitor.reset(); - Heap::IterateWeakRoots(&lol_visitor, VISIT_ALL); + isolate->heap()->IterateWeakRoots(&lol_visitor, VISIT_ALL); if (!AddRootRetainerIfFound(lol_visitor, filter, summary, @@ -1903,11 +1929,15 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id, int start, int dump_limit, Handle filter_obj) { - HandleScope scope; + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + Heap* heap = isolate->heap(); + + HandleScope scope(isolate); // Get the target object. HeapObject* heap_obj = HeapObject::cast(GetObj(obj_id)); - if (heap_obj == Heap::undefined_value()) { + if (heap_obj == heap->undefined_value()) { return heap_obj; } @@ -1915,7 +1945,7 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id, // Get the constructor function for context extension and arguments array. JSObject* arguments_boilerplate = - Top::context()->global_context()->arguments_boilerplate(); + isolate->context()->global_context()->arguments_boilerplate(); JSFunction* arguments_function = JSFunction::cast(arguments_boilerplate->map()->constructor()); @@ -1937,7 +1967,7 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id, // Set body.id. Handle body = Handle(JSObject::cast(body_obj)); - Handle id_sym = Factory::LookupAsciiSymbol("id"); + Handle id_sym = factory->LookupAsciiSymbol("id"); maybe_result = body->SetProperty(*id_sym, Smi::FromInt(obj_id), NONE, @@ -1952,13 +1982,17 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id, Object* LiveObjectList::PrintObj(int obj_id) { Object* obj = GetObj(obj_id); if (!obj) { - return Heap::undefined_value(); + return HEAP->undefined_value(); } EmbeddedVector temp_filename; static int temp_count = 0; const char* path_prefix = "."; + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + Heap* heap = isolate->heap(); + if (FLAG_lol_workdir) { path_prefix = FLAG_lol_workdir; } @@ -1987,13 +2021,13 @@ Object* LiveObjectList::PrintObj(int obj_id) { if (resource->exists() && !resource->is_empty()) { ASSERT(resource->IsAscii()); Handle dump_string = - Factory::NewExternalStringFromAscii(resource); - ExternalStringTable::AddString(*dump_string); + factory->NewExternalStringFromAscii(resource); + heap->external_string_table()->AddString(*dump_string); return *dump_string; } else { delete resource; } - return Heap::undefined_value(); + return HEAP->undefined_value(); } @@ -2081,6 +2115,10 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) { FILE* f = OS::FOpen(temp_filename.start(), "w+"); + Isolate* isolate = Isolate::Current(); + Factory* factory = isolate->factory(); + Heap* heap = isolate->heap(); + // Save the previous verbosity. bool prev_verbosity = FLAG_use_verbose_printer; FLAG_use_verbose_printer = false; @@ -2096,15 +2134,14 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) { // Check for ObjectGroups that references this object. // TODO(mlam): refactor this to be more modular. { - List* groups = GlobalHandles::ObjectGroups(); + List* groups = isolate->global_handles()->object_groups(); for (int i = 0; i < groups->length(); i++) { ObjectGroup* group = groups->at(i); if (group == NULL) continue; bool found_group = false; - List& objects = group->objects_; - for (int j = 0; j < objects.length(); j++) { - Object* object = *objects[j]; + for (size_t j = 0; j < group->length_; j++) { + Object* object = *(group->objects_[j]); HeapObject* hobj = HeapObject::cast(object); if (obj2 == hobj) { found_group = true; @@ -2117,8 +2154,8 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) { "obj %p is a member of object group %p {\n", reinterpret_cast(obj2), reinterpret_cast(group)); - for (int j = 0; j < objects.length(); j++) { - Object* object = *objects[j]; + for (size_t j = 0; j < group->length_; j++) { + Object* object = *(group->objects_[j]); if (!object->IsHeapObject()) continue; HeapObject* hobj = HeapObject::cast(object); @@ -2143,12 +2180,12 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) { } PrintF(f, "path from roots to obj %p\n", reinterpret_cast(obj2)); - Heap::IterateRoots(&tracer, VISIT_ONLY_STRONG); + heap->IterateRoots(&tracer, VISIT_ONLY_STRONG); found = tracer.found(); if (!found) { PrintF(f, " No paths found. Checking symbol tables ...\n"); - SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table(); + SymbolTable* symbol_table = HEAP->raw_unchecked_symbol_table(); tracer.VisitPointers(reinterpret_cast(&symbol_table), reinterpret_cast(&symbol_table)+1); found = tracer.found(); @@ -2161,7 +2198,7 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) { if (!found) { PrintF(f, " No paths found. Checking weak roots ...\n"); // Check weak refs next. - GlobalHandles::IterateWeakRoots(&tracer); + isolate->global_handles()->IterateWeakRoots(&tracer); found = tracer.found(); } @@ -2191,13 +2228,13 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) { if (resource->exists() && !resource->is_empty()) { ASSERT(resource->IsAscii()); Handle path_string = - Factory::NewExternalStringFromAscii(resource); - ExternalStringTable::AddString(*path_string); + factory->NewExternalStringFromAscii(resource); + heap->external_string_table()->AddString(*path_string); return *path_string; } else { delete resource; } - return Heap::undefined_value(); + return heap->undefined_value(); } @@ -2210,13 +2247,13 @@ Object* LiveObjectList::GetPath(int obj_id1, HeapObject* obj1 = NULL; if (obj_id1 != 0) { obj1 = HeapObject::cast(GetObj(obj_id1)); - if (obj1 == Heap::undefined_value()) { + if (obj1 == HEAP->undefined_value()) { return obj1; } } HeapObject* obj2 = HeapObject::cast(GetObj(obj_id2)); - if (obj2 == Heap::undefined_value()) { + if (obj2 == HEAP->undefined_value()) { return obj2; } @@ -2570,12 +2607,13 @@ void LiveObjectList::Verify(bool match_heap_exactly) { void LiveObjectList::VerifyNotInFromSpace() { OS::Print("VerifyNotInFromSpace() ...\n"); LolIterator it(NULL, last()); + Heap* heap = ISOLATE->heap(); int i = 0; for (it.Init(); !it.Done(); it.Next()) { HeapObject* heap_obj = it.Obj(); - if (Heap::InFromSpace(heap_obj)) { + if (heap->InFromSpace(heap_obj)) { OS::Print(" ERROR: VerifyNotInFromSpace: [%d] obj %p in From space %p\n", - i++, heap_obj, Heap::new_space()->FromSpaceLow()); + i++, heap_obj, heap->new_space()->FromSpaceLow()); } } } diff --git a/deps/v8/src/liveobjectlist.h b/deps/v8/src/liveobjectlist.h index 23e418d6d8..542482d9c5 100644 --- a/deps/v8/src/liveobjectlist.h +++ b/deps/v8/src/liveobjectlist.h @@ -237,10 +237,10 @@ class UpdateLiveObjectListVisitor: public ObjectVisitor { // to live new space objects, and not actually keep them alive. void UpdatePointer(Object** p) { Object* object = *p; - if (!Heap::InNewSpace(object)) return; + if (!HEAP->InNewSpace(object)) return; HeapObject* heap_obj = HeapObject::cast(object); - ASSERT(Heap::InFromSpace(heap_obj)); + ASSERT(HEAP->InFromSpace(heap_obj)); // We use the first word (where the map pointer usually is) of a heap // object to record the forwarding pointer. A forwarding pointer can diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index 6603185a32..58c9a53025 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -247,6 +247,7 @@ function FormatMessage(message) { 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 message_type = %MessageGetType(message); diff --git a/deps/v8/src/mips/frames-mips.h b/deps/v8/src/mips/frames-mips.h index 2e720fb17e..8c605a39d9 100644 --- a/deps/v8/src/mips/frames-mips.h +++ b/deps/v8/src/mips/frames-mips.h @@ -121,10 +121,11 @@ static const int kSafepointRegisterStackIndexMap[kNumRegs] = { class StackHandlerConstants : public AllStatic { public: - static const int kNextOffset = 0 * kPointerSize; - static const int kStateOffset = 1 * kPointerSize; - static const int kFPOffset = 2 * kPointerSize; - static const int kPCOffset = 3 * kPointerSize; + static const int kNextOffset = 0 * kPointerSize; + static const int kStateOffset = 1 * kPointerSize; + static const int kContextOffset = 2 * kPointerSize; + static const int kFPOffset = 3 * kPointerSize; + static const int kPCOffset = 4 * kPointerSize; static const int kSize = kPCOffset + kPointerSize; }; diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc index 4943a03a1a..d8909c9ddd 100644 --- a/deps/v8/src/mips/full-codegen-mips.cc +++ b/deps/v8/src/mips/full-codegen-mips.cc @@ -4052,6 +4052,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ Branch(if_true, eq, v0, Operand(at)); __ LoadRoot(at, Heap::kFalseValueRootIndex); Split(eq, v0, Operand(at), if_true, if_false, fall_through); + } else if (FLAG_harmony_typeof && + check->Equals(isolate()->heap()->null_symbol())) { + __ LoadRoot(at, Heap::kNullValueRootIndex); + Split(eq, v0, Operand(at), if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->undefined_symbol())) { __ LoadRoot(at, Heap::kUndefinedValueRootIndex); __ Branch(if_true, eq, v0, Operand(at)); @@ -4069,8 +4073,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } else if (check->Equals(isolate()->heap()->object_symbol())) { __ JumpIfSmi(v0, if_false); - __ LoadRoot(at, Heap::kNullValueRootIndex); - __ Branch(if_true, eq, v0, Operand(at)); + if (!FLAG_harmony_typeof) { + __ LoadRoot(at, Heap::kNullValueRootIndex); + __ Branch(if_true, eq, v0, Operand(at)); + } // Check for JS objects => true. __ GetObjectType(v0, v0, a1); __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc index 5e8d676ace..76b713f511 100644 --- a/deps/v8/src/mips/macro-assembler-mips.cc +++ b/deps/v8/src/mips/macro-assembler-mips.cc @@ -2244,7 +2244,13 @@ void MacroAssembler::DebugBreak() { void MacroAssembler::PushTryHandler(CodeLocation try_location, HandlerType type) { // Adjust this code if not the case. - ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); + // The return address is passed in register ra. if (try_location == IN_JAVASCRIPT) { if (type == TRY_CATCH_HANDLER) { @@ -2252,19 +2258,16 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, } else { li(t0, Operand(StackHandler::TRY_FINALLY)); } - ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize - && StackHandlerConstants::kFPOffset == 2 * kPointerSize - && StackHandlerConstants::kPCOffset == 3 * kPointerSize - && StackHandlerConstants::kNextOffset == 0 * kPointerSize); // Save the current handler as the next handler. li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); lw(t1, MemOperand(t2)); addiu(sp, sp, -StackHandlerConstants::kSize); - sw(ra, MemOperand(sp, 12)); - sw(fp, MemOperand(sp, 8)); - sw(t0, MemOperand(sp, 4)); - sw(t1, MemOperand(sp, 0)); + sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset)); + sw(fp, MemOperand(sp, StackHandlerConstants::kFPOffset)); + sw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset)); + sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset)); + sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset)); // Link this handler as the new current one. sw(sp, MemOperand(t2)); @@ -2272,11 +2275,6 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, } else { // Must preserve a0-a3, and s0 (argv). ASSERT(try_location == IN_JS_ENTRY); - ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize - && StackHandlerConstants::kFPOffset == 2 * kPointerSize - && StackHandlerConstants::kPCOffset == 3 * kPointerSize - && StackHandlerConstants::kNextOffset == 0 * kPointerSize); - // The frame pointer does not point to a JS frame so we save NULL // for fp. We expect the code throwing an exception to check fp // before dereferencing it to restore the context. @@ -2286,11 +2284,14 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); lw(t1, MemOperand(t2)); + ASSERT(Smi::FromInt(0) == 0); // Used for no context. + addiu(sp, sp, -StackHandlerConstants::kSize); - sw(ra, MemOperand(sp, 12)); - sw(zero_reg, MemOperand(sp, 8)); - sw(t0, MemOperand(sp, 4)); - sw(t1, MemOperand(sp, 0)); + sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset)); + sw(zero_reg, MemOperand(sp, StackHandlerConstants::kFPOffset)); + sw(zero_reg, MemOperand(sp, StackHandlerConstants::kContextOffset)); + sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset)); + sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset)); // Link this handler as the new current one. sw(sp, MemOperand(t2)); @@ -2299,7 +2300,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, void MacroAssembler::PopTryHandler() { - ASSERT_EQ(0, StackHandlerConstants::kNextOffset); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); pop(a1); Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); @@ -2312,28 +2313,31 @@ void MacroAssembler::Throw(Register value) { Move(v0, value); // Adjust this code if not the case. - STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); // Drop the sp to the top of the handler. li(a3, Operand(ExternalReference(Isolate::k_handler_address, - isolate()))); + isolate()))); lw(sp, MemOperand(a3)); - // Restore the next handler and frame pointer, discard handler state. - STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); + // Restore the next handler. pop(a2); sw(a2, MemOperand(a3)); - STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); - MultiPop(a3.bit() | fp.bit()); - // Before returning we restore the context from the frame pointer if - // not NULL. The frame pointer is NULL in the exception handler of a - // JS entry frame. - // Set cp to NULL if fp is NULL. + // Restore context and frame pointer, discard state (a3). + MultiPop(a3.bit() | cp.bit() | fp.bit()); + + // If the handler is a JS frame, restore the context to the frame. + // (a3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any + // of them. Label done; - Branch(USE_DELAY_SLOT, &done, eq, fp, Operand(zero_reg)); - mov(cp, zero_reg); // In branch delay slot. - lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + Branch(&done, eq, fp, Operand(zero_reg)); + sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); bind(&done); #ifdef DEBUG @@ -2355,7 +2359,6 @@ void MacroAssembler::Throw(Register value) { } #endif - STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); pop(t9); // 2 instructions: lw, add sp. Jump(t9); // 2 instructions: jr, nop (in delay slot). @@ -2370,7 +2373,12 @@ void MacroAssembler::Throw(Register value) { void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, Register value) { // Adjust this code if not the case. - STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); // v0 is expected to hold the exception. Move(v0, value); @@ -2393,7 +2401,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, bind(&done); // Set the top handler address to next handler past the current ENTRY handler. - STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); pop(a2); sw(a2, MemOperand(a3)); @@ -2415,20 +2422,12 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, // Stack layout at this point. See also StackHandlerConstants. // sp -> state (ENTRY) + // cp // fp // ra - // Discard handler state (a2 is not used) and restore frame pointer. - STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); - MultiPop(a2.bit() | fp.bit()); // a2: discarded state. - // Before returning we restore the context from the frame pointer if - // not NULL. The frame pointer is NULL in the exception handler of a - // JS entry frame. - Label cp_null; - Branch(USE_DELAY_SLOT, &cp_null, eq, fp, Operand(zero_reg)); - mov(cp, zero_reg); // In the branch delay slot. - lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - bind(&cp_null); + // Restore context and frame pointer, discard state (r2). + MultiPop(a2.bit() | cp.bit() | fp.bit()); #ifdef DEBUG // When emitting debug_code, set ra as return address for the jump. @@ -2448,7 +2447,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, addiu(ra, ra, kOffsetRaBytes); } #endif - STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); pop(t9); // 2 instructions: lw, add sp. Jump(t9); // 2 instructions: jr, nop (in delay slot). diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc index 84ff991ce2..ec63551b1c 100644 --- a/deps/v8/src/mips/stub-cache-mips.cc +++ b/deps/v8/src/mips/stub-cache-mips.cc @@ -3494,7 +3494,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset)); __ sra(t2, key, kSmiTagSize); // Unsigned comparison catches both negative and too-large values. - __ Branch(&miss_force_generic, Uless, t1, Operand(t2)); + __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1)); __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset)); // a3: base pointer of external storage @@ -3822,16 +3822,16 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset)); - - // Check that the key is a smi. + // Check that the key is a smi. __ JumpIfNotSmi(key, &miss_force_generic); + __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset)); + // Check that the index is in range. __ SmiUntag(t0, key); __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset)); // Unsigned comparison catches both negative and too-large values. - __ Branch(&miss_force_generic, Ugreater_equal, t0, Operand(t1)); + __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1)); // Handle both smis and HeapNumbers in the fast path. Go to the // runtime for all other kinds of values. diff --git a/deps/v8/src/mirror-debugger.js b/deps/v8/src/mirror-debugger.js index bad08002d7..e3f3c48bb5 100644 --- a/deps/v8/src/mirror-debugger.js +++ b/deps/v8/src/mirror-debugger.js @@ -195,7 +195,8 @@ ScopeType = { Global: 0, Local: 1, With: 2, Closure: 3, - Catch: 4 }; + Catch: 4, + Block: 5 }; // Mirror hierarchy: diff --git a/deps/v8/src/mksnapshot.cc b/deps/v8/src/mksnapshot.cc index c5ce12f0ec..4f5fe96a90 100644 --- a/deps/v8/src/mksnapshot.cc +++ b/deps/v8/src/mksnapshot.cc @@ -40,8 +40,6 @@ #include "serialize.h" #include "list.h" -// use explicit namespace to avoid clashing with types in namespace v8 -namespace i = v8::internal; using namespace v8; static const unsigned int kMaxCounters = 256; diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 70ed47be1f..c5fda89e42 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -552,7 +552,8 @@ bool Object::IsContext() { return (map == heap->function_context_map() || map == heap->catch_context_map() || map == heap->with_context_map() || - map == heap->global_context_map()); + map == heap->global_context_map() || + map == heap->block_context_map()); } return false; } @@ -565,6 +566,13 @@ bool Object::IsGlobalContext() { } +bool Object::IsSerializedScopeInfo() { + return Object::IsHeapObject() && + HeapObject::cast(this)->map() == + HeapObject::cast(this)->GetHeap()->serialized_scope_info_map(); +} + + bool Object::IsJSFunction() { return Object::IsHeapObject() && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE; @@ -1335,14 +1343,14 @@ int HeapNumber::get_sign() { ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset) -HeapObject* JSObject::elements() { +FixedArrayBase* JSObject::elements() { Object* array = READ_FIELD(this, kElementsOffset); ASSERT(array->HasValidElements()); - return reinterpret_cast(array); + return static_cast(array); } -void JSObject::set_elements(HeapObject* value, WriteBarrierMode mode) { +void JSObject::set_elements(FixedArrayBase* value, WriteBarrierMode mode) { ASSERT(map()->has_fast_elements() == (value->map() == GetHeap()->fixed_array_map() || value->map() == GetHeap()->fixed_cow_array_map())); @@ -2114,12 +2122,6 @@ HashTable* HashTable::cast(Object* obj) { SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset) -SMI_ACCESSORS(ByteArray, length, kLengthOffset) - -// TODO(1493): Investigate if it's possible to s/INT/SMI/ here (and -// subsequently unify H{Fixed,External}ArrayLength). -INT_ACCESSORS(ExternalArray, length, kLengthOffset) - SMI_ACCESSORS(String, length, kLengthOffset) diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index e35274d0aa..337dd65db0 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -2318,7 +2318,8 @@ MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler( if (has_exception) return Failure::Exception(); Object* bool_result = result->ToBoolean(); - if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) { + if (mode == STRICT_DELETION && + bool_result == isolate->heap()->false_value()) { Handle args[] = { handler, trap_name }; Handle error = isolate->factory()->NewTypeError( "handler_failed", HandleVector(args, ARRAY_SIZE(args))); @@ -3167,9 +3168,10 @@ MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) { ASSERT(result->IsBoolean()); return *v8::Utils::OpenHandle(*result); } - MaybeObject* raw_result = GetElementsAccessor()->Delete(*this_handle, - index, - NORMAL_DELETION); + MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete( + *this_handle, + index, + NORMAL_DELETION); RETURN_IF_SCHEDULED_EXCEPTION(isolate); return raw_result; } @@ -4637,7 +4639,20 @@ MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps, MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { - return array->GetElementsAccessor()->AddJSArrayKeysToFixedArray(array, this); + ElementsAccessor* accessor = array->GetElementsAccessor(); + MaybeObject* maybe_result = + accessor->AddElementsToFixedArray(array->elements(), this); + FixedArray* result; + if (!maybe_result->To(&result)) return maybe_result; +#ifdef DEBUG + if (FLAG_enable_slow_asserts) { + for (int i = 0; i < result->length(); i++) { + Object* current = result->get(i); + ASSERT(current->IsNumber() || current->IsString()); + } + } +#endif + return result; } @@ -6961,12 +6976,16 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count); if (0 == deopt_count) return; - PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands"); + PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", + FLAG_print_code_verbose ? "commands" : ""); for (int i = 0; i < deopt_count; i++) { PrintF(out, "%6d %6d %6d", i, AstId(i)->value(), ArgumentsStackHeight(i)->value()); - if (!FLAG_print_code_verbose) continue; + if (!FLAG_print_code_verbose) { + PrintF(out, "\n"); + continue; + } // Print details of the frame translation. int translation_index = TranslationIndex(i)->value(); TranslationIterator iterator(TranslationByteArray(), translation_index); @@ -8403,14 +8422,14 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, return isolate->Throw(*error); } } - Object* new_dictionary; + FixedArrayBase* new_dictionary; MaybeObject* maybe = dictionary->AtNumberPut(index, value); - if (!maybe->ToObject(&new_dictionary)) return maybe; + if (!maybe->To(&new_dictionary)) return maybe; if (dictionary != NumberDictionary::cast(new_dictionary)) { if (is_arguments) { elements->set(1, new_dictionary); } else { - set_elements(HeapObject::cast(new_dictionary)); + set_elements(new_dictionary); } dictionary = NumberDictionary::cast(new_dictionary); } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index ff13aedcce..93f7a1d119 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -62,17 +62,8 @@ // - JSMessageObject // - JSProxy // - JSFunctionProxy -// - ByteArray -// - ExternalArray -// - ExternalPixelArray -// - ExternalByteArray -// - ExternalUnsignedByteArray -// - ExternalShortArray -// - ExternalUnsignedShortArray -// - ExternalIntArray -// - ExternalUnsignedIntArray -// - ExternalFloatArray // - FixedArrayBase +// - ByteArray // - FixedArray // - DescriptorArray // - HashTable @@ -85,6 +76,15 @@ // - JSFunctionResultCache // - SerializedScopeInfo // - FixedDoubleArray +// - ExternalArray +// - ExternalPixelArray +// - ExternalByteArray +// - ExternalUnsignedByteArray +// - ExternalShortArray +// - ExternalUnsignedShortArray +// - ExternalIntArray +// - ExternalUnsignedIntArray +// - ExternalFloatArray // - String // - SeqString // - SeqAsciiString @@ -322,6 +322,7 @@ static const int kVariableSizeSentinel = 0; V(POLYMORPHIC_CODE_CACHE_TYPE) \ \ V(FIXED_ARRAY_TYPE) \ + V(FIXED_DOUBLE_ARRAY_TYPE) \ V(SHARED_FUNCTION_INFO_TYPE) \ \ V(JS_MESSAGE_OBJECT_TYPE) \ @@ -635,10 +636,11 @@ enum CompareResult { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \ +class DictionaryElementsAccessor; class ElementsAccessor; -class StringStream; +class FixedArrayBase; class ObjectVisitor; -class DictionaryElementsAccessor; +class StringStream; struct ValueInfo : public Malloced { ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { } @@ -743,6 +745,7 @@ class MaybeObject BASE_EMBEDDED { V(FixedDoubleArray) \ V(Context) \ V(GlobalContext) \ + V(SerializedScopeInfo) \ V(JSFunction) \ V(Code) \ V(Oddball) \ @@ -1492,7 +1495,7 @@ class JSObject: public JSReceiver { // In the slow mode the elements is either a NumberDictionary, an // ExternalArray, or a FixedArray parameter map for a (non-strict) // arguments object. - DECL_ACCESSORS(elements, HeapObject) + DECL_ACCESSORS(elements, FixedArrayBase) inline void initialize_elements(); MUST_USE_RESULT inline MaybeObject* ResetElements(); inline ElementsKind GetElementsKind(); @@ -2084,6 +2087,7 @@ class FixedArrayBase: public HeapObject { static const int kHeaderSize = kLengthOffset + kPointerSize; }; + class FixedDoubleArray; // FixedArray describes fixed-sized arrays with element type Object*. @@ -3053,12 +3057,8 @@ class NormalizedMapCache: public FixedArray { // ByteArray represents fixed sized byte arrays. Used by the outside world, // such as PCRE, and also by the memory allocator and garbage collector to // fill in free blocks in the heap. -class ByteArray: public HeapObject { +class ByteArray: public FixedArrayBase { public: - // [length]: length of the array. - inline int length(); - inline void set_length(int value); - // Setter and getter. inline byte get(int index); inline void set(int index, byte value); @@ -3103,10 +3103,6 @@ class ByteArray: public HeapObject { #endif // Layout description. - // Length is smi tagged when it is stored. - static const int kLengthOffset = HeapObject::kHeaderSize; - static const int kHeaderSize = kLengthOffset + kPointerSize; - static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize); // Maximal memory consumption for a single ByteArray. @@ -3130,11 +3126,8 @@ class ByteArray: public HeapObject { // Out-of-range values passed to the setter are converted via a C // cast, not clamping. Out-of-range indices cause exceptions to be // raised rather than being silently ignored. -class ExternalArray: public HeapObject { +class ExternalArray: public FixedArrayBase { public: - // [length]: length of the array. - inline int length(); - inline void set_length(int value); inline bool is_the_hole(int index) { return false; } @@ -3149,9 +3142,8 @@ class ExternalArray: public HeapObject { static const int kMaxLength = 0x3fffffff; // ExternalArray headers are not quadword aligned. - static const int kLengthOffset = HeapObject::kHeaderSize; static const int kExternalPointerOffset = - POINTER_SIZE_ALIGN(kLengthOffset + kIntSize); + POINTER_SIZE_ALIGN(FixedArrayBase::kLengthOffset + kPointerSize); static const int kHeaderSize = kExternalPointerOffset + kPointerSize; static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize); @@ -4444,6 +4436,7 @@ class Script: public Struct { #define FUNCTIONS_WITH_ID_LIST(V) \ V(Array.prototype, push, ArrayPush) \ V(Array.prototype, pop, ArrayPop) \ + V(Function.prototype, apply, FunctionApply) \ V(String.prototype, charCodeAt, StringCharCodeAt) \ V(String.prototype, charAt, StringCharAt) \ V(String, fromCharCode, StringFromCharCode) \ diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index f32e9177b5..844dd7060c 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -584,7 +584,8 @@ Parser::Parser(Handle