diff --git a/deps/v8/0002-Patch-for-oprofile.patch b/deps/v8/0002-Patch-for-oprofile.patch deleted file mode 100644 index e4316a8ccf..0000000000 --- a/deps/v8/0002-Patch-for-oprofile.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- SConstruct 2010-12-16 11:49:26.000000000 -0800 -+++ /tmp/SConstruct 2010-12-16 11:48:23.000000000 -0800 -@@ -225,7 +225,8 @@ - 'LINKFLAGS': ['-m64'], - }, - 'prof:oprofile': { -- 'CPPDEFINES': ['ENABLE_OPROFILE_AGENT'] -+ 'CPPDEFINES': ['ENABLE_OPROFILE_AGENT'], -+ 'LIBS': ['opagent', 'bfd'] - } - }, - 'msvc': { diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index ea5b93e1e9..eedf840c55 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -34,3 +34,4 @@ Rodolph Perfetta Ryan Dahl Subrato K De Vlad Burlik +Mike Gilbert diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index e2f87c5a1d..7e2a1306db 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,8 +1,26 @@ +2011-01-28: Version 3.0.12 + + Added support for strict mode parameter and object property + validation. + + Fixed a couple of crash bugs. + + +2011-01-25: Version 3.0.11 + + Fixed a bug in deletion of lookup slots that could cause global + variables to be accidentally deleted (http://crbug.com/70066). + + Added support for strict mode octal literal verification. + + Fixed a couple of crash bugs (issues 1070 and 1071). + + 2011-01-24: Version 3.0.10 Fixed External::Wrap for 64-bit addresses (issue 1037). - Fixed incorrect .arguments variable proxy handling in the full + Fixed incorrect .arguments variable proxy handling in the full code generator (issue 1060). Introduced partial strict mode support. @@ -11,7 +29,7 @@ (issue http://crbug.com/70334). Fixed incorrect rounding for float-to-integer conversions for external - array types, which implement the Typed Array spec + array types, which implement the Typed Array spec (issue http://crbug.com/50972). Performance improvements on the IA32 platform. diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index 77482d4f81..bae1cd5e1d 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -32,7 +32,7 @@ import os from os.path import join, dirname, abspath from types import DictType, StringTypes root_dir = dirname(File('SConstruct').rfile().abspath) -sys.path.append(join(root_dir, 'tools')) +sys.path.insert(0, join(root_dir, 'tools')) import js2c, utils # ANDROID_TOP is the top of the Android checkout, fetched from the environment @@ -127,12 +127,16 @@ LIBRARY_FLAGS = { }, 'inspector:on': { 'CPPDEFINES': ['INSPECTOR'], + }, + 'liveobjectlist:on': { + 'CPPDEFINES': ['ENABLE_DEBUGGER_SUPPORT', 'INSPECTOR', + 'LIVE_OBJECT_LIST', 'OBJECT_PRINT'], } }, 'gcc': { 'all': { 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], - 'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions', '-fno-builtin-memcpy'], + 'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'], }, 'visibility:hidden': { # Use visibility=default to disable this. @@ -325,7 +329,7 @@ V8_EXTRA_FLAGS = { }, 'msvc': { 'all': { - 'WARNINGFLAGS': ['/W3', '/WX', '/wd4355', '/wd4800'] + 'WARNINGFLAGS': ['/W3', '/WX', '/wd4351', '/wd4355', '/wd4800'] }, 'library:shared': { 'CPPDEFINES': ['BUILDING_V8_SHARED'], @@ -751,6 +755,11 @@ SIMPLE_OPTIONS = { 'default': 'off', 'help': 'enable inspector features' }, + 'liveobjectlist': { + 'values': ['on', 'off'], + 'default': 'off', + 'help': 'enable live object list features in the debugger' + }, 'soname': { 'values': ['on', 'off'], 'default': 'off', @@ -1008,6 +1017,13 @@ def PostprocessOptions(options, os): # Print a warning if native regexp is specified for mips print "Warning: forcing regexp to interpreted for mips" options['regexp'] = 'interpreted' + if options['liveobjectlist'] == 'on': + if (options['debuggersupport'] != 'on') or (options['mode'] == 'release'): + # Print a warning that liveobjectlist will implicitly enable the debugger + print "Warning: forcing debuggersupport on for liveobjectlist" + options['debuggersupport'] = 'on' + options['inspector'] = 'on' + options['objectprint'] = 'on' def ParseEnvOverrides(arg, imports): diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index f3b9d43281..76ca2dc7c6 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -95,6 +95,7 @@ SOURCES = { mark-compact.cc messages.cc objects.cc + objects-printer.cc objects-visiting.cc oprofile-agent.cc parser.cc @@ -216,8 +217,9 @@ SOURCES = { x64/full-codegen-x64.cc x64/ic-x64.cc x64/jump-target-x64.cc - x64/lithium-x64.cc x64/lithium-codegen-x64.cc + x64/lithium-gap-resolver-x64.cc + x64/lithium-x64.cc x64/macro-assembler-x64.cc x64/regexp-macro-assembler-x64.cc x64/register-allocator-x64.cc @@ -236,10 +238,8 @@ SOURCES = { 'os:win32': ['platform-win32.cc'], 'mode:release': [], 'mode:debug': [ - 'objects-debug.cc', 'objects-printer.cc', 'prettyprinter.cc', - 'regexp-macro-assembler-tracer.cc' - ], - 'objectprint:on': ['objects-printer.cc'] + 'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc' + ] } diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index 155aef8b8d..0f52ac6e3a 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -213,74 +213,29 @@ MemOperand::MemOperand(Register rn, Register rm, // ----------------------------------------------------------------------------- -// Implementation of Assembler. - -// Instruction encoding bits. -enum { - H = 1 << 5, // halfword (or byte) - S6 = 1 << 6, // signed (or unsigned) - L = 1 << 20, // load (or store) - S = 1 << 20, // set condition code (or leave unchanged) - W = 1 << 21, // writeback base register (or leave unchanged) - A = 1 << 21, // accumulate in multiply instruction (or not) - B = 1 << 22, // unsigned byte (or word) - N = 1 << 22, // long (or short) - U = 1 << 23, // positive (or negative) offset/index - P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing) - I = 1 << 25, // immediate shifter operand (or not) - - B4 = 1 << 4, - B5 = 1 << 5, - B6 = 1 << 6, - B7 = 1 << 7, - B8 = 1 << 8, - B9 = 1 << 9, - B12 = 1 << 12, - B16 = 1 << 16, - B18 = 1 << 18, - B19 = 1 << 19, - B20 = 1 << 20, - B21 = 1 << 21, - B22 = 1 << 22, - B23 = 1 << 23, - B24 = 1 << 24, - B25 = 1 << 25, - B26 = 1 << 26, - B27 = 1 << 27, - - // Instruction bit masks. - RdMask = 15 << 12, // in str instruction - CondMask = 15 << 28, - CoprocessorMask = 15 << 8, - OpCodeMask = 15 << 21, // in data-processing instructions - Imm24Mask = (1 << 24) - 1, - Off12Mask = (1 << 12) - 1, - // Reserved condition. - nv = 15 << 28 -}; - +// Specific instructions, constants, and masks. // add(sp, sp, 4) instruction (aka Pop()) -static const Instr kPopInstruction = - al | 4 * B21 | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12; +const Instr kPopInstruction = + al | PostIndex | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12; // str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r)) // register r is not encoded. -static const Instr kPushRegPattern = +const Instr kPushRegPattern = al | B26 | 4 | NegPreIndex | sp.code() * B16; // ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r)) // register r is not encoded. -static const Instr kPopRegPattern = +const Instr kPopRegPattern = al | B26 | L | 4 | PostIndex | sp.code() * B16; // mov lr, pc -const Instr kMovLrPc = al | 13*B21 | pc.code() | lr.code() * B12; +const Instr kMovLrPc = al | MOV | pc.code() | lr.code() * B12; // ldr rd, [pc, #offset] -const Instr kLdrPCMask = CondMask | 15 * B24 | 7 * B20 | 15 * B16; +const Instr kLdrPCMask = kCondMask | 15 * B24 | 7 * B20 | 15 * B16; const Instr kLdrPCPattern = al | 5 * B24 | L | pc.code() * B16; // blxcc rm const Instr kBlxRegMask = 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4; const Instr kBlxRegPattern = - B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | 3 * B4; + B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX; const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16; const Instr kMovMvnPattern = 0xd * B21; const Instr kMovMvnFlip = B22; @@ -292,33 +247,28 @@ const Instr kMovwLeaveCCFlip = 0x5 * B21; const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12; const Instr kCmpCmnPattern = 0x15 * B20; const Instr kCmpCmnFlip = B21; -const Instr kALUMask = 0x6f * B21; -const Instr kAddPattern = 0x4 * B21; -const Instr kSubPattern = 0x2 * B21; -const Instr kBicPattern = 0xe * B21; -const Instr kAndPattern = 0x0 * B21; const Instr kAddSubFlip = 0x6 * B21; const Instr kAndBicFlip = 0xe * B21; // A mask for the Rd register for push, pop, ldr, str instructions. -const Instr kRdMask = 0x0000f000; -static const int kRdShift = 12; -static const Instr kLdrRegFpOffsetPattern = +const Instr kLdrRegFpOffsetPattern = al | B26 | L | Offset | fp.code() * B16; -static const Instr kStrRegFpOffsetPattern = +const Instr kStrRegFpOffsetPattern = al | B26 | Offset | fp.code() * B16; -static const Instr kLdrRegFpNegOffsetPattern = +const Instr kLdrRegFpNegOffsetPattern = al | B26 | L | NegOffset | fp.code() * B16; -static const Instr kStrRegFpNegOffsetPattern = +const Instr kStrRegFpNegOffsetPattern = al | B26 | NegOffset | fp.code() * B16; -static const Instr kLdrStrInstrTypeMask = 0xffff0000; -static const Instr kLdrStrInstrArgumentMask = 0x0000ffff; -static const Instr kLdrStrOffsetMask = 0x00000fff; +const Instr kLdrStrInstrTypeMask = 0xffff0000; +const Instr kLdrStrInstrArgumentMask = 0x0000ffff; +const Instr kLdrStrOffsetMask = 0x00000fff; + // Spare buffer. static const int kMinimalBufferSize = 4*KB; static byte* spare_buffer_ = NULL; + Assembler::Assembler(void* buffer, int buffer_size) : positions_recorder_(this), allow_peephole_optimization_(false) { @@ -411,7 +361,7 @@ int Assembler::GetBranchOffset(Instr instr) { ASSERT(IsBranch(instr)); // Take the jump offset in the lower 24 bits, sign extend it and multiply it // with 4 to get the offset in bytes. - return ((instr & Imm24Mask) << 8) >> 6; + return ((instr & kImm24Mask) << 8) >> 6; } @@ -423,7 +373,7 @@ bool Assembler::IsLdrRegisterImmediate(Instr instr) { int Assembler::GetLdrRegisterImmediateOffset(Instr instr) { ASSERT(IsLdrRegisterImmediate(instr)); bool positive = (instr & B23) == B23; - int offset = instr & Off12Mask; // Zero extended offset. + int offset = instr & kOff12Mask; // Zero extended offset. return positive ? offset : -offset; } @@ -436,7 +386,7 @@ Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) { // Set bit indicating whether the offset should be added. instr = (instr & ~B23) | (positive ? B23 : 0); // Set the actual offset. - return (instr & ~Off12Mask) | offset; + return (instr & ~kOff12Mask) | offset; } @@ -453,7 +403,7 @@ Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) { // Set bit indicating whether the offset should be added. instr = (instr & ~B23) | (positive ? B23 : 0); // Set the actual offset. - return (instr & ~Off12Mask) | offset; + return (instr & ~kOff12Mask) | offset; } @@ -467,13 +417,13 @@ Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) { ASSERT(offset >= 0); ASSERT(is_uint12(offset)); // Set the offset. - return (instr & ~Off12Mask) | offset; + return (instr & ~kOff12Mask) | offset; } Register Assembler::GetRd(Instr instr) { Register reg; - reg.code_ = ((instr & kRdMask) >> kRdShift); + reg.code_ = Instruction::RdValue(instr); return reg; } @@ -511,7 +461,7 @@ bool Assembler::IsLdrRegFpNegOffset(Instr instr) { bool Assembler::IsLdrPcImmediateOffset(Instr instr) { // Check the instruction is indeed a // ldr , [pc +/- offset_12]. - return (instr & 0x0f7f0000) == 0x051f0000; + return (instr & (kLdrPCMask & ~kCondMask)) == 0x051f0000; } @@ -532,13 +482,14 @@ const int kEndOfChain = -4; int Assembler::target_at(int pos) { Instr instr = instr_at(pos); - if ((instr & ~Imm24Mask) == 0) { + if ((instr & ~kImm24Mask) == 0) { // Emitted label constant, not part of a branch. return instr - (Code::kHeaderSize - kHeapObjectTag); } ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 - int imm26 = ((instr & Imm24Mask) << 8) >> 6; - if ((instr & CondMask) == nv && (instr & B24) != 0) { + int imm26 = ((instr & kImm24Mask) << 8) >> 6; + if ((Instruction::ConditionField(instr) == kSpecialCondition) && + ((instr & B24) != 0)) { // blx uses bit 24 to encode bit 2 of imm26 imm26 += 2; } @@ -548,7 +499,7 @@ int Assembler::target_at(int pos) { void Assembler::target_at_put(int pos, int target_pos) { Instr instr = instr_at(pos); - if ((instr & ~Imm24Mask) == 0) { + if ((instr & ~kImm24Mask) == 0) { ASSERT(target_pos == kEndOfChain || target_pos >= 0); // Emitted label constant, not part of a branch. // Make label relative to Code* of generated Code object. @@ -557,17 +508,17 @@ void Assembler::target_at_put(int pos, int target_pos) { } int imm26 = target_pos - (pos + kPcLoadDelta); ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 - if ((instr & CondMask) == nv) { + if (Instruction::ConditionField(instr) == kSpecialCondition) { // blx uses bit 24 to encode bit 2 of imm26 ASSERT((imm26 & 1) == 0); - instr = (instr & ~(B24 | Imm24Mask)) | ((imm26 & 2) >> 1)*B24; + instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1)*B24; } else { ASSERT((imm26 & 3) == 0); - instr &= ~Imm24Mask; + instr &= ~kImm24Mask; } int imm24 = imm26 >> 2; ASSERT(is_int24(imm24)); - instr_at_put(pos, instr | (imm24 & Imm24Mask)); + instr_at_put(pos, instr | (imm24 & kImm24Mask)); } @@ -582,14 +533,14 @@ void Assembler::print(Label* L) { while (l.is_linked()) { PrintF("@ %d ", l.pos()); Instr instr = instr_at(l.pos()); - if ((instr & ~Imm24Mask) == 0) { + if ((instr & ~kImm24Mask) == 0) { PrintF("value\n"); } else { ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx - int cond = instr & CondMask; + Condition cond = Instruction::ConditionField(instr); const char* b; const char* c; - if (cond == nv) { + if (cond == kSpecialCondition) { b = "blx"; c = ""; } else { @@ -731,14 +682,14 @@ static bool fits_shifter(uint32_t imm32, } } else { Instr alu_insn = (*instr & kALUMask); - if (alu_insn == kAddPattern || - alu_insn == kSubPattern) { + if (alu_insn == ADD || + alu_insn == SUB) { if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) { *instr ^= kAddSubFlip; return true; } - } else if (alu_insn == kAndPattern || - alu_insn == kBicPattern) { + } else if (alu_insn == AND || + alu_insn == BIC) { if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) { *instr ^= kAndBicFlip; return true; @@ -782,7 +733,7 @@ void Assembler::addrmod1(Instr instr, Register rd, const Operand& x) { CheckBuffer(); - ASSERT((instr & ~(CondMask | OpCodeMask | S)) == 0); + ASSERT((instr & ~(kCondMask | kOpCodeMask | S)) == 0); if (!x.rm_.is_valid()) { // Immediate. uint32_t rotate_imm; @@ -794,8 +745,8 @@ void Assembler::addrmod1(Instr instr, // However, if the original instruction is a 'mov rd, x' (not setting the // condition code), then replace it with a 'ldr rd, [pc]'. CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed - Condition cond = static_cast(instr & CondMask); - if ((instr & ~CondMask) == 13*B21) { // mov, S not set + Condition cond = Instruction::ConditionField(instr); + if ((instr & ~kCondMask) == 13*B21) { // mov, S not set if (x.must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) { RecordRelocInfo(x.rmode_, x.imm32_); ldr(rd, MemOperand(pc, 0), cond); @@ -836,7 +787,7 @@ void Assembler::addrmod1(Instr instr, void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) { - ASSERT((instr & ~(CondMask | B | L)) == B26); + ASSERT((instr & ~(kCondMask | B | L)) == B26); int am = x.am_; if (!x.rm_.is_valid()) { // Immediate offset. @@ -849,8 +800,7 @@ void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) { // Immediate offset cannot be encoded, load it first to register ip // rn (and rd in a load) should never be ip, or will be trashed. ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); - mov(ip, Operand(x.offset_), LeaveCC, - static_cast(instr & CondMask)); + mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr)); addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_)); return; } @@ -869,7 +819,7 @@ void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) { void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) { - ASSERT((instr & ~(CondMask | L | S6 | H)) == (B4 | B7)); + ASSERT((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7)); ASSERT(x.rn_.is_valid()); int am = x.am_; if (!x.rm_.is_valid()) { @@ -883,8 +833,7 @@ void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) { // Immediate offset cannot be encoded, load it first to register ip // rn (and rd in a load) should never be ip, or will be trashed. ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); - mov(ip, Operand(x.offset_), LeaveCC, - static_cast(instr & CondMask)); + mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr)); addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); return; } @@ -895,7 +844,7 @@ void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) { // rn (and rd in a load) should never be ip, or will be trashed. ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip))); mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC, - static_cast(instr & CondMask)); + Instruction::ConditionField(instr)); addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_)); return; } else { @@ -909,7 +858,7 @@ void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) { void Assembler::addrmod4(Instr instr, Register rn, RegList rl) { - ASSERT((instr & ~(CondMask | P | U | W | L)) == B27); + ASSERT((instr & ~(kCondMask | P | U | W | L)) == B27); ASSERT(rl != 0); ASSERT(!rn.is(pc)); emit(instr | rn.code()*B16 | rl); @@ -919,7 +868,7 @@ void Assembler::addrmod4(Instr instr, Register rn, RegList rl) { void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) { // Unindexed addressing is not encoded by this function. ASSERT_EQ((B27 | B26), - (instr & ~(CondMask | CoprocessorMask | P | U | N | W | L))); + (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L))); ASSERT(x.rn_.is_valid() && !x.rm_.is_valid()); int am = x.am_; int offset_8 = x.offset_; @@ -982,7 +931,7 @@ void Assembler::b(int branch_offset, Condition cond) { ASSERT((branch_offset & 3) == 0); int imm24 = branch_offset >> 2; ASSERT(is_int24(imm24)); - emit(cond | B27 | B25 | (imm24 & Imm24Mask)); + emit(cond | B27 | B25 | (imm24 & kImm24Mask)); if (cond == al) { // Dead code is a good location to emit the constant pool. @@ -996,7 +945,7 @@ void Assembler::bl(int branch_offset, Condition cond) { ASSERT((branch_offset & 3) == 0); int imm24 = branch_offset >> 2; ASSERT(is_int24(imm24)); - emit(cond | B27 | B25 | B24 | (imm24 & Imm24Mask)); + emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask)); } @@ -1006,21 +955,21 @@ void Assembler::blx(int branch_offset) { // v5 and above int h = ((branch_offset & 2) >> 1)*B24; int imm24 = branch_offset >> 2; ASSERT(is_int24(imm24)); - emit(nv | B27 | B25 | h | (imm24 & Imm24Mask)); + emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask)); } void Assembler::blx(Register target, Condition cond) { // v5 and above positions_recorder()->WriteRecordedPositions(); ASSERT(!target.is(pc)); - emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code()); + emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code()); } void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t positions_recorder()->WriteRecordedPositions(); ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged - emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code()); + emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code()); } @@ -1028,31 +977,31 @@ void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t void Assembler::and_(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 0*B21 | s, src1, dst, src2); + addrmod1(cond | AND | s, src1, dst, src2); } void Assembler::eor(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 1*B21 | s, src1, dst, src2); + addrmod1(cond | EOR | s, src1, dst, src2); } void Assembler::sub(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 2*B21 | s, src1, dst, src2); + addrmod1(cond | SUB | s, src1, dst, src2); } void Assembler::rsb(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 3*B21 | s, src1, dst, src2); + addrmod1(cond | RSB | s, src1, dst, src2); } void Assembler::add(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 4*B21 | s, src1, dst, src2); + addrmod1(cond | ADD | s, src1, dst, src2); // Eliminate pattern: push(r), pop() // str(src, MemOperand(sp, 4, NegPreIndex), al); @@ -1061,7 +1010,7 @@ void Assembler::add(Register dst, Register src1, const Operand& src2, if (can_peephole_optimize(2) && // Pattern. instr_at(pc_ - 1 * kInstrSize) == kPopInstruction && - (instr_at(pc_ - 2 * kInstrSize) & ~RdMask) == kPushRegPattern) { + (instr_at(pc_ - 2 * kInstrSize) & ~kRdMask) == kPushRegPattern) { pc_ -= 2 * kInstrSize; if (FLAG_print_peephole_optimization) { PrintF("%x push(reg)/pop() eliminated\n", pc_offset()); @@ -1072,45 +1021,45 @@ void Assembler::add(Register dst, Register src1, const Operand& src2, void Assembler::adc(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 5*B21 | s, src1, dst, src2); + addrmod1(cond | ADC | s, src1, dst, src2); } void Assembler::sbc(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 6*B21 | s, src1, dst, src2); + addrmod1(cond | SBC | s, src1, dst, src2); } void Assembler::rsc(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 7*B21 | s, src1, dst, src2); + addrmod1(cond | RSC | s, src1, dst, src2); } void Assembler::tst(Register src1, const Operand& src2, Condition cond) { - addrmod1(cond | 8*B21 | S, src1, r0, src2); + addrmod1(cond | TST | S, src1, r0, src2); } void Assembler::teq(Register src1, const Operand& src2, Condition cond) { - addrmod1(cond | 9*B21 | S, src1, r0, src2); + addrmod1(cond | TEQ | S, src1, r0, src2); } void Assembler::cmp(Register src1, const Operand& src2, Condition cond) { - addrmod1(cond | 10*B21 | S, src1, r0, src2); + addrmod1(cond | CMP | S, src1, r0, src2); } void Assembler::cmn(Register src1, const Operand& src2, Condition cond) { - addrmod1(cond | 11*B21 | S, src1, r0, src2); + addrmod1(cond | CMN | S, src1, r0, src2); } void Assembler::orr(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 12*B21 | s, src1, dst, src2); + addrmod1(cond | ORR | s, src1, dst, src2); } @@ -1122,7 +1071,7 @@ void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) { // the mov instruction. They must be generated using nop(int/NopMarkerTypes) // or MarkCode(int/NopMarkerTypes) pseudo instructions. ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al)); - addrmod1(cond | 13*B21 | s, r0, dst, src); + addrmod1(cond | MOV | s, r0, dst, src); } @@ -1139,12 +1088,12 @@ void Assembler::movt(Register reg, uint32_t immediate, Condition cond) { void Assembler::bic(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { - addrmod1(cond | 14*B21 | s, src1, dst, src2); + addrmod1(cond | BIC | s, src1, dst, src2); } void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) { - addrmod1(cond | 15*B21 | s, r0, dst, src); + addrmod1(cond | MVN | s, r0, dst, src); } @@ -1222,7 +1171,7 @@ void Assembler::clz(Register dst, Register src, Condition cond) { // v5 and above. ASSERT(!dst.is(pc) && !src.is(pc)); emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 | - 15*B8 | B4 | src.code()); + 15*B8 | CLZ | src.code()); } @@ -1376,7 +1325,7 @@ void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) { Instr pop_instr = instr_at(pc_ - 1 * kInstrSize); if (IsPush(push_instr) && IsPop(pop_instr)) { - if ((pop_instr & kRdMask) != (push_instr & kRdMask)) { + if (Instruction::RdValue(pop_instr) != Instruction::RdValue(push_instr)) { // For consecutive push and pop on different registers, // we delete both the push & pop and insert a register move. // push ry, pop rx --> mov rx, ry @@ -1457,8 +1406,8 @@ void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) { IsPop(mem_read_instr)) { if ((IsLdrRegFpOffset(ldr_instr) || IsLdrRegFpNegOffset(ldr_instr))) { - if ((mem_write_instr & kRdMask) == - (mem_read_instr & kRdMask)) { + if (Instruction::RdValue(mem_write_instr) == + Instruction::RdValue(mem_read_instr)) { // Pattern: push & pop from/to same register, // with a fp+offset ldr in between // @@ -1473,7 +1422,8 @@ void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) { // else // ldr rz, [fp, #-24] - if ((mem_write_instr & kRdMask) == (ldr_instr & kRdMask)) { + if (Instruction::RdValue(mem_write_instr) == + Instruction::RdValue(ldr_instr)) { pc_ -= 3 * kInstrSize; } else { pc_ -= 3 * kInstrSize; @@ -1503,22 +1453,23 @@ void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) { // ldr rz, [fp, #-24] Register reg_pushed, reg_popped; - if ((mem_read_instr & kRdMask) == (ldr_instr & kRdMask)) { + if (Instruction::RdValue(mem_read_instr) == + Instruction::RdValue(ldr_instr)) { reg_pushed = GetRd(mem_write_instr); reg_popped = GetRd(mem_read_instr); pc_ -= 3 * kInstrSize; mov(reg_popped, reg_pushed); - } else if ((mem_write_instr & kRdMask) - != (ldr_instr & kRdMask)) { + } else if (Instruction::RdValue(mem_write_instr) != + Instruction::RdValue(ldr_instr)) { reg_pushed = GetRd(mem_write_instr); reg_popped = GetRd(mem_read_instr); pc_ -= 3 * kInstrSize; emit(ldr_instr); mov(reg_popped, reg_pushed); - } else if (((mem_read_instr & kRdMask) - != (ldr_instr & kRdMask)) || - ((mem_write_instr & kRdMask) - == (ldr_instr & kRdMask)) ) { + } else if ((Instruction::RdValue(mem_read_instr) != + Instruction::RdValue(ldr_instr)) || + (Instruction::RdValue(mem_write_instr) == + Instruction::RdValue(ldr_instr))) { reg_pushed = GetRd(mem_write_instr); reg_popped = GetRd(mem_read_instr); pc_ -= 3 * kInstrSize; @@ -1640,18 +1591,14 @@ void Assembler::stm(BlockAddrMode am, // enabling/disabling and a counter feature. See simulator-arm.h . void Assembler::stop(const char* msg, Condition cond, int32_t code) { #ifndef __arm__ - // See constants-arm.h SoftwareInterruptCodes. Unluckily the Assembler and - // Simulator do not share constants declaration. ASSERT(code >= kDefaultStopCode); - static const uint32_t kStopInterruptCode = 1 << 23; - static const uint32_t kMaxStopCode = kStopInterruptCode - 1; // The Simulator will handle the stop instruction and get the message address. // It expects to find the address just after the svc instruction. BlockConstPoolFor(2); if (code >= 0) { - svc(kStopInterruptCode + code, cond); + svc(kStopCode + code, cond); } else { - svc(kStopInterruptCode + kMaxStopCode, cond); + svc(kStopCode + kMaxStopCode, cond); } emit(reinterpret_cast(msg)); #else // def __arm__ @@ -1673,7 +1620,7 @@ void Assembler::stop(const char* msg, Condition cond, int32_t code) { void Assembler::bkpt(uint32_t imm16) { // v5 and above ASSERT(is_uint16(imm16)); - emit(al | B24 | B21 | (imm16 >> 4)*B8 | 7*B4 | (imm16 & 0xf)); + emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf)); } @@ -1703,7 +1650,7 @@ void Assembler::cdp2(Coprocessor coproc, CRegister crn, CRegister crm, int opcode_2) { // v5 and above - cdp(coproc, opcode_1, crd, crn, crm, opcode_2, static_cast(nv)); + cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition); } @@ -1726,7 +1673,7 @@ void Assembler::mcr2(Coprocessor coproc, CRegister crn, CRegister crm, int opcode_2) { // v5 and above - mcr(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast(nv)); + mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition); } @@ -1749,7 +1696,7 @@ void Assembler::mrc2(Coprocessor coproc, CRegister crn, CRegister crm, int opcode_2) { // v5 and above - mrc(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast(nv)); + mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition); } @@ -1779,7 +1726,7 @@ void Assembler::ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src, LFlag l) { // v5 and above - ldc(coproc, crd, src, l, static_cast(nv)); + ldc(coproc, crd, src, l, kSpecialCondition); } @@ -1788,7 +1735,7 @@ void Assembler::ldc2(Coprocessor coproc, Register rn, int option, LFlag l) { // v5 and above - ldc(coproc, crd, rn, option, l, static_cast(nv)); + ldc(coproc, crd, rn, option, l, kSpecialCondition); } @@ -1818,7 +1765,7 @@ void Assembler::stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst, LFlag l) { // v5 and above - stc(coproc, crd, dst, l, static_cast(nv)); + stc(coproc, crd, dst, l, kSpecialCondition); } @@ -1827,7 +1774,7 @@ void Assembler::stc2(Coprocessor coproc, Register rn, int option, LFlag l) { // v5 and above - stc(coproc, crd, rn, option, l, static_cast(nv)); + stc(coproc, crd, rn, option, l, kSpecialCondition); } @@ -2637,7 +2584,7 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) { // Instruction to patch must be a ldr/str [pc, #offset]. // P and U set, B and W clear, Rn == pc, offset12 still 0. - ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | Off12Mask)) == + ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | kOff12Mask)) == (2*B25 | P | U | pc.code()*B16)); int delta = pc_ - rinfo.pc() - 8; ASSERT(delta >= -4); // instr could be ldr pc, [pc, #-4] followed by targ32 diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index ad1bdabd01..b3343f0177 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -41,6 +41,7 @@ #define V8_ARM_ASSEMBLER_ARM_H_ #include #include "assembler.h" +#include "constants-arm.h" #include "serialize.h" namespace v8 { @@ -300,18 +301,6 @@ const DwVfpRegister d13 = { 13 }; const DwVfpRegister d14 = { 14 }; const DwVfpRegister d15 = { 15 }; -// VFP FPSCR constants. -static const uint32_t kVFPNConditionFlagBit = 1 << 31; -static const uint32_t kVFPZConditionFlagBit = 1 << 30; -static const uint32_t kVFPCConditionFlagBit = 1 << 29; -static const uint32_t kVFPVConditionFlagBit = 1 << 28; - -static const uint32_t kVFPFlushToZeroMask = 1 << 24; - -static const uint32_t kVFPRoundingModeMask = 3 << 22; -static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22; - -static const uint32_t kVFPExceptionMask = 0xf; // Coprocessor register struct CRegister { @@ -372,149 +361,6 @@ enum Coprocessor { }; -// Condition field in instructions. -enum Condition { - // any value < 0 is considered no_condition - no_condition = -1, - - eq = 0 << 28, // Z set equal. - ne = 1 << 28, // Z clear not equal. - nz = 1 << 28, // Z clear not zero. - cs = 2 << 28, // C set carry set. - hs = 2 << 28, // C set unsigned higher or same. - cc = 3 << 28, // C clear carry clear. - lo = 3 << 28, // C clear unsigned lower. - mi = 4 << 28, // N set negative. - pl = 5 << 28, // N clear positive or zero. - vs = 6 << 28, // V set overflow. - vc = 7 << 28, // V clear no overflow. - hi = 8 << 28, // C set, Z clear unsigned higher. - ls = 9 << 28, // C clear or Z set unsigned lower or same. - ge = 10 << 28, // N == V greater or equal. - lt = 11 << 28, // N != V less than. - gt = 12 << 28, // Z clear, N == V greater than. - le = 13 << 28, // Z set or N != V less then or equal - al = 14 << 28 // always. -}; - - -// Returns the equivalent of !cc. -inline Condition NegateCondition(Condition cc) { - ASSERT(cc != al); - return static_cast(cc ^ ne); -} - - -// Corresponds to transposing the operands of a comparison. -inline Condition ReverseCondition(Condition cc) { - switch (cc) { - case lo: - return hi; - case hi: - return lo; - case hs: - return ls; - case ls: - return hs; - case lt: - return gt; - case gt: - return lt; - case ge: - return le; - case le: - return ge; - default: - return cc; - }; -} - - -// Branch hints are not used on the ARM. They are defined so that they can -// appear in shared function signatures, but will be ignored in ARM -// implementations. -enum Hint { no_hint }; - -// Hints are not used on the arm. Negating is trivial. -inline Hint NegateHint(Hint ignored) { return no_hint; } - - -// ----------------------------------------------------------------------------- -// Addressing modes and instruction variants - -// Shifter operand shift operation -enum ShiftOp { - LSL = 0 << 5, - LSR = 1 << 5, - ASR = 2 << 5, - ROR = 3 << 5, - RRX = -1 -}; - - -// Condition code updating mode -enum SBit { - SetCC = 1 << 20, // set condition code - LeaveCC = 0 << 20 // leave condition code unchanged -}; - - -// Status register selection -enum SRegister { - CPSR = 0 << 22, - SPSR = 1 << 22 -}; - - -// Status register fields -enum SRegisterField { - CPSR_c = CPSR | 1 << 16, - CPSR_x = CPSR | 1 << 17, - CPSR_s = CPSR | 1 << 18, - CPSR_f = CPSR | 1 << 19, - SPSR_c = SPSR | 1 << 16, - SPSR_x = SPSR | 1 << 17, - SPSR_s = SPSR | 1 << 18, - SPSR_f = SPSR | 1 << 19 -}; - -// Status register field mask (or'ed SRegisterField enum values) -typedef uint32_t SRegisterFieldMask; - - -// Memory operand addressing mode -enum AddrMode { - // bit encoding P U W - Offset = (8|4|0) << 21, // offset (without writeback to base) - PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback - PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback - NegOffset = (8|0|0) << 21, // negative offset (without writeback to base) - NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback - NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback -}; - - -// Load/store multiple addressing mode -enum BlockAddrMode { - // bit encoding P U W - da = (0|0|0) << 21, // decrement after - ia = (0|4|0) << 21, // increment after - db = (8|0|0) << 21, // decrement before - ib = (8|4|0) << 21, // increment before - da_w = (0|0|1) << 21, // decrement after with writeback to base - ia_w = (0|4|1) << 21, // increment after with writeback to base - db_w = (8|0|1) << 21, // decrement before with writeback to base - ib_w = (8|4|1) << 21 // increment before with writeback to base -}; - - -// Coprocessor load/store operand size -enum LFlag { - Long = 1 << 22, // long load/store coprocessor - Short = 0 << 22 // short load/store coprocessor -}; - - // ----------------------------------------------------------------------------- // Machine instruction Operands @@ -658,9 +504,6 @@ class CpuFeatures : public AllStatic { }; -typedef int32_t Instr; - - extern const Instr kMovLrPc; extern const Instr kLdrPCMask; extern const Instr kLdrPCPattern; @@ -680,15 +523,11 @@ extern const Instr kMovwLeaveCCFlip; extern const Instr kCmpCmnMask; extern const Instr kCmpCmnPattern; extern const Instr kCmpCmnFlip; - -extern const Instr kALUMask; -extern const Instr kAddPattern; -extern const Instr kSubPattern; -extern const Instr kAndPattern; -extern const Instr kBicPattern; extern const Instr kAddSubFlip; extern const Instr kAndBicFlip; + + class Assembler : public Malloced { public: // Create an assembler. Instructions and relocation information are emitted @@ -1001,7 +840,6 @@ class Assembler : public Malloced { void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al); // Exception-generating instructions and debugging support - static const int kDefaultStopCode = -1; void stop(const char* msg, Condition cond = al, int32_t code = kDefaultStopCode); diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index 0210b1b96e..dbb8242c55 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -190,7 +190,7 @@ static void AllocateJSArray(MacroAssembler* masm, // Check whether an empty sized array is requested. __ tst(array_size, array_size); - __ b(nz, ¬_empty); + __ b(ne, ¬_empty); // If an empty array is requested allocate a small elements array anyway. This // keeps the code below free of special casing for the empty array. @@ -566,7 +566,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // if it's a string already before calling the conversion builtin. Label convert_argument; __ bind(¬_cached); - __ BranchOnSmi(r0, &convert_argument); + __ JumpIfSmi(r0, &convert_argument); // Is it a String? __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); @@ -666,7 +666,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ mov(r2, Operand(debug_step_in_fp)); __ ldr(r2, MemOperand(r2)); __ tst(r2, r2); - __ b(nz, &rt_call); + __ b(ne, &rt_call); #endif // Load the initial map and verify that it is in fact a map. diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index a446007275..4fa927ff0d 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -41,7 +41,7 @@ namespace internal { static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, - Condition cc, + Condition cond, bool never_nan_nan); static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs, @@ -49,7 +49,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm, Label* lhs_not_nan, Label* slow, bool strict); -static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); +static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond); static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, Register lhs, Register rhs); @@ -112,9 +112,10 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) { void FastNewContextStub::Generate(MacroAssembler* masm) { // Try to allocate the context in new space. Label gc; + int length = slots_ + Context::MIN_CONTEXT_SLOTS; // Attempt to allocate the context in new space. - __ AllocateInNewSpace(FixedArray::SizeFor(slots_), + __ AllocateInNewSpace(FixedArray::SizeFor(length), r0, r1, r2, @@ -127,7 +128,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { // Setup the object header. __ LoadRoot(r2, Heap::kContextMapRootIndex); __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ mov(r2, Operand(Smi::FromInt(slots_))); + __ mov(r2, Operand(Smi::FromInt(length))); __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset)); // Setup the fixed slots. @@ -143,7 +144,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { // Initialize the rest of the slots to undefined. __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); - for (int i = Context::MIN_CONTEXT_SLOTS; i < slots_; i++) { + for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { __ str(r1, MemOperand(r0, Context::SlotOffset(i))); } @@ -343,6 +344,155 @@ void ConvertToDoubleStub::Generate(MacroAssembler* masm) { } +class FloatingPointHelper : public AllStatic { + public: + + enum Destination { + kVFPRegisters, + kCoreRegisters + }; + + + // Loads smis from r0 and r1 (right and left in binary operations) into + // floating point registers. Depending on the destination the values ends up + // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is + // floating point registers VFP3 must be supported. If core registers are + // requested when VFP3 is supported d6 and d7 will be scratched. + static void LoadSmis(MacroAssembler* masm, + Destination destination, + Register scratch1, + Register scratch2); + + // Loads objects from r0 and r1 (right and left in binary operations) into + // floating point registers. Depending on the destination the values ends up + // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is + // floating point registers VFP3 must be supported. If core registers are + // requested when VFP3 is supported d6 and d7 will still be scratched. If + // either r0 or r1 is not a number (not smi and not heap number object) the + // not_number label is jumped to. + static void LoadOperands(MacroAssembler* masm, + FloatingPointHelper::Destination destination, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* not_number); + private: + static void LoadNumber(MacroAssembler* masm, + FloatingPointHelper::Destination destination, + Register object, + DwVfpRegister dst, + Register dst1, + Register dst2, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* not_number); +}; + + +void FloatingPointHelper::LoadSmis(MacroAssembler* masm, + FloatingPointHelper::Destination destination, + Register scratch1, + Register scratch2) { + if (CpuFeatures::IsSupported(VFP3)) { + CpuFeatures::Scope scope(VFP3); + __ mov(scratch1, Operand(r0, ASR, kSmiTagSize)); + __ vmov(s15, scratch1); + __ vcvt_f64_s32(d7, s15); + __ mov(scratch1, Operand(r1, ASR, kSmiTagSize)); + __ vmov(s13, scratch1); + __ vcvt_f64_s32(d6, s13); + if (destination == kCoreRegisters) { + __ vmov(r2, r3, d7); + __ vmov(r0, r1, d6); + } + } else { + ASSERT(destination == kCoreRegisters); + // Write Smi from r0 to r3 and r2 in double format. + __ mov(scratch1, Operand(r0)); + ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2); + __ push(lr); + __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); + // Write Smi from r1 to r1 and r0 in double format. r9 is scratch. + __ mov(scratch1, Operand(r1)); + ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2); + __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); + __ pop(lr); + } +} + + +void FloatingPointHelper::LoadOperands( + MacroAssembler* masm, + FloatingPointHelper::Destination destination, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* slow) { + + // Load right operand (r0) to d6 or r2/r3. + LoadNumber(masm, destination, + r0, d7, r2, r3, heap_number_map, scratch1, scratch2, slow); + + // Load left operand (r1) to d7 or r0/r1. + LoadNumber(masm, destination, + r1, d6, r0, r1, heap_number_map, scratch1, scratch2, slow); +} + + +void FloatingPointHelper::LoadNumber(MacroAssembler* masm, + Destination destination, + Register object, + DwVfpRegister dst, + Register dst1, + Register dst2, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* not_number) { + Label is_smi, done; + + __ JumpIfSmi(object, &is_smi); + __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); + + // Handle loading a double from a heap number. + if (CpuFeatures::IsSupported(VFP3)) { + CpuFeatures::Scope scope(VFP3); + // Load the double from tagged HeapNumber to double register. + __ sub(scratch1, object, Operand(kHeapObjectTag)); + __ vldr(dst, scratch1, HeapNumber::kValueOffset); + } else { + ASSERT(destination == kCoreRegisters); + // Load the double from heap number to dst1 and dst2 in double format. + __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset)); + } + __ jmp(&done); + + // Handle loading a double from a smi. + __ bind(&is_smi); + if (CpuFeatures::IsSupported(VFP3)) { + CpuFeatures::Scope scope(VFP3); + // Convert smi to double. + __ SmiUntag(scratch1, object); + __ vmov(dst.high(), scratch1); + __ vcvt_f64_s32(dst, dst.high()); + if (destination == kCoreRegisters) { + __ vmov(dst1, dst2, dst); + } + } else { + ASSERT(destination == kCoreRegisters); + // Write Smi to dst1 and dst2 double format. + __ mov(scratch1, Operand(object)); + ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); + __ push(lr); + __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); + __ pop(lr); + } + + __ bind(&done); +} + + // See comment for class. void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { Label max_negative_int; @@ -394,7 +544,7 @@ void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { // for "identity and not NaN". static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, - Condition cc, + Condition cond, bool never_nan_nan) { Label not_identical; Label heap_number, return_equal; @@ -403,31 +553,31 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, // The two objects are identical. If we know that one of them isn't NaN then // we now know they test equal. - if (cc != eq || !never_nan_nan) { + if (cond != eq || !never_nan_nan) { // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), // so we do the second best thing - test it ourselves. // They are both equal and they are not both Smis so both of them are not // Smis. If it's not a heap number, then return equal. - if (cc == lt || cc == gt) { + if (cond == lt || cond == gt) { __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE); __ b(ge, slow); } else { __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); __ b(eq, &heap_number); // Comparing JS objects with <=, >= is complicated. - if (cc != eq) { + if (cond != eq) { __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE)); __ b(ge, slow); // Normally here we fall through to return_equal, but undefined is // special: (undefined == undefined) == true, but // (undefined <= undefined) == false! See ECMAScript 11.8.5. - if (cc == le || cc == ge) { + if (cond == le || cond == ge) { __ cmp(r4, Operand(ODDBALL_TYPE)); __ b(ne, &return_equal); __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); __ cmp(r0, r2); __ b(ne, &return_equal); - if (cc == le) { + if (cond == le) { // undefined <= undefined should fail. __ mov(r0, Operand(GREATER)); } else { @@ -441,20 +591,20 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, } __ bind(&return_equal); - if (cc == lt) { + if (cond == lt) { __ mov(r0, Operand(GREATER)); // Things aren't less than themselves. - } else if (cc == gt) { + } else if (cond == gt) { __ mov(r0, Operand(LESS)); // Things aren't greater than themselves. } else { __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves. } __ Ret(); - if (cc != eq || !never_nan_nan) { + if (cond != eq || !never_nan_nan) { // For less and greater we don't have to check for NaN since the result of // x < x is false regardless. For the others here is some code to check // for NaN. - if (cc != lt && cc != gt) { + if (cond != lt && cond != gt) { __ bind(&heap_number); // It is a heap number, so return non-equal if it's NaN and equal if it's // not NaN. @@ -478,10 +628,10 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, // if all bits in mantissa are zero (it's an Infinity) and non-zero if // not (it's a NaN). For <= and >= we need to load r0 with the failing // value if it's a NaN. - if (cc != eq) { + if (cond != eq) { // All-zero means Infinity means equal. __ Ret(eq); - if (cc == le) { + if (cond == le) { __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. } else { __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. @@ -588,7 +738,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm, } -void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cc) { +void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) { bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); Register rhs_exponent = exp_first ? r0 : r1; Register lhs_exponent = exp_first ? r2 : r3; @@ -628,7 +778,7 @@ void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cc) { __ bind(&one_is_nan); // NaN comparisons always fail. // Load whatever we need in r0 to make the comparison fail. - if (cc == lt || cc == le) { + if (cond == lt || cond == le) { __ mov(r0, Operand(GREATER)); } else { __ mov(r0, Operand(LESS)); @@ -640,7 +790,8 @@ void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cc) { // See comment at call site. -static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { +static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, + Condition cond) { bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); Register rhs_exponent = exp_first ? r0 : r1; Register lhs_exponent = exp_first ? r2 : r3; @@ -648,7 +799,7 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { Register lhs_mantissa = exp_first ? r3 : r2; // r0, r1, r2, r3 have the two doubles. Neither is a NaN. - if (cc == eq) { + if (cond == eq) { // Doubles are not equal unless they have the same bit pattern. // Exception: 0 and -0. __ cmp(rhs_mantissa, Operand(lhs_mantissa)); @@ -834,7 +985,7 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, Label is_smi; Label load_result_from_cache; if (!object_is_smi) { - __ BranchOnSmi(object, &is_smi); + __ JumpIfSmi(object, &is_smi); if (CpuFeatures::IsSupported(VFP3)) { CpuFeatures::Scope scope(VFP3); __ CheckMap(object, @@ -860,7 +1011,7 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, Register probe = mask; __ ldr(probe, FieldMemOperand(scratch1, FixedArray::kHeaderSize)); - __ BranchOnSmi(probe, not_found); + __ JumpIfSmi(probe, not_found); __ sub(scratch2, object, Operand(kHeapObjectTag)); __ vldr(d0, scratch2, HeapNumber::kValueOffset); __ sub(probe, probe, Operand(kHeapObjectTag)); @@ -937,7 +1088,7 @@ void CompareStub::Generate(MacroAssembler* masm) { } else if (FLAG_debug_code) { __ orr(r2, r1, r0); __ tst(r2, Operand(kSmiTagMask)); - __ Assert(nz, "CompareStub: unexpected smi operands."); + __ Assert(ne, "CompareStub: unexpected smi operands."); } // NOTICE! This code is only reached after a smi-fast-case check, so @@ -1374,7 +1525,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( __ sub(r0, r5, Operand(kHeapObjectTag)); __ vstr(d5, r0, HeapNumber::kValueOffset); __ add(r0, r0, Operand(kHeapObjectTag)); - __ mov(pc, lr); + __ Ret(); } else { // If we did not inline the operation, then the arguments are in: // r0: Left value (least significant part of mantissa). @@ -1959,7 +2110,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { Label not_smi; if (ShouldGenerateSmiCode() && specialized_on_rhs_) { Label lhs_is_unsuitable; - __ BranchOnNotSmi(lhs, ¬_smi); + __ JumpIfNotSmi(lhs, ¬_smi); if (IsPowerOf2(constant_rhs_)) { if (op_ == Token::MOD) { __ and_(rhs, @@ -2206,8 +2357,467 @@ Handle GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { Handle GetTypeRecordingBinaryOpStub(int key, TRBinaryOpIC::TypeInfo type_info, TRBinaryOpIC::TypeInfo result_type_info) { + TypeRecordingBinaryOpStub stub(key, type_info, result_type_info); + return stub.GetCode(); +} + + +void TypeRecordingBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { + Label get_result; + + __ Push(r1, r0); + + __ mov(r2, Operand(Smi::FromInt(MinorKey()))); + __ mov(r1, Operand(Smi::FromInt(op_))); + __ mov(r0, Operand(Smi::FromInt(operands_type_))); + __ Push(r2, r1, r0); + + __ TailCallExternalReference( + ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch)), + 5, + 1); +} + + +void TypeRecordingBinaryOpStub::GenerateTypeTransitionWithSavedArgs( + MacroAssembler* masm) { UNIMPLEMENTED(); - return Handle::null(); +} + + +void TypeRecordingBinaryOpStub::Generate(MacroAssembler* masm) { + switch (operands_type_) { + case TRBinaryOpIC::UNINITIALIZED: + GenerateTypeTransition(masm); + break; + case TRBinaryOpIC::SMI: + GenerateSmiStub(masm); + break; + case TRBinaryOpIC::INT32: + GenerateInt32Stub(masm); + break; + case TRBinaryOpIC::HEAP_NUMBER: + GenerateHeapNumberStub(masm); + break; + case TRBinaryOpIC::STRING: + GenerateStringStub(masm); + break; + case TRBinaryOpIC::GENERIC: + GenerateGeneric(masm); + break; + default: + UNREACHABLE(); + } +} + + +const char* TypeRecordingBinaryOpStub::GetName() { + if (name_ != NULL) return name_; + const int kMaxNameLength = 100; + name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); + if (name_ == NULL) return "OOM"; + const char* op_name = Token::Name(op_); + const char* overwrite_name; + switch (mode_) { + case NO_OVERWRITE: overwrite_name = "Alloc"; break; + case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; + case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; + default: overwrite_name = "UnknownOverwrite"; break; + } + + OS::SNPrintF(Vector(name_, kMaxNameLength), + "TypeRecordingBinaryOpStub_%s_%s_%s", + op_name, + overwrite_name, + TRBinaryOpIC::GetName(operands_type_)); + return name_; +} + + +void TypeRecordingBinaryOpStub::GenerateSmiSmiOperation( + MacroAssembler* masm) { + Register left = r1; + Register right = r0; + Register scratch1 = r7; + Register scratch2 = r9; + + ASSERT(right.is(r0)); + STATIC_ASSERT(kSmiTag == 0); + + Label not_smi_result; + switch (op_) { + case Token::ADD: + __ add(right, left, Operand(right), SetCC); // Add optimistically. + __ Ret(vc); + __ sub(right, right, Operand(left)); // Revert optimistic add. + break; + case Token::SUB: + __ sub(right, left, Operand(right), SetCC); // Subtract optimistically. + __ Ret(vc); + __ sub(right, left, Operand(right)); // Revert optimistic subtract. + break; + case Token::MUL: + // Remove tag from one of the operands. This way the multiplication result + // will be a smi if it fits the smi range. + __ SmiUntag(ip, right); + // Do multiplication + // scratch1 = lower 32 bits of ip * left. + // scratch2 = higher 32 bits of ip * left. + __ smull(scratch1, scratch2, left, ip); + // Check for overflowing the smi range - no overflow if higher 33 bits of + // the result are identical. + __ mov(ip, Operand(scratch1, ASR, 31)); + __ cmp(ip, Operand(scratch2)); + __ b(ne, ¬_smi_result); + // Go slow on zero result to handle -0. + __ tst(scratch1, Operand(scratch1)); + __ mov(right, Operand(scratch1), LeaveCC, ne); + __ Ret(ne); + // We need -0 if we were multiplying a negative number with 0 to get 0. + // We know one of them was zero. + __ add(scratch2, right, Operand(left), SetCC); + __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl); + __ Ret(pl); // Return smi 0 if the non-zero one was positive. + // We fall through here if we multiplied a negative number with 0, because + // that would mean we should produce -0. + break; + default: + UNREACHABLE(); + } + __ bind(¬_smi_result); +} + + +void TypeRecordingBinaryOpStub::GenerateVFPOperation( + MacroAssembler* masm) { + switch (op_) { + case Token::ADD: + __ vadd(d5, d6, d7); + break; + case Token::SUB: + __ vsub(d5, d6, d7); + break; + case Token::MUL: + __ vmul(d5, d6, d7); + break; + default: + UNREACHABLE(); + } +} + + +// Generate the smi code. If the operation on smis are successful this return is +// generated. If the result is not a smi and heap number allocation is not +// requested the code falls through. If number allocation is requested but a +// heap number cannot be allocated the code jumps to the lable gc_required. +void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, + Label* gc_required, + SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { + Label not_smis; + + ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); + + Register left = r1; + Register right = r0; + Register scratch1 = r7; + Register scratch2 = r9; + + // Perform combined smi check on both operands. + __ orr(scratch1, left, Operand(right)); + STATIC_ASSERT(kSmiTag == 0); + __ tst(scratch1, Operand(kSmiTagMask)); + __ b(ne, ¬_smis); + + GenerateSmiSmiOperation(masm); + + // If heap number results are possible generate the result in an allocated + // heap number. + if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { + FloatingPointHelper::Destination destination = + CpuFeatures::IsSupported(VFP3) && Token::MOD != op_ ? + FloatingPointHelper::kVFPRegisters : + FloatingPointHelper::kCoreRegisters; + + Register heap_number_map = r6; + __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); + + // Allocate new heap number for result. + Register heap_number = r5; + __ AllocateHeapNumber( + heap_number, scratch1, scratch2, heap_number_map, gc_required); + + // Load the smis. + FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); + + // Calculate the result. + if (destination == FloatingPointHelper::kVFPRegisters) { + // Using VFP registers: + // d6: Left value + // d7: Right value + CpuFeatures::Scope scope(VFP3); + GenerateVFPOperation(masm); + + __ sub(r0, heap_number, Operand(kHeapObjectTag)); + __ vstr(d5, r0, HeapNumber::kValueOffset); + __ add(r0, r0, Operand(kHeapObjectTag)); + __ Ret(); + } else { + // Using core registers: + // r0: Left value (least significant part of mantissa). + // r1: Left value (sign, exponent, top of mantissa). + // r2: Right value (least significant part of mantissa). + // r3: Right value (sign, exponent, top of mantissa). + + __ push(lr); // For later. + __ PrepareCallCFunction(4, scratch1); // Two doubles are 4 arguments. + // Call C routine that may not cause GC or other trouble. r5 is callee + // save. + __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); + // Store answer in the overwritable heap number. +#if !defined(USE_ARM_EABI) + // Double returned in fp coprocessor register 0 and 1, encoded as + // register cr8. Offsets must be divisible by 4 for coprocessor so we + // need to substract the tag from r5. + __ sub(scratch1, heap_number, Operand(kHeapObjectTag)); + __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); +#else + // Double returned in registers 0 and 1. + __ Strd(r0, r1, FieldMemOperand(heap_number, HeapNumber::kValueOffset)); +#endif + __ mov(r0, Operand(heap_number)); + // And we are done. + __ pop(pc); + } + } + __ bind(¬_smis); +} + + +void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { + Label not_smis, call_runtime; + + ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); + + if (result_type_ == TRBinaryOpIC::UNINITIALIZED || + result_type_ == TRBinaryOpIC::SMI) { + // Only allow smi results. + GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS); + } else { + // Allow heap number result and don't make a transition if a heap number + // cannot be allocated. + GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); + } + + // Code falls through if the result is not returned as either a smi or heap + // number. + GenerateTypeTransition(masm); + + __ bind(&call_runtime); + GenerateCallRuntime(masm); +} + + +void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) { + ASSERT(operands_type_ == TRBinaryOpIC::STRING); + ASSERT(op_ == Token::ADD); + // Try to add arguments as strings, otherwise, transition to the generic + // TRBinaryOpIC type. + GenerateAddStrings(masm); + GenerateTypeTransition(masm); +} + + +void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { + ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); + + ASSERT(operands_type_ == TRBinaryOpIC::INT32); + + GenerateTypeTransition(masm); +} + + +void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { + ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); + + Register scratch1 = r7; + Register scratch2 = r9; + + Label not_number, call_runtime; + ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER); + + Register heap_number_map = r6; + __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); + + // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 depending on + // whether VFP3 is available. + FloatingPointHelper::Destination destination = + CpuFeatures::IsSupported(VFP3) ? + FloatingPointHelper::kVFPRegisters : + FloatingPointHelper::kCoreRegisters; + FloatingPointHelper::LoadOperands(masm, + destination, + heap_number_map, + scratch1, + scratch2, + ¬_number); + if (destination == FloatingPointHelper::kVFPRegisters) { + // Use floating point instructions for the binary operation. + CpuFeatures::Scope scope(VFP3); + GenerateVFPOperation(masm); + + // Get a heap number object for the result - might be left or right if one + // of these are overwritable. + GenerateHeapResultAllocation( + masm, r4, heap_number_map, scratch1, scratch2, &call_runtime); + + // Fill the result into the allocated heap number and return. + __ sub(r0, r4, Operand(kHeapObjectTag)); + __ vstr(d5, r0, HeapNumber::kValueOffset); + __ add(r0, r0, Operand(kHeapObjectTag)); + __ Ret(); + + } else { + // Call a C function for the binary operation. + // r0/r1: Left operand + // r2/r3: Right operand + + // Get a heap number object for the result - might be left or right if one + // of these are overwritable. Uses a callee-save register to keep the value + // across the c call. + GenerateHeapResultAllocation( + masm, r4, heap_number_map, scratch1, scratch2, &call_runtime); + + __ push(lr); // For returning later (no GC after this point). + __ PrepareCallCFunction(4, scratch1); // Two doubles count as 4 arguments. + // Call C routine that may not cause GC or other trouble. r4 is callee + // saved. + __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); + + // Fill the result into the allocated heap number. + #if !defined(USE_ARM_EABI) + // Double returned in fp coprocessor register 0 and 1, encoded as + // register cr8. Offsets must be divisible by 4 for coprocessor so we + // need to substract the tag from r5. + __ sub(scratch1, r4, Operand(kHeapObjectTag)); + __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); + #else + // Double returned in registers 0 and 1. + __ Strd(r0, r1, FieldMemOperand(r4, HeapNumber::kValueOffset)); + #endif + __ mov(r0, Operand(r4)); + __ pop(pc); // Return to the pushed lr. + } + + __ bind(¬_number); + GenerateTypeTransition(masm); + + __ bind(&call_runtime); + GenerateCallRuntime(masm); +} + + +void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { + ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); + + Label call_runtime; + + GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); + + // If all else fails, use the runtime system to get the correct + // result. + __ bind(&call_runtime); + + // Try to add strings before calling runtime. + if (op_ == Token::ADD) { + GenerateAddStrings(masm); + } + + GenericBinaryOpStub stub(op_, mode_, r1, r0); + __ TailCallStub(&stub); +} + + +void TypeRecordingBinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { + ASSERT(op_ == Token::ADD); + + Register left = r1; + Register right = r0; + Label call_runtime; + + // Check if first argument is a string. + __ JumpIfSmi(left, &call_runtime); + __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); + __ b(ge, &call_runtime); + + // First argument is a a string, test second. + __ JumpIfSmi(right, &call_runtime); + __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); + __ b(ge, &call_runtime); + + // First and second argument are strings. + StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); + GenerateRegisterArgsPush(masm); + __ TailCallStub(&string_add_stub); + + // At least one argument is not a string. + __ bind(&call_runtime); +} + + +void TypeRecordingBinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { + GenerateRegisterArgsPush(masm); + switch (op_) { + case Token::ADD: + __ InvokeBuiltin(Builtins::ADD, JUMP_JS); + break; + case Token::SUB: + __ InvokeBuiltin(Builtins::SUB, JUMP_JS); + break; + case Token::MUL: + __ InvokeBuiltin(Builtins::MUL, JUMP_JS); + break; + default: + UNREACHABLE(); + } +} + + +void TypeRecordingBinaryOpStub::GenerateHeapResultAllocation( + MacroAssembler* masm, + Register result, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* gc_required) { + + // Code below will scratch result if allocation fails. To keep both arguments + // intact for the runtime call result cannot be one of these. + ASSERT(!result.is(r0) && !result.is(r1)); + + if (mode_ == OVERWRITE_LEFT || mode_ == OVERWRITE_RIGHT) { + Label skip_allocation, allocated; + Register overwritable_operand = mode_ == OVERWRITE_LEFT ? r1 : r0; + // If the overwritable operand is already an object, we skip the + // allocation of a heap number. + __ JumpIfNotSmi(overwritable_operand, &skip_allocation); + // Allocate a heap number for the result. + __ AllocateHeapNumber( + result, scratch1, scratch2, heap_number_map, gc_required); + __ b(&allocated); + __ bind(&skip_allocation); + // Use object holding the overwritable operand for result. + __ mov(result, Operand(overwritable_operand)); + __ bind(&allocated); + } else { + ASSERT(mode_ == NO_OVERWRITE); + __ AllocateHeapNumber( + result, scratch1, scratch2, heap_number_map, gc_required); + } +} + + +void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { + __ Push(r1, r0); } @@ -2219,7 +2829,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { if (CpuFeatures::IsSupported(VFP3)) { // Load argument and check if it is a smi. - __ BranchOnNotSmi(r0, &input_not_smi); + __ JumpIfNotSmi(r0, &input_not_smi); CpuFeatures::Scope scope(VFP3); // Input is a smi. Convert to double and load the low and high words @@ -2373,7 +2983,7 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) { } else if (op_ == Token::BIT_NOT) { if (include_smi_code_) { Label non_smi; - __ BranchOnNotSmi(r0, &non_smi); + __ JumpIfNotSmi(r0, &non_smi); __ mvn(r0, Operand(r0)); // Bit-clear inverted smi-tag. __ bic(r0, r0, Operand(kSmiTagMask)); @@ -2557,8 +3167,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_termination_exception, Label* throw_out_of_memory_exception, bool do_gc, - bool always_allocate, - int frame_alignment_skew) { + bool always_allocate) { // r0: result parameter for PerformGC, if any // r4: number of arguments including receiver (C callee-saved) // r5: pointer to builtin function (C callee-saved) @@ -2584,15 +3193,14 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, __ mov(r0, Operand(r4)); __ mov(r1, Operand(r6)); +#if defined(V8_HOST_ARCH_ARM) int frame_alignment = MacroAssembler::ActivationFrameAlignment(); int frame_alignment_mask = frame_alignment - 1; -#if defined(V8_HOST_ARCH_ARM) if (FLAG_debug_code) { if (frame_alignment > kPointerSize) { Label alignment_as_expected; ASSERT(IsPowerOf2(frame_alignment)); - __ sub(r2, sp, Operand(frame_alignment_skew)); - __ tst(r2, Operand(frame_alignment_mask)); + __ tst(sp, Operand(frame_alignment_mask)); __ b(eq, &alignment_as_expected); // Don't use Check here, as it will call Runtime_Abort re-entering here. __ stop("Unexpected alignment"); @@ -2601,35 +3209,20 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, } #endif - // Just before the call (jump) below lr is pushed, so the actual alignment is - // adding one to the current skew. - int alignment_before_call = - (frame_alignment_skew + kPointerSize) & frame_alignment_mask; - if (alignment_before_call > 0) { - // Push until the alignment before the call is met. - __ mov(r2, Operand(0, RelocInfo::NONE)); - for (int i = alignment_before_call; - (i & frame_alignment_mask) != 0; - i += kPointerSize) { - __ push(r2); - } - } - // TODO(1242173): To let the GC traverse the return address of the exit // frames, we need to know where the return address is. Right now, - // we push it on the stack to be able to find it again, but we never + // we store it on the stack to be able to find it again, but we never // restore from it in case of changes, which makes it impossible to // support moving the C entry code stub. This should be fixed, but currently // this is OK because the CEntryStub gets generated so early in the V8 boot // sequence that it is not moving ever. - masm->add(lr, pc, Operand(4)); // Compute return address: (pc + 8) + 4 - masm->push(lr); - masm->Jump(r5); - // Restore sp back to before aligning the stack. - if (alignment_before_call > 0) { - __ add(sp, sp, Operand(alignment_before_call)); - } + // Compute the return address in lr to return to after the jump below. Pc is + // already at '+ 8' from the current instruction but return is after three + // instructions so add another 4 to pc to get the return address. + masm->add(lr, pc, Operand(4)); + __ str(lr, MemOperand(sp, 0)); + masm->Jump(r5); if (always_allocate) { // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 @@ -2717,8 +3310,7 @@ void CEntryStub::Generate(MacroAssembler* masm) { &throw_termination_exception, &throw_out_of_memory_exception, false, - false, - -kPointerSize); + false); // Do space-specific GC and retry runtime call. GenerateCore(masm, @@ -2726,8 +3318,7 @@ void CEntryStub::Generate(MacroAssembler* masm) { &throw_termination_exception, &throw_out_of_memory_exception, true, - false, - 0); + false); // Do full GC and retry runtime call one final time. Failure* failure = Failure::InternalError(); @@ -2737,8 +3328,7 @@ void CEntryStub::Generate(MacroAssembler* masm) { &throw_termination_exception, &throw_out_of_memory_exception, true, - true, - kPointerSize); + true); __ bind(&throw_out_of_memory_exception); GenerateThrowUncatchable(masm, OUT_OF_MEMORY); @@ -2922,7 +3512,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { } // Check that the left hand is a JS object and load map. - __ BranchOnSmi(object, ¬_js_object); + __ JumpIfSmi(object, ¬_js_object); __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); // If there is a call site cache don't look in the global cache, but do the @@ -2945,7 +3535,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ TryGetFunctionPrototype(function, prototype, scratch, &slow); // Check that the function prototype is a JS object. - __ BranchOnSmi(prototype, &slow); + __ JumpIfSmi(prototype, &slow); __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); // Update the global instanceof or call site inlined cache with the current @@ -3025,7 +3615,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ bind(¬_js_object); // Before null, smi and string value checks, check that the rhs is a function // as for a non-function rhs an exception needs to be thrown. - __ BranchOnSmi(function, &slow); + __ JumpIfSmi(function, &slow); __ CompareObjectType(function, scratch2, scratch, JS_FUNCTION_TYPE); __ b(ne, &slow); @@ -3037,7 +3627,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ bind(&object_not_null); // Smi values are not instances of anything. - __ BranchOnNotSmi(object, &object_not_null_or_smi); + __ JumpIfNotSmi(object, &object_not_null_or_smi); __ mov(r0, Operand(Smi::FromInt(1))); __ Ret(HasArgsInRegisters() ? 0 : 2); @@ -3081,7 +3671,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { // Check that the key is a smi. Label slow; - __ BranchOnNotSmi(r1, &slow); + __ JumpIfNotSmi(r1, &slow); // Check if the calling frame is an arguments adaptor frame. Label adaptor; @@ -3285,7 +3875,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); if (FLAG_debug_code) { __ tst(regexp_data, Operand(kSmiTagMask)); - __ Check(nz, "Unexpected type for RegExp data, FixedArray expected"); + __ Check(ne, "Unexpected type for RegExp data, FixedArray expected"); __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); } @@ -3388,7 +3978,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Is first part a flat string? STATIC_ASSERT(kSeqStringTag == 0); __ tst(r0, Operand(kStringRepresentationMask)); - __ b(nz, &runtime); + __ b(ne, &runtime); __ bind(&seq_string); // subject: Subject string @@ -3663,7 +4253,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ ldr(r1, MemOperand(sp, argc_ * kPointerSize)); // Check if receiver is a smi (which is a number value). - __ BranchOnSmi(r1, &receiver_is_value); + __ JumpIfSmi(r1, &receiver_is_value); // Check if the receiver is a valid JS object. __ CompareObjectType(r1, r2, r2, FIRST_JS_OBJECT_TYPE); @@ -3686,7 +4276,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { // Check that the function is really a JavaScript function. // r1: pushed function (to be verified) - __ BranchOnSmi(r1, &slow); + __ JumpIfSmi(r1, &slow); // Get the map of the function object. __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); __ b(ne, &slow); @@ -3790,7 +4380,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { Label got_char_code; // If the receiver is a smi trigger the non-string case. - __ BranchOnSmi(object_, receiver_not_string_); + __ JumpIfSmi(object_, receiver_not_string_); // Fetch the instance type of the receiver into result register. __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); @@ -3800,7 +4390,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { __ b(ne, receiver_not_string_); // If the index is non-smi trigger the non-smi case. - __ BranchOnNotSmi(index_, &index_not_smi_); + __ JumpIfNotSmi(index_, &index_not_smi_); // Put smi-tagged index into scratch register. __ mov(scratch_, index_); @@ -3836,13 +4426,13 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // If the first cons component is also non-flat, then go to runtime. STATIC_ASSERT(kSeqStringTag == 0); __ tst(result_, Operand(kStringRepresentationMask)); - __ b(nz, &call_runtime_); + __ b(ne, &call_runtime_); // Check for 1-byte or 2-byte string. __ bind(&flat_string); STATIC_ASSERT(kAsciiStringTag != 0); __ tst(result_, Operand(kStringEncodingMask)); - __ b(nz, &ascii_string); + __ b(ne, &ascii_string); // 2-byte string. // Load the 2-byte character code into the result register. We can @@ -3897,7 +4487,7 @@ void StringCharCodeAtGenerator::GenerateSlow( __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); call_helper.AfterCall(masm); // If index is still not a smi, it must be out of range. - __ BranchOnNotSmi(scratch_, index_out_of_range_); + __ JumpIfNotSmi(scratch_, index_out_of_range_); // Otherwise, return to the fast path. __ jmp(&got_smi_index_); @@ -3927,7 +4517,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { __ tst(code_, Operand(kSmiTagMask | ((~String::kMaxAsciiCharCode) << kSmiTagSize))); - __ b(nz, &slow_case_); + __ b(ne, &slow_case_); __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); // At this point code register contains smi tagged ascii char code. @@ -4374,7 +4964,7 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, __ add(hash, hash, Operand(hash, LSL, 15), SetCC); // if (hash == 0) hash = 27; - __ mov(hash, Operand(27), LeaveCC, nz); + __ mov(hash, Operand(27), LeaveCC, ne); } diff --git a/deps/v8/src/arm/code-stubs-arm.h b/deps/v8/src/arm/code-stubs-arm.h index 9fa868798e..a79b2392d9 100644 --- a/deps/v8/src/arm/code-stubs-arm.h +++ b/deps/v8/src/arm/code-stubs-arm.h @@ -218,6 +218,117 @@ class GenericBinaryOpStub : public CodeStub { }; +class TypeRecordingBinaryOpStub: public CodeStub { + public: + TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode) + : op_(op), + mode_(mode), + operands_type_(TRBinaryOpIC::UNINITIALIZED), + result_type_(TRBinaryOpIC::UNINITIALIZED), + name_(NULL) { + use_vfp3_ = CpuFeatures::IsSupported(VFP3); + ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); + } + + TypeRecordingBinaryOpStub( + int key, + TRBinaryOpIC::TypeInfo operands_type, + TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED) + : op_(OpBits::decode(key)), + mode_(ModeBits::decode(key)), + use_vfp3_(VFP3Bits::decode(key)), + operands_type_(operands_type), + result_type_(result_type), + name_(NULL) { } + + private: + enum SmiCodeGenerateHeapNumberResults { + ALLOW_HEAPNUMBER_RESULTS, + NO_HEAPNUMBER_RESULTS + }; + + Token::Value op_; + OverwriteMode mode_; + bool use_vfp3_; + + // Operand type information determined at runtime. + TRBinaryOpIC::TypeInfo operands_type_; + TRBinaryOpIC::TypeInfo result_type_; + + char* name_; + + const char* GetName(); + +#ifdef DEBUG + void Print() { + PrintF("TypeRecordingBinaryOpStub %d (op %s), " + "(mode %d, runtime_type_info %s)\n", + MinorKey(), + Token::String(op_), + static_cast(mode_), + TRBinaryOpIC::GetName(operands_type_)); + } +#endif + + // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM. + class ModeBits: public BitField {}; + class OpBits: public BitField {}; + class VFP3Bits: public BitField {}; + class OperandTypeInfoBits: public BitField {}; + class ResultTypeInfoBits: public BitField {}; + + Major MajorKey() { return TypeRecordingBinaryOp; } + int MinorKey() { + return OpBits::encode(op_) + | ModeBits::encode(mode_) + | VFP3Bits::encode(use_vfp3_) + | OperandTypeInfoBits::encode(operands_type_) + | ResultTypeInfoBits::encode(result_type_); + } + + void Generate(MacroAssembler* masm); + void GenerateGeneric(MacroAssembler* masm); + void GenerateSmiSmiOperation(MacroAssembler* masm); + void GenerateVFPOperation(MacroAssembler* masm); + void GenerateSmiCode(MacroAssembler* masm, + Label* gc_required, + SmiCodeGenerateHeapNumberResults heapnumber_results); + void GenerateLoadArguments(MacroAssembler* masm); + void GenerateReturn(MacroAssembler* masm); + void GenerateUninitializedStub(MacroAssembler* masm); + void GenerateSmiStub(MacroAssembler* masm); + void GenerateInt32Stub(MacroAssembler* masm); + void GenerateHeapNumberStub(MacroAssembler* masm); + void GenerateStringStub(MacroAssembler* masm); + void GenerateGenericStub(MacroAssembler* masm); + void GenerateAddStrings(MacroAssembler* masm); + void GenerateCallRuntime(MacroAssembler* masm); + + void GenerateHeapResultAllocation(MacroAssembler* masm, + Register result, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* gc_required); + void GenerateRegisterArgsPush(MacroAssembler* masm); + void GenerateTypeTransition(MacroAssembler* masm); + void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); + + virtual int GetCodeKind() { return Code::TYPE_RECORDING_BINARY_OP_IC; } + + virtual InlineCacheState GetICState() { + return TRBinaryOpIC::ToState(operands_type_); + } + + virtual void FinishCode(Code* code) { + code->set_type_recording_binary_op_type(operands_type_); + code->set_type_recording_binary_op_result_type(result_type_); + } + + friend class CodeGenerator; +}; + + // Flag that indicates how to generate code for the stub StringAddStub. enum StringAddFlags { NO_STRING_ADD_FLAGS = 0, diff --git a/deps/v8/src/arm/codegen-arm-inl.h b/deps/v8/src/arm/codegen-arm-inl.h index 264498dbfb..81ed2d043b 100644 --- a/deps/v8/src/arm/codegen-arm-inl.h +++ b/deps/v8/src/arm/codegen-arm-inl.h @@ -39,7 +39,7 @@ namespace internal { // Platform-specific inline functions. void DeferredCode::Jump() { __ jmp(&entry_label_); } -void DeferredCode::Branch(Condition cc) { __ b(cc, &entry_label_); } +void DeferredCode::Branch(Condition cond) { __ b(cond, &entry_label_); } #undef __ diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 2fa0711959..0d429d602f 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -209,7 +209,7 @@ void CodeGenerator::Generate(CompilationInfo* info) { frame_->AllocateStackSlots(); frame_->AssertIsSpilled(); - int heap_slots = scope()->num_heap_slots(); + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; if (heap_slots > 0) { // Allocate local context. // Get outer context and create a new context based on it. @@ -1589,7 +1589,7 @@ void CodeGenerator::SmiOperation(Token::Value op, } -void CodeGenerator::Comparison(Condition cc, +void CodeGenerator::Comparison(Condition cond, Expression* left, Expression* right, bool strict) { @@ -1603,7 +1603,7 @@ void CodeGenerator::Comparison(Condition cc, // result : cc register // Strict only makes sense for equality comparisons. - ASSERT(!strict || cc == eq); + ASSERT(!strict || cond == eq); Register lhs; Register rhs; @@ -1614,8 +1614,8 @@ void CodeGenerator::Comparison(Condition cc, // We load the top two stack positions into registers chosen by the virtual // frame. This should keep the register shuffling to a minimum. // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. - if (cc == gt || cc == le) { - cc = ReverseCondition(cc); + if (cond == gt || cond == le) { + cond = ReverseCondition(cond); lhs_is_smi = frame_->KnownSmiAt(0); rhs_is_smi = frame_->KnownSmiAt(1); lhs = frame_->PopToRegister(); @@ -1655,7 +1655,7 @@ void CodeGenerator::Comparison(Condition cc, // Perform non-smi comparison by stub. // CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0. // We call with 0 args because there are 0 on the stack. - CompareStub stub(cc, strict, NO_SMI_COMPARE_IN_STUB, lhs, rhs); + CompareStub stub(cond, strict, NO_SMI_COMPARE_IN_STUB, lhs, rhs); frame_->CallStub(&stub, 0); __ cmp(r0, Operand(0, RelocInfo::NONE)); exit.Jump(); @@ -1667,7 +1667,7 @@ void CodeGenerator::Comparison(Condition cc, __ cmp(lhs, Operand(rhs)); exit.Bind(); - cc_reg_ = cc; + cc_reg_ = cond; } @@ -1762,7 +1762,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, // sp[2]: applicand. // Check that the receiver really is a JavaScript object. - __ BranchOnSmi(receiver_reg, &build_args); + __ JumpIfSmi(receiver_reg, &build_args); // We allow all JSObjects including JSFunctions. As long as // JS_FUNCTION_TYPE is the last instance type and it is right // after LAST_JS_OBJECT_TYPE, we do not have to check the upper @@ -1774,7 +1774,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, // Check that applicand.apply is Function.prototype.apply. __ ldr(r0, MemOperand(sp, kPointerSize)); - __ BranchOnSmi(r0, &build_args); + __ JumpIfSmi(r0, &build_args); __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE); __ b(ne, &build_args); Handle apply_code(Builtins::builtin(Builtins::FunctionApply)); @@ -1785,7 +1785,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, // Check that applicand is a function. __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); - __ BranchOnSmi(r1, &build_args); + __ JumpIfSmi(r1, &build_args); __ CompareObjectType(r1, r2, r3, JS_FUNCTION_TYPE); __ b(ne, &build_args); @@ -1885,8 +1885,8 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, void CodeGenerator::Branch(bool if_true, JumpTarget* target) { ASSERT(has_cc()); - Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); - target->Branch(cc); + Condition cond = if_true ? cc_reg_ : NegateCondition(cc_reg_); + target->Branch(cond); cc_reg_ = al; } @@ -4618,8 +4618,8 @@ void CodeGenerator::GenerateMathPow(ZoneList* args) { ASSERT(runtime.entry_frame() == NULL); runtime.set_entry_frame(frame_); - __ BranchOnNotSmi(exponent, &exponent_nonsmi); - __ BranchOnNotSmi(base, &base_nonsmi); + __ JumpIfNotSmi(exponent, &exponent_nonsmi); + __ JumpIfNotSmi(base, &base_nonsmi); heap_number_map = r6; __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); @@ -5572,7 +5572,7 @@ void CodeGenerator::GenerateSwapElements(ZoneList* args) { deferred->Branch(lt); __ ldrb(tmp2, FieldMemOperand(tmp1, Map::kBitFieldOffset)); __ tst(tmp2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask)); - deferred->Branch(nz); + deferred->Branch(ne); // Check the object's elements are in fast case and writable. __ ldr(tmp1, FieldMemOperand(object, JSObject::kElementsOffset)); @@ -5589,7 +5589,7 @@ void CodeGenerator::GenerateSwapElements(ZoneList* args) { __ mov(tmp2, index1); __ orr(tmp2, tmp2, index2); __ tst(tmp2, Operand(kSmiTagMask)); - deferred->Branch(nz); + deferred->Branch(ne); // Check that both indices are valid. __ ldr(tmp2, FieldMemOperand(object, JSArray::kLengthOffset)); @@ -5849,14 +5849,10 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { frame_->EmitPush(r0); } else if (slot != NULL && slot->type() == Slot::LOOKUP) { - // lookup the context holding the named variable + // Delete from the context holding the named variable. frame_->EmitPush(cp); frame_->EmitPush(Operand(variable->name())); - frame_->CallRuntime(Runtime::kLookupContext, 2); - // r0: context - frame_->EmitPush(r0); - frame_->EmitPush(Operand(variable->name())); - frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 2); + frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); frame_->EmitPush(r0); } else { diff --git a/deps/v8/src/arm/constants-arm.cc b/deps/v8/src/arm/constants-arm.cc index 3df7b4e08e..bf9da232cc 100644 --- a/deps/v8/src/arm/constants-arm.cc +++ b/deps/v8/src/arm/constants-arm.cc @@ -32,12 +32,10 @@ #include "constants-arm.h" -namespace assembler { -namespace arm { +namespace v8 { +namespace internal { -namespace v8i = v8::internal; - -double Instr::DoubleImmedVmov() const { +double Instruction::DoubleImmedVmov() const { // Reconstruct a double from the immediate encoded in the vmov instruction. // // instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh] @@ -149,6 +147,6 @@ int Registers::Number(const char* name) { } -} } // namespace assembler::arm +} } // namespace v8::internal #endif // V8_TARGET_ARCH_ARM diff --git a/deps/v8/src/arm/constants-arm.h b/deps/v8/src/arm/constants-arm.h index ff814476ae..7502ef0d65 100644 --- a/deps/v8/src/arm/constants-arm.h +++ b/deps/v8/src/arm/constants-arm.h @@ -86,8 +86,8 @@ #define USE_BLX 1 #endif -namespace assembler { -namespace arm { +namespace v8 { +namespace internal { // Number of registers in normal ARM mode. static const int kNumRegisters = 16; @@ -102,6 +102,9 @@ static const int kNumVFPRegisters = static const int kPCRegister = 15; static const int kNoRegister = -1; +// ----------------------------------------------------------------------------- +// Conditions. + // Defines constants and accessor classes to assemble, disassemble and // simulate ARM instructions. // @@ -111,78 +114,246 @@ static const int kNoRegister = -1; // Constants for specific fields are defined in their respective named enums. // General constants are in an anonymous enum in class Instr. -typedef unsigned char byte; - // Values for the condition field as defined in section A3.2 enum Condition { - no_condition = -1, - EQ = 0, // equal - NE = 1, // not equal - CS = 2, // carry set/unsigned higher or same - CC = 3, // carry clear/unsigned lower - MI = 4, // minus/negative - PL = 5, // plus/positive or zero - VS = 6, // overflow - VC = 7, // no overflow - HI = 8, // unsigned higher - LS = 9, // unsigned lower or same - GE = 10, // signed greater than or equal - LT = 11, // signed less than - GT = 12, // signed greater than - LE = 13, // signed less than or equal - AL = 14, // always (unconditional) - special_condition = 15, // special condition (refer to section A3.2.1) - max_condition = 16 + kNoCondition = -1, + + eq = 0 << 28, // Z set Equal. + ne = 1 << 28, // Z clear Not equal. + cs = 2 << 28, // C set Unsigned higher or same. + cc = 3 << 28, // C clear Unsigned lower. + mi = 4 << 28, // N set Negative. + pl = 5 << 28, // N clear Positive or zero. + vs = 6 << 28, // V set Overflow. + vc = 7 << 28, // V clear No overflow. + hi = 8 << 28, // C set, Z clear Unsigned higher. + ls = 9 << 28, // C clear or Z set Unsigned lower or same. + ge = 10 << 28, // N == V Greater or equal. + lt = 11 << 28, // N != V Less than. + gt = 12 << 28, // Z clear, N == V Greater than. + le = 13 << 28, // Z set or N != V Less then or equal + al = 14 << 28, // Always. + + kSpecialCondition = 15 << 28, // Special condition (refer to section A3.2.1). + kNumberOfConditions = 16, + + // Aliases. + hs = cs, // C set Unsigned higher or same. + lo = cc // C clear Unsigned lower. }; +inline Condition NegateCondition(Condition cond) { + ASSERT(cond != al); + return static_cast(cond ^ ne); +} + + +// Corresponds to transposing the operands of a comparison. +inline Condition ReverseCondition(Condition cond) { + switch (cond) { + case lo: + return hi; + case hi: + return lo; + case hs: + return ls; + case ls: + return hs; + case lt: + return gt; + case gt: + return lt; + case ge: + return le; + case le: + return ge; + default: + return cond; + }; +} + + +// ----------------------------------------------------------------------------- +// Instructions encoding. + +// Instr is merely used by the Assembler to distinguish 32bit integers +// representing instructions from usual 32 bit values. +// Instruction objects are pointers to 32bit values, and provide methods to +// access the various ISA fields. +typedef int32_t Instr; + + // Opcodes for Data-processing instructions (instructions with a type 0 and 1) // as defined in section A3.4 enum Opcode { - no_operand = -1, - AND = 0, // Logical AND - EOR = 1, // Logical Exclusive OR - SUB = 2, // Subtract - RSB = 3, // Reverse Subtract - ADD = 4, // Add - ADC = 5, // Add with Carry - SBC = 6, // Subtract with Carry - RSC = 7, // Reverse Subtract with Carry - TST = 8, // Test - TEQ = 9, // Test Equivalence - CMP = 10, // Compare - CMN = 11, // Compare Negated - ORR = 12, // Logical (inclusive) OR - MOV = 13, // Move - BIC = 14, // Bit Clear - MVN = 15, // Move Not - max_operand = 16 + AND = 0 << 21, // Logical AND. + EOR = 1 << 21, // Logical Exclusive OR. + SUB = 2 << 21, // Subtract. + RSB = 3 << 21, // Reverse Subtract. + ADD = 4 << 21, // Add. + ADC = 5 << 21, // Add with Carry. + SBC = 6 << 21, // Subtract with Carry. + RSC = 7 << 21, // Reverse Subtract with Carry. + TST = 8 << 21, // Test. + TEQ = 9 << 21, // Test Equivalence. + CMP = 10 << 21, // Compare. + CMN = 11 << 21, // Compare Negated. + ORR = 12 << 21, // Logical (inclusive) OR. + MOV = 13 << 21, // Move. + BIC = 14 << 21, // Bit Clear. + MVN = 15 << 21 // Move Not. }; // The bits for bit 7-4 for some type 0 miscellaneous instructions. enum MiscInstructionsBits74 { // With bits 22-21 01. - BX = 1, - BXJ = 2, - BLX = 3, - BKPT = 7, + BX = 1 << 4, + BXJ = 2 << 4, + BLX = 3 << 4, + BKPT = 7 << 4, // With bits 22-21 11. - CLZ = 1 + CLZ = 1 << 4 +}; + + +// Instruction encoding bits and masks. +enum { + H = 1 << 5, // Halfword (or byte). + S6 = 1 << 6, // Signed (or unsigned). + L = 1 << 20, // Load (or store). + S = 1 << 20, // Set condition code (or leave unchanged). + W = 1 << 21, // Writeback base register (or leave unchanged). + A = 1 << 21, // Accumulate in multiply instruction (or not). + B = 1 << 22, // Unsigned byte (or word). + N = 1 << 22, // Long (or short). + U = 1 << 23, // Positive (or negative) offset/index. + P = 1 << 24, // Offset/pre-indexed addressing (or post-indexed addressing). + I = 1 << 25, // Immediate shifter operand (or not). + + B4 = 1 << 4, + B5 = 1 << 5, + B6 = 1 << 6, + B7 = 1 << 7, + B8 = 1 << 8, + B9 = 1 << 9, + B12 = 1 << 12, + B16 = 1 << 16, + B18 = 1 << 18, + B19 = 1 << 19, + B20 = 1 << 20, + B21 = 1 << 21, + B22 = 1 << 22, + B23 = 1 << 23, + B24 = 1 << 24, + B25 = 1 << 25, + B26 = 1 << 26, + B27 = 1 << 27, + B28 = 1 << 28, + + // Instruction bit masks. + kCondMask = 15 << 28, + kALUMask = 0x6f << 21, + kRdMask = 15 << 12, // In str instruction. + kCoprocessorMask = 15 << 8, + kOpCodeMask = 15 << 21, // In data-processing instructions. + kImm24Mask = (1 << 24) - 1, + kOff12Mask = (1 << 12) - 1 +}; + + +// ----------------------------------------------------------------------------- +// Addressing modes and instruction variants. + +// Condition code updating mode. +enum SBit { + SetCC = 1 << 20, // Set condition code. + LeaveCC = 0 << 20 // Leave condition code unchanged. +}; + + +// Status register selection. +enum SRegister { + CPSR = 0 << 22, + SPSR = 1 << 22 }; // Shifter types for Data-processing operands as defined in section A5.1.2. -enum Shift { - no_shift = -1, - LSL = 0, // Logical shift left - LSR = 1, // Logical shift right - ASR = 2, // Arithmetic shift right - ROR = 3, // Rotate right - max_shift = 4 +enum ShiftOp { + LSL = 0 << 5, // Logical shift left. + LSR = 1 << 5, // Logical shift right. + ASR = 2 << 5, // Arithmetic shift right. + ROR = 3 << 5, // Rotate right. + + // RRX is encoded as ROR with shift_imm == 0. + // Use a special code to make the distinction. The RRX ShiftOp is only used + // as an argument, and will never actually be encoded. The Assembler will + // detect it and emit the correct ROR shift operand with shift_imm == 0. + RRX = -1, + kNumberOfShifts = 4 +}; + + +// Status register fields. +enum SRegisterField { + CPSR_c = CPSR | 1 << 16, + CPSR_x = CPSR | 1 << 17, + CPSR_s = CPSR | 1 << 18, + CPSR_f = CPSR | 1 << 19, + SPSR_c = SPSR | 1 << 16, + SPSR_x = SPSR | 1 << 17, + SPSR_s = SPSR | 1 << 18, + SPSR_f = SPSR | 1 << 19 }; +// Status register field mask (or'ed SRegisterField enum values). +typedef uint32_t SRegisterFieldMask; + + +// Memory operand addressing mode. +enum AddrMode { + // Bit encoding P U W. + Offset = (8|4|0) << 21, // Offset (without writeback to base). + PreIndex = (8|4|1) << 21, // Pre-indexed addressing with writeback. + PostIndex = (0|4|0) << 21, // Post-indexed addressing with writeback. + NegOffset = (8|0|0) << 21, // Negative offset (without writeback to base). + NegPreIndex = (8|0|1) << 21, // Negative pre-indexed with writeback. + NegPostIndex = (0|0|0) << 21 // Negative post-indexed with writeback. +}; + + +// Load/store multiple addressing mode. +enum BlockAddrMode { + // Bit encoding P U W . + da = (0|0|0) << 21, // Decrement after. + ia = (0|4|0) << 21, // Increment after. + db = (8|0|0) << 21, // Decrement before. + ib = (8|4|0) << 21, // Increment before. + da_w = (0|0|1) << 21, // Decrement after with writeback to base. + ia_w = (0|4|1) << 21, // Increment after with writeback to base. + db_w = (8|0|1) << 21, // Decrement before with writeback to base. + ib_w = (8|4|1) << 21, // Increment before with writeback to base. + + // Alias modes for comparison when writeback does not matter. + da_x = (0|0|0) << 21, // Decrement after. + ia_x = (0|4|0) << 21, // Increment after. + db_x = (8|0|0) << 21, // Decrement before. + ib_x = (8|4|0) << 21 // Increment before. +}; + + +// Coprocessor load/store operand size. +enum LFlag { + Long = 1 << 22, // Long load/store coprocessor. + Short = 0 << 22 // Short load/store coprocessor. +}; + + +// ----------------------------------------------------------------------------- +// Supervisor Call (svc) specific support. // Special Software Interrupt codes when used in the presence of the ARM // simulator. @@ -190,14 +361,15 @@ enum Shift { // standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature. enum SoftwareInterruptCodes { // transition to C code - call_rt_redirected = 0x10, + kCallRtRedirected= 0x10, // break point - break_point = 0x20, + kBreakpoint= 0x20, // stop - stop = 1 << 23 + kStopCode = 1 << 23 }; -static const int32_t kStopCodeMask = stop - 1; -static const uint32_t kMaxStopCode = stop - 1; +static const uint32_t kStopCodeMask = kStopCode - 1; +static const uint32_t kMaxStopCode = kStopCode - 1; +static const int32_t kDefaultStopCode = -1; // Type of VFP register. Determines register encoding. @@ -206,6 +378,20 @@ enum VFPRegPrecision { kDoublePrecision = 1 }; + +// VFP FPSCR constants. +static const uint32_t kVFPExceptionMask = 0xf; +static const uint32_t kVFPRoundingModeMask = 3 << 22; +static const uint32_t kVFPFlushToZeroMask = 1 << 24; +static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22; +static const uint32_t kVFPInvalidExceptionBit = 1; + +static const uint32_t kVFPNConditionFlagBit = 1 << 31; +static const uint32_t kVFPZConditionFlagBit = 1 << 30; +static const uint32_t kVFPCConditionFlagBit = 1 << 29; +static const uint32_t kVFPVConditionFlagBit = 1 << 28; + + // VFP rounding modes. See ARM DDI 0406B Page A2-29. enum FPSCRRoundingModes { RN, // Round to Nearest. @@ -214,22 +400,91 @@ enum FPSCRRoundingModes { RZ // Round towards zero. }; -typedef int32_t instr_t; +// ----------------------------------------------------------------------------- +// Hints. + +// Branch hints are not used on the ARM. They are defined so that they can +// appear in shared function signatures, but will be ignored in ARM +// implementations. +enum Hint { no_hint }; + +// Hints are not used on the arm. Negating is trivial. +inline Hint NegateHint(Hint ignored) { return no_hint; } + + +// ----------------------------------------------------------------------------- +// Specific instructions, constants, and masks. +// These constants are declared in assembler-arm.cc, as they use named registers +// and other constants. + + +// add(sp, sp, 4) instruction (aka Pop()) +extern const Instr kPopInstruction; -// The class Instr enables access to individual fields defined in the ARM +// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r)) +// register r is not encoded. +extern const Instr kPushRegPattern; + +// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r)) +// register r is not encoded. +extern const Instr kPopRegPattern; + +// mov lr, pc +extern const Instr kMovLrPc; +// ldr rd, [pc, #offset] +extern const Instr kLdrPCMask; +extern const Instr kLdrPCPattern; +// blxcc rm +extern const Instr kBlxRegMask; + +extern const Instr kBlxRegPattern; + +extern const Instr kMovMvnMask; +extern const Instr kMovMvnPattern; +extern const Instr kMovMvnFlip; +extern const Instr kMovLeaveCCMask; +extern const Instr kMovLeaveCCPattern; +extern const Instr kMovwMask; +extern const Instr kMovwPattern; +extern const Instr kMovwLeaveCCFlip; +extern const Instr kCmpCmnMask; +extern const Instr kCmpCmnPattern; +extern const Instr kCmpCmnFlip; +extern const Instr kAddSubFlip; +extern const Instr kAndBicFlip; + +// A mask for the Rd register for push, pop, ldr, str instructions. +extern const Instr kLdrRegFpOffsetPattern; + +extern const Instr kStrRegFpOffsetPattern; + +extern const Instr kLdrRegFpNegOffsetPattern; + +extern const Instr kStrRegFpNegOffsetPattern; + +extern const Instr kLdrStrInstrTypeMask; +extern const Instr kLdrStrInstrArgumentMask; +extern const Instr kLdrStrOffsetMask; + + +// ----------------------------------------------------------------------------- +// Instruction abstraction. + +// The class Instruction enables access to individual fields defined in the ARM // architecture instruction set encoding as described in figure A3-1. +// Note that the Assembler uses typedef int32_t Instr. // // Example: Test whether the instruction at ptr does set the condition code // bits. // // bool InstructionSetsConditionCodes(byte* ptr) { -// Instr* instr = Instr::At(ptr); -// int type = instr->TypeField(); +// Instruction* instr = Instruction::At(ptr); +// int type = instr->TypeValue(); // return ((type == 0) || (type == 1)) && instr->HasS(); // } // -class Instr { +class Instruction { public: enum { kInstrSize = 4, @@ -237,14 +492,24 @@ class Instr { kPCReadOffset = 8 }; + // Helper macro to define static accessors. + // We use the cast to char* trick to bypass the strict anti-aliasing rules. + #define DECLARE_STATIC_TYPED_ACCESSOR(return_type, Name) \ + static inline return_type Name(Instr instr) { \ + char* temp = reinterpret_cast(&instr); \ + return reinterpret_cast(temp)->Name(); \ + } + + #define DECLARE_STATIC_ACCESSOR(Name) DECLARE_STATIC_TYPED_ACCESSOR(int, Name) + // Get the raw instruction bits. - inline instr_t InstructionBits() const { - return *reinterpret_cast(this); + inline Instr InstructionBits() const { + return *reinterpret_cast(this); } // Set the raw instruction bits to value. - inline void SetInstructionBits(instr_t value) { - *reinterpret_cast(this) = value; + inline void SetInstructionBits(Instr value) { + *reinterpret_cast(this) = value; } // Read one particular bit out of the instruction bits. @@ -252,93 +517,141 @@ class Instr { return (InstructionBits() >> nr) & 1; } - // Read a bit field out of the instruction bits. + // Read a bit field's value out of the instruction bits. inline int Bits(int hi, int lo) const { return (InstructionBits() >> lo) & ((2 << (hi - lo)) - 1); } + // Read a bit field out of the instruction bits. + inline int BitField(int hi, int lo) const { + return InstructionBits() & (((2 << (hi - lo)) - 1) << lo); + } + + // Static support. + + // Read one particular bit out of the instruction bits. + static inline int Bit(Instr instr, int nr) { + return (instr >> nr) & 1; + } + + // Read the value of a bit field out of the instruction bits. + static inline int Bits(Instr instr, int hi, int lo) { + return (instr >> lo) & ((2 << (hi - lo)) - 1); + } + + + // Read a bit field out of the instruction bits. + static inline int BitField(Instr instr, int hi, int lo) { + return instr & (((2 << (hi - lo)) - 1) << lo); + } + // Accessors for the different named fields used in the ARM encoding. // The naming of these accessor corresponds to figure A3-1. + // + // Two kind of accessors are declared: + // - Field() will return the raw field, ie the field's bits at their + // original place in the instruction encoding. + // eg. if instr is the 'addgt r0, r1, r2' instruction, encoded as 0xC0810002 + // ConditionField(instr) will return 0xC0000000. + // - Value() will return the field value, shifted back to bit 0. + // eg. if instr is the 'addgt r0, r1, r2' instruction, encoded as 0xC0810002 + // ConditionField(instr) will return 0xC. + + // Generally applicable fields - inline Condition ConditionField() const { + inline Condition ConditionValue() const { return static_cast(Bits(31, 28)); } - inline int TypeField() const { return Bits(27, 25); } + inline Condition ConditionField() const { + return static_cast(BitField(31, 28)); + } + DECLARE_STATIC_TYPED_ACCESSOR(Condition, ConditionValue); + DECLARE_STATIC_TYPED_ACCESSOR(Condition, ConditionField); - inline int RnField() const { return Bits(19, 16); } - inline int RdField() const { return Bits(15, 12); } + inline int TypeValue() const { return Bits(27, 25); } - inline int CoprocessorField() const { return Bits(11, 8); } + inline int RnValue() const { return Bits(19, 16); } + inline int RdValue() const { return Bits(15, 12); } + DECLARE_STATIC_ACCESSOR(RdValue); + + inline int CoprocessorValue() const { return Bits(11, 8); } // Support for VFP. // Vn(19-16) | Vd(15-12) | Vm(3-0) - inline int VnField() const { return Bits(19, 16); } - inline int VmField() const { return Bits(3, 0); } - inline int VdField() const { return Bits(15, 12); } - inline int NField() const { return Bit(7); } - inline int MField() const { return Bit(5); } - inline int DField() const { return Bit(22); } - inline int RtField() const { return Bits(15, 12); } - inline int PField() const { return Bit(24); } - inline int UField() const { return Bit(23); } - inline int Opc1Field() const { return (Bit(23) << 2) | Bits(21, 20); } - inline int Opc2Field() const { return Bits(19, 16); } - inline int Opc3Field() const { return Bits(7, 6); } - inline int SzField() const { return Bit(8); } - inline int VLField() const { return Bit(20); } - inline int VCField() const { return Bit(8); } - inline int VAField() const { return Bits(23, 21); } - inline int VBField() const { return Bits(6, 5); } - inline int VFPNRegCode(VFPRegPrecision pre) { - return VFPGlueRegCode(pre, 16, 7); + inline int VnValue() const { return Bits(19, 16); } + inline int VmValue() const { return Bits(3, 0); } + inline int VdValue() const { return Bits(15, 12); } + inline int NValue() const { return Bit(7); } + inline int MValue() const { return Bit(5); } + inline int DValue() const { return Bit(22); } + inline int RtValue() const { return Bits(15, 12); } + inline int PValue() const { return Bit(24); } + inline int UValue() const { return Bit(23); } + inline int Opc1Value() const { return (Bit(23) << 2) | Bits(21, 20); } + inline int Opc2Value() const { return Bits(19, 16); } + inline int Opc3Value() const { return Bits(7, 6); } + inline int SzValue() const { return Bit(8); } + inline int VLValue() const { return Bit(20); } + inline int VCValue() const { return Bit(8); } + inline int VAValue() const { return Bits(23, 21); } + inline int VBValue() const { return Bits(6, 5); } + inline int VFPNRegValue(VFPRegPrecision pre) { + return VFPGlueRegValue(pre, 16, 7); } - inline int VFPMRegCode(VFPRegPrecision pre) { - return VFPGlueRegCode(pre, 0, 5); + inline int VFPMRegValue(VFPRegPrecision pre) { + return VFPGlueRegValue(pre, 0, 5); } - inline int VFPDRegCode(VFPRegPrecision pre) { - return VFPGlueRegCode(pre, 12, 22); + inline int VFPDRegValue(VFPRegPrecision pre) { + return VFPGlueRegValue(pre, 12, 22); } // Fields used in Data processing instructions - inline Opcode OpcodeField() const { + inline int OpcodeValue() const { return static_cast(Bits(24, 21)); } - inline int SField() const { return Bit(20); } + inline Opcode OpcodeField() const { + return static_cast(BitField(24, 21)); + } + inline int SValue() const { return Bit(20); } // with register - inline int RmField() const { return Bits(3, 0); } - inline Shift ShiftField() const { return static_cast(Bits(6, 5)); } - inline int RegShiftField() const { return Bit(4); } - inline int RsField() const { return Bits(11, 8); } - inline int ShiftAmountField() const { return Bits(11, 7); } + inline int RmValue() const { return Bits(3, 0); } + inline int ShiftValue() const { return static_cast(Bits(6, 5)); } + inline ShiftOp ShiftField() const { + return static_cast(BitField(6, 5)); + } + inline int RegShiftValue() const { return Bit(4); } + inline int RsValue() const { return Bits(11, 8); } + inline int ShiftAmountValue() const { return Bits(11, 7); } // with immediate - inline int RotateField() const { return Bits(11, 8); } - inline int Immed8Field() const { return Bits(7, 0); } - inline int Immed4Field() const { return Bits(19, 16); } - inline int ImmedMovwMovtField() const { - return Immed4Field() << 12 | Offset12Field(); } + inline int RotateValue() const { return Bits(11, 8); } + inline int Immed8Value() const { return Bits(7, 0); } + inline int Immed4Value() const { return Bits(19, 16); } + inline int ImmedMovwMovtValue() const { + return Immed4Value() << 12 | Offset12Value(); } // Fields used in Load/Store instructions - inline int PUField() const { return Bits(24, 23); } - inline int BField() const { return Bit(22); } - inline int WField() const { return Bit(21); } - inline int LField() const { return Bit(20); } + inline int PUValue() const { return Bits(24, 23); } + inline int PUField() const { return BitField(24, 23); } + inline int BValue() const { return Bit(22); } + inline int WValue() const { return Bit(21); } + inline int LValue() const { return Bit(20); } // with register uses same fields as Data processing instructions above // with immediate - inline int Offset12Field() const { return Bits(11, 0); } + inline int Offset12Value() const { return Bits(11, 0); } // multiple - inline int RlistField() const { return Bits(15, 0); } + inline int RlistValue() const { return Bits(15, 0); } // extra loads and stores - inline int SignField() const { return Bit(6); } - inline int HField() const { return Bit(5); } - inline int ImmedHField() const { return Bits(11, 8); } - inline int ImmedLField() const { return Bits(3, 0); } + inline int SignValue() const { return Bit(6); } + inline int HValue() const { return Bit(5); } + inline int ImmedHValue() const { return Bits(11, 8); } + inline int ImmedLValue() const { return Bits(3, 0); } // Fields used in Branch instructions - inline int LinkField() const { return Bit(24); } - inline int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); } + inline int LinkValue() const { return Bit(24); } + inline int SImmed24Value() const { return ((InstructionBits() << 8) >> 8); } // Fields used in Software interrupt instructions - inline SoftwareInterruptCodes SvcField() const { + inline SoftwareInterruptCodes SvcValue() const { return static_cast(Bits(23, 0)); } @@ -354,42 +667,45 @@ class Instr { // Test for a stop instruction. inline bool IsStop() const { - return (TypeField() == 7) && (Bit(24) == 1) && (SvcField() >= stop); + return (TypeValue() == 7) && (Bit(24) == 1) && (SvcValue() >= kStopCode); } // Special accessors that test for existence of a value. - inline bool HasS() const { return SField() == 1; } - inline bool HasB() const { return BField() == 1; } - inline bool HasW() const { return WField() == 1; } - inline bool HasL() const { return LField() == 1; } - inline bool HasU() const { return UField() == 1; } - inline bool HasSign() const { return SignField() == 1; } - inline bool HasH() const { return HField() == 1; } - inline bool HasLink() const { return LinkField() == 1; } + inline bool HasS() const { return SValue() == 1; } + inline bool HasB() const { return BValue() == 1; } + inline bool HasW() const { return WValue() == 1; } + inline bool HasL() const { return LValue() == 1; } + inline bool HasU() const { return UValue() == 1; } + inline bool HasSign() const { return SignValue() == 1; } + inline bool HasH() const { return HValue() == 1; } + inline bool HasLink() const { return LinkValue() == 1; } // Decoding the double immediate in the vmov instruction. double DoubleImmedVmov() const; // Instructions are read of out a code stream. The only way to get a // reference to an instruction is to convert a pointer. There is no way - // to allocate or create instances of class Instr. - // Use the At(pc) function to create references to Instr. - static Instr* At(byte* pc) { return reinterpret_cast(pc); } + // to allocate or create instances of class Instruction. + // Use the At(pc) function to create references to Instruction. + static Instruction* At(byte* pc) { + return reinterpret_cast(pc); + } + private: // Join split register codes, depending on single or double precision. // four_bit is the position of the least-significant bit of the four // bit specifier. one_bit is the position of the additional single bit // specifier. - inline int VFPGlueRegCode(VFPRegPrecision pre, int four_bit, int one_bit) { + inline int VFPGlueRegValue(VFPRegPrecision pre, int four_bit, int one_bit) { if (pre == kSinglePrecision) { return (Bits(four_bit + 3, four_bit) << 1) | Bit(one_bit); } return (Bit(one_bit) << 4) | Bits(four_bit + 3, four_bit); } - // We need to prevent the creation of instances of class Instr. - DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); + // We need to prevent the creation of instances of class Instruction. + DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction); }; @@ -428,6 +744,6 @@ class VFPRegisters { }; -} } // namespace assembler::arm +} } // namespace v8::internal #endif // V8_ARM_CONSTANTS_ARM_H_ diff --git a/deps/v8/src/arm/cpu-arm.cc b/deps/v8/src/arm/cpu-arm.cc index b359dce668..507954d9e1 100644 --- a/deps/v8/src/arm/cpu-arm.cc +++ b/deps/v8/src/arm/cpu-arm.cc @@ -56,7 +56,7 @@ void CPU::FlushICache(void* start, size_t size) { // that the Icache was flushed. // None of this code ends up in the snapshot so there are no issues // around whether or not to generate the code when building snapshots. - assembler::arm::Simulator::FlushICache(start, size); + Simulator::FlushICache(start, size); #else // Ideally, we would call // syscall(__ARM_NR_cacheflush, start, diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index 8a53d1cbd6..3fd1e394e7 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -112,13 +112,16 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } -void Deoptimizer::PatchStackCheckCode(RelocInfo* rinfo, +void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code, + Code* check_code, Code* replacement_code) { UNIMPLEMENTED(); } -void Deoptimizer::RevertStackCheckCode(RelocInfo* rinfo, Code* check_code) { +void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code, + Code* check_code, + Code* replacement_code) { UNIMPLEMENTED(); } @@ -367,7 +370,7 @@ void Deoptimizer::EntryGenerator::Generate() { // Copy core registers into FrameDescription::registers_[kNumRegisters]. ASSERT(Register::kNumRegisters == kNumberOfRegisters); for (int i = 0; i < kNumberOfRegisters; i++) { - int offset = (i * kIntSize) + FrameDescription::registers_offset(); + int offset = (i * kPointerSize) + FrameDescription::registers_offset(); __ ldr(r2, MemOperand(sp, i * kPointerSize)); __ str(r2, MemOperand(r1, offset)); } @@ -456,7 +459,7 @@ void Deoptimizer::EntryGenerator::Generate() { // Push the registers from the last output frame. for (int i = kNumberOfRegisters - 1; i >= 0; i--) { - int offset = (i * kIntSize) + FrameDescription::registers_offset(); + int offset = (i * kPointerSize) + FrameDescription::registers_offset(); __ ldr(r6, MemOperand(r2, offset)); __ push(r6); } diff --git a/deps/v8/src/arm/disasm-arm.cc b/deps/v8/src/arm/disasm-arm.cc index 297a2db5b2..4e77ef3f12 100644 --- a/deps/v8/src/arm/disasm-arm.cc +++ b/deps/v8/src/arm/disasm-arm.cc @@ -64,10 +64,8 @@ #include "platform.h" -namespace assembler { -namespace arm { - -namespace v8i = v8::internal; +namespace v8 { +namespace internal { //------------------------------------------------------------------------------ @@ -78,7 +76,7 @@ namespace v8i = v8::internal; class Decoder { public: Decoder(const disasm::NameConverter& converter, - v8::internal::Vector out_buffer) + Vector out_buffer) : converter_(converter), out_buffer_(out_buffer), out_buffer_pos_(0) { @@ -100,45 +98,45 @@ class Decoder { void PrintRegister(int reg); void PrintSRegister(int reg); void PrintDRegister(int reg); - int FormatVFPRegister(Instr* instr, const char* format); - void PrintMovwMovt(Instr* instr); - int FormatVFPinstruction(Instr* instr, const char* format); - void PrintCondition(Instr* instr); - void PrintShiftRm(Instr* instr); - void PrintShiftImm(Instr* instr); - void PrintShiftSat(Instr* instr); - void PrintPU(Instr* instr); + int FormatVFPRegister(Instruction* instr, const char* format); + void PrintMovwMovt(Instruction* instr); + int FormatVFPinstruction(Instruction* instr, const char* format); + void PrintCondition(Instruction* instr); + void PrintShiftRm(Instruction* instr); + void PrintShiftImm(Instruction* instr); + void PrintShiftSat(Instruction* instr); + void PrintPU(Instruction* instr); void PrintSoftwareInterrupt(SoftwareInterruptCodes svc); // Handle formatting of instructions and their options. - int FormatRegister(Instr* instr, const char* option); - int FormatOption(Instr* instr, const char* option); - void Format(Instr* instr, const char* format); - void Unknown(Instr* instr); + int FormatRegister(Instruction* instr, const char* option); + int FormatOption(Instruction* instr, const char* option); + void Format(Instruction* instr, const char* format); + void Unknown(Instruction* instr); // Each of these functions decodes one particular instruction type, a 3-bit // field in the instruction encoding. // Types 0 and 1 are combined as they are largely the same except for the way // they interpret the shifter operand. - void DecodeType01(Instr* instr); - void DecodeType2(Instr* instr); - void DecodeType3(Instr* instr); - void DecodeType4(Instr* instr); - void DecodeType5(Instr* instr); - void DecodeType6(Instr* instr); + void DecodeType01(Instruction* instr); + void DecodeType2(Instruction* instr); + void DecodeType3(Instruction* instr); + void DecodeType4(Instruction* instr); + void DecodeType5(Instruction* instr); + void DecodeType6(Instruction* instr); // Type 7 includes special Debugger instructions. - int DecodeType7(Instr* instr); + int DecodeType7(Instruction* instr); // For VFP support. - void DecodeTypeVFP(Instr* instr); - void DecodeType6CoprocessorIns(Instr* instr); + void DecodeTypeVFP(Instruction* instr); + void DecodeType6CoprocessorIns(Instruction* instr); - void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr); - void DecodeVCMP(Instr* instr); - void DecodeVCVTBetweenDoubleAndSingle(Instr* instr); - void DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr); + void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction* instr); + void DecodeVCMP(Instruction* instr); + void DecodeVCVTBetweenDoubleAndSingle(Instruction* instr); + void DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr); const disasm::NameConverter& converter_; - v8::internal::Vector out_buffer_; + Vector out_buffer_; int out_buffer_pos_; DISALLOW_COPY_AND_ASSIGN(Decoder); @@ -169,15 +167,15 @@ void Decoder::Print(const char* str) { // These condition names are defined in a way to match the native disassembler // formatting. See for example the command "objdump -d ". -static const char* cond_names[max_condition] = { +static const char* cond_names[kNumberOfConditions] = { "eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" , "hi", "ls", "ge", "lt", "gt", "le", "", "invalid", }; // Print the condition guarding the instruction. -void Decoder::PrintCondition(Instr* instr) { - Print(cond_names[instr->ConditionField()]); +void Decoder::PrintCondition(Instruction* instr) { + Print(cond_names[instr->ConditionValue()]); } @@ -188,36 +186,37 @@ void Decoder::PrintRegister(int reg) { // Print the VFP S register name according to the active name converter. void Decoder::PrintSRegister(int reg) { - Print(assembler::arm::VFPRegisters::Name(reg, false)); + Print(VFPRegisters::Name(reg, false)); } // Print the VFP D register name according to the active name converter. void Decoder::PrintDRegister(int reg) { - Print(assembler::arm::VFPRegisters::Name(reg, true)); + Print(VFPRegisters::Name(reg, true)); } // These shift names are defined in a way to match the native disassembler // formatting. See for example the command "objdump -d ". -static const char* shift_names[max_shift] = { +static const char* shift_names[kNumberOfShifts] = { "lsl", "lsr", "asr", "ror" }; // Print the register shift operands for the instruction. Generally used for // data processing instructions. -void Decoder::PrintShiftRm(Instr* instr) { - Shift shift = instr->ShiftField(); - int shift_amount = instr->ShiftAmountField(); - int rm = instr->RmField(); +void Decoder::PrintShiftRm(Instruction* instr) { + ShiftOp shift = instr->ShiftField(); + int shift_index = instr->ShiftValue(); + int shift_amount = instr->ShiftAmountValue(); + int rm = instr->RmValue(); PrintRegister(rm); - if ((instr->RegShiftField() == 0) && (shift == LSL) && (shift_amount == 0)) { + if ((instr->RegShiftValue() == 0) && (shift == LSL) && (shift_amount == 0)) { // Special case for using rm only. return; } - if (instr->RegShiftField() == 0) { + if (instr->RegShiftValue() == 0) { // by immediate if ((shift == ROR) && (shift_amount == 0)) { Print(", RRX"); @@ -225,14 +224,15 @@ void Decoder::PrintShiftRm(Instr* instr) { } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) { shift_amount = 32; } - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - ", %s #%d", - shift_names[shift], shift_amount); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + ", %s #%d", + shift_names[shift_index], + shift_amount); } else { // by register - int rs = instr->RsField(); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - ", %s ", shift_names[shift]); + int rs = instr->RsValue(); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + ", %s ", shift_names[shift_index]); PrintRegister(rs); } } @@ -240,43 +240,43 @@ void Decoder::PrintShiftRm(Instr* instr) { // Print the immediate operand for the instruction. Generally used for data // processing instructions. -void Decoder::PrintShiftImm(Instr* instr) { - int rotate = instr->RotateField() * 2; - int immed8 = instr->Immed8Field(); +void Decoder::PrintShiftImm(Instruction* instr) { + int rotate = instr->RotateValue() * 2; + int immed8 = instr->Immed8Value(); int imm = (immed8 >> rotate) | (immed8 << (32 - rotate)); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "#%d", imm); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "#%d", imm); } // Print the optional shift and immediate used by saturating instructions. -void Decoder::PrintShiftSat(Instr* instr) { +void Decoder::PrintShiftSat(Instruction* instr) { int shift = instr->Bits(11, 7); if (shift > 0) { - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - ", %s #%d", - shift_names[instr->Bit(6) * 2], - instr->Bits(11, 7)); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + ", %s #%d", + shift_names[instr->Bit(6) * 2], + instr->Bits(11, 7)); } } // Print PU formatting to reduce complexity of FormatOption. -void Decoder::PrintPU(Instr* instr) { +void Decoder::PrintPU(Instruction* instr) { switch (instr->PUField()) { - case 0: { + case da_x: { Print("da"); break; } - case 1: { + case ia_x: { Print("ia"); break; } - case 2: { + case db_x: { Print("db"); break; } - case 3: { + case ib_x: { Print("ib"); break; } @@ -292,22 +292,22 @@ void Decoder::PrintPU(Instr* instr) { // the FormatOption method. void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) { switch (svc) { - case call_rt_redirected: - Print("call_rt_redirected"); + case kCallRtRedirected: + Print("call rt redirected"); return; - case break_point: - Print("break_point"); + case kBreakpoint: + Print("breakpoint"); return; default: - if (svc >= stop) { - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%d - 0x%x", - svc & kStopCodeMask, - svc & kStopCodeMask); + if (svc >= kStopCode) { + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d - 0x%x", + svc & kStopCodeMask, + svc & kStopCodeMask); } else { - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%d", - svc); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d", + svc); } return; } @@ -316,32 +316,32 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) { // Handle all register based formatting in this function to reduce the // complexity of FormatOption. -int Decoder::FormatRegister(Instr* instr, const char* format) { +int Decoder::FormatRegister(Instruction* instr, const char* format) { ASSERT(format[0] == 'r'); if (format[1] == 'n') { // 'rn: Rn register - int reg = instr->RnField(); + int reg = instr->RnValue(); PrintRegister(reg); return 2; } else if (format[1] == 'd') { // 'rd: Rd register - int reg = instr->RdField(); + int reg = instr->RdValue(); PrintRegister(reg); return 2; } else if (format[1] == 's') { // 'rs: Rs register - int reg = instr->RsField(); + int reg = instr->RsValue(); PrintRegister(reg); return 2; } else if (format[1] == 'm') { // 'rm: Rm register - int reg = instr->RmField(); + int reg = instr->RmValue(); PrintRegister(reg); return 2; } else if (format[1] == 't') { // 'rt: Rt register - int reg = instr->RtField(); + int reg = instr->RtValue(); PrintRegister(reg); return 2; } else if (format[1] == 'l') { // 'rlist: register list for load and store multiple instructions ASSERT(STRING_STARTS_WITH(format, "rlist")); - int rlist = instr->RlistField(); + int rlist = instr->RlistValue(); int reg = 0; Print("{"); // Print register list in ascending order, by scanning the bit mask. @@ -365,22 +365,22 @@ int Decoder::FormatRegister(Instr* instr, const char* format) { // Handle all VFP register based formatting in this function to reduce the // complexity of FormatOption. -int Decoder::FormatVFPRegister(Instr* instr, const char* format) { +int Decoder::FormatVFPRegister(Instruction* instr, const char* format) { ASSERT((format[0] == 'S') || (format[0] == 'D')); if (format[1] == 'n') { - int reg = instr->VnField(); - if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->NField())); + int reg = instr->VnValue(); + if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->NValue())); if (format[0] == 'D') PrintDRegister(reg); return 2; } else if (format[1] == 'm') { - int reg = instr->VmField(); - if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->MField())); + int reg = instr->VmValue(); + if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->MValue())); if (format[0] == 'D') PrintDRegister(reg); return 2; } else if (format[1] == 'd') { - int reg = instr->VdField(); - if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->DField())); + int reg = instr->VdValue(); + if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->DValue())); if (format[0] == 'D') PrintDRegister(reg); return 2; } @@ -390,19 +390,19 @@ int Decoder::FormatVFPRegister(Instr* instr, const char* format) { } -int Decoder::FormatVFPinstruction(Instr* instr, const char* format) { +int Decoder::FormatVFPinstruction(Instruction* instr, const char* format) { Print(format); return 0; } // Print the movw or movt instruction. -void Decoder::PrintMovwMovt(Instr* instr) { - int imm = instr->ImmedMovwMovtField(); - int rd = instr->RdField(); +void Decoder::PrintMovwMovt(Instruction* instr) { + int imm = instr->ImmedMovwMovtValue(); + int rd = instr->RdValue(); PrintRegister(rd); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - ", #%d", imm); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + ", #%d", imm); } @@ -411,7 +411,7 @@ void Decoder::PrintMovwMovt(Instr* instr) { // character of the option string (the option escape has already been // consumed by the caller.) FormatOption returns the number of // characters that were consumed from the formatting string. -int Decoder::FormatOption(Instr* instr, const char* format) { +int Decoder::FormatOption(Instruction* instr, const char* format) { switch (format[0]) { case 'a': { // 'a: accumulate multiplies if (instr->Bit(21) == 0) { @@ -434,8 +434,8 @@ int Decoder::FormatOption(Instr* instr, const char* format) { } case 'd': { // 'd: vmov double immediate. double d = instr->DoubleImmedVmov(); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "#%g", d); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "#%g", d); return 1; } case 'f': { // 'f: bitfield instructions - v7 and above. @@ -448,8 +448,8 @@ int Decoder::FormatOption(Instr* instr, const char* format) { ASSERT(width > 0); } ASSERT((width + lsbit) <= 32); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "#%d, #%d", lsbit, width); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "#%d, #%d", lsbit, width); return 1; } case 'h': { // 'h: halfword operation for extra loads and stores @@ -469,9 +469,9 @@ int Decoder::FormatOption(Instr* instr, const char* format) { ASSERT((lsb >= 0) && (lsb <= 31)); ASSERT((width + lsb) <= 32); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%d", - instr->Bits(width + lsb - 1, lsb)); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d", + instr->Bits(width + lsb - 1, lsb)); return 8; } case 'l': { // 'l: branch and link @@ -505,31 +505,31 @@ int Decoder::FormatOption(Instr* instr, const char* format) { ASSERT(STRING_STARTS_WITH(format, "msg")); byte* str = reinterpret_cast(instr->InstructionBits() & 0x0fffffff); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%s", converter_.NameInCode(str)); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%s", converter_.NameInCode(str)); return 3; } case 'o': { if ((format[3] == '1') && (format[4] == '2')) { // 'off12: 12-bit offset for load and store instructions ASSERT(STRING_STARTS_WITH(format, "off12")); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%d", instr->Offset12Field()); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d", instr->Offset12Value()); return 5; } else if (format[3] == '0') { // 'off0to3and8to19 16-bit immediate encoded in bits 19-8 and 3-0. ASSERT(STRING_STARTS_WITH(format, "off0to3and8to19")); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%d", - (instr->Bits(19, 8) << 4) + - instr->Bits(3, 0)); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d", + (instr->Bits(19, 8) << 4) + + instr->Bits(3, 0)); return 15; } // 'off8: 8-bit offset for extra load and store instructions ASSERT(STRING_STARTS_WITH(format, "off8")); - int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField(); - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%d", offs8); + int offs8 = (instr->ImmedHValue() << 4) | instr->ImmedLValue(); + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d", offs8); return 4; } case 'p': { // 'pu: P and U bits for load and store instructions @@ -544,10 +544,10 @@ int Decoder::FormatOption(Instr* instr, const char* format) { if (format[1] == 'h') { // 'shift_op or 'shift_rm or 'shift_sat. if (format[6] == 'o') { // 'shift_op ASSERT(STRING_STARTS_WITH(format, "shift_op")); - if (instr->TypeField() == 0) { + if (instr->TypeValue() == 0) { PrintShiftRm(instr); } else { - ASSERT(instr->TypeField() == 1); + ASSERT(instr->TypeValue() == 1); PrintShiftImm(instr); } return 8; @@ -562,7 +562,7 @@ int Decoder::FormatOption(Instr* instr, const char* format) { } } else if (format[1] == 'v') { // 'svc ASSERT(STRING_STARTS_WITH(format, "svc")); - PrintSoftwareInterrupt(instr->SvcField()); + PrintSoftwareInterrupt(instr->SvcValue()); return 3; } else if (format[1] == 'i') { // 'sign: signed extra loads and stores ASSERT(STRING_STARTS_WITH(format, "sign")); @@ -579,12 +579,12 @@ int Decoder::FormatOption(Instr* instr, const char* format) { } case 't': { // 'target: target of branch instructions ASSERT(STRING_STARTS_WITH(format, "target")); - int off = (instr->SImmed24Field() << 2) + 8; - out_buffer_pos_ += v8i::OS::SNPrintF( - out_buffer_ + out_buffer_pos_, - "%+d -> %s", - off, - converter_.NameOfAddress(reinterpret_cast(instr) + off)); + int off = (instr->SImmed24Value() << 2) + 8; + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%+d -> %s", + off, + converter_.NameOfAddress( + reinterpret_cast(instr) + off)); return 6; } case 'u': { // 'u: signed or unsigned multiplies @@ -633,7 +633,7 @@ int Decoder::FormatOption(Instr* instr, const char* format) { // Format takes a formatting string for a whole instruction and prints it into // the output buffer. All escaped options are handed to FormatOption to be // parsed further. -void Decoder::Format(Instr* instr, const char* format) { +void Decoder::Format(Instruction* instr, const char* format) { char cur = *format++; while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) { if (cur == '\'') { // Single quote is used as the formatting escape. @@ -649,13 +649,13 @@ void Decoder::Format(Instr* instr, const char* format) { // For currently unimplemented decodings the disassembler calls Unknown(instr) // which will just print "unknown" of the instruction bits. -void Decoder::Unknown(Instr* instr) { +void Decoder::Unknown(Instruction* instr) { Format(instr, "unknown"); } -void Decoder::DecodeType01(Instr* instr) { - int type = instr->TypeField(); +void Decoder::DecodeType01(Instruction* instr) { + int type = instr->TypeValue(); if ((type == 0) && instr->IsSpecialType0()) { // multiply instruction or extra loads and stores if (instr->Bits(7, 4) == 9) { @@ -689,7 +689,7 @@ void Decoder::DecodeType01(Instr* instr) { } else if ((instr->Bit(20) == 0) && ((instr->Bits(7, 4) & 0xd) == 0xd)) { // ldrd, strd switch (instr->PUField()) { - case 0: { + case da_x: { if (instr->Bit(22) == 0) { Format(instr, "'memop'cond's 'rd, ['rn], -'rm"); } else { @@ -697,7 +697,7 @@ void Decoder::DecodeType01(Instr* instr) { } break; } - case 1: { + case ia_x: { if (instr->Bit(22) == 0) { Format(instr, "'memop'cond's 'rd, ['rn], +'rm"); } else { @@ -705,7 +705,7 @@ void Decoder::DecodeType01(Instr* instr) { } break; } - case 2: { + case db_x: { if (instr->Bit(22) == 0) { Format(instr, "'memop'cond's 'rd, ['rn, -'rm]'w"); } else { @@ -713,7 +713,7 @@ void Decoder::DecodeType01(Instr* instr) { } break; } - case 3: { + case ib_x: { if (instr->Bit(22) == 0) { Format(instr, "'memop'cond's 'rd, ['rn, +'rm]'w"); } else { @@ -730,7 +730,7 @@ void Decoder::DecodeType01(Instr* instr) { } else { // extra load/store instructions switch (instr->PUField()) { - case 0: { + case da_x: { if (instr->Bit(22) == 0) { Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm"); } else { @@ -738,7 +738,7 @@ void Decoder::DecodeType01(Instr* instr) { } break; } - case 1: { + case ia_x: { if (instr->Bit(22) == 0) { Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm"); } else { @@ -746,7 +746,7 @@ void Decoder::DecodeType01(Instr* instr) { } break; } - case 2: { + case db_x: { if (instr->Bit(22) == 0) { Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w"); } else { @@ -754,7 +754,7 @@ void Decoder::DecodeType01(Instr* instr) { } break; } - case 3: { + case ib_x: { if (instr->Bit(22) == 0) { Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w"); } else { @@ -772,7 +772,7 @@ void Decoder::DecodeType01(Instr* instr) { } } else if ((type == 0) && instr->IsMiscType0()) { if (instr->Bits(22, 21) == 1) { - switch (instr->Bits(7, 4)) { + switch (instr->BitField(7, 4)) { case BX: Format(instr, "bx'cond 'rm"); break; @@ -787,7 +787,7 @@ void Decoder::DecodeType01(Instr* instr) { break; } } else if (instr->Bits(22, 21) == 3) { - switch (instr->Bits(7, 4)) { + switch (instr->BitField(7, 4)) { case CLZ: Format(instr, "clz'cond 'rd, 'rm"); break; @@ -894,27 +894,27 @@ void Decoder::DecodeType01(Instr* instr) { } -void Decoder::DecodeType2(Instr* instr) { +void Decoder::DecodeType2(Instruction* instr) { switch (instr->PUField()) { - case 0: { + case da_x: { if (instr->HasW()) { Unknown(instr); // not used in V8 } Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12"); break; } - case 1: { + case ia_x: { if (instr->HasW()) { Unknown(instr); // not used in V8 } Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12"); break; } - case 2: { + case db_x: { Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w"); break; } - case 3: { + case ib_x: { Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w"); break; } @@ -927,14 +927,14 @@ void Decoder::DecodeType2(Instr* instr) { } -void Decoder::DecodeType3(Instr* instr) { +void Decoder::DecodeType3(Instruction* instr) { switch (instr->PUField()) { - case 0: { + case da_x: { ASSERT(!instr->HasW()); Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm"); break; } - case 1: { + case ia_x: { if (instr->HasW()) { ASSERT(instr->Bits(5, 4) == 0x1); if (instr->Bit(22) == 0x1) { @@ -947,11 +947,11 @@ void Decoder::DecodeType3(Instr* instr) { } break; } - case 2: { + case db_x: { Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w"); break; } - case 3: { + case ib_x: { if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) { uint32_t widthminus1 = static_cast(instr->Bits(20, 16)); uint32_t lsbit = static_cast(instr->Bits(11, 7)); @@ -969,7 +969,7 @@ void Decoder::DecodeType3(Instr* instr) { uint32_t lsbit = static_cast(instr->Bits(11, 7)); uint32_t msbit = static_cast(instr->Bits(20, 16)); if (msbit >= lsbit) { - if (instr->RmField() == 15) { + if (instr->RmValue() == 15) { Format(instr, "bfc'cond 'rd, 'f"); } else { Format(instr, "bfi'cond 'rd, 'rm, 'f"); @@ -991,7 +991,7 @@ void Decoder::DecodeType3(Instr* instr) { } -void Decoder::DecodeType4(Instr* instr) { +void Decoder::DecodeType4(Instruction* instr) { ASSERT(instr->Bit(22) == 0); // Privileged mode currently not supported. if (instr->HasL()) { Format(instr, "ldm'cond'pu 'rn'w, 'rlist"); @@ -1001,41 +1001,43 @@ void Decoder::DecodeType4(Instr* instr) { } -void Decoder::DecodeType5(Instr* instr) { +void Decoder::DecodeType5(Instruction* instr) { Format(instr, "b'l'cond 'target"); } -void Decoder::DecodeType6(Instr* instr) { +void Decoder::DecodeType6(Instruction* instr) { DecodeType6CoprocessorIns(instr); } -int Decoder::DecodeType7(Instr* instr) { +int Decoder::DecodeType7(Instruction* instr) { if (instr->Bit(24) == 1) { - if (instr->SvcField() >= stop) { + if (instr->SvcValue() >= kStopCode) { Format(instr, "stop'cond 'svc"); // Also print the stop message. Its address is encoded // in the following 4 bytes. - out_buffer_pos_ += - v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "\n %p %08x stop message: %s", - reinterpret_cast(instr + Instr::kInstrSize), - *reinterpret_cast(instr + Instr::kInstrSize), - *reinterpret_cast(instr + Instr::kInstrSize)); - // We have decoded 2 * Instr::kInstrSize bytes. - return 2 * Instr::kInstrSize; + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "\n %p %08x stop message: %s", + reinterpret_cast(instr + + Instruction::kInstrSize), + *reinterpret_cast(instr + + Instruction::kInstrSize), + *reinterpret_cast(instr + + Instruction::kInstrSize)); + // We have decoded 2 * Instruction::kInstrSize bytes. + return 2 * Instruction::kInstrSize; } else { Format(instr, "svc'cond 'svc"); } } else { DecodeTypeVFP(instr); } - return Instr::kInstrSize; + return Instruction::kInstrSize; } -// void Decoder::DecodeTypeVFP(Instr* instr) +// void Decoder::DecodeTypeVFP(Instruction* instr) // vmov: Sn = Rt // vmov: Rt = Sn // vcvt: Dd = Sm @@ -1048,34 +1050,34 @@ int Decoder::DecodeType7(Instr* instr) { // vmrs // vmsr // Dd = vsqrt(Dm) -void Decoder::DecodeTypeVFP(Instr* instr) { - ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) ); +void Decoder::DecodeTypeVFP(Instruction* instr) { + ASSERT((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) ); ASSERT(instr->Bits(11, 9) == 0x5); if (instr->Bit(4) == 0) { - if (instr->Opc1Field() == 0x7) { + if (instr->Opc1Value() == 0x7) { // Other data processing instructions - if ((instr->Opc2Field() == 0x0) && (instr->Opc3Field() == 0x1)) { + if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) { // vmov register to register. - if (instr->SzField() == 0x1) { + if (instr->SzValue() == 0x1) { Format(instr, "vmov.f64'cond 'Dd, 'Dm"); } else { Format(instr, "vmov.f32'cond 'Sd, 'Sm"); } - } else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) { + } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) { DecodeVCVTBetweenDoubleAndSingle(instr); - } else if ((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) { + } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) { DecodeVCVTBetweenFloatingPointAndInteger(instr); - } else if (((instr->Opc2Field() >> 1) == 0x6) && - (instr->Opc3Field() & 0x1)) { + } else if (((instr->Opc2Value() >> 1) == 0x6) && + (instr->Opc3Value() & 0x1)) { DecodeVCVTBetweenFloatingPointAndInteger(instr); - } else if (((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && - (instr->Opc3Field() & 0x1)) { + } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) && + (instr->Opc3Value() & 0x1)) { DecodeVCMP(instr); - } else if (((instr->Opc2Field() == 0x1)) && (instr->Opc3Field() == 0x3)) { + } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) { Format(instr, "vsqrt.f64'cond 'Dd, 'Dm"); - } else if (instr->Opc3Field() == 0x0) { - if (instr->SzField() == 0x1) { + } else if (instr->Opc3Value() == 0x0) { + if (instr->SzValue() == 0x1) { Format(instr, "vmov.f64'cond 'Dd, 'd"); } else { Unknown(instr); // Not used by V8. @@ -1083,9 +1085,9 @@ void Decoder::DecodeTypeVFP(Instr* instr) { } else { Unknown(instr); // Not used by V8. } - } else if (instr->Opc1Field() == 0x3) { - if (instr->SzField() == 0x1) { - if (instr->Opc3Field() & 0x1) { + } else if (instr->Opc1Value() == 0x3) { + if (instr->SzValue() == 0x1) { + if (instr->Opc3Value() & 0x1) { Format(instr, "vsub.f64'cond 'Dd, 'Dn, 'Dm"); } else { Format(instr, "vadd.f64'cond 'Dd, 'Dn, 'Dm"); @@ -1093,14 +1095,14 @@ void Decoder::DecodeTypeVFP(Instr* instr) { } else { Unknown(instr); // Not used by V8. } - } else if ((instr->Opc1Field() == 0x2) && !(instr->Opc3Field() & 0x1)) { - if (instr->SzField() == 0x1) { + } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) { + if (instr->SzValue() == 0x1) { Format(instr, "vmul.f64'cond 'Dd, 'Dn, 'Dm"); } else { Unknown(instr); // Not used by V8. } - } else if ((instr->Opc1Field() == 0x4) && !(instr->Opc3Field() & 0x1)) { - if (instr->SzField() == 0x1) { + } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) { + if (instr->SzValue() == 0x1) { Format(instr, "vdiv.f64'cond 'Dd, 'Dn, 'Dm"); } else { Unknown(instr); // Not used by V8. @@ -1109,13 +1111,13 @@ void Decoder::DecodeTypeVFP(Instr* instr) { Unknown(instr); // Not used by V8. } } else { - if ((instr->VCField() == 0x0) && - (instr->VAField() == 0x0)) { + if ((instr->VCValue() == 0x0) && + (instr->VAValue() == 0x0)) { DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr); - } else if ((instr->VCField() == 0x0) && - (instr->VAField() == 0x7) && + } else if ((instr->VCValue() == 0x0) && + (instr->VAValue() == 0x7) && (instr->Bits(19, 16) == 0x1)) { - if (instr->VLField() == 0) { + if (instr->VLValue() == 0) { if (instr->Bits(15, 12) == 0xF) { Format(instr, "vmsr'cond FPSCR, APSR"); } else { @@ -1133,11 +1135,12 @@ void Decoder::DecodeTypeVFP(Instr* instr) { } -void Decoder::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) { - ASSERT((instr->Bit(4) == 1) && (instr->VCField() == 0x0) && - (instr->VAField() == 0x0)); +void Decoder::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters( + Instruction* instr) { + ASSERT((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) && + (instr->VAValue() == 0x0)); - bool to_arm_register = (instr->VLField() == 0x1); + bool to_arm_register = (instr->VLValue() == 0x1); if (to_arm_register) { Format(instr, "vmov'cond 'rt, 'Sn"); @@ -1147,19 +1150,19 @@ void Decoder::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) { } -void Decoder::DecodeVCMP(Instr* instr) { - ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); - ASSERT(((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && - (instr->Opc3Field() & 0x1)); +void Decoder::DecodeVCMP(Instruction* instr) { + ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7)); + ASSERT(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) && + (instr->Opc3Value() & 0x1)); // Comparison. - bool dp_operation = (instr->SzField() == 1); + bool dp_operation = (instr->SzValue() == 1); bool raise_exception_for_qnan = (instr->Bit(7) == 0x1); if (dp_operation && !raise_exception_for_qnan) { - if (instr->Opc2Field() == 0x4) { + if (instr->Opc2Value() == 0x4) { Format(instr, "vcmp.f64'cond 'Dd, 'Dm"); - } else if (instr->Opc2Field() == 0x5) { + } else if (instr->Opc2Value() == 0x5) { Format(instr, "vcmp.f64'cond 'Dd, #0.0"); } else { Unknown(instr); // invalid @@ -1170,11 +1173,11 @@ void Decoder::DecodeVCMP(Instr* instr) { } -void Decoder::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) { - ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); - ASSERT((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)); +void Decoder::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) { + ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7)); + ASSERT((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)); - bool double_to_single = (instr->SzField() == 1); + bool double_to_single = (instr->SzValue() == 1); if (double_to_single) { Format(instr, "vcvt.f32.f64'cond 'Sd, 'Dm"); @@ -1184,13 +1187,13 @@ void Decoder::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) { } -void Decoder::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { - ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); - ASSERT(((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) || - (((instr->Opc2Field() >> 1) == 0x6) && (instr->Opc3Field() & 0x1))); +void Decoder::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) { + ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7)); + ASSERT(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) || + (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1))); bool to_integer = (instr->Bit(18) == 1); - bool dp_operation = (instr->SzField() == 1); + bool dp_operation = (instr->SzValue() == 1); if (to_integer) { bool unsigned_integer = (instr->Bit(16) == 0); @@ -1232,11 +1235,11 @@ void Decoder::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { // = vmov(Dm) // Ddst = MEM(Rbase + 4*offset). // MEM(Rbase + 4*offset) = Dsrc. -void Decoder::DecodeType6CoprocessorIns(Instr* instr) { - ASSERT((instr->TypeField() == 6)); +void Decoder::DecodeType6CoprocessorIns(Instruction* instr) { + ASSERT(instr->TypeValue() == 6); - if (instr->CoprocessorField() == 0xA) { - switch (instr->OpcodeField()) { + if (instr->CoprocessorValue() == 0xA) { + switch (instr->OpcodeValue()) { case 0x8: case 0xA: if (instr->HasL()) { @@ -1257,8 +1260,8 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) { Unknown(instr); // Not used by V8. break; } - } else if (instr->CoprocessorField() == 0xB) { - switch (instr->OpcodeField()) { + } else if (instr->CoprocessorValue() == 0xB) { + switch (instr->OpcodeValue()) { case 0x2: // Load and store double to two GP registers if (instr->Bits(7, 4) != 0x1) { @@ -1295,16 +1298,16 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) { // Disassemble the instruction at *instr_ptr into the output buffer. int Decoder::InstructionDecode(byte* instr_ptr) { - Instr* instr = Instr::At(instr_ptr); + Instruction* instr = Instruction::At(instr_ptr); // Print raw instruction bytes. - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%08x ", - instr->InstructionBits()); - if (instr->ConditionField() == special_condition) { + out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%08x ", + instr->InstructionBits()); + if (instr->ConditionField() == kSpecialCondition) { UNIMPLEMENTED(); - return Instr::kInstrSize; + return Instruction::kInstrSize; } - switch (instr->TypeField()) { + switch (instr->TypeValue()) { case 0: case 1: { DecodeType01(instr); @@ -1339,11 +1342,11 @@ int Decoder::InstructionDecode(byte* instr_ptr) { break; } } - return Instr::kInstrSize; + return Instruction::kInstrSize; } -} } // namespace assembler::arm +} } // namespace v8::internal @@ -1351,8 +1354,6 @@ int Decoder::InstructionDecode(byte* instr_ptr) { namespace disasm { -namespace v8i = v8::internal; - const char* NameConverter::NameOfAddress(byte* addr) const { static v8::internal::EmbeddedVector tmp_buffer; @@ -1367,7 +1368,7 @@ const char* NameConverter::NameOfConstant(byte* addr) const { const char* NameConverter::NameOfCPURegister(int reg) const { - return assembler::arm::Registers::Name(reg); + return v8::internal::Registers::Name(reg); } @@ -1401,7 +1402,7 @@ Disassembler::~Disassembler() {} int Disassembler::InstructionDecode(v8::internal::Vector buffer, byte* instruction) { - assembler::arm::Decoder d(converter_, buffer); + v8::internal::Decoder d(converter_, buffer); return d.InstructionDecode(instruction); } diff --git a/deps/v8/src/arm/frames-arm.cc b/deps/v8/src/arm/frames-arm.cc index d2726cfcfe..a805d280ca 100644 --- a/deps/v8/src/arm/frames-arm.cc +++ b/deps/v8/src/arm/frames-arm.cc @@ -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: @@ -30,20 +30,13 @@ #if defined(V8_TARGET_ARCH_ARM) #include "frames-inl.h" -#include "arm/assembler-arm-inl.h" - namespace v8 { namespace internal { Address ExitFrame::ComputeStackPointer(Address fp) { - Address marker = Memory::Address_at(fp + ExitFrameConstants::kMarkerOffset); - Address sp = fp + ExitFrameConstants::kSPOffset; - if (marker == NULL) { - sp -= DwVfpRegister::kNumRegisters * kDoubleSize + 2 * kPointerSize; - } - return sp; + return Memory::Address_at(fp + ExitFrameConstants::kSPOffset); } diff --git a/deps/v8/src/arm/frames-arm.h b/deps/v8/src/arm/frames-arm.h index f1be27f4bf..4aa8d6aa9a 100644 --- a/deps/v8/src/arm/frames-arm.h +++ b/deps/v8/src/arm/frames-arm.h @@ -107,21 +107,17 @@ class EntryFrameConstants : public AllStatic { class ExitFrameConstants : public AllStatic { public: - static const int kCodeOffset = -1 * kPointerSize; + static const int kCodeOffset = -2 * kPointerSize; static const int kSPOffset = -1 * kPointerSize; - // TODO(regis): Use a patched sp value on the stack instead. - // A marker of 0 indicates that double registers are saved. - static const int kMarkerOffset = -2 * kPointerSize; - // The caller fields are below the frame pointer on the stack. - static const int kCallerFPOffset = +0 * kPointerSize; - // The calling JS function is between FP and PC. - static const int kCallerPCOffset = +2 * kPointerSize; + static const int kCallerFPOffset = 0 * kPointerSize; + // The calling JS function is below FP. + static const int kCallerPCOffset = 1 * kPointerSize; // FP-relative displacement of the caller's SP. It points just // below the saved PC. - static const int kCallerSPDisplacement = +3 * kPointerSize; + static const int kCallerSPDisplacement = 2 * kPointerSize; }; @@ -131,8 +127,8 @@ class StandardFrameConstants : public AllStatic { static const int kMarkerOffset = -2 * kPointerSize; static const int kContextOffset = -1 * kPointerSize; static const int kCallerFPOffset = 0 * kPointerSize; - static const int kCallerPCOffset = +1 * kPointerSize; - static const int kCallerSPOffset = +2 * kPointerSize; + static const int kCallerPCOffset = 1 * kPointerSize; + static const int kCallerSPOffset = 2 * kPointerSize; }; diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index ddc74e2f73..66de8e972f 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -92,7 +92,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { bool function_in_register = true; // Possibly allocate a local context. - int heap_slots = scope()->num_heap_slots(); + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; if (heap_slots > 0) { Comment cmnt(masm_, "[ Allocate local context"); // Argument to NewContext is the function, which is in r1. @@ -517,16 +517,16 @@ void FullCodeGenerator::DoTest(Label* if_true, } -void FullCodeGenerator::Split(Condition cc, +void FullCodeGenerator::Split(Condition cond, Label* if_true, Label* if_false, Label* fall_through) { if (if_false == fall_through) { - __ b(cc, if_true); + __ b(cond, if_true); } else if (if_true == fall_through) { - __ b(NegateCondition(cc), if_false); + __ b(NegateCondition(cond), if_false); } else { - __ b(cc, if_true); + __ b(cond, if_true); __ b(if_false); } } @@ -734,6 +734,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // Compile all the tests with branches to their bodies. for (int i = 0; i < clauses->length(); i++) { CaseClause* clause = clauses->at(i); + clause->body_target()->entry_label()->Unuse(); + // The default is not a test, but remember it as final fall through. if (clause->is_default()) { default_clause = clause; @@ -817,7 +819,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Convert the object to a JS object. Label convert, done_convert; - __ BranchOnSmi(r0, &convert); + __ JumpIfSmi(r0, &convert); __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE); __ b(hs, &done_convert); __ bind(&convert); @@ -1548,8 +1550,13 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, void FullCodeGenerator::EmitBinaryOp(Token::Value op, OverwriteMode mode) { __ pop(r1); - GenericBinaryOpStub stub(op, mode, r1, r0); - __ CallStub(&stub); + if (op == Token::ADD || op == Token::SUB || op == Token::MUL) { + TypeRecordingBinaryOpStub stub(op, mode); + __ CallStub(&stub); + } else { + GenericBinaryOpStub stub(op, mode, r1, r0); + __ CallStub(&stub); + } context()->Plug(r0); } @@ -2130,7 +2137,7 @@ void FullCodeGenerator::EmitIsObject(ZoneList* args) { context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - __ BranchOnSmi(r0, if_false); + __ JumpIfSmi(r0, if_false); __ LoadRoot(ip, Heap::kNullValueRootIndex); __ cmp(r0, ip); __ b(eq, if_true); @@ -2162,7 +2169,7 @@ void FullCodeGenerator::EmitIsSpecObject(ZoneList* args) { context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - __ BranchOnSmi(r0, if_false); + __ JumpIfSmi(r0, if_false); __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE); PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); Split(ge, if_true, if_false, fall_through); @@ -2183,7 +2190,7 @@ void FullCodeGenerator::EmitIsUndetectableObject(ZoneList* args) { context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - __ BranchOnSmi(r0, if_false); + __ JumpIfSmi(r0, if_false); __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset)); __ tst(r1, Operand(1 << Map::kIsUndetectable)); @@ -2229,7 +2236,7 @@ void FullCodeGenerator::EmitIsFunction(ZoneList* args) { context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - __ BranchOnSmi(r0, if_false); + __ JumpIfSmi(r0, if_false); __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE); PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); Split(eq, if_true, if_false, fall_through); @@ -2250,7 +2257,7 @@ void FullCodeGenerator::EmitIsArray(ZoneList* args) { context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - __ BranchOnSmi(r0, if_false); + __ JumpIfSmi(r0, if_false); __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); Split(eq, if_true, if_false, fall_through); @@ -2271,7 +2278,7 @@ void FullCodeGenerator::EmitIsRegExp(ZoneList* args) { context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - __ BranchOnSmi(r0, if_false); + __ JumpIfSmi(r0, if_false); __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); Split(eq, if_true, if_false, fall_through); @@ -2378,7 +2385,7 @@ void FullCodeGenerator::EmitClassOf(ZoneList* args) { VisitForAccumulatorValue(args->at(0)); // If the object is a smi, we return null. - __ BranchOnSmi(r0, &null); + __ JumpIfSmi(r0, &null); // Check that the object is a JS object but take special care of JS // functions to make sure they have 'Function' as their class. @@ -2529,7 +2536,7 @@ void FullCodeGenerator::EmitValueOf(ZoneList* args) { Label done; // If the object is a smi return the object. - __ BranchOnSmi(r0, &done); + __ JumpIfSmi(r0, &done); // If the object is not a value type, return the object. __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE); __ b(ne, &done); @@ -2559,7 +2566,7 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList* args) { Label done; // If the object is a smi, return the value. - __ BranchOnSmi(r1, &done); + __ JumpIfSmi(r1, &done); // If the object is not a value type, return the value. __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE); @@ -2992,22 +2999,20 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { if (prop != NULL) { VisitForStackValue(prop->obj()); VisitForStackValue(prop->key()); + __ InvokeBuiltin(Builtins::DELETE, CALL_JS); } else if (var->is_global()) { __ ldr(r1, GlobalObjectOperand()); __ mov(r0, Operand(var->name())); __ Push(r1, r0); + __ InvokeBuiltin(Builtins::DELETE, CALL_JS); } else { - // Non-global variable. Call the runtime to look up the context - // where the variable was introduced. + // Non-global variable. Call the runtime to delete from the + // context where the variable was introduced. __ push(context_register()); __ mov(r2, Operand(var->name())); __ push(r2); - __ CallRuntime(Runtime::kLookupContext, 2); - __ push(r0); - __ mov(r2, Operand(var->name())); - __ push(r2); + __ CallRuntime(Runtime::kDeleteContextSlot, 2); } - __ InvokeBuiltin(Builtins::DELETE, CALL_JS); context()->Plug(r0); } break; @@ -3084,7 +3089,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { bool inline_smi_code = ShouldInlineSmiCase(expr->op()); if (inline_smi_code) { Label call_stub; - __ BranchOnNotSmi(r0, &call_stub); + __ JumpIfNotSmi(r0, &call_stub); __ mvn(r0, Operand(r0)); // Bit-clear inverted smi-tag. __ bic(r0, r0, Operand(kSmiTagMask)); @@ -3171,7 +3176,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { // Call ToNumber only if operand is not a smi. Label no_conversion; - __ BranchOnSmi(r0, &no_conversion); + __ JumpIfSmi(r0, &no_conversion); __ push(r0); __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); __ bind(&no_conversion); @@ -3205,7 +3210,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ b(vs, &stub_call); // We could eliminate this smi check if we split the code at // the first smi check before calling ToNumber. - __ BranchOnSmi(r0, &done); + __ JumpIfSmi(r0, &done); __ bind(&stub_call); // Call stub. Undo operation first. __ sub(r0, r0, Operand(Smi::FromInt(count_value))); @@ -3458,34 +3463,34 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { default: { VisitForAccumulatorValue(expr->right()); - Condition cc = eq; + Condition cond = eq; bool strict = false; switch (op) { case Token::EQ_STRICT: strict = true; // Fall through case Token::EQ: - cc = eq; + cond = eq; __ pop(r1); break; case Token::LT: - cc = lt; + cond = lt; __ pop(r1); break; case Token::GT: // Reverse left and right sides to obtain ECMA-262 conversion order. - cc = lt; + cond = lt; __ mov(r1, result_register()); __ pop(r0); break; case Token::LTE: // Reverse left and right sides to obtain ECMA-262 conversion order. - cc = ge; + cond = ge; __ mov(r1, result_register()); __ pop(r0); break; case Token::GTE: - cc = ge; + cond = ge; __ pop(r1); break; case Token::IN: @@ -3498,19 +3503,19 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { if (inline_smi_code) { Label slow_case; __ orr(r2, r0, Operand(r1)); - __ BranchOnNotSmi(r2, &slow_case); + __ JumpIfNotSmi(r2, &slow_case); __ cmp(r1, r0); - Split(cc, if_true, if_false, NULL); + Split(cond, if_true, if_false, NULL); __ bind(&slow_case); } CompareFlags flags = inline_smi_code ? NO_SMI_COMPARE_IN_STUB : NO_COMPARE_FLAGS; - CompareStub stub(cc, strict, flags, r1, r0); + CompareStub stub(cond, strict, flags, r1, r0); __ CallStub(&stub); PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); __ cmp(r0, Operand(0, RelocInfo::NONE)); - Split(cc, if_true, if_false, fall_through); + Split(cond, if_true, if_false, fall_through); } } diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 51a8149efb..d74468c945 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -95,13 +95,13 @@ static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm, __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset)); __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasNamedInterceptor))); - __ b(nz, miss); + __ b(ne, miss); __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset)); __ LoadRoot(ip, Heap::kHashTableMapRootIndex); __ cmp(t1, ip); - __ b(nz, miss); + __ b(ne, miss); } @@ -379,7 +379,7 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) { } -void LoadIC::GenerateStringLength(MacroAssembler* masm) { +void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) { // ----------- S t a t e ------------- // -- r2 : name // -- lr : return address @@ -388,7 +388,8 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) { // ----------------------------------- Label miss; - StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss); + StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss, + support_wrappers); // Cache miss: Jump to runtime. __ bind(&miss); StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); @@ -419,14 +420,14 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, int interceptor_bit, Label* slow) { // Check that the object isn't a smi. - __ BranchOnSmi(receiver, slow); + __ JumpIfSmi(receiver, slow); // Get the map of the receiver. __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); // Check bit field. __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset)); __ tst(scratch, Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit))); - __ b(nz, slow); + __ b(ne, slow); // Check that the object is some kind of JS object EXCEPT JS Value type. // In the case that the object is a value-wrapper object, // we enter the runtime system to make sure that indexing into string @@ -749,7 +750,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { Label index_smi, index_string; // Check that the key is a smi. - __ BranchOnNotSmi(r2, &check_string); + __ JumpIfNotSmi(r2, &check_string); __ bind(&index_smi); // Now the key is known to be a smi. This place is also jumped to from below // where a numeric string is converted to a smi. @@ -1165,7 +1166,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { Register receiver = r1; // Check that the key is a smi. - __ BranchOnNotSmi(key, &check_string); + __ JumpIfNotSmi(key, &check_string); __ bind(&index_smi); // Now the key is known to be a smi. This place is also jumped to from below // where a numeric string is converted to a smi. @@ -1346,7 +1347,7 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { Label slow; // Check that the receiver isn't a smi. - __ BranchOnSmi(r1, &slow); + __ JumpIfSmi(r1, &slow); // Check that the key is an array index, that is Uint32. __ tst(r0, Operand(kSmiTagMask | kSmiSignMask)); @@ -1470,7 +1471,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { __ b(ne, &slow); // Check that the value is a smi. If a conversion is needed call into the // runtime to convert and clamp. - __ BranchOnNotSmi(value, &slow); + __ JumpIfNotSmi(value, &slow); __ mov(r4, Operand(key, ASR, kSmiTagSize)); // Untag the key. __ ldr(ip, FieldMemOperand(elements, PixelArray::kLengthOffset)); __ cmp(r4, Operand(ip)); @@ -1589,7 +1590,7 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) { Register scratch = r3; // Check that the receiver isn't a smi. - __ BranchOnSmi(receiver, &miss); + __ JumpIfSmi(receiver, &miss); // Check that the object is a JS array. __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE); @@ -1603,7 +1604,7 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) { __ b(ne, &miss); // Check that value is a smi. - __ BranchOnNotSmi(value, &miss); + __ JumpIfNotSmi(value, &miss); // Prepare tail call to StoreIC_ArrayLength. __ Push(receiver, value); @@ -1673,7 +1674,7 @@ Condition CompareIC::ComputeCondition(Token::Value op) { return ge; default: UNREACHABLE(); - return no_condition; + return kNoCondition; } } @@ -1704,7 +1705,7 @@ void CompareIC::UpdateCaches(Handle x, Handle y) { void PatchInlinedSmiCode(Address address) { - UNIMPLEMENTED(); + // Currently there is no smi inlining in the ARM full code generator. } diff --git a/deps/v8/src/arm/jump-target-arm.cc b/deps/v8/src/arm/jump-target-arm.cc index c6eb62891f..b9e6ebf247 100644 --- a/deps/v8/src/arm/jump-target-arm.cc +++ b/deps/v8/src/arm/jump-target-arm.cc @@ -76,7 +76,7 @@ void JumpTarget::DoJump() { } -void JumpTarget::DoBranch(Condition cc, Hint ignored) { +void JumpTarget::DoBranch(Condition cond, Hint ignored) { ASSERT(cgen()->has_valid_frame()); if (entry_frame_set_) { @@ -86,7 +86,7 @@ void JumpTarget::DoBranch(Condition cc, Hint ignored) { ASSERT(entry_frame_.IsCompatibleWith(cgen()->frame())); } // We have an expected frame to merge to on the backward edge. - cgen()->frame()->MergeTo(&entry_frame_, cc); + cgen()->frame()->MergeTo(&entry_frame_, cond); } else { // Clone the current frame to use as the expected one at the target. set_entry_frame(cgen()->frame()); @@ -98,8 +98,8 @@ void JumpTarget::DoBranch(Condition cc, Hint ignored) { // frame with less precise type info branches to them. ASSERT(direction_ != FORWARD_ONLY); } - __ b(cc, &entry_label_); - if (cc == al) { + __ b(cond, &entry_label_); + if (cond == al) { cgen()->DeleteFrame(); } } diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index c484e39edc..c458138380 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -820,6 +820,7 @@ LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op, return MarkAsCall(DefineFixed(result, r0), instr); } + void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) { ASSERT(is_building()); current_block_ = block; @@ -1018,11 +1019,8 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { HIsObject* compare = HIsObject::cast(v); ASSERT(compare->value()->representation().IsTagged()); - LOperand* temp1 = TempRegister(); - LOperand* temp2 = TempRegister(); - return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()), - temp1, - temp2); + LOperand* temp = TempRegister(); + return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()), temp); } else if (v->IsCompareJSObjectEq()) { HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), @@ -1030,8 +1028,8 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { } else if (v->IsInstanceOf()) { HInstanceOf* instance_of = HInstanceOf::cast(v); LInstruction* result = - new LInstanceOfAndBranch(Use(instance_of->left()), - Use(instance_of->right())); + new LInstanceOfAndBranch(UseFixed(instance_of->left(), r0), + UseFixed(instance_of->right(), r1)); return MarkAsCall(result, instr); } else if (v->IsTypeofIs()) { HTypeofIs* typeof_is = HTypeofIs::cast(v); @@ -1133,7 +1131,7 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { case kMathAbs: return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result))); case kMathFloor: - return AssignEnvironment(DefineAsRegister(result)); + return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); case kMathSqrt: return DefineSameAsFirst(result); case kMathRound: @@ -1313,8 +1311,8 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { if (instr->representation().IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); - LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); - LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand()); + LOperand* left = UseRegisterAtStart(instr->left()); + LOperand* right = UseOrConstantAtStart(instr->right()); LSubI* sub = new LSubI(left, right); LInstruction* result = DefineSameAsFirst(sub); if (instr->CheckFlag(HValue::kCanOverflow)) { @@ -1404,7 +1402,7 @@ LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) { ASSERT(instr->value()->representation().IsTagged()); LOperand* value = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new LIsObject(value, TempRegister())); + return DefineAsRegister(new LIsObject(value)); } @@ -1604,7 +1602,14 @@ LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) { LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) { - return new LStoreGlobal(UseRegisterAtStart(instr->value())); + if (instr->check_hole_value()) { + LOperand* temp = TempRegister(); + LOperand* value = UseRegister(instr->value()); + return AssignEnvironment(new LStoreGlobal(value, temp)); + } else { + LOperand* value = UseRegisterAtStart(instr->value()); + return new LStoreGlobal(value, NULL); + } } diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index 81a0266b2f..3de5832981 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -734,9 +734,8 @@ class LIsNullAndBranch: public LControlInstruction<1, 0> { class LIsObject: public LTemplateInstruction<1, 1, 1> { public: - LIsObject(LOperand* value, LOperand* temp) { + explicit LIsObject(LOperand* value) { inputs_[0] = value; - temps_[0] = temp; } DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object") @@ -745,10 +744,9 @@ class LIsObject: public LTemplateInstruction<1, 1, 1> { class LIsObjectAndBranch: public LControlInstruction<1, 2> { public: - LIsObjectAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { + LIsObjectAndBranch(LOperand* value, LOperand* temp) { inputs_[0] = value; temps_[0] = temp; - temps_[1] = temp2; } DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") @@ -1256,10 +1254,11 @@ class LLoadGlobal: public LTemplateInstruction<1, 0, 0> { }; -class LStoreGlobal: public LTemplateInstruction<0, 1, 0> { +class LStoreGlobal: public LTemplateInstruction<0, 1, 1> { public: - explicit LStoreGlobal(LOperand* value) { + LStoreGlobal(LOperand* value, LOperand* temp) { inputs_[0] = value; + temps_[0] = temp; } DECLARE_CONCRETE_INSTRUCTION(StoreGlobal, "store-global") diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 6abb830f83..1ccad1774f 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -661,7 +661,7 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { return; } - if (cc == no_condition) { + if (cc == kNoCondition) { if (FLAG_trap_on_deopt) __ stop("trap_on_deopt"); __ Jump(entry, RelocInfo::RUNTIME_ENTRY); } else { @@ -736,37 +736,40 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() { } -void LCodeGen::RecordSafepoint(LPointerMap* pointers, - int deoptimization_index) { +void LCodeGen::RecordSafepoint( + LPointerMap* pointers, + Safepoint::Kind kind, + int arguments, + int deoptimization_index) { const ZoneList* operands = pointers->operands(); Safepoint safepoint = safepoints_.DefineSafepoint(masm(), - deoptimization_index); + kind, arguments, deoptimization_index); for (int i = 0; i < operands->length(); i++) { LOperand* pointer = operands->at(i); if (pointer->IsStackSlot()) { safepoint.DefinePointerSlot(pointer->index()); + } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { + safepoint.DefinePointerRegister(ToRegister(pointer)); } } + if (kind & Safepoint::kWithRegisters) { + // Register cp always contains a pointer to the context. + safepoint.DefinePointerRegister(cp); + } +} + + +void LCodeGen::RecordSafepoint(LPointerMap* pointers, + int deoptimization_index) { + RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); } void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, int deoptimization_index) { - const ZoneList* operands = pointers->operands(); - Safepoint safepoint = - safepoints_.DefineSafepointWithRegisters( - masm(), arguments, deoptimization_index); - for (int i = 0; i < operands->length(); i++) { - LOperand* pointer = operands->at(i); - if (pointer->IsStackSlot()) { - safepoint.DefinePointerSlot(pointer->index()); - } else if (pointer->IsRegister()) { - safepoint.DefinePointerRegister(ToRegister(pointer)); - } - } - // Register cp always contains a pointer to the context. - safepoint.DefinePointerRegister(cp); + RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, + deoptimization_index); } @@ -774,20 +777,8 @@ void LCodeGen::RecordSafepointWithRegistersAndDoubles( LPointerMap* pointers, int arguments, int deoptimization_index) { - const ZoneList* operands = pointers->operands(); - Safepoint safepoint = - safepoints_.DefineSafepointWithRegistersAndDoubles( - masm(), arguments, deoptimization_index); - for (int i = 0; i < operands->length(); i++) { - LOperand* pointer = operands->at(i); - if (pointer->IsStackSlot()) { - safepoint.DefinePointerSlot(pointer->index()); - } else if (pointer->IsRegister()) { - safepoint.DefinePointerRegister(ToRegister(pointer)); - } - } - // Register cp always contains a pointer to the context. - safepoint.DefinePointerRegister(cp); + RecordSafepoint(pointers, Safepoint::kWithRegistersAndDoubles, arguments, + deoptimization_index); } @@ -1080,7 +1071,7 @@ void LCodeGen::DoModI(LModI* instr) { __ bind(deferred->exit()); // If the result in r0 is a Smi, untag it, else deoptimize. - __ BranchOnNotSmi(result, &deoptimize); + __ JumpIfNotSmi(result, &deoptimize); __ SmiUntag(result); __ b(al, &done); @@ -1160,7 +1151,7 @@ void LCodeGen::DoDivI(LDivI* instr) { __ bind(deferred->exit()); // If the result in r0 is a Smi, untag it, else deoptimize. - __ BranchOnNotSmi(result, &deoptimize); + __ JumpIfNotSmi(result, &deoptimize); __ SmiUntag(result); __ b(&done); @@ -1216,7 +1207,7 @@ void LCodeGen::DoMulI(LMulI* instr) { __ b(ne, &done); if (instr->InputAt(1)->IsConstantOperand()) { if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) < 0) { - DeoptimizeIf(no_condition, instr->environment()); + DeoptimizeIf(kNoCondition, instr->environment()); } } else { // Test the non-zero operand for negative sign. @@ -1483,7 +1474,7 @@ void LCodeGen::DoBranch(LBranch* instr) { if (r.IsInteger32()) { Register reg = ToRegister(instr->InputAt(0)); __ cmp(reg, Operand(0)); - EmitBranch(true_block, false_block, nz); + EmitBranch(true_block, false_block, ne); } else if (r.IsDouble()) { DoubleRegister reg = ToDoubleRegister(instr->InputAt(0)); Register scratch = scratch0(); @@ -1541,7 +1532,7 @@ void LCodeGen::DoBranch(LBranch* instr) { __ CallStub(&stub); __ cmp(reg, Operand(0)); __ ldm(ia_w, sp, saved_regs); - EmitBranch(true_block, false_block, nz); + EmitBranch(true_block, false_block, ne); } } } @@ -1593,7 +1584,7 @@ void LCodeGen::DoGoto(LGoto* instr) { Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { - Condition cond = no_condition; + Condition cond = kNoCondition; switch (op) { case Token::EQ: case Token::EQ_STRICT: @@ -1730,18 +1721,62 @@ Condition LCodeGen::EmitIsObject(Register input, Register temp2, Label* is_not_object, Label* is_object) { - Abort("EmitIsObject unimplemented."); - return ne; + __ JumpIfSmi(input, is_not_object); + + __ LoadRoot(temp1, Heap::kNullValueRootIndex); + __ cmp(input, temp1); + __ b(eq, is_object); + + // Load map. + __ ldr(temp1, FieldMemOperand(input, HeapObject::kMapOffset)); + // Undetectable objects behave like undefined. + __ ldrb(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset)); + __ tst(temp2, Operand(1 << Map::kIsUndetectable)); + __ b(ne, is_not_object); + + // Load instance type and check that it is in object type range. + __ ldrb(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset)); + __ cmp(temp2, Operand(FIRST_JS_OBJECT_TYPE)); + __ b(lt, is_not_object); + __ cmp(temp2, Operand(LAST_JS_OBJECT_TYPE)); + return le; } void LCodeGen::DoIsObject(LIsObject* instr) { - Abort("DoIsObject unimplemented."); + Register reg = ToRegister(instr->InputAt(0)); + Register result = ToRegister(instr->result()); + Register temp = scratch0(); + Label is_false, is_true, done; + + Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true); + __ b(true_cond, &is_true); + + __ bind(&is_false); + __ LoadRoot(result, Heap::kFalseValueRootIndex); + __ b(&done); + + __ bind(&is_true); + __ LoadRoot(result, Heap::kTrueValueRootIndex); + + __ bind(&done); } void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { - Abort("DoIsObjectAndBranch unimplemented."); + Register reg = ToRegister(instr->InputAt(0)); + Register temp1 = ToRegister(instr->TempAt(0)); + Register temp2 = scratch0(); + + int true_block = chunk_->LookupDestination(instr->true_block_id()); + int false_block = chunk_->LookupDestination(instr->false_block_id()); + Label* true_label = chunk_->GetAssemblyLabel(true_block); + Label* false_label = chunk_->GetAssemblyLabel(false_block); + + Condition true_cond = + EmitIsObject(reg, temp1, temp2, false_label, true_label); + + EmitBranch(true_block, false_block, true_cond); } @@ -1956,7 +1991,16 @@ void LCodeGen::DoInstanceOf(LInstanceOf* instr) { void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { - Abort("DoInstanceOfAndBranch unimplemented."); + ASSERT(ToRegister(instr->InputAt(0)).is(r0)); // Object is in r0. + ASSERT(ToRegister(instr->InputAt(1)).is(r1)); // Function is in r1. + + int true_block = chunk_->LookupDestination(instr->true_block_id()); + int false_block = chunk_->LookupDestination(instr->false_block_id()); + + InstanceofStub stub(InstanceofStub::kArgsInRegisters); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + __ tst(r0, Operand(r0)); + EmitBranch(true_block, false_block, eq); } @@ -1989,7 +2033,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { ASSERT(result.is(r0)); // A Smi is not instance of anything. - __ BranchOnSmi(object, &false_result); + __ JumpIfSmi(object, &false_result); // This is the inlined call site instanceof cache. The two occurences of the // hole value will be patched to the last map/result pair generated by the @@ -2092,7 +2136,7 @@ static Condition ComputeCompareCondition(Token::Value op) { return ge; default: UNREACHABLE(); - return no_condition; + return kNoCondition; } } @@ -2151,8 +2195,26 @@ void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) { void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { Register value = ToRegister(instr->InputAt(0)); - __ mov(ip, Operand(Handle(instr->hydrogen()->cell()))); - __ str(value, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset)); + Register scratch = scratch0(); + + // Load the cell. + __ mov(scratch, Operand(Handle(instr->hydrogen()->cell()))); + + // If the cell we are storing to contains the hole it could have + // been deleted from the property dictionary. In that case, we need + // to update the property details in the property dictionary to mark + // it as no longer deleted. + if (instr->hydrogen()->check_hole_value()) { + Register scratch2 = ToRegister(instr->TempAt(0)); + __ ldr(scratch2, + FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ cmp(scratch2, ip); + DeoptimizeIf(eq, instr->environment()); + } + + // Store the value. + __ str(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); } @@ -2565,7 +2627,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { new DeferredMathAbsTaggedHeapNumber(this, instr); Register input = ToRegister(instr->InputAt(0)); // Smi check. - __ BranchOnNotSmi(input, deferred->entry()); + __ JumpIfNotSmi(input, deferred->entry()); // If smi, handle it directly. EmitIntegerMathAbs(instr); __ bind(deferred->exit()); @@ -3512,7 +3574,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, Label* false_label, Register input, Handle type_name) { - Condition final_branch_condition = no_condition; + Condition final_branch_condition = kNoCondition; Register scratch = scratch0(); if (type_name->Equals(Heap::number_symbol())) { __ tst(input, Operand(kSmiTagMask)); @@ -3597,7 +3659,7 @@ void LCodeGen::DoLazyBailout(LLazyBailout* instr) { void LCodeGen::DoDeoptimize(LDeoptimize* instr) { - DeoptimizeIf(no_condition, instr->environment()); + DeoptimizeIf(kNoCondition, instr->environment()); } diff --git a/deps/v8/src/arm/lithium-codegen-arm.h b/deps/v8/src/arm/lithium-codegen-arm.h index 3b2ad80c5f..27a72f29a0 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.h +++ b/deps/v8/src/arm/lithium-codegen-arm.h @@ -223,6 +223,10 @@ class LCodeGen BASE_EMBEDDED { void DoMathSqrt(LUnaryMathOperation* instr); // Support for recording safepoint and position information. + void RecordSafepoint(LPointerMap* pointers, + Safepoint::Kind kind, + int arguments, + int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index a78de986e7..66cfdca670 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -318,7 +318,7 @@ void MacroAssembler::SmiJumpTable(Register index, Vector targets) { CheckConstPool(true, true); add(pc, pc, Operand(index, LSL, - assembler::arm::Instr::kInstrSizeLog2 - kSmiTagSize)); + Instruction::kInstrSizeLog2 - kSmiTagSize)); BlockConstPoolBefore(pc_offset() + (targets.length() + 1) * kInstrSize); nop(); // Jump table alignment. for (int i = 0; i < targets.length(); i++) { @@ -369,12 +369,12 @@ void MacroAssembler::RecordWriteHelper(Register object, void MacroAssembler::InNewSpace(Register object, Register scratch, - Condition cc, + Condition cond, Label* branch) { - ASSERT(cc == eq || cc == ne); + ASSERT(cond == eq || cond == ne); and_(scratch, object, Operand(ExternalReference::new_space_mask())); cmp(scratch, Operand(ExternalReference::new_space_start())); - b(cc, branch); + b(cond, branch); } @@ -615,37 +615,24 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { void MacroAssembler::EnterExitFrame(bool save_doubles) { - // r0 is argc. - // Compute callee's stack pointer before making changes and save it as - // ip register so that it is restored as sp register on exit, thereby - // popping the args. - - // ip = sp + kPointerSize * #args; - add(ip, sp, Operand(r0, LSL, kPointerSizeLog2)); - - // Compute the argv pointer and keep it in a callee-saved register. - sub(r6, ip, Operand(kPointerSize)); - - // Prepare the stack to be aligned when calling into C. After this point there - // are 5 pushes before the call into C, so the stack needs to be aligned after - // 5 pushes. - int frame_alignment = ActivationFrameAlignment(); - int frame_alignment_mask = frame_alignment - 1; - if (frame_alignment != kPointerSize) { - // The following code needs to be more general if this assert does not hold. - ASSERT(frame_alignment == 2 * kPointerSize); - // With 5 pushes left the frame must be unaligned at this point. - mov(r7, Operand(Smi::FromInt(0))); - tst(sp, Operand((frame_alignment - kPointerSize) & frame_alignment_mask)); - push(r7, eq); // Push if aligned to make it unaligned. - } - - // Push in reverse order: caller_fp, sp_on_exit, and caller_pc. - stm(db_w, sp, fp.bit() | ip.bit() | lr.bit()); + // Compute the argv pointer in a callee-saved register. + add(r6, sp, Operand(r0, LSL, kPointerSizeLog2)); + sub(r6, r6, Operand(kPointerSize)); + + // Setup the frame structure on the stack. + ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); + ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); + ASSERT_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); + Push(lr, fp); mov(fp, Operand(sp)); // Setup new frame pointer. - + // Reserve room for saved entry sp and code object. + sub(sp, sp, Operand(2 * kPointerSize)); + if (FLAG_debug_code) { + mov(ip, Operand(0)); + str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); + } mov(ip, Operand(CodeObject())); - push(ip); // Accessed from ExitFrame::code_slot. + str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset)); // Save the frame pointer and the context in top. mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); @@ -659,25 +646,30 @@ void MacroAssembler::EnterExitFrame(bool save_doubles) { // Optionally save all double registers. if (save_doubles) { - // TODO(regis): Use vstrm instruction. - // The stack alignment code above made sp unaligned, so add space for one - // more double register and use aligned addresses. - ASSERT(kDoubleSize == frame_alignment); - // Mark the frame as containing doubles by pushing a non-valid return - // address, i.e. 0. - ASSERT(ExitFrameConstants::kMarkerOffset == -2 * kPointerSize); - mov(ip, Operand(0)); // Marker and alignment word. - push(ip); - int space = DwVfpRegister::kNumRegisters * kDoubleSize + kPointerSize; - sub(sp, sp, Operand(space)); + sub(sp, sp, Operand(DwVfpRegister::kNumRegisters * kDoubleSize)); + const int offset = -2 * kPointerSize; for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { DwVfpRegister reg = DwVfpRegister::from_code(i); - vstr(reg, sp, i * kDoubleSize + kPointerSize); + vstr(reg, fp, offset - ((i + 1) * kDoubleSize)); } - // Note that d0 will be accessible at fp - 2*kPointerSize - - // DwVfpRegister::kNumRegisters * kDoubleSize, since the code slot and the - // alignment word were pushed after the fp. + // Note that d0 will be accessible at + // fp - 2 * kPointerSize - DwVfpRegister::kNumRegisters * kDoubleSize, + // since the sp slot and code slot were pushed after the fp. + } + + // Reserve place for the return address and align the frame preparing for + // calling the runtime function. + const int frame_alignment = MacroAssembler::ActivationFrameAlignment(); + sub(sp, sp, Operand(kPointerSize)); + if (frame_alignment > 0) { + ASSERT(IsPowerOf2(frame_alignment)); + and_(sp, sp, Operand(-frame_alignment)); } + + // Set the exit frame sp value to point just before the return address + // location. + add(ip, sp, Operand(kPointerSize)); + str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); } @@ -715,12 +707,10 @@ int MacroAssembler::ActivationFrameAlignment() { void MacroAssembler::LeaveExitFrame(bool save_doubles) { // Optionally restore all double registers. if (save_doubles) { - // TODO(regis): Use vldrm instruction. for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { DwVfpRegister reg = DwVfpRegister::from_code(i); - // Register d15 is just below the marker. - const int offset = ExitFrameConstants::kMarkerOffset; - vldr(reg, fp, (i - DwVfpRegister::kNumRegisters) * kDoubleSize + offset); + const int offset = -2 * kPointerSize; + vldr(reg, fp, offset - ((i + 1) * kDoubleSize)); } } @@ -736,9 +726,12 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) { str(r3, MemOperand(ip)); #endif - // Pop the arguments, restore registers, and return. - mov(sp, Operand(fp)); // respect ABI stack constraint - ldm(ia, sp, fp.bit() | sp.bit() | pc.bit()); + // Tear down the exit frame, pop the arguments, and return. Callee-saved + // register r4 still holds argc. + mov(sp, Operand(fp)); + ldm(ia_w, sp, fp.bit() | lr.bit()); + add(sp, sp, Operand(r4, LSL, kPointerSizeLog2)); + mov(pc, lr); } @@ -933,7 +926,7 @@ void MacroAssembler::IsObjectJSStringType(Register object, ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); tst(scratch, Operand(kIsNotStringMask)); - b(nz, fail); + b(ne, fail); } @@ -1392,7 +1385,7 @@ void MacroAssembler::CheckMap(Register obj, Label* fail, bool is_heap_object) { if (!is_heap_object) { - BranchOnSmi(obj, fail); + JumpIfSmi(obj, fail); } ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); mov(ip, Operand(map)); @@ -1407,7 +1400,7 @@ void MacroAssembler::CheckMap(Register obj, Label* fail, bool is_heap_object) { if (!is_heap_object) { - BranchOnSmi(obj, fail); + JumpIfSmi(obj, fail); } ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); LoadRoot(ip, index); @@ -1421,7 +1414,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function, Register scratch, Label* miss) { // Check that the receiver isn't a smi. - BranchOnSmi(function, miss); + JumpIfSmi(function, miss); // Check that the function really is a function. Load map into result reg. CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE); @@ -1520,7 +1513,7 @@ void MacroAssembler::ObjectToDoubleVFPRegister(Register object, Label done; if ((flags & OBJECT_NOT_SMI) == 0) { Label not_smi; - BranchOnNotSmi(object, ¬_smi); + JumpIfNotSmi(object, ¬_smi); // Remove smi tag and convert to double. mov(scratch1, Operand(object, ASR, kSmiTagSize)); vmov(scratch3, scratch1); @@ -1813,9 +1806,9 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, } -void MacroAssembler::Assert(Condition cc, const char* msg) { +void MacroAssembler::Assert(Condition cond, const char* msg) { if (FLAG_debug_code) - Check(cc, msg); + Check(cond, msg); } @@ -1848,9 +1841,9 @@ void MacroAssembler::AssertFastElements(Register elements) { } -void MacroAssembler::Check(Condition cc, const char* msg) { +void MacroAssembler::Check(Condition cond, const char* msg) { Label L; - b(cc, &L); + b(cond, &L); Abort(msg); // will not return here bind(&L); @@ -1946,7 +1939,7 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); tst(reg1, Operand(kSmiTagMask)); tst(reg2, Operand(kSmiTagMask), eq); b(ne, on_not_both_smi); @@ -1956,7 +1949,7 @@ void MacroAssembler::JumpIfNotBothSmi(Register reg1, void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); tst(reg1, Operand(kSmiTagMask)); tst(reg2, Operand(kSmiTagMask), ne); b(eq, on_either_smi); @@ -1964,19 +1957,30 @@ void MacroAssembler::JumpIfEitherSmi(Register reg1, void MacroAssembler::AbortIfSmi(Register object) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); tst(object, Operand(kSmiTagMask)); Assert(ne, "Operand is a smi"); } void MacroAssembler::AbortIfNotSmi(Register object) { - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); tst(object, Operand(kSmiTagMask)); Assert(eq, "Operand is not smi"); } +void MacroAssembler::JumpIfNotHeapNumber(Register object, + Register heap_number_map, + Register scratch, + Label* on_not_heap_number) { + ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); + AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); + cmp(scratch, heap_number_map); + b(ne, on_not_heap_number); +} + + void MacroAssembler::JumpIfNonSmisNotBothSequentialAsciiStrings( Register first, Register second, @@ -2003,7 +2007,7 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first, Register scratch2, Label* failure) { // Check that neither is a smi. - ASSERT_EQ(0, kSmiTag); + STATIC_ASSERT(kSmiTag == 0); and_(scratch1, first, Operand(second)); tst(scratch1, Operand(kSmiTagMask)); b(eq, failure); diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 7392d36659..e2b1db807f 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -139,7 +139,7 @@ class MacroAssembler: public Assembler { // scratch can be object itself, but it will be clobbered. void InNewSpace(Register object, Register scratch, - Condition cc, // eq for new space, ne otherwise + Condition cond, // eq for new space, ne otherwise Label* branch); @@ -545,16 +545,6 @@ class MacroAssembler: public Assembler { } - inline void BranchOnSmi(Register value, Label* smi_label) { - tst(value, Operand(kSmiTagMask)); - b(eq, smi_label); - } - - inline void BranchOnNotSmi(Register value, Label* not_smi_label) { - tst(value, Operand(kSmiTagMask)); - b(ne, not_smi_label); - } - // Generates code for reporting that an illegal operation has // occurred. void IllegalOperation(int num_arguments); @@ -695,14 +685,14 @@ class MacroAssembler: public Assembler { // --------------------------------------------------------------------------- // Debugging - // Calls Abort(msg) if the condition cc is not satisfied. + // Calls Abort(msg) if the condition cond is not satisfied. // Use --debug_code to enable. - void Assert(Condition cc, const char* msg); + void Assert(Condition cond, const char* msg); void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index); void AssertFastElements(Register elements); // Like Assert(), but always enabled. - void Check(Condition cc, const char* msg); + void Check(Condition cond, const char* msg); // Print a message to stdout and abort execution. void Abort(const char* msg); @@ -719,6 +709,9 @@ class MacroAssembler: public Assembler { void SmiTag(Register reg, SBit s = LeaveCC) { add(reg, reg, Operand(reg), s); } + void SmiTag(Register dst, Register src, SBit s = LeaveCC) { + add(dst, src, Operand(src), s); + } // Try to convert int32 to smi. If the value is to large, preserve // the original value and jump to not_a_smi. Destroys scratch and @@ -733,7 +726,20 @@ class MacroAssembler: public Assembler { void SmiUntag(Register reg) { mov(reg, Operand(reg, ASR, kSmiTagSize)); } + void SmiUntag(Register dst, Register src) { + mov(dst, Operand(src, ASR, kSmiTagSize)); + } + // Jump the register contains a smi. + inline void JumpIfSmi(Register value, Label* smi_label) { + tst(value, Operand(kSmiTagMask)); + b(eq, smi_label); + } + // Jump if either of the registers contain a non-smi. + inline void JumpIfNotSmi(Register value, Label* not_smi_label) { + tst(value, Operand(kSmiTagMask)); + b(ne, not_smi_label); + } // Jump if either of the registers contain a non-smi. void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi); // Jump if either of the registers contain a smi. @@ -743,6 +749,14 @@ class MacroAssembler: public Assembler { void AbortIfSmi(Register object); void AbortIfNotSmi(Register object); + // --------------------------------------------------------------------------- + // HeapNumber utilities + + void JumpIfNotHeapNumber(Register object, + Register heap_number_map, + Register scratch, + Label* on_not_heap_number); + // --------------------------------------------------------------------------- // String utilities diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index 138e8f8955..296b2b4130 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -40,14 +40,8 @@ #if defined(USE_SIMULATOR) // Only build the simulator if not compiling for real ARM hardware. -namespace assembler { -namespace arm { - -using ::v8::internal::Object; -using ::v8::internal::PrintF; -using ::v8::internal::OS; -using ::v8::internal::ReadLine; -using ::v8::internal::DeleteArray; +namespace v8 { +namespace internal { // This macro provides a platform independent use of sscanf. The reason for // SScanF not being implemented in a platform independent way through @@ -62,14 +56,13 @@ class Debugger { explicit Debugger(Simulator* sim); ~Debugger(); - void Stop(Instr* instr); + void Stop(Instruction* instr); void Debug(); private: - static const instr_t kBreakpointInstr = - ((AL << 28) | (7 << 25) | (1 << 24) | break_point); - static const instr_t kNopInstr = - ((AL << 28) | (13 << 21)); + static const Instr kBreakpointInstr = + (al | (7*B25) | (1*B24) | kBreakpoint); + static const Instr kNopInstr = (al | (13*B21)); Simulator* sim_; @@ -80,8 +73,8 @@ class Debugger { bool GetVFPDoubleValue(const char* desc, double* value); // Set or delete a breakpoint. Returns true if successful. - bool SetBreakpoint(Instr* breakpc); - bool DeleteBreakpoint(Instr* breakpc); + bool SetBreakpoint(Instruction* breakpc); + bool DeleteBreakpoint(Instruction* breakpc); // Undo and redo all breakpoints. This is needed to bracket disassembly and // execution to skip past breakpoints when run from the debugger. @@ -112,12 +105,12 @@ static void InitializeCoverage() { } -void Debugger::Stop(Instr* instr) { +void Debugger::Stop(Instruction* instr) { // Get the stop code. - uint32_t code = instr->SvcField() & kStopCodeMask; + uint32_t code = instr->SvcValue() & kStopCodeMask; // Retrieve the encoded address, which comes just after this stop. char** msg_address = - reinterpret_cast(sim_->get_pc() + Instr::kInstrSize); + reinterpret_cast(sim_->get_pc() + Instruction::kInstrSize); char* msg = *msg_address; ASSERT(msg != NULL); @@ -133,9 +126,9 @@ void Debugger::Stop(Instr* instr) { } // Overwrite the instruction and address with nops. instr->SetInstructionBits(kNopInstr); - reinterpret_cast(msg_address)->SetInstructionBits(kNopInstr); + reinterpret_cast(msg_address)->SetInstructionBits(kNopInstr); } - sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize); + sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize); } #else // ndef GENERATED_CODE_COVERAGE @@ -144,11 +137,12 @@ static void InitializeCoverage() { } -void Debugger::Stop(Instr* instr) { +void Debugger::Stop(Instruction* instr) { // Get the stop code. - uint32_t code = instr->SvcField() & kStopCodeMask; + uint32_t code = instr->SvcValue() & kStopCodeMask; // Retrieve the encoded address, which comes just after this stop. - char* msg = *reinterpret_cast(sim_->get_pc() + Instr::kInstrSize); + char* msg = *reinterpret_cast(sim_->get_pc() + + Instruction::kInstrSize); // Update this stop description. if (sim_->isWatchedStop(code) && !sim_->watched_stops[code].desc) { sim_->watched_stops[code].desc = msg; @@ -159,7 +153,7 @@ void Debugger::Stop(Instr* instr) { } else { PrintF("Simulator hit %s\n", msg); } - sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize); + sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize); Debug(); } #endif @@ -217,7 +211,7 @@ bool Debugger::GetVFPDoubleValue(const char* desc, double* value) { } -bool Debugger::SetBreakpoint(Instr* breakpc) { +bool Debugger::SetBreakpoint(Instruction* breakpc) { // Check if a breakpoint can be set. If not return without any side-effects. if (sim_->break_pc_ != NULL) { return false; @@ -232,7 +226,7 @@ bool Debugger::SetBreakpoint(Instr* breakpc) { } -bool Debugger::DeleteBreakpoint(Instr* breakpc) { +bool Debugger::DeleteBreakpoint(Instruction* breakpc) { if (sim_->break_pc_ != NULL) { sim_->break_pc_->SetInstructionBits(sim_->break_instr_); } @@ -304,10 +298,10 @@ void Debugger::Debug() { "%" XSTR(ARG_SIZE) "s", cmd, arg1, arg2); if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { - sim_->InstructionDecode(reinterpret_cast(sim_->get_pc())); + sim_->InstructionDecode(reinterpret_cast(sim_->get_pc())); } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { // Execute the one instruction we broke at with breakpoints disabled. - sim_->InstructionDecode(reinterpret_cast(sim_->get_pc())); + sim_->InstructionDecode(reinterpret_cast(sim_->get_pc())); // Leave the debugger shell. done = true; } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { @@ -402,20 +396,20 @@ void Debugger::Debug() { if (argc == 1) { cur = reinterpret_cast(sim_->get_pc()); - end = cur + (10 * Instr::kInstrSize); + end = cur + (10 * Instruction::kInstrSize); } else if (argc == 2) { int32_t value; if (GetValue(arg1, &value)) { cur = reinterpret_cast(sim_->get_pc()); // Disassemble instructions. - end = cur + (value * Instr::kInstrSize); + end = cur + (value * Instruction::kInstrSize); } } else { int32_t value1; int32_t value2; if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { cur = reinterpret_cast(value1); - end = cur + (value2 * Instr::kInstrSize); + end = cur + (value2 * Instruction::kInstrSize); } } @@ -433,7 +427,7 @@ void Debugger::Debug() { if (argc == 2) { int32_t value; if (GetValue(arg1, &value)) { - if (!SetBreakpoint(reinterpret_cast(value))) { + if (!SetBreakpoint(reinterpret_cast(value))) { PrintF("setting breakpoint failed\n"); } } else { @@ -458,10 +452,10 @@ void Debugger::Debug() { PrintF("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_); } else if (strcmp(cmd, "stop") == 0) { int32_t value; - intptr_t stop_pc = sim_->get_pc() - 2 * Instr::kInstrSize; - Instr* stop_instr = reinterpret_cast(stop_pc); - Instr* msg_address = - reinterpret_cast(stop_pc + Instr::kInstrSize); + intptr_t stop_pc = sim_->get_pc() - 2 * Instruction::kInstrSize; + Instruction* stop_instr = reinterpret_cast(stop_pc); + Instruction* msg_address = + reinterpret_cast(stop_pc + Instruction::kInstrSize); if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) { // Remove the current stop. if (sim_->isStopInstruction(stop_instr)) { @@ -646,7 +640,7 @@ void Simulator::FlushOnePage(intptr_t start, int size) { } -void Simulator::CheckICache(Instr* instr) { +void Simulator::CheckICache(Instruction* instr) { intptr_t address = reinterpret_cast(instr); void* page = reinterpret_cast(address & (~CachePage::kPageMask)); void* line = reinterpret_cast(address & (~CachePage::kLineMask)); @@ -659,7 +653,7 @@ void Simulator::CheckICache(Instr* instr) { // Check that the data in memory matches the contents of the I-cache. CHECK(memcmp(reinterpret_cast(instr), cache_page->CachedData(offset), - Instr::kInstrSize) == 0); + Instruction::kInstrSize) == 0); } else { // Cache miss. Load memory into the cache. memcpy(cached_line, line, CachePage::kLineLength); @@ -752,12 +746,12 @@ class Redirection { public: Redirection(void* external_function, bool fp_return) : external_function_(external_function), - swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected), + swi_instruction_(al | (0xf*B24) | kCallRtRedirected), fp_return_(fp_return), next_(list_) { Simulator::current()-> FlushICache(reinterpret_cast(&swi_instruction_), - Instr::kInstrSize); + Instruction::kInstrSize); list_ = this; } @@ -776,7 +770,7 @@ class Redirection { return new Redirection(external_function, fp_return); } - static Redirection* FromSwiInstruction(Instr* swi_instruction) { + static Redirection* FromSwiInstruction(Instruction* swi_instruction) { char* addr_of_swi = reinterpret_cast(swi_instruction); char* addr_of_redirection = addr_of_swi - OFFSET_OF(Redirection, swi_instruction_); @@ -835,7 +829,7 @@ int32_t Simulator::get_register(int reg) const { // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949 if (reg >= num_registers) return 0; // End stupid code. - return registers_[reg] + ((reg == pc) ? Instr::kPCReadOffset : 0); + return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0); } @@ -1001,7 +995,7 @@ void Simulator::TrashCallerSaveRegisters() { // targets that don't support unaligned loads and stores. -int Simulator::ReadW(int32_t addr, Instr* instr) { +int Simulator::ReadW(int32_t addr, Instruction* instr) { #if V8_TARGET_CAN_READ_UNALIGNED intptr_t* ptr = reinterpret_cast(addr); return *ptr; @@ -1017,7 +1011,7 @@ int Simulator::ReadW(int32_t addr, Instr* instr) { } -void Simulator::WriteW(int32_t addr, int value, Instr* instr) { +void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { #if V8_TARGET_CAN_READ_UNALIGNED intptr_t* ptr = reinterpret_cast(addr); *ptr = value; @@ -1034,7 +1028,7 @@ void Simulator::WriteW(int32_t addr, int value, Instr* instr) { } -uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) { +uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { #if V8_TARGET_CAN_READ_UNALIGNED uint16_t* ptr = reinterpret_cast(addr); return *ptr; @@ -1050,7 +1044,7 @@ uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) { } -int16_t Simulator::ReadH(int32_t addr, Instr* instr) { +int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { #if V8_TARGET_CAN_READ_UNALIGNED int16_t* ptr = reinterpret_cast(addr); return *ptr; @@ -1066,7 +1060,7 @@ int16_t Simulator::ReadH(int32_t addr, Instr* instr) { } -void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) { +void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { #if V8_TARGET_CAN_READ_UNALIGNED uint16_t* ptr = reinterpret_cast(addr); *ptr = value; @@ -1083,7 +1077,7 @@ void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) { } -void Simulator::WriteH(int32_t addr, int16_t value, Instr* instr) { +void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { #if V8_TARGET_CAN_READ_UNALIGNED int16_t* ptr = reinterpret_cast(addr); *ptr = value; @@ -1168,7 +1162,7 @@ uintptr_t Simulator::StackLimit() const { // Unsupported instructions use Format to print an error and stop execution. -void Simulator::Format(Instr* instr, const char* format) { +void Simulator::Format(Instruction* instr, const char* format) { PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n", reinterpret_cast(instr), format); UNIMPLEMENTED(); @@ -1177,23 +1171,23 @@ void Simulator::Format(Instr* instr, const char* format) { // Checks if the current instruction should be executed based on its // condition bits. -bool Simulator::ConditionallyExecute(Instr* instr) { +bool Simulator::ConditionallyExecute(Instruction* instr) { switch (instr->ConditionField()) { - case EQ: return z_flag_; - case NE: return !z_flag_; - case CS: return c_flag_; - case CC: return !c_flag_; - case MI: return n_flag_; - case PL: return !n_flag_; - case VS: return v_flag_; - case VC: return !v_flag_; - case HI: return c_flag_ && !z_flag_; - case LS: return !c_flag_ || z_flag_; - case GE: return n_flag_ == v_flag_; - case LT: return n_flag_ != v_flag_; - case GT: return !z_flag_ && (n_flag_ == v_flag_); - case LE: return z_flag_ || (n_flag_ != v_flag_); - case AL: return true; + case eq: return z_flag_; + case ne: return !z_flag_; + case cs: return c_flag_; + case cc: return !c_flag_; + case mi: return n_flag_; + case pl: return !n_flag_; + case vs: return v_flag_; + case vc: return !v_flag_; + case hi: return c_flag_ && !z_flag_; + case ls: return !c_flag_ || z_flag_; + case ge: return n_flag_ == v_flag_; + case lt: return n_flag_ != v_flag_; + case gt: return !z_flag_ && (n_flag_ == v_flag_); + case le: return z_flag_ || (n_flag_ != v_flag_); + case al: return true; default: UNREACHABLE(); } return false; @@ -1295,10 +1289,10 @@ void Simulator::Copy_FPSCR_to_APSR() { // Addressing Mode 1 - Data-processing operands: // Get the value based on the shifter_operand with register. -int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) { - Shift shift = instr->ShiftField(); - int shift_amount = instr->ShiftAmountField(); - int32_t result = get_register(instr->RmField()); +int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) { + ShiftOp shift = instr->ShiftField(); + int shift_amount = instr->ShiftAmountValue(); + int32_t result = get_register(instr->RmValue()); if (instr->Bit(4) == 0) { // by immediate if ((shift == ROR) && (shift_amount == 0)) { @@ -1362,7 +1356,7 @@ int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) { } } else { // by register - int rs = instr->RsField(); + int rs = instr->RsValue(); shift_amount = get_register(rs) &0xff; switch (shift) { case ASR: { @@ -1439,9 +1433,9 @@ int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) { // Addressing Mode 1 - Data-processing operands: // Get the value based on the shifter_operand with immediate. -int32_t Simulator::GetImm(Instr* instr, bool* carry_out) { - int rotate = instr->RotateField() * 2; - int immed8 = instr->Immed8Field(); +int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) { + int rotate = instr->RotateValue() * 2; + int immed8 = instr->Immed8Value(); int imm = (immed8 >> rotate) | (immed8 << (32 - rotate)); *carry_out = (rotate == 0) ? c_flag_ : (imm < 0); return imm; @@ -1461,36 +1455,32 @@ static int count_bits(int bit_vector) { // Addressing Mode 4 - Load and Store Multiple -void Simulator::HandleRList(Instr* instr, bool load) { - int rn = instr->RnField(); +void Simulator::HandleRList(Instruction* instr, bool load) { + int rn = instr->RnValue(); int32_t rn_val = get_register(rn); - int rlist = instr->RlistField(); + int rlist = instr->RlistValue(); int num_regs = count_bits(rlist); intptr_t start_address = 0; intptr_t end_address = 0; switch (instr->PUField()) { - case 0: { - // Print("da"); + case da_x: { UNIMPLEMENTED(); break; } - case 1: { - // Print("ia"); + case ia_x: { start_address = rn_val; end_address = rn_val + (num_regs * 4) - 4; rn_val = rn_val + (num_regs * 4); break; } - case 2: { - // Print("db"); + case db_x: { start_address = rn_val - (num_regs * 4); end_address = rn_val - 4; rn_val = start_address; break; } - case 3: { - // Print("ib"); + case ib_x: { start_address = rn_val + 4; end_address = rn_val + (num_regs * 4); rn_val = end_address; @@ -1541,10 +1531,10 @@ typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, // Software interrupt instructions are used by the simulator to call into the // C-based V8 runtime. -void Simulator::SoftwareInterrupt(Instr* instr) { - int svc = instr->SvcField(); +void Simulator::SoftwareInterrupt(Instruction* instr) { + int svc = instr->SvcValue(); switch (svc) { - case call_rt_redirected: { + case kCallRtRedirected: { // Check if stack is aligned. Error if not aligned is reported below to // include information on the function called. bool stack_aligned = @@ -1611,7 +1601,7 @@ void Simulator::SoftwareInterrupt(Instr* instr) { set_pc(get_register(lr)); break; } - case break_point: { + case kBreakpoint: { Debugger dbg(this); dbg.Debug(); break; @@ -1629,7 +1619,7 @@ void Simulator::SoftwareInterrupt(Instr* instr) { Debugger dbg(this); dbg.Stop(instr); } else { - set_pc(get_pc() + 2 * Instr::kInstrSize); + set_pc(get_pc() + 2 * Instruction::kInstrSize); } } else { // This is not a valid svc code. @@ -1642,8 +1632,8 @@ void Simulator::SoftwareInterrupt(Instr* instr) { // Stop helper functions. -bool Simulator::isStopInstruction(Instr* instr) { - return (instr->Bits(27, 24) == 0xF) && (instr->SvcField() >= stop); +bool Simulator::isStopInstruction(Instruction* instr) { + return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode); } @@ -1717,17 +1707,17 @@ void Simulator::PrintStopInfo(uint32_t code) { // Instruction types 0 and 1 are both rolled into one function because they // only differ in the handling of the shifter_operand. -void Simulator::DecodeType01(Instr* instr) { - int type = instr->TypeField(); +void Simulator::DecodeType01(Instruction* instr) { + int type = instr->TypeValue(); if ((type == 0) && instr->IsSpecialType0()) { // multiply instruction or extra loads and stores if (instr->Bits(7, 4) == 9) { if (instr->Bit(24) == 0) { // Raw field decoding here. Multiply instructions have their Rd in // funny places. - int rn = instr->RnField(); - int rm = instr->RmField(); - int rs = instr->RsField(); + int rn = instr->RnValue(); + int rm = instr->RmValue(); + int rs = instr->RsValue(); int32_t rs_val = get_register(rs); int32_t rm_val = get_register(rm); if (instr->Bit(23) == 0) { @@ -1761,7 +1751,7 @@ void Simulator::DecodeType01(Instr* instr) { // at a very detailed level.) // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm"); int rd_hi = rn; // Remap the rn field to the RdHi register. - int rd_lo = instr->RdField(); + int rd_lo = instr->RdValue(); int32_t hi_res = 0; int32_t lo_res = 0; if (instr->Bit(22) == 1) { @@ -1789,15 +1779,15 @@ void Simulator::DecodeType01(Instr* instr) { } } else { // extra load/store instructions - int rd = instr->RdField(); - int rn = instr->RnField(); + int rd = instr->RdValue(); + int rn = instr->RnValue(); int32_t rn_val = get_register(rn); int32_t addr = 0; if (instr->Bit(22) == 0) { - int rm = instr->RmField(); + int rm = instr->RmValue(); int32_t rm_val = get_register(rm); switch (instr->PUField()) { - case 0: { + case da_x: { // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm"); ASSERT(!instr->HasW()); addr = rn_val; @@ -1805,7 +1795,7 @@ void Simulator::DecodeType01(Instr* instr) { set_register(rn, rn_val); break; } - case 1: { + case ia_x: { // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm"); ASSERT(!instr->HasW()); addr = rn_val; @@ -1813,7 +1803,7 @@ void Simulator::DecodeType01(Instr* instr) { set_register(rn, rn_val); break; } - case 2: { + case db_x: { // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w"); rn_val -= rm_val; addr = rn_val; @@ -1822,7 +1812,7 @@ void Simulator::DecodeType01(Instr* instr) { } break; } - case 3: { + case ib_x: { // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w"); rn_val += rm_val; addr = rn_val; @@ -1838,9 +1828,9 @@ void Simulator::DecodeType01(Instr* instr) { } } } else { - int32_t imm_val = (instr->ImmedHField() << 4) | instr->ImmedLField(); + int32_t imm_val = (instr->ImmedHValue() << 4) | instr->ImmedLValue(); switch (instr->PUField()) { - case 0: { + case da_x: { // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8"); ASSERT(!instr->HasW()); addr = rn_val; @@ -1848,7 +1838,7 @@ void Simulator::DecodeType01(Instr* instr) { set_register(rn, rn_val); break; } - case 1: { + case ia_x: { // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8"); ASSERT(!instr->HasW()); addr = rn_val; @@ -1856,7 +1846,7 @@ void Simulator::DecodeType01(Instr* instr) { set_register(rn, rn_val); break; } - case 2: { + case db_x: { // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w"); rn_val -= imm_val; addr = rn_val; @@ -1865,7 +1855,7 @@ void Simulator::DecodeType01(Instr* instr) { } break; } - case 3: { + case ib_x: { // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w"); rn_val += imm_val; addr = rn_val; @@ -1922,15 +1912,15 @@ void Simulator::DecodeType01(Instr* instr) { } } else if ((type == 0) && instr->IsMiscType0()) { if (instr->Bits(22, 21) == 1) { - int rm = instr->RmField(); - switch (instr->Bits(7, 4)) { + int rm = instr->RmValue(); + switch (instr->BitField(7, 4)) { case BX: set_pc(get_register(rm)); break; case BLX: { uint32_t old_pc = get_pc(); set_pc(get_register(rm)); - set_register(lr, old_pc + Instr::kInstrSize); + set_register(lr, old_pc + Instruction::kInstrSize); break; } case BKPT: { @@ -1943,9 +1933,9 @@ void Simulator::DecodeType01(Instr* instr) { UNIMPLEMENTED(); } } else if (instr->Bits(22, 21) == 3) { - int rm = instr->RmField(); - int rd = instr->RdField(); - switch (instr->Bits(7, 4)) { + int rm = instr->RmValue(); + int rd = instr->RdValue(); + switch (instr->BitField(7, 4)) { case CLZ: { uint32_t bits = get_register(rm); int leading_zeros = 0; @@ -1968,15 +1958,15 @@ void Simulator::DecodeType01(Instr* instr) { UNIMPLEMENTED(); } } else { - int rd = instr->RdField(); - int rn = instr->RnField(); + int rd = instr->RdValue(); + int rn = instr->RnValue(); int32_t rn_val = get_register(rn); int32_t shifter_operand = 0; bool shifter_carry_out = 0; if (type == 0) { shifter_operand = GetShiftRm(instr, &shifter_carry_out); } else { - ASSERT(instr->TypeField() == 1); + ASSERT(instr->TypeValue() == 1); shifter_operand = GetImm(instr, &shifter_carry_out); } int32_t alu_out; @@ -2072,7 +2062,7 @@ void Simulator::DecodeType01(Instr* instr) { SetCFlag(shifter_carry_out); } else { // Format(instr, "movw'cond 'rd, 'imm"). - alu_out = instr->ImmedMovwMovtField(); + alu_out = instr->ImmedMovwMovtValue(); set_register(rd, alu_out); } break; @@ -2104,7 +2094,7 @@ void Simulator::DecodeType01(Instr* instr) { } else { // Format(instr, "movt'cond 'rd, 'imm"). alu_out = (get_register(rd) & 0xffff) | - (instr->ImmedMovwMovtField() << 16); + (instr->ImmedMovwMovtValue() << 16); set_register(rd, alu_out); } break; @@ -2183,14 +2173,14 @@ void Simulator::DecodeType01(Instr* instr) { } -void Simulator::DecodeType2(Instr* instr) { - int rd = instr->RdField(); - int rn = instr->RnField(); +void Simulator::DecodeType2(Instruction* instr) { + int rd = instr->RdValue(); + int rn = instr->RnValue(); int32_t rn_val = get_register(rn); - int32_t im_val = instr->Offset12Field(); + int32_t im_val = instr->Offset12Value(); int32_t addr = 0; switch (instr->PUField()) { - case 0: { + case da_x: { // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12"); ASSERT(!instr->HasW()); addr = rn_val; @@ -2198,7 +2188,7 @@ void Simulator::DecodeType2(Instr* instr) { set_register(rn, rn_val); break; } - case 1: { + case ia_x: { // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12"); ASSERT(!instr->HasW()); addr = rn_val; @@ -2206,7 +2196,7 @@ void Simulator::DecodeType2(Instr* instr) { set_register(rn, rn_val); break; } - case 2: { + case db_x: { // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w"); rn_val -= im_val; addr = rn_val; @@ -2215,7 +2205,7 @@ void Simulator::DecodeType2(Instr* instr) { } break; } - case 3: { + case ib_x: { // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w"); rn_val += im_val; addr = rn_val; @@ -2247,21 +2237,21 @@ void Simulator::DecodeType2(Instr* instr) { } -void Simulator::DecodeType3(Instr* instr) { - int rd = instr->RdField(); - int rn = instr->RnField(); +void Simulator::DecodeType3(Instruction* instr) { + int rd = instr->RdValue(); + int rn = instr->RnValue(); int32_t rn_val = get_register(rn); bool shifter_carry_out = 0; int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out); int32_t addr = 0; switch (instr->PUField()) { - case 0: { + case da_x: { ASSERT(!instr->HasW()); Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm"); UNIMPLEMENTED(); break; } - case 1: { + case ia_x: { if (instr->HasW()) { ASSERT(instr->Bits(5, 4) == 0x1); @@ -2270,7 +2260,7 @@ void Simulator::DecodeType3(Instr* instr) { int32_t sat_val = (1 << sat_pos) - 1; int32_t shift = instr->Bits(11, 7); int32_t shift_type = instr->Bit(6); - int32_t rm_val = get_register(instr->RmField()); + int32_t rm_val = get_register(instr->RmValue()); if (shift_type == 0) { // LSL rm_val <<= shift; } else { // ASR @@ -2295,7 +2285,7 @@ void Simulator::DecodeType3(Instr* instr) { } break; } - case 2: { + case db_x: { // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w"); addr = rn_val - shifter_operand; if (instr->HasW()) { @@ -2303,7 +2293,7 @@ void Simulator::DecodeType3(Instr* instr) { } break; } - case 3: { + case ib_x: { if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) { uint32_t widthminus1 = static_cast(instr->Bits(20, 16)); uint32_t lsbit = static_cast(instr->Bits(11, 7)); @@ -2312,16 +2302,16 @@ void Simulator::DecodeType3(Instr* instr) { if (instr->Bit(22)) { // ubfx - unsigned bitfield extract. uint32_t rm_val = - static_cast(get_register(instr->RmField())); + static_cast(get_register(instr->RmValue())); uint32_t extr_val = rm_val << (31 - msbit); extr_val = extr_val >> (31 - widthminus1); - set_register(instr->RdField(), extr_val); + set_register(instr->RdValue(), extr_val); } else { // sbfx - signed bitfield extract. - int32_t rm_val = get_register(instr->RmField()); + int32_t rm_val = get_register(instr->RmValue()); int32_t extr_val = rm_val << (31 - msbit); extr_val = extr_val >> (31 - widthminus1); - set_register(instr->RdField(), extr_val); + set_register(instr->RdValue(), extr_val); } } else { UNREACHABLE(); @@ -2333,18 +2323,18 @@ void Simulator::DecodeType3(Instr* instr) { if (msbit >= lsbit) { // bfc or bfi - bitfield clear/insert. uint32_t rd_val = - static_cast(get_register(instr->RdField())); + static_cast(get_register(instr->RdValue())); uint32_t bitcount = msbit - lsbit + 1; uint32_t mask = (1 << bitcount) - 1; rd_val &= ~(mask << lsbit); - if (instr->RmField() != 15) { + if (instr->RmValue() != 15) { // bfi - bitfield insert. uint32_t rm_val = - static_cast(get_register(instr->RmField())); + static_cast(get_register(instr->RmValue())); rm_val &= mask; rd_val |= rm_val << lsbit; } - set_register(instr->RdField(), rd_val); + set_register(instr->RdValue(), rd_val); } else { UNREACHABLE(); } @@ -2381,7 +2371,7 @@ void Simulator::DecodeType3(Instr* instr) { } -void Simulator::DecodeType4(Instr* instr) { +void Simulator::DecodeType4(Instruction* instr) { ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode if (instr->HasL()) { // Format(instr, "ldm'cond'pu 'rn'w, 'rlist"); @@ -2393,24 +2383,24 @@ void Simulator::DecodeType4(Instr* instr) { } -void Simulator::DecodeType5(Instr* instr) { +void Simulator::DecodeType5(Instruction* instr) { // Format(instr, "b'l'cond 'target"); - int off = (instr->SImmed24Field() << 2); + int off = (instr->SImmed24Value() << 2); intptr_t pc_address = get_pc(); if (instr->HasLink()) { - set_register(lr, pc_address + Instr::kInstrSize); + set_register(lr, pc_address + Instruction::kInstrSize); } int pc_reg = get_register(pc); set_pc(pc_reg + off); } -void Simulator::DecodeType6(Instr* instr) { +void Simulator::DecodeType6(Instruction* instr) { DecodeType6CoprocessorIns(instr); } -void Simulator::DecodeType7(Instr* instr) { +void Simulator::DecodeType7(Instruction* instr) { if (instr->Bit(24) == 1) { SoftwareInterrupt(instr); } else { @@ -2419,7 +2409,7 @@ void Simulator::DecodeType7(Instr* instr) { } -// void Simulator::DecodeTypeVFP(Instr* instr) +// void Simulator::DecodeTypeVFP(Instruction* instr) // The Following ARMv7 VFPv instructions are currently supported. // vmov :Sn = Rt // vmov :Rt = Sn @@ -2432,47 +2422,47 @@ void Simulator::DecodeType7(Instr* instr) { // vcmp(Dd, Dm) // vmrs // Dd = vsqrt(Dm) -void Simulator::DecodeTypeVFP(Instr* instr) { - ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) ); +void Simulator::DecodeTypeVFP(Instruction* instr) { + ASSERT((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) ); ASSERT(instr->Bits(11, 9) == 0x5); // Obtain double precision register codes. - int vm = instr->VFPMRegCode(kDoublePrecision); - int vd = instr->VFPDRegCode(kDoublePrecision); - int vn = instr->VFPNRegCode(kDoublePrecision); + int vm = instr->VFPMRegValue(kDoublePrecision); + int vd = instr->VFPDRegValue(kDoublePrecision); + int vn = instr->VFPNRegValue(kDoublePrecision); if (instr->Bit(4) == 0) { - if (instr->Opc1Field() == 0x7) { + if (instr->Opc1Value() == 0x7) { // Other data processing instructions - if ((instr->Opc2Field() == 0x0) && (instr->Opc3Field() == 0x1)) { + if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) { // vmov register to register. - if (instr->SzField() == 0x1) { - int m = instr->VFPMRegCode(kDoublePrecision); - int d = instr->VFPDRegCode(kDoublePrecision); + if (instr->SzValue() == 0x1) { + int m = instr->VFPMRegValue(kDoublePrecision); + int d = instr->VFPDRegValue(kDoublePrecision); set_d_register_from_double(d, get_double_from_d_register(m)); } else { - int m = instr->VFPMRegCode(kSinglePrecision); - int d = instr->VFPDRegCode(kSinglePrecision); + int m = instr->VFPMRegValue(kSinglePrecision); + int d = instr->VFPDRegValue(kSinglePrecision); set_s_register_from_float(d, get_float_from_s_register(m)); } - } else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) { + } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) { DecodeVCVTBetweenDoubleAndSingle(instr); - } else if ((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) { + } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) { DecodeVCVTBetweenFloatingPointAndInteger(instr); - } else if (((instr->Opc2Field() >> 1) == 0x6) && - (instr->Opc3Field() & 0x1)) { + } else if (((instr->Opc2Value() >> 1) == 0x6) && + (instr->Opc3Value() & 0x1)) { DecodeVCVTBetweenFloatingPointAndInteger(instr); - } else if (((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && - (instr->Opc3Field() & 0x1)) { + } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) && + (instr->Opc3Value() & 0x1)) { DecodeVCMP(instr); - } else if (((instr->Opc2Field() == 0x1)) && (instr->Opc3Field() == 0x3)) { + } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) { // vsqrt double dm_value = get_double_from_d_register(vm); double dd_value = sqrt(dm_value); set_d_register_from_double(vd, dd_value); - } else if (instr->Opc3Field() == 0x0) { + } else if (instr->Opc3Value() == 0x0) { // vmov immediate. - if (instr->SzField() == 0x1) { + if (instr->SzValue() == 0x1) { set_d_register_from_double(vd, instr->DoubleImmedVmov()); } else { UNREACHABLE(); // Not used by v8. @@ -2480,12 +2470,12 @@ void Simulator::DecodeTypeVFP(Instr* instr) { } else { UNREACHABLE(); // Not used by V8. } - } else if (instr->Opc1Field() == 0x3) { - if (instr->SzField() != 0x1) { + } else if (instr->Opc1Value() == 0x3) { + if (instr->SzValue() != 0x1) { UNREACHABLE(); // Not used by V8. } - if (instr->Opc3Field() & 0x1) { + if (instr->Opc3Value() & 0x1) { // vsub double dn_value = get_double_from_d_register(vn); double dm_value = get_double_from_d_register(vm); @@ -2498,9 +2488,9 @@ void Simulator::DecodeTypeVFP(Instr* instr) { double dd_value = dn_value + dm_value; set_d_register_from_double(vd, dd_value); } - } else if ((instr->Opc1Field() == 0x2) && !(instr->Opc3Field() & 0x1)) { + } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) { // vmul - if (instr->SzField() != 0x1) { + if (instr->SzValue() != 0x1) { UNREACHABLE(); // Not used by V8. } @@ -2508,9 +2498,9 @@ void Simulator::DecodeTypeVFP(Instr* instr) { double dm_value = get_double_from_d_register(vm); double dd_value = dn_value * dm_value; set_d_register_from_double(vd, dd_value); - } else if ((instr->Opc1Field() == 0x4) && !(instr->Opc3Field() & 0x1)) { + } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) { // vdiv - if (instr->SzField() != 0x1) { + if (instr->SzValue() != 0x1) { UNREACHABLE(); // Not used by V8. } @@ -2522,15 +2512,15 @@ void Simulator::DecodeTypeVFP(Instr* instr) { UNIMPLEMENTED(); // Not used by V8. } } else { - if ((instr->VCField() == 0x0) && - (instr->VAField() == 0x0)) { + if ((instr->VCValue() == 0x0) && + (instr->VAValue() == 0x0)) { DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr); - } else if ((instr->VLField() == 0x1) && - (instr->VCField() == 0x0) && - (instr->VAField() == 0x7) && + } else if ((instr->VLValue() == 0x1) && + (instr->VCValue() == 0x0) && + (instr->VAValue() == 0x7) && (instr->Bits(19, 16) == 0x1)) { // vmrs - uint32_t rt = instr->RtField(); + uint32_t rt = instr->RtValue(); if (rt == 0xF) { Copy_FPSCR_to_APSR(); } else { @@ -2547,12 +2537,12 @@ void Simulator::DecodeTypeVFP(Instr* instr) { (FPSCR_rounding_mode_ << 22); set_register(rt, fpscr); } - } else if ((instr->VLField() == 0x0) && - (instr->VCField() == 0x0) && - (instr->VAField() == 0x7) && + } else if ((instr->VLValue() == 0x0) && + (instr->VCValue() == 0x0) && + (instr->VAValue() == 0x7) && (instr->Bits(19, 16) == 0x1)) { // vmsr - uint32_t rt = instr->RtField(); + uint32_t rt = instr->RtValue(); if (rt == pc) { UNREACHABLE(); } else { @@ -2576,13 +2566,14 @@ void Simulator::DecodeTypeVFP(Instr* instr) { } -void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) { - ASSERT((instr->Bit(4) == 1) && (instr->VCField() == 0x0) && - (instr->VAField() == 0x0)); +void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters( + Instruction* instr) { + ASSERT((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) && + (instr->VAValue() == 0x0)); - int t = instr->RtField(); - int n = instr->VFPNRegCode(kSinglePrecision); - bool to_arm_register = (instr->VLField() == 0x1); + int t = instr->RtValue(); + int n = instr->VFPNRegValue(kSinglePrecision); + bool to_arm_register = (instr->VLValue() == 0x1); if (to_arm_register) { int32_t int_value = get_sinteger_from_s_register(n); @@ -2594,27 +2585,27 @@ void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) { } -void Simulator::DecodeVCMP(Instr* instr) { - ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); - ASSERT(((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && - (instr->Opc3Field() & 0x1)); +void Simulator::DecodeVCMP(Instruction* instr) { + ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7)); + ASSERT(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) && + (instr->Opc3Value() & 0x1)); // Comparison. VFPRegPrecision precision = kSinglePrecision; - if (instr->SzField() == 1) { + if (instr->SzValue() == 1) { precision = kDoublePrecision; } - int d = instr->VFPDRegCode(precision); + int d = instr->VFPDRegValue(precision); int m = 0; - if (instr->Opc2Field() == 0x4) { - m = instr->VFPMRegCode(precision); + if (instr->Opc2Value() == 0x4) { + m = instr->VFPMRegValue(precision); } if (precision == kDoublePrecision) { double dd_value = get_double_from_d_register(d); double dm_value = 0.0; - if (instr->Opc2Field() == 0x4) { + if (instr->Opc2Value() == 0x4) { dm_value = get_double_from_d_register(m); } @@ -2632,19 +2623,19 @@ void Simulator::DecodeVCMP(Instr* instr) { } -void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) { - ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); - ASSERT((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)); +void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) { + ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7)); + ASSERT((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)); VFPRegPrecision dst_precision = kDoublePrecision; VFPRegPrecision src_precision = kSinglePrecision; - if (instr->SzField() == 1) { + if (instr->SzValue() == 1) { dst_precision = kSinglePrecision; src_precision = kDoublePrecision; } - int dst = instr->VFPDRegCode(dst_precision); - int src = instr->VFPMRegCode(src_precision); + int dst = instr->VFPDRegValue(dst_precision); + int src = instr->VFPMRegValue(src_precision); if (dst_precision == kSinglePrecision) { double val = get_double_from_d_register(src); @@ -2656,16 +2647,16 @@ void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) { } -void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { - ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); - ASSERT(((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) || - (((instr->Opc2Field() >> 1) == 0x6) && (instr->Opc3Field() & 0x1))); +void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) { + ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7)); + ASSERT(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) || + (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1))); // Conversion between floating-point and integer. bool to_integer = (instr->Bit(18) == 1); VFPRegPrecision src_precision = kSinglePrecision; - if (instr->SzField() == 1) { + if (instr->SzValue() == 1) { src_precision = kDoublePrecision; } @@ -2682,8 +2673,8 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { mode = RZ; } - int dst = instr->VFPDRegCode(kSinglePrecision); - int src = instr->VFPMRegCode(src_precision); + int dst = instr->VFPDRegValue(kSinglePrecision); + int src = instr->VFPMRegValue(src_precision); int32_t kMaxInt = v8::internal::kMaxInt; int32_t kMinInt = v8::internal::kMinInt; switch (mode) { @@ -2739,8 +2730,8 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { } else { bool unsigned_integer = (instr->Bit(7) == 0); - int dst = instr->VFPDRegCode(src_precision); - int src = instr->VFPMRegCode(kSinglePrecision); + int dst = instr->VFPDRegValue(src_precision); + int src = instr->VFPMRegValue(kSinglePrecision); int val = get_sinteger_from_s_register(src); @@ -2763,24 +2754,24 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { } -// void Simulator::DecodeType6CoprocessorIns(Instr* instr) +// void Simulator::DecodeType6CoprocessorIns(Instruction* instr) // Decode Type 6 coprocessor instructions. // Dm = vmov(Rt, Rt2) // = vmov(Dm) // Ddst = MEM(Rbase + 4*offset). // MEM(Rbase + 4*offset) = Dsrc. -void Simulator::DecodeType6CoprocessorIns(Instr* instr) { - ASSERT((instr->TypeField() == 6)); +void Simulator::DecodeType6CoprocessorIns(Instruction* instr) { + ASSERT((instr->TypeValue() == 6)); - if (instr->CoprocessorField() == 0xA) { - switch (instr->OpcodeField()) { + if (instr->CoprocessorValue() == 0xA) { + switch (instr->OpcodeValue()) { case 0x8: case 0xA: case 0xC: case 0xE: { // Load and store single precision float to memory. - int rn = instr->RnField(); - int vd = instr->VFPDRegCode(kSinglePrecision); - int offset = instr->Immed8Field(); + int rn = instr->RnValue(); + int vd = instr->VFPDRegValue(kSinglePrecision); + int offset = instr->Immed8Value(); if (!instr->HasU()) { offset = -offset; } @@ -2799,16 +2790,16 @@ void Simulator::DecodeType6CoprocessorIns(Instr* instr) { UNIMPLEMENTED(); // Not used by V8. break; } - } else if (instr->CoprocessorField() == 0xB) { - switch (instr->OpcodeField()) { + } else if (instr->CoprocessorValue() == 0xB) { + switch (instr->OpcodeValue()) { case 0x2: // Load and store double to two GP registers if (instr->Bits(7, 4) != 0x1) { UNIMPLEMENTED(); // Not used by V8. } else { - int rt = instr->RtField(); - int rn = instr->RnField(); - int vm = instr->VmField(); + int rt = instr->RtValue(); + int rn = instr->RnValue(); + int vm = instr->VmValue(); if (instr->HasL()) { int32_t rt_int_value = get_sinteger_from_s_register(2*vm); int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1); @@ -2826,9 +2817,9 @@ void Simulator::DecodeType6CoprocessorIns(Instr* instr) { break; case 0x8: case 0xC: { // Load and store double to memory. - int rn = instr->RnField(); - int vd = instr->VdField(); - int offset = instr->Immed8Field(); + int rn = instr->RnValue(); + int vd = instr->VdValue(); + int offset = instr->Immed8Value(); if (!instr->HasU()) { offset = -offset; } @@ -2855,7 +2846,7 @@ void Simulator::DecodeType6CoprocessorIns(Instr* instr) { // Executes the current instruction. -void Simulator::InstructionDecode(Instr* instr) { +void Simulator::InstructionDecode(Instruction* instr) { if (v8::internal::FLAG_check_icache) { CheckICache(instr); } @@ -2869,10 +2860,10 @@ void Simulator::InstructionDecode(Instr* instr) { reinterpret_cast(instr)); PrintF(" 0x%08x %s\n", reinterpret_cast(instr), buffer.start()); } - if (instr->ConditionField() == special_condition) { + if (instr->ConditionField() == kSpecialCondition) { UNIMPLEMENTED(); } else if (ConditionallyExecute(instr)) { - switch (instr->TypeField()) { + switch (instr->TypeValue()) { case 0: case 1: { DecodeType01(instr); @@ -2910,10 +2901,11 @@ void Simulator::InstructionDecode(Instr* instr) { // If the instruction is a non taken conditional stop, we need to skip the // inlined message address. } else if (instr->IsStop()) { - set_pc(get_pc() + 2 * Instr::kInstrSize); + set_pc(get_pc() + 2 * Instruction::kInstrSize); } if (!pc_modified_) { - set_register(pc, reinterpret_cast(instr) + Instr::kInstrSize); + set_register(pc, reinterpret_cast(instr) + + Instruction::kInstrSize); } } @@ -2927,7 +2919,7 @@ void Simulator::Execute() { // Fast version of the dispatch loop without checking whether the simulator // should be stopping at a particular executed instruction. while (program_counter != end_sim_pc) { - Instr* instr = reinterpret_cast(program_counter); + Instruction* instr = reinterpret_cast(program_counter); icount_++; InstructionDecode(instr); program_counter = get_pc(); @@ -2936,7 +2928,7 @@ void Simulator::Execute() { // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when // we reach the particular instuction count. while (program_counter != end_sim_pc) { - Instr* instr = reinterpret_cast(program_counter); + Instruction* instr = reinterpret_cast(program_counter); icount_++; if (icount_ == ::v8::internal::FLAG_stop_sim_at) { Debugger dbg(this); @@ -3057,7 +3049,7 @@ uintptr_t Simulator::PopAddress() { return address; } -} } // namespace assembler::arm +} } // namespace v8::internal #endif // USE_SIMULATOR diff --git a/deps/v8/src/arm/simulator-arm.h b/deps/v8/src/arm/simulator-arm.h index 7bfe76ac3b..be44766d54 100644 --- a/deps/v8/src/arm/simulator-arm.h +++ b/deps/v8/src/arm/simulator-arm.h @@ -80,8 +80,8 @@ class SimulatorStack : public v8::internal::AllStatic { #include "constants-arm.h" #include "hashmap.h" -namespace assembler { -namespace arm { +namespace v8 { +namespace internal { class CachePage { public: @@ -203,11 +203,11 @@ class Simulator { }; // Unsupported instructions use Format to print an error and stop execution. - void Format(Instr* instr, const char* format); + void Format(Instruction* instr, const char* format); // Checks if the current instruction should be executed based on its // condition bits. - bool ConditionallyExecute(Instr* instr); + bool ConditionallyExecute(Instruction* instr); // Helper functions to set the conditional flags in the architecture state. void SetNZFlags(int32_t val); @@ -225,13 +225,13 @@ class Simulator { void Copy_FPSCR_to_APSR(); // Helper functions to decode common "addressing" modes - int32_t GetShiftRm(Instr* instr, bool* carry_out); - int32_t GetImm(Instr* instr, bool* carry_out); - void HandleRList(Instr* instr, bool load); - void SoftwareInterrupt(Instr* instr); + int32_t GetShiftRm(Instruction* instr, bool* carry_out); + int32_t GetImm(Instruction* instr, bool* carry_out); + void HandleRList(Instruction* instr, bool load); + void SoftwareInterrupt(Instruction* instr); // Stop helper functions. - inline bool isStopInstruction(Instr* instr); + inline bool isStopInstruction(Instruction* instr); inline bool isWatchedStop(uint32_t bkpt_code); inline bool isEnabledStop(uint32_t bkpt_code); inline void EnableStop(uint32_t bkpt_code); @@ -245,41 +245,42 @@ class Simulator { inline void WriteB(int32_t addr, uint8_t value); inline void WriteB(int32_t addr, int8_t value); - inline uint16_t ReadHU(int32_t addr, Instr* instr); - inline int16_t ReadH(int32_t addr, Instr* instr); + inline uint16_t ReadHU(int32_t addr, Instruction* instr); + inline int16_t ReadH(int32_t addr, Instruction* instr); // Note: Overloaded on the sign of the value. - inline void WriteH(int32_t addr, uint16_t value, Instr* instr); - inline void WriteH(int32_t addr, int16_t value, Instr* instr); + inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); + inline void WriteH(int32_t addr, int16_t value, Instruction* instr); - inline int ReadW(int32_t addr, Instr* instr); - inline void WriteW(int32_t addr, int value, Instr* instr); + inline int ReadW(int32_t addr, Instruction* instr); + inline void WriteW(int32_t addr, int value, Instruction* instr); int32_t* ReadDW(int32_t addr); void WriteDW(int32_t addr, int32_t value1, int32_t value2); // Executing is handled based on the instruction type. - void DecodeType01(Instr* instr); // both type 0 and type 1 rolled into one - void DecodeType2(Instr* instr); - void DecodeType3(Instr* instr); - void DecodeType4(Instr* instr); - void DecodeType5(Instr* instr); - void DecodeType6(Instr* instr); - void DecodeType7(Instr* instr); + // Both type 0 and type 1 rolled into one. + void DecodeType01(Instruction* instr); + void DecodeType2(Instruction* instr); + void DecodeType3(Instruction* instr); + void DecodeType4(Instruction* instr); + void DecodeType5(Instruction* instr); + void DecodeType6(Instruction* instr); + void DecodeType7(Instruction* instr); // Support for VFP. - void DecodeTypeVFP(Instr* instr); - void DecodeType6CoprocessorIns(Instr* instr); + void DecodeTypeVFP(Instruction* instr); + void DecodeType6CoprocessorIns(Instruction* instr); - void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr); - void DecodeVCMP(Instr* instr); - void DecodeVCVTBetweenDoubleAndSingle(Instr* instr); - void DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr); + void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction* instr); + void DecodeVCMP(Instruction* instr); + void DecodeVCVTBetweenDoubleAndSingle(Instruction* instr); + void DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr); // Executes one instruction. - void InstructionDecode(Instr* instr); + void InstructionDecode(Instruction* instr); // ICache. - static void CheckICache(Instr* instr); + static void CheckICache(Instruction* instr); static void FlushOnePage(intptr_t start, int size); static CachePage* GetCachePage(void* page); @@ -330,8 +331,8 @@ class Simulator { static v8::internal::HashMap* i_cache_; // Registered breakpoints. - Instr* break_pc_; - instr_t break_instr_; + Instruction* break_pc_; + Instr break_instr_; // A stop is watched if its code is less than kNumOfWatchedStops. // Only watched stops support enabling/disabling and the counter feature. @@ -344,27 +345,22 @@ class Simulator { // instruction, if bit 31 of watched_stops[code].count is unset. // The value watched_stops[code].count & ~(1 << 31) indicates how many times // the breakpoint was hit or gone through. - struct StopCoundAndDesc { + struct StopCountAndDesc { uint32_t count; char* desc; }; - StopCoundAndDesc watched_stops[kNumOfWatchedStops]; + StopCountAndDesc watched_stops[kNumOfWatchedStops]; }; -} } // namespace assembler::arm - - -namespace v8 { -namespace internal { // When running with the simulator transition into simulated execution at this // point. #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ - reinterpret_cast(assembler::arm::Simulator::current()->Call( \ + reinterpret_cast(Simulator::current()->Call( \ FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ - assembler::arm::Simulator::current()->Call( \ + Simulator::current()->Call( \ FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6) #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ @@ -380,16 +376,16 @@ namespace internal { class SimulatorStack : public v8::internal::AllStatic { public: static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) { - return assembler::arm::Simulator::current()->StackLimit(); + return Simulator::current()->StackLimit(); } static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { - assembler::arm::Simulator* sim = assembler::arm::Simulator::current(); + Simulator* sim = Simulator::current(); return sim->PushAddress(try_catch_address); } static inline void UnregisterCTryCatch() { - assembler::arm::Simulator::current()->PopAddress(); + Simulator::current()->PopAddress(); } }; diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index ce1d854481..1e99e60694 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -370,27 +370,31 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, Register receiver, Register scratch1, Register scratch2, - Label* miss) { + Label* miss, + bool support_wrappers) { Label check_wrapper; // Check if the object is a string leaving the instance type in the // scratch1 register. - GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper); + GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, + support_wrappers ? &check_wrapper : miss); // Load length directly from the string. __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset)); __ Ret(); - // Check if the object is a JSValue wrapper. - __ bind(&check_wrapper); - __ cmp(scratch1, Operand(JS_VALUE_TYPE)); - __ b(ne, miss); + if (support_wrappers) { + // Check if the object is a JSValue wrapper. + __ bind(&check_wrapper); + __ cmp(scratch1, Operand(JS_VALUE_TYPE)); + __ b(ne, miss); - // Unwrap the value and check if the wrapped value is a string. - __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset)); - GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss); - __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset)); - __ Ret(); + // Unwrap the value and check if the wrapped value is a string. + __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset)); + GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss); + __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset)); + __ Ret(); + } } @@ -521,7 +525,7 @@ static void GenerateCallFunction(MacroAssembler* masm, // ----------------------------------- // Check that the function really is a function. - __ BranchOnSmi(r1, miss); + __ JumpIfSmi(r1, miss); __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); __ b(ne, miss); @@ -660,7 +664,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); // Check that the receiver isn't a smi. - __ BranchOnSmi(receiver, miss); + __ JumpIfSmi(receiver, miss); CallOptimization optimization(lookup); @@ -1194,17 +1198,16 @@ void StubCompiler::GenerateLoadConstant(JSObject* object, } -bool StubCompiler::GenerateLoadCallback(JSObject* object, - JSObject* holder, - Register receiver, - Register name_reg, - Register scratch1, - Register scratch2, - Register scratch3, - AccessorInfo* callback, - String* name, - Label* miss, - Failure** failure) { +MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, + JSObject* holder, + Register receiver, + Register name_reg, + Register scratch1, + Register scratch2, + Register scratch3, + AccessorInfo* callback, + String* name, + Label* miss) { // Check that the receiver isn't a smi. __ tst(receiver, Operand(kSmiTagMask)); __ b(eq, miss); @@ -1225,7 +1228,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); __ TailCallExternalReference(load_callback_property, 5, 1); - return true; + return Heap::undefined_value(); // Success. } @@ -1243,7 +1246,7 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); // Check that the receiver isn't a smi. - __ BranchOnSmi(receiver, miss); + __ JumpIfSmi(receiver, miss); // So far the most popular follow ups for interceptor loads are FIELD // and CALLBACKS, so inline only them, other cases may be added @@ -1511,7 +1514,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); // Check that the receiver isn't a smi. - __ BranchOnSmi(receiver, &miss); + __ JumpIfSmi(receiver, &miss); // Check that the maps haven't changed. CheckPrototypes(JSObject::cast(object), receiver, @@ -1565,7 +1568,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex)); // Check for a smi. - __ BranchOnNotSmi(r4, &with_write_barrier); + __ JumpIfNotSmi(r4, &with_write_barrier); __ bind(&exit); __ Drop(argc + 1); __ Ret(); @@ -1672,7 +1675,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); // Check that the receiver isn't a smi. - __ BranchOnSmi(receiver, &miss); + __ JumpIfSmi(receiver, &miss); // Check that the maps haven't changed. CheckPrototypes(JSObject::cast(object), @@ -2009,7 +2012,7 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object, __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); STATIC_ASSERT(kSmiTag == 0); - __ BranchOnSmi(r1, &miss); + __ JumpIfSmi(r1, &miss); CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name, &miss); @@ -2168,7 +2171,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, // Check if the argument is a smi. Label not_smi; STATIC_ASSERT(kSmiTag == 0); - __ BranchOnNotSmi(r0, ¬_smi); + __ JumpIfNotSmi(r0, ¬_smi); // Do bitwise not or do nothing depending on the sign of the // argument. @@ -2646,9 +2649,18 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, __ cmp(r3, Operand(Handle(object->map()))); __ b(ne, &miss); + // Check that the value in the cell is not the hole. If it is, this + // cell could have been deleted and reintroducing the global needs + // to update the property details in the property dictionary of the + // global object. We bail out to the runtime system to do that. + __ mov(r4, Operand(Handle(cell))); + __ LoadRoot(r5, Heap::kTheHoleValueRootIndex); + __ ldr(r6, FieldMemOperand(r4, JSGlobalPropertyCell::kValueOffset)); + __ cmp(r5, r6); + __ b(eq, &miss); + // Store the value in the cell. - __ mov(r2, Operand(Handle(cell))); - __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); + __ str(r0, FieldMemOperand(r4, JSGlobalPropertyCell::kValueOffset)); __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3); __ Ret(); @@ -2738,12 +2750,11 @@ MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, // ----------------------------------- Label miss; - Failure* failure = Failure::InternalError(); - bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1, r4, - callback, name, &miss, &failure); - if (!success) { + MaybeObject* result = GenerateLoadCallback(object, holder, r0, r2, r3, r1, r4, + callback, name, &miss); + if (result->IsFailure()) { miss.Unuse(); - return failure; + return result; } __ bind(&miss); @@ -2890,12 +2901,11 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( __ cmp(r0, Operand(Handle(name))); __ b(ne, &miss); - Failure* failure = Failure::InternalError(); - bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3, r4, - callback, name, &miss, &failure); - if (!success) { + MaybeObject* result = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3, + r4, callback, name, &miss); + if (result->IsFailure()) { miss.Unuse(); - return failure; + return result; } __ bind(&miss); @@ -2995,7 +3005,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { __ cmp(r0, Operand(Handle(name))); __ b(ne, &miss); - GenerateLoadStringLength(masm(), r1, r2, r3, &miss); + GenerateLoadStringLength(masm(), r1, r2, r3, &miss, true); __ bind(&miss); __ DecrementCounter(&Counters::keyed_load_string_length, 1, r2, r3); @@ -3361,10 +3371,10 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( Register receiver = r1; // Check that the object isn't a smi - __ BranchOnSmi(receiver, &slow); + __ JumpIfSmi(receiver, &slow); // Check that the key is a smi. - __ BranchOnNotSmi(key, &slow); + __ JumpIfNotSmi(key, &slow); // Check that the object is a JS object. Load map into r2. __ CompareObjectType(receiver, r2, r3, FIRST_JS_OBJECT_TYPE); @@ -3645,7 +3655,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( // r3 mostly holds the elements array or the destination external array. // Check that the object isn't a smi. - __ BranchOnSmi(receiver, &slow); + __ JumpIfSmi(receiver, &slow); // Check that the object is a JS object. Load map into r3. __ CompareObjectType(receiver, r3, r4, FIRST_JS_OBJECT_TYPE); @@ -3658,7 +3668,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( __ b(ne, &slow); // Check that the key is a smi. - __ BranchOnNotSmi(key, &slow); + __ JumpIfNotSmi(key, &slow); // Check that the elements array is the appropriate type of ExternalArray. __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); @@ -3678,7 +3688,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( // runtime for all other kinds of values. // r3: external array. // r4: key (integer). - __ BranchOnNotSmi(value, &check_heap_number); + __ JumpIfNotSmi(value, &check_heap_number); __ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value. __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 4ef61e4b14..a29aa064b8 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -185,7 +185,6 @@ class RelocInfo BASE_EMBEDDED { DEBUG_BREAK, // Code target for the debugger statement. CODE_TARGET, // Code target which is not any of the above. EMBEDDED_OBJECT, - GLOBAL_PROPERTY_CELL, // Everything after runtime_entry (inclusive) is not GC'ed. @@ -203,7 +202,7 @@ class RelocInfo BASE_EMBEDDED { NUMBER_OF_MODES, // must be no greater than 14 - see RelocInfoWriter NONE, // never recorded LAST_CODE_ENUM = CODE_TARGET, - LAST_GCED_ENUM = EMBEDDED_OBJECT + LAST_GCED_ENUM = GLOBAL_PROPERTY_CELL }; diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index fa01be016c..80927a88fd 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -239,12 +239,19 @@ void ObjectLiteral::CalculateEmitStore() { HashMap* table; void* key; uint32_t index; + Smi* smi_key_location; if (handle->IsSymbol()) { Handle name(String::cast(*handle)); - ASSERT(!name->AsArrayIndex(&index)); - key = name.location(); - hash = name->Hash(); - table = &properties; + if (name->AsArrayIndex(&index)) { + smi_key_location = Smi::FromInt(index); + key = &smi_key_location; + hash = index; + table = &elements; + } else { + key = name.location(); + hash = name->Hash(); + table = &properties; + } } else if (handle->ToArrayIndex(&index)) { key = handle.location(); hash = index; @@ -514,6 +521,8 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { if (key()->IsPropertyName()) { if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_ArrayLength)) { is_array_length_ = true; + } else if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_StringLength)) { + is_string_length_ = true; } else if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_FunctionPrototype)) { is_function_prototype_ = true; @@ -570,7 +579,14 @@ static bool CanCallWithoutIC(Handle target, int arity) { bool Call::ComputeTarget(Handle type, Handle name) { - holder_ = Handle::null(); + if (check_type_ == RECEIVER_MAP_CHECK) { + // For primitive checks the holder is set up to point to the + // corresponding prototype object, i.e. one step of the algorithm + // below has been already performed. + // For non-primitive checks we clear it to allow computing targets + // for polymorphic calls. + holder_ = Handle::null(); + } while (true) { LookupResult lookup; type->LookupInDescriptors(NULL, *name, &lookup); @@ -640,27 +656,20 @@ void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle) { map = receiver_types_->at(0); } else { ASSERT(check_type_ != RECEIVER_MAP_CHECK); - map = Handle( - oracle->GetPrototypeForPrimitiveCheck(check_type_)->map()); + holder_ = Handle( + oracle->GetPrototypeForPrimitiveCheck(check_type_)); + map = Handle(holder_->map()); } is_monomorphic_ = ComputeTarget(map, name); } } -void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) { - TypeInfo left = oracle->BinaryType(this, TypeFeedbackOracle::LEFT); - TypeInfo right = oracle->BinaryType(this, TypeFeedbackOracle::RIGHT); - is_smi_only_ = left.IsSmi() && right.IsSmi(); -} - - void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) { - TypeInfo left = oracle->CompareType(this, TypeFeedbackOracle::LEFT); - TypeInfo right = oracle->CompareType(this, TypeFeedbackOracle::RIGHT); - if (left.IsSmi() && right.IsSmi()) { + TypeInfo info = oracle->CompareType(this); + if (info.IsSmi()) { compare_type_ = SMI_ONLY; - } else if (left.IsNonPrimitive() && right.IsNonPrimitive()) { + } else if (info.IsNonPrimitive()) { compare_type_ = OBJECT_ONLY; } else { ASSERT(compare_type_ == NONE); diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index a897e886dd..2aee5d72a4 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -1205,9 +1205,10 @@ class Property: public Expression { key_(key), pos_(pos), type_(type), - is_monomorphic_(false), receiver_types_(NULL), + is_monomorphic_(false), is_array_length_(false), + is_string_length_(false), is_function_prototype_(false), is_arguments_access_(false) { } @@ -1221,6 +1222,7 @@ class Property: public Expression { int position() const { return pos_; } bool is_synthetic() const { return type_ == SYNTHETIC; } + bool IsStringLength() const { return is_string_length_; } bool IsFunctionPrototype() const { return is_function_prototype_; } // Marks that this is actually an argument rewritten to a keyed property @@ -1249,11 +1251,12 @@ class Property: public Expression { int pos_; Type type_; - bool is_monomorphic_; ZoneMapList* receiver_types_; - bool is_array_length_; - bool is_function_prototype_; - bool is_arguments_access_; + bool is_monomorphic_ : 1; + bool is_array_length_ : 1; + bool is_string_length_ : 1; + bool is_function_prototype_ : 1; + bool is_arguments_access_ : 1; Handle monomorphic_receiver_type_; // Dummy property used during preparsing. @@ -1395,7 +1398,7 @@ class BinaryOperation: public Expression { Expression* left, Expression* right, int pos) - : op_(op), left_(left), right_(right), pos_(pos), is_smi_only_(false) { + : op_(op), left_(left), right_(right), pos_(pos) { ASSERT(Token::IsBinaryOp(op)); right_id_ = (op == Token::AND || op == Token::OR) ? static_cast(GetNextId()) @@ -1416,10 +1419,6 @@ class BinaryOperation: public Expression { Expression* right() const { return right_; } int position() const { return pos_; } - // Type feedback information. - void RecordTypeFeedback(TypeFeedbackOracle* oracle); - bool IsSmiOnly() const { return is_smi_only_; } - // Bailout support. int RightId() const { return right_id_; } @@ -1428,7 +1427,6 @@ class BinaryOperation: public Expression { Expression* left_; Expression* right_; int pos_; - bool is_smi_only_; // The short-circuit logical operations have an AST ID for their // right-hand subexpression. int right_id_; diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index cae1a9a288..16a186fe6e 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -1805,9 +1805,8 @@ Genesis::Genesis(Handle global_object, AddToWeakGlobalContextList(*global_context_); Top::set_context(*global_context_); i::Counters::contexts_created_by_snapshot.Increment(); - result_ = global_context_; JSFunction* empty_function = - JSFunction::cast(result_->function_map()->prototype()); + JSFunction::cast(global_context_->function_map()->prototype()); empty_function_ = Handle(empty_function); Handle inner_global; Handle global_proxy = diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 7c2c2bca3d..58dd439d25 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -1228,7 +1228,12 @@ static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) { static void Generate_LoadIC_StringLength(MacroAssembler* masm) { - LoadIC::GenerateStringLength(masm); + LoadIC::GenerateStringLength(masm, false); +} + + +static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) { + LoadIC::GenerateStringLength(masm, true); } diff --git a/deps/v8/src/builtins.h b/deps/v8/src/builtins.h index 39f35469ff..88d31c7612 100644 --- a/deps/v8/src/builtins.h +++ b/deps/v8/src/builtins.h @@ -86,6 +86,7 @@ enum BuiltinExtraArguments { V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \ V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \ V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \ + V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC) \ V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \ V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \ \ diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index bc7516a3fe..06cffed491 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -273,21 +273,20 @@ class FastNewClosureStub : public CodeStub { class FastNewContextStub : public CodeStub { public: - // We want no more than 64 different stubs. - static const int kMaximumSlots = Context::MIN_CONTEXT_SLOTS + 63; + static const int kMaximumSlots = 64; explicit FastNewContextStub(int slots) : slots_(slots) { - ASSERT(slots_ >= Context::MIN_CONTEXT_SLOTS && slots_ <= kMaximumSlots); + ASSERT(slots_ > 0 && slots <= kMaximumSlots); } void Generate(MacroAssembler* masm); private: - virtual const char* GetName() { return "FastNewContextStub"; } - virtual Major MajorKey() { return FastNewContext; } - virtual int MinorKey() { return slots_; } - int slots_; + + const char* GetName() { return "FastNewContextStub"; } + Major MajorKey() { return FastNewContext; } + int MinorKey() { return slots_; } }; @@ -600,8 +599,7 @@ class CEntryStub : public CodeStub { Label* throw_termination_exception, Label* throw_out_of_memory_exception, bool do_gc, - bool always_allocate_scope, - int alignment_skew = 0); + bool always_allocate_scope); void GenerateThrowTOS(MacroAssembler* masm); void GenerateThrowUncatchable(MacroAssembler* masm, UncatchableExceptionType type); diff --git a/deps/v8/src/deoptimizer.h b/deps/v8/src/deoptimizer.h index f9bf280ea8..69aa497f8c 100644 --- a/deps/v8/src/deoptimizer.h +++ b/deps/v8/src/deoptimizer.h @@ -128,14 +128,17 @@ class Deoptimizer : public Malloced { static void VisitAllOptimizedFunctions(OptimizedFunctionVisitor* visitor); - // Given the relocation info of a call to the stack check stub, patch the - // code so as to go unconditionally to the on-stack replacement builtin - // instead. - static void PatchStackCheckCode(RelocInfo* rinfo, Code* replacement_code); - - // Given the relocation info of a call to the on-stack replacement - // builtin, patch the code back to the original stack check code. - static void RevertStackCheckCode(RelocInfo* rinfo, Code* check_code); + // Patch all stack guard checks in the unoptimized code to + // unconditionally call replacement_code. + static void PatchStackCheckCode(Code* unoptimized_code, + Code* check_code, + Code* replacement_code); + + // Change all patched stack guard checks in the unoptimized code + // back to a normal stack guard check. + static void RevertStackCheckCode(Code* unoptimized_code, + Code* check_code, + Code* replacement_code); ~Deoptimizer(); diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index 7f28ff175a..24ea8dde2d 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -695,7 +695,7 @@ void OptimizedFrame::Summarize(List* frames) { ASSERT(frames->length() == 0); ASSERT(is_optimized()); - int deopt_index = AstNode::kNoNumber; + int deopt_index = Safepoint::kNoDeoptimizationIndex; DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index); // BUG(3243555): Since we don't have a lazy-deopt registered at @@ -793,7 +793,7 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData( SafepointEntry safepoint_entry = code->GetSafepointEntry(pc()); *deopt_index = safepoint_entry.deoptimization_index(); - ASSERT(*deopt_index != AstNode::kNoNumber); + ASSERT(*deopt_index != Safepoint::kNoDeoptimizationIndex); return DeoptimizationInputData::cast(code->deoptimization_data()); } @@ -803,7 +803,7 @@ void OptimizedFrame::GetFunctions(List* functions) { ASSERT(functions->length() == 0); ASSERT(is_optimized()); - int deopt_index = AstNode::kNoNumber; + int deopt_index = Safepoint::kNoDeoptimizationIndex; DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index); TranslationIterator it(data->TranslationByteArray(), diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 32d751a392..7c7f3d269e 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -35,6 +35,7 @@ #include "debug.h" #include "heap-profiler.h" #include "global-handles.h" +#include "liveobjectlist-inl.h" #include "mark-compact.h" #include "natives.h" #include "objects-visiting.h" @@ -400,6 +401,8 @@ void Heap::GarbageCollectionPrologue() { #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) ReportStatisticsBeforeGC(); #endif + + LiveObjectList::GCPrologue(); } intptr_t Heap::SizeOfObjects() { @@ -412,6 +415,7 @@ intptr_t Heap::SizeOfObjects() { } void Heap::GarbageCollectionEpilogue() { + LiveObjectList::GCEpilogue(); #ifdef DEBUG allow_allocation(true); ZapFromSpace(); @@ -1066,6 +1070,8 @@ void Heap::Scavenge() { UpdateNewSpaceReferencesInExternalStringTable( &UpdateNewSpaceReferenceInExternalStringTableEntry); + LiveObjectList::UpdateReferencesForScavengeGC(); + ASSERT(new_space_front == new_space_.top()); // Set age mark. diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index d1a4782a01..2f8b6e263d 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/deps/v8/src/hydrogen-instructions.cc @@ -490,7 +490,7 @@ void HInstruction::InsertAfter(HInstruction* previous) { #ifdef DEBUG -void HInstruction::Verify() const { +void HInstruction::Verify() { // Verify that input operands are defined before use. HBasicBlock* cur_block = block(); for (int i = 0; i < OperandCount(); ++i) { @@ -517,6 +517,11 @@ void HInstruction::Verify() const { if (HasSideEffects() && !IsOsrEntry()) { ASSERT(next()->IsSimulate()); } + + // Verify that instructions that can be eliminated by GVN have overridden + // HValue::DataEquals. The default implementation is UNREACHABLE. We + // don't actually care whether DataEquals returns true or false here. + if (CheckFlag(kUseGVN)) DataEquals(this); } #endif @@ -524,7 +529,7 @@ void HInstruction::Verify() const { HCall::HCall(int count) : arguments_(Zone::NewArray(count), count) { for (int i = 0; i < count; ++i) arguments_[i] = NULL; set_representation(Representation::Tagged()); - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } @@ -1119,10 +1124,10 @@ void HCompare::PrintDataTo(StringStream* stream) const { void HCompare::SetInputRepresentation(Representation r) { input_representation_ = r; if (r.IsTagged()) { - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); ClearFlag(kUseGVN); } else { - ClearFlagMask(AllSideEffects()); + ClearAllSideEffects(); SetFlag(kUseGVN); } } @@ -1388,7 +1393,7 @@ HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) { // Node-specific verification code is only included in debug mode. #ifdef DEBUG -void HPhi::Verify() const { +void HPhi::Verify() { ASSERT(OperandCount() == block()->predecessors()->length()); for (int i = 0; i < OperandCount(); ++i) { HValue* value = OperandAt(i); @@ -1400,49 +1405,49 @@ void HPhi::Verify() const { } -void HSimulate::Verify() const { +void HSimulate::Verify() { HInstruction::Verify(); ASSERT(HasAstId()); } -void HBoundsCheck::Verify() const { +void HBoundsCheck::Verify() { HInstruction::Verify(); ASSERT(HasNoUses()); } -void HCheckSmi::Verify() const { +void HCheckSmi::Verify() { HInstruction::Verify(); ASSERT(HasNoUses()); } -void HCheckNonSmi::Verify() const { +void HCheckNonSmi::Verify() { HInstruction::Verify(); ASSERT(HasNoUses()); } -void HCheckInstanceType::Verify() const { +void HCheckInstanceType::Verify() { HInstruction::Verify(); ASSERT(HasNoUses()); } -void HCheckMap::Verify() const { +void HCheckMap::Verify() { HInstruction::Verify(); ASSERT(HasNoUses()); } -void HCheckFunction::Verify() const { +void HCheckFunction::Verify() { HInstruction::Verify(); ASSERT(HasNoUses()); } -void HCheckPrototypeMaps::Verify() const { +void HCheckPrototypeMaps::Verify() { HInstruction::Verify(); ASSERT(HasNoUses()); } diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index d57655ab79..ff8170012e 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -46,112 +46,6 @@ class LInstruction; class LChunkBuilder; -// Type hierarchy: -// -// HValue -// HInstruction -// HAccessArgumentsAt -// HApplyArguments -// HArgumentsElements -// HArgumentsLength -// HArgumentsObject -// HBinaryOperation -// HArithmeticBinaryOperation -// HAdd -// HDiv -// HMod -// HMul -// HSub -// HBitwiseBinaryOperation -// HBitAnd -// HBitOr -// HBitXor -// HSar -// HShl -// HShr -// HBoundsCheck -// HCompare -// HCompareJSObjectEq -// HInstanceOf -// HInstanceOfKnownGlobal -// HLoadKeyed -// HLoadKeyedFastElement -// HLoadKeyedGeneric -// HPower -// HStoreNamed -// HStoreNamedField -// HStoreNamedGeneric -// HStringCharCodeAt -// HBlockEntry -// HCall -// HCallConstantFunction -// HCallFunction -// HCallGlobal -// HCallKeyed -// HCallKnownGlobal -// HCallNamed -// HCallNew -// HCallRuntime -// HCallStub -// HCheckPrototypeMaps -// HConstant -// HControlInstruction -// HDeoptimize -// HGoto -// HUnaryControlInstruction -// HCompareMap -// HReturn -// HTest -// HThrow -// HEnterInlined -// HFunctionLiteral -// HGlobalObject -// HGlobalReceiver -// HLeaveInlined -// HLoadContextSlot -// HLoadGlobal -// HMaterializedLiteral -// HArrayLiteral -// HObjectLiteral -// HRegExpLiteral -// HOsrEntry -// HParameter -// HSimulate -// HStackCheck -// HStoreKeyed -// HStoreKeyedFastElement -// HStoreKeyedGeneric -// HUnaryOperation -// HBitNot -// HChange -// HCheckFunction -// HCheckInstanceType -// HCheckMap -// HCheckNonSmi -// HCheckSmi -// HDeleteProperty -// HFixedArrayLength -// HJSArrayLength -// HLoadElements -// HTypeofIs -// HLoadNamedField -// HLoadNamedGeneric -// HLoadFunctionPrototype -// HPushArgument -// HStringLength -// HTypeof -// HUnaryMathOperation -// HUnaryPredicate -// HClassOfTest -// HHasCachedArrayIndex -// HHasInstanceType -// HIsNull -// HIsObject -// HIsSmi -// HValueOf -// HUnknownOSRValue -// HPhi - #define HYDROGEN_ALL_INSTRUCTION_LIST(V) \ V(ArithmeticBinaryOperation) \ V(BinaryOperation) \ @@ -224,12 +118,12 @@ class LChunkBuilder; V(LeaveInlined) \ V(LoadContextSlot) \ V(LoadElements) \ + V(LoadFunctionPrototype) \ V(LoadGlobal) \ V(LoadKeyedFastElement) \ V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ - V(LoadFunctionPrototype) \ V(Mod) \ V(Mul) \ V(ObjectLiteral) \ @@ -268,7 +162,6 @@ class LChunkBuilder; V(GlobalVars) \ V(Maps) \ V(ArrayLengths) \ - V(FunctionPrototypes) \ V(OsrEntries) #define DECLARE_INSTRUCTION(type) \ @@ -573,11 +466,6 @@ class HValue: public ZoneObject { return flags << kChangesToDependsFlagsLeftShift; } - // A flag mask to mark an instruction as having arbitrary side effects. - static int AllSideEffects() { - return ChangesFlagsMask() & ~(1 << kChangesOsrEntries); - } - static HValue* cast(HValue* value) { return value; } enum Opcode { @@ -636,9 +524,6 @@ class HValue: public ZoneObject { return NULL; } - bool HasSideEffects() const { - return (flags_ & AllSideEffects()) != 0; - } bool IsDefinedAfter(HBasicBlock* other) const; // Operands. @@ -661,12 +546,13 @@ class HValue: public ZoneObject { void Delete(); int flags() const { return flags_; } - void SetFlagMask(int mask) { flags_ |= mask; } - void SetFlag(Flag f) { SetFlagMask(1 << f); } - void ClearFlagMask(int mask) { flags_ &= ~mask; } - void ClearFlag(Flag f) { ClearFlagMask(1 << f); } - bool CheckFlag(Flag f) const { return CheckFlagMask(1 << f); } - bool CheckFlagMask(int mask) const { return (flags_ & mask) != 0; } + void SetFlag(Flag f) { flags_ |= (1 << f); } + void ClearFlag(Flag f) { flags_ &= ~(1 << f); } + bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; } + + void SetAllSideEffects() { flags_ |= AllSideEffects(); } + void ClearAllSideEffects() { flags_ &= ~AllSideEffects(); } + bool HasSideEffects() const { return (flags_ & AllSideEffects()) != 0; } Range* range() const { return range_; } bool HasRange() const { return range_ != NULL; } @@ -714,11 +600,16 @@ class HValue: public ZoneObject { void InsertInputConversion(HInstruction* previous, int index, HType type); #ifdef DEBUG - virtual void Verify() const = 0; + virtual void Verify() = 0; #endif protected: - virtual bool DataEquals(HValue* other) const { return true; } + // This function must be overridden for instructions with flag kUseGVN, to + // compare the non-Operand parts of the instruction. + virtual bool DataEquals(HValue* other) const { + UNREACHABLE(); + return false; + } virtual void RepresentationChanged(Representation to) { } virtual Range* InferRange(); virtual void DeleteFromGraph() = 0; @@ -735,6 +626,11 @@ class HValue: public ZoneObject { } private: + // A flag mask to mark an instruction as having arbitrary side effects. + static int AllSideEffects() { + return ChangesFlagsMask() & ~(1 << kChangesOsrEntries); + } + void InternalReplaceAtUse(HValue* use, HValue* other); void RegisterUse(int index, HValue* new_value); @@ -774,7 +670,7 @@ class HInstruction: public HValue { virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0; #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif // Returns whether this is some kind of deoptimizing check @@ -1063,7 +959,7 @@ class HSimulate: public HInstruction { DECLARE_CONCRETE_INSTRUCTION(Simulate, "simulate") #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif protected: @@ -1159,6 +1055,9 @@ class HGlobalObject: public HInstruction { } DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global_object") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1171,6 +1070,9 @@ class HGlobalReceiver: public HInstruction { } DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global_receiver") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1361,6 +1263,9 @@ class HJSArrayLength: public HUnaryOperation { } DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js_array_length") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1377,6 +1282,9 @@ class HFixedArrayLength: public HUnaryOperation { } DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed_array_length") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1394,6 +1302,9 @@ class HBitNot: public HUnaryOperation { virtual HType CalculateInferredType() const; DECLARE_CONCRETE_INSTRUCTION(BitNot, "bit_not") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1489,6 +1400,9 @@ class HLoadElements: public HUnaryOperation { } DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1510,7 +1424,7 @@ class HCheckMap: public HUnaryOperation { virtual HType CalculateInferredType() const; #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif Handle map() const { return map_; } @@ -1545,7 +1459,7 @@ class HCheckFunction: public HUnaryOperation { virtual HType CalculateInferredType() const; #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif Handle target() const { return target_; } @@ -1587,7 +1501,7 @@ class HCheckInstanceType: public HUnaryOperation { } #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif static HCheckInstanceType* NewIsJSObjectOrJSFunction(HValue* value); @@ -1628,10 +1542,13 @@ class HCheckNonSmi: public HUnaryOperation { virtual HType CalculateInferredType() const; #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check_non_smi") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1646,7 +1563,7 @@ class HCheckPrototypeMaps: public HInstruction { virtual bool IsCheckInstruction() const { return true; } #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif Handle prototype() const { return prototype_; } @@ -1689,10 +1606,13 @@ class HCheckSmi: public HUnaryOperation { virtual HType CalculateInferredType() const; #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check_smi") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1745,7 +1665,7 @@ class HPhi: public HValue { virtual void PrintTo(StringStream* stream) const; #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif DECLARE_INSTRUCTION(Phi) @@ -1833,7 +1753,7 @@ class HConstant: public HInstruction { } #ifdef DEBUG - virtual void Verify() const { } + virtual void Verify() { } #endif DECLARE_CONCRETE_INSTRUCTION(Constant, "constant") @@ -1952,6 +1872,9 @@ class HArgumentsElements: public HInstruction { } DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments_elements") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1963,6 +1886,9 @@ class HArgumentsLength: public HUnaryOperation { } DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments_length") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -1999,6 +1925,8 @@ class HAccessArgumentsAt: public HInstruction { operands_[index] = value; } + virtual bool DataEquals(HValue* other) const { return true; } + private: HOperandVector<3> operands_; }; @@ -2018,13 +1946,16 @@ class HBoundsCheck: public HBinaryOperation { } #ifdef DEBUG - virtual void Verify() const; + virtual void Verify(); #endif HValue* index() const { return left(); } HValue* length() const { return right(); } DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds_check") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2034,7 +1965,7 @@ class HBitwiseBinaryOperation: public HBinaryOperation { : HBinaryOperation(left, right) { set_representation(Representation::Tagged()); SetFlag(kFlexibleRepresentation); - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } virtual Representation RequiredInputRepresentation(int index) const { @@ -2044,7 +1975,7 @@ class HBitwiseBinaryOperation: public HBinaryOperation { virtual void RepresentationChanged(Representation to) { if (!to.IsTagged()) { ASSERT(to.IsInteger32()); - ClearFlagMask(AllSideEffects()); + ClearAllSideEffects(); SetFlag(kTruncatingToInt32); SetFlag(kUseGVN); } @@ -2062,12 +1993,12 @@ class HArithmeticBinaryOperation: public HBinaryOperation { : HBinaryOperation(left, right) { set_representation(Representation::Tagged()); SetFlag(kFlexibleRepresentation); - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } virtual void RepresentationChanged(Representation to) { if (!to.IsTagged()) { - ClearFlagMask(AllSideEffects()); + ClearAllSideEffects(); SetFlag(kUseGVN); } } @@ -2093,7 +2024,7 @@ class HCompare: public HBinaryOperation { : HBinaryOperation(left, right), token_(token) { ASSERT(Token::IsCompareOp(token)); set_representation(Representation::Tagged()); - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } void SetInputRepresentation(Representation r); @@ -2142,6 +2073,9 @@ class HCompareJSObjectEq: public HBinaryOperation { virtual HType CalculateInferredType() const; DECLARE_CONCRETE_INSTRUCTION(CompareJSObjectEq, "compare-js-object-eq") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2184,6 +2118,9 @@ class HIsObject: public HUnaryPredicate { explicit HIsObject(HValue* value) : HUnaryPredicate(value) { } DECLARE_CONCRETE_INSTRUCTION(IsObject, "is_object") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2192,6 +2129,9 @@ class HIsSmi: public HUnaryPredicate { explicit HIsSmi(HValue* value) : HUnaryPredicate(value) { } DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is_smi") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2228,6 +2168,9 @@ class HHasCachedArrayIndex: public HUnaryPredicate { explicit HHasCachedArrayIndex(HValue* value) : HUnaryPredicate(value) { } DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has_cached_array_index") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2278,7 +2221,7 @@ class HInstanceOf: public HBinaryOperation { public: HInstanceOf(HValue* left, HValue* right) : HBinaryOperation(left, right) { set_representation(Representation::Tagged()); - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } virtual bool EmitAtUses() const { return uses()->length() <= 1; } @@ -2296,7 +2239,7 @@ class HInstanceOfKnownGlobal: public HUnaryOperation { HInstanceOfKnownGlobal(HValue* left, Handle right) : HUnaryOperation(left), function_(right) { set_representation(Representation::Tagged()); - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } Handle function() { return function_; } @@ -2326,6 +2269,9 @@ class HPower: public HBinaryOperation { } DECLARE_CONCRETE_INSTRUCTION(Power, "power") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2348,6 +2294,8 @@ class HAdd: public HArithmeticBinaryOperation { DECLARE_CONCRETE_INSTRUCTION(Add, "add") protected: + virtual bool DataEquals(HValue* other) const { return true; } + virtual Range* InferRange(); }; @@ -2363,6 +2311,8 @@ class HSub: public HArithmeticBinaryOperation { DECLARE_CONCRETE_INSTRUCTION(Sub, "sub") protected: + virtual bool DataEquals(HValue* other) const { return true; } + virtual Range* InferRange(); }; @@ -2383,6 +2333,8 @@ class HMul: public HArithmeticBinaryOperation { DECLARE_CONCRETE_INSTRUCTION(Mul, "mul") protected: + virtual bool DataEquals(HValue* other) const { return true; } + virtual Range* InferRange(); }; @@ -2398,6 +2350,8 @@ class HMod: public HArithmeticBinaryOperation { DECLARE_CONCRETE_INSTRUCTION(Mod, "mod") protected: + virtual bool DataEquals(HValue* other) const { return true; } + virtual Range* InferRange(); }; @@ -2414,6 +2368,8 @@ class HDiv: public HArithmeticBinaryOperation { DECLARE_CONCRETE_INSTRUCTION(Div, "div") protected: + virtual bool DataEquals(HValue* other) const { return true; } + virtual Range* InferRange(); }; @@ -2429,6 +2385,8 @@ class HBitAnd: public HBitwiseBinaryOperation { DECLARE_CONCRETE_INSTRUCTION(BitAnd, "bit_and") protected: + virtual bool DataEquals(HValue* other) const { return true; } + virtual Range* InferRange(); }; @@ -2442,6 +2400,9 @@ class HBitXor: public HBitwiseBinaryOperation { virtual HType CalculateInferredType() const; DECLARE_CONCRETE_INSTRUCTION(BitXor, "bit_xor") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2456,6 +2417,8 @@ class HBitOr: public HBitwiseBinaryOperation { DECLARE_CONCRETE_INSTRUCTION(BitOr, "bit_or") protected: + virtual bool DataEquals(HValue* other) const { return true; } + virtual Range* InferRange(); }; @@ -2469,6 +2432,9 @@ class HShl: public HBitwiseBinaryOperation { virtual HType CalculateInferredType() const; DECLARE_CONCRETE_INSTRUCTION(Shl, "shl") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2480,6 +2446,9 @@ class HShr: public HBitwiseBinaryOperation { virtual HType CalculateInferredType() const; DECLARE_CONCRETE_INSTRUCTION(Shr, "shr") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2492,6 +2461,9 @@ class HSar: public HBitwiseBinaryOperation { virtual HType CalculateInferredType() const; DECLARE_CONCRETE_INSTRUCTION(Sar, "sar") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; @@ -2534,7 +2506,7 @@ class HCallStub: public HInstruction { argument_count_(argument_count), transcendental_type_(TranscendentalCache::kNumberOfCaches) { set_representation(Representation::Tagged()); - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } CodeStub::Major major_key() { return major_key_; } @@ -2603,12 +2575,17 @@ class HLoadGlobal: public HInstruction { class HStoreGlobal: public HUnaryOperation { public: - HStoreGlobal(HValue* value, Handle cell) - : HUnaryOperation(value), cell_(cell) { + HStoreGlobal(HValue* value, + Handle cell, + bool check_hole_value) + : HUnaryOperation(value), + cell_(cell), + check_hole_value_(check_hole_value) { SetFlag(kChangesGlobalVars); } Handle cell() const { return cell_; } + bool check_hole_value() const { return check_hole_value_; } virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); @@ -2617,14 +2594,9 @@ class HStoreGlobal: public HUnaryOperation { DECLARE_CONCRETE_INSTRUCTION(StoreGlobal, "store_global") - protected: - virtual bool DataEquals(HValue* other) const { - HStoreGlobal* b = HStoreGlobal::cast(other); - return cell_.is_identical_to(b->cell()); - } - private: Handle cell_; + bool check_hole_value_; }; @@ -2704,7 +2676,7 @@ class HLoadNamedGeneric: public HUnaryOperation { HLoadNamedGeneric(HValue* object, Handle name) : HUnaryOperation(object), name_(name) { set_representation(Representation::Tagged()); - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } HValue* object() const { return OperandAt(0); } @@ -2716,12 +2688,6 @@ class HLoadNamedGeneric: public HUnaryOperation { DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load_named_generic") - protected: - virtual bool DataEquals(HValue* other) const { - HLoadNamedGeneric* b = HLoadNamedGeneric::cast(other); - return name_.is_identical_to(b->name_); - } - private: Handle name_; }; @@ -2732,7 +2698,8 @@ class HLoadFunctionPrototype: public HUnaryOperation { explicit HLoadFunctionPrototype(HValue* function) : HUnaryOperation(function) { set_representation(Representation::Tagged()); - SetFlagMask(kDependsOnFunctionPrototypes); + SetFlag(kUseGVN); + SetFlag(kDependsOnCalls); } HValue* function() const { return OperandAt(0); } @@ -2781,13 +2748,16 @@ class HLoadKeyedFastElement: public HLoadKeyed { DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load_keyed_fast_element") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } }; class HLoadKeyedGeneric: public HLoadKeyed { public: HLoadKeyedGeneric(HValue* obj, HValue* key) : HLoadKeyed(obj, key) { - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load_keyed_generic") @@ -2823,12 +2793,6 @@ class HStoreNamed: public HBinaryOperation { DECLARE_INSTRUCTION(StoreNamed) - protected: - virtual bool DataEquals(HValue* other) const { - HStoreNamed* b = HStoreNamed::cast(other); - return name_.is_identical_to(b->name_); - } - private: Handle name_; }; @@ -2874,7 +2838,7 @@ class HStoreNamedGeneric: public HStoreNamed { public: HStoreNamedGeneric(HValue* obj, Handle name, HValue* val) : HStoreNamed(obj, name, val) { - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store_named_generic") @@ -2939,7 +2903,7 @@ class HStoreKeyedGeneric: public HStoreKeyed { public: HStoreKeyedGeneric(HValue* obj, HValue* key, HValue* val) : HStoreKeyed(obj, key, val) { - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store_keyed_generic") @@ -2960,14 +2924,14 @@ class HStringCharCodeAt: public HBinaryOperation { : Representation::Tagged(); } - virtual bool DataEquals(HValue* other) const { return true; } - HValue* string() const { return OperandAt(0); } HValue* index() const { return OperandAt(1); } DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string_char_code_at") protected: + virtual bool DataEquals(HValue* other) const { return true; } + virtual Range* InferRange() { return new Range(0, String::kMaxUC16CharCode); } @@ -2990,11 +2954,11 @@ class HStringLength: public HUnaryOperation { return HType::Smi(); } - virtual bool DataEquals(HValue* other) const { return true; } - DECLARE_CONCRETE_INSTRUCTION(StringLength, "string_length") protected: + virtual bool DataEquals(HValue* other) const { return true; } + virtual Range* InferRange() { return new Range(0, String::kMaxLength); } @@ -3128,7 +3092,7 @@ class HDeleteProperty: public HBinaryOperation { HDeleteProperty(HValue* obj, HValue* key) : HBinaryOperation(obj, key) { set_representation(Representation::Tagged()); - SetFlagMask(AllSideEffects()); + SetAllSideEffects(); } virtual Representation RequiredInputRepresentation(int index) const { diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index ae91065d59..84623069a0 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -684,7 +684,7 @@ HGraph::HGraph(CompilationInfo* info) } -bool HGraph::AllowAggressiveOptimizations() const { +bool HGraph::AllowCodeMotion() const { return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; } @@ -1446,19 +1446,23 @@ void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block, } } -// Only move instructions that postdominate the loop header (i.e. are -// always executed inside the loop). This is to avoid unnecessary -// deoptimizations assuming the loop is executed at least once. -// TODO(fschneider): Better type feedback should give us information -// about code that was never executed. + bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, HBasicBlock* loop_header) { - if (FLAG_aggressive_loop_invariant_motion && - !instr->IsChange() && - (!instr->IsCheckInstruction() || - graph_->AllowAggressiveOptimizations())) { + // If we've disabled code motion, don't move any instructions. + if (!graph_->AllowCodeMotion()) return false; + + // If --aggressive-loop-invariant-motion, move everything except change + // instructions. + if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { return true; } + + // Otherwise only move instructions that postdominate the loop header + // (i.e. are always executed inside the loop). This is to avoid + // unnecessary deoptimizations assuming the loop is executed at least + // once. TODO(fschneider): Better type feedback should give us + // information about code that was never executed. HBasicBlock* block = instr->block(); bool result = true; if (block != loop_header) { @@ -3366,9 +3370,10 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, LookupGlobalPropertyCell(var, &lookup, true); CHECK_BAILOUT; + bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); Handle global(graph()->info()->global_object()); Handle cell(global->GetPropertyCell(&lookup)); - HInstruction* instr = new HStoreGlobal(value, cell); + HInstruction* instr = new HStoreGlobal(value, cell, check_hole); instr->set_position(position); AddInstruction(instr); if (instr->HasSideEffects()) AddSimulate(ast_id); @@ -3385,7 +3390,6 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { // We have a second position recorded in the FullCodeGenerator to have // type feedback for the binary operation. BinaryOperation* operation = expr->binary_operation(); - operation->RecordTypeFeedback(oracle()); if (var != NULL) { if (!var->is_global() && !var->IsStackAllocated()) { @@ -3766,6 +3770,14 @@ void HGraphBuilder::VisitProperty(Property* expr) { AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE)); instr = new HJSArrayLength(array); + } else if (expr->IsStringLength()) { + HValue* string = Pop(); + AddInstruction(new HCheckNonSmi(string)); + AddInstruction(new HCheckInstanceType(string, + FIRST_STRING_TYPE, + LAST_STRING_TYPE)); + instr = new HStringLength(string); + } else if (expr->IsFunctionPrototype()) { HValue* function = Pop(); AddInstruction(new HCheckNonSmi(function)); @@ -3952,8 +3964,7 @@ bool HGraphBuilder::TryInline(Call* expr) { int count_before = AstNode::Count(); // Parse and allocate variables. - Handle shared(target->shared()); - CompilationInfo inner_info(shared); + CompilationInfo inner_info(target); if (!ParserApi::Parse(&inner_info) || !Scope::Analyze(&inner_info)) { return false; @@ -3976,9 +3987,10 @@ bool HGraphBuilder::TryInline(Call* expr) { // Don't inline functions that uses the arguments object or that // have a mismatching number of parameters. + Handle shared(target->shared()); int arity = expr->arguments()->length(); if (function->scope()->arguments() != NULL || - arity != target->shared()->formal_parameter_count()) { + arity != shared->formal_parameter_count()) { return false; } @@ -4801,7 +4813,7 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, default: UNREACHABLE(); } - TypeInfo info = oracle()->BinaryType(expr, TypeFeedbackOracle::RESULT); + TypeInfo info = oracle()->BinaryType(expr); // If we hit an uninitialized binary op stub we will get type info // for a smi operation. If one of the operands is a constant string // do not generate code assuming it is a smi operation. @@ -4952,7 +4964,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { HValue* left = Pop(); Token::Value op = expr->op(); - TypeInfo info = oracle()->CompareType(expr, TypeFeedbackOracle::RESULT); + TypeInfo info = oracle()->CompareType(expr); HInstruction* instr = NULL; if (op == Token::INSTANCEOF) { // Check to see if the rhs of the instanceof is a global function not diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index 3524df9495..dbcb82e6e8 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -297,7 +297,7 @@ class HGraph: public HSubgraph { CompilationInfo* info() const { return info_; } - bool AllowAggressiveOptimizations() const; + bool AllowCodeMotion() const; const ZoneList* blocks() const { return &blocks_; } const ZoneList* phi_list() const { return phi_list_; } diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index 2c83662efd..5f3400f83e 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -91,7 +91,8 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) { void FastNewContextStub::Generate(MacroAssembler* masm) { // Try to allocate the context in new space. Label gc; - __ AllocateInNewSpace((slots_ * kPointerSize) + FixedArray::kHeaderSize, + int length = slots_ + Context::MIN_CONTEXT_SLOTS; + __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, eax, ebx, ecx, &gc, TAG_OBJECT); // Get the function from the stack. @@ -100,7 +101,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { // Setup the object header. __ mov(FieldOperand(eax, HeapObject::kMapOffset), Factory::context_map()); __ mov(FieldOperand(eax, Context::kLengthOffset), - Immediate(Smi::FromInt(slots_))); + Immediate(Smi::FromInt(length))); // Setup the fixed slots. __ Set(ebx, Immediate(0)); // Set to NULL. @@ -118,7 +119,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { // Initialize the rest of the slots to undefined. __ mov(ebx, Factory::undefined_value()); - for (int i = Context::MIN_CONTEXT_SLOTS; i < slots_; i++) { + for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { __ mov(Operand(eax, Context::SlotOffset(i)), ebx); } @@ -1772,40 +1773,11 @@ void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) { - Label call_runtime; ASSERT(operands_type_ == TRBinaryOpIC::STRING); ASSERT(op_ == Token::ADD); - // If one of the arguments is a string, call the string add stub. - // Otherwise, transition to the generic TRBinaryOpIC type. - - // Registers containing left and right operands respectively. - Register left = edx; - Register right = eax; - - // Test if left operand is a string. - NearLabel left_not_string; - __ test(left, Immediate(kSmiTagMask)); - __ j(zero, &left_not_string); - __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); - __ j(above_equal, &left_not_string); - - StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); - GenerateRegisterArgsPush(masm); - __ TailCallStub(&string_add_left_stub); - - // Left operand is not a string, test right. - __ bind(&left_not_string); - __ test(right, Immediate(kSmiTagMask)); - __ j(zero, &call_runtime); - __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); - __ j(above_equal, &call_runtime); - - StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); - GenerateRegisterArgsPush(masm); - __ TailCallStub(&string_add_right_stub); - - // Neither argument is a string. - __ bind(&call_runtime); + // Try to add arguments as strings, otherwise, transition to the generic + // TRBinaryOpIC type. + GenerateAddStrings(masm); GenerateTypeTransition(masm); } @@ -2346,36 +2318,8 @@ void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { __ bind(&call_runtime); switch (op_) { case Token::ADD: { + GenerateAddStrings(masm); GenerateRegisterArgsPush(masm); - // Test for string arguments before calling runtime. - // Registers containing left and right operands respectively. - Register lhs, rhs; - lhs = edx; - rhs = eax; - - // Test if left operand is a string. - NearLabel lhs_not_string; - __ test(lhs, Immediate(kSmiTagMask)); - __ j(zero, &lhs_not_string); - __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, ecx); - __ j(above_equal, &lhs_not_string); - - StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); - __ TailCallStub(&string_add_left_stub); - - NearLabel call_add_runtime; - // Left operand is not a string, test right. - __ bind(&lhs_not_string); - __ test(rhs, Immediate(kSmiTagMask)); - __ j(zero, &call_add_runtime); - __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx); - __ j(above_equal, &call_add_runtime); - - StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); - __ TailCallStub(&string_add_right_stub); - - // Neither argument is a string. - __ bind(&call_add_runtime); __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); break; } @@ -2418,6 +2362,40 @@ void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { } +void TypeRecordingBinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { + NearLabel call_runtime; + + // Registers containing left and right operands respectively. + Register left = edx; + Register right = eax; + + // Test if left operand is a string. + NearLabel left_not_string; + __ test(left, Immediate(kSmiTagMask)); + __ j(zero, &left_not_string); + __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); + __ j(above_equal, &left_not_string); + + StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); + GenerateRegisterArgsPush(masm); + __ TailCallStub(&string_add_left_stub); + + // Left operand is not a string, test right. + __ bind(&left_not_string); + __ test(right, Immediate(kSmiTagMask)); + __ j(zero, &call_runtime); + __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); + __ j(above_equal, &call_runtime); + + StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); + GenerateRegisterArgsPush(masm); + __ TailCallStub(&string_add_right_stub); + + // Neither argument is a string. + __ bind(&call_runtime); +} + + void TypeRecordingBinaryOpStub::GenerateHeapResultAllocation( MacroAssembler* masm, Label* alloc_failure) { @@ -4660,8 +4638,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_termination_exception, Label* throw_out_of_memory_exception, bool do_gc, - bool always_allocate_scope, - int /* alignment_skew */) { + bool always_allocate_scope) { // eax: result parameter for PerformGC, if any // ebx: pointer to C function (C callee-saved) // ebp: frame pointer (restored after C call) diff --git a/deps/v8/src/ia32/code-stubs-ia32.h b/deps/v8/src/ia32/code-stubs-ia32.h index 4a56d0d143..cd18749b12 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.h +++ b/deps/v8/src/ia32/code-stubs-ia32.h @@ -308,6 +308,7 @@ class TypeRecordingBinaryOpStub: public CodeStub { void GenerateHeapNumberStub(MacroAssembler* masm); void GenerateStringStub(MacroAssembler* masm); void GenerateGenericStub(MacroAssembler* masm); + void GenerateAddStrings(MacroAssembler* masm); void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure); void GenerateRegisterArgsPush(MacroAssembler* masm); diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index 29c8c0e406..2b48b0bc99 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -209,7 +209,7 @@ void CodeGenerator::Generate(CompilationInfo* info) { frame_->AllocateStackSlots(); // Allocate the local context if needed. - int heap_slots = scope()->num_heap_slots(); + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; if (heap_slots > 0) { Comment cmnt(masm_, "[ allocate local context"); // Allocate local context. @@ -8230,19 +8230,13 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { return; } else if (slot != NULL && slot->type() == Slot::LOOKUP) { - // Call the runtime to look up the context holding the named + // Call the runtime to delete from the context holding the named // variable. Sync the virtual frame eagerly so we can push the // arguments directly into place. frame_->SyncRange(0, frame_->element_count() - 1); frame_->EmitPush(esi); frame_->EmitPush(Immediate(variable->name())); - Result context = frame_->CallRuntime(Runtime::kLookupContext, 2); - ASSERT(context.is_register()); - frame_->EmitPush(context.reg()); - context.Unuse(); - frame_->EmitPush(Immediate(variable->name())); - Result answer = frame_->InvokeBuiltin(Builtins::DELETE, - CALL_FUNCTION, 2); + Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); frame_->Push(&answer); return; } diff --git a/deps/v8/src/ia32/deoptimizer-ia32.cc b/deps/v8/src/ia32/deoptimizer-ia32.cc index 3050c5674f..e9e3fcfb7f 100644 --- a/deps/v8/src/ia32/deoptimizer-ia32.cc +++ b/deps/v8/src/ia32/deoptimizer-ia32.cc @@ -106,44 +106,71 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } -void Deoptimizer::PatchStackCheckCode(RelocInfo* rinfo, +void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code, + Code* check_code, Code* replacement_code) { - // The stack check code matches the pattern: - // - // cmp esp, - // jae ok - // call - // test eax, - // ok: ... - // - // We will patch away the branch so the code is: - // - // cmp esp, ;; Not changed - // nop - // nop - // call - // test eax, - // ok: - Address call_target_address = rinfo->pc(); - ASSERT(*(call_target_address - 3) == 0x73 && // jae - *(call_target_address - 2) == 0x07 && // offset - *(call_target_address - 1) == 0xe8); // call - *(call_target_address - 3) = 0x90; // nop - *(call_target_address - 2) = 0x90; // nop - rinfo->set_target_address(replacement_code->entry()); + // Iterate the unoptimized code and patch every stack check except at + // the function entry. This code assumes the function entry stack + // check appears first i.e., is not deferred or otherwise reordered. + ASSERT(unoptimized_code->kind() == Code::FUNCTION); + bool first = true; + for (RelocIterator it(unoptimized_code, RelocInfo::kCodeTargetMask); + !it.done(); + it.next()) { + RelocInfo* rinfo = it.rinfo(); + if (rinfo->target_address() == Code::cast(check_code)->entry()) { + if (first) { + first = false; + } else { + // The stack check code matches the pattern: + // + // cmp esp, + // jae ok + // call + // test eax, + // ok: ... + // + // We will patch away the branch so the code is: + // + // cmp esp, ;; Not changed + // nop + // nop + // call + // test eax, + // ok: + Address call_target_address = rinfo->pc(); + ASSERT(*(call_target_address - 3) == 0x73 && // jae + *(call_target_address - 2) == 0x07 && // offset + *(call_target_address - 1) == 0xe8); // call + *(call_target_address - 3) = 0x90; // nop + *(call_target_address - 2) = 0x90; // nop + rinfo->set_target_address(replacement_code->entry()); + } + } + } } -void Deoptimizer::RevertStackCheckCode(RelocInfo* rinfo, Code* check_code) { - // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to - // restore the conditional branch. - Address call_target_address = rinfo->pc(); - ASSERT(*(call_target_address - 3) == 0x90 && // nop - *(call_target_address - 2) == 0x90 && // nop - *(call_target_address - 1) == 0xe8); // call - *(call_target_address - 3) = 0x73; // jae - *(call_target_address - 2) = 0x07; // offset - rinfo->set_target_address(check_code->entry()); +void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code, + Code* check_code, + Code* replacement_code) { + // Iterate the unoptimized code and revert all the patched stack checks. + for (RelocIterator it(unoptimized_code, RelocInfo::kCodeTargetMask); + !it.done(); + it.next()) { + RelocInfo* rinfo = it.rinfo(); + if (rinfo->target_address() == replacement_code->entry()) { + // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to + // restore the conditional branch. + Address call_target_address = rinfo->pc(); + ASSERT(*(call_target_address - 3) == 0x90 && // nop + *(call_target_address - 2) == 0x90 && // nop + *(call_target_address - 1) == 0xe8); // call + *(call_target_address - 3) = 0x73; // jae + *(call_target_address - 2) = 0x07; // offset + rinfo->set_target_address(check_code->entry()); + } + } } @@ -507,26 +534,25 @@ void Deoptimizer::EntryGenerator::Generate() { __ mov(ebx, Operand(eax, Deoptimizer::input_offset())); // Fill in the input registers. - for (int i = 0; i < kNumberOfRegisters; i++) { - int offset = (i * kIntSize) + FrameDescription::registers_offset(); - __ mov(ecx, Operand(esp, (kNumberOfRegisters - 1 - i) * kPointerSize)); - __ mov(Operand(ebx, offset), ecx); + for (int i = kNumberOfRegisters - 1; i >= 0; i--) { + int offset = (i * kPointerSize) + FrameDescription::registers_offset(); + __ pop(Operand(ebx, offset)); } // Fill in the double input registers. int double_regs_offset = FrameDescription::double_registers_offset(); for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) { int dst_offset = i * kDoubleSize + double_regs_offset; - int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize; + int src_offset = i * kDoubleSize; __ movdbl(xmm0, Operand(esp, src_offset)); __ movdbl(Operand(ebx, dst_offset), xmm0); } - // Remove the bailout id and the general purpose registers from the stack. + // Remove the bailout id and the double registers from the stack. if (type() == EAGER) { - __ add(Operand(esp), Immediate(kSavedRegistersAreaSize + kPointerSize)); + __ add(Operand(esp), Immediate(kDoubleRegsSize + kPointerSize)); } else { - __ add(Operand(esp), Immediate(kSavedRegistersAreaSize + 2 * kPointerSize)); + __ add(Operand(esp), Immediate(kDoubleRegsSize + 2 * kPointerSize)); } // Compute a pointer to the unwinding limit in register ecx; that is @@ -591,7 +617,7 @@ void Deoptimizer::EntryGenerator::Generate() { // Push the registers from the last output frame. for (int i = 0; i < kNumberOfRegisters; i++) { - int offset = (i * kIntSize) + FrameDescription::registers_offset(); + int offset = (i * kPointerSize) + FrameDescription::registers_offset(); __ push(Operand(ebx, offset)); } diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index 772eb8f905..8bcb49f2e1 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -142,7 +142,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { bool function_in_register = true; // Possibly allocate a local context. - int heap_slots = scope()->num_heap_slots(); + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; if (heap_slots > 0) { Comment cmnt(masm_, "[ Allocate local context"); // Argument to NewContext is the function, which is still in edi. @@ -764,6 +764,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // Compile all the tests with branches to their bodies. for (int i = 0; i < clauses->length(); i++) { CaseClause* clause = clauses->at(i); + clause->body_target()->entry_label()->Unuse(); + // The default is not a test, but remember it as final fall through. if (clause->is_default()) { default_clause = clause; @@ -3689,19 +3691,18 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { if (prop != NULL) { VisitForStackValue(prop->obj()); VisitForStackValue(prop->key()); + __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); } else if (var->is_global()) { __ push(GlobalObjectOperand()); __ push(Immediate(var->name())); + __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); } else { - // Non-global variable. Call the runtime to look up the context - // where the variable was introduced. + // Non-global variable. Call the runtime to delete from the + // context where the variable was introduced. __ push(context_register()); __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kLookupContext, 2); - __ push(eax); - __ push(Immediate(var->name())); + __ CallRuntime(Runtime::kDeleteContextSlot, 2); } - __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(eax); } break; diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc index c234b364ce..c1369774d8 100644 --- a/deps/v8/src/ia32/ic-ia32.cc +++ b/deps/v8/src/ia32/ic-ia32.cc @@ -388,7 +388,8 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) { } -void LoadIC::GenerateStringLength(MacroAssembler* masm) { +void LoadIC::GenerateStringLength(MacroAssembler* masm, + bool support_wrappers) { // ----------- S t a t e ------------- // -- eax : receiver // -- ecx : name @@ -396,7 +397,8 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) { // ----------------------------------- Label miss; - StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss); + StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss, + support_wrappers); __ bind(&miss); StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 3bfb10f80e..d35bfc9a2b 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -566,37 +566,40 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() { } -void LCodeGen::RecordSafepoint(LPointerMap* pointers, - int deoptimization_index) { +void LCodeGen::RecordSafepoint( + LPointerMap* pointers, + Safepoint::Kind kind, + int arguments, + int deoptimization_index) { const ZoneList* operands = pointers->operands(); Safepoint safepoint = safepoints_.DefineSafepoint(masm(), - deoptimization_index); + kind, arguments, deoptimization_index); for (int i = 0; i < operands->length(); i++) { LOperand* pointer = operands->at(i); if (pointer->IsStackSlot()) { safepoint.DefinePointerSlot(pointer->index()); + } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { + safepoint.DefinePointerRegister(ToRegister(pointer)); } } + if (kind & Safepoint::kWithRegisters) { + // Register esi always contains a pointer to the context. + safepoint.DefinePointerRegister(esi); + } +} + + +void LCodeGen::RecordSafepoint(LPointerMap* pointers, + int deoptimization_index) { + RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); } void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, int deoptimization_index) { - const ZoneList* operands = pointers->operands(); - Safepoint safepoint = - safepoints_.DefineSafepointWithRegisters( - masm(), arguments, deoptimization_index); - for (int i = 0; i < operands->length(); i++) { - LOperand* pointer = operands->at(i); - if (pointer->IsStackSlot()) { - safepoint.DefinePointerSlot(pointer->index()); - } else if (pointer->IsRegister()) { - safepoint.DefinePointerRegister(ToRegister(pointer)); - } - } - // Register esi always contains a pointer to the context. - safepoint.DefinePointerRegister(esi); + RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, + deoptimization_index); } @@ -1908,7 +1911,19 @@ void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) { void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { Register value = ToRegister(instr->InputAt(0)); - __ mov(Operand::Cell(instr->hydrogen()->cell()), value); + Operand cell_operand = Operand::Cell(instr->hydrogen()->cell()); + + // If the cell we are storing to contains the hole it could have + // been deleted from the property dictionary. In that case, we need + // to update the property details in the property dictionary to mark + // it as no longer deleted. We deoptimize in that case. + if (instr->hydrogen()->check_hole_value()) { + __ cmp(cell_operand, Factory::the_hole_value()); + DeoptimizeIf(equal, instr->environment()); + } + + // Store the value. + __ mov(cell_operand, value); } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index 780525a590..f0379c02e3 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -198,6 +198,10 @@ class LCodeGen BASE_EMBEDDED { void DoMathSin(LUnaryMathOperation* instr); // Support for recording safepoint and position information. + void RecordSafepoint(LPointerMap* pointers, + Safepoint::Kind kind, + int arguments, + int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, diff --git a/deps/v8/src/ia32/lithium-gap-resolver-ia32.cc b/deps/v8/src/ia32/lithium-gap-resolver-ia32.cc index 88869590e7..45c790f3f0 100644 --- a/deps/v8/src/ia32/lithium-gap-resolver-ia32.cc +++ b/deps/v8/src/ia32/lithium-gap-resolver-ia32.cc @@ -32,12 +32,11 @@ namespace v8 { namespace internal { LGapResolver::LGapResolver(LCodeGen* owner) - : cgen_(owner), moves_(32), spilled_register_(-1) { - for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) { - source_uses_[i] = 0; - destination_uses_[i] = 0; - } -} + : cgen_(owner), + moves_(32), + source_uses_(), + destination_uses_(), + spilled_register_(-1) {} void LGapResolver::Resolve(LParallelMove* parallel_move) { diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index f422514235..100a2d44fa 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/deps/v8/src/ia32/lithium-ia32.cc @@ -1343,8 +1343,8 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { if (instr->representation().IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); - LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); - LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand()); + LOperand* left = UseRegisterAtStart(instr->left()); + LOperand* right = UseOrConstantAtStart(instr->right()); LSubI* sub = new LSubI(left, right); LInstruction* result = DefineSameAsFirst(sub); if (instr->CheckFlag(HValue::kCanOverflow)) { @@ -1645,7 +1645,8 @@ LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) { LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) { - return new LStoreGlobal(UseRegisterAtStart(instr->value())); + LStoreGlobal* result = new LStoreGlobal(UseRegisterAtStart(instr->value())); + return instr->check_hole_value() ? AssignEnvironment(result) : result; } diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 10c942a5b3..a4c9b11879 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -339,7 +339,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) { CpuFeatures::Scope scope(SSE2); int space = XMMRegister::kNumRegisters * kDoubleSize + argc * kPointerSize; sub(Operand(esp), Immediate(space)); - int offset = -2 * kPointerSize; + const int offset = -2 * kPointerSize; for (int i = 0; i < XMMRegister::kNumRegisters; i++) { XMMRegister reg = XMMRegister::from_code(i); movdbl(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg); @@ -382,7 +382,7 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) { // Optionally restore all XMM registers. if (save_doubles) { CpuFeatures::Scope scope(SSE2); - int offset = -2 * kPointerSize; + const int offset = -2 * kPointerSize; for (int i = 0; i < XMMRegister::kNumRegisters; i++) { XMMRegister reg = XMMRegister::from_code(i); movdbl(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize))); @@ -1288,7 +1288,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, ExternalReference scheduled_exception_address = ExternalReference::scheduled_exception_address(); cmp(Operand::StaticVariable(scheduled_exception_address), - Immediate(Factory::the_hole_value())); + Immediate(Factory::the_hole_value())); j(not_equal, &promote_scheduled_exception, not_taken); LeaveApiExitFrame(); ret(stack_space * kPointerSize); diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index 6d353c2670..6de9a410d1 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -327,28 +327,32 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, Register receiver, Register scratch1, Register scratch2, - Label* miss) { + Label* miss, + bool support_wrappers) { Label check_wrapper; // Check if the object is a string leaving the instance type in the // scratch register. - GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper); + GenerateStringCheck(masm, receiver, scratch1, miss, + support_wrappers ? &check_wrapper : miss); // Load length from the string and convert to a smi. __ mov(eax, FieldOperand(receiver, String::kLengthOffset)); __ ret(0); - // Check if the object is a JSValue wrapper. - __ bind(&check_wrapper); - __ cmp(scratch1, JS_VALUE_TYPE); - __ j(not_equal, miss, not_taken); + if (support_wrappers) { + // Check if the object is a JSValue wrapper. + __ bind(&check_wrapper); + __ cmp(scratch1, JS_VALUE_TYPE); + __ j(not_equal, miss, not_taken); - // Check if the wrapped value is a string and load the length - // directly if it is. - __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); - GenerateStringCheck(masm, scratch2, scratch1, miss, miss); - __ mov(eax, FieldOperand(scratch2, String::kLengthOffset)); - __ ret(0); + // Check if the wrapped value is a string and load the length + // directly if it is. + __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); + GenerateStringCheck(masm, scratch2, scratch1, miss, miss); + __ mov(eax, FieldOperand(scratch2, String::kLengthOffset)); + __ ret(0); + } } @@ -451,10 +455,9 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { // Generates call to API function. -static bool GenerateFastApiCall(MacroAssembler* masm, - const CallOptimization& optimization, - int argc, - Failure** failure) { +static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, + const CallOptimization& optimization, + int argc) { // ----------- S t a t e ------------- // -- esp[0] : return address // -- esp[4] : object passing the type check @@ -516,13 +519,8 @@ static bool GenerateFastApiCall(MacroAssembler* masm, // already generated). Do not allow the assembler to perform a // garbage collection but instead return the allocation failure // object. - MaybeObject* result = - masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1); - if (result->IsFailure()) { - *failure = Failure::cast(result); - return false; - } - return true; + return masm->TryCallApiFunctionAndReturn(&fun, + argc + kFastApiCallArguments + 1); } @@ -535,17 +533,16 @@ class CallInterceptorCompiler BASE_EMBEDDED { arguments_(arguments), name_(name) {} - bool Compile(MacroAssembler* masm, - JSObject* object, - JSObject* holder, - String* name, - LookupResult* lookup, - Register receiver, - Register scratch1, - Register scratch2, - Register scratch3, - Label* miss, - Failure** failure) { + MaybeObject* Compile(MacroAssembler* masm, + JSObject* object, + JSObject* holder, + String* name, + LookupResult* lookup, + Register receiver, + Register scratch1, + Register scratch2, + Register scratch3, + Label* miss) { ASSERT(holder->HasNamedInterceptor()); ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); @@ -566,8 +563,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { lookup, name, optimization, - miss, - failure); + miss); } else { CompileRegular(masm, object, @@ -578,23 +574,22 @@ class CallInterceptorCompiler BASE_EMBEDDED { name, holder, miss); - return true; + return Heap::undefined_value(); // Success. } } private: - bool CompileCacheable(MacroAssembler* masm, - JSObject* object, - Register receiver, - Register scratch1, - Register scratch2, - Register scratch3, - JSObject* interceptor_holder, - LookupResult* lookup, - String* name, - const CallOptimization& optimization, - Label* miss_label, - Failure** failure) { + MaybeObject* CompileCacheable(MacroAssembler* masm, + JSObject* object, + Register receiver, + Register scratch1, + Register scratch2, + Register scratch3, + JSObject* interceptor_holder, + LookupResult* lookup, + String* name, + const CallOptimization& optimization, + Label* miss_label) { ASSERT(optimization.is_constant_call()); ASSERT(!lookup->holder()->IsGlobalObject()); @@ -656,11 +651,9 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Invoke function. if (can_do_fast_api_call) { - bool success = GenerateFastApiCall(masm, optimization, - arguments_.immediate(), failure); - if (!success) { - return false; - } + MaybeObject* result = + GenerateFastApiCall(masm, optimization, arguments_.immediate()); + if (result->IsFailure()) return result; } else { __ InvokeFunction(optimization.constant_function(), arguments_, JUMP_FUNCTION); @@ -679,7 +672,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { FreeSpaceForFastApiCall(masm, scratch1); } - return true; + return Heap::undefined_value(); // Success. } void CompileRegular(MacroAssembler* masm, @@ -1057,17 +1050,16 @@ void StubCompiler::GenerateLoadField(JSObject* object, } -bool StubCompiler::GenerateLoadCallback(JSObject* object, - JSObject* holder, - Register receiver, - Register name_reg, - Register scratch1, - Register scratch2, - Register scratch3, - AccessorInfo* callback, - String* name, - Label* miss, - Failure** failure) { +MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, + JSObject* holder, + Register receiver, + Register name_reg, + Register scratch1, + Register scratch2, + Register scratch3, + AccessorInfo* callback, + String* name, + Label* miss) { // Check that the receiver isn't a smi. __ test(receiver, Immediate(kSmiTagMask)); __ j(zero, miss, not_taken); @@ -1122,13 +1114,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, // already generated). Do not allow the assembler to perform a // garbage collection but instead return the allocation failure // object. - MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); - if (result->IsFailure()) { - *failure = Failure::cast(result); - return false; - } - - return true; + return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); } @@ -2280,17 +2266,14 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, } if (depth != kInvalidProtoDepth) { - Failure* failure; // Move the return address on top of the stack. __ mov(eax, Operand(esp, 3 * kPointerSize)); __ mov(Operand(esp, 0 * kPointerSize), eax); // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains // duplicate of return address and will be overwritten. - bool success = GenerateFastApiCall(masm(), optimization, argc, &failure); - if (!success) { - return failure; - } + MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc); + if (result->IsFailure()) return result; } else { __ InvokeFunction(function, arguments(), JUMP_FUNCTION); } @@ -2335,21 +2318,17 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); CallInterceptorCompiler compiler(this, arguments(), ecx); - Failure* failure; - bool success = compiler.Compile(masm(), - object, - holder, - name, - &lookup, - edx, - ebx, - edi, - eax, - &miss, - &failure); - if (!success) { - return failure; - } + MaybeObject* result = compiler.Compile(masm(), + object, + holder, + name, + &lookup, + edx, + ebx, + edi, + eax, + &miss); + if (result->IsFailure()) return result; // Restore receiver. __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); @@ -2603,14 +2582,24 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, Immediate(Handle(object->map()))); __ j(not_equal, &miss, not_taken); - // Store the value in the cell. + + // Compute the cell operand to use. + Operand cell_operand = Operand::Cell(Handle(cell)); if (Serializer::enabled()) { __ mov(ecx, Immediate(Handle(cell))); - __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax); - } else { - __ mov(Operand::Cell(Handle(cell)), eax); + cell_operand = FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset); } + // Check that the value in the cell is not the hole. If it is, this + // cell could have been deleted and reintroducing the global needs + // to update the property details in the property dictionary of the + // global object. We bail out to the runtime system to do that. + __ cmp(cell_operand, Factory::the_hole_value()); + __ j(equal, &miss); + + // Store the value in the cell. + __ mov(cell_operand, eax); + // Return the value (register eax). __ IncrementCounter(&Counters::named_store_global_inline, 1); __ ret(0); @@ -2799,12 +2788,11 @@ MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, // ----------------------------------- Label miss; - Failure* failure = Failure::InternalError(); - bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, edi, - callback, name, &miss, &failure); - if (!success) { + MaybeObject* result = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, + edi, callback, name, &miss); + if (result->IsFailure()) { miss.Unuse(); - return failure; + return result; } __ bind(&miss); @@ -2968,12 +2956,11 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( __ cmp(Operand(eax), Immediate(Handle(name))); __ j(not_equal, &miss, not_taken); - Failure* failure = Failure::InternalError(); - bool success = GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, edi, - callback, name, &miss, &failure); - if (!success) { + MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, + ecx, edi, callback, name, &miss); + if (result->IsFailure()) { miss.Unuse(); - return failure; + return result; } __ bind(&miss); @@ -3089,7 +3076,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { __ cmp(Operand(eax), Immediate(Handle(name))); __ j(not_equal, &miss, not_taken); - GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss); + GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); __ bind(&miss); __ DecrementCounter(&Counters::keyed_load_string_length, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index 555ce3f139..9a277d6c0c 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -822,6 +822,9 @@ MaybeObject* LoadIC::Load(State state, } if (FLAG_use_ic) { + Code* non_monomorphic_stub = + (state == UNINITIALIZED) ? pre_monomorphic_stub() : megamorphic_stub(); + // Use specialized code for getting the length of strings and // string wrapper objects. The length property of string wrapper // objects is read-only and therefore always returns the length of @@ -829,22 +832,27 @@ MaybeObject* LoadIC::Load(State state, if ((object->IsString() || object->IsStringWrapper()) && name->Equals(Heap::length_symbol())) { HandleScope scope; - // Get the string if we have a string wrapper object. - if (object->IsJSValue()) { - object = Handle(Handle::cast(object)->value()); - } #ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); #endif - Map* map = HeapObject::cast(*object)->map(); - if (object->IsString()) { - const int offset = String::kLengthOffset; - PatchInlinedLoad(address(), map, offset); + if (state == PREMONOMORPHIC) { + if (object->IsString()) { + Map* map = HeapObject::cast(*object)->map(); + const int offset = String::kLengthOffset; + PatchInlinedLoad(address(), map, offset); + set_target(Builtins::builtin(Builtins::LoadIC_StringLength)); + } else { + set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength)); + } + } else if (state == MONOMORPHIC && object->IsStringWrapper()) { + set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength)); + } else { + set_target(non_monomorphic_stub); + } + // Get the string if we have a string wrapper object. + if (object->IsJSValue()) { + object = Handle(Handle::cast(object)->value()); } - - Code* target = NULL; - target = Builtins::builtin(Builtins::LoadIC_StringLength); - set_target(target); return Smi::FromInt(String::cast(*object)->length()); } @@ -853,12 +861,14 @@ MaybeObject* LoadIC::Load(State state, #ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); #endif - Map* map = HeapObject::cast(*object)->map(); - const int offset = JSArray::kLengthOffset; - PatchInlinedLoad(address(), map, offset); - - Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength); - set_target(target); + if (state == PREMONOMORPHIC) { + Map* map = HeapObject::cast(*object)->map(); + const int offset = JSArray::kLengthOffset; + PatchInlinedLoad(address(), map, offset); + set_target(Builtins::builtin(Builtins::LoadIC_ArrayLength)); + } else { + set_target(non_monomorphic_stub); + } return JSArray::cast(*object)->length(); } @@ -868,8 +878,11 @@ MaybeObject* LoadIC::Load(State state, #ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); #endif - Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype); - set_target(target); + if (state == PREMONOMORPHIC) { + set_target(Builtins::builtin(Builtins::LoadIC_FunctionPrototype)); + } else { + set_target(non_monomorphic_stub); + } return Accessors::FunctionGetPrototype(*object, 0); } } @@ -1092,6 +1105,8 @@ MaybeObject* KeyedLoadIC::Load(State state, } if (FLAG_use_ic) { + // TODO(1073): don't ignore the current stub state. + // Use specialized code for getting the length of strings. if (object->IsString() && name->Equals(Heap::length_symbol())) { Handle string = Handle::cast(object); @@ -2098,8 +2113,6 @@ MaybeObject* TypeRecordingBinaryOp_Patch(Arguments args) { Handle code = GetTypeRecordingBinaryOpStub(key, type, result_type); if (!code.is_null()) { - TRBinaryOpIC ic; - ic.patch(*code); if (FLAG_trace_ic) { PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n", TRBinaryOpIC::GetName(previous_type), @@ -2107,6 +2120,8 @@ MaybeObject* TypeRecordingBinaryOp_Patch(Arguments args) { TRBinaryOpIC::GetName(result_type), Token::Name(op)); } + TRBinaryOpIC ic; + ic.patch(*code); // Activate inlined smi code. if (previous_type == TRBinaryOpIC::UNINITIALIZED) { diff --git a/deps/v8/src/ic.h b/deps/v8/src/ic.h index 55cb34a1cd..409ad3806d 100644 --- a/deps/v8/src/ic.h +++ b/deps/v8/src/ic.h @@ -284,7 +284,8 @@ class LoadIC: public IC { // Specialized code generator routines. static void GenerateArrayLength(MacroAssembler* masm); - static void GenerateStringLength(MacroAssembler* masm); + static void GenerateStringLength(MacroAssembler* masm, + bool support_wrappers); static void GenerateFunctionPrototype(MacroAssembler* masm); // Clear the use of the inlined version. diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc index a946ffa23f..5c649d17d5 100644 --- a/deps/v8/src/mark-compact.cc +++ b/deps/v8/src/mark-compact.cc @@ -33,6 +33,7 @@ #include "gdb-jit.h" #include "global-handles.h" #include "ic-inl.h" +#include "liveobjectlist-inl.h" #include "mark-compact.h" #include "objects-visiting.h" #include "stub-cache.h" @@ -1660,6 +1661,7 @@ inline void EncodeForwardingAddressesInRange(Address start, free_start = current; is_prev_alive = false; } + LiveObjectList::ProcessNonLive(object); } } @@ -1880,6 +1882,9 @@ static void SweepNewSpace(NewSpace* space) { size, false); } else { + // Process the dead object before we write a NULL into its header. + LiveObjectList::ProcessNonLive(object); + size = object->Size(); Memory::Address_at(current) = NULL; } @@ -1899,6 +1904,7 @@ static void SweepNewSpace(NewSpace* space) { // Update roots. Heap::IterateRoots(&updating_visitor, VISIT_ALL_IN_SCAVENGE); + LiveObjectList::IterateElements(&updating_visitor); // Update pointers in old spaces. Heap::IterateDirtyRegions(Heap::old_pointer_space(), @@ -1986,6 +1992,7 @@ static void SweepSpace(PagedSpace* space) { free_start = current; is_previous_alive = false; } + LiveObjectList::ProcessNonLive(object); } // The object is now unmarked for the call to Size() at the top of the // loop. @@ -2164,6 +2171,7 @@ class MapCompact { void UpdateMapPointersInRoots() { Heap::IterateRoots(&map_updating_visitor_, VISIT_ONLY_STRONG); GlobalHandles::IterateWeakRoots(&map_updating_visitor_); + LiveObjectList::IterateElements(&map_updating_visitor_); } void UpdateMapPointersInPagedSpace(PagedSpace* space) { @@ -2533,6 +2541,8 @@ void MarkCompactCollector::UpdatePointers() { // Update the pointer to the head of the weak list of global contexts. updating_visitor.VisitPointer(&Heap::global_contexts_list_); + LiveObjectList::IterateElements(&updating_visitor); + int live_maps_size = IterateLiveObjects(Heap::map_space(), &UpdatePointersInOldObject); int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(), diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index 932d64d2ea..a072d3b473 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -82,20 +82,39 @@ function FormatString(format, args) { var result = format; for (var i = 0; i < args.length; i++) { var str; - try { str = ToDetailString(args[i]); } - catch (e) { str = "#"; } + try { + str = ToDetailString(args[i]); + } catch (e) { + str = "#"; + } result = ArrayJoin.call(StringSplit.call(result, "%" + i), str); } return result; } +// To check if something is a native error we need to check the +// concrete native error types. It is not enough to check "obj +// instanceof $Error" because user code can replace +// NativeError.prototype.__proto__. User code cannot replace +// NativeError.prototype though and therefore this is a safe test. +function IsNativeErrorObject(obj) { + return (obj instanceof $Error) || + (obj instanceof $EvalError) || + (obj instanceof $RangeError) || + (obj instanceof $ReferenceError) || + (obj instanceof $SyntaxError) || + (obj instanceof $TypeError) || + (obj instanceof $URIError); +} + + // When formatting internally created error messages, do not // invoke overwritten error toString methods but explicitly use // the error to string method. This is to avoid leaking error // objects between script tags in a browser setting. function ToStringCheckErrorObject(obj) { - if (obj instanceof $Error) { + if (IsNativeErrorObject(obj)) { return %_CallFunction(obj, errorToString); } else { return ToString(obj); @@ -108,7 +127,9 @@ function ToDetailString(obj) { var constructor = obj.constructor; if (!constructor) return ToStringCheckErrorObject(obj); var constructorName = constructor.name; - if (!constructorName) return ToStringCheckErrorObject(obj); + if (!constructorName || !IS_STRING(constructorName)) { + return ToStringCheckErrorObject(obj); + } return "#<" + GetInstanceName(constructorName) + ">"; } else { return ToStringCheckErrorObject(obj); @@ -216,6 +237,13 @@ function FormatMessage(message) { strict_param_dupe: "Strict mode function may not have duplicate parameter names", strict_var_name: "Variable name may not be eval or arguments in strict mode", strict_function_name: "Function name may not be eval or arguments in strict mode", + strict_octal_literal: "Octal literals are not allowed in strict mode.", + strict_duplicate_property: "Duplicate data property in object literal not allowed in strict mode", + accessor_data_property: "Object literal may not have data and accessor property with the same name", + accessor_get_set: "Object literal may not have multiple get/set accessors with the same name", + strict_lhs_eval_assignment: "Assignment to eval or arguments is not allowed in strict mode", + strict_lhs_postfix: "Postfix increment/decrement may not have eval or arguments operand in strict mode", + strict_lhs_prefix: "Prefix increment/decrement may not have eval or arguments operand in strict mode", }; } var format = kMessages[message.type]; diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 21e318bfce..db9e2ef7b1 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -57,8 +57,7 @@ Smi* PropertyDetails::AsSmi() { PropertyDetails PropertyDetails::AsDeleted() { - PropertyDetails d(DONT_ENUM, NORMAL); - Smi* smi = Smi::FromInt(AsSmi()->value() | DeletedField::encode(1)); + Smi* smi = Smi::FromInt(value_ | DeletedField::encode(1)); return PropertyDetails(smi); } diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 2637281f08..c0976988ea 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -664,7 +664,11 @@ FunctionLiteral* Parser::DoParseProgram(Handle source, TemporaryScope temp_scope(&this->temp_scope_); ZoneList* body = new ZoneList(16); bool ok = true; + int beg_loc = scanner().location().beg_pos; ParseSourceElements(body, Token::EOS, &ok); + if (ok && temp_scope_->StrictMode()) { + CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok); + } if (ok) { result = new FunctionLiteral( no_name, @@ -2288,6 +2292,11 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) { expression = NewThrowReferenceError(type); } + if (temp_scope_->StrictMode()) { + // Assignment to eval or arguments is disallowed in strict mode. + CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK); + } + Token::Value op = Next(); // Get assignment operator. int pos = scanner().location().beg_pos; Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); @@ -2514,6 +2523,12 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { Handle type = Factory::invalid_lhs_in_prefix_op_symbol(); expression = NewThrowReferenceError(type); } + + if (temp_scope_->StrictMode()) { + // Prefix expression operand in strict mode may not be eval or arguments. + CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK); + } + int position = scanner().location().beg_pos; IncrementOperation* increment = new IncrementOperation(op, expression); return new CountOperation(true /* prefix */, increment, position); @@ -2539,6 +2554,12 @@ Expression* Parser::ParsePostfixExpression(bool* ok) { Handle type = Factory::invalid_lhs_in_postfix_op_symbol(); expression = NewThrowReferenceError(type); } + + if (temp_scope_->StrictMode()) { + // Postfix expression operand in strict mode may not be eval or arguments. + CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK); + } + Token::Value next = Next(); int position = scanner().location().beg_pos; IncrementOperation* increment = new IncrementOperation(next, expression); @@ -3012,6 +3033,126 @@ Handle Parser::GetBoilerplateValue(Expression* expression) { return Factory::undefined_value(); } +// Defined in ast.cc +bool IsEqualString(void* first, void* second); +bool IsEqualSmi(void* first, void* second); + + +// Validation per 11.1.5 Object Initialiser +class ObjectLiteralPropertyChecker { + public: + ObjectLiteralPropertyChecker(Parser* parser, bool strict) : + props(&IsEqualString), + elems(&IsEqualSmi), + parser_(parser), + strict_(strict) { + } + + void CheckProperty( + ObjectLiteral::Property* property, + Scanner::Location loc, + bool* ok); + + private: + enum PropertyKind { + kGetAccessor = 0x01, + kSetAccessor = 0x02, + kAccessor = kGetAccessor | kSetAccessor, + kData = 0x04 + }; + + static intptr_t GetPropertyKind(ObjectLiteral::Property* property) { + switch (property->kind()) { + case ObjectLiteral::Property::GETTER: + return kGetAccessor; + case ObjectLiteral::Property::SETTER: + return kSetAccessor; + default: + return kData; + } + } + + HashMap props; + HashMap elems; + Parser* parser_; + bool strict_; +}; + + +void ObjectLiteralPropertyChecker::CheckProperty( + ObjectLiteral::Property* property, + Scanner::Location loc, + bool* ok) { + + ASSERT(property != NULL); + + Literal *lit = property->key(); + Handle handle = lit->handle(); + + uint32_t hash; + HashMap* map; + void* key; + Smi* smi_key_location; + + if (handle->IsSymbol()) { + Handle name(String::cast(*handle)); + if (name->AsArrayIndex(&hash)) { + smi_key_location = Smi::FromInt(hash); + key = &smi_key_location; + map = &elems; + } else { + key = handle.location(); + hash = name->Hash(); + map = &props; + } + } else if (handle->ToArrayIndex(&hash)) { + key = handle.location(); + map = &elems; + } else { + ASSERT(handle->IsNumber()); + double num = handle->Number(); + char arr[100]; + Vector buffer(arr, ARRAY_SIZE(arr)); + const char* str = DoubleToCString(num, buffer); + Handle name = Factory::NewStringFromAscii(CStrVector(str)); + key = name.location(); + hash = name->Hash(); + map = &props; + } + + // Lookup property previously defined, if any. + HashMap::Entry* entry = map->Lookup(key, hash, true); + intptr_t prev = reinterpret_cast (entry->value); + intptr_t curr = GetPropertyKind(property); + + // Duplicate data properties are illegal in strict mode. + if (strict_ && (curr & prev & kData) != 0) { + parser_->ReportMessageAt(loc, "strict_duplicate_property", + Vector::empty()); + *ok = false; + return; + } + // Data property conflicting with an accessor. + if (((curr & kData) && (prev & kAccessor)) || + ((prev & kData) && (curr & kAccessor))) { + parser_->ReportMessageAt(loc, "accessor_data_property", + Vector::empty()); + *ok = false; + return; + } + // Two accessors of the same type conflicting + if ((curr & prev & kAccessor) != 0) { + parser_->ReportMessageAt(loc, "accessor_get_set", + Vector::empty()); + *ok = false; + return; + } + + // Update map + entry->value = reinterpret_cast (prev | curr); + *ok = true; +} + void Parser::BuildObjectLiteralConstantProperties( ZoneList* properties, @@ -3117,12 +3258,20 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { new ZoneList(4); int number_of_boilerplate_properties = 0; + ObjectLiteralPropertyChecker checker(this, temp_scope_->StrictMode()); + Expect(Token::LBRACE, CHECK_OK); + Scanner::Location loc = scanner().location(); + while (peek() != Token::RBRACE) { if (fni_ != NULL) fni_->Enter(); Literal* key = NULL; Token::Value next = peek(); + + // Location of the property name token + Scanner::Location loc = scanner().peek_location(); + switch (next) { case Token::IDENTIFIER: { bool is_getter = false; @@ -3132,11 +3281,15 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { if (fni_ != NULL) fni_->PushLiteralName(id); if ((is_getter || is_setter) && peek() != Token::COLON) { + // Update loc to point to the identifier + loc = scanner().peek_location(); ObjectLiteral::Property* property = ParseObjectLiteralGetSet(is_getter, CHECK_OK); if (IsBoilerplateProperty(property)) { number_of_boilerplate_properties++; } + // Validate the property. + checker.CheckProperty(property, loc, CHECK_OK); properties->Add(property); if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK); @@ -3193,6 +3346,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { // Count CONSTANT or COMPUTED properties to maintain the enumeration order. if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++; + // Validate the property + checker.CheckProperty(property, loc, CHECK_OK); properties->Add(property); // TODO(1240767): Consider allowing trailing comma. @@ -3204,6 +3359,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { } } Expect(Token::RBRACE, CHECK_OK); + // Computation of literal_index must happen before pre parse bailout. int literal_index = temp_scope_->NextMaterializedLiteralIndex(); @@ -3296,10 +3452,21 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle var_name, // '(' (Identifier)*[','] ')' Expect(Token::LPAREN, CHECK_OK); int start_pos = scanner().location().beg_pos; + Scanner::Location name_loc = Scanner::NoLocation(); + Scanner::Location dupe_loc = Scanner::NoLocation(); bool done = (peek() == Token::RPAREN); while (!done) { Handle param_name = ParseIdentifier(CHECK_OK); + + // Store locations for possible future error reports. + if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) { + name_loc = scanner().location(); + } + if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) { + dupe_loc = scanner().location(); + } + Variable* parameter = top_scope_->DeclareLocal(param_name, Variable::VAR); top_scope_->AddParameter(parameter); num_parameters++; @@ -3377,14 +3544,26 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle var_name, if (temp_scope_->StrictMode()) { if (IsEvalOrArguments(name)) { int position = function_token_position != RelocInfo::kNoPosition - ? function_token_position - : (start_pos > 0 ? start_pos - 1 : start_pos); + ? function_token_position + : (start_pos > 0 ? start_pos - 1 : start_pos); ReportMessageAt(Scanner::Location(position, start_pos), "strict_function_name", Vector::empty()); *ok = false; return NULL; } - // TODO(mmaly): Check for octal escape sequence here. + if (name_loc.IsValid()) { + ReportMessageAt(name_loc, "strict_param_name", + Vector::empty()); + *ok = false; + return NULL; + } + if (dupe_loc.IsValid()) { + ReportMessageAt(dupe_loc, "strict_param_dupe", + Vector::empty()); + *ok = false; + return NULL; + } + CheckOctalLiteral(start_pos, end_pos, CHECK_OK); } FunctionLiteral* function_literal = @@ -3531,6 +3710,36 @@ Handle Parser::ParseIdentifierName(bool* ok) { } +// Checks LHS expression for assignment and prefix/postfix increment/decrement +// in strict mode. +void Parser::CheckStrictModeLValue(Expression* expression, + const char* error, + bool* ok) { + ASSERT(temp_scope_->StrictMode()); + VariableProxy* lhs = expression != NULL + ? expression->AsVariableProxy() + : NULL; + + if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) { + ReportMessage(error, Vector::empty()); + *ok = false; + } +} + + +// Checks whether octal literal last seen is between beg_pos and end_pos. +// If so, reports an error. +void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { + int octal = scanner().octal_position(); + if (beg_pos <= octal && octal <= end_pos) { + ReportMessageAt(Scanner::Location(octal, octal + 1), "strict_octal_literal", + Vector::empty()); + scanner().clear_octal_position(); + *ok = false; + } +} + + // This function reads an identifier and determines whether or not it // is 'get' or 'set'. The reason for not using ParseIdentifier and // checking on the output is that this involves heap allocation which diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h index 0613a8de99..68983b42cc 100644 --- a/deps/v8/src/parser.h +++ b/deps/v8/src/parser.h @@ -613,6 +613,14 @@ class Parser { bool* is_set, bool* ok); + // Strict mode validation of LValue expressions + void CheckStrictModeLValue(Expression* expression, + const char* error, + bool* ok); + + // Strict mode octal literal validation. + void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); + // Parser support VariableProxy* Declare(Handle name, Variable::Mode mode, FunctionLiteral* fun, diff --git a/deps/v8/src/platform-freebsd.cc b/deps/v8/src/platform-freebsd.cc index 7174c7f9cb..c18049fec7 100644 --- a/deps/v8/src/platform-freebsd.cc +++ b/deps/v8/src/platform-freebsd.cc @@ -430,7 +430,7 @@ Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { - set_names(name); + set_name(name); } diff --git a/deps/v8/src/runtime-profiler.cc b/deps/v8/src/runtime-profiler.cc index d7792aceae..3406cdc250 100644 --- a/deps/v8/src/runtime-profiler.cc +++ b/deps/v8/src/runtime-profiler.cc @@ -193,22 +193,9 @@ static void AttemptOnStackReplacement(JSFunction* function) { if (maybe_check_code->ToObject(&check_code)) { Code* replacement_code = Builtins::builtin(Builtins::OnStackReplacement); Code* unoptimized_code = shared->code(); - // Iterate the unoptimized code and patch every stack check except at - // the function entry. This code assumes the function entry stack - // check appears first i.e., is not deferred or otherwise reordered. - bool first = true; - for (RelocIterator it(unoptimized_code, RelocInfo::kCodeTargetMask); - !it.done(); - it.next()) { - RelocInfo* rinfo = it.rinfo(); - if (rinfo->target_address() == Code::cast(check_code)->entry()) { - if (first) { - first = false; - } else { - Deoptimizer::PatchStackCheckCode(rinfo, replacement_code); - } - } - } + Deoptimizer::PatchStackCheckCode(unoptimized_code, + Code::cast(check_code), + replacement_code); } } diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 2f1f54c696..b8133ae15e 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -6944,15 +6944,9 @@ static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) { Handle check_code = check_stub.GetCode(); Handle replacement_code( Builtins::builtin(Builtins::OnStackReplacement)); - // Iterate the unoptimized code and revert all the patched stack checks. - for (RelocIterator it(*unoptimized, RelocInfo::kCodeTargetMask); - !it.done(); - it.next()) { - RelocInfo* rinfo = it.rinfo(); - if (rinfo->target_address() == replacement_code->entry()) { - Deoptimizer::RevertStackCheckCode(rinfo, *check_code); - } - } + Deoptimizer::RevertStackCheckCode(*unoptimized, + *check_code, + *replacement_code); // Allow OSR only at nesting level zero again. unoptimized->set_allow_osr_at_loop_nesting_level(0); @@ -7049,7 +7043,7 @@ static MaybeObject* Runtime_PushCatchContext(Arguments args) { } -static MaybeObject* Runtime_LookupContext(Arguments args) { +static MaybeObject* Runtime_DeleteContextSlot(Arguments args) { HandleScope scope; ASSERT(args.length() == 2); @@ -7059,16 +7053,31 @@ static MaybeObject* Runtime_LookupContext(Arguments args) { int index; PropertyAttributes attributes; ContextLookupFlags flags = FOLLOW_CHAINS; - Handle holder = - context->Lookup(name, flags, &index, &attributes); + Handle holder = context->Lookup(name, flags, &index, &attributes); - if (index < 0 && !holder.is_null()) { - ASSERT(holder->IsJSObject()); - return *holder; + // If the slot was not found the result is true. + if (holder.is_null()) { + return Heap::true_value(); } - // No intermediate context found. Use global object by default. - return Top::context()->global(); + // If the slot was found in a context, it should be DONT_DELETE. + if (holder->IsContext()) { + return Heap::false_value(); + } + + // The slot was found in a JSObject, either a context extension object, + // the global object, or an arguments object. Try to delete it + // (respecting DONT_DELETE). For consistency with V8's usual behavior, + // which allows deleting all parameters in functions that mention + // 'arguments', we do this even for the case of slots found on an + // arguments object. The slot was found on an arguments object if the + // index is non-negative. + Handle object = Handle::cast(holder); + if (index >= 0) { + return object->DeleteElement(index, JSObject::NORMAL_DELETION); + } else { + return object->DeleteProperty(*name, JSObject::NORMAL_DELETION); + } } @@ -7141,8 +7150,7 @@ static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) { int index; PropertyAttributes attributes; ContextLookupFlags flags = FOLLOW_CHAINS; - Handle holder = - context->Lookup(name, flags, &index, &attributes); + Handle holder = context->Lookup(name, flags, &index, &attributes); // If the index is non-negative, the slot has been found in a local // variable or a parameter. Read it from the context object or the @@ -7209,8 +7217,7 @@ static MaybeObject* Runtime_StoreContextSlot(Arguments args) { int index; PropertyAttributes attributes; ContextLookupFlags flags = FOLLOW_CHAINS; - Handle holder = - context->Lookup(name, flags, &index, &attributes); + Handle holder = context->Lookup(name, flags, &index, &attributes); if (index >= 0) { if (holder->IsContext()) { diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index dbd8d644b7..d8b34570c3 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -284,7 +284,7 @@ namespace internal { F(NewContext, 1, 1) \ F(PushContext, 1, 1) \ F(PushCatchContext, 1, 1) \ - F(LookupContext, 2, 1) \ + F(DeleteContextSlot, 2, 1) \ F(LoadContextSlot, 2, 2) \ F(LoadContextSlotNoReferenceError, 2, 2) \ F(StoreContextSlot, 3, 1) \ diff --git a/deps/v8/src/safepoint-table.cc b/deps/v8/src/safepoint-table.cc index e79dcff09a..153bf4327f 100644 --- a/deps/v8/src/safepoint-table.cc +++ b/deps/v8/src/safepoint-table.cc @@ -117,24 +117,9 @@ void Safepoint::DefinePointerRegister(Register reg) { } -Safepoint SafepointTableBuilder::DefineSafepoint(Assembler* assembler, - int deoptimization_index) { - ASSERT(deoptimization_index != -1); - DeoptimizationInfo pc_and_deoptimization_index; - pc_and_deoptimization_index.pc = assembler->pc_offset(); - pc_and_deoptimization_index.deoptimization_index = deoptimization_index; - pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset(); - pc_and_deoptimization_index.arguments = 0; - pc_and_deoptimization_index.has_doubles = false; - deoptimization_info_.Add(pc_and_deoptimization_index); - indexes_.Add(new ZoneList(8)); - registers_.Add(NULL); - return Safepoint(indexes_.last(), registers_.last()); -} - - -Safepoint SafepointTableBuilder::DefineSafepointWithRegisters( - Assembler* assembler, int arguments, int deoptimization_index) { +Safepoint SafepointTableBuilder::DefineSafepoint( + Assembler* assembler, Safepoint::Kind kind, int arguments, + int deoptimization_index) { ASSERT(deoptimization_index != -1); ASSERT(arguments >= 0); DeoptimizationInfo pc_and_deoptimization_index; @@ -142,30 +127,16 @@ Safepoint SafepointTableBuilder::DefineSafepointWithRegisters( pc_and_deoptimization_index.deoptimization_index = deoptimization_index; pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset(); pc_and_deoptimization_index.arguments = arguments; - pc_and_deoptimization_index.has_doubles = false; + pc_and_deoptimization_index.has_doubles = (kind & Safepoint::kWithDoubles); deoptimization_info_.Add(pc_and_deoptimization_index); indexes_.Add(new ZoneList(8)); - registers_.Add(new ZoneList(4)); + registers_.Add((kind & Safepoint::kWithRegisters) + ? new ZoneList(4) + : NULL); return Safepoint(indexes_.last(), registers_.last()); } -Safepoint SafepointTableBuilder::DefineSafepointWithRegistersAndDoubles( - Assembler* assembler, int arguments, int deoptimization_index) { - ASSERT(deoptimization_index != -1); - ASSERT(arguments >= 0); - DeoptimizationInfo pc_and_deoptimization_index; - pc_and_deoptimization_index.pc = assembler->pc_offset(); - pc_and_deoptimization_index.deoptimization_index = deoptimization_index; - pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset(); - pc_and_deoptimization_index.arguments = arguments; - pc_and_deoptimization_index.has_doubles = true; - deoptimization_info_.Add(pc_and_deoptimization_index); - indexes_.Add(new ZoneList(8)); - registers_.Add(new ZoneList(4)); - return Safepoint(indexes_.last(), registers_.last()); -} - unsigned SafepointTableBuilder::GetCodeOffset() const { ASSERT(emitted_); return offset_; diff --git a/deps/v8/src/safepoint-table.h b/deps/v8/src/safepoint-table.h index d703051423..fa3590511e 100644 --- a/deps/v8/src/safepoint-table.h +++ b/deps/v8/src/safepoint-table.h @@ -180,6 +180,13 @@ class SafepointTable BASE_EMBEDDED { class Safepoint BASE_EMBEDDED { public: + typedef enum { + kSimple = 0, + kWithRegisters = 1 << 0, + kWithDoubles = 1 << 1, + kWithRegistersAndDoubles = kWithRegisters | kWithDoubles + } Kind; + static const int kNoDeoptimizationIndex = (1 << (SafepointEntry::kDeoptIndexBits)) - 1; @@ -210,23 +217,7 @@ class SafepointTableBuilder BASE_EMBEDDED { // Define a new safepoint for the current position in the body. Safepoint DefineSafepoint( Assembler* assembler, - int deoptimization_index = Safepoint::kNoDeoptimizationIndex); - - // Define a new safepoint with registers on the stack for the - // current position in the body and take the number of arguments on - // top of the registers into account. - Safepoint DefineSafepointWithRegisters( - Assembler* assembler, - int arguments, - int deoptimization_index = Safepoint::kNoDeoptimizationIndex); - - // Define a new safepoint with all double registers and the normal - // registers on the stack for the current position in the body and - // take the number of arguments on top of the registers into account. - // TODO(1043) Rewrite the three SafepointTableBuilder::DefineSafepoint - // methods to one method that uses template arguments. - Safepoint DefineSafepointWithRegistersAndDoubles( - Assembler* assembler, + Safepoint::Kind kind, int arguments, int deoptimization_index = Safepoint::kNoDeoptimizationIndex); diff --git a/deps/v8/src/scanner-base.cc b/deps/v8/src/scanner-base.cc index 997fb312fc..e141d0eb70 100644 --- a/deps/v8/src/scanner-base.cc +++ b/deps/v8/src/scanner-base.cc @@ -64,7 +64,8 @@ bool ScannerConstants::IsIdentifier(unibrow::CharacterStream* buffer) { // ---------------------------------------------------------------------------- // Scanner -Scanner::Scanner() { } +Scanner::Scanner() + : octal_pos_(kNoOctalLocation) { } uc32 Scanner::ScanHexEscape(uc32 c, int length) { @@ -98,6 +99,7 @@ uc32 Scanner::ScanHexEscape(uc32 c, int length) { // Octal escapes of the forms '\0xx' and '\xxx' are not a part of // ECMA-262. Other JS VMs support them. uc32 Scanner::ScanOctalEscape(uc32 c, int length) { + octal_pos_ = source_pos() - 1; // Already advanced uc32 x = c - '0'; for (int i = 0; i < length; i++) { int d = c0_ - '0'; @@ -601,7 +603,11 @@ Token::Value JavaScriptScanner::ScanNumber(bool seen_period) { kind = DECIMAL; break; } - if (c0_ < '0' || '7' < c0_) break; + if (c0_ < '0' || '7' < c0_) { + // Octal literal finished. + octal_pos_ = next_.location.beg_pos; + break; + } AddLiteralCharAdvance(); } } diff --git a/deps/v8/src/scanner-base.h b/deps/v8/src/scanner-base.h index 1024ad1858..3d9800f02a 100644 --- a/deps/v8/src/scanner-base.h +++ b/deps/v8/src/scanner-base.h @@ -247,6 +247,9 @@ class LiteralBuffer { // Generic functionality used by both JSON and JavaScript scanners. class Scanner { public: + // -1 is outside of the range of any real source code. + static const int kNoOctalLocation = -1; + typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder; class LiteralScope { @@ -271,15 +274,28 @@ class Scanner { struct Location { Location(int b, int e) : beg_pos(b), end_pos(e) { } Location() : beg_pos(0), end_pos(0) { } + + bool IsValid() const { + return beg_pos >= 0 && end_pos >= beg_pos; + } + int beg_pos; int end_pos; }; + static Location NoLocation() { + return Location(-1, -1); + } + // Returns the location information for the current token // (the token returned by Next()). Location location() const { return current_.location; } Location peek_location() const { return next_.location; } + // Returns the location of the last seen octal literal + int octal_position() const { return octal_pos_; } + void clear_octal_position() { octal_pos_ = -1; } + // Returns the literal string, if any, for the current token (the // token returned by Next()). The string is 0-terminated and in // UTF-8 format; they may contain 0-characters. Literal strings are @@ -410,6 +426,8 @@ class Scanner { // Input stream. Must be initialized to an UC16CharacterStream. UC16CharacterStream* source_; + // Start position of the octal literal last scanned. + int octal_pos_; // One Unicode character look-ahead; c0_ < 0 at the end of the input. uc32 c0_; diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc index 50da1faf91..d3f54ad3f2 100644 --- a/deps/v8/src/scopes.cc +++ b/deps/v8/src/scopes.cc @@ -726,7 +726,6 @@ void Scope::ResolveVariable(Scope* global_scope, // Note that we must do a lookup anyway, because if we find one, // we must mark that variable as potentially accessed from this // inner scope (the property may not be in the 'with' object). - if (var != NULL) var->set_is_used(true); var = NonLocal(proxy->name(), Variable::DYNAMIC); } else { @@ -834,8 +833,8 @@ bool Scope::MustAllocate(Variable* var) { // visible name. if ((var->is_this() || var->name()->length() > 0) && (var->is_accessed_from_inner_scope() || - scope_calls_eval_ || - inner_scope_calls_eval_)) { + scope_calls_eval_ || inner_scope_calls_eval_ || + scope_contains_with_)) { var->set_is_used(true); } // Global variables do not need to be allocated. diff --git a/deps/v8/src/scopes.h b/deps/v8/src/scopes.h index 09901ade61..a9220eb827 100644 --- a/deps/v8/src/scopes.h +++ b/deps/v8/src/scopes.h @@ -288,6 +288,17 @@ class Scope: public ZoneObject { // The number of contexts between this and scope; zero if this == scope. int ContextChainLength(Scope* scope); + // --------------------------------------------------------------------------- + // Strict mode support. + bool IsDeclared(Handle name) { + // During formal parameter list parsing the scope only contains + // two variables inserted at initialization: "this" and "arguments". + // "this" is an invalid parameter name and "arguments" is invalid parameter + // name in strict mode. Therefore looking up with the map which includes + // "this" and "arguments" in addition to all formal parameters is safe. + return variables_.Lookup(name) != NULL; + } + // --------------------------------------------------------------------------- // Debugging. diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc index 6a6c6bbdb1..60c2cbb69d 100644 --- a/deps/v8/src/serialize.cc +++ b/deps/v8/src/serialize.cc @@ -335,7 +335,7 @@ void ExternalReferenceTable::PopulateTable() { Add(ExternalReference::delete_handle_scope_extensions().address(), RUNTIME_ENTRY, - 3, + 4, "HandleScope::DeleteExtensions"); // Miscellaneous @@ -504,7 +504,7 @@ void ExternalReferenceTable::PopulateTable() { "power_double_int_function"); Add(ExternalReference::arguments_marker_location().address(), UNCLASSIFIED, - 40, + 41, "Factory::arguments_marker().location()"); } diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index fca1032969..a586fbf904 100644 --- a/deps/v8/src/spaces.cc +++ b/deps/v8/src/spaces.cc @@ -27,6 +27,7 @@ #include "v8.h" +#include "liveobjectlist-inl.h" #include "macro-assembler.h" #include "mark-compact.h" #include "platform.h" @@ -3125,6 +3126,8 @@ void LargeObjectSpace::FreeUnmarkedObjects() { // Free the chunk. MarkCompactCollector::ReportDeleteIfNeeded(object); + LiveObjectList::ProcessNonLive(object); + size_ -= static_cast(chunk_size); objects_size_ -= object->Size(); page_count_--; diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h index 1f534d9aad..07f894a512 100644 --- a/deps/v8/src/stub-cache.h +++ b/deps/v8/src/stub-cache.h @@ -427,7 +427,8 @@ class StubCompiler BASE_EMBEDDED { Register receiver, Register scratch1, Register scratch2, - Label* miss_label); + Label* miss_label, + bool support_wrappers); static void GenerateLoadFunctionPrototype(MacroAssembler* masm, Register receiver, @@ -501,17 +502,16 @@ class StubCompiler BASE_EMBEDDED { String* name, Label* miss); - bool GenerateLoadCallback(JSObject* object, - JSObject* holder, - Register receiver, - Register name_reg, - Register scratch1, - Register scratch2, - Register scratch3, - AccessorInfo* callback, - String* name, - Label* miss, - Failure** failure); + MaybeObject* GenerateLoadCallback(JSObject* object, + JSObject* holder, + Register receiver, + Register name_reg, + Register scratch1, + Register scratch2, + Register scratch3, + AccessorInfo* callback, + String* name, + Label* miss); void GenerateLoadConstant(JSObject* object, JSObject* holder, diff --git a/deps/v8/src/top.cc b/deps/v8/src/top.cc index 98c673c1b8..e32eb6bc8b 100644 --- a/deps/v8/src/top.cc +++ b/deps/v8/src/top.cc @@ -72,7 +72,7 @@ void ThreadLocalTop::Initialize() { handler_ = 0; #ifdef USE_SIMULATOR #ifdef V8_TARGET_ARCH_ARM - simulator_ = assembler::arm::Simulator::current(); + simulator_ = Simulator::current(); #elif V8_TARGET_ARCH_MIPS simulator_ = assembler::mips::Simulator::current(); #endif @@ -806,7 +806,7 @@ void Top::ComputeLocation(MessageLocation* target) { } -bool Top::ShouldReturnException(bool* is_caught_externally, +bool Top::ShouldReportException(bool* is_caught_externally, bool catchable_by_javascript) { // Find the top-most try-catch handler. StackHandler* handler = @@ -847,15 +847,15 @@ void Top::DoThrow(MaybeObject* exception, Handle exception_handle(exception_object); // Determine reporting and whether the exception is caught externally. - bool is_caught_externally = false; bool is_out_of_memory = exception == Failure::OutOfMemoryException(); bool is_termination_exception = exception == Heap::termination_exception(); bool catchable_by_javascript = !is_termination_exception && !is_out_of_memory; // Only real objects can be caught by JS. ASSERT(!catchable_by_javascript || is_object); - bool should_return_exception = - ShouldReturnException(&is_caught_externally, catchable_by_javascript); - bool report_exception = catchable_by_javascript && should_return_exception; + bool is_caught_externally = false; + bool should_report_exception = + ShouldReportException(&is_caught_externally, catchable_by_javascript); + bool report_exception = catchable_by_javascript && should_report_exception; #ifdef ENABLE_DEBUGGER_SUPPORT // Notify debugger of exception. @@ -1095,7 +1095,7 @@ char* Top::RestoreThread(char* from) { // thread_local_ is restored on a separate OS thread. #ifdef USE_SIMULATOR #ifdef V8_TARGET_ARCH_ARM - thread_local_.simulator_ = assembler::arm::Simulator::current(); + thread_local_.simulator_ = Simulator::current(); #elif V8_TARGET_ARCH_MIPS thread_local_.simulator_ = assembler::mips::Simulator::current(); #endif diff --git a/deps/v8/src/top.h b/deps/v8/src/top.h index e485de1032..5b0fd6157c 100644 --- a/deps/v8/src/top.h +++ b/deps/v8/src/top.h @@ -109,7 +109,7 @@ class ThreadLocalTop BASE_EMBEDDED { #ifdef USE_SIMULATOR #ifdef V8_TARGET_ARCH_ARM - assembler::arm::Simulator* simulator_; + Simulator* simulator_; #elif V8_TARGET_ARCH_MIPS assembler::mips::Simulator* simulator_; #endif @@ -386,7 +386,9 @@ class Top { static void DoThrow(MaybeObject* exception, MessageLocation* location, const char* message); - static bool ShouldReturnException(bool* is_caught_externally, + // Checks if exception should be reported and finds out if it's + // caught externally. + static bool ShouldReportException(bool* is_caught_externally, bool catchable_by_javascript); // Attempts to compute the current source location, storing the diff --git a/deps/v8/src/type-info.cc b/deps/v8/src/type-info.cc index f4f65e99b4..0bb7262128 100644 --- a/deps/v8/src/type-info.cc +++ b/deps/v8/src/type-info.cc @@ -171,7 +171,7 @@ bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) { } -TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr, Side side) { +TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) { Handle object = GetElement(map_, expr->position()); TypeInfo unknown = TypeInfo::Unknown(); if (!object->IsCode()) return unknown; @@ -198,7 +198,7 @@ TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr, Side side) { } -TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr, Side side) { +TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) { Handle object = GetElement(map_, expr->position()); TypeInfo unknown = TypeInfo::Unknown(); if (!object->IsCode()) return unknown; diff --git a/deps/v8/src/type-info.h b/deps/v8/src/type-info.h index e026e88c0f..c7029c8823 100644 --- a/deps/v8/src/type-info.h +++ b/deps/v8/src/type-info.h @@ -236,12 +236,6 @@ class CaseClause; class TypeFeedbackOracle BASE_EMBEDDED { public: - enum Side { - LEFT, - RIGHT, - RESULT - }; - TypeFeedbackOracle(Handle code, Handle global_context); bool LoadIsMonomorphic(Property* expr); @@ -261,8 +255,8 @@ class TypeFeedbackOracle BASE_EMBEDDED { bool LoadIsBuiltin(Property* expr, Builtins::Name id); // Get type information for arithmetic operations and compares. - TypeInfo BinaryType(BinaryOperation* expr, Side side); - TypeInfo CompareType(CompareOperation* expr, Side side); + TypeInfo BinaryType(BinaryOperation* expr); + TypeInfo CompareType(CompareOperation* expr); TypeInfo SwitchType(CaseClause* clause); private: diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc index f5b6150bd1..c5a5775e5b 100644 --- a/deps/v8/src/v8.cc +++ b/deps/v8/src/v8.cc @@ -79,7 +79,7 @@ bool V8::Initialize(Deserializer* des) { // Initialize other runtime facilities #if defined(USE_SIMULATOR) #if defined(V8_TARGET_ARCH_ARM) - ::assembler::arm::Simulator::Initialize(); + Simulator::Initialize(); #elif defined(V8_TARGET_ARCH_MIPS) ::assembler::mips::Simulator::Initialize(); #endif diff --git a/deps/v8/src/variables.cc b/deps/v8/src/variables.cc index 7f580fc6f0..fa7ce1b0c5 100644 --- a/deps/v8/src/variables.cc +++ b/deps/v8/src/variables.cc @@ -112,12 +112,12 @@ Variable::Variable(Scope* scope, : scope_(scope), name_(name), mode_(mode), - is_valid_LHS_(is_valid_LHS), kind_(kind), local_if_not_shadowed_(NULL), + rewrite_(NULL), + is_valid_LHS_(is_valid_LHS), is_accessed_from_inner_scope_(false), - is_used_(false), - rewrite_(NULL) { + is_used_(false) { // names must be canonicalized for fast equality checks ASSERT(name->IsSymbol()); } diff --git a/deps/v8/src/variables.h b/deps/v8/src/variables.h index 882a52ed82..5d27a02d53 100644 --- a/deps/v8/src/variables.h +++ b/deps/v8/src/variables.h @@ -187,21 +187,23 @@ class Variable: public ZoneObject { Scope* scope_; Handle name_; Mode mode_; - bool is_valid_LHS_; Kind kind_; Variable* local_if_not_shadowed_; - // Usage info. - bool is_accessed_from_inner_scope_; // set by variable resolver - bool is_used_; - // Static type information StaticType type_; // Code generation. // rewrite_ is usually a Slot or a Property, but may be any expression. Expression* rewrite_; + + // Valid as a LHS? (const and this are not valid LHS, for example) + bool is_valid_LHS_; + + // Usage info. + bool is_accessed_from_inner_scope_; // set by variable resolver + bool is_used_; }; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index a2659a1c33..6c5ffd97d6 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 0 -#define BUILD_NUMBER 10 +#define BUILD_NUMBER 12 #define PATCH_LEVEL 0 #define CANDIDATE_VERSION false diff --git a/deps/v8/src/x64/assembler-x64-inl.h b/deps/v8/src/x64/assembler-x64-inl.h index 70b40e07c8..440645222f 100644 --- a/deps/v8/src/x64/assembler-x64-inl.h +++ b/deps/v8/src/x64/assembler-x64-inl.h @@ -425,7 +425,7 @@ void Operand::set_sib(ScaleFactor scale, Register index, Register base) { // Use SIB with no index register only for base rsp or r12. Otherwise we // would skip the SIB byte entirely. ASSERT(!index.is(rsp) || base.is(rsp) || base.is(r12)); - buf_[1] = scale << 6 | index.low_bits() << 3 | base.low_bits(); + buf_[1] = (scale << 6) | (index.low_bits() << 3) | base.low_bits(); rex_ |= index.high_bit() << 1 | base.high_bit(); len_ = 2; } diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc index 0f866a4b99..999306e378 100644 --- a/deps/v8/src/x64/assembler-x64.cc +++ b/deps/v8/src/x64/assembler-x64.cc @@ -300,6 +300,34 @@ Operand::Operand(const Operand& operand, int32_t offset) { } } + +bool Operand::AddressUsesRegister(Register reg) const { + int code = reg.code(); + ASSERT((buf_[0] & 0xC0) != 0xC0); // Always a memory operand. + // Start with only low three bits of base register. Initial decoding doesn't + // distinguish on the REX.B bit. + int base_code = buf_[0] & 0x07; + if (base_code == rsp.code()) { + // SIB byte present in buf_[1]. + // Check the index register from the SIB byte + REX.X prefix. + int index_code = ((buf_[1] >> 3) & 0x07) | ((rex_ & 0x02) << 2); + // Index code (including REX.X) of 0x04 (rsp) means no index register. + if (index_code != rsp.code() && index_code == code) return true; + // Add REX.B to get the full base register code. + base_code = (buf_[1] & 0x07) | ((rex_ & 0x01) << 3); + // A base register of 0x05 (rbp) with mod = 0 means no base register. + if (base_code == rbp.code() && ((buf_[0] & 0xC0) == 0)) return false; + return code == base_code; + } else { + // A base register with low bits of 0x05 (rbp or r13) and mod = 0 means + // no base register. + if (base_code == rbp.code() && ((buf_[0] & 0xC0) == 0)) return false; + base_code |= ((rex_ & 0x01) << 3); + return code == base_code; + } +} + + // ----------------------------------------------------------------------------- // Implementation of Assembler. @@ -1949,6 +1977,14 @@ void Assembler::push(Immediate value) { } +void Assembler::push_imm32(int32_t imm32) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0x68); + emitl(imm32); +} + + void Assembler::pushfq() { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -2641,6 +2677,30 @@ void Assembler::movq(Register dst, XMMRegister src) { } +void Assembler::movdqa(const Operand& dst, XMMRegister src) { + ASSERT(CpuFeatures::IsEnabled(SSE2)); + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0x66); + emit_rex_64(src, dst); + emit(0x0F); + emit(0x7F); + emit_sse_operand(src, dst); +} + + +void Assembler::movdqa(XMMRegister dst, const Operand& src) { + ASSERT(CpuFeatures::IsEnabled(SSE2)); + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0x66); + emit_rex_64(dst, src); + emit(0x0F); + emit(0x6F); + emit_sse_operand(dst, src); +} + + void Assembler::extractps(Register dst, XMMRegister src, byte imm8) { ASSERT(is_uint2(imm8)); EnsureSpace ensure_space(this); diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h index 890cd8ac5b..29817a3161 100644 --- a/deps/v8/src/x64/assembler-x64.h +++ b/deps/v8/src/x64/assembler-x64.h @@ -153,6 +153,7 @@ struct Register { // Unfortunately we can't make this private in a struct when initializing // by assignment. int code_; + private: static const int registerCodeByAllocationIndex[kNumAllocatableRegisters]; static const int allocationIndexByRegisterCode[kNumRegisters]; @@ -390,11 +391,15 @@ class Operand BASE_EMBEDDED { // this must not overflow. Operand(const Operand& base, int32_t offset); + // Checks whether either base or index register is the given register. + // Does not check the "reg" part of the Operand. + bool AddressUsesRegister(Register reg) const; + private: byte rex_; byte buf_[6]; - // The number of bytes in buf_. - unsigned int len_; + // The number of bytes of buf_ in use. + byte len_; // Set the ModR/M byte without an encoded 'reg' register. The // register is encoded later as part of the emit_operand operation. @@ -590,6 +595,9 @@ class Assembler : public Malloced { void popfq(); void push(Immediate value); + // Push a 32 bit integer, and guarantee that it is actually pushed as a + // 32 bit value, the normal push will optimize the 8 bit case. + void push_imm32(int32_t imm32); void push(Register src); void push(const Operand& src); @@ -821,6 +829,10 @@ class Assembler : public Malloced { arithmetic_op_32(0x23, dst, src); } + void andl(Register dst, const Operand& src) { + arithmetic_op_32(0x23, dst, src); + } + void andb(Register dst, Immediate src) { immediate_arithmetic_op_8(0x4, dst, src); } @@ -1205,6 +1217,9 @@ class Assembler : public Malloced { void movsd(XMMRegister dst, XMMRegister src); void movsd(XMMRegister dst, const Operand& src); + void movdqa(const Operand& dst, XMMRegister src); + void movdqa(XMMRegister dst, const Operand& src); + void movss(XMMRegister dst, const Operand& src); void movss(const Operand& dst, XMMRegister src); @@ -1245,10 +1260,6 @@ class Assembler : public Malloced { void emit_sse_operand(XMMRegister dst, Register src); void emit_sse_operand(Register dst, XMMRegister src); - // Use either movsd or movlpd. - // void movdbl(XMMRegister dst, const Operand& src); - // void movdbl(const Operand& dst, XMMRegister src); - // Debugging void Print(); diff --git a/deps/v8/src/x64/builtins-x64.cc b/deps/v8/src/x64/builtins-x64.cc index d738261a1b..079dc8a590 100644 --- a/deps/v8/src/x64/builtins-x64.cc +++ b/deps/v8/src/x64/builtins-x64.cc @@ -561,7 +561,33 @@ void Builtins::Generate_LazyRecompile(MacroAssembler* masm) { static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, Deoptimizer::BailoutType type) { - __ int3(); + // Enter an internal frame. + __ EnterInternalFrame(); + + // Pass the deoptimization type to the runtime system. + __ Push(Smi::FromInt(static_cast(type))); + + __ CallRuntime(Runtime::kNotifyDeoptimized, 1); + // Tear down temporary frame. + __ LeaveInternalFrame(); + + // Get the full codegen state from the stack and untag it. + __ SmiToInteger32(rcx, Operand(rsp, 1 * kPointerSize)); + + // Switch on the state. + NearLabel not_no_registers, not_tos_rax; + __ cmpq(rcx, Immediate(FullCodeGenerator::NO_REGISTERS)); + __ j(not_equal, ¬_no_registers); + __ ret(1 * kPointerSize); // Remove state. + + __ bind(¬_no_registers); + __ movq(rax, Operand(rsp, 2 * kPointerSize)); + __ cmpq(rcx, Immediate(FullCodeGenerator::TOS_REG)); + __ j(not_equal, ¬_tos_rax); + __ ret(2 * kPointerSize); // Remove state, rax. + + __ bind(¬_tos_rax); + __ Abort("no cases left"); } void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index a261b9d086..e38591580b 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -91,7 +91,8 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) { void FastNewContextStub::Generate(MacroAssembler* masm) { // Try to allocate the context in new space. Label gc; - __ AllocateInNewSpace((slots_ * kPointerSize) + FixedArray::kHeaderSize, + int length = slots_ + Context::MIN_CONTEXT_SLOTS; + __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, rax, rbx, rcx, &gc, TAG_OBJECT); // Get the function from the stack. @@ -100,7 +101,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { // Setup the object header. __ LoadRoot(kScratchRegister, Heap::kContextMapRootIndex); __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister); - __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(slots_)); + __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length)); // Setup the fixed slots. __ Set(rbx, 0); // Set to NULL. @@ -115,7 +116,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { // Initialize the rest of the slots to undefined. __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); - for (int i = Context::MIN_CONTEXT_SLOTS; i < slots_; i++) { + for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { __ movq(Operand(rax, Context::SlotOffset(i)), rbx); } @@ -2773,8 +2774,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_termination_exception, Label* throw_out_of_memory_exception, bool do_gc, - bool always_allocate_scope, - int /* alignment_skew */) { + bool always_allocate_scope) { // rax: result parameter for PerformGC, if any. // rbx: pointer to C function (C callee-saved). // rbp: frame pointer (restored after C call). @@ -2867,7 +2867,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, __ j(zero, &failure_returned); // Exit the JavaScript to C++ exit frame. - __ LeaveExitFrame(); + __ LeaveExitFrame(save_doubles_); __ ret(0); // Handling of failure. @@ -2976,7 +2976,7 @@ void CEntryStub::Generate(MacroAssembler* masm) { #else int arg_stack_space = 0; #endif - __ EnterExitFrame(arg_stack_space); + __ EnterExitFrame(arg_stack_space, save_doubles_); // rax: Holds the context at this point, but should not be used. // On entry to code generated by GenerateCore, it must hold diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index 57720a8019..bebe4682d6 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -206,7 +206,7 @@ void CodeGenerator::Generate(CompilationInfo* info) { frame_->AllocateStackSlots(); // Allocate the local context if needed. - int heap_slots = scope()->num_heap_slots(); + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; if (heap_slots > 0) { Comment cmnt(masm_, "[ allocate local context"); // Allocate local context. @@ -7235,19 +7235,13 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { return; } else if (slot != NULL && slot->type() == Slot::LOOKUP) { - // Call the runtime to look up the context holding the named + // Call the runtime to delete from the context holding the named // variable. Sync the virtual frame eagerly so we can push the // arguments directly into place. frame_->SyncRange(0, frame_->element_count() - 1); frame_->EmitPush(rsi); frame_->EmitPush(variable->name()); - Result context = frame_->CallRuntime(Runtime::kLookupContext, 2); - ASSERT(context.is_register()); - frame_->EmitPush(context.reg()); - context.Unuse(); - frame_->EmitPush(variable->name()); - Result answer = frame_->InvokeBuiltin(Builtins::DELETE, - CALL_FUNCTION, 2); + Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); frame_->Push(&answer); return; } diff --git a/deps/v8/src/x64/deoptimizer-x64.cc b/deps/v8/src/x64/deoptimizer-x64.cc index 6b19d3f141..60d46ef2bb 100644 --- a/deps/v8/src/x64/deoptimizer-x64.cc +++ b/deps/v8/src/x64/deoptimizer-x64.cc @@ -41,18 +41,82 @@ namespace internal { int Deoptimizer::table_entry_size_ = 10; void Deoptimizer::DeoptimizeFunction(JSFunction* function) { - // UNIMPLEMENTED, for now just return. - return; + AssertNoAllocation no_allocation; + + if (!function->IsOptimized()) return; + + // Get the optimized code. + Code* code = function->code(); + + // Invalidate the relocation information, as it will become invalid by the + // code patching below, and is not needed any more. + code->InvalidateRelocation(); + + // For each return after a safepoint insert a absolute call to the + // corresponding deoptimization entry. + unsigned last_pc_offset = 0; + SafepointTable table(function->code()); + for (unsigned i = 0; i < table.length(); i++) { + unsigned pc_offset = table.GetPcOffset(i); + SafepointEntry safepoint_entry = table.GetEntry(i); + int deoptimization_index = safepoint_entry.deoptimization_index(); + int gap_code_size = safepoint_entry.gap_code_size(); +#ifdef DEBUG + // Destroy the code which is not supposed to run again. + unsigned instructions = pc_offset - last_pc_offset; + CodePatcher destroyer(code->instruction_start() + last_pc_offset, + instructions); + for (unsigned i = 0; i < instructions; i++) { + destroyer.masm()->int3(); + } +#endif + last_pc_offset = pc_offset; + if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { + CodePatcher patcher( + code->instruction_start() + pc_offset + gap_code_size, + Assembler::kCallInstructionLength); + patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY), + RelocInfo::NONE); + last_pc_offset += gap_code_size + Assembler::kCallInstructionLength; + } + } +#ifdef DEBUG + // Destroy the code which is not supposed to run again. + CHECK(code->safepoint_table_start() >= last_pc_offset); + unsigned instructions = code->safepoint_table_start() - last_pc_offset; + CodePatcher destroyer(code->instruction_start() + last_pc_offset, + instructions); + for (unsigned i = 0; i < instructions; i++) { + destroyer.masm()->int3(); + } +#endif + + // Add the deoptimizing code to the list. + DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); + node->set_next(deoptimizing_code_list_); + deoptimizing_code_list_ = node; + + // Set the code for the function to non-optimized version. + function->ReplaceCode(function->shared()->code()); + + if (FLAG_trace_deopt) { + PrintF("[forced deoptimization: "); + function->PrintName(); + PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast(function)); + } } -void Deoptimizer::PatchStackCheckCode(RelocInfo* rinfo, +void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code, + Code* check_code, Code* replacement_code) { UNIMPLEMENTED(); } -void Deoptimizer::RevertStackCheckCode(RelocInfo* rinfo, Code* check_code) { +void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code, + Code* check_code, + Code* replacement_code) { UNIMPLEMENTED(); } @@ -64,20 +128,382 @@ void Deoptimizer::DoComputeOsrOutputFrame() { void Deoptimizer::DoComputeFrame(TranslationIterator* iterator, int frame_index) { - UNIMPLEMENTED(); + // Read the ast node id, function, and frame height for this output frame. + Translation::Opcode opcode = + static_cast(iterator->Next()); + USE(opcode); + ASSERT(Translation::FRAME == opcode); + int node_id = iterator->Next(); + JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); + unsigned height = iterator->Next(); + unsigned height_in_bytes = height * kPointerSize; + if (FLAG_trace_deopt) { + PrintF(" translating "); + function->PrintName(); + PrintF(" => node=%d, height=%d\n", node_id, height_in_bytes); + } + + // The 'fixed' part of the frame consists of the incoming parameters and + // the part described by JavaScriptFrameConstants. + unsigned fixed_frame_size = ComputeFixedSize(function); + unsigned input_frame_size = static_cast(input_->GetFrameSize()); + unsigned output_frame_size = height_in_bytes + fixed_frame_size; + + // Allocate and store the output frame description. + FrameDescription* output_frame = + new(output_frame_size) FrameDescription(output_frame_size, function); + + bool is_bottommost = (0 == frame_index); + bool is_topmost = (output_count_ - 1 == frame_index); + ASSERT(frame_index >= 0 && frame_index < output_count_); + ASSERT(output_[frame_index] == NULL); + output_[frame_index] = output_frame; + + // The top address for the bottommost output frame can be computed from + // the input frame pointer and the output frame's height. For all + // subsequent output frames, it can be computed from the previous one's + // top address and the current frame's size. + intptr_t top_address; + if (is_bottommost) { + // 2 = context and function in the frame. + top_address = + input_->GetRegister(rbp.code()) - (2 * kPointerSize) - height_in_bytes; + } else { + top_address = output_[frame_index - 1]->GetTop() - output_frame_size; + } + output_frame->SetTop(top_address); + + // Compute the incoming parameter translation. + int parameter_count = function->shared()->formal_parameter_count() + 1; + unsigned output_offset = output_frame_size; + unsigned input_offset = input_frame_size; + for (int i = 0; i < parameter_count; ++i) { + output_offset -= kPointerSize; + DoTranslateCommand(iterator, frame_index, output_offset); + } + input_offset -= (parameter_count * kPointerSize); + + // There are no translation commands for the caller's pc and fp, the + // context, and the function. Synthesize their values and set them up + // explicitly. + // + // The caller's pc for the bottommost output frame is the same as in the + // input frame. For all subsequent output frames, it can be read from the + // previous one. This frame's pc can be computed from the non-optimized + // function code and AST id of the bailout. + output_offset -= kPointerSize; + input_offset -= kPointerSize; + intptr_t value; + if (is_bottommost) { + value = input_->GetFrameSlot(input_offset); + } else { + value = output_[frame_index - 1]->GetPc(); + } + output_frame->SetFrameSlot(output_offset, value); + if (FLAG_trace_deopt) { + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" + V8PRIxPTR " ; caller's pc\n", + top_address + output_offset, output_offset, value); + } + + // The caller's frame pointer for the bottommost output frame is the same + // as in the input frame. For all subsequent output frames, it can be + // read from the previous one. Also compute and set this frame's frame + // pointer. + output_offset -= kPointerSize; + input_offset -= kPointerSize; + if (is_bottommost) { + value = input_->GetFrameSlot(input_offset); + } else { + value = output_[frame_index - 1]->GetFp(); + } + output_frame->SetFrameSlot(output_offset, value); + intptr_t fp_value = top_address + output_offset; + ASSERT(!is_bottommost || input_->GetRegister(rbp.code()) == fp_value); + output_frame->SetFp(fp_value); + if (is_topmost) output_frame->SetRegister(rbp.code(), fp_value); + if (FLAG_trace_deopt) { + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" + V8PRIxPTR " ; caller's fp\n", + fp_value, output_offset, value); + } + + // The context can be gotten from the function so long as we don't + // optimize functions that need local contexts. + output_offset -= kPointerSize; + input_offset -= kPointerSize; + value = reinterpret_cast(function->context()); + // The context for the bottommost output frame should also agree with the + // input frame. + ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); + output_frame->SetFrameSlot(output_offset, value); + if (is_topmost) output_frame->SetRegister(rsi.code(), value); + if (FLAG_trace_deopt) { + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" + V8PRIxPTR "; context\n", + top_address + output_offset, output_offset, value); + } + + // The function was mentioned explicitly in the BEGIN_FRAME. + output_offset -= kPointerSize; + input_offset -= kPointerSize; + value = reinterpret_cast(function); + // The function for the bottommost output frame should also agree with the + // input frame. + ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); + output_frame->SetFrameSlot(output_offset, value); + if (FLAG_trace_deopt) { + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" + V8PRIxPTR "; function\n", + top_address + output_offset, output_offset, value); + } + + // Translate the rest of the frame. + for (unsigned i = 0; i < height; ++i) { + output_offset -= kPointerSize; + DoTranslateCommand(iterator, frame_index, output_offset); + } + ASSERT(0 == output_offset); + + // Compute this frame's PC, state, and continuation. + Code* non_optimized_code = function->shared()->code(); + FixedArray* raw_data = non_optimized_code->deoptimization_data(); + DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); + Address start = non_optimized_code->instruction_start(); + unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); + unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); + intptr_t pc_value = reinterpret_cast(start + pc_offset); + output_frame->SetPc(pc_value); + + FullCodeGenerator::State state = + FullCodeGenerator::StateField::decode(pc_and_state); + output_frame->SetState(Smi::FromInt(state)); + + // Set the continuation for the topmost frame. + if (is_topmost) { + Code* continuation = (bailout_type_ == EAGER) + ? Builtins::builtin(Builtins::NotifyDeoptimized) + : Builtins::builtin(Builtins::NotifyLazyDeoptimized); + output_frame->SetContinuation( + reinterpret_cast(continuation->entry())); + } + + if (output_count_ - 1 == frame_index) iterator->Done(); } +#define __ masm()-> + void Deoptimizer::EntryGenerator::Generate() { - // UNIMPLEMENTED, for now just return. - return; + GeneratePrologue(); + CpuFeatures::Scope scope(SSE2); + + // Save all general purpose registers before messing with them. + const int kNumberOfRegisters = Register::kNumRegisters; + + const int kDoubleRegsSize = kDoubleSize * + XMMRegister::kNumAllocatableRegisters; + __ subq(rsp, Immediate(kDoubleRegsSize)); + + for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) { + XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i); + int offset = i * kDoubleSize; + __ movsd(Operand(rsp, offset), xmm_reg); + } + + // We push all registers onto the stack, even though we do not need + // to restore all later. + for (int i = 0; i < kNumberOfRegisters; i++) { + Register r = Register::toRegister(i); + __ push(r); + } + + const int kSavedRegistersAreaSize = kNumberOfRegisters * kPointerSize + + kDoubleRegsSize; + + // When calling new_deoptimizer_function we need to pass the last argument + // on the stack on windows and in r8 on linux. The remaining arguments are + // all passed in registers (different ones on linux and windows though). + +#ifdef _WIN64 + Register arg4 = r9; + Register arg3 = r8; + Register arg2 = rdx; + Register arg1 = rcx; +#else + Register arg4 = rcx; + Register arg3 = rdx; + Register arg2 = rsi; + Register arg1 = rdi; +#endif + + // We use this to keep the value of the fifth argument temporarily. + // Unfortunately we can't store it directly in r8 (used for passing + // this on linux), since it is another parameter passing register on windows. + Register arg5 = r11; + + // Get the bailout id from the stack. + __ movq(arg3, Operand(rsp, kSavedRegistersAreaSize)); + + // Get the address of the location in the code object if possible + // and compute the fp-to-sp delta in register arg5. + if (type() == EAGER) { + __ Set(arg4, 0); + __ lea(arg5, Operand(rsp, kSavedRegistersAreaSize + 1 * kPointerSize)); + } else { + __ movq(arg4, Operand(rsp, kSavedRegistersAreaSize + 1 * kPointerSize)); + __ lea(arg5, Operand(rsp, kSavedRegistersAreaSize + 2 * kPointerSize)); + } + + __ subq(arg5, rbp); + __ neg(arg5); + + // Allocate a new deoptimizer object. + __ PrepareCallCFunction(5); + __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); + __ movq(arg1, rax); + __ movq(arg2, Immediate(type())); + // Args 3 and 4 are already in the right registers. + + // On windows put the argument on the stack (PrepareCallCFunction have + // created space for this). On linux pass the argument in r8. +#ifdef _WIN64 + __ movq(Operand(rsp, 0 * kPointerSize), arg5); +#else + __ movq(r8, arg5); +#endif + + __ CallCFunction(ExternalReference::new_deoptimizer_function(), 5); + // Preserve deoptimizer object in register rax and get the input + // frame descriptor pointer. + __ movq(rbx, Operand(rax, Deoptimizer::input_offset())); + + // Fill in the input registers. + for (int i = kNumberOfRegisters -1; i >= 0; i--) { + int offset = (i * kPointerSize) + FrameDescription::registers_offset(); + __ pop(Operand(rbx, offset)); + } + + // Fill in the double input registers. + int double_regs_offset = FrameDescription::double_registers_offset(); + for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) { + int dst_offset = i * kDoubleSize + double_regs_offset; + __ pop(Operand(rbx, dst_offset)); + } + + // Remove the bailout id from the stack. + if (type() == EAGER) { + __ addq(rsp, Immediate(kPointerSize)); + } else { + __ addq(rsp, Immediate(2 * kPointerSize)); + } + + // Compute a pointer to the unwinding limit in register ecx; that is + // the first stack slot not part of the input frame. + __ movq(rcx, Operand(rbx, FrameDescription::frame_size_offset())); + __ addq(rcx, rsp); + + // Unwind the stack down to - but not including - the unwinding + // limit and copy the contents of the activation frame to the input + // frame description. + __ lea(rdx, Operand(rbx, FrameDescription::frame_content_offset())); + Label pop_loop; + __ bind(&pop_loop); + __ pop(Operand(rdx, 0)); + __ addq(rdx, Immediate(sizeof(intptr_t))); + __ cmpq(rcx, rsp); + __ j(not_equal, &pop_loop); + + // Compute the output frame in the deoptimizer. + __ push(rax); + __ PrepareCallCFunction(1); + __ movq(arg1, rax); + __ CallCFunction(ExternalReference::compute_output_frames_function(), 1); + __ pop(rax); + + // Replace the current frame with the output frames. + Label outer_push_loop, inner_push_loop; + // Outer loop state: rax = current FrameDescription**, rdx = one past the + // last FrameDescription**. + __ movl(rdx, Operand(rax, Deoptimizer::output_count_offset())); + __ movq(rax, Operand(rax, Deoptimizer::output_offset())); + __ lea(rdx, Operand(rax, rdx, times_8, 0)); + __ bind(&outer_push_loop); + // Inner loop state: rbx = current FrameDescription*, rcx = loop index. + __ movq(rbx, Operand(rax, 0)); + __ movq(rcx, Operand(rbx, FrameDescription::frame_size_offset())); + __ bind(&inner_push_loop); + __ subq(rcx, Immediate(sizeof(intptr_t))); + __ push(Operand(rbx, rcx, times_1, FrameDescription::frame_content_offset())); + __ testq(rcx, rcx); + __ j(not_zero, &inner_push_loop); + __ addq(rax, Immediate(kPointerSize)); + __ cmpq(rax, rdx); + __ j(below, &outer_push_loop); + + // In case of OSR, we have to restore the XMM registers. + if (type() == OSR) { + for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) { + XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i); + int src_offset = i * kDoubleSize + double_regs_offset; + __ movsd(xmm_reg, Operand(rbx, src_offset)); + } + } + + // Push state, pc, and continuation from the last output frame. + if (type() != OSR) { + __ push(Operand(rbx, FrameDescription::state_offset())); + } + __ push(Operand(rbx, FrameDescription::pc_offset())); + __ push(Operand(rbx, FrameDescription::continuation_offset())); + + // Push the registers from the last output frame. + for (int i = 0; i < kNumberOfRegisters; i++) { + int offset = (i * kPointerSize) + FrameDescription::registers_offset(); + __ push(Operand(rbx, offset)); + } + + // Restore the registers from the stack. + for (int i = kNumberOfRegisters - 1; i >= 0 ; i--) { + Register r = Register::toRegister(i); + // Do not restore rsp, simply pop the value into the next register + // and overwrite this afterwards. + if (r.is(rsp)) { + ASSERT(i > 0); + r = Register::toRegister(i - 1); + } + __ pop(r); + } + + // Set up the roots register. + ExternalReference roots_address = ExternalReference::roots_address(); + __ movq(r13, roots_address); + + __ movq(kSmiConstantRegister, + reinterpret_cast(Smi::FromInt(kSmiConstantRegisterValue)), + RelocInfo::NONE); + + // Return to the continuation point. + __ ret(0); } void Deoptimizer::TableEntryGenerator::GeneratePrologue() { - UNIMPLEMENTED(); + // Create a sequence of deoptimization entries. + Label done; + for (int i = 0; i < count(); i++) { + int start = masm()->pc_offset(); + USE(start); + __ push_imm32(i); + __ jmp(&done); + ASSERT(masm()->pc_offset() - start == table_entry_size_); + } + __ bind(&done); } +#undef __ + + } } // namespace v8::internal #endif // V8_TARGET_ARCH_X64 diff --git a/deps/v8/src/x64/disasm-x64.cc b/deps/v8/src/x64/disasm-x64.cc index 8fdf20b7be..92a8a7d3cd 100644 --- a/deps/v8/src/x64/disasm-x64.cc +++ b/deps/v8/src/x64/disasm-x64.cc @@ -1025,11 +1025,19 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { rex_w() ? 'q' : 'd', NameOfXMMRegister(regop)); current += PrintRightOperand(current); + } else if (opcode == 0x6F) { + AppendToBuffer("movdqa %s,", + NameOfXMMRegister(regop)); + current += PrintRightOperand(current); } else if (opcode == 0x7E) { AppendToBuffer("mov%c ", rex_w() ? 'q' : 'd'); current += PrintRightOperand(current); AppendToBuffer(", %s", NameOfXMMRegister(regop)); + } else if (opcode == 0x7F) { + AppendToBuffer("movdqa "); + current += PrintRightOperand(current); + AppendToBuffer(", %s", NameOfXMMRegister(regop)); } else { const char* mnemonic = "?"; if (opcode == 0x57) { diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index 896e53da60..8b7f3c2b2c 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -88,7 +88,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { bool function_in_register = true; // Possibly allocate a local context. - int heap_slots = scope()->num_heap_slots(); + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; if (heap_slots > 0) { Comment cmnt(masm_, "[ Allocate local context"); // Argument to NewContext is the function, which is still in rdi. @@ -710,6 +710,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // Compile all the tests with branches to their bodies. for (int i = 0; i < clauses->length(); i++) { CaseClause* clause = clauses->at(i); + clause->body_target()->entry_label()->Unuse(); + // The default is not a test, but remember it as final fall through. if (clause->is_default()) { default_clause = clause; @@ -3006,19 +3008,18 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { if (prop != NULL) { VisitForStackValue(prop->obj()); VisitForStackValue(prop->key()); + __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); } else if (var->is_global()) { __ push(GlobalObjectOperand()); __ Push(var->name()); + __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); } else { - // Non-global variable. Call the runtime to look up the context - // where the variable was introduced. + // Non-global variable. Call the runtime to delete from the + // context where the variable was introduced. __ push(context_register()); __ Push(var->name()); - __ CallRuntime(Runtime::kLookupContext, 2); - __ push(rax); - __ Push(var->name()); + __ CallRuntime(Runtime::kDeleteContextSlot, 2); } - __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); context()->Plug(rax); } break; diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc index e31a341dc3..d060e31ced 100644 --- a/deps/v8/src/x64/ic-x64.cc +++ b/deps/v8/src/x64/ic-x64.cc @@ -397,7 +397,7 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) { } -void LoadIC::GenerateStringLength(MacroAssembler* masm) { +void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) { // ----------- S t a t e ------------- // -- rax : receiver // -- rcx : name @@ -405,7 +405,8 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) { // ----------------------------------- Label miss; - StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss); + StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss, + support_wrappers); __ bind(&miss); StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index dc988b1a65..513c98407c 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -37,157 +37,6 @@ namespace v8 { namespace internal { -class LGapNode: public ZoneObject { - public: - explicit LGapNode(LOperand* operand) - : operand_(operand), resolved_(false), visited_id_(-1) { } - - LOperand* operand() const { return operand_; } - bool IsResolved() const { return !IsAssigned() || resolved_; } - void MarkResolved() { - ASSERT(!IsResolved()); - resolved_ = true; - } - int visited_id() const { return visited_id_; } - void set_visited_id(int id) { - ASSERT(id > visited_id_); - visited_id_ = id; - } - - bool IsAssigned() const { return assigned_from_.is_set(); } - LGapNode* assigned_from() const { return assigned_from_.get(); } - void set_assigned_from(LGapNode* n) { assigned_from_.set(n); } - - private: - LOperand* operand_; - SetOncePointer assigned_from_; - bool resolved_; - int visited_id_; -}; - - -LGapResolver::LGapResolver() - : nodes_(32), - identified_cycles_(4), - result_(16), - next_visited_id_(0) { -} - - -const ZoneList* LGapResolver::Resolve( - const ZoneList* moves, - LOperand* marker_operand) { - nodes_.Rewind(0); - identified_cycles_.Rewind(0); - result_.Rewind(0); - next_visited_id_ = 0; - - for (int i = 0; i < moves->length(); ++i) { - LMoveOperands move = moves->at(i); - if (!move.IsRedundant()) RegisterMove(move); - } - - for (int i = 0; i < identified_cycles_.length(); ++i) { - ResolveCycle(identified_cycles_[i], marker_operand); - } - - int unresolved_nodes; - do { - unresolved_nodes = 0; - for (int j = 0; j < nodes_.length(); j++) { - LGapNode* node = nodes_[j]; - if (!node->IsResolved() && node->assigned_from()->IsResolved()) { - AddResultMove(node->assigned_from(), node); - node->MarkResolved(); - } - if (!node->IsResolved()) ++unresolved_nodes; - } - } while (unresolved_nodes > 0); - return &result_; -} - - -void LGapResolver::AddResultMove(LGapNode* from, LGapNode* to) { - AddResultMove(from->operand(), to->operand()); -} - - -void LGapResolver::AddResultMove(LOperand* from, LOperand* to) { - result_.Add(LMoveOperands(from, to)); -} - - -void LGapResolver::ResolveCycle(LGapNode* start, LOperand* marker_operand) { - ZoneList cycle_operands(8); - cycle_operands.Add(marker_operand); - LGapNode* cur = start; - do { - cur->MarkResolved(); - cycle_operands.Add(cur->operand()); - cur = cur->assigned_from(); - } while (cur != start); - cycle_operands.Add(marker_operand); - - for (int i = cycle_operands.length() - 1; i > 0; --i) { - LOperand* from = cycle_operands[i]; - LOperand* to = cycle_operands[i - 1]; - AddResultMove(from, to); - } -} - - -bool LGapResolver::CanReach(LGapNode* a, LGapNode* b, int visited_id) { - ASSERT(a != b); - LGapNode* cur = a; - while (cur != b && cur->visited_id() != visited_id && cur->IsAssigned()) { - cur->set_visited_id(visited_id); - cur = cur->assigned_from(); - } - - return cur == b; -} - - -bool LGapResolver::CanReach(LGapNode* a, LGapNode* b) { - ASSERT(a != b); - return CanReach(a, b, next_visited_id_++); -} - - -void LGapResolver::RegisterMove(LMoveOperands move) { - if (move.source()->IsConstantOperand()) { - // Constant moves should be last in the machine code. Therefore add them - // first to the result set. - AddResultMove(move.source(), move.destination()); - } else { - LGapNode* from = LookupNode(move.source()); - LGapNode* to = LookupNode(move.destination()); - if (to->IsAssigned() && to->assigned_from() == from) { - move.Eliminate(); - return; - } - ASSERT(!to->IsAssigned()); - if (CanReach(from, to)) { - // This introduces a cycle. Save. - identified_cycles_.Add(from); - } - to->set_assigned_from(from); - } -} - - -LGapNode* LGapResolver::LookupNode(LOperand* operand) { - for (int i = 0; i < nodes_.length(); ++i) { - if (nodes_[i]->operand()->Equals(operand)) return nodes_[i]; - } - - // No node found => create a new one. - LGapNode* result = new LGapNode(operand); - nodes_.Add(result); - return result; -} - - #define __ masm()-> bool LCodeGen::GenerateCode() { @@ -339,6 +188,10 @@ bool LCodeGen::GenerateDeferredCode() { bool LCodeGen::GenerateSafepointTable() { ASSERT(is_done()); + // Ensure that patching a deoptimization point won't overwrite the table. + for (int i = 0; i < Assembler::kCallInstructionLength; i++) { + masm()->int3(); + } safepoints_.Emit(masm(), StackSlotCount()); return !is_aborted(); } @@ -567,7 +420,24 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { - Abort("Unimplemented: %s", "Deoptimiz"); + RegisterEnvironmentForDeoptimization(environment); + ASSERT(environment->HasBeenRegistered()); + int id = environment->deoptimization_index(); + Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); + ASSERT(entry != NULL); + if (entry == NULL) { + Abort("bailout was not prepared"); + return; + } + + if (cc == no_condition) { + __ Jump(entry, RelocInfo::RUNTIME_ENTRY); + } else { + NearLabel done; + __ j(NegateCondition(cc), &done); + __ Jump(entry, RelocInfo::RUNTIME_ENTRY); + __ bind(&done); + } } @@ -629,37 +499,40 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() { } -void LCodeGen::RecordSafepoint(LPointerMap* pointers, - int deoptimization_index) { +void LCodeGen::RecordSafepoint( + LPointerMap* pointers, + Safepoint::Kind kind, + int arguments, + int deoptimization_index) { const ZoneList* operands = pointers->operands(); Safepoint safepoint = safepoints_.DefineSafepoint(masm(), - deoptimization_index); + kind, arguments, deoptimization_index); for (int i = 0; i < operands->length(); i++) { LOperand* pointer = operands->at(i); if (pointer->IsStackSlot()) { safepoint.DefinePointerSlot(pointer->index()); + } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { + safepoint.DefinePointerRegister(ToRegister(pointer)); } } + if (kind & Safepoint::kWithRegisters) { + // Register rsi always contains a pointer to the context. + safepoint.DefinePointerRegister(rsi); + } +} + + +void LCodeGen::RecordSafepoint(LPointerMap* pointers, + int deoptimization_index) { + RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); } void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, int deoptimization_index) { - const ZoneList* operands = pointers->operands(); - Safepoint safepoint = - safepoints_.DefineSafepointWithRegisters( - masm(), arguments, deoptimization_index); - for (int i = 0; i < operands->length(); i++) { - LOperand* pointer = operands->at(i); - if (pointer->IsStackSlot()) { - safepoint.DefinePointerSlot(pointer->index()); - } else if (pointer->IsRegister()) { - safepoint.DefinePointerRegister(ToRegister(pointer)); - } - } - // Register rsi always contains a pointer to the context. - safepoint.DefinePointerRegister(rsi); + RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, + deoptimization_index); } @@ -682,86 +555,7 @@ void LCodeGen::DoLabel(LLabel* label) { void LCodeGen::DoParallelMove(LParallelMove* move) { - // xmm0 must always be a scratch register. - XMMRegister xmm_scratch = xmm0; - LUnallocated marker_operand(LUnallocated::NONE); - - Register cpu_scratch = kScratchRegister; - - const ZoneList* moves = - resolver_.Resolve(move->move_operands(), &marker_operand); - for (int i = moves->length() - 1; i >= 0; --i) { - LMoveOperands move = moves->at(i); - LOperand* from = move.source(); - LOperand* to = move.destination(); - ASSERT(!from->IsDoubleRegister() || - !ToDoubleRegister(from).is(xmm_scratch)); - ASSERT(!to->IsDoubleRegister() || !ToDoubleRegister(to).is(xmm_scratch)); - ASSERT(!from->IsRegister() || !ToRegister(from).is(cpu_scratch)); - ASSERT(!to->IsRegister() || !ToRegister(to).is(cpu_scratch)); - if (from->IsConstantOperand()) { - LConstantOperand* constant_from = LConstantOperand::cast(from); - if (to->IsRegister()) { - if (IsInteger32Constant(constant_from)) { - __ movl(ToRegister(to), Immediate(ToInteger32(constant_from))); - } else { - __ Move(ToRegister(to), ToHandle(constant_from)); - } - } else { - if (IsInteger32Constant(constant_from)) { - __ movl(ToOperand(to), Immediate(ToInteger32(constant_from))); - } else { - __ Move(ToOperand(to), ToHandle(constant_from)); - } - } - } else if (from == &marker_operand) { - if (to->IsRegister()) { - __ movq(ToRegister(to), cpu_scratch); - } else if (to->IsStackSlot()) { - __ movq(ToOperand(to), cpu_scratch); - } else if (to->IsDoubleRegister()) { - __ movsd(ToDoubleRegister(to), xmm_scratch); - } else { - ASSERT(to->IsDoubleStackSlot()); - __ movsd(ToOperand(to), xmm_scratch); - } - } else if (to == &marker_operand) { - if (from->IsRegister()) { - __ movq(cpu_scratch, ToRegister(from)); - } else if (from->IsStackSlot()) { - __ movq(cpu_scratch, ToOperand(from)); - } else if (from->IsDoubleRegister()) { - __ movsd(xmm_scratch, ToDoubleRegister(from)); - } else { - ASSERT(from->IsDoubleStackSlot()); - __ movsd(xmm_scratch, ToOperand(from)); - } - } else if (from->IsRegister()) { - if (to->IsRegister()) { - __ movq(ToRegister(to), ToRegister(from)); - } else { - __ movq(ToOperand(to), ToRegister(from)); - } - } else if (to->IsRegister()) { - __ movq(ToRegister(to), ToOperand(from)); - } else if (from->IsStackSlot()) { - ASSERT(to->IsStackSlot()); - __ push(rax); - __ movq(rax, ToOperand(from)); - __ movq(ToOperand(to), rax); - __ pop(rax); - } else if (from->IsDoubleRegister()) { - ASSERT(to->IsDoubleStackSlot()); - __ movsd(ToOperand(to), ToDoubleRegister(from)); - } else if (to->IsDoubleRegister()) { - ASSERT(from->IsDoubleStackSlot()); - __ movsd(ToDoubleRegister(to), ToOperand(from)); - } else { - ASSERT(to->IsDoubleStackSlot() && from->IsDoubleStackSlot()); - __ movsd(xmm_scratch, ToOperand(from)); - __ movsd(ToOperand(to), xmm_scratch); - } - } + resolver_.Resolve(move); } @@ -820,7 +614,22 @@ void LCodeGen::DoShiftI(LShiftI* instr) { void LCodeGen::DoSubI(LSubI* instr) { - Abort("Unimplemented: %s", "DoSubI"); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); + ASSERT(left->Equals(instr->result())); + + if (right->IsConstantOperand()) { + __ subl(ToRegister(left), + Immediate(ToInteger32(LConstantOperand::cast(right)))); + } else if (right->IsRegister()) { + __ subl(ToRegister(left), ToRegister(right)); + } else { + __ subl(ToRegister(left), ToOperand(right)); + } + + if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { + DeoptimizeIf(overflow, instr->environment()); + } } @@ -1146,7 +955,18 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { - Abort("Unimplemented: %s", "DoCmpJSObjectEq"); + Register left = ToRegister(instr->InputAt(0)); + Register right = ToRegister(instr->InputAt(1)); + Register result = ToRegister(instr->result()); + + NearLabel different, done; + __ cmpq(left, right); + __ j(not_equal, &different); + __ LoadRoot(result, Heap::kTrueValueRootIndex); + __ jmp(&done); + __ bind(&different); + __ LoadRoot(result, Heap::kFalseValueRootIndex); + __ bind(&done); } @@ -1162,7 +982,45 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { void LCodeGen::DoIsNull(LIsNull* instr) { - Abort("Unimplemented: %s", "DoIsNull"); + Register reg = ToRegister(instr->InputAt(0)); + Register result = ToRegister(instr->result()); + + // If the expression is known to be a smi, then it's + // definitely not null. Materialize false. + // Consider adding other type and representation tests too. + if (instr->hydrogen()->value()->type().IsSmi()) { + __ LoadRoot(result, Heap::kFalseValueRootIndex); + return; + } + + __ CompareRoot(reg, Heap::kNullValueRootIndex); + if (instr->is_strict()) { + __ movl(result, Immediate(Heap::kTrueValueRootIndex)); + NearLabel load; + __ j(equal, &load); + __ movl(result, Immediate(Heap::kFalseValueRootIndex)); + __ bind(&load); + __ movq(result, Operand(kRootRegister, result, times_pointer_size, 0)); + } else { + NearLabel true_value, false_value, done; + __ j(equal, &true_value); + __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); + __ j(equal, &true_value); + __ JumpIfSmi(reg, &false_value); + // Check for undetectable objects by looking in the bit field in + // the map. The object has already been smi checked. + Register scratch = result; + __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); + __ testb(FieldOperand(scratch, Map::kBitFieldOffset), + Immediate(1 << Map::kIsUndetectable)); + __ j(not_zero, &true_value); + __ bind(&false_value); + __ LoadRoot(result, Heap::kFalseValueRootIndex); + __ jmp(&done); + __ bind(&true_value); + __ LoadRoot(result, Heap::kTrueValueRootIndex); + __ bind(&done); + } } @@ -1204,56 +1062,77 @@ void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { Condition LCodeGen::EmitIsObject(Register input, - Register temp1, - Register temp2, Label* is_not_object, Label* is_object) { - ASSERT(!input.is(temp1)); - ASSERT(!input.is(temp2)); - ASSERT(!temp1.is(temp2)); + ASSERT(!input.is(kScratchRegister)); __ JumpIfSmi(input, is_not_object); - __ Cmp(input, Factory::null_value()); + __ CompareRoot(input, Heap::kNullValueRootIndex); __ j(equal, is_object); - __ movq(temp1, FieldOperand(input, HeapObject::kMapOffset)); + __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); // Undetectable objects behave like undefined. - __ testb(FieldOperand(temp1, Map::kBitFieldOffset), + __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), Immediate(1 << Map::kIsUndetectable)); __ j(not_zero, is_not_object); - __ movzxbl(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset)); - __ cmpb(temp2, Immediate(FIRST_JS_OBJECT_TYPE)); + __ movzxbl(kScratchRegister, + FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); + __ cmpb(kScratchRegister, Immediate(FIRST_JS_OBJECT_TYPE)); __ j(below, is_not_object); - __ cmpb(temp2, Immediate(LAST_JS_OBJECT_TYPE)); + __ cmpb(kScratchRegister, Immediate(LAST_JS_OBJECT_TYPE)); return below_equal; } void LCodeGen::DoIsObject(LIsObject* instr) { - Abort("Unimplemented: %s", "DoIsObject"); + Register reg = ToRegister(instr->InputAt(0)); + Register result = ToRegister(instr->result()); + Label is_false, is_true, done; + + Condition true_cond = EmitIsObject(reg, &is_false, &is_true); + __ j(true_cond, &is_true); + + __ bind(&is_false); + __ LoadRoot(result, Heap::kFalseValueRootIndex); + __ jmp(&done); + + __ bind(&is_true); + __ LoadRoot(result, Heap::kTrueValueRootIndex); + + __ bind(&done); } void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { Register reg = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); - Register temp2 = ToRegister(instr->TempAt(1)); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); Label* true_label = chunk_->GetAssemblyLabel(true_block); Label* false_label = chunk_->GetAssemblyLabel(false_block); - Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label); + Condition true_cond = EmitIsObject(reg, false_label, true_label); EmitBranch(true_block, false_block, true_cond); } void LCodeGen::DoIsSmi(LIsSmi* instr) { - Abort("Unimplemented: %s", "DoIsSmi"); + LOperand* input_operand = instr->InputAt(0); + Register result = ToRegister(instr->result()); + if (input_operand->IsRegister()) { + Register input = ToRegister(input_operand); + __ CheckSmiToIndicator(result, input); + } else { + Operand input = ToOperand(instr->InputAt(0)); + __ CheckSmiToIndicator(result, input); + } + // result is zero if input is a smi, and one otherwise. + ASSERT(Heap::kFalseValueRootIndex == Heap::kTrueValueRootIndex + 1); + __ movq(result, Operand(kRootRegister, result, times_pointer_size, + Heap::kTrueValueRootIndex * kPointerSize)); } @@ -1386,7 +1265,25 @@ void LCodeGen::EmitClassOfTest(Label* is_true, void LCodeGen::DoClassOfTest(LClassOfTest* instr) { - Abort("Unimplemented: %s", "DoClassOfTest"); + Register input = ToRegister(instr->InputAt(0)); + Register result = ToRegister(instr->result()); + ASSERT(input.is(result)); + Register temp = ToRegister(instr->TempAt(0)); + Handle class_name = instr->hydrogen()->class_name(); + NearLabel done; + Label is_true, is_false; + + EmitClassOfTest(&is_true, &is_false, class_name, input, temp); + + __ j(not_equal, &is_false); + + __ bind(&is_true); + __ LoadRoot(result, Heap::kTrueValueRootIndex); + __ jmp(&done); + + __ bind(&is_false); + __ LoadRoot(result, Heap::kFalseValueRootIndex); + __ bind(&done); } @@ -1408,7 +1305,12 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { - Abort("Unimplemented: %s", "DoCmpMapAndBranch"); + Register reg = ToRegister(instr->InputAt(0)); + int true_block = instr->true_block_id(); + int false_block = instr->false_block_id(); + + __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); + EmitBranch(true_block, false_block, equal); } @@ -1493,12 +1395,32 @@ void LCodeGen::DoReturn(LReturn* instr) { void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) { - Abort("Unimplemented: %s", "DoLoadGlobal"); + Register result = ToRegister(instr->result()); + if (result.is(rax)) { + __ load_rax(instr->hydrogen()->cell().location(), + RelocInfo::GLOBAL_PROPERTY_CELL); + } else { + __ movq(result, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); + __ movq(result, Operand(result, 0)); + } + if (instr->hydrogen()->check_hole_value()) { + __ CompareRoot(result, Heap::kTheHoleValueRootIndex); + DeoptimizeIf(equal, instr->environment()); + } } void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { - Abort("Unimplemented: %s", "DoStoreGlobal"); + Register value = ToRegister(instr->InputAt(0)); + if (value.is(rax)) { + __ store_rax(instr->hydrogen()->cell().location(), + RelocInfo::GLOBAL_PROPERTY_CELL); + } else { + __ movq(kScratchRegister, + Handle::cast(instr->hydrogen()->cell()), + RelocInfo::GLOBAL_PROPERTY_CELL); + __ movq(Operand(kScratchRegister, 0), value); + } } @@ -1508,7 +1430,14 @@ void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { - Abort("Unimplemented: %s", "DoLoadNamedField"); + Register object = ToRegister(instr->InputAt(0)); + Register result = ToRegister(instr->result()); + if (instr->hydrogen()->is_in_object()) { + __ movq(result, FieldOperand(object, instr->hydrogen()->offset())); + } else { + __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); + __ movq(result, FieldOperand(result, instr->hydrogen()->offset())); + } } @@ -1558,17 +1487,39 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { - Abort("Unimplemented: %s", "DoPushArgument"); + LOperand* argument = instr->InputAt(0); + if (argument->IsConstantOperand()) { + LConstantOperand* const_op = LConstantOperand::cast(argument); + Handle literal = chunk_->LookupLiteral(const_op); + Representation r = chunk_->LookupLiteralRepresentation(const_op); + if (r.IsInteger32()) { + ASSERT(literal->IsNumber()); + __ push(Immediate(static_cast(literal->Number()))); + } else if (r.IsDouble()) { + Abort("unsupported double immediate"); + } else { + ASSERT(r.IsTagged()); + __ Push(literal); + } + } else if (argument->IsRegister()) { + __ push(ToRegister(argument)); + } else { + ASSERT(!argument->IsDoubleRegister()); + __ push(ToOperand(argument)); + } } void LCodeGen::DoGlobalObject(LGlobalObject* instr) { - Abort("Unimplemented: %s", "DoGlobalObject"); + Register result = ToRegister(instr->result()); + __ movq(result, GlobalObjectOperand()); } void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { - Abort("Unimplemented: %s", "DoGlobalReceiver"); + Register result = ToRegister(instr->result()); + __ movq(result, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ movq(result, FieldOperand(result, GlobalObject::kGlobalReceiverOffset)); } @@ -1665,7 +1616,12 @@ void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { void LCodeGen::DoCallNew(LCallNew* instr) { - Abort("Unimplemented: %s", "DoCallNew"); + ASSERT(ToRegister(instr->InputAt(0)).is(rdi)); + ASSERT(ToRegister(instr->result()).is(rax)); + + Handle builtin(Builtins::builtin(Builtins::JSConstructCall)); + __ Set(rax, instr->arity()); + CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr); } @@ -1675,7 +1631,32 @@ void LCodeGen::DoCallRuntime(LCallRuntime* instr) { void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { - Abort("Unimplemented: %s", "DoStoreNamedField"); + Register object = ToRegister(instr->object()); + Register value = ToRegister(instr->value()); + int offset = instr->offset(); + + if (!instr->transition().is_null()) { + __ Move(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); + } + + // Do the store. + if (instr->is_in_object()) { + __ movq(FieldOperand(object, offset), value); + if (instr->needs_write_barrier()) { + Register temp = ToRegister(instr->TempAt(0)); + // Update the write barrier for the object for in-object properties. + __ RecordWrite(object, offset, value, temp); + } + } else { + Register temp = ToRegister(instr->TempAt(0)); + __ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset)); + __ movq(FieldOperand(temp, offset), value); + if (instr->needs_write_barrier()) { + // Update the write barrier for the properties array. + // object is used as a scratch register. + __ RecordWrite(temp, offset, value, object); + } + } } @@ -1700,27 +1681,63 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { - Abort("Unimplemented: %s", "DoInteger32ToDouble"); + LOperand* input = instr->InputAt(0); + ASSERT(input->IsRegister() || input->IsStackSlot()); + LOperand* output = instr->result(); + ASSERT(output->IsDoubleRegister()); + __ cvtlsi2sd(ToDoubleRegister(output), ToOperand(input)); } void LCodeGen::DoNumberTagI(LNumberTagI* instr) { - Abort("Unimplemented: %s", "DoNumberTagI"); -} - + LOperand* input = instr->InputAt(0); + ASSERT(input->IsRegister() && input->Equals(instr->result())); + Register reg = ToRegister(input); -void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { - Abort("Unimplemented: %s", "DoDeferredNumberTagI"); + __ Integer32ToSmi(reg, reg); } void LCodeGen::DoNumberTagD(LNumberTagD* instr) { - Abort("Unimplemented: %s", "DoNumberTagD"); + class DeferredNumberTagD: public LDeferredCode { + public: + DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) + : LDeferredCode(codegen), instr_(instr) { } + virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } + private: + LNumberTagD* instr_; + }; + + XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->result()); + Register tmp = ToRegister(instr->TempAt(0)); + + DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); + if (FLAG_inline_new) { + __ AllocateHeapNumber(reg, tmp, deferred->entry()); + } else { + __ jmp(deferred->entry()); + } + __ bind(deferred->exit()); + __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); } void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { - Abort("Unimplemented: %s", "DoDeferredNumberTagD"); + // TODO(3095996): Get rid of this. For now, we need to make the + // result register contain a valid pointer because it is already + // contained in the register pointer map. + Register reg = ToRegister(instr->result()); + __ Move(reg, Smi::FromInt(0)); + + __ PushSafepointRegisters(); + __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); + RecordSafepointWithRegisters( + instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); + // Ensure that value in rax survives popping registers. + __ movq(kScratchRegister, rax); + __ PopSafepointRegisters(); + __ movq(reg, kScratchRegister); } @@ -1737,7 +1754,34 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { void LCodeGen::EmitNumberUntagD(Register input_reg, XMMRegister result_reg, LEnvironment* env) { - Abort("Unimplemented: %s", "EmitNumberUntagD"); + NearLabel load_smi, heap_number, done; + + // Smi check. + __ JumpIfSmi(input_reg, &load_smi); + + // Heap number map check. + __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), + Heap::kHeapNumberMapRootIndex); + __ j(equal, &heap_number); + + __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex); + DeoptimizeIf(not_equal, env); + + // Convert undefined to NaN. Compute NaN as 0/0. + __ xorpd(result_reg, result_reg); + __ divsd(result_reg, result_reg); + __ jmp(&done); + + // Heap number to XMM conversion. + __ bind(&heap_number); + __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); + __ jmp(&done); + + // Smi to XMM conversion + __ bind(&load_smi); + __ SmiToInteger32(kScratchRegister, input_reg); // Untag smi first. + __ cvtlsi2sd(result_reg, kScratchRegister); + __ bind(&done); } @@ -1762,7 +1806,13 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { void LCodeGen::DoCheckSmi(LCheckSmi* instr) { - Abort("Unimplemented: %s", "DoCheckSmi"); + LOperand* input = instr->InputAt(0); + ASSERT(input->IsRegister()); + Condition cc = masm()->CheckSmi(ToRegister(input)); + if (instr->condition() != equal) { + cc = NegateCondition(cc); + } + DeoptimizeIf(cc, instr->environment()); } @@ -1772,12 +1822,20 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { void LCodeGen::DoCheckFunction(LCheckFunction* instr) { - Abort("Unimplemented: %s", "DoCheckFunction"); + ASSERT(instr->InputAt(0)->IsRegister()); + Register reg = ToRegister(instr->InputAt(0)); + __ Cmp(reg, instr->hydrogen()->target()); + DeoptimizeIf(not_equal, instr->environment()); } void LCodeGen::DoCheckMap(LCheckMap* instr) { - Abort("Unimplemented: %s", "DoCheckMap"); + LOperand* input = instr->InputAt(0); + ASSERT(input->IsRegister()); + Register reg = ToRegister(input); + __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), + instr->hydrogen()->map()); + DeoptimizeIf(not_equal, instr->environment()); } @@ -1787,7 +1845,29 @@ void LCodeGen::LoadHeapObject(Register result, Handle object) { void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { - Abort("Unimplemented: %s", "DoCheckPrototypeMaps"); + Register reg = ToRegister(instr->TempAt(0)); + + Handle holder = instr->holder(); + Handle current_prototype = instr->prototype(); + + // Load prototype object. + LoadHeapObject(reg, current_prototype); + + // Check prototype maps up to the holder. + while (!current_prototype.is_identical_to(holder)) { + __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), + Handle(current_prototype->map())); + DeoptimizeIf(not_equal, instr->environment()); + current_prototype = + Handle(JSObject::cast(current_prototype->GetPrototype())); + // Load next prototype object. + LoadHeapObject(reg, current_prototype); + } + + // Check the holder map. + __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), + Handle(current_prototype->map())); + DeoptimizeIf(not_equal, instr->environment()); } diff --git a/deps/v8/src/x64/lithium-codegen-x64.h b/deps/v8/src/x64/lithium-codegen-x64.h index 4ce7004625..cbcc5c8b0c 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.h +++ b/deps/v8/src/x64/lithium-codegen-x64.h @@ -34,37 +34,15 @@ #include "deoptimizer.h" #include "safepoint-table.h" #include "scopes.h" +#include "x64/lithium-gap-resolver-x64.h" namespace v8 { namespace internal { // Forward declarations. class LDeferredCode; -class LGapNode; class SafepointGenerator; -class LGapResolver BASE_EMBEDDED { - public: - LGapResolver(); - const ZoneList* Resolve(const ZoneList* moves, - LOperand* marker_operand); - - private: - LGapNode* LookupNode(LOperand* operand); - bool CanReach(LGapNode* a, LGapNode* b, int visited_id); - bool CanReach(LGapNode* a, LGapNode* b); - void RegisterMove(LMoveOperands move); - void AddResultMove(LOperand* from, LOperand* to); - void AddResultMove(LGapNode* from, LGapNode* to); - void ResolveCycle(LGapNode* start, LOperand* marker_operand); - - ZoneList nodes_; - ZoneList identified_cycles_; - ZoneList result_; - int next_visited_id_; -}; - - class LCodeGen BASE_EMBEDDED { public: LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) @@ -80,10 +58,24 @@ class LCodeGen BASE_EMBEDDED { scope_(chunk->graph()->info()->scope()), status_(UNUSED), deferred_(8), - osr_pc_offset_(-1) { + osr_pc_offset_(-1), + resolver_(this) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); } + // Simple accessors. + MacroAssembler* masm() const { return masm_; } + + // Support for converting LOperands to assembler types. + Register ToRegister(LOperand* op) const; + XMMRegister ToDoubleRegister(LOperand* op) const; + bool IsInteger32Constant(LConstantOperand* op) const; + int ToInteger32(LConstantOperand* op) const; + bool IsTaggedConstant(LConstantOperand* op) const; + Handle ToHandle(LConstantOperand* op) const; + Operand ToOperand(LOperand* op) const; + + // Try to generate code for the entire chunk, but it may fail if the // chunk contains constructs we cannot handle. Returns true if the // code generation attempt succeeded. @@ -95,7 +87,6 @@ class LCodeGen BASE_EMBEDDED { // Deferred code support. void DoDeferredNumberTagD(LNumberTagD* instr); - void DoDeferredNumberTagI(LNumberTagI* instr); void DoDeferredTaggedToI(LTaggedToI* instr); void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr); void DoDeferredStackCheck(LGoto* instr); @@ -129,7 +120,6 @@ class LCodeGen BASE_EMBEDDED { LChunk* chunk() const { return chunk_; } Scope* scope() const { return scope_; } HGraph* graph() const { return chunk_->graph(); } - MacroAssembler* masm() const { return masm_; } int GetNextEmittedBlock(int block); LInstruction* GetNextInstruction(); @@ -190,13 +180,6 @@ class LCodeGen BASE_EMBEDDED { Register ToRegister(int index) const; XMMRegister ToDoubleRegister(int index) const; - Register ToRegister(LOperand* op) const; - XMMRegister ToDoubleRegister(LOperand* op) const; - bool IsInteger32Constant(LConstantOperand* op) const; - int ToInteger32(LConstantOperand* op) const; - bool IsTaggedConstant(LConstantOperand* op) const; - Handle ToHandle(LConstantOperand* op) const; - Operand ToOperand(LOperand* op) const; // Specific math operations - used from DoUnaryMathOperation. void DoMathAbs(LUnaryMathOperation* instr); @@ -209,6 +192,10 @@ class LCodeGen BASE_EMBEDDED { void DoMathSin(LUnaryMathOperation* instr); // Support for recording safepoint and position information. + void RecordSafepoint(LPointerMap* pointers, + Safepoint::Kind kind, + int arguments, + int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, @@ -231,8 +218,6 @@ class LCodeGen BASE_EMBEDDED { // Returns the condition on which a final split to // true and false label should be made, to optimize fallthrough. Condition EmitIsObject(Register input, - Register temp1, - Register temp2, Label* is_not_object, Label* is_object); diff --git a/deps/v8/src/x64/lithium-gap-resolver-x64.cc b/deps/v8/src/x64/lithium-gap-resolver-x64.cc new file mode 100644 index 0000000000..cedd0256dd --- /dev/null +++ b/deps/v8/src/x64/lithium-gap-resolver-x64.cc @@ -0,0 +1,320 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "v8.h" + +#if defined(V8_TARGET_ARCH_X64) + +#include "x64/lithium-gap-resolver-x64.h" +#include "x64/lithium-codegen-x64.h" + +namespace v8 { +namespace internal { + +LGapResolver::LGapResolver(LCodeGen* owner) + : cgen_(owner), moves_(32) {} + + +void LGapResolver::Resolve(LParallelMove* parallel_move) { + ASSERT(moves_.is_empty()); + // Build up a worklist of moves. + BuildInitialMoveList(parallel_move); + + for (int i = 0; i < moves_.length(); ++i) { + LMoveOperands move = moves_[i]; + // Skip constants to perform them last. They don't block other moves + // and skipping such moves with register destinations keeps those + // registers free for the whole algorithm. + if (!move.IsEliminated() && !move.source()->IsConstantOperand()) { + PerformMove(i); + } + } + + // Perform the moves with constant sources. + for (int i = 0; i < moves_.length(); ++i) { + if (!moves_[i].IsEliminated()) { + ASSERT(moves_[i].source()->IsConstantOperand()); + EmitMove(i); + } + } + + moves_.Rewind(0); +} + + +void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) { + // Perform a linear sweep of the moves to add them to the initial list of + // moves to perform, ignoring any move that is redundant (the source is + // the same as the destination, the destination is ignored and + // unallocated, or the move was already eliminated). + const ZoneList* moves = parallel_move->move_operands(); + for (int i = 0; i < moves->length(); ++i) { + LMoveOperands move = moves->at(i); + if (!move.IsRedundant()) moves_.Add(move); + } + Verify(); +} + + +void LGapResolver::PerformMove(int index) { + // Each call to this function performs a move and deletes it from the move + // graph. We first recursively perform any move blocking this one. We + // mark a move as "pending" on entry to PerformMove in order to detect + // cycles in the move graph. We use operand swaps to resolve cycles, + // which means that a call to PerformMove could change any source operand + // in the move graph. + + ASSERT(!moves_[index].IsPending()); + ASSERT(!moves_[index].IsRedundant()); + + // Clear this move's destination to indicate a pending move. The actual + // destination is saved in a stack-allocated local. Recursion may allow + // multiple moves to be pending. + ASSERT(moves_[index].source() != NULL); // Or else it will look eliminated. + LOperand* destination = moves_[index].destination(); + moves_[index].set_destination(NULL); + + // Perform a depth-first traversal of the move graph to resolve + // dependencies. Any unperformed, unpending move with a source the same + // as this one's destination blocks this one so recursively perform all + // such moves. + for (int i = 0; i < moves_.length(); ++i) { + LMoveOperands other_move = moves_[i]; + if (other_move.Blocks(destination) && !other_move.IsPending()) { + // Though PerformMove can change any source operand in the move graph, + // this call cannot create a blocking move via a swap (this loop does + // not miss any). Assume there is a non-blocking move with source A + // and this move is blocked on source B and there is a swap of A and + // B. Then A and B must be involved in the same cycle (or they would + // not be swapped). Since this move's destination is B and there is + // only a single incoming edge to an operand, this move must also be + // involved in the same cycle. In that case, the blocking move will + // be created but will be "pending" when we return from PerformMove. + PerformMove(i); + } + } + + // We are about to resolve this move and don't need it marked as + // pending, so restore its destination. + moves_[index].set_destination(destination); + + // This move's source may have changed due to swaps to resolve cycles and + // so it may now be the last move in the cycle. If so remove it. + if (moves_[index].source()->Equals(destination)) { + moves_[index].Eliminate(); + return; + } + + // The move may be blocked on a (at most one) pending move, in which case + // we have a cycle. Search for such a blocking move and perform a swap to + // resolve it. + for (int i = 0; i < moves_.length(); ++i) { + LMoveOperands other_move = moves_[i]; + if (other_move.Blocks(destination)) { + ASSERT(other_move.IsPending()); + EmitSwap(index); + return; + } + } + + // This move is not blocked. + EmitMove(index); +} + + +void LGapResolver::Verify() { +#ifdef ENABLE_SLOW_ASSERTS + // No operand should be the destination for more than one move. + for (int i = 0; i < moves_.length(); ++i) { + LOperand* destination = moves_[i].destination(); + for (int j = i + 1; j < moves_.length(); ++j) { + SLOW_ASSERT(!destination->Equals(moves_[j].destination())); + } + } +#endif +} + + +#define __ ACCESS_MASM(cgen_->masm()) + + +void LGapResolver::EmitMove(int index) { + LOperand* source = moves_[index].source(); + LOperand* destination = moves_[index].destination(); + + // Dispatch on the source and destination operand kinds. Not all + // combinations are possible. + if (source->IsRegister()) { + Register src = cgen_->ToRegister(source); + if (destination->IsRegister()) { + Register dst = cgen_->ToRegister(destination); + __ movq(dst, src); + } else { + ASSERT(destination->IsStackSlot()); + Operand dst = cgen_->ToOperand(destination); + __ movq(dst, src); + } + + } else if (source->IsStackSlot()) { + Operand src = cgen_->ToOperand(source); + if (destination->IsRegister()) { + Register dst = cgen_->ToRegister(destination); + __ movq(dst, src); + } else { + ASSERT(destination->IsStackSlot()); + Operand dst = cgen_->ToOperand(destination); + __ movq(kScratchRegister, src); + __ movq(dst, kScratchRegister); + } + + } else if (source->IsConstantOperand()) { + LConstantOperand* constant_source = LConstantOperand::cast(source); + if (destination->IsRegister()) { + Register dst = cgen_->ToRegister(destination); + if (cgen_->IsInteger32Constant(constant_source)) { + __ movl(dst, Immediate(cgen_->ToInteger32(constant_source))); + } else { + __ Move(dst, cgen_->ToHandle(constant_source)); + } + } else { + ASSERT(destination->IsStackSlot()); + Operand dst = cgen_->ToOperand(destination); + if (cgen_->IsInteger32Constant(constant_source)) { + // Allow top 32 bits of an untagged Integer32 to be arbitrary. + __ movl(dst, Immediate(cgen_->ToInteger32(constant_source))); + } else { + __ Move(dst, cgen_->ToHandle(constant_source)); + } + } + + } else if (source->IsDoubleRegister()) { + XMMRegister src = cgen_->ToDoubleRegister(source); + if (destination->IsDoubleRegister()) { + __ movsd(cgen_->ToDoubleRegister(destination), src); + } else { + ASSERT(destination->IsDoubleStackSlot()); + __ movsd(cgen_->ToOperand(destination), src); + } + } else if (source->IsDoubleStackSlot()) { + Operand src = cgen_->ToOperand(source); + if (destination->IsDoubleRegister()) { + __ movsd(cgen_->ToDoubleRegister(destination), src); + } else { + ASSERT(destination->IsDoubleStackSlot()); + __ movsd(xmm0, src); + __ movsd(cgen_->ToOperand(destination), xmm0); + } + } else { + UNREACHABLE(); + } + + moves_[index].Eliminate(); +} + + +void LGapResolver::EmitSwap(int index) { + LOperand* source = moves_[index].source(); + LOperand* destination = moves_[index].destination(); + + // Dispatch on the source and destination operand kinds. Not all + // combinations are possible. + if (source->IsRegister() && destination->IsRegister()) { + // Swap two general-purpose registers. + Register src = cgen_->ToRegister(source); + Register dst = cgen_->ToRegister(destination); + __ xchg(dst, src); + + } else if ((source->IsRegister() && destination->IsStackSlot()) || + (source->IsStackSlot() && destination->IsRegister())) { + // Swap a general-purpose register and a stack slot. + Register reg = + cgen_->ToRegister(source->IsRegister() ? source : destination); + Operand mem = + cgen_->ToOperand(source->IsRegister() ? destination : source); + __ movq(kScratchRegister, mem); + __ movq(mem, reg); + __ movq(reg, kScratchRegister); + + } else if ((source->IsStackSlot() && destination->IsStackSlot()) || + (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot())) { + // Swap two stack slots or two double stack slots. + Operand src = cgen_->ToOperand(source); + Operand dst = cgen_->ToOperand(destination); + __ movsd(xmm0, src); + __ movq(kScratchRegister, dst); + __ movsd(dst, xmm0); + __ movq(src, kScratchRegister); + + } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) { + // Swap two double registers. + XMMRegister source_reg = cgen_->ToDoubleRegister(source); + XMMRegister destination_reg = cgen_->ToDoubleRegister(destination); + __ movsd(xmm0, source_reg); + __ movsd(source_reg, destination_reg); + __ movsd(destination_reg, xmm0); + + } else if (source->IsDoubleRegister() || destination->IsDoubleRegister()) { + // Swap a double register and a double stack slot. + ASSERT((source->IsDoubleRegister() && destination->IsDoubleStackSlot()) || + (source->IsDoubleStackSlot() && destination->IsDoubleRegister())); + XMMRegister reg = cgen_->ToDoubleRegister(source->IsDoubleRegister() + ? source + : destination); + LOperand* other = source->IsDoubleRegister() ? destination : source; + ASSERT(other->IsDoubleStackSlot()); + Operand other_operand = cgen_->ToOperand(other); + __ movsd(xmm0, other_operand); + __ movsd(other_operand, reg); + __ movsd(reg, xmm0); + + } else { + // No other combinations are possible. + UNREACHABLE(); + } + + // The swap of source and destination has executed a move from source to + // destination. + moves_[index].Eliminate(); + + // Any unperformed (including pending) move with a source of either + // this move's source or destination needs to have their source + // changed to reflect the state of affairs after the swap. + for (int i = 0; i < moves_.length(); ++i) { + LMoveOperands other_move = moves_[i]; + if (other_move.Blocks(source)) { + moves_[i].set_source(destination); + } else if (other_move.Blocks(destination)) { + moves_[i].set_source(source); + } + } +} + +#undef __ + +} } // namespace v8::internal + +#endif // V8_TARGET_ARCH_X64 diff --git a/deps/v8/src/x64/lithium-gap-resolver-x64.h b/deps/v8/src/x64/lithium-gap-resolver-x64.h new file mode 100644 index 0000000000..d828455921 --- /dev/null +++ b/deps/v8/src/x64/lithium-gap-resolver-x64.h @@ -0,0 +1,74 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef V8_X64_LITHIUM_GAP_RESOLVER_X64_H_ +#define V8_X64_LITHIUM_GAP_RESOLVER_X64_H_ + +#include "v8.h" + +#include "lithium.h" + +namespace v8 { +namespace internal { + +class LCodeGen; +class LGapResolver; + +class LGapResolver BASE_EMBEDDED { + public: + explicit LGapResolver(LCodeGen* owner); + + // Resolve a set of parallel moves, emitting assembler instructions. + void Resolve(LParallelMove* parallel_move); + + private: + // Build the initial list of moves. + void BuildInitialMoveList(LParallelMove* parallel_move); + + // Perform the move at the moves_ index in question (possibly requiring + // other moves to satisfy dependencies). + void PerformMove(int index); + + // Emit a move and remove it from the move graph. + void EmitMove(int index); + + // Execute a move by emitting a swap of two operands. The move from + // source to destination is removed from the move graph. + void EmitSwap(int index); + + // Verify the move list before performing moves. + void Verify(); + + LCodeGen* cgen_; + + // List of moves not yet resolved. + ZoneList moves_; +}; + +} } // namespace v8::internal + +#endif // V8_X64_LITHIUM_GAP_RESOLVER_X64_H_ diff --git a/deps/v8/src/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc index eff6d51e83..2dd5cf7337 100644 --- a/deps/v8/src/x64/lithium-x64.cc +++ b/deps/v8/src/x64/lithium-x64.cc @@ -974,12 +974,7 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { } else if (v->IsIsObject()) { HIsObject* compare = HIsObject::cast(v); ASSERT(compare->value()->representation().IsTagged()); - - LOperand* temp1 = TempRegister(); - LOperand* temp2 = TempRegister(); - return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()), - temp1, - temp2); + return new LIsObjectAndBranch(UseRegisterAtStart(compare->value())); } else if (v->IsCompareJSObjectEq()) { HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), @@ -1048,20 +1043,19 @@ LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) { LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) { - Abort("Unimplemented: %s", "DoPushArgument"); - return NULL; + ++argument_count_; + LOperand* argument = UseOrConstant(instr->argument()); + return new LPushArgument(argument); } LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { - Abort("Unimplemented: %s", "DoGlobalObject"); - return NULL; + return DefineAsRegister(new LGlobalObject); } LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) { - Abort("Unimplemented: %s", "DoGlobalReceiver"); - return NULL; + return DefineAsRegister(new LGlobalReceiver); } @@ -1103,8 +1097,10 @@ LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) { LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) { - Abort("Unimplemented: %s", "DoCallNew"); - return NULL; + LOperand* constructor = UseFixed(instr->constructor(), rdi); + argument_count_ -= instr->argument_count(); + LCallNew* result = new LCallNew(constructor); + return MarkAsCall(DefineFixed(result, rax), instr); } @@ -1181,8 +1177,23 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { LInstruction* LChunkBuilder::DoSub(HSub* instr) { - Abort("Unimplemented: %s", "DoSub"); - return NULL; + if (instr->representation().IsInteger32()) { + ASSERT(instr->left()->representation().IsInteger32()); + ASSERT(instr->right()->representation().IsInteger32()); + LOperand* left = UseRegisterAtStart(instr->left()); + LOperand* right = UseOrConstantAtStart(instr->right()); + LSubI* sub = new LSubI(left, right); + LInstruction* result = DefineSameAsFirst(sub); + if (instr->CheckFlag(HValue::kCanOverflow)) { + result = AssignEnvironment(result); + } + return result; + } else if (instr->representation().IsDouble()) { + return DoArithmeticD(Token::SUB, instr); + } else { + ASSERT(instr->representation().IsTagged()); + return DoArithmeticT(Token::SUB, instr); + } } @@ -1243,26 +1254,34 @@ LInstruction* LChunkBuilder::DoCompare(HCompare* instr) { LInstruction* LChunkBuilder::DoCompareJSObjectEq( HCompareJSObjectEq* instr) { - Abort("Unimplemented: %s", "DoCompareJSObjectEq"); - return NULL; + LOperand* left = UseRegisterAtStart(instr->left()); + LOperand* right = UseRegisterAtStart(instr->right()); + LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right); + return DefineAsRegister(result); } LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) { - Abort("Unimplemented: %s", "DoIsNull"); - return NULL; + ASSERT(instr->value()->representation().IsTagged()); + LOperand* value = UseRegisterAtStart(instr->value()); + + return DefineAsRegister(new LIsNull(value)); } LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) { - Abort("Unimplemented: %s", "DoIsObject"); - return NULL; + ASSERT(instr->value()->representation().IsTagged()); + LOperand* value = UseRegister(instr->value()); + + return DefineAsRegister(new LIsObject(value)); } LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { - Abort("Unimplemented: %s", "DoIsSmi"); - return NULL; + ASSERT(instr->value()->representation().IsTagged()); + LOperand* value = UseAtStart(instr->value()); + + return DefineAsRegister(new LIsSmi(value)); } @@ -1316,14 +1335,69 @@ LInstruction* LChunkBuilder::DoThrow(HThrow* instr) { LInstruction* LChunkBuilder::DoChange(HChange* instr) { - Abort("Unimplemented: %s", "DoChange"); + Representation from = instr->from(); + Representation to = instr->to(); + if (from.IsTagged()) { + if (to.IsDouble()) { + LOperand* value = UseRegister(instr->value()); + LNumberUntagD* res = new LNumberUntagD(value); + return AssignEnvironment(DefineAsRegister(res)); + } else { + ASSERT(to.IsInteger32()); + LOperand* value = UseRegister(instr->value()); + bool needs_check = !instr->value()->type().IsSmi(); + if (needs_check) { + LOperand* xmm_temp = + (instr->CanTruncateToInt32() && CpuFeatures::IsSupported(SSE3)) + ? NULL + : FixedTemp(xmm1); + LTaggedToI* res = new LTaggedToI(value, xmm_temp); + return AssignEnvironment(DefineSameAsFirst(res)); + } else { + return DefineSameAsFirst(new LSmiUntag(value, needs_check)); + } + } + } else if (from.IsDouble()) { + if (to.IsTagged()) { + LOperand* value = UseRegister(instr->value()); + LOperand* temp = TempRegister(); + + // Make sure that temp and result_temp are different registers. + LUnallocated* result_temp = TempRegister(); + LNumberTagD* result = new LNumberTagD(value, temp); + return AssignPointerMap(Define(result, result_temp)); + } else { + ASSERT(to.IsInteger32()); + bool needs_temp = instr->CanTruncateToInt32() && + !CpuFeatures::IsSupported(SSE3); + LOperand* value = needs_temp ? + UseTempRegister(instr->value()) : UseRegister(instr->value()); + LOperand* temp = needs_temp ? TempRegister() : NULL; + return AssignEnvironment(DefineAsRegister(new LDoubleToI(value, temp))); + } + } else if (from.IsInteger32()) { + if (to.IsTagged()) { + HValue* val = instr->value(); + LOperand* value = UseRegister(val); + if (val->HasRange() && val->range()->IsInSmiRange()) { + return DefineSameAsFirst(new LSmiTag(value)); + } else { + LNumberTagI* result = new LNumberTagI(value); + return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result))); + } + } else { + ASSERT(to.IsDouble()); + return DefineAsRegister(new LInteger32ToDouble(Use(instr->value()))); + } + } + UNREACHABLE(); return NULL; } LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) { - Abort("Unimplemented: %s", "DoCheckNonSmi"); - return NULL; + LOperand* value = UseRegisterAtStart(instr->value()); + return AssignEnvironment(new LCheckSmi(value, zero)); } @@ -1334,26 +1408,28 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { - Abort("Unimplemented: %s", "DoCheckPrototypeMaps"); - return NULL; + LOperand* temp = TempRegister(); + LCheckPrototypeMaps* result = new LCheckPrototypeMaps(temp); + return AssignEnvironment(result); } LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) { - Abort("Unimplemented: %s", "DoCheckSmi"); - return NULL; + LOperand* value = UseRegisterAtStart(instr->value()); + return AssignEnvironment(new LCheckSmi(value, not_zero)); } LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { - Abort("Unimplemented: %s", "DoCheckFunction"); - return NULL; + LOperand* value = UseRegisterAtStart(instr->value()); + return AssignEnvironment(new LCheckFunction(value)); } LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) { - Abort("Unimplemented: %s", "DoCheckMap"); - return NULL; + LOperand* value = UseRegisterAtStart(instr->value()); + LCheckMap* result = new LCheckMap(value); + return AssignEnvironment(result); } @@ -1381,15 +1457,15 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) { LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) { - Abort("Unimplemented: %s", "DoLoadGlobal"); - return NULL; + LLoadGlobal* result = new LLoadGlobal; + return instr->check_hole_value() + ? AssignEnvironment(DefineAsRegister(result)) + : DefineAsRegister(result); } LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) { - Abort("Unimplemented: %s", "DoStoreGlobal"); - return NULL; -} + return new LStoreGlobal(UseRegisterAtStart(instr->value()));} LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) { @@ -1399,8 +1475,9 @@ LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) { LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { - Abort("Unimplemented: %s", "DoLoadNamedField"); - return NULL; + ASSERT(instr->representation().IsTagged()); + LOperand* obj = UseRegisterAtStart(instr->object()); + return DefineAsRegister(new LLoadNamedField(obj)); } @@ -1450,8 +1527,22 @@ LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) { LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { - Abort("Unimplemented: %s", "DoStoreNamedField"); - return NULL; + bool needs_write_barrier = instr->NeedsWriteBarrier(); + + LOperand* obj = needs_write_barrier + ? UseTempRegister(instr->object()) + : UseRegisterAtStart(instr->object()); + + LOperand* val = needs_write_barrier + ? UseTempRegister(instr->value()) + : UseRegister(instr->value()); + + // We only need a scratch register if we have a write barrier or we + // have a store into the properties array (not in-object-property). + LOperand* temp = (!instr->is_in_object() || needs_write_barrier) + ? TempRegister() : NULL; + + return new LStoreNamedField(obj, val, temp); } @@ -1588,7 +1679,14 @@ LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) { LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { - Abort("Unimplemented: %s", "DoEnterInlined"); + HEnvironment* outer = current_block_->last_environment(); + HConstant* undefined = graph()->GetConstantUndefined(); + HEnvironment* inner = outer->CopyForInlining(instr->closure(), + instr->function(), + false, + undefined); + current_block_->UpdateEnvironment(inner); + chunk_->AddInlinedClosure(instr->closure()); return NULL; } diff --git a/deps/v8/src/x64/lithium-x64.h b/deps/v8/src/x64/lithium-x64.h index 9b7d56827e..3195791654 100644 --- a/deps/v8/src/x64/lithium-x64.h +++ b/deps/v8/src/x64/lithium-x64.h @@ -732,23 +732,20 @@ class LIsNullAndBranch: public LControlInstruction<1, 1> { }; -class LIsObject: public LTemplateInstruction<1, 1, 1> { +class LIsObject: public LTemplateInstruction<1, 1, 0> { public: - LIsObject(LOperand* value, LOperand* temp) { + explicit LIsObject(LOperand* value) { inputs_[0] = value; - temps_[0] = temp; } DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object") }; -class LIsObjectAndBranch: public LControlInstruction<1, 2> { +class LIsObjectAndBranch: public LControlInstruction<1, 0> { public: - LIsObjectAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { + explicit LIsObjectAndBranch(LOperand* value) { inputs_[0] = value; - temps_[0] = temp; - temps_[1] = temp2; } DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index a690bd5256..e104e5bb91 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -375,6 +375,16 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { } +void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) { + Runtime::Function* function = Runtime::FunctionForId(id); + Set(rax, function->nargs); + movq(rbx, ExternalReference(function)); + CEntryStub ces(1); + ces.SaveDoubles(); + CallStub(&ces); +} + + MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id, int num_arguments) { return TryCallRuntime(Runtime::FunctionForId(id), num_arguments); @@ -967,6 +977,27 @@ Condition MacroAssembler::CheckUInteger32ValidSmiValue(Register src) { } +void MacroAssembler::CheckSmiToIndicator(Register dst, Register src) { + if (dst.is(src)) { + andl(dst, Immediate(kSmiTagMask)); + } else { + movl(dst, Immediate(kSmiTagMask)); + andl(dst, src); + } +} + + +void MacroAssembler::CheckSmiToIndicator(Register dst, const Operand& src) { + if (!(src.AddressUsesRegister(dst))) { + movl(dst, Immediate(kSmiTagMask)); + andl(dst, src); + } else { + movl(dst, src); + andl(dst, Immediate(kSmiTagMask)); + } +} + + void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) { if (constant->value() == 0) { if (!dst.is(src)) { @@ -1427,6 +1458,34 @@ void MacroAssembler::Popad() { } +void MacroAssembler::Dropad() { + const int kRegistersPushedByPushad = 11; + addq(rsp, Immediate(kRegistersPushedByPushad * kPointerSize)); +} + + +// Order general registers are pushed by Pushad: +// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14. +int MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = { + 0, + 1, + 2, + 3, + -1, + -1, + 4, + 5, + 6, + 7, + -1, + 8, + 9, + -1, + 10, + -1 +}; + + void MacroAssembler::PushTryHandler(CodeLocation try_location, HandlerType type) { // Adjust this code if not the case. @@ -1711,10 +1770,18 @@ void MacroAssembler::InvokeFunction(JSFunction* function, Move(rdi, Handle(function)); movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); - // Invoke the cached code. - Handle code(function->code()); - ParameterCount expected(function->shared()->formal_parameter_count()); - InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag); + if (V8::UseCrankshaft()) { + // Since Crankshaft can recompile a function, we need to load + // the Code object every time we call the function. + movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); + ParameterCount expected(function->shared()->formal_parameter_count()); + InvokeCode(rdx, expected, actual, flag); + } else { + // Invoke the cached code. + Handle code(function->code()); + ParameterCount expected(function->shared()->formal_parameter_count()); + InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag); + } } @@ -1775,12 +1842,24 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax) { } -void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space) { +void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space, + bool save_doubles) { #ifdef _WIN64 - const int kShaddowSpace = 4; - arg_stack_space += kShaddowSpace; + const int kShadowSpace = 4; + arg_stack_space += kShadowSpace; #endif - if (arg_stack_space > 0) { + // Optionally save all XMM registers. + if (save_doubles) { + CpuFeatures::Scope scope(SSE2); + int space = XMMRegister::kNumRegisters * kDoubleSize + + arg_stack_space * kPointerSize; + subq(rsp, Immediate(space)); + int offset = -2 * kPointerSize; + for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) { + XMMRegister reg = XMMRegister::FromAllocationIndex(i); + movsd(Operand(rbp, offset - ((i + 1) * kDoubleSize)), reg); + } + } else if (arg_stack_space > 0) { subq(rsp, Immediate(arg_stack_space * kPointerSize)); } @@ -1797,7 +1876,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space) { } -void MacroAssembler::EnterExitFrame(int arg_stack_space) { +void MacroAssembler::EnterExitFrame(int arg_stack_space, bool save_doubles) { EnterExitFramePrologue(true); // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, @@ -1805,25 +1884,31 @@ void MacroAssembler::EnterExitFrame(int arg_stack_space) { int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; lea(r12, Operand(rbp, r14, times_pointer_size, offset)); - EnterExitFrameEpilogue(arg_stack_space); + EnterExitFrameEpilogue(arg_stack_space, save_doubles); } void MacroAssembler::EnterApiExitFrame(int arg_stack_space) { EnterExitFramePrologue(false); - EnterExitFrameEpilogue(arg_stack_space); + EnterExitFrameEpilogue(arg_stack_space, false); } -void MacroAssembler::LeaveExitFrame() { +void MacroAssembler::LeaveExitFrame(bool save_doubles) { // Registers: // r12 : argv - + if (save_doubles) { + int offset = -2 * kPointerSize; + for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) { + XMMRegister reg = XMMRegister::FromAllocationIndex(i); + movsd(reg, Operand(rbp, offset - ((i + 1) * kDoubleSize))); + } + } // Get the return address from the stack and restore the frame pointer. movq(rcx, Operand(rbp, 1 * kPointerSize)); movq(rbp, Operand(rbp, 0 * kPointerSize)); - // Pop everything up to and including the arguments and the receiver + // Drop everything up to and including the arguments and the receiver // from the caller stack. lea(rsp, Operand(r12, 1 * kPointerSize)); diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index b2d085f905..3536911875 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -152,7 +152,7 @@ class MacroAssembler: public Assembler { // // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack // accessible via StackSpaceOperand. - void EnterExitFrame(int arg_stack_space = 0); + void EnterExitFrame(int arg_stack_space = 0, bool save_doubles = false); // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize // memory (not GCed) on the stack accessible via StackSpaceOperand. @@ -161,20 +161,20 @@ class MacroAssembler: public Assembler { // Leave the current exit frame. Expects/provides the return value in // register rax:rdx (untouched) and the pointer to the first // argument in register rsi. - void LeaveExitFrame(); + void LeaveExitFrame(bool save_doubles = false); // Leave the current exit frame. Expects/provides the return value in // register rax (untouched). void LeaveApiExitFrame(); // Push and pop the registers that can hold pointers. - void PushSafepointRegisters() { UNIMPLEMENTED(); } - void PopSafepointRegisters() { UNIMPLEMENTED(); } + void PushSafepointRegisters() { Pushad(); } + void PopSafepointRegisters() { Popad(); } static int SafepointRegisterStackIndex(int reg_code) { - UNIMPLEMENTED(); - return 0; + return kSafepointPushRegisterIndices[reg_code]; } + // --------------------------------------------------------------------------- // JavaScript invokes @@ -301,6 +301,11 @@ class MacroAssembler: public Assembler { // conversion to a smi. Condition CheckUInteger32ValidSmiValue(Register src); + // Check whether src is a Smi, and set dst to zero if it is a smi, + // and to one if it isn't. + void CheckSmiToIndicator(Register dst, Register src); + void CheckSmiToIndicator(Register dst, const Operand& src); + // Test-and-jump functions. Typically combines a check function // above with a conditional jump. @@ -597,6 +602,9 @@ class MacroAssembler: public Assembler { // (kScratchRegister, kSmiConstantRegister, kRootRegister). void Pushad(); void Popad(); + // Sets the stack as after performing Popad, without actually loading the + // registers. + void Dropad(); // Compare object type for heap object. // Always use unsigned comparisons: above and below, not less and greater. @@ -812,6 +820,9 @@ class MacroAssembler: public Assembler { // Call a runtime routine. void CallRuntime(Runtime::Function* f, int num_arguments); + // Call a runtime function and save the value of XMM registers. + void CallRuntimeSaveDoubles(Runtime::FunctionId id); + // Call a runtime function, returning the CodeStub object called. // Try to generate the stub code if necessary. Do not perform a GC // but instead return a retry after GC failure. @@ -931,6 +942,9 @@ class MacroAssembler: public Assembler { bool allow_stub_calls() { return allow_stub_calls_; } private: + // Order general registers are pushed by Pushad. + // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14. + static int kSafepointPushRegisterIndices[Register::kNumRegisters]; bool generating_stub_; bool allow_stub_calls_; @@ -961,7 +975,7 @@ class MacroAssembler: public Assembler { // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack // accessible via StackSpaceOperand. - void EnterExitFrameEpilogue(int arg_stack_space); + void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles); void LeaveExitFrameEpilogue(); diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index c86f43de2c..8888d70a6b 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -307,28 +307,32 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, Register receiver, Register scratch1, Register scratch2, - Label* miss) { + Label* miss, + bool support_wrappers) { Label check_wrapper; // Check if the object is a string leaving the instance type in the // scratch register. - GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper); + GenerateStringCheck(masm, receiver, scratch1, miss, + support_wrappers ? &check_wrapper : miss); // Load length directly from the string. __ movq(rax, FieldOperand(receiver, String::kLengthOffset)); __ ret(0); - // Check if the object is a JSValue wrapper. - __ bind(&check_wrapper); - __ cmpl(scratch1, Immediate(JS_VALUE_TYPE)); - __ j(not_equal, miss); + if (support_wrappers) { + // Check if the object is a JSValue wrapper. + __ bind(&check_wrapper); + __ cmpl(scratch1, Immediate(JS_VALUE_TYPE)); + __ j(not_equal, miss); - // Check if the wrapped value is a string and load the length - // directly if it is. - __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); - GenerateStringCheck(masm, scratch2, scratch1, miss, miss); - __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); - __ ret(0); + // Check if the wrapped value is a string and load the length + // directly if it is. + __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); + GenerateStringCheck(masm, scratch2, scratch1, miss, miss); + __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); + __ ret(0); + } } @@ -437,10 +441,9 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { // Generates call to API function. -static bool GenerateFastApiCall(MacroAssembler* masm, - const CallOptimization& optimization, - int argc, - Failure** failure) { +static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, + const CallOptimization& optimization, + int argc) { // ----------- S t a t e ------------- // -- rsp[0] : return address // -- rsp[8] : object passing the type check @@ -504,13 +507,8 @@ static bool GenerateFastApiCall(MacroAssembler* masm, // already generated). Do not allow the assembler to perform a // garbage collection but instead return the allocation failure // object. - MaybeObject* result = - masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1); - if (result->IsFailure()) { - *failure = Failure::cast(result); - return false; - } - return true; + return masm->TryCallApiFunctionAndReturn(&fun, + argc + kFastApiCallArguments + 1); } @@ -523,17 +521,16 @@ class CallInterceptorCompiler BASE_EMBEDDED { arguments_(arguments), name_(name) {} - bool Compile(MacroAssembler* masm, - JSObject* object, - JSObject* holder, - String* name, - LookupResult* lookup, - Register receiver, - Register scratch1, - Register scratch2, - Register scratch3, - Label* miss, - Failure** failure) { + MaybeObject* Compile(MacroAssembler* masm, + JSObject* object, + JSObject* holder, + String* name, + LookupResult* lookup, + Register receiver, + Register scratch1, + Register scratch2, + Register scratch3, + Label* miss) { ASSERT(holder->HasNamedInterceptor()); ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); @@ -553,8 +550,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { lookup, name, optimization, - miss, - failure); + miss); } else { CompileRegular(masm, object, @@ -565,23 +561,22 @@ class CallInterceptorCompiler BASE_EMBEDDED { name, holder, miss); - return true; + return Heap::undefined_value(); // Success. } } private: - bool CompileCacheable(MacroAssembler* masm, - JSObject* object, - Register receiver, - Register scratch1, - Register scratch2, - Register scratch3, - JSObject* interceptor_holder, - LookupResult* lookup, - String* name, - const CallOptimization& optimization, - Label* miss_label, - Failure** failure) { + MaybeObject* CompileCacheable(MacroAssembler* masm, + JSObject* object, + Register receiver, + Register scratch1, + Register scratch2, + Register scratch3, + JSObject* interceptor_holder, + LookupResult* lookup, + String* name, + const CallOptimization& optimization, + Label* miss_label) { ASSERT(optimization.is_constant_call()); ASSERT(!lookup->holder()->IsGlobalObject()); @@ -643,13 +638,10 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Invoke function. if (can_do_fast_api_call) { - bool success = GenerateFastApiCall(masm, - optimization, - arguments_.immediate(), - failure); - if (!success) { - return false; - } + MaybeObject* result = GenerateFastApiCall(masm, + optimization, + arguments_.immediate()); + if (result->IsFailure()) return result; } else { __ InvokeFunction(optimization.constant_function(), arguments_, JUMP_FUNCTION); @@ -668,7 +660,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { FreeSpaceForFastApiCall(masm, scratch1); } - return true; + return Heap::undefined_value(); // Success. } void CompileRegular(MacroAssembler* masm, @@ -1021,17 +1013,16 @@ void StubCompiler::GenerateLoadField(JSObject* object, } -bool StubCompiler::GenerateLoadCallback(JSObject* object, - JSObject* holder, - Register receiver, - Register name_reg, - Register scratch1, - Register scratch2, - Register scratch3, - AccessorInfo* callback, - String* name, - Label* miss, - Failure** failure) { +MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, + JSObject* holder, + Register receiver, + Register name_reg, + Register scratch1, + Register scratch2, + Register scratch3, + AccessorInfo* callback, + String* name, + Label* miss) { // Check that the receiver isn't a smi. __ JumpIfSmi(receiver, miss); @@ -1095,12 +1086,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, // already generated). Do not allow the assembler to perform a // garbage collection but instead return the allocation failure // object. - MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); - if (result->IsFailure()) { - *failure = Failure::cast(result); - return false; - } - return true; + return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); } @@ -2135,17 +2121,14 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, } if (depth != kInvalidProtoDepth) { - Failure* failure; // Move the return address on top of the stack. __ movq(rax, Operand(rsp, 3 * kPointerSize)); __ movq(Operand(rsp, 0 * kPointerSize), rax); // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains // duplicate of return address and will be overwritten. - bool success = GenerateFastApiCall(masm(), optimization, argc, &failure); - if (!success) { - return failure; - } + MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc); + if (result->IsFailure()) return result; } else { __ InvokeFunction(function, arguments(), JUMP_FUNCTION); } @@ -2194,21 +2177,17 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); CallInterceptorCompiler compiler(this, arguments(), rcx); - Failure* failure; - bool success = compiler.Compile(masm(), - object, - holder, - name, - &lookup, - rdx, - rbx, - rdi, - rax, - &miss, - &failure); - if (!success) { - return failure; - } + MaybeObject* result = compiler.Compile(masm(), + object, + holder, + name, + &lookup, + rdx, + rbx, + rdi, + rax, + &miss); + if (result->IsFailure()) return result; // Restore receiver. __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); @@ -2459,9 +2438,17 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, Handle(object->map())); __ j(not_equal, &miss); + // Check that the value in the cell is not the hole. If it is, this + // cell could have been deleted and reintroducing the global needs + // to update the property details in the property dictionary of the + // global object. We bail out to the runtime system to do that. + __ Move(rbx, Handle(cell)); + __ CompareRoot(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), + Heap::kTheHoleValueRootIndex); + __ j(equal, &miss); + // Store the value in the cell. - __ Move(rcx, Handle(cell)); - __ movq(FieldOperand(rcx, JSGlobalPropertyCell::kValueOffset), rax); + __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rax); // Return the value (register rax). __ IncrementCounter(&Counters::named_store_global_inline, 1); @@ -2648,12 +2635,11 @@ MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, // ----------------------------------- Label miss; - Failure* failure = Failure::InternalError(); - bool success = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi, - callback, name, &miss, &failure); - if (!success) { + MaybeObject* result = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, + rdi, callback, name, &miss); + if (result->IsFailure()) { miss.Unuse(); - return failure; + return result; } __ bind(&miss); @@ -2812,12 +2798,11 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( __ Cmp(rax, Handle(name)); __ j(not_equal, &miss); - Failure* failure = Failure::InternalError(); - bool success = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi, - callback, name, &miss, &failure); - if (!success) { + MaybeObject* result = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, + rcx, rdi, callback, name, &miss); + if (result->IsFailure()) { miss.Unuse(); - return failure; + return result; } __ bind(&miss); @@ -2933,7 +2918,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { __ Cmp(rax, Handle(name)); __ j(not_equal, &miss); - GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss); + GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true); __ bind(&miss); __ DecrementCounter(&Counters::keyed_load_string_length, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index 5d2d9cc410..1009f85c0f 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -51,6 +51,8 @@ test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL test-serialize/TestThatAlwaysFails: FAIL test-serialize/DependentTestThatAlwaysFails: FAIL +# BUG(1079) +test-api/CaptureStackTraceForUncaughtException: PASS || FAIL ############################################################################## [ $arch == x64 ] @@ -77,12 +79,9 @@ test-deoptimization/DeoptimizeCompare: FAIL # Tests that time out with crankshaft. test-api/Threading: SKIP -# BUG(1049): Currently no deoptimization support. +# BUG(1069): Context serialization fails on optimized functions. test-serialize/ContextSerialization: SKIP test-serialize/ContextDeserialization: SKIP -test-debug/BreakPointReturn: SKIP -test-debug/DebugStepLinearMixedICs: SKIP -test-debug/DebugConditional: SKIP ############################################################################## [ $arch == arm ] @@ -104,6 +103,11 @@ test-log/ProfLazyMode: SKIP test-debug/DebuggerAgentProtocolOverflowHeader: SKIP test-sockets/Socket: SKIP +# BUG(1075): Some deserialization tests fail om ARM +test-serialize/Deserialize: SKIP +test-serialize/DeserializeFromSecondSerializationAndRunScript2: SKIP +test-serialize/DeserializeAndRunScript2: SKIP +test-serialize/DeserializeFromSecondSerialization: SKIP ############################################################################## [ $arch == arm && $crankshaft ] diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index de00fbba46..48dc72e7b3 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -2383,8 +2383,17 @@ TEST(APIThrowMessageOverwrittenToString) { CompileRun("asdf;"); CompileRun("ReferenceError.prototype.constructor = void 0;"); CompileRun("asdf;"); + CompileRun("ReferenceError.prototype.__proto__ = new Object();"); + CompileRun("asdf;"); + CompileRun("ReferenceError.prototype = new Object();"); + CompileRun("asdf;"); v8::Handle string = CompileRun("try { asdf; } catch(e) { e + ''; }"); CHECK(string->Equals(v8_str("Whoops"))); + CompileRun("ReferenceError.prototype.constructor = new Object();" + "ReferenceError.prototype.constructor.name = 1;" + "Number.prototype.toString = function() { return 'Whoops'; };" + "ReferenceError.prototype.toString = Object.prototype.toString;"); + CompileRun("asdf;"); v8::V8::RemoveMessageListeners(check_message); } diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc index 0f12f985a3..af1a4e8aa4 100644 --- a/deps/v8/test/cctest/test-assembler-arm.cc +++ b/deps/v8/test/cctest/test-assembler-arm.cc @@ -45,11 +45,7 @@ typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4); static v8::Persistent env; -// The test framework does not accept flags on the command line, so we set them static void InitializeVM() { - // enable generation of comments - FLAG_debug_code = true; - if (env.IsEmpty()) { env = v8::Context::New(); } diff --git a/deps/v8/test/cctest/test-assembler-mips.cc b/deps/v8/test/cctest/test-assembler-mips.cc index 955562b287..ecb42e2f7b 100644 --- a/deps/v8/test/cctest/test-assembler-mips.cc +++ b/deps/v8/test/cctest/test-assembler-mips.cc @@ -47,14 +47,10 @@ typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4); static v8::Persistent env; -// The test framework does not accept flags on the command line, so we set them. static void InitializeVM() { // Disable compilation of natives. FLAG_disable_native_files = true; - // Enable generation of comments. - FLAG_debug_code = true; - if (env.IsEmpty()) { env = v8::Context::New(); } diff --git a/deps/v8/test/cctest/test-assembler-x64.cc b/deps/v8/test/cctest/test-assembler-x64.cc index f100b73485..5d292df05f 100644 --- a/deps/v8/test/cctest/test-assembler-x64.cc +++ b/deps/v8/test/cctest/test-assembler-x64.cc @@ -48,6 +48,12 @@ using v8::internal::rcx; using v8::internal::rdx; using v8::internal::rbp; using v8::internal::rsp; +using v8::internal::r8; +using v8::internal::r9; +using v8::internal::r12; +using v8::internal::r13; +using v8::internal::times_1; + using v8::internal::FUNCTION_CAST; using v8::internal::CodeDesc; using v8::internal::less_equal; @@ -289,4 +295,47 @@ TEST(AssemblerX64LoopImmediates) { CHECK_EQ(1, result); } + +TEST(OperandRegisterDependency) { + int offsets[4] = {0, 1, 0xfed, 0xbeefcad}; + for (int i = 0; i < 4; i++) { + int offset = offsets[i]; + CHECK(Operand(rax, offset).AddressUsesRegister(rax)); + CHECK(!Operand(rax, offset).AddressUsesRegister(r8)); + CHECK(!Operand(rax, offset).AddressUsesRegister(rcx)); + + CHECK(Operand(rax, rax, times_1, offset).AddressUsesRegister(rax)); + CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(r8)); + CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(rcx)); + + CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rax)); + CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rcx)); + CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r8)); + CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r9)); + CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rdx)); + CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rsp)); + + CHECK(Operand(rsp, offset).AddressUsesRegister(rsp)); + CHECK(!Operand(rsp, offset).AddressUsesRegister(rax)); + CHECK(!Operand(rsp, offset).AddressUsesRegister(r12)); + + CHECK(Operand(rbp, offset).AddressUsesRegister(rbp)); + CHECK(!Operand(rbp, offset).AddressUsesRegister(rax)); + CHECK(!Operand(rbp, offset).AddressUsesRegister(r13)); + + CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rbp)); + CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rax)); + CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rcx)); + CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r13)); + CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r8)); + CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rsp)); + + CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp)); + CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp)); + CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax)); + CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r12)); + CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13)); + } +} + #undef __ diff --git a/deps/v8/test/es5conform/es5conform.status b/deps/v8/test/es5conform/es5conform.status index a51bd30200..47b6887887 100644 --- a/deps/v8/test/es5conform/es5conform.status +++ b/deps/v8/test/es5conform/es5conform.status @@ -41,11 +41,6 @@ chapter10/10.4/10.4.2/10.4.2-2-c-1: FAIL_OK # We are compatible with Safari and Firefox. chapter11/11.1/11.1.5: UNIMPLEMENTED -# Delete returns true in eval even when it should return false. -# Please see http://code.google.com/p/v8/issues/detail?id=759 -chapter11/11.4/11.4.1//11.4.1-4.a-5: FAIL -chapter11/11.4/11.4.1//11.4.1-4.a-7: FAIL - # We do not have a global object called 'global' as required by tests. chapter15/15.1: FAIL_OK diff --git a/deps/v8/test/mjsunit/debug-evaluate-locals.js b/deps/v8/test/mjsunit/debug-evaluate-locals.js index 8430bd3576..4b87829169 100644 --- a/deps/v8/test/mjsunit/debug-evaluate-locals.js +++ b/deps/v8/test/mjsunit/debug-evaluate-locals.js @@ -34,18 +34,18 @@ exception = false; function checkFrame0(name, value) { - assertTrue(name == 'a' || name == 'b', 'frame0 name'); + assertTrue(name == 'a' || name == 'b'); if (name == 'a') { assertEquals(1, value); - } else if (name == 'b') { + } + if (name == 'b') { assertEquals(2, value); } } function checkFrame1(name, value) { - assertTrue(name == '.arguments' || name == 'arguments' || name == 'a', - 'frame1 name'); + assertTrue(name == '.arguments' || name == 'a'); if (name == 'a') { assertEquals(3, value); } @@ -53,10 +53,12 @@ function checkFrame1(name, value) { function checkFrame2(name, value) { - assertTrue(name == 'a' || name == 'b', 'frame2 name'); + assertTrue(name == '.arguments' || name == 'a' || + name == 'arguments' || name == 'b'); if (name == 'a') { assertEquals(5, value); - } else if (name == 'b') { + } + if (name == 'b') { assertEquals(0, value); } } @@ -71,17 +73,18 @@ function listener(event, exec_state, event_data, data) { checkFrame0(frame0.localName(0), frame0.localValue(0).value()); checkFrame0(frame0.localName(1), frame0.localValue(1).value()); - // Frame 1 has normal variables a and arguments (and the .arguments - // variable). + // Frame 1 has normal variable a (and the .arguments variable). var frame1 = exec_state.frame(1); checkFrame1(frame1.localName(0), frame1.localValue(0).value()); checkFrame1(frame1.localName(1), frame1.localValue(1).value()); - checkFrame1(frame1.localName(2), frame1.localValue(2).value()); - // Frame 2 has normal variables a and b. + // Frame 2 has normal variables a and b (and both the .arguments and + // arguments variable). var frame2 = exec_state.frame(2); checkFrame2(frame2.localName(0), frame2.localValue(0).value()); checkFrame2(frame2.localName(1), frame2.localValue(1).value()); + checkFrame2(frame2.localName(2), frame2.localValue(2).value()); + checkFrame2(frame2.localName(3), frame2.localValue(3).value()); // Evaluating a and b on frames 0, 1 and 2 produces 1, 2, 3, 4, 5 and 6. assertEquals(1, exec_state.frame(0).evaluate('a').value()); diff --git a/deps/v8/test/mjsunit/delete-global-properties.js b/deps/v8/test/mjsunit/delete-global-properties.js index b3813dc150..2acf591635 100644 --- a/deps/v8/test/mjsunit/delete-global-properties.js +++ b/deps/v8/test/mjsunit/delete-global-properties.js @@ -1,4 +1,4 @@ -// Copyright 2008 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -32,6 +32,17 @@ assertFalse(delete tmp); // should be DONT_DELETE assertTrue("tmp" in this); function f() { return 1; } assertFalse(delete f); // should be DONT_DELETE -assertEquals(1, f()); +assertEquals(1, f()); -/* Perhaps related to bugs/11? */ +// Check that deleting and reintroducing global variables works. +// Get into the IC case for storing to a deletable global property. +function introduce_x() { x = 42; } +for (var i = 0; i < 10; i++) introduce_x(); +// Check that the property has been introduced. +assertTrue(this.hasOwnProperty('x')); +// Check that deletion works. +delete x; +assertFalse(this.hasOwnProperty('x')); +// Check that reintroduction works. +introduce_x(); +assertTrue(this.hasOwnProperty('x')); diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index 39ddf5a415..057c0fa874 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -119,9 +119,6 @@ compiler/simple-osr: FAIL # BUG (1026) This test is currently flaky. compiler/simple-osr: SKIP -# BUG(1049): Currently no deoptimization support. -debug-liveedit-newsource: SKIP -debug-liveedit-1: SKIP ############################################################################## [ $arch == mips ] diff --git a/deps/v8/test/mjsunit/regress/regress-70066.js b/deps/v8/test/mjsunit/regress/regress-70066.js new file mode 100644 index 0000000000..b8386a706e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-70066.js @@ -0,0 +1,146 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Regression test for Chromium issue 70066. Delete should work properly +// from inside 'with' scopes. +// http://code.google.com/p/chromium/issues/detail?id=70066 + +x = 0; + +// Delete on a slot from a function's own context. +function test1() { + var value = 1; + var status; + with ({}) { status = delete value; } + return value + ":" + status; +} + +assertEquals("1:false", test1(), "test1"); +assertEquals(0, x, "test1"); // Global x is undisturbed. + + +// Delete on a slot from an outer context. +function test2() { + function f() { + with ({}) { return delete value; } + } + var value = 2; + var status = f(); + return value + ":" + status; +} + +assertEquals("2:false", test2(), "test2"); +assertEquals(0, x, "test2"); // Global x is undisturbed. + + +// Delete on an argument. This hits the same code paths as test5 because +// 'with' forces all parameters to be indirected through the arguments +// object. +function test3(value) { + var status; + with ({}) { status = delete value; } + return value + ":" + status; +} + +assertEquals("undefined:true", test3(3), "test3"); +assertEquals(0, x, "test3"); // Global x is undisturbed. + + +// Delete on an argument from an outer context. This hits the same code +// path as test2. +function test4(value) { + function f() { + with ({}) { return delete value; } + } + var status = f(); + return value + ":" + status; +} + +assertEquals("4:false", test4(4), "test4"); +assertEquals(0, x, "test4"); // Global x is undisturbed. + + +// Delete on an argument found in the arguments object. Such properties are +// normally DONT_DELETE in JavaScript but deletion is allowed by V8. +function test5(value) { + var status; + with ({}) { status = delete value; } + return arguments[0] + ":" + status; +} + +assertEquals("undefined:true", test5(5), "test5"); +assertEquals(0, x, "test5"); // Global x is undisturbed. + +function test6(value) { + function f() { + with ({}) { return delete value; } + } + var status = f(); + return arguments[0] + ":" + status; +} + +assertEquals("undefined:true", test6(6), "test6"); +assertEquals(0, x, "test6"); // Global x is undisturbed. + + +// Delete on a property found on 'with' object. +function test7(object) { + with (object) { return delete value; } +} + +var o = {value: 7}; +assertEquals(true, test7(o), "test7"); +assertEquals(void 0, o.value, "test7"); +assertEquals(0, x, "test7"); // Global x is undisturbed. + + +// Delete on a global property. +function test8() { + with ({}) { return delete x; } +} + +assertEquals(true, test8(), "test8"); +assertThrows("x", "test8"); // Global x should be deleted. + + +// Delete on a property that is not found anywhere. +function test9() { + with ({}) { return delete x; } +} + +assertThrows("x", "test9"); // Make sure it's not there. +assertEquals(true, test9(), "test9"); + + +// Delete on a DONT_DELETE property of the global object. +var y = 10; +function test10() { + with ({}) { return delete y; } +} + +assertEquals(false, test10(), "test10"); +assertEquals(10, y, "test10"); diff --git a/deps/v8/test/mjsunit/strict-mode.js b/deps/v8/test/mjsunit/strict-mode.js index 924b34f936..6f3a244134 100644 --- a/deps/v8/test/mjsunit/strict-mode.js +++ b/deps/v8/test/mjsunit/strict-mode.js @@ -44,6 +44,23 @@ function CheckStrictMode(code, exception) { }", exception); } +function CheckFunctionConstructorStrictMode() { + var args = []; + for (var i = 0; i < arguments.length; i ++) { + args[i] = arguments[i]; + } + // Create non-strict function. No exception. + args[arguments.length] = ""; + assertDoesNotThrow(function() { + Function.apply(this, args); + }); + // Create strict mode function. Exception expected. + args[arguments.length] = "'use strict';"; + assertThrows(function() { + Function.apply(this, args); + }, SyntaxError); +} + // Incorrect 'use strict' directive. function UseStrictEscape() { "use\\x20strict"; @@ -76,19 +93,29 @@ CheckStrictMode("function eval() {}", SyntaxError) CheckStrictMode("function arguments() {}", SyntaxError) // Function parameter named 'eval'. -//CheckStrictMode("function foo(a, b, eval, c, d) {}", SyntaxError) +CheckStrictMode("function foo(a, b, eval, c, d) {}", SyntaxError) // Function parameter named 'arguments'. -//CheckStrictMode("function foo(a, b, arguments, c, d) {}", SyntaxError) +CheckStrictMode("function foo(a, b, arguments, c, d) {}", SyntaxError) // Property accessor parameter named 'eval'. -//CheckStrictMode("var o = { set foo(eval) {} }", SyntaxError) +CheckStrictMode("var o = { set foo(eval) {} }", SyntaxError) // Property accessor parameter named 'arguments'. -//CheckStrictMode("var o = { set foo(arguments) {} }", SyntaxError) +CheckStrictMode("var o = { set foo(arguments) {} }", SyntaxError) // Duplicate function parameter name. -//CheckStrictMode("function foo(a, b, c, d, b) {}", SyntaxError) +CheckStrictMode("function foo(a, b, c, d, b) {}", SyntaxError) + +// Function constructor: eval parameter name. +CheckFunctionConstructorStrictMode("eval") + +// Function constructor: arguments parameter name. +CheckFunctionConstructorStrictMode("arguments") + +// Function constructor: duplicate parameter name. +CheckFunctionConstructorStrictMode("a", "b", "c", "b") +CheckFunctionConstructorStrictMode("a,b,c,b") // catch(eval) CheckStrictMode("try{}catch(eval){};", SyntaxError) @@ -103,10 +130,10 @@ CheckStrictMode("var eval;", SyntaxError) CheckStrictMode("var arguments;", SyntaxError) // Strict mode applies to the function in which the directive is used.. -//assertThrows('\ -//function foo(eval) {\ -// "use strict";\ -//}', SyntaxError); +assertThrows('\ +function foo(eval) {\ + "use strict";\ +}', SyntaxError); // Strict mode doesn't affect the outer stop of strict code. function NotStrict(eval) { @@ -115,3 +142,126 @@ function NotStrict(eval) { } with ({}) {}; } + +// Octal literal +CheckStrictMode("var x = 012"); +CheckStrictMode("012"); +CheckStrictMode("'Hello octal\\032'"); +CheckStrictMode("function octal() { return 012; }"); +CheckStrictMode("function octal() { return '\\032'; }"); + +// Octal before "use strict" +assertThrows('\ + function strict() {\ + "octal\\032directive";\ + "use strict";\ + }', SyntaxError); + +// Duplicate data properties. +CheckStrictMode("var x = { dupe : 1, nondupe: 3, dupe : 2 };", SyntaxError) +CheckStrictMode("var x = { '1234' : 1, '2345' : 2, '1234' : 3 };", SyntaxError) +CheckStrictMode("var x = { '1234' : 1, '2345' : 2, 1234 : 3 };", SyntaxError) +CheckStrictMode("var x = { 3.14 : 1, 2.71 : 2, 3.14 : 3 };", SyntaxError) +CheckStrictMode("var x = { 3.14 : 1, '3.14' : 2 };", SyntaxError) +CheckStrictMode("var x = { 123: 1, 123.00000000000000000000000000000000000000000000000000000000000000000001 : 2 }", SyntaxError) + +// Non-conflicting data properties. +function StrictModeNonDuplicate() { + "use strict"; + var x = { 123 : 1, "0123" : 2 }; + var x = { 123: 1, '123.00000000000000000000000000000000000000000000000000000000000000000001' : 2 } +} + +// Two getters (non-strict) +assertThrows("var x = { get foo() { }, get foo() { } };", SyntaxError) +assertThrows("var x = { get foo(){}, get 'foo'(){}};", SyntaxError) +assertThrows("var x = { get 12(){}, get '12'(){}};", SyntaxError) + +// Two setters (non-strict) +assertThrows("var x = { set foo(v) { }, set foo(v) { } };", SyntaxError) +assertThrows("var x = { set foo(v) { }, set 'foo'(v) { } };", SyntaxError) +assertThrows("var x = { set 13(v) { }, set '13'(v) { } };", SyntaxError) + +// Setter and data (non-strict) +assertThrows("var x = { foo: 'data', set foo(v) { } };", SyntaxError) +assertThrows("var x = { set foo(v) { }, foo: 'data' };", SyntaxError) +assertThrows("var x = { foo: 'data', set 'foo'(v) { } };", SyntaxError) +assertThrows("var x = { set foo(v) { }, 'foo': 'data' };", SyntaxError) +assertThrows("var x = { 'foo': 'data', set foo(v) { } };", SyntaxError) +assertThrows("var x = { set 'foo'(v) { }, foo: 'data' };", SyntaxError) +assertThrows("var x = { 'foo': 'data', set 'foo'(v) { } };", SyntaxError) +assertThrows("var x = { set 'foo'(v) { }, 'foo': 'data' };", SyntaxError) +assertThrows("var x = { 12: 1, set '12'(v){}};", SyntaxError); +assertThrows("var x = { 12: 1, set 12(v){}};", SyntaxError); +assertThrows("var x = { '12': 1, set '12'(v){}};", SyntaxError); +assertThrows("var x = { '12': 1, set 12(v){}};", SyntaxError); + +// Getter and data (non-strict) +assertThrows("var x = { foo: 'data', get foo() { } };", SyntaxError) +assertThrows("var x = { get foo() { }, foo: 'data' };", SyntaxError) +assertThrows("var x = { 'foo': 'data', get foo() { } };", SyntaxError) +assertThrows("var x = { get 'foo'() { }, 'foo': 'data' };", SyntaxError) +assertThrows("var x = { '12': 1, get '12'(){}};", SyntaxError); +assertThrows("var x = { '12': 1, get 12(){}};", SyntaxError); + +// Assignment to eval or arguments +CheckStrictMode("function strict() { eval = undefined; }", SyntaxError) +CheckStrictMode("function strict() { arguments = undefined; }", SyntaxError) +CheckStrictMode("function strict() { print(eval = undefined); }", SyntaxError) +CheckStrictMode("function strict() { print(arguments = undefined); }", SyntaxError) +CheckStrictMode("function strict() { var x = eval = undefined; }", SyntaxError) +CheckStrictMode("function strict() { var x = arguments = undefined; }", SyntaxError) + +// Compound assignment to eval or arguments +CheckStrictMode("function strict() { eval *= undefined; }", SyntaxError) +CheckStrictMode("function strict() { arguments /= undefined; }", SyntaxError) +CheckStrictMode("function strict() { print(eval %= undefined); }", SyntaxError) +CheckStrictMode("function strict() { print(arguments %= undefined); }", SyntaxError) +CheckStrictMode("function strict() { var x = eval += undefined; }", SyntaxError) +CheckStrictMode("function strict() { var x = arguments -= undefined; }", SyntaxError) +CheckStrictMode("function strict() { eval <<= undefined; }", SyntaxError) +CheckStrictMode("function strict() { arguments >>= undefined; }", SyntaxError) +CheckStrictMode("function strict() { print(eval >>>= undefined); }", SyntaxError) +CheckStrictMode("function strict() { print(arguments &= undefined); }", SyntaxError) +CheckStrictMode("function strict() { var x = eval ^= undefined; }", SyntaxError) +CheckStrictMode("function strict() { var x = arguments |= undefined; }", SyntaxError) + +// Postfix increment with eval or arguments +CheckStrictMode("function strict() { eval++; }", SyntaxError) +CheckStrictMode("function strict() { arguments++; }", SyntaxError) +CheckStrictMode("function strict() { print(eval++); }", SyntaxError) +CheckStrictMode("function strict() { print(arguments++); }", SyntaxError) +CheckStrictMode("function strict() { var x = eval++; }", SyntaxError) +CheckStrictMode("function strict() { var x = arguments++; }", SyntaxError) + +// Postfix decrement with eval or arguments +CheckStrictMode("function strict() { eval--; }", SyntaxError) +CheckStrictMode("function strict() { arguments--; }", SyntaxError) +CheckStrictMode("function strict() { print(eval--); }", SyntaxError) +CheckStrictMode("function strict() { print(arguments--); }", SyntaxError) +CheckStrictMode("function strict() { var x = eval--; }", SyntaxError) +CheckStrictMode("function strict() { var x = arguments--; }", SyntaxError) + +// Prefix increment with eval or arguments +CheckStrictMode("function strict() { ++eval; }", SyntaxError) +CheckStrictMode("function strict() { ++arguments; }", SyntaxError) +CheckStrictMode("function strict() { print(++eval); }", SyntaxError) +CheckStrictMode("function strict() { print(++arguments); }", SyntaxError) +CheckStrictMode("function strict() { var x = ++eval; }", SyntaxError) +CheckStrictMode("function strict() { var x = ++arguments; }", SyntaxError) + +// Prefix decrement with eval or arguments +CheckStrictMode("function strict() { --eval; }", SyntaxError) +CheckStrictMode("function strict() { --arguments; }", SyntaxError) +CheckStrictMode("function strict() { print(--eval); }", SyntaxError) +CheckStrictMode("function strict() { print(--arguments); }", SyntaxError) +CheckStrictMode("function strict() { var x = --eval; }", SyntaxError) +CheckStrictMode("function strict() { var x = --arguments; }", SyntaxError) + +// Prefix unary operators other than delete, ++, -- are valid in strict mode +function StrictModeUnaryOperators() { + "use strict"; + var x = [void eval, typeof eval, +eval, -eval, ~eval, !eval]; + var y = [void arguments, typeof arguments, + +arguments, -arguments, ~arguments, !arguments]; +} \ No newline at end of file diff --git a/deps/v8/test/mjsunit/string-charcodeat.js b/deps/v8/test/mjsunit/string-charcodeat.js index fb7ab9af86..f18d0a532e 100644 --- a/deps/v8/test/mjsunit/string-charcodeat.js +++ b/deps/v8/test/mjsunit/string-charcodeat.js @@ -205,3 +205,23 @@ assertTrue(isNaN(long.charCodeAt(-1)), 35); assertEquals(49, long.charCodeAt(0), 36); assertEquals(56, long.charCodeAt(65535), 37); assertTrue(isNaN(long.charCodeAt(65536)), 38); + + +// Test crankshaft code when the function is set directly on the +// string prototype object instead of the hidden prototype object. +// See http://code.google.com/p/v8/issues/detail?id=1070 + +String.prototype.x = String.prototype.charCodeAt; + +function directlyOnPrototype() { + assertEquals(97, "a".x(0)); + assertEquals(98, "b".x(0)); + assertEquals(99, "c".x(0)); + assertEquals(97, "a".x(0)); + assertEquals(98, "b".x(0)); + assertEquals(99, "c".x(0)); +} + +for (var i = 0; i < 10000; i++) { + directlyOnPrototype(); +} diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp index fe4526668f..c5af0164d4 100644 --- a/deps/v8/tools/gyp/v8.gyp +++ b/deps/v8/tools/gyp/v8.gyp @@ -691,6 +691,8 @@ '../../src/x64/jump-target-x64.cc', '../../src/x64/lithium-codegen-x64.cc', '../../src/x64/lithium-codegen-x64.h', + '../../src/x64/lithium-gap-resolver-x64.cc', + '../../src/x64/lithium-gap-resolver-x64.h', '../../src/x64/lithium-x64.cc', '../../src/x64/lithium-x64.h', '../../src/x64/macro-assembler-x64.cc', @@ -747,8 +749,7 @@ 'sources': [ '../../src/platform-win32.cc', ], - # 4355, 4800 came from common.vsprops - 'msvs_disabled_warnings': [4355, 4800], + 'msvs_disabled_warnings': [4351, 4355, 4800], 'link_settings': { 'libraries': [ '-lwinmm.lib' ], },