Improved performance of garbage collection by changing the way we use the marking stack in the event of stack overflow during full garbage collection and by changing the way we mark roots.
Cleaned up ARM version by removing top of stack caching and by introducing push/pop elimination.
Cleaned up the way runtime functions are called to allow runtime calls with no arguments.
Changed Windows build options to make sure that exceptions are disabled and that optimization flags are enabled.
Added first version of Visual Studio project files.
git-svn-id: http://v8.googlecode.com/svn/trunk@13 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/SConscript b/src/SConscript
index d784fa4..407ab5f 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -94,11 +94,10 @@
'ARFLAGS': '/NOLOGO',
'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS /Od /Gm /MTd',
'CCPDBFLAGS': '/Zi',
- 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING', 'DEBUG', '_DEBUG', 'ENABLE_DISASSEMBLER'],
- 'CXXFLAGS': '$CCFLAGS /EHsc /GS- /GR-',
+ 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', '_HAS_EXCEPTIONS=0', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING', 'DEBUG', '_DEBUG', 'ENABLE_DISASSEMBLER'],
+ 'CXXFLAGS': '$CCFLAGS /GS- /GR- /Gy',
'DIALECTFLAGS': '/nologo',
- 'LIBS': 'WS2_32',
- 'LINKFLAGS': '/NOLOGO /SUBSYSTEM:CONSOLE /MACHINE:X86 /INCREMENTAL:NO /DEBUG',
+ 'LINKFLAGS': '/NOLOGO /MACHINE:X86 /INCREMENTAL:NO /NXCOMPAT /IGNORE:4221 /DEBUG',
'PDB': '${TARGET}.pdb',
'WARNINGFLAGS': '/W3 /WX /wd4355 /wd4800'
},
@@ -106,11 +105,10 @@
'ARFLAGS': '/NOLOGO',
'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS /Od /Gm /MTd',
'CCPDBFLAGS': '/Zi',
- 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING', 'DEBUG', '_DEBUG', 'ENABLE_DISASSEMBLER'],
- 'CXXFLAGS': '$CCFLAGS /EHsc /GS- /GR-',
+ 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', '_HAS_EXCEPTIONS=0', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING', 'DEBUG', '_DEBUG', 'ENABLE_DISASSEMBLER'],
+ 'CXXFLAGS': '$CCFLAGS /GS- /GR- /Gy',
'DIALECTFLAGS': '/nologo',
- 'LIBS': 'WS2_32',
- 'LINKFLAGS': '/NOLOGO /SUBSYSTEM:CONSOLE /MACHINE:X86 /INCREMENTAL:NO /DEBUG',
+ 'LINKFLAGS': '/NOLOGO /MACHINE:X86 /INCREMENTAL:NO /NXCOMPAT /IGNORE:4221 /DEBUG',
'PDB': '${TARGET}.pdb',
'WARNINGFLAGS': '/WX /wd4018 /wd4244'
},
@@ -118,51 +116,47 @@
'ARFLAGS': '/NOLOGO',
'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS /Od /Gm /MTd',
'CCPDBFLAGS': '/Zi',
- 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING', 'DEBUG', '_DEBUG', 'ENABLE_DISASSEMBLER', 'SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
- 'CXXFLAGS': '$CCFLAGS /EHsc /GS- /GR-',
+ 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', '_HAS_EXCEPTIONS=0', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING', 'DEBUG', '_DEBUG', 'ENABLE_DISASSEMBLER', 'SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
+ 'CXXFLAGS': '$CCFLAGS /GS- /GR- /Gy',
'DIALECTFLAGS': '/nologo',
- 'LIBS': 'WS2_32',
- 'LINKFLAGS': '/NOLOGO /SUBSYSTEM:CONSOLE /MACHINE:X86 /INCREMENTAL:NO /DEBUG',
+ 'LINKFLAGS': '/NOLOGO /MACHINE:X86 /INCREMENTAL:NO /NXCOMPAT /IGNORE:4221 /DEBUG',
'PDB': '${TARGET}.pdb',
- 'WARNINGFLAGS': '/WX /wd4003 /wd4005 /wd4018 /wd4133'
+ 'WARNINGFLAGS': '/W3 /WX /wd4355 /wd4800'
}
},
'release': {
'default': {
'ARFLAGS': '/NOLOGO',
- 'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS /O2 /MT',
+ 'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS /Ox /MT /Ob2 /Oi /Oy',
'CCPDBFLAGS': '/Zi',
- 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING'],
- 'CXXFLAGS': '$CCFLAGS /EHsc /GS- /GR-',
+ 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', '_HAS_EXCEPTIONS=0', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING'],
+ 'CXXFLAGS': '$CCFLAGS /GS- /GR- /Gy',
'DIALECTFLAGS': '/nologo',
- 'LIBS': 'WS2_32',
- 'LINKFLAGS': '/NOLOGO /SUBSYSTEM:CONSOLE /MACHINE:X86 /INCREMENTAL:NO /OPT:REF /OPT:ICF /SUBSYSTEM:CONSOLE',
+ 'LINKFLAGS': '/NOLOGO /MACHINE:X86 /INCREMENTAL:NO /NXCOMPAT /IGNORE:4221 /OPT:REF',
'PDB': '${TARGET}.pdb',
'WARNINGFLAGS': '/W3 /WX /wd4355 /wd4800'
},
'dtoa': {
'ARFLAGS': '/NOLOGO',
- 'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS /O2 /MT',
+ 'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS /Ox /MT /Ob2 /Oi /Oy',
'CCPDBFLAGS': '/Zi',
- 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING'],
- 'CXXFLAGS': '$CCFLAGS /EHsc /GS- /GR-',
+ 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', '_HAS_EXCEPTIONS=0', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING'],
+ 'CXXFLAGS': '$CCFLAGS /GS- /GR- /Gy',
'DIALECTFLAGS': '/nologo',
- 'LIBS': 'WS2_32',
- 'LINKFLAGS': '/NOLOGO /SUBSYSTEM:CONSOLE /MACHINE:X86 /INCREMENTAL:NO /OPT:REF /OPT:ICF /SUBSYSTEM:CONSOLE',
+ 'LINKFLAGS': '/NOLOGO /MACHINE:X86 /INCREMENTAL:NO /NXCOMPAT /IGNORE:4221 /OPT:REF',
'PDB': '${TARGET}.pdb',
'WARNINGFLAGS': '/WX /wd4018 /wd4244'
},
'jscre': {
'ARFLAGS': '/NOLOGO',
- 'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS /O2 /MT',
+ 'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS /Ox /MT /Ob2 /Oi /Oy',
'CCPDBFLAGS': '/Zi',
- 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING', 'SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
- 'CXXFLAGS': '$CCFLAGS /EHsc /GS- /GR-',
+ 'CPPDEFINES': ['WIN32', '_CRT_SECURE_NO_DEPRECATE', '_CRT_NONSTDC_NO_DEPRECATE', '_USE_32BIT_TIME_T', '_HAS_EXCEPTIONS=0', 'PCRE_STATIC', 'ENABLE_LOGGING_AND_PROFILING', 'SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
+ 'CXXFLAGS': '$CCFLAGS /GS- /GR- /Gy',
'DIALECTFLAGS': '/nologo',
- 'LIBS': 'WS2_32',
- 'LINKFLAGS': '/NOLOGO /SUBSYSTEM:CONSOLE /MACHINE:X86 /INCREMENTAL:NO /OPT:REF /OPT:ICF /SUBSYSTEM:CONSOLE',
+ 'LINKFLAGS': '/NOLOGO /MACHINE:X86 /INCREMENTAL:NO /NXCOMPAT /IGNORE:4221 /OPT:REF',
'PDB': '${TARGET}.pdb',
- 'WARNINGFLAGS': '/WX /wd4003 /wd4005 /wd4018 /wd4133'
+ 'WARNINGFLAGS': '/W3 /WX /wd4355 /wd4800'
}
}
}
diff --git a/src/api.cc b/src/api.cc
index 8051962..3c2fc12 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2091,7 +2091,7 @@
const char* v8::V8::GetVersion() {
- return "0.2.1 (130029)";
+ return "0.2.2 (130807)";
}
diff --git a/src/arguments.h b/src/arguments.h
index 418d568..55e9c45 100644
--- a/src/arguments.h
+++ b/src/arguments.h
@@ -45,7 +45,7 @@
class Arguments BASE_EMBEDDED {
public:
Object*& operator[] (int index) {
- ASSERT(0 <= index && index <= length_);
+ ASSERT(0 <= index && index < length_);
return arguments_[-index];
}
@@ -58,7 +58,7 @@
}
// Get the total number of arguments including the receiver.
- int length() const { return length_ + 1; }
+ int length() const { return length_; }
private:
int length_;
diff --git a/src/assembler-arm-inl.h b/src/assembler-arm-inl.h
index 4d9a46c..fbe8cce 100644
--- a/src/assembler-arm-inl.h
+++ b/src/assembler-arm-inl.h
@@ -170,6 +170,14 @@
}
+bool Operand::is_reg() const {
+ return rm_.is_valid() &&
+ rs_.is(no_reg) &&
+ shift_op_ == LSL &&
+ shift_imm_ == 0;
+}
+
+
void Assembler::CheckBuffer() {
if (buffer_space() <= kGap) {
GrowBuffer();
diff --git a/src/assembler-arm.cc b/src/assembler-arm.cc
index d92e35c..70e7b42 100644
--- a/src/assembler-arm.cc
+++ b/src/assembler-arm.cc
@@ -252,6 +252,7 @@
B27 = 1 << 27,
// Instruction bit masks
+ RdMask = 15 << 12, // in str instruction
CondMask = 15 << 28,
OpCodeMask = 15 << 21, // in data-processing instructions
Imm24Mask = (1 << 24) - 1,
@@ -261,6 +262,23 @@
};
+DEFINE_bool(push_pop_elimination, true,
+ "eliminate redundant push/pops in assembly code");
+DEFINE_bool(print_push_pop_elimination, false,
+ "print elimination of redundant push/pops in assembly code");
+
+// add(sp, sp, 4) instruction (aka Pop())
+static const Instr kPopInstruction =
+ al | 4 * B21 | 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 =
+ 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 =
+ al | B26 | L | 4 | PostIndex | sp.code() * B16;
+
// spare_buffer_
static const int kMinimalBufferSize = 4*KB;
static byte* spare_buffer_ = NULL;
@@ -817,6 +835,23 @@
void Assembler::add(Register dst, Register src1, const Operand& src2,
SBit s, Condition cond) {
addrmod1(cond | 4*B21 | s, src1, dst, src2);
+
+ // Eliminate pattern: push(r), pop()
+ // str(src, MemOperand(sp, 4, NegPreIndex), al);
+ // add(sp, sp, Operand(kPointerSize));
+ // Both instructions can be eliminated.
+ int pattern_size = 2 * kInstrSize;
+ if (FLAG_push_pop_elimination &&
+ last_bound_pos_ <= (pc_offset() - pattern_size) &&
+ reloc_info_writer.last_pc() <= (pc_ - pattern_size) &&
+ // pattern
+ instr_at(pc_ - 1 * kInstrSize) == kPopInstruction &&
+ (instr_at(pc_ - 2 * kInstrSize) & ~RdMask) == kPushRegPattern) {
+ pc_ -= 2 * kInstrSize;
+ if (FLAG_print_push_pop_elimination) {
+ PrintF("%x push(reg)/pop() eliminated\n", pc_offset());
+ }
+ }
}
@@ -994,11 +1029,44 @@
// Load/Store instructions
void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
addrmod2(cond | B26 | L, dst, src);
+
+ // Eliminate pattern: push(r), pop(r)
+ // str(r, MemOperand(sp, 4, NegPreIndex), al)
+ // ldr(r, MemOperand(sp, 4, PostIndex), al)
+ // Both instructions can be eliminated.
+ int pattern_size = 2 * kInstrSize;
+ if (FLAG_push_pop_elimination &&
+ last_bound_pos_ <= (pc_offset() - pattern_size) &&
+ reloc_info_writer.last_pc() <= (pc_ - pattern_size) &&
+ // pattern
+ instr_at(pc_ - 1 * kInstrSize) == (kPopRegPattern | dst.code() * B12) &&
+ instr_at(pc_ - 2 * kInstrSize) == (kPushRegPattern | dst.code() * B12)) {
+ pc_ -= 2 * kInstrSize;
+ if (FLAG_print_push_pop_elimination) {
+ PrintF("%x push/pop (same reg) eliminated\n", pc_offset());
+ }
+ }
}
void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
addrmod2(cond | B26, src, dst);
+
+ // Eliminate pattern: pop(), push(r)
+ // add sp, sp, #4 LeaveCC, al; str r, [sp, #-4], al
+ // -> str r, [sp, 0], al
+ int pattern_size = 2 * kInstrSize;
+ if (FLAG_push_pop_elimination &&
+ last_bound_pos_ <= (pc_offset() - pattern_size) &&
+ reloc_info_writer.last_pc() <= (pc_ - pattern_size) &&
+ instr_at(pc_ - 1 * kInstrSize) == (kPushRegPattern | src.code() * B12) &&
+ instr_at(pc_ - 2 * kInstrSize) == kPopInstruction) {
+ pc_ -= 2 * kInstrSize;
+ emit(al | B26 | 0 | Offset | sp.code() * B16 | src.code() * B12);
+ if (FLAG_print_push_pop_elimination) {
+ PrintF("%x pop()/push(reg) eliminated\n", pc_offset());
+ }
+ }
}
diff --git a/src/assembler-arm.h b/src/assembler-arm.h
index e3f5692..43bedff 100644
--- a/src/assembler-arm.h
+++ b/src/assembler-arm.h
@@ -306,6 +306,11 @@
// rm <shift_op> rs
explicit Operand(Register rm, ShiftOp shift_op, Register rs);
+ // Return true if this is a register operand.
+ INLINE(bool is_reg() const);
+
+ Register rm() const { return rm_; }
+
private:
Register rm_;
Register rs_;
@@ -583,12 +588,16 @@
// Pseudo instructions
void nop() { mov(r0, Operand(r0)); }
- void push(Register src, Condition cond = al) {
- str(src, MemOperand(sp, 4, NegPreIndex), cond);
+ void push(Register src) {
+ str(src, MemOperand(sp, 4, NegPreIndex), al);
}
- void pop(Register dst, Condition cond = al) {
- ldr(dst, MemOperand(sp, 4, PostIndex), cond);
+ void pop(Register dst) {
+ ldr(dst, MemOperand(sp, 4, PostIndex), al);
+ }
+
+ void pop() {
+ add(sp, sp, Operand(kPointerSize));
}
// Load effective address of memory operand x into register dst
diff --git a/src/assembler.cc b/src/assembler.cc
index b3c8afb..ebe0d6a 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -435,10 +435,8 @@
}
return "unknown relocation type";
}
-#endif // ENABLE_DISASSEMBLER
-#ifdef DEBUG
void RelocInfo::Print() {
PrintF("%p %s", pc_, RelocModeName(rmode_));
if (rmode_ == comment) {
@@ -461,8 +459,10 @@
PrintF("\n");
}
+#endif // ENABLE_DISASSEMBLER
+#ifdef DEBUG
void RelocInfo::Verify() {
switch (rmode_) {
case embedded_object:
diff --git a/src/assembler.h b/src/assembler.h
index a149f8c..9eb0cea 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -271,10 +271,10 @@
#ifdef ENABLE_DISASSEMBLER
// Printing
static const char* RelocModeName(RelocMode rmode);
+ void Print();
#endif // ENABLE_DISASSEMBLER
#ifdef DEBUG
// Debugging
- void Print();
void Verify();
#endif
diff --git a/src/builtins-arm.cc b/src/builtins-arm.cc
index 4cb54f5..323cb3d 100644
--- a/src/builtins-arm.cc
+++ b/src/builtins-arm.cc
@@ -40,6 +40,10 @@
void Builtins::Generate_Adaptor(MacroAssembler* masm,
int argc,
CFunctionId id) {
+ // r0 contains the number of arguments excluding the receiver.
+ // JumpToBuiltin expects r0 to contains the number of arguments
+ // including the receiver.
+ __ add(r0, r0, Operand(1));
__ JumpToBuiltin(ExternalReference(id));
}
@@ -50,10 +54,10 @@
__ EnterJSFrame(0);
// Allocate the new receiver object.
- __ push(r0);
__ ldr(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
+ __ push(r0);
__ CallRuntime(Runtime::kNewObject, 1);
- __ push(r0); // empty TOS cache
+ __ push(r0); // save the receiver
// Push the function and the allocated receiver from the stack.
__ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
@@ -90,7 +94,7 @@
// Restore context from the frame and discard the function.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- __ add(sp, sp, Operand(kPointerSize));
+ __ pop();
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
@@ -273,20 +277,15 @@
__ add(fp, sp, Operand(-StandardFrameConstants::kContextOffset));
__ mov(pp, Operand(ip)); // setup new parameter pointer
// r0 is already set to 0 as spare slot to store caller code object during GC
+ __ push(r0); // code pointer
// Inlined EnterJSFrame ends here.
- // Empty top-of-stack cache (code pointer).
- __ push(r0);
-
// Store the registers containing object pointers on the expression stack to
// make sure that these are correctly updated during GC.
// Use sp as base to push.
__ CopyRegistersFromMemoryToStack(sp, pointer_regs);
- // Empty top-of-stack cache (fake receiver).
- __ push(r0);
-
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
@@ -308,7 +307,7 @@
__ mov(sp, Operand(fp)); // respect ABI stack constraint
__ ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | lr.bit());
- __ add(sp, sp, Operand(kPointerSize)); // discard fake function
+ __ pop(); // discard fake function
// Inlined ExitJSFrame ends here.
diff --git a/src/builtins-ia32.cc b/src/builtins-ia32.cc
index e7a7e83..f61454a 100644
--- a/src/builtins-ia32.cc
+++ b/src/builtins-ia32.cc
@@ -40,7 +40,10 @@
void Builtins::Generate_Adaptor(MacroAssembler* masm,
int argc,
CFunctionId id) {
- __ mov(eax, argc);
+ // argc is the number of arguments excluding the receiver.
+ // JumpToBuiltin expects eax to contain the number of arguments
+ // including the receiver.
+ __ mov(eax, argc + 1);
__ mov(Operand::StaticVariable(ExternalReference::builtin_passed_function()),
edi);
__ JumpToBuiltin(ExternalReference(id));
@@ -754,7 +757,6 @@
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ Set(eax, Immediate(0)); // no arguments
- __ push(eax); // fake receiver - use NULL
__ mov(Operand(ebx), Immediate(ExternalReference::debug_break()));
CEntryDebugBreakStub ceb;
diff --git a/src/builtins.cc b/src/builtins.cc
index 1f859b9..b51c39b 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -34,6 +34,11 @@
namespace v8 { namespace internal {
+#ifdef DEBUG
+ DECLARE_bool(print_builtin_code);
+#endif // DEBUG
+
+
// ----------------------------------------------------------------------------
// Support macros for defining builtins in C.
// ----------------------------------------------------------------------------
@@ -58,6 +63,8 @@
//
// and they evaluate to undefined values if too few arguments were
// passed to the builtin function invocation.
+//
+// __argc__ is the number of arguments including the receiver.
// ----------------------------------------------------------------------------
@@ -82,7 +89,8 @@
} else if (type == StackFrame::ARGUMENTS_ADAPTOR) { \
ArgumentsAdaptorFrame* frame = \
ArgumentsAdaptorFrame::cast(it.frame()); \
- __argc__ = frame->GetProvidedParametersCount(); \
+ /* __argc__ includes the receiver. */ \
+ __argc__ = frame->GetProvidedParametersCount() + 1; \
__argv__ = reinterpret_cast<Object**>(frame->pp()) - 1; \
it.Advance(); \
is_construct = \
@@ -107,17 +115,11 @@
Object* a2 = BUILTIN_ARG(3);
-#define BUILTIN_VARARG(name, aidx0, aidxN) \
- BUILTIN_0(name); \
- int aidx0 = 1; \
- int aidxN = __argc__; \
-
-
// Use an inline function to avoid evaluating the index (n) more than
// once in the BUILTIN_ARG macro.
static inline Object* __builtin_arg__(int n, int argc, Object** argv) {
ASSERT(n >= 0);
- return (argc >= n) ? argv[-n] : Heap::undefined_value();
+ return (argc > n) ? argv[-n] : Heap::undefined_value();
}
@@ -181,7 +183,7 @@
// Optimize the case where there is one argument and the argument is a
// small smi.
- if (__argc__ == 1) {
+ if (__argc__ == 2) {
Object* obj = BUILTIN_ARG(1);
if (obj->IsSmi()) {
int len = Smi::cast(obj)->value();
@@ -195,26 +197,27 @@
// Take the argument as the length.
obj = array->Initialize(0);
if (obj->IsFailure()) return obj;
- if (__argc__ == 1) return array->SetElementsLength(BUILTIN_ARG(1));
+ if (__argc__ == 2) return array->SetElementsLength(BUILTIN_ARG(1));
}
// Optimize the case where there are no paramaters passed.
- if (__argc__ == 0) return array->Initialize(4);
+ if (__argc__ == 1) return array->Initialize(4);
// Take the arguments as elements.
- int len = Smi::FromInt(__argc__)->value();
- Object* obj = Heap::AllocateFixedArrayWithHoles(len);
+ int number_of_elements = __argc__ - 1;
+ Smi* len = Smi::FromInt(number_of_elements);
+ Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
if (obj->IsFailure()) return obj;
FixedArray* elms = FixedArray::cast(obj);
FixedArray::WriteBarrierMode mode = elms->GetWriteBarrierMode();
// Fill in the content
- for (int index = 0; index < __argc__; index++) {
+ for (int index = 0; index < number_of_elements; index++) {
elms->set(index, BUILTIN_ARG(index+1), mode);
}
// Set length and elements on the array.
array->set_elements(FixedArray::cast(obj));
- array->set_length(Smi::FromInt(__argc__));
+ array->set_length(len);
return array;
}
@@ -229,12 +232,12 @@
int len = Smi::cast(array->length())->value();
// Set new length.
- int new_length = len + __argc__;
+ int new_length = len + __argc__ - 1;
FixedArray* elms = FixedArray::cast(array->elements());
if (new_length <= elms->length()) {
// Backing storage has extra space for the provided values.
- for (int index = 0; index < __argc__; index++) {
+ for (int index = 0; index < __argc__ - 1; index++) {
elms->set(index + len, BUILTIN_ARG(index+1));
}
} else {
@@ -247,7 +250,7 @@
// Fill out the new array with old elements.
for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
// Add the provided values.
- for (int index = 0; index < __argc__; index++) {
+ for (int index = 0; index < __argc__ - 1; index++) {
new_elms->set(index + len, BUILTIN_ARG(index+1), mode);
}
// Set the new backing storage.
@@ -327,7 +330,7 @@
if (args_obj->IsUndefined()) return holder;
FixedArray* args = FixedArray::cast(args_obj);
int length = args->length();
- if (argc < length) length = argc;
+ if (argc <= length) length = argc - 1;
for (int i = 0; i < length; i++) {
Object* argtype = args->get(i);
if (argtype->IsUndefined()) continue;
@@ -405,7 +408,7 @@
callee,
is_construct,
reinterpret_cast<void**>(__argv__ - 1),
- __argc__);
+ __argc__ - 1);
v8::Handle<v8::Value> value;
{
@@ -467,7 +470,7 @@
callee,
is_construct,
reinterpret_cast<void**>(__argv__ - 1),
- __argc__);
+ __argc__ - 1);
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
@@ -692,6 +695,13 @@
// Log the event and add the code to the builtins array.
LOG(CodeCreateEvent("Builtin", Code::cast(code), functions[i].s_name));
builtins_[i] = code;
+#ifdef DEBUG
+ if (FLAG_print_builtin_code) {
+ PrintF("Builtin: %s\n", functions[i].s_name);
+ code->Print();
+ PrintF("\n");
+ }
+#endif
} else {
// Deserializing. The values will be filled in during IterateBuiltins.
builtins_[i] = NULL;
diff --git a/src/code-stubs.h b/src/code-stubs.h
index b198663..b4f7c28 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -69,6 +69,10 @@
virtual ~CodeStub() {}
+ protected:
+ static const int kMajorBits = 5;
+ static const int kMinorBits = kBitsPerPointer - kMajorBits - kSmiTagSize;
+
private:
// Generates the assembler code for the stub.
virtual void Generate(MacroAssembler* masm) = 0;
@@ -93,9 +97,6 @@
bool AllowsStubCalls() { return MajorKey() <= RecordWrite; }
- static const int kMajorBits = 5;
- static const int kMinorBits = kBitsPerPointer - kMajorBits - kSmiTagSize;
-
class MajorKeyBits: public BitField<uint32_t, 0, kMajorBits> {};
class MinorKeyBits: public BitField<uint32_t, kMajorBits, kMinorBits> {};
diff --git a/src/code.h b/src/code.h
index 4f44583..004c362 100644
--- a/src/code.h
+++ b/src/code.h
@@ -55,10 +55,10 @@
}
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterCount);
-
const Register reg_;
const int immediate_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterCount);
};
diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc
index 4513291..da7c73f 100644
--- a/src/codegen-arm.cc
+++ b/src/codegen-arm.cc
@@ -41,11 +41,14 @@
DECLARE_bool(debug_info);
DECLARE_bool(debug_code);
+#ifdef ENABLE_DISASSEMBLER
+DEFINE_bool(print_code, false, "print generated code");
+#endif
+
#ifdef DEBUG
DECLARE_bool(gc_greedy);
DEFINE_bool(trace_codegen, false,
"print name of functions for which code is generated");
-DEFINE_bool(print_code, false, "print generated code");
DEFINE_bool(print_builtin_code, false, "print generated code for builtins");
DEFINE_bool(print_source, false, "pretty print source code");
DEFINE_bool(print_builtin_source, false,
@@ -233,7 +236,7 @@
AccessReference(ref, CodeGenState::INIT_CONST);
}
- void ToBoolean(Register reg, Label* true_target, Label* false_target);
+ void ToBoolean(Label* true_target, Label* false_target);
// Access property from the reference (must be at the TOS).
@@ -303,10 +306,13 @@
Handle<Code> ArmCodeGenerator::MakeCode(FunctionLiteral* flit,
Handle<Script> script,
bool is_eval) {
+#ifdef ENABLE_DISASSEMBLER
+ bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
+#endif // ENABLE_DISASSEMBLER
+
#ifdef DEBUG
bool print_source = false;
bool print_ast = false;
- bool print_code = false;
const char* ftype;
if (Bootstrapper::IsActive()) {
@@ -317,7 +323,6 @@
} else {
print_source = FLAG_print_source;
print_ast = FLAG_print_ast;
- print_code = FLAG_print_code;
ftype = "user-defined";
}
@@ -358,7 +363,7 @@
// Add unresolved entries in the code to the fixup list.
Bootstrapper::AddFixup(*code, cgen.masm());
-#ifdef DEBUG
+#ifdef ENABLE_DISASSEMBLER
if (print_code) {
// Print the source code if available.
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
@@ -374,9 +379,9 @@
PrintF("\n\n");
}
PrintF("--- Code ---\n");
- code->Print();
+ code->Disassemble();
}
-#endif // DEBUG
+#endif // ENABLE_DISASSEMBLER
return code;
}
@@ -396,8 +401,7 @@
// Calling conventions:
-// r0: always contains top-of-stack (TOS), but in case of a call it's
-// the number of arguments
+// r0: the number of arguments
// fp: frame pointer
// sp: stack pointer
// pp: caller's parameter pointer
@@ -435,20 +439,18 @@
// Allocate space for locals and initialize them.
if (scope->num_stack_slots() > 0) {
Comment cmnt(masm_, "[ allocate space for locals");
- // Pushing the first local materializes the code slot on the stack
- // (formerly stored in tos register r0).
- __ Push(Operand(Factory::undefined_value()));
- // The remaining locals are pushed using the fact that r0 (tos)
- // already contains the undefined value.
- for (int i = 1; i < scope->num_stack_slots(); i++) {
- __ push(r0);
+ // Initialize stack slots with 'undefined' value.
+ __ mov(ip, Operand(Factory::undefined_value()));
+ for (int i = 0; i < scope->num_stack_slots(); i++) {
+ __ push(ip);
}
}
if (scope->num_heap_slots() > 0) {
// Allocate local context.
// Get outer context and create a new context based on it.
- __ Push(FunctionOperand());
+ __ ldr(r0, FunctionOperand());
+ __ push(r0);
__ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result
if (kDebug) {
@@ -458,7 +460,6 @@
__ stop("NewContext: r0 is expected to be the same as cp");
__ bind(&verified_true);
}
- __ pop(r0); // restore TOS
// Update context local.
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
@@ -505,8 +506,10 @@
Comment cmnt(masm_, "[ allocate arguments object");
{
Reference target(this, scope->arguments());
- __ Push(FunctionOperand());
+ __ ldr(r0, FunctionOperand());
+ __ push(r0);
__ CallRuntime(Runtime::kNewArguments, 1);
+ __ push(r0);
SetValue(&target);
}
// The value of arguments must also be stored in .arguments.
@@ -528,13 +531,21 @@
scope->VisitIllegalRedeclaration(this);
} else {
Comment cmnt(masm_, "[ declarations");
+ // ProcessDeclarations calls DeclareGlobals indirectly
ProcessDeclarations(scope->declarations());
+
// Bail out if a stack-overflow exception occured when
// processing declarations.
if (HasStackOverflow()) return;
}
- if (FLAG_trace) __ CallRuntime(Runtime::kTraceEnter, 1);
+ if (FLAG_trace) {
+ // Push a valid value as the parameter. The runtime call only uses
+ // it as the return value to indicate non-failure.
+ __ mov(r0, Operand(Smi::FromInt(0)));
+ __ push(r0);
+ __ CallRuntime(Runtime::kTraceEnter, 1);
+ }
CheckStack();
// Compile the body of the function in a vanilla state. Don't
@@ -546,7 +557,13 @@
bool is_builtin = Bootstrapper::IsActive();
bool should_trace =
is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
- if (should_trace) __ CallRuntime(Runtime::kDebugTrace, 1);
+ if (should_trace) {
+ // Push a valid value as the parameter. The runtime call only uses
+ // it as the return value to indicate non-failure.
+ __ mov(r0, Operand(Smi::FromInt(0)));
+ __ push(r0);
+ __ CallRuntime(Runtime::kDebugTrace, 1);
+ }
#endif
VisitStatements(body);
}
@@ -560,9 +577,16 @@
// fp: frame pointer
// pp: parameter pointer
// cp: callee's context
- __ Push(Operand(Factory::undefined_value()));
+ __ mov(r0, Operand(Factory::undefined_value()));
+
__ bind(&function_return_);
- if (FLAG_trace) __ CallRuntime(Runtime::kTraceExit, 1);
+ if (FLAG_trace) {
+ // Push the return value on the stack as the parameter.
+ // Runtime::TraceExit returns the parameter as it is.
+ __ push(r0);
+ __ CallRuntime(Runtime::kTraceExit, 1);
+ }
+
ExitJSFrame();
// Code generation state must be reset.
@@ -629,10 +653,10 @@
}
-// Loads a value on TOS. If it is a boolean value, the result may have been
-// (partially) translated into branches, or it may have set the condition code
-// register. If force_cc is set, the value is forced to set the condition code
-// register and no value is pushed. If the condition code register was set,
+// Loads a value on the stack. If it is a boolean value, the result may have
+// been (partially) translated into branches, or it may have set the condition
+// code register. If force_cc is set, the value is forced to set the condition
+// code register and no value is pushed. If the condition code register was set,
// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
void ArmCodeGenerator::LoadCondition(Expression* x,
CodeGenState::AccessType access,
@@ -649,11 +673,8 @@
Visit(x);
state_ = old_state;
if (force_cc && !has_cc()) {
- // Pop the TOS from the stack and convert it to a boolean in the
- // condition code register.
- __ mov(r1, Operand(r0));
- __ pop(r0);
- ToBoolean(r1, true_target, false_target);
+ // Convert the TOS value to a boolean in the condition code register.
+ ToBoolean(true_target, false_target);
}
ASSERT(has_cc() || !force_cc);
}
@@ -671,10 +692,12 @@
// convert cc_reg_ into a bool
Label loaded, materialize_true;
__ b(cc_reg_, &materialize_true);
- __ Push(Operand(Factory::false_value()));
+ __ mov(r0, Operand(Factory::false_value()));
+ __ push(r0);
__ b(&loaded);
__ bind(&materialize_true);
- __ Push(Operand(Factory::true_value()));
+ __ mov(r0, Operand(Factory::true_value()));
+ __ push(r0);
__ bind(&loaded);
cc_reg_ = al;
}
@@ -689,7 +712,8 @@
// reincarnate "true", if necessary
if (true_target.is_linked()) {
__ bind(&true_target);
- __ Push(Operand(Factory::true_value()));
+ __ mov(r0, Operand(Factory::true_value()));
+ __ push(r0);
}
// if both "true" and "false" need to be reincarnated,
// jump across code for "false"
@@ -698,7 +722,8 @@
// reincarnate "false", if necessary
if (false_target.is_linked()) {
__ bind(&false_target);
- __ Push(Operand(Factory::false_value()));
+ __ mov(r0, Operand(Factory::false_value()));
+ __ push(r0);
}
// everything is loaded at this point
__ bind(&loaded);
@@ -708,7 +733,8 @@
void ArmCodeGenerator::LoadGlobal() {
- __ Push(GlobalObject());
+ __ ldr(r0, GlobalObject());
+ __ push(r0);
}
@@ -776,6 +802,7 @@
} else {
Load(e);
__ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ push(r0);
}
}
@@ -785,7 +812,9 @@
if (size <= 0) {
// Do nothing. No popping is necessary.
} else {
+ __ pop(r0);
__ add(sp, sp, Operand(size * kPointerSize));
+ __ push(r0);
}
}
@@ -805,43 +834,38 @@
// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given
// register to a boolean in the condition code register. The code
// may jump to 'false_target' in case the register converts to 'false'.
-void ArmCodeGenerator::ToBoolean(Register reg,
- Label* true_target,
+void ArmCodeGenerator::ToBoolean(Label* true_target,
Label* false_target) {
- // Note: The generated code snippet cannot change 'reg'.
+ // Note: The generated code snippet does not change stack variables.
// Only the condition code should be set.
+ __ pop(r0);
// Fast case checks
- // Check if reg is 'false'.
- __ cmp(reg, Operand(Factory::false_value()));
+ // Check if the value is 'false'.
+ __ cmp(r0, Operand(Factory::false_value()));
__ b(eq, false_target);
- // Check if reg is 'true'.
- __ cmp(reg, Operand(Factory::true_value()));
+ // Check if the value is 'true'.
+ __ cmp(r0, Operand(Factory::true_value()));
__ b(eq, true_target);
- // Check if reg is 'undefined'.
- __ cmp(reg, Operand(Factory::undefined_value()));
+ // Check if the value is 'undefined'.
+ __ cmp(r0, Operand(Factory::undefined_value()));
__ b(eq, false_target);
- // Check if reg is a smi.
- __ cmp(reg, Operand(Smi::FromInt(0)));
+ // Check if the value is a smi.
+ __ cmp(r0, Operand(Smi::FromInt(0)));
__ b(eq, false_target);
- __ tst(reg, Operand(kSmiTagMask));
+ __ tst(r0, Operand(kSmiTagMask));
__ b(eq, true_target);
// Slow case: call the runtime.
__ push(r0);
- if (r0.is(reg)) {
- __ CallRuntime(Runtime::kToBool, 1);
- } else {
- __ mov(r0, Operand(reg));
- __ CallRuntime(Runtime::kToBool, 1);
- }
+ __ CallRuntime(Runtime::kToBool, 1);
+
// Convert result (r0) to condition code
__ cmp(r0, Operand(Factory::false_value()));
- __ pop(r0);
cc_reg_ = ne;
}
@@ -865,9 +889,11 @@
void GetPropertyStub::Generate(MacroAssembler* masm) {
+ // sp[0]: key
+ // sp[1]: receiver
Label slow, fast;
- // Get the object from the stack.
- __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // 1 ~ key
+ // Get the key and receiver object from the stack.
+ __ ldm(ia, sp, r0.bit() | r1.bit());
// Check that the key is a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(ne, &slow);
@@ -903,8 +929,7 @@
__ ldm(ia, sp, r0.bit() | r1.bit());
__ stm(db_w, sp, r0.bit() | r1.bit());
// Do tail-call to runtime routine.
- __ mov(r0, Operand(1)); // not counting receiver
- __ JumpToBuiltin(ExternalReference(Runtime::kGetProperty));
+ __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2);
// Fast case: Do the load.
__ bind(&fast);
@@ -932,10 +957,15 @@
};
+
void SetPropertyStub::Generate(MacroAssembler* masm) {
+ // r0 : value
+ // sp[0] : key
+ // sp[1] : receiver
+
Label slow, fast, array, extra, exit;
// Get the key and the object from the stack.
- __ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object
+ __ ldm(ia, sp, r1.bit() | r3.bit()); // r1 = key, r3 = receiver
// Check that the key is a smi.
__ tst(r1, Operand(kSmiTagMask));
__ b(ne, &slow);
@@ -970,13 +1000,11 @@
// Slow case: Push extra copies of the arguments (3).
- // r0 == value
__ bind(&slow);
__ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object
__ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit());
// Do tail-call to runtime routine.
- __ mov(r0, Operand(2)); // not counting receiver
- __ JumpToBuiltin(ExternalReference(Runtime::kSetProperty));
+ __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
// Extra capacity case: Check if there is extra capacity to
@@ -1067,12 +1095,14 @@
void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
+ // r1 : x
+ // r0 : y
+ // result : r0
+
switch (op_) {
case Token::ADD: {
Label slow, exit;
// fast path
- // Get x (y is on TOS, i.e., r0).
- __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
__ orr(r2, r1, Operand(r0)); // r2 = x | y;
__ add(r0, r1, Operand(r0), SetCC); // add y optimistically
// go slow-path in case of overflow
@@ -1084,6 +1114,7 @@
// slow path
__ bind(&slow);
__ sub(r0, r0, Operand(r1)); // revert optimistic add
+ __ push(r1);
__ push(r0);
__ mov(r0, Operand(1)); // set number of arguments
__ InvokeBuiltin("ADD", 1, JUMP_JS);
@@ -1095,7 +1126,6 @@
case Token::SUB: {
Label slow, exit;
// fast path
- __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // get x
__ orr(r2, r1, Operand(r0)); // r2 = x | y;
__ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically
// go slow-path in case of overflow
@@ -1107,6 +1137,7 @@
__ b(eq, &exit);
// slow path
__ bind(&slow);
+ __ push(r1);
__ push(r0);
__ mov(r0, Operand(1)); // set number of arguments
__ InvokeBuiltin("SUB", 1, JUMP_JS);
@@ -1117,7 +1148,6 @@
case Token::MUL: {
Label slow, exit;
- __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // get x
// tag check
__ orr(r2, r1, Operand(r0)); // r2 = x | y;
ASSERT(kSmiTag == 0); // adjust code below
@@ -1137,6 +1167,7 @@
__ b(ne, &exit);
// slow case
__ bind(&slow);
+ __ push(r1);
__ push(r0);
__ mov(r0, Operand(1)); // set number of arguments
__ InvokeBuiltin("MUL", 1, JUMP_JS);
@@ -1146,7 +1177,7 @@
}
default: UNREACHABLE();
}
- masm->StubReturn(2);
+ __ Ret();
}
@@ -1221,8 +1252,7 @@
__ b(hs, &within_limit);
// Do tail-call to runtime routine.
__ push(r0);
- __ mov(r0, Operand(0)); // not counting receiver (i.e. flushed TOS)
- __ JumpToBuiltin(ExternalReference(Runtime::kStackGuard));
+ __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
__ bind(&within_limit);
masm->StubReturn(1);
@@ -1385,7 +1415,7 @@
__ mov(r2, Operand(external_caught));
__ str(r0, MemOperand(r2));
- // Set pending exception and TOS to out of memory exception.
+ // Set pending exception and r0 to out of memory exception.
Failure* out_of_memory = Failure::OutOfMemoryException();
__ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
__ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
@@ -1414,17 +1444,19 @@
bool do_gc,
bool do_restore) {
// r0: result parameter for PerformGC, if any
- // r4: number of arguments (C callee-saved)
+ // r4: number of arguments including receiver (C callee-saved)
// r5: pointer to builtin function (C callee-saved)
if (do_gc) {
__ Call(FUNCTION_ADDR(Runtime::PerformGC), runtime_entry); // passing r0
}
- // call C built-in
- __ mov(r0, Operand(r4)); // a0 = argc
+ // Call C built-in.
+ // r0 = argc.
+ __ mov(r0, Operand(r4));
+ // r1 = argv.
__ add(r1, fp, Operand(r4, LSL, kPointerSizeLog2));
- __ add(r1, r1, Operand(ExitFrameConstants::kPPDisplacement)); // a1 = argv
+ __ add(r1, r1, Operand(ExitFrameConstants::kPPDisplacement - kPointerSize));
// 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,
@@ -1512,7 +1544,7 @@
void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
// Called from JavaScript; parameters are on stack as if calling JS function
- // r0: number of arguments
+ // r0: number of arguments including receiver
// r1: pointer to builtin function
// fp: frame pointer (restored after C call)
// sp: stack pointer (restored as callee's pp after C call)
@@ -1527,9 +1559,8 @@
// Enter C frame
// Compute parameter 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_len+1); // +1 for receiver
+ // ip = sp + kPointerSize*args_len;
__ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
- __ add(ip, ip, Operand(kPointerSize));
// all JS callee-saved are saved and traversed by GC; push in reverse order:
// JS callee-saved, caller_pp, caller_fp, sp_on_exit (ip==pp), caller_pc
@@ -1701,7 +1732,7 @@
__ str(r3, MemOperand(ip));
// Remove constructor mark.
- __ add(sp, sp, Operand(kPointerSize));
+ __ pop();
// Restore callee-saved registers, sp, and return.
#ifdef DEBUG
@@ -1759,8 +1790,7 @@
// by calling the runtime system.
__ bind(&slow);
__ push(r0);
- __ mov(r0, Operand(0)); // not counting receiver
- __ JumpToBuiltin(ExternalReference(Runtime::kGetArgumentsProperty));
+ __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
}
}
@@ -1787,14 +1817,10 @@
Literal* literal = key->AsLiteral();
Handle<String> name(String::cast(*literal->handle()));
- // Loading adds a value to the stack; push the TOS to prepare.
- if (is_load) __ push(r0);
-
- // Setup the name register.
- __ mov(r2, Operand(name));
-
// Call the appropriate IC code.
if (is_load) {
+ // Setup the name register.
+ __ mov(r2, Operand(name));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
if (var != NULL) {
@@ -1803,49 +1829,59 @@
} else {
__ Call(ic, code_target);
}
+
} else {
+ __ pop(r0); // value
+ // Setup the name register.
+ __ mov(r2, Operand(name));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, code_target);
}
- return;
- }
- // Access keyed property.
- ASSERT(type == Reference::KEYED);
-
- if (is_load) {
- __ push(r0); // empty tos
- // TODO(1224671): Implement inline caching for keyed loads as on ia32.
- GetPropertyStub stub;
- __ CallStub(&stub);
} else {
- SetPropertyStub stub;
- __ CallStub(&stub);
+ // Access keyed property.
+ ASSERT(type == Reference::KEYED);
+
+ if (is_load) {
+ // TODO(1224671): Implement inline caching for keyed loads as on ia32.
+ GetPropertyStub stub;
+ __ CallStub(&stub);
+
+ } else {
+ __ pop(r0); // value
+ SetPropertyStub stub;
+ __ CallStub(&stub);
+ }
}
+ __ push(r0);
}
void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
+ // sp[0] : y
+ // sp[1] : x
+ // result : r0
+
// Stub is entered with a call: 'return address' is in lr.
switch (op) {
case Token::ADD: // fall through.
case Token::SUB: // fall through.
case Token::MUL: {
+ __ pop(r0); // r0 : y
+ __ pop(r1); // r1 : x
GenericBinaryOpStub stub(op);
__ CallStub(&stub);
break;
}
case Token::DIV: {
- __ push(r0);
- __ mov(r0, Operand(1)); // set number of arguments
+ __ mov(r0, Operand(1));
__ InvokeBuiltin("DIV", 1, CALL_JS);
break;
}
case Token::MOD: {
- __ push(r0);
- __ mov(r0, Operand(1)); // set number of arguments
+ __ mov(r0, Operand(1));
__ InvokeBuiltin("MOD", 1, CALL_JS);
break;
}
@@ -1854,6 +1890,7 @@
case Token::BIT_AND:
case Token::BIT_XOR: {
Label slow, exit;
+ __ pop(r0); // get y
__ pop(r1); // get x
// tag check
__ orr(r2, r1, Operand(r0)); // r2 = x | y;
@@ -1885,7 +1922,7 @@
case Token::SHR:
case Token::SAR: {
Label slow, exit;
- __ mov(r1, Operand(r0)); // get y
+ __ pop(r1); // get y
__ pop(r0); // get x
// tag check
__ orr(r2, r1, Operand(r0)); // r2 = x | y;
@@ -1928,15 +1965,15 @@
default: UNREACHABLE();
}
- // tag result and store it in TOS (r0)
+ // tag result and store it in r0
ASSERT(kSmiTag == 0); // adjust code below
__ mov(r0, Operand(r3, LSL, kSmiTagSize));
__ b(&exit);
// slow case
__ bind(&slow);
__ push(r0); // restore stack
- __ mov(r0, Operand(r1));
- __ Push(Operand(1)); // 1 argument (not counting receiver).
+ __ push(r1);
+ __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
switch (op) {
case Token::SAR: __ InvokeBuiltin("SAR", 1, CALL_JS); break;
case Token::SHR: __ InvokeBuiltin("SHR", 1, CALL_JS); break;
@@ -1948,8 +1985,9 @@
}
case Token::COMMA:
+ __ pop(r0);
// simply discard left value
- __ add(sp, sp, Operand(kPointerSize));
+ __ pop();
break;
default:
@@ -1960,8 +1998,6 @@
}
-
-
void ArmCodeGenerator::SmiOperation(Token::Value op,
Handle<Object> value,
bool reversed) {
@@ -1972,9 +2008,12 @@
// code size is increased by ~1% (measured on a combination of
// different benchmarks).
+ // sp[0] : operand
+
ASSERT(value->IsSmi());
Label exit;
+ __ pop(r0);
switch (op) {
case Token::ADD: {
@@ -2015,10 +2054,13 @@
default:
if (!reversed) {
- __ Push(Operand(value));
+ __ push(r0);
+ __ mov(r0, Operand(value));
+ __ push(r0);
} else {
__ mov(ip, Operand(value));
__ push(ip);
+ __ push(r0);
}
GenericBinaryOperation(op);
break;
@@ -2029,6 +2071,10 @@
void ArmCodeGenerator::Comparison(Condition cc, bool strict) {
+ // sp[0] : y
+ // sp[1] : x
+ // result : cc register
+
// Strict only makes sense for equality comparisons.
ASSERT(!strict || cc == eq);
@@ -2036,9 +2082,10 @@
// Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
if (cc == gt || cc == le) {
cc = ReverseCondition(cc);
- __ mov(r1, Operand(r0));
+ __ pop(r1);
__ pop(r0);
} else {
+ __ pop(r0);
__ pop(r1);
}
__ orr(r2, r0, Operand(r1));
@@ -2063,13 +2110,15 @@
ASSERT(cc == gt || cc == ge); // remaining cases
ncr = LESS;
}
- __ Push(Operand(Smi::FromInt(ncr)));
+ __ push(r0);
+ __ mov(r0, Operand(Smi::FromInt(ncr)));
argc = 2;
}
// Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
// tagged as a small integer.
- __ Push(Operand(argc));
+ __ push(r0);
+ __ mov(r0, Operand(argc));
__ InvokeBuiltin(native, argc, CALL_JS);
__ cmp(r0, Operand(0));
__ b(&exit);
@@ -2079,7 +2128,6 @@
__ cmp(r1, Operand(r0));
__ bind(&exit);
- __ pop(r0); // be careful not to destroy the cc register
cc_reg_ = cc;
}
@@ -2106,10 +2154,6 @@
void CallFunctionStub::Generate(MacroAssembler* masm) {
Label slow;
-
- // Flush the TOS cache
- masm->push(r0);
-
// Get the function to call from the stack.
// function, receiver [, arguments]
masm->ldr(r1, MemOperand(sp, (argc_ + 1) * kPointerSize));
@@ -2136,12 +2180,13 @@
}
-// Call the function just below TOS on the stack with the given
-// arguments. The receiver is the TOS.
+// Call the function on the stack with the given arguments.
void ArmCodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
int position) {
// Push the arguments ("left-to-right") on the stack.
- for (int i = 0; i < args->length(); i++) Load(args->at(i));
+ for (int i = 0; i < args->length(); i++) {
+ Load(args->at(i));
+ }
// Record the position for debugging purposes.
__ RecordPosition(position);
@@ -2152,7 +2197,7 @@
// Restore context and pop function from the stack.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- __ add(sp, sp, Operand(kPointerSize)); // discard
+ __ pop(); // discard the TOS
}
@@ -2183,13 +2228,13 @@
void ArmCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
- __ Push(Operand(pairs));
- __ Push(Operand(cp));
- __ Push(Operand(Smi::FromInt(is_eval() ? 1 : 0)));
+ __ mov(r0, Operand(pairs));
+ __ push(r0);
+ __ push(cp);
+ __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
+ __ push(r0);
__ CallRuntime(Runtime::kDeclareGlobals, 3);
-
- // Get rid of return value.
- __ pop(r0);
+ // The result is discarded.
}
@@ -2207,27 +2252,30 @@
// during variable resolution and must have mode DYNAMIC.
ASSERT(var->mode() == Variable::DYNAMIC);
// For now, just do a runtime call.
- __ Push(Operand(cp));
- __ Push(Operand(var->name()));
+ __ push(cp);
+ __ mov(r0, Operand(var->name()));
+ __ push(r0);
// Declaration nodes are always declared in only two modes.
ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
- __ Push(Operand(Smi::FromInt(attr)));
+ __ mov(r0, Operand(Smi::FromInt(attr)));
+ __ push(r0);
// Push initial value, if any.
// Note: For variables we must not push an initial value (such as
// 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value.
if (node->mode() == Variable::CONST) {
- __ Push(Operand(Factory::the_hole_value()));
+ __ mov(r0, Operand(Factory::the_hole_value()));
+ __ push(r0);
} else if (node->fun() != NULL) {
Load(node->fun());
} else {
- __ Push(Operand(0)); // no initial value!
+ __ mov(r0, Operand(0)); // no initial value!
+ __ push(r0);
}
__ CallRuntime(Runtime::kDeclareContextSlot, 5);
- // DeclareContextSlot pops the assigned value by accepting an
- // extra argument and returning the TOS; no need to explicitly pop
- // here.
+ __ push(r0);
+
return;
}
@@ -2247,7 +2295,7 @@
Load(val);
SetValue(&target);
// Get rid of the assigned value (declarations are statements).
- __ pop(r0); // Pop(no_reg);
+ __ pop();
}
}
@@ -2258,7 +2306,7 @@
Expression* expression = node->expression();
expression->MarkAsStatement();
Load(expression);
- __ pop(r0); // __ Pop(no_reg)
+ __ pop();
}
@@ -2279,6 +2327,7 @@
Label exit;
if (has_then_stm && has_else_stm) {
+ Comment cmnt(masm_, "[ IfThenElse");
Label then;
Label else_;
// if (cond)
@@ -2293,6 +2342,7 @@
Visit(node->else_statement());
} else if (has_then_stm) {
+ Comment cmnt(masm_, "[ IfThen");
ASSERT(!has_else_stm);
Label then;
// if (cond)
@@ -2303,6 +2353,7 @@
Visit(node->then_statement());
} else if (has_else_stm) {
+ Comment cmnt(masm_, "[ IfElse");
ASSERT(!has_then_stm);
Label else_;
// if (!cond)
@@ -2313,6 +2364,7 @@
Visit(node->else_statement());
} else {
+ Comment cmnt(masm_, "[ If");
ASSERT(!has_then_stm && !has_else_stm);
// if (cond)
LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false);
@@ -2331,8 +2383,7 @@
void ArmCodeGenerator::CleanStack(int num_bytes) {
ASSERT(num_bytes >= 0);
if (num_bytes > 0) {
- __ add(sp, sp, Operand(num_bytes - kPointerSize));
- __ pop(r0);
+ __ add(sp, sp, Operand(num_bytes));
}
}
@@ -2357,6 +2408,9 @@
Comment cmnt(masm_, "[ ReturnStatement");
if (FLAG_debug_info) RecordStatementPosition(node);
Load(node->expression());
+ // Move the function result into r0.
+ __ pop(r0);
+
__ b(&function_return_);
}
@@ -2373,7 +2427,6 @@
__ stop("PushContext: r0 is expected to be the same as cp");
__ bind(&verified_true);
}
- __ pop(r0); // restore TOS
// Update context local.
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
@@ -2421,11 +2474,13 @@
} else {
__ bind(&next);
next.Unuse();
+ __ ldr(r0, MemOperand(sp, 0));
__ push(r0); // duplicate TOS
Load(clause->label());
Comparison(eq, true);
Branch(false, &next);
- __ pop(r0); // __ Pop(no_reg)
+ // Entering the case statement -> remove the switch value from the stack
+ __ pop(r0);
}
// Generate code for the body.
@@ -2436,6 +2491,8 @@
}
__ bind(&next);
+ // Reached the end of the case statements -> remove the switch value
+ // from the stack.
__ pop(r0); // __ Pop(no_reg)
if (default_case.is_bound()) __ b(&default_case);
@@ -2532,6 +2589,7 @@
// Get the object to enumerate over (converted to JSObject).
Load(node->enumerable());
+ __ pop(r0);
// Both SpiderMonkey and kjs ignore null and undefined in contrast
// to the specification. 12.6.4 mandates a call to ToObject.
@@ -2556,7 +2614,8 @@
__ b(hs, &jsobject);
__ bind(&primitive);
- __ Push(Operand(0));
+ __ push(r0);
+ __ mov(r0, Operand(0));
__ InvokeBuiltin("TO_OBJECT", 0, CALL_JS);
@@ -2564,6 +2623,7 @@
// Get the set of properties (as a FixedArray or Map).
__ push(r0); // duplicate the object being enumerated
+ __ push(r0);
__ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
// If we got a Map, we can do a fast modification check.
@@ -2580,10 +2640,13 @@
__ ldr(r2,
FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
- __ Push(Operand(r2));
- __ Push(FieldMemOperand(r2, FixedArray::kLengthOffset));
+ __ push(r0); // map
+ __ push(r2); // enum cache bridge cache
+ __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
- __ Push(Operand(Smi::FromInt(0)));
+ __ push(r0);
+ __ mov(r0, Operand(Smi::FromInt(0)));
+ __ push(r0);
__ b(&entry);
@@ -2591,11 +2654,15 @@
__ mov(r1, Operand(Smi::FromInt(0)));
__ push(r1); // insert 0 in place of Map
+ __ push(r0);
// Push the length of the array and the initial index onto the stack.
- __ Push(FieldMemOperand(r0, FixedArray::kLengthOffset));
+ __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
- __ Push(Operand(Smi::FromInt(0)));
+ __ push(r0);
+ __ mov(r0, Operand(Smi::FromInt(0))); // init index
+ __ push(r0);
+
__ b(&entry);
// Body.
@@ -2605,36 +2672,46 @@
// Next.
__ bind(node->continue_target());
__ bind(&next);
+ __ pop(r0);
__ add(r0, r0, Operand(Smi::FromInt(1)));
+ __ push(r0);
// Condition.
__ bind(&entry);
- __ ldr(ip, MemOperand(sp, 0));
- __ cmp(r0, Operand(ip));
+ // sp[0] : index
+ // sp[1] : array/enum cache length
+ // sp[2] : array or enum cache
+ // sp[3] : 0 or map
+ // sp[4] : enumerable
+ __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); // load the current count
+ __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // load the length
+ __ cmp(r0, Operand(r1)); // compare to the array length
__ b(hs, &cleanup);
+ __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
+
// Get the i'th entry of the array.
- __ ldr(r2, MemOperand(sp, kPointerSize));
+ __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
__ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
// Get Map or 0.
- __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
+ __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
// Check if this (still) matches the map of the enumerable.
// If not, we have to filter the key.
- __ ldr(r1, MemOperand(sp, 3 * kPointerSize));
+ __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
__ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
__ cmp(r1, Operand(r2));
__ b(eq, &end_del_check);
// Convert the entry to a string (or null if it isn't a property anymore).
- __ Push(MemOperand(sp, 4 * kPointerSize)); // push enumerable
- __ Push(Operand(r3)); // push entry
- __ Push(Operand(1));
+ __ ldr(r0, MemOperand(sp, 4 * kPointerSize)); // push enumerable
+ __ push(r0);
+ __ push(r3); // push entry
+ __ mov(r0, Operand(1));
__ InvokeBuiltin("FILTER_KEY", 1, CALL_JS);
__ mov(r3, Operand(r0));
- __ pop(r0);
// If the property has been removed while iterating, we just skip it.
__ cmp(r3, Operand(Factory::null_value()));
@@ -2644,26 +2721,31 @@
__ bind(&end_del_check);
// Store the entry in the 'each' expression and take another spin in the loop.
- __ Push(Operand(r3));
+ // r3: i'th entry of the enum cache (or string there of)
+ __ push(r3); // push entry
{ Reference each(this, node->each());
if (!each.is_illegal()) {
- if (each.size() > 0) __ Push(MemOperand(sp, kPointerSize * each.size()));
+ if (each.size() > 0) {
+ __ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
+ __ push(r0);
+ }
SetValue(&each);
- if (each.size() > 0) __ pop(r0);
+ if (each.size() > 0) {
+ __ pop(r0); // discard the value
+ }
}
}
- __ pop(r0);
+ __ pop(); // pop the i'th entry pushed above
CheckStack(); // TODO(1222600): ignore if body contains calls.
__ jmp(&loop);
// Cleanup.
__ bind(&cleanup);
__ bind(node->break_target());
- __ add(sp, sp, Operand(4 * kPointerSize));
+ __ add(sp, sp, Operand(5 * kPointerSize));
// Exit.
__ bind(&exit);
- __ pop(r0);
break_stack_height_ -= kForInStackSize;
}
@@ -2674,24 +2756,22 @@
Label try_block, exit;
- __ push(r0);
__ bl(&try_block);
-
// --- Catch block ---
// Store the caught exception in the catch variable.
+ __ push(r0);
{ Reference ref(this, node->catch_var());
// Load the exception to the top of the stack.
- __ Push(MemOperand(sp, ref.size() * kPointerSize));
+ __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
+ __ push(r0);
SetValue(&ref);
+ __ pop(r0);
}
// Remove the exception from the stack.
- __ add(sp, sp, Operand(kPointerSize));
-
- // Restore TOS register caching.
- __ pop(r0);
+ __ pop();
VisitStatements(node->catch_block()->statements());
__ b(&exit);
@@ -2714,6 +2794,7 @@
// Generate code for the statements in the try block.
VisitStatements(node->try_block()->statements());
+ __ pop(r0); // Discard the result.
// Stop the introduced shadowing and count the number of required unlinks.
int nof_unlinks = 0;
@@ -2732,21 +2813,14 @@
ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
__ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
// Code slot popped.
- __ pop(r0); // restore TOS
if (nof_unlinks > 0) __ b(&exit);
// Generate unlink code for all used shadow labels.
for (int i = 0; i <= nof_escapes; i++) {
if (shadows[i]->is_linked()) {
- // Unlink from try chain; be careful not to destroy the TOS.
+ // Unlink from try chain;
__ bind(shadows[i]);
- bool is_return = (shadows[i]->shadowed() == &function_return_);
- if (!is_return) {
- // Break/continue case. TOS is the code slot of the handler.
- __ push(r0); // flush TOS
- }
-
// Reload sp from the top handler, because some statements that we
// break from (eg, for...in) may have left stuff on the stack.
__ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
@@ -2758,10 +2832,6 @@
__ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
// Code slot popped.
- if (!is_return) {
- __ pop(r0); // restore TOS
- }
-
__ b(shadows[i]->shadowed());
}
}
@@ -2780,9 +2850,9 @@
Label exit, unlink, try_block, finally_block;
- __ push(r0);
__ bl(&try_block);
+ __ push(r0); // save exception object on the stack
// In case of thrown exceptions, this is where we continue.
__ mov(r2, Operand(Smi::FromInt(THROWING)));
__ b(&finally_block);
@@ -2815,7 +2885,8 @@
}
// Set the state on the stack to FALLING.
- __ Push(Operand(Factory::undefined_value())); // fake TOS
+ __ mov(r0, Operand(Factory::undefined_value())); // fake TOS
+ __ push(r0);
__ mov(r2, Operand(Smi::FromInt(FALLING)));
if (nof_unlinks > 0) __ b(&unlink);
@@ -2823,18 +2894,22 @@
for (int i = 0; i <= nof_escapes; i++) {
if (shadows[i]->is_linked()) {
__ bind(shadows[i]);
- if (shadows[i]->shadowed() != &function_return_) {
+ if (shadows[i]->shadowed() == &function_return_) {
+ __ push(r0); // Materialize the return value on the stack
+ } else {
// Fake TOS for break and continue (not return).
- __ Push(Operand(Factory::undefined_value()));
+ __ mov(r0, Operand(Factory::undefined_value()));
+ __ push(r0);
}
__ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
__ b(&unlink);
}
}
- // Unlink from try chain; be careful not to destroy the TOS.
+ // Unlink from try chain;
__ bind(&unlink);
+ __ pop(r0); // Store TOS in r0 across stack manipulation
// Reload sp from the top handler, because some statements that we
// break from (eg, for...in) may have left stuff on the stack.
__ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
@@ -2846,7 +2921,7 @@
ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
__ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
// Code slot popped.
-
+ __ push(r0);
// --- Finally block ---
__ bind(&finally_block);
@@ -2854,25 +2929,25 @@
// Push the state on the stack. If necessary move the state to a
// local variable to avoid having extra values on the stack while
// evaluating the finally block.
- __ Push(Operand(r2));
+ __ push(r2);
if (node->finally_var() != NULL) {
Reference target(this, node->finally_var());
SetValue(&target);
ASSERT(target.size() == 0); // no extra stuff on the stack
- __ pop(r0);
+ __ pop(); // remove the extra avalue that was pushed above
}
// Generate code for the statements in the finally block.
VisitStatements(node->finally_block()->statements());
- // Get the state from the stack - or the local variable - and
- // restore the TOS register.
+ // Get the state from the stack - or the local variable.
if (node->finally_var() != NULL) {
Reference target(this, node->finally_var());
GetValue(&target);
}
- __ Pop(r2);
+ __ pop(r2);
+ __ pop(r0); // Restore value or faked TOS.
// Generate code that jumps to the right destination for all used
// shadow labels.
for (int i = 0; i <= nof_escapes; i++) {
@@ -2881,7 +2956,6 @@
if (shadows[i]->shadowed() != &function_return_) {
Label next;
__ b(ne, &next);
- __ pop(r0); // pop faked TOS
__ b(shadows[i]->shadowed());
__ bind(&next);
} else {
@@ -2895,11 +2969,11 @@
__ b(ne, &exit);
// Rethrow exception.
+ __ push(r0);
__ CallRuntime(Runtime::kReThrow, 1);
// Done.
__ bind(&exit);
- __ pop(r0); // restore TOS caching.
}
@@ -2907,6 +2981,7 @@
Comment cmnt(masm_, "[ DebuggerStatament");
if (FLAG_debug_info) RecordStatementPosition(node);
__ CallRuntime(Runtime::kDebugBreak, 1);
+ __ push(r0);
}
@@ -2914,11 +2989,13 @@
ASSERT(boilerplate->IsBoilerplate());
// Push the boilerplate on the stack.
- __ Push(Operand(boilerplate));
+ __ mov(r0, Operand(boilerplate));
+ __ push(r0);
// Create a new closure.
- __ Push(Operand(cp));
+ __ push(cp);
__ CallRuntime(Runtime::kNewClosure, 2);
+ __ push(r0);
}
@@ -2961,8 +3038,9 @@
ASSERT(node->var()->mode() == Variable::DYNAMIC);
// For now, just do a runtime call.
- __ Push(Operand(cp));
- __ Push(Operand(node->var()->name()));
+ __ push(cp);
+ __ mov(r0, Operand(node->var()->name()));
+ __ push(r0);
switch (access()) {
case CodeGenState::UNDEFINED:
@@ -2971,18 +3049,19 @@
case CodeGenState::LOAD:
__ CallRuntime(Runtime::kLoadContextSlot, 2);
- // result (TOS) is the value that was loaded
+ __ push(r0);
break;
case CodeGenState::LOAD_TYPEOF_EXPR:
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
- // result (TOS) is the value that was loaded
+ __ push(r0);
break;
case CodeGenState::STORE:
// Storing a variable must keep the (new) value on the stack. This
// is necessary for compiling assignment expressions.
__ CallRuntime(Runtime::kStoreContextSlot, 3);
+ __ push(r0);
// result (TOS) is the value that was stored
break;
@@ -3004,6 +3083,7 @@
// need the split into 2 operations: declaration of the
// context slot followed by initialization.
__ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+ __ push(r0);
break;
}
@@ -3020,14 +3100,17 @@
case CodeGenState::LOAD: // fall through
case CodeGenState::LOAD_TYPEOF_EXPR:
// Special handling for locals allocated in registers.
- __ Push(SlotOperand(node, r2));
+ __ ldr(r0, SlotOperand(node, r2));
+ __ push(r0);
if (node->var()->mode() == Variable::CONST) {
// Const slots may contain 'the hole' value (the constant hasn't
// been initialized yet) which needs to be converted into the
// 'undefined' value.
Comment cmnt(masm_, "[ Unhole const");
+ __ pop(r0);
__ cmp(r0, Operand(Factory::the_hole_value()));
__ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
+ __ push(r0);
}
break;
@@ -3043,6 +3126,7 @@
__ b(ne, &L);
// We must execute the store.
// r2 may be loaded with context; used below in RecordWrite.
+ __ ldr(r0, MemOperand(sp, 0));
__ str(r0, SlotOperand(node, r2));
if (node->type() == Slot::CONTEXT) {
// Skip write barrier if the written value is a smi.
@@ -3070,6 +3154,7 @@
// initialize consts to 'the hole' value and by doing so, end
// up calling this code.
// r2 may be loaded with context; used below in RecordWrite.
+ __ pop(r0);
__ str(r0, SlotOperand(node, r2));
if (node->type() == Slot::CONTEXT) {
// Skip write barrier if the written value is a smi.
@@ -3082,6 +3167,7 @@
__ RecordWrite(r2, r3, r1);
__ bind(&exit);
}
+ __ push(r0);
break;
}
}
@@ -3117,7 +3203,8 @@
void ArmCodeGenerator::VisitLiteral(Literal* node) {
Comment cmnt(masm_, "[ Literal");
- __ Push(Operand(node->handle()));
+ __ mov(r0, Operand(node->handle()));
+ __ push(r0);
}
@@ -3143,16 +3230,19 @@
// If the entry is undefined we call the runtime system to computed
// the literal.
- __ Push(Operand(r1)); // literal array (0)
- __ Push(Operand(Smi::FromInt(node->literal_index()))); // literal index (1)
- __ Push(Operand(node->pattern())); // RegExp pattern (2)
- __ Push(Operand(node->flags())); // RegExp flags (3)
+ __ push(r1); // literal array (0)
+ __ mov(r0, Operand(Smi::FromInt(node->literal_index())));
+ __ push(r0); // literal index (1)
+ __ mov(r0, Operand(node->pattern())); // RegExp pattern (2)
+ __ push(r0);
+ __ mov(r0, Operand(node->flags())); // RegExp flags (3)
+ __ push(r0);
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
- __ Pop(r2);
- __ bind(&done);
+ __ mov(r2, Operand(r0));
+ __ bind(&done);
// Push the literal.
- __ Push(Operand(r2));
+ __ push(r2);
}
@@ -3177,13 +3267,15 @@
// the literal.
// Literal array (0).
- __ Push(Operand(r1));
+ __ push(r1);
// Literal index (1).
- __ Push(Operand(Smi::FromInt(node_->literal_index())));
+ __ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
+ __ push(r0);
// Constant properties (2).
- __ Push(Operand(node_->constant_properties()));
+ __ mov(r0, Operand(node_->constant_properties()));
+ __ push(r0);
__ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
- __ Pop(r2);
+ __ mov(r2, Operand(r0));
}
@@ -3212,9 +3304,12 @@
__ bind(deferred->exit());
// Push the object literal boilerplate.
- __ Push(Operand(r2));
+ __ push(r2);
+
// Clone the boilerplate object.
__ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
+ __ push(r0); // save the result
+ // r0: cloned object literal
for (int i = 0; i < node->properties()->length(); i++) {
ObjectLiteral::Property* property = node->properties()->at(i);
@@ -3224,31 +3319,32 @@
case ObjectLiteral::Property::CONSTANT: break;
case ObjectLiteral::Property::COMPUTED: // fall through
case ObjectLiteral::Property::PROTOTYPE: {
- // Save a copy of the resulting object on the stack.
- __ push(r0);
+ __ push(r0); // dup the result
Load(key);
Load(value);
__ CallRuntime(Runtime::kSetProperty, 3);
- // Restore the result object from the stack.
- __ pop(r0);
+ // restore r0
+ __ ldr(r0, MemOperand(sp, 0));
break;
}
case ObjectLiteral::Property::SETTER: {
__ push(r0);
Load(key);
- __ Push(Operand(Smi::FromInt(1)));
+ __ mov(r0, Operand(Smi::FromInt(1)));
+ __ push(r0);
Load(value);
__ CallRuntime(Runtime::kDefineAccessor, 4);
- __ pop(r0);
+ __ ldr(r0, MemOperand(sp, 0));
break;
}
case ObjectLiteral::Property::GETTER: {
__ push(r0);
Load(key);
- __ Push(Operand(Smi::FromInt(0)));
+ __ mov(r0, Operand(Smi::FromInt(0)));
+ __ push(r0);
Load(value);
__ CallRuntime(Runtime::kDefineAccessor, 4);
- __ pop(r0);
+ __ ldr(r0, MemOperand(sp, 0));
break;
}
}
@@ -3268,6 +3364,7 @@
if (value->AsLiteral() == NULL) {
// The property must be set by generated code.
Load(value);
+ __ pop(r0);
// Fetch the object literal
__ ldr(r1, MemOperand(sp, 0));
@@ -3281,8 +3378,6 @@
// Update the write barrier for the array address.
__ mov(r3, Operand(offset));
__ RecordWrite(r1, r3, r2);
-
- __ pop(r0);
}
}
}
@@ -3290,8 +3385,8 @@
void ArmCodeGenerator::VisitAssignment(Assignment* node) {
Comment cmnt(masm_, "[ Assignment");
-
if (FLAG_debug_info) RecordStatementPosition(node);
+
Reference target(this, node->target());
if (target.is_illegal()) return;
@@ -3305,9 +3400,12 @@
Literal* literal = node->value()->AsLiteral();
if (literal != NULL && literal->handle()->IsSmi()) {
SmiOperation(node->binary_op(), literal->handle(), false);
+ __ push(r0);
+
} else {
Load(node->value());
GenericBinaryOperation(node->binary_op());
+ __ push(r0);
}
}
@@ -3316,6 +3414,7 @@
(var->mode() == Variable::CONST) &&
node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
// Assignment ignored - leave the value on the stack.
+
} else {
__ RecordPosition(node->position());
if (node->op() == Token::INIT_CONST) {
@@ -3336,6 +3435,7 @@
Load(node->exception());
__ RecordPosition(node->position());
__ CallRuntime(Runtime::kThrow, 1);
+ __ push(r0);
}
@@ -3344,6 +3444,7 @@
if (is_referenced()) {
__ RecordPosition(node->position());
AccessReferenceProperty(node->key(), access());
+
} else {
// All stores are through references.
ASSERT(access() != CodeGenState::STORE);
@@ -3382,22 +3483,21 @@
// ----------------------------------
// Push the name of the function and the receiver onto the stack.
- __ Push(Operand(var->name()));
+ __ mov(r0, Operand(var->name()));
+ __ push(r0);
LoadGlobal();
// Load the arguments.
for (int i = 0; i < args->length(); i++) Load(args->at(i));
- __ Push(Operand(args->length()));
// Setup the receiver register and call the IC initialization code.
Handle<Code> stub = ComputeCallInitialize(args->length());
- __ ldr(r1, GlobalObject());
__ RecordPosition(node->position());
__ Call(stub, code_target_context);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-
// Remove the function from the stack.
- __ add(sp, sp, Operand(kPointerSize));
+ __ pop();
+ __ push(r0);
} else if (var != NULL && var->slot() != NULL &&
var->slot()->type() == Slot::LOOKUP) {
@@ -3406,17 +3506,19 @@
// ----------------------------------
// Load the function
- __ Push(Operand(cp));
- __ Push(Operand(var->name()));
+ __ push(cp);
+ __ mov(r0, Operand(var->name()));
+ __ push(r0);
__ CallRuntime(Runtime::kLoadContextSlot, 2);
// r0: slot value; r1: receiver
// Load the receiver.
- __ push(r0);
- __ mov(r0, Operand(r1));
+ __ push(r0); // function
+ __ push(r1); // receiver
// Call the function.
CallWithArguments(args, node->position());
+ __ push(r0);
} else if (property != NULL) {
// Check if the key is a literal string.
@@ -3428,22 +3530,23 @@
// ------------------------------------------------------------------
// Push the name of the function and the receiver onto the stack.
- __ Push(Operand(literal->handle()));
+ __ mov(r0, Operand(literal->handle()));
+ __ push(r0);
Load(property->obj());
// Load the arguments.
for (int i = 0; i < args->length(); i++) Load(args->at(i));
- __ Push(Operand(args->length()));
// Set the receiver register and call the IC initialization code.
Handle<Code> stub = ComputeCallInitialize(args->length());
- __ ldr(r1, MemOperand(sp, args->length() * kPointerSize));
__ RecordPosition(node->position());
__ Call(stub, code_target);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Remove the function from the stack.
- __ add(sp, sp, Operand(kPointerSize));
+ __ pop();
+
+ __ push(r0); // push after get rid of function from the stack
} else {
// -------------------------------------------
@@ -3452,13 +3555,14 @@
// Load the function to call from the property through a reference.
Reference ref(this, property);
- GetValue(&ref);
+ GetValue(&ref); // receiver
// Pass receiver to called function.
- __ Push(MemOperand(sp, ref.size() * kPointerSize));
-
+ __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
+ __ push(r0);
// Call the function.
CallWithArguments(args, node->position());
+ __ push(r0);
}
} else {
@@ -3468,12 +3572,11 @@
// Load the function.
Load(function);
-
// Pass the global object as the receiver.
LoadGlobal();
-
// Call the function.
CallWithArguments(args, node->position());
+ __ push(r0);
}
}
@@ -3496,34 +3599,39 @@
ZoneList<Expression*>* args = node->arguments();
for (int i = 0; i < args->length(); i++) Load(args->at(i));
- // Push the number of arguments.
- __ Push(Operand(args->length()));
+ // r0: the number of arguments.
+ __ mov(r0, Operand(args->length()));
// Call the construct call builtin that handles allocation and
// constructor invocation.
__ RecordPosition(position);
__ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
js_construct_call);
- __ add(sp, sp, Operand(kPointerSize)); // discard
+
+ // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
+ __ str(r0, MemOperand(sp, 0 * kPointerSize));
}
void ArmCodeGenerator::GenerateSetThisFunction(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
+ __ ldr(r0, MemOperand(sp, 0));
__ str(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
}
void ArmCodeGenerator::GenerateGetThisFunction(ZoneList<Expression*>* args) {
ASSERT(args->length() == 0);
- __ Push(MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
+ __ ldr(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
+ __ push(r0);
}
void ArmCodeGenerator::GenerateSetThis(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
+ __ ldr(r0, MemOperand(sp, 0));
__ str(r0, MemOperand(pp, JavaScriptFrameConstants::kReceiverOffset));
}
@@ -3531,17 +3639,19 @@
void ArmCodeGenerator::GenerateSetArgumentsLength(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
+ __ pop(r0);
__ mov(r0, Operand(r0, LSR, kSmiTagSize));
__ str(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
- __ mov(r0, Operand(Smi::FromInt(0)));
+ __ mov(r0, Operand(Smi::FromInt(0))); // return a meaningful value
+ __ push(r0);
}
void ArmCodeGenerator::GenerateGetArgumentsLength(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
- __ push(r0);
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
+ __ push(r0);
}
@@ -3549,19 +3659,20 @@
ASSERT(args->length() == 1);
Label leave;
Load(args->at(0));
- // r0 contains object.
- // if (object->IsSmi()) return TOS.
+ __ pop(r0); // r0 contains object.
+ // if (object->IsSmi()) return the object.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &leave);
// It is a heap object - get map.
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
- // if (!object->IsJSValue()) return TOS.
+ // if (!object->IsJSValue()) return the object.
__ cmp(r1, Operand(JS_VALUE_TYPE));
__ b(ne, &leave);
// Load the value.
__ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
__ bind(&leave);
+ __ push(r0);
}
@@ -3570,9 +3681,8 @@
Label leave;
Load(args->at(0)); // Load the object.
Load(args->at(1)); // Load the value.
- __ pop(r1);
- // r0 contains value.
- // r1 contains object.
+ __ pop(r0); // r0 contains value
+ __ pop(r1); // r1 contains object
// if (object->IsSmi()) return object.
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &leave);
@@ -3589,6 +3699,7 @@
__ RecordWrite(r1, r2, r3);
// Leave.
__ bind(&leave);
+ __ push(r0);
}
@@ -3597,6 +3708,7 @@
// r0 = number of arguments (smi)
ASSERT(args->length() == 1);
Load(args->at(0));
+ __ pop(r0);
__ mov(r0, Operand(r0, LSR, kSmiTagSize));
// r1 = new function (previously written to stack)
@@ -3615,34 +3727,35 @@
void ArmCodeGenerator::GenerateSetArgument(ZoneList<Expression*>* args) {
ASSERT(args->length() == 3);
- // r1 = args[i]
+ // r0 = args[i]; r1 = i
Comment cmnt(masm_, "[ GenerateSetArgument");
- Load(args->at(1));
- __ mov(r1, Operand(r0));
- // r0 = i
- Load(args->at(0));
+ Load(args->at(1)); // args[i] (value)
+ Load(args->at(0)); // i
+ __ pop(r1); // i
+ __ pop(r0); // value
#if defined(DEBUG)
{ Label L;
- __ tst(r0, Operand(kSmiTagMask));
+ __ tst(r1, Operand(kSmiTagMask));
__ b(eq, &L);
__ stop("SMI expected");
__ bind(&L);
}
#endif // defined(DEBUG)
__ add(r2, pp, Operand(JavaScriptFrameConstants::kParam0Offset));
- __ str(r1,
- MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize, NegOffset));
- __ pop(r0);
+ __ str(r0,
+ MemOperand(r2, r1, LSL, kPointerSizeLog2 - kSmiTagSize, NegOffset));
+ __ push(r0);
}
void ArmCodeGenerator::GenerateSquashFrame(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
- // Load r1 with old number of arguments, r0 with new number, r1 > r0.
- Load(args->at(0));
- __ mov(r1, Operand(r0, LSR, kSmiTagSize));
- Load(args->at(1));
+ Load(args->at(0)); // old number of arguments
+ Load(args->at(1)); // new number of arguments, r1 > r0
+ __ pop(r0);
__ mov(r0, Operand(r0, LSR, kSmiTagSize));
+ __ pop(r1);
+ __ mov(r1, Operand(r1, LSR, kSmiTagSize));
// r1 = number of words to move stack.
__ sub(r1, r1, Operand(r0));
// r2 is source.
@@ -3663,17 +3776,20 @@
// Move down stack pointer esp.
__ mov(sp, Operand(r1));
- // Balance stack and put something GC-able in r0.
- __ pop(r0);
+ // Put something GC-able in r0.
+ __ mov(r0, Operand(Smi::FromInt(0)));
+ __ push(r0);
}
void ArmCodeGenerator::GenerateExpandFrame(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
- // Load r1 with new number of arguments, r0 with old number (as Smi), r1 > r0.
Load(args->at(1));
- __ mov(r1, Operand(r0, LSR, kSmiTagSize));
Load(args->at(0));
+ __ pop(r0); // new number of arguments
+ __ pop(r1); // old number of arguments, r1 > r0
+ __ mov(r1, Operand(r1, LSR, kSmiTagSize));
+
// r1 = number of words to move stack.
__ sub(r1, r1, Operand(r0, LSR, kSmiTagSize));
Label end_of_expand_frame;
@@ -3684,7 +3800,6 @@
__ ldr(ip, MemOperand(ip));
__ cmp(r2, Operand(ip));
__ b(gt, ¬_too_big);
- __ pop(r0);
__ mov(r0, Operand(Factory::false_value()));
__ b(&end_of_expand_frame);
__ bind(¬_too_big);
@@ -3710,18 +3825,18 @@
__ cmp(r3, Operand(r0));
__ b(ne, &move);
- // Balance stack and put success value in top of stack
- __ pop(r0);
+ // Put success value in top of stack
__ mov(r0, Operand(Factory::true_value()));
__ bind(&end_of_expand_frame);
+ __ push(r0);
}
void ArmCodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
- __ tst(r0, Operand(kSmiTagMask));
__ pop(r0);
+ __ tst(r0, Operand(kSmiTagMask));
cc_reg_ = eq;
}
@@ -3731,8 +3846,8 @@
// It is not yet implemented on ARM, so it always goes to the slow case.
void ArmCodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
- __ push(r0);
__ mov(r0, Operand(Factory::undefined_value()));
+ __ push(r0);
}
@@ -3748,15 +3863,14 @@
void ArmCodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
ASSERT(args->length() == 0);
- // Flush the TOS cache and seed the result with the formal
- // parameters count, which will be used in case no arguments adaptor
- // frame is found below the current frame.
- __ push(r0);
+ // Seed the result with the formal parameters count, which will be used
+ // in case no arguments adaptor frame is found below the current frame.
__ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
// Call the shared stub to get to the arguments.length.
ArgumentsAccessStub stub(true);
__ CallStub(&stub);
+ __ push(r0);
}
@@ -3766,48 +3880,52 @@
// Load the key onto the stack and set register r1 to the formal
// parameters count for the currently executing function.
Load(args->at(0));
+ __ pop(r0);
__ mov(r1, Operand(Smi::FromInt(scope_->num_parameters())));
// Call the shared stub to get to arguments[key].
ArgumentsAccessStub stub(false);
__ CallStub(&stub);
+ __ push(r0);
}
void ArmCodeGenerator::GenerateShiftDownAndTailCall(
ZoneList<Expression*>* args) {
- // r0 = number of arguments
- ASSERT(args->length() == 1);
- Load(args->at(0));
- __ mov(r0, Operand(r0, LSR, kSmiTagSize));
+ // r0 = number of arguments
+ ASSERT(args->length() == 1);
+ Load(args->at(0));
+ __ pop(r0);
+ __ mov(r0, Operand(r0, LSR, kSmiTagSize));
- // Get the 'this' function and exit the frame without returning.
- __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
- ExitJSFrame(DO_NOT_RETURN);
- // return address in lr
+ // Get the 'this' function and exit the frame without returning.
+ __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
+ ExitJSFrame(DO_NOT_RETURN);
+ // return address in lr
- // Move arguments one element down the stack.
- Label move;
- Label moved;
- __ sub(r2, r0, Operand(0), SetCC);
- __ b(eq, &moved);
- __ bind(&move);
- __ sub(ip, r2, Operand(1));
- __ ldr(r3, MemOperand(sp, ip, LSL, kPointerSizeLog2));
- __ str(r3, MemOperand(sp, r2, LSL, kPointerSizeLog2));
- __ sub(r2, r2, Operand(1), SetCC);
- __ b(ne, &move);
- __ bind(&moved);
+ // Move arguments one element down the stack.
+ Label move;
+ Label moved;
+ __ sub(r2, r0, Operand(0), SetCC);
+ __ b(eq, &moved);
+ __ bind(&move);
+ __ sub(ip, r2, Operand(1));
+ __ ldr(r3, MemOperand(sp, ip, LSL, kPointerSizeLog2));
+ __ str(r3, MemOperand(sp, r2, LSL, kPointerSizeLog2));
+ __ sub(r2, r2, Operand(1), SetCC);
+ __ b(ne, &move);
+ __ bind(&moved);
- // Remove the TOS (copy of last argument)
- __ add(sp, sp, Operand(kPointerSize));
+ // Remove the TOS (copy of last argument)
+ __ pop();
- // Jump (tail-call) to the function in register r1.
- __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
- __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
- __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
- __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
- return;
+ // Jump (tail-call) to the function in register r1.
+ __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+ __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+ __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
+ __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+ return;
}
@@ -3819,28 +3937,31 @@
Comment cmnt(masm_, "[ CallRuntime");
Runtime::Function* function = node->function();
- if (function == NULL) {
- // Prepare stack for calling JS runtime function.
- __ Push(Operand(node->name()));
- // Push the builtins object found in the current global object.
- __ ldr(r1, GlobalObject());
- __ Push(FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
- }
-
- // Push the arguments ("left-to-right").
- for (int i = 0; i < args->length(); i++) Load(args->at(i));
-
if (function != NULL) {
+ // Push the arguments ("left-to-right").
+ for (int i = 0; i < args->length(); i++) Load(args->at(i));
+
// Call the C runtime function.
__ CallRuntime(function, args->length());
+ __ push(r0);
+
} else {
+ // Prepare stack for calling JS runtime function.
+ __ mov(r0, Operand(node->name()));
+ __ push(r0);
+ // Push the builtins object found in the current global object.
+ __ ldr(r1, GlobalObject());
+ __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
+ __ push(r0);
+
+ for (int i = 0; i < args->length(); i++) Load(args->at(i));
+
// Call the JS runtime function.
- __ Push(Operand(args->length()));
- __ ldr(r1, MemOperand(sp, args->length() * kPointerSize));
Handle<Code> stub = ComputeCallInitialize(args->length());
__ Call(stub, code_target);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- __ add(sp, sp, Operand(kPointerSize));
+ __ pop();
+ __ push(r0);
}
}
@@ -3860,54 +3981,59 @@
} else if (op == Token::DELETE) {
Property* property = node->expression()->AsProperty();
+ Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
if (property != NULL) {
Load(property->obj());
Load(property->key());
- __ Push(Operand(1)); // not counting receiver
+ __ mov(r0, Operand(1)); // not counting receiver
__ InvokeBuiltin("DELETE", 1, CALL_JS);
- return;
- }
- Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
- if (variable != NULL) {
+ } else if (variable != NULL) {
Slot* slot = variable->slot();
if (variable->is_global()) {
LoadGlobal();
- __ Push(Operand(variable->name()));
- __ Push(Operand(1)); // not counting receiver
+ __ mov(r0, Operand(variable->name()));
+ __ push(r0);
+ __ mov(r0, Operand(1)); // not counting receiver
__ InvokeBuiltin("DELETE", 1, CALL_JS);
- return;
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
// lookup the context holding the named variable
- __ Push(Operand(cp));
- __ Push(Operand(variable->name()));
+ __ push(cp);
+ __ mov(r0, Operand(variable->name()));
+ __ push(r0);
__ CallRuntime(Runtime::kLookupContext, 2);
// r0: context
- __ Push(Operand(variable->name()));
- __ Push(Operand(1)); // not counting receiver
+ __ push(r0);
+ __ mov(r0, Operand(variable->name()));
+ __ push(r0);
+ __ mov(r0, Operand(1)); // not counting receiver
__ InvokeBuiltin("DELETE", 1, CALL_JS);
- return;
- }
- // Default: Result of deleting non-global, not dynamically
- // introduced variables is false.
- __ Push(Operand(Factory::false_value()));
+ } else {
+ // Default: Result of deleting non-global, not dynamically
+ // introduced variables is false.
+ __ mov(r0, Operand(Factory::false_value()));
+ }
} else {
// Default: Result of deleting expressions is true.
Load(node->expression()); // may have side-effects
+ __ pop();
__ mov(r0, Operand(Factory::true_value()));
}
+ __ push(r0);
} else if (op == Token::TYPEOF) {
// Special case for loading the typeof expression; see comment on
// LoadTypeofExpression().
LoadTypeofExpression(node->expression());
__ CallRuntime(Runtime::kTypeof, 1);
+ __ push(r0); // r0 has result
} else {
Load(node->expression());
+ __ pop(r0);
switch (op) {
case Token::NOT:
case Token::DELETE:
@@ -3928,7 +4054,8 @@
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &smi_label);
- __ Push(Operand(0)); // not counting receiver
+ __ push(r0);
+ __ mov(r0, Operand(0)); // not counting receiver
__ InvokeBuiltin("BIT_NOT", 0, CALL_JS);
__ b(&continue_label);
@@ -3946,13 +4073,15 @@
break;
case Token::ADD:
- __ Push(Operand(0)); // not counting receiver
+ __ push(r0);
+ __ mov(r0, Operand(0)); // not counting receiver
__ InvokeBuiltin("TO_NUMBER", 0, CALL_JS);
break;
default:
UNREACHABLE();
}
+ __ push(r0); // r0 has result
}
}
@@ -3967,11 +4096,15 @@
bool is_const = (var != NULL && var->mode() == Variable::CONST);
// Postfix: Make room for the result.
- if (is_postfix) __ Push(Operand(0));
+ if (is_postfix) {
+ __ mov(r0, Operand(0));
+ __ push(r0);
+ }
{ Reference target(this, node->expression());
if (target.is_illegal()) return;
GetValue(&target);
+ __ pop(r0);
Label slow, exit;
@@ -4024,6 +4157,7 @@
// Store the new value in the target if not const.
__ bind(&exit);
+ __ push(r0);
if (!is_const) SetValue(&target);
}
@@ -4069,10 +4203,12 @@
} else {
Label pop_and_continue, exit;
+ __ ldr(r0, MemOperand(sp, 0)); // dup the stack top
+ __ push(r0);
// Avoid popping the result if it converts to 'false' using the
// standard ToBoolean() conversion as described in ECMA-262,
// section 9.2, page 30.
- ToBoolean(r0, &pop_and_continue, &exit);
+ ToBoolean(&pop_and_continue, &exit);
Branch(false, &exit);
// Pop the result of evaluating the first part.
@@ -4108,10 +4244,12 @@
} else {
Label pop_and_continue, exit;
+ __ ldr(r0, MemOperand(sp, 0));
+ __ push(r0);
// Avoid popping the result if it converts to 'true' using the
// standard ToBoolean() conversion as described in ECMA-262,
// section 9.2, page 30.
- ToBoolean(r0, &exit, &pop_and_continue);
+ ToBoolean(&exit, &pop_and_continue);
Branch(true, &exit);
// Pop the result of evaluating the first part.
@@ -4145,12 +4283,14 @@
Load(node->right());
GenericBinaryOperation(node->op());
}
+ __ push(r0);
}
}
void ArmCodeGenerator::VisitThisFunction(ThisFunction* node) {
- __ Push(FunctionOperand());
+ __ ldr(r0, FunctionOperand());
+ __ push(r0);
}
@@ -4177,6 +4317,7 @@
if (left_is_null || right_is_null) {
Load(left_is_null ? right : left);
Label exit, undetectable;
+ __ pop(r0);
__ cmp(r0, Operand(Factory::null_value()));
// The 'null' value is only equal to 'undefined' if using
@@ -4190,7 +4331,6 @@
__ tst(r0, Operand(kSmiTagMask));
__ b(ne, &undetectable);
- __ pop(r0);
__ b(false_target());
__ bind(&undetectable);
@@ -4201,7 +4341,6 @@
}
__ bind(&exit);
- __ pop(r0);
cc_reg_ = eq;
return;
@@ -4220,10 +4359,9 @@
right->AsLiteral()->handle()->IsString())) {
Handle<String> check(String::cast(*right->AsLiteral()->handle()));
- // Load the operand, move it to register r1, and restore TOS.
+ // Load the operand, move it to register r1.
LoadTypeofExpression(operation->expression());
- __ mov(r1, Operand(r0));
- __ pop(r0);
+ __ pop(r1);
if (check->Equals(Heap::number_symbol())) {
__ tst(r1, Operand(kSmiTagMask));
@@ -4333,13 +4471,15 @@
break;
case Token::IN:
- __ Push(Operand(1)); // not counting receiver
+ __ mov(r0, Operand(1)); // not counting receiver
__ InvokeBuiltin("IN", 1, CALL_JS);
+ __ push(r0);
break;
case Token::INSTANCEOF:
- __ Push(Operand(1)); // not counting receiver
+ __ mov(r0, Operand(1)); // not counting receiver
__ InvokeBuiltin("INSTANCE_OF", 1, CALL_JS);
+ __ push(r0);
break;
default:
diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc
index e240a13..bec5ab4 100644
--- a/src/codegen-ia32.cc
+++ b/src/codegen-ia32.cc
@@ -42,11 +42,14 @@
DECLARE_bool(debug_info);
DECLARE_bool(debug_code);
+#ifdef ENABLE_DISASSEMBLER
+DEFINE_bool(print_code, false, "print generated code");
+#endif
+
#ifdef DEBUG
DECLARE_bool(gc_greedy);
DEFINE_bool(trace_codegen, false,
"print name of functions for which code is generated");
-DEFINE_bool(print_code, false, "print generated code");
DEFINE_bool(print_builtin_code, false, "print generated code for builtins");
DEFINE_bool(print_source, false, "pretty print source code");
DEFINE_bool(print_builtin_source, false,
@@ -322,10 +325,13 @@
Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit,
Handle<Script> script,
bool is_eval) {
+#ifdef ENABLE_DISASSEMBLER
+ bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
+#endif
+
#ifdef DEBUG
bool print_source = false;
bool print_ast = false;
- bool print_code = false;
const char* ftype;
if (Bootstrapper::IsActive()) {
@@ -336,7 +342,6 @@
} else {
print_source = FLAG_print_source;
print_ast = FLAG_print_ast;
- print_code = FLAG_print_code;
ftype = "user-defined";
}
@@ -377,7 +382,7 @@
// Add unresolved entries in the code to the fixup list.
Bootstrapper::AddFixup(*code, cgen.masm());
-#ifdef DEBUG
+#ifdef ENABLE_DISASSEMBLER
if (print_code) {
// Print the source code if available.
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
@@ -393,9 +398,9 @@
PrintF("\n\n");
}
PrintF("--- Code ---\n");
- code->Print();
+ code->Disassemble();
}
-#endif // DEBUG
+#endif // ENABLE_DISASSEMBLER
return code;
}
@@ -1710,8 +1715,7 @@
// by calling the runtime system.
if (!is_length_) {
__ bind(&slow);
- __ Set(eax, Immediate(0)); // not counting receiver
- __ JumpToBuiltin(ExternalReference(Runtime::kGetArgumentsProperty));
+ __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
}
}
@@ -2268,8 +2272,7 @@
__ push(eax);
// Do tail-call to runtime routine.
- __ Set(eax, Immediate(0)); // not counting receiver
- __ JumpToBuiltin(ExternalReference(Runtime::kStackGuard));
+ __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
}
@@ -5020,7 +5023,7 @@
// ebx: pointer to C function (C callee-saved)
// ebp: frame pointer (restored after C call)
// esp: stack pointer (restored after C call)
- // edi: number of arguments (C callee-saved)
+ // edi: number of arguments including receiver (C callee-saved)
if (do_gc) {
__ mov(Operand(esp, 0 * kPointerSize), eax); // Result.
@@ -5028,8 +5031,10 @@
}
// Call C function.
- __ lea(eax,
- Operand(ebp, edi, times_4, StandardFrameConstants::kCallerSPOffset));
+ __ lea(eax, Operand(ebp,
+ edi,
+ times_4,
+ StandardFrameConstants::kCallerSPOffset - kPointerSize));
__ mov(Operand(esp, 0 * kPointerSize), edi); // argc.
__ mov(Operand(esp, 1 * kPointerSize), eax); // argv.
__ call(Operand(ebx));
@@ -5073,7 +5078,7 @@
// Pop arguments from caller's stack and return.
__ pop(ebx); // Ok to clobber ebx - function pointer not needed anymore.
- __ lea(esp, Operand(esp, ecx, times_4, +1 * kPointerSize)); // +1 ~ receiver.
+ __ lea(esp, Operand(esp, ecx, times_4, 0));
__ push(ebx);
__ ret(0);
@@ -5162,7 +5167,7 @@
void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
- // eax: number of arguments
+ // eax: number of arguments including receiver
// ebx: pointer to C function (C callee-saved)
// ebp: frame pointer (restored after C call)
// esp: stack pointer (restored after C call)
@@ -5219,7 +5224,7 @@
// ebx: pointer to builtin function (C callee-saved)
// ebp: frame pointer (restored after C call)
// esp: stack pointer (restored after C call)
- // edi: number of arguments (C callee-saved)
+ // edi: number of arguments including receiver (C callee-saved)
Label entry;
__ bind(&entry);
diff --git a/src/codegen.cc b/src/codegen.cc
index c140c37..fc057a9 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -276,7 +276,7 @@
void RuntimeStub::Generate(MacroAssembler* masm) {
- masm->TailCallRuntime(Runtime::FunctionForId((Runtime::FunctionId)id_));
+ masm->TailCallRuntime(ExternalReference(id_), num_arguments_);
}
diff --git a/src/codegen.h b/src/codegen.h
index e2f069f..4782753 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -182,15 +182,28 @@
// RuntimeStub models code stubs calling entrypoints in the Runtime class.
class RuntimeStub : public CodeStub {
public:
- explicit RuntimeStub(Runtime::FunctionId id) : id_(id) { }
+ explicit RuntimeStub(Runtime::FunctionId id, int num_arguments)
+ : id_(id), num_arguments_(num_arguments) { }
void Generate(MacroAssembler* masm);
+ // Disassembler support. It is useful to be able to print the name
+ // of the runtime function called through this stub.
+ static const char* GetNameFromMinorKey(int minor_key) {
+ return Runtime::FunctionForId(IdField::decode(minor_key))->stub_name;
+ }
+
private:
Runtime::FunctionId id_;
+ int num_arguments_;
+
+ class ArgumentField: public BitField<int, 0, 16> {};
+ class IdField: public BitField<Runtime::FunctionId, 16, kMinorBits - 16> {};
Major MajorKey() { return Runtime; }
- int MinorKey() { return id_; }
+ int MinorKey() {
+ return IdField::encode(id_) | ArgumentField::encode(num_arguments_);
+ }
const char* GetName();
diff --git a/src/date-delay.js b/src/date-delay.js
index 9a1dc31..4faa967 100644
--- a/src/date-delay.js
+++ b/src/date-delay.js
@@ -134,7 +134,7 @@
function LocalTimeOffset() {
if (IS_UNDEFINED(local_time_offset)) {
- local_time_offset = %DateLocalTimeOffset(0);
+ local_time_offset = %DateLocalTimeOffset();
}
return local_time_offset;
};
@@ -355,11 +355,11 @@
%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
- if (%IsConstructCall(this)) {
+ if (%IsConstructCall()) {
// ECMA 262 - 15.9.3
var argc = %_ArgumentsLength();
if (argc == 0) {
- %_SetValueOf(this, %DateCurrentTime(argc));
+ %_SetValueOf(this, %DateCurrentTime());
return;
}
if (argc == 1) {
@@ -585,7 +585,7 @@
// Mozilla-specific extension. Returns the number of milliseconds
// elapsed since 1 January 1970 00:00:00 UTC.
function DateNow() {
- return %DateCurrentTime(0);
+ return %DateCurrentTime();
};
diff --git a/src/debug-delay.js b/src/debug-delay.js
index dae097d..1409f78 100644
--- a/src/debug-delay.js
+++ b/src/debug-delay.js
@@ -395,7 +395,7 @@
};
Debug.Break = function(f) {
- %Break(0);
+ %Break();
};
Debug.breakLocations = function(f) {
@@ -622,7 +622,7 @@
Debug.clearStepping = function() {
- %ClearStepping(0);
+ %ClearStepping();
}
Debug.setBreakOnException = function() {
@@ -667,7 +667,7 @@
// scanning the heap.
Debug.scripts = function() {
// Collect all scripts in the heap.
- return %DebugGetLoadedScripts(0);
+ return %DebugGetLoadedScripts();
}
function MakeExecutionState(break_id) {
@@ -1858,7 +1858,7 @@
}
// Collect all scripts in the heap.
- var scripts = %DebugGetLoadedScripts(0);
+ var scripts = %DebugGetLoadedScripts();
response.body = [];
@@ -1896,7 +1896,7 @@
DebugCommandProcessor.prototype.systemBreak = function(cmd, args) {
- return %SystemBreak(0);
+ return %SystemBreak();
};
diff --git a/src/debug.cc b/src/debug.cc
index 7901ca1..4baad88 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -618,7 +618,7 @@
Object* Debug::Break(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 0);
// Get the top-most JavaScript frame.
JavaScriptFrameIterator it;
@@ -627,7 +627,7 @@
// Just continue if breaks are disabled or debugger cannot be loaded.
if (disable_break() || !Load()) {
SetAfterBreakTarget(frame);
- return args[0];
+ return Heap::undefined_value();
}
SaveBreakFrame save;
@@ -689,7 +689,7 @@
// Install jump to the call address which was overwritten.
SetAfterBreakTarget(frame);
- return args[0];
+ return Heap::undefined_value();
}
diff --git a/src/disassembler.cc b/src/disassembler.cc
index dba4a3d..51a9bf1 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -28,6 +28,7 @@
#include "v8.h"
#include "code-stubs.h"
+#include "codegen.h"
#include "debug.h"
#include "disasm.h"
#include "disassembler.h"
@@ -234,9 +235,9 @@
out.AddFormatted("argc = %d)", minor_key);
break;
case CodeStub::Runtime: {
- Runtime::FunctionId id =
- static_cast<Runtime::FunctionId>(minor_key);
- out.AddFormatted("%s)", Runtime::FunctionForId(id)->name);
+ const char* name =
+ RuntimeStub::GetNameFromMinorKey(minor_key);
+ out.AddFormatted("%s)", name);
break;
}
default:
diff --git a/src/factory.cc b/src/factory.cc
index 1fcaf0b..ba7dc3c 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -664,13 +664,6 @@
map->set_needs_access_check();
}
- // If the function template info specifies a lookup handler the
- // initial_map must have set the bit has_special_lookup.
- if (obj->lookup_callback()->IsProxy()) {
- ASSERT(!map->has_special_lookup());
- map->set_special_lookup();
- }
-
// Set interceptor information in the map.
if (!obj->named_property_handler()->IsUndefined()) {
map->set_has_named_interceptor();
diff --git a/src/frames-arm.h b/src/frames-arm.h
index 319b567..e08758f 100644
--- a/src/frames-arm.h
+++ b/src/frames-arm.h
@@ -68,7 +68,7 @@
kR9Available
<< 9 | // r9 v6
1 << 10 | // r10 v7 (pp in JavaScript code)
- 1 << 11 ; // r11 v8 (fp in JavaScript code)
+ 1 << 11; // r11 v8 (fp in JavaScript code)
static const int kNumCalleeSaved = 7 + kR9Available;
diff --git a/src/frames.h b/src/frames.h
index cfc012e..2b9551c 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -81,13 +81,13 @@
static const int kCodeNotPresent = 0;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
-
// Accessors.
inline State state() const;
inline Address pc() const;
inline void set_pc(Address value);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
};
@@ -187,9 +187,6 @@
// Compute the stack frame type for the given state.
static Type ComputeType(State* state);
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(StackFrame);
-
protected:
// TODO(1233523): Once the ARM code uses the new calling
// conventions, we should be able to make state_ private again.
@@ -207,6 +204,8 @@
friend class StackFrameIterator;
friend class StackHandlerIterator;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StackFrame);
};
diff --git a/src/heap.h b/src/heap.h
index ebce468..cd2fb2a 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -985,11 +985,17 @@
void clear_overflowed() { overflowed_ = false; }
+ // Push the (marked) object on the marking stack if there is room,
+ // otherwise mark the object as overflowed and wait for a rescan of the
+ // heap.
void Push(HeapObject* object) {
- ASSERT(!is_full());
CHECK(object->IsHeapObject());
- *(top_++) = object;
- if (is_full()) overflowed_ = true;
+ if (is_full()) {
+ object->SetOverflow();
+ overflowed_ = true;
+ } else {
+ *(top_++) = object;
+ }
}
HeapObject* Pop() {
diff --git a/src/ic-arm.cc b/src/ic-arm.cc
index d39808e..869ffcb 100644
--- a/src/ic-arm.cc
+++ b/src/ic-arm.cc
@@ -125,7 +125,6 @@
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -133,6 +132,8 @@
Label miss;
+ __ ldr(r0, MemOperand(sp, 0));
+
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -156,7 +157,6 @@
void LoadIC::GenerateShortStringLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -164,6 +164,8 @@
Label miss;
+ __ ldr(r0, MemOperand(sp, 0));
+
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -191,7 +193,6 @@
void LoadIC::GenerateMediumStringLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -199,6 +200,8 @@
Label miss;
+ __ ldr(r0, MemOperand(sp, 0));
+
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -225,7 +228,6 @@
void LoadIC::GenerateLongStringLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -233,6 +235,7 @@
Label miss;
+ __ ldr(r0, MemOperand(sp, 0));
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -259,7 +262,6 @@
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -278,15 +280,14 @@
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
- // -- r0: number of arguments
- // -- r1: receiver
// -- lr: return address
// -----------------------------------
Label number, non_number, non_string, boolean, probe, miss;
+ // Get the receiver of the function from the stack into r1.
+ __ ldr(r1, MemOperand(sp, argc * kPointerSize));
// Get the name of the function from the stack; 1 ~ receiver.
- __ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
- __ ldr(r2, MemOperand(ip, 1 * kPointerSize));
+ __ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize));
// Probe the stub cache.
Code::Flags flags =
@@ -340,12 +341,13 @@
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
- // -- r1: receiver
// -- lr: return address
// -----------------------------------
Label miss, probe, done, global;
+ // Get the receiver of the function from the stack into r1.
+ __ ldr(r1, MemOperand(sp, argc * kPointerSize));
// Get the name of the function from the stack; 1 ~ receiver.
__ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize));
@@ -405,11 +407,12 @@
// -- lr: return address
// -----------------------------------
+ // Setup number of arguments for EnterJSFrame.
+ __ mov(r0, Operand(argc));
// Get the receiver of the function from the stack into r1.
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
-
- __ mov(r0, Operand(argc)); // Setup number of arguments for EnterJSFrame.
__ EnterJSFrame(0);
+ __ pop(); // remove the code slot
// Push the receiver and the name of the function.
__ ldr(r0, MemOperand(pp, 0));
@@ -417,7 +420,7 @@
__ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
// Call the entry.
- __ mov(r0, Operand(2 - 1)); // do not count receiver
+ __ mov(r0, Operand(2));
__ mov(r1, Operand(f));
CEntryStub stub;
@@ -442,12 +445,12 @@
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
// -----------------------------------
+ __ ldr(r0, MemOperand(sp, 0));
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
StubCache::GenerateProbe(masm, flags, r0, r2, r3);
@@ -459,7 +462,6 @@
void LoadIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -467,6 +469,7 @@
Label miss, probe, done, global;
+ __ ldr(r0, MemOperand(sp, 0));
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -495,7 +498,6 @@
// Cache miss: Restore receiver from stack and jump to runtime.
__ bind(&miss);
- __ ldr(r0, MemOperand(sp));
Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
}
@@ -507,18 +509,17 @@
void LoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
// -----------------------------------
+ __ ldr(r0, MemOperand(sp, 0));
__ push(r0);
__ push(r2);
- // Set the number of arguments and jump to the entry.
- __ mov(r0, Operand(2 - 1)); // not counting receiver.
- __ JumpToBuiltin(f);
+ // Perform tail call to the entry.
+ __ TailCallRuntime(f, 2);
}
@@ -572,9 +573,8 @@
__ ldr(r3, MemOperand(sp)); // copy receiver
__ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit());
- // Set the number of arguments and jump to the entry.
- __ mov(r0, Operand(3 - 1)); // not counting receiver.
- __ JumpToBuiltin(f);
+ // Perform tail call to the entry.
+ __ TailCallRuntime(f, 3);
}
diff --git a/src/ic-ia32.cc b/src/ic-ia32.cc
index 38216b5..e7f89d5 100644
--- a/src/ic-ia32.cc
+++ b/src/ic-ia32.cc
@@ -248,8 +248,6 @@
__ j(below, &fast, taken);
// Slow case: Load name and receiver from stack and jump to runtime.
__ bind(&slow);
- __ mov(eax, Operand(esp, 1 * kPointerSize)); // 1 ~ return address.
- __ mov(ecx, Operand(esp, 2 * kPointerSize)); // 1 ~ return address, name.
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kGetProperty));
// Check if the key is a symbol that is not an array index.
@@ -333,8 +331,7 @@
__ push(eax);
__ push(ecx);
// Do tail-call to runtime routine.
- __ Set(eax, Immediate(2)); // not counting receiver
- __ JumpToBuiltin(ExternalReference(Runtime::kSetProperty));
+ __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
// Extra capacity case: Check if there is extra capacity to
@@ -530,7 +527,7 @@
// Call the entry.
CEntryStub stub;
- __ mov(Operand(eax), Immediate(2 - 1)); // do not count receiver
+ __ mov(Operand(eax), Immediate(2));
__ mov(Operand(ebx), Immediate(f));
__ CallStub(&stub);
@@ -636,9 +633,8 @@
__ push(ecx);
__ push(ebx);
- // Set the number of arguments and jump to the entry.
- __ mov(Operand(eax), Immediate(1)); // not counting receiver.
- __ JumpToBuiltin(f);
+ // Perform tail call to the entry.
+ __ TailCallRuntime(f, 2);
}
@@ -673,9 +669,8 @@
__ push(eax);
__ push(ebx);
- // Set the number of arguments and jump to the entry.
- __ mov(Operand(eax), Immediate(1)); // not counting receiver.
- __ JumpToBuiltin(f);
+ // Perform tail call to the entry.
+ __ TailCallRuntime(f, 2);
}
@@ -715,9 +710,8 @@
__ push(eax);
__ push(ebx);
- // Set the number of arguments and jump to the entry.
- __ Set(eax, Immediate(2)); // not counting receiver.
- __ JumpToBuiltin(f);
+ // Perform tail call to the entry.
+ __ TailCallRuntime(f, 3);
}
@@ -740,8 +734,7 @@
__ push(ecx);
// Do tail-call to runtime routine.
- __ Set(eax, Immediate(2)); // not counting receiver
- __ JumpToBuiltin(f);
+ __ TailCallRuntime(f, 3);
}
diff --git a/src/ic.h b/src/ic.h
index 6319ba9..b474e9f 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -128,8 +128,6 @@
static inline void SetTargetAtAddress(Address address, Code* target);
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
-
// Frame pointer for the frame that uses (calls) the IC.
Address fp_;
@@ -138,6 +136,8 @@
// GetProperty and SetProperty are called and they in turn might
// invoke the garbage collector.
Address* pc_address_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
};
diff --git a/src/macro-assembler-arm.cc b/src/macro-assembler-arm.cc
index bf81510..21fcea4 100644
--- a/src/macro-assembler-arm.cc
+++ b/src/macro-assembler-arm.cc
@@ -174,30 +174,6 @@
}
-void MacroAssembler::Push(const Operand& src) {
- push(r0);
- mov(r0, src);
-}
-
-
-void MacroAssembler::Push(const MemOperand& src) {
- push(r0);
- ldr(r0, src);
-}
-
-
-void MacroAssembler::Pop(Register dst) {
- mov(dst, Operand(r0));
- pop(r0);
-}
-
-
-void MacroAssembler::Pop(const MemOperand& dst) {
- str(r0, dst);
- pop(r0);
-}
-
-
// Will clobber 4 registers: object, offset, scratch, ip. The
// register 'object' contains a heap object pointer. The heap object
// tag is shifted away.
@@ -320,7 +296,7 @@
add(fp, sp, Operand(-StandardFrameConstants::kContextOffset));
mov(pp, Operand(ip)); // setup new parameter pointer
mov(r0, Operand(0)); // spare slot to store caller code object during GC
- // r0: TOS (code slot == 0)
+ push(r0);
// r1: preserved
}
@@ -517,7 +493,6 @@
ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code
// The pc (return address) is passed in register lr.
if (try_location == IN_JAVASCRIPT) {
- mov(r0, Operand(Smi::FromInt(StackHandler::kCodeNotPresent))); // new TOS
stm(db_w, sp, pp.bit() | fp.bit() | lr.bit());
if (type == TRY_CATCH_HANDLER) {
mov(r3, Operand(StackHandler::TRY_CATCH));
@@ -529,14 +504,14 @@
ldr(r1, MemOperand(r3));
push(r1); // next sp
str(sp, MemOperand(r3)); // chain handler
- // TOS is r0
+ mov(r0, Operand(Smi::FromInt(StackHandler::kCodeNotPresent))); // new TOS
+ push(r0);
} else {
// Must preserve r0-r3, r5-r7 are available.
ASSERT(try_location == IN_JS_ENTRY);
// The parameter pointer is meaningless here and fp does not point to a JS
// frame. So we save NULL for both pp and fp. We expect the code throwing an
// exception to check fp before dereferencing it to restore the context.
- mov(r5, Operand(Smi::FromInt(StackHandler::kCodeNotPresent))); // new TOS
mov(pp, Operand(0)); // set pp to NULL
mov(ip, Operand(0)); // to save a NULL fp
stm(db_w, sp, pp.bit() | ip.bit() | lr.bit());
@@ -546,6 +521,7 @@
ldr(r6, MemOperand(r7));
push(r6); // next sp
str(sp, MemOperand(r7)); // chain handler
+ mov(r5, Operand(Smi::FromInt(StackHandler::kCodeNotPresent))); // new TOS
push(r5); // flush TOS
}
}
@@ -670,29 +646,17 @@
Ret();
}
+
void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
- ASSERT(num_arguments >= 1); // must have receiver for call
+ // All parameters are on the stack. r0 has the return value after call.
- if (f->nargs < 0) {
- // The number of arguments is not constant for this call, or we don't
- // have an entry stub that pushes the value. Push it before the call.
- push(r0);
- // Receiver does not count as an argument.
- mov(r0, Operand(num_arguments - 1));
- } else {
- ASSERT(f->nargs == num_arguments);
- // TODO(1236192): Most runtime routines don't need the number of
- // arguments passed in because it is constant. At some point we
- // should remove this need and make the runtime routine entry code
- // smarter.
+ // Either the expected number of arguments is unknown, or the actual
+ // number of arguments match the expectation.
+ ASSERT(f->nargs < 0 || f->nargs == num_arguments);
- // The number of arguments is fixed for this call.
- // Set r0 correspondingly.
- push(r0);
- mov(r0, Operand(f->nargs - 1)); // receiver does not count as an argument
- }
-
- RuntimeStub stub((Runtime::FunctionId) f->stub_id);
+ Runtime::FunctionId function_id =
+ static_cast<Runtime::FunctionId>(f->stub_id);
+ RuntimeStub stub(function_id, num_arguments);
CallStub(&stub);
}
@@ -702,8 +666,14 @@
}
-void MacroAssembler::TailCallRuntime(Runtime::Function* f) {
- JumpToBuiltin(ExternalReference(f)); // tail call to runtime routine
+void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
+ int num_arguments) {
+ // TODO(1236192): Most runtime routines don't need the number of
+ // arguments passed in because it is constant. At some point we
+ // should remove this need and make the runtime routine entry code
+ // smarter.
+ mov(r0, Operand(num_arguments));
+ JumpToBuiltin(ext);
}
@@ -781,10 +751,10 @@
RecordComment(msg);
}
#endif
- push(r0);
mov(r0, Operand(p0));
push(r0);
mov(r0, Operand(Smi::FromInt(p1 - p0)));
+ push(r0);
CallRuntime(Runtime::kAbort, 2);
// will not return here
}
diff --git a/src/macro-assembler-arm.h b/src/macro-assembler-arm.h
index 60a827d..00cf621 100644
--- a/src/macro-assembler-arm.h
+++ b/src/macro-assembler-arm.h
@@ -102,12 +102,6 @@
void ExitJSFrame(ExitJSFlag flag);
- // Support functions.
- void Push(const Operand& src);
- void Push(const MemOperand& src);
- void Pop(Register dst);
- void Pop(const MemOperand& dst);
-
// ---------------------------------------------------------------------------
// JavaScript invokes
@@ -198,8 +192,8 @@
// Tail call of a runtime routine (jump).
// Like JumpToBuiltin, but also takes care of passing the number
- // of parameters, if known.
- void TailCallRuntime(Runtime::Function* f);
+ // of parameters.
+ void TailCallRuntime(const ExternalReference& ext, int num_arguments);
// Jump to the builtin routine.
void JumpToBuiltin(const ExternalReference& builtin);
diff --git a/src/macro-assembler-ia32.cc b/src/macro-assembler-ia32.cc
index d6f2264..c56d334 100644
--- a/src/macro-assembler-ia32.cc
+++ b/src/macro-assembler-ia32.cc
@@ -530,38 +530,29 @@
void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
- if (num_arguments < 1) {
- // must have receiver for call
+ // If the expected number of arguments of the runtime function is
+ // constant, we check that the actual number of arguments match the
+ // expectation.
+ if (f->nargs >= 0 && f->nargs != num_arguments) {
IllegalOperation();
return;
}
- // TODO(1236192): Most runtime routines don't need the number of
- // arguments passed in because it is constant. At some point we
- // should remove this need and make the runtime routine entry code
- // smarter.
-
- if (f->nargs < 0) {
- // The number of arguments is not constant for this call.
- // Receiver does not count as an argument.
- mov(Operand(eax), Immediate(num_arguments - 1));
- } else {
- if (f->nargs != num_arguments) {
- IllegalOperation();
- return;
- }
- // Receiver does not count as an argument.
- mov(Operand(eax), Immediate(f->nargs - 1));
- }
-
- RuntimeStub stub((Runtime::FunctionId) f->stub_id);
+ Runtime::FunctionId function_id =
+ static_cast<Runtime::FunctionId>(f->stub_id);
+ RuntimeStub stub(function_id, num_arguments);
CallStub(&stub);
}
-
-void MacroAssembler::TailCallRuntime(Runtime::Function* f) {
- JumpToBuiltin(ExternalReference(f)); // tail call to runtime routine
+void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
+ int num_arguments) {
+ // TODO(1236192): Most runtime routines don't need the number of
+ // arguments passed in because it is constant. At some point we
+ // should remove this need and make the runtime routine entry code
+ // smarter.
+ mov(Operand(eax), Immediate(num_arguments));
+ JumpToBuiltin(ext);
}
diff --git a/src/macro-assembler-ia32.h b/src/macro-assembler-ia32.h
index 0fad02d..b3aba9a 100644
--- a/src/macro-assembler-ia32.h
+++ b/src/macro-assembler-ia32.h
@@ -196,8 +196,8 @@
// Tail call of a runtime routine (jump).
// Like JumpToBuiltin, but also takes care of passing the number
- // of parameters, if known.
- void TailCallRuntime(Runtime::Function* f);
+ // of arguments.
+ void TailCallRuntime(const ExternalReference& ext, int num_arguments);
// Jump to the builtin routine.
void JumpToBuiltin(const ExternalReference& ext);
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index b28ee5e..0ec3bb0 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -214,6 +214,44 @@
static MarkingStack marking_stack;
+
+inline HeapObject* ShortCircuitConsString(Object** p) {
+ // Optimization: If the heap object pointed to by p is a cons string whose
+ // right substring is Heap::empty_string, update it in place to its left
+ // substring. Return the updated value.
+ //
+ // Here we assume that if we change *p, we replace it with a heap object
+ // (ie, the left substring of a cons string is always a heap object).
+ //
+ // The check performed is:
+ // object->IsConsString() &&
+ // (ConsString::cast(object)->second() == Heap::empty_string())
+ // except the maps for the object and its possible substrings might be
+ // marked.
+ HeapObject* object = HeapObject::cast(*p);
+ MapWord map_word = object->map_word();
+ map_word.ClearMark();
+ InstanceType type = map_word.ToMap()->instance_type();
+ if (type >= FIRST_NONSTRING_TYPE) return object;
+
+ StringRepresentationTag rep =
+ static_cast<StringRepresentationTag>(type & kStringRepresentationMask);
+ if (rep != kConsStringTag) return object;
+
+ Object* second = reinterpret_cast<ConsString*>(object)->second();
+ if (reinterpret_cast<String*>(second) != Heap::empty_string()) return object;
+
+ // Since we don't have the object's start, it is impossible to update the
+ // remembered set. Therefore, we only replace the string with its left
+ // substring when the remembered set does not change.
+ Object* first = reinterpret_cast<ConsString*>(object)->first();
+ if (!Heap::InNewSpace(object) && Heap::InNewSpace(first)) return object;
+
+ *p = first;
+ return HeapObject::cast(first);
+}
+
+
// Helper class for marking pointers in HeapObjects.
class MarkingVisitor : public ObjectVisitor {
public:
@@ -272,34 +310,9 @@
private:
// Mark object pointed to by p.
void MarkObjectByPointer(Object** p) {
- Object* obj = *p;
- if (!obj->IsHeapObject()) return;
-
- // Optimization: Bypass ConsString object where right size is
- // Heap::empty_string().
- // Please note this checks performed equals:
- // object->IsConsString() &&
- // (ConsString::cast(object)->second() == Heap::empty_string())
- // except the map for the object might be marked.
- MapWord map_word = HeapObject::cast(obj)->map_word();
- map_word.ClearMark();
- InstanceType type = map_word.ToMap()->instance_type();
- if ((type < FIRST_NONSTRING_TYPE) &&
- (static_cast<StringRepresentationTag>(
- type & kStringRepresentationMask) == kConsStringTag) &&
- (reinterpret_cast<String*>(
- reinterpret_cast<ConsString*>(obj)->second()) ==
- Heap::empty_string())) {
- // Since we don't have the object start it is impossible to update the
- // remeber set quickly. Therefore this optimization only is taking
- // place when we can avoid changing.
- Object* first = reinterpret_cast<ConsString*>(obj)->first();
- if (Heap::InNewSpace(obj) || !Heap::InNewSpace(first)) {
- obj = first;
- *p = obj;
- }
- }
- MarkCompactCollector::MarkObject(HeapObject::cast(obj));
+ if (!(*p)->IsHeapObject()) return;
+ HeapObject* object = ShortCircuitConsString(p);
+ MarkCompactCollector::MarkObject(object);
}
// Tells whether the mark sweep collection will perform compaction.
@@ -345,6 +358,48 @@
};
+// Visitor class for marking heap roots.
+class RootMarkingVisitor : public ObjectVisitor {
+ public:
+ void VisitPointer(Object** p) {
+ MarkObjectByPointer(p);
+ }
+
+ void VisitPointers(Object** start, Object** end) {
+ for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
+ }
+
+ MarkingVisitor* stack_visitor() { return &stack_visitor_; }
+
+ private:
+ MarkingVisitor stack_visitor_;
+
+ void MarkObjectByPointer(Object** p) {
+ if (!(*p)->IsHeapObject()) return;
+
+ // Replace flat cons strings in place.
+ HeapObject* object = ShortCircuitConsString(p);
+ if (object->IsMarked()) return;
+
+#ifdef DEBUG
+ MarkCompactCollector::UpdateLiveObjectCount(object);
+#endif
+ Map* map = object->map();
+ // Mark the object.
+ object->SetMark();
+ MarkCompactCollector::tracer()->increment_marked_count();
+ // Mark the map pointer and body, and push them on the marking stack.
+ MarkCompactCollector::MarkObject(map);
+ object->IterateBody(map->instance_type(), object->SizeFromMap(map),
+ &stack_visitor_);
+
+ // Mark all the objects reachable from the map and body. May leave
+ // overflowed objects in the heap.
+ MarkCompactCollector::EmptyMarkingStack(&stack_visitor_);
+ }
+};
+
+
// Helper class for pruning the symbol table.
class SymbolTableCleaner : public ObjectVisitor {
public:
@@ -368,26 +423,21 @@
};
-void MarkCompactCollector::MarkUnmarkedObject(HeapObject* obj) {
+void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) {
#ifdef DEBUG
- UpdateLiveObjectCount(obj);
+ UpdateLiveObjectCount(object);
#endif
- ASSERT(!obj->IsMarked());
- if (obj->IsJSGlobalObject()) Counters::global_objects.Increment();
+ ASSERT(!object->IsMarked());
+ if (object->IsJSGlobalObject()) Counters::global_objects.Increment();
- if (FLAG_cleanup_caches_in_maps_at_gc && obj->IsMap()) {
- Map::cast(obj)->ClearCodeCache();
+ if (FLAG_cleanup_caches_in_maps_at_gc && object->IsMap()) {
+ Map::cast(object)->ClearCodeCache();
}
- obj->SetMark();
+ object->SetMark();
tracer_->increment_marked_count();
- if (!marking_stack.overflowed()) {
- ASSERT(Heap::Contains(obj));
- marking_stack.Push(obj);
- } else {
- // Set object's stack overflow bit, wait for rescan.
- obj->SetOverflow();
- }
+ ASSERT(Heap::Contains(object));
+ marking_stack.Push(object);
}
@@ -401,26 +451,23 @@
}
-static bool VisitOverflowedObject(HeapObject* obj) {
- if (!obj->IsOverflowed()) return true;
- ASSERT(obj->IsMarked());
-
- if (marking_stack.overflowed()) return false;
-
- obj->ClearOverflow();
- ASSERT(Heap::Contains(obj));
- marking_stack.Push(obj);
- return true;
-}
-
-
+// Fill the marking stack with overflowed objects returned by the given
+// iterator. Stop when the marking stack is filled or the end of the space
+// is reached, whichever comes first.
template<class T>
static void ScanOverflowedObjects(T* it) {
+ // The caller should ensure that the marking stack is initially not full,
+ // so that we don't waste effort pointlessly scanning for objects.
+ ASSERT(!marking_stack.is_full());
+
while (it->has_next()) {
- HeapObject* obj = it->next();
- if (!VisitOverflowedObject(obj)) {
- ASSERT(marking_stack.overflowed());
- break;
+ HeapObject* object = it->next();
+ if (object->IsOverflowed()) {
+ object->ClearOverflow();
+ ASSERT(object->IsMarked());
+ ASSERT(Heap::Contains(object));
+ marking_stack.Push(object);
+ if (marking_stack.is_full()) return;
}
}
}
@@ -433,15 +480,15 @@
}
-void MarkCompactCollector::MarkStrongRoots(MarkingVisitor* marking_visitor) {
+void MarkCompactCollector::ProcessRoots(RootMarkingVisitor* visitor) {
// Mark the heap roots gray, including global variables, stack variables,
// etc.
- Heap::IterateStrongRoots(marking_visitor);
+ Heap::IterateStrongRoots(visitor);
// Take care of the symbol table specially.
SymbolTable* symbol_table = SymbolTable::cast(Heap::symbol_table());
// 1. Mark the prefix of the symbol table gray.
- symbol_table->IteratePrefix(marking_visitor);
+ symbol_table->IteratePrefix(visitor);
#ifdef DEBUG
UpdateLiveObjectCount(symbol_table);
#endif
@@ -449,6 +496,12 @@
// or mark it overflowed).
symbol_table->SetMark();
tracer_->increment_marked_count();
+
+ // There may be overflowed objects in the heap. Visit them now.
+ while (marking_stack.overflowed()) {
+ RefillMarkingStack();
+ EmptyMarkingStack(visitor->stack_visitor());
+ }
}
@@ -486,70 +539,82 @@
}
-// Mark as black all objects reachable starting from gray objects. (Gray
-// objects are marked and on the marking stack, or marked and marked as
-// overflowed and not on the marking stack).
-//
-// Before: the heap contains a mixture of white, gray, and black objects.
-// After: the heap contains a mixture of white and black objects.
-void MarkCompactCollector::ProcessMarkingStack(
- MarkingVisitor* marking_visitor) {
+// Mark all objects reachable from the objects on the marking stack.
+// Before: the marking stack contains zero or more heap object pointers.
+// After: the marking stack is empty, and all objects reachable from the
+// marking stack have been marked, or are overflowed in the heap.
+void MarkCompactCollector::EmptyMarkingStack(MarkingVisitor* visitor) {
+ while (!marking_stack.is_empty()) {
+ HeapObject* object = marking_stack.Pop();
+ ASSERT(object->IsHeapObject());
+ ASSERT(Heap::Contains(object));
+ ASSERT(object->IsMarked());
+ ASSERT(!object->IsOverflowed());
- while (true) {
- while (!marking_stack.is_empty()) {
- HeapObject* object = marking_stack.Pop();
- ASSERT(object->IsHeapObject());
- ASSERT(Heap::Contains(object));
- // Removing a (gray) object from the marking stack turns it black.
- ASSERT(object->IsMarked() && !object->IsOverflowed());
-
- // Because the object is marked, we have to recover the original map
- // pointer and use it to mark the object's body.
- MapWord map_word = object->map_word();
- map_word.ClearMark();
- Map* map = map_word.ToMap();
- MarkObject(map);
- object->IterateBody(map->instance_type(), object->SizeFromMap(map),
- marking_visitor);
- }
-
- // The only gray objects are marked overflowed in the heap. If there
- // are any, refill the marking stack and continue.
- if (!marking_stack.overflowed()) return;
-
- marking_stack.clear_overflowed();
- // We have early stops if the marking stack overflows while refilling it
- // with gray objects to avoid pointlessly scanning extra spaces.
- SemiSpaceIterator new_it(Heap::new_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&new_it);
- if (marking_stack.overflowed()) continue;
-
- HeapObjectIterator old_it(Heap::old_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&old_it);
- if (marking_stack.overflowed()) continue;
-
- HeapObjectIterator code_it(Heap::code_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&code_it);
- if (marking_stack.overflowed()) continue;
-
- HeapObjectIterator map_it(Heap::map_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&map_it);
- if (marking_stack.overflowed()) continue;
-
- LargeObjectIterator lo_it(Heap::lo_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&lo_it);
+ // Because the object is marked, we have to recover the original map
+ // pointer and use it to mark the object's body.
+ MapWord map_word = object->map_word();
+ map_word.ClearMark();
+ Map* map = map_word.ToMap();
+ MarkObject(map);
+ object->IterateBody(map->instance_type(), object->SizeFromMap(map),
+ visitor);
}
}
-void MarkCompactCollector::ProcessObjectGroups(
- MarkingVisitor* marking_visitor) {
+// Sweep the heap for overflowed objects, clear their overflow bits, and
+// push them on the marking stack. Stop early if the marking stack fills
+// before sweeping completes. If sweeping completes, there are no remaining
+// overflowed objects in the heap so the overflow flag on the markings stack
+// is cleared.
+void MarkCompactCollector::RefillMarkingStack() {
+ ASSERT(marking_stack.overflowed());
+
+ SemiSpaceIterator new_it(Heap::new_space(), &OverflowObjectSize);
+ ScanOverflowedObjects(&new_it);
+ if (marking_stack.is_full()) return;
+
+ HeapObjectIterator old_it(Heap::old_space(), &OverflowObjectSize);
+ ScanOverflowedObjects(&old_it);
+ if (marking_stack.is_full()) return;
+
+ HeapObjectIterator code_it(Heap::code_space(), &OverflowObjectSize);
+ ScanOverflowedObjects(&code_it);
+ if (marking_stack.is_full()) return;
+
+ HeapObjectIterator map_it(Heap::map_space(), &OverflowObjectSize);
+ ScanOverflowedObjects(&map_it);
+ if (marking_stack.is_full()) return;
+
+ LargeObjectIterator lo_it(Heap::lo_space(), &OverflowObjectSize);
+ ScanOverflowedObjects(&lo_it);
+ if (marking_stack.is_full()) return;
+
+ marking_stack.clear_overflowed();
+}
+
+
+// Mark all objects reachable (transitively) from objects on the marking
+// stack. Before: the marking stack contains zero or more heap object
+// pointers. After: the marking stack is empty and there are no overflowed
+// objects in the heap.
+void MarkCompactCollector::ProcessMarkingStack(MarkingVisitor* visitor) {
+ EmptyMarkingStack(visitor);
+ while (marking_stack.overflowed()) {
+ RefillMarkingStack();
+ EmptyMarkingStack(visitor);
+ }
+}
+
+
+void MarkCompactCollector::ProcessObjectGroups(MarkingVisitor* visitor) {
bool work_to_do = true;
ASSERT(marking_stack.is_empty());
while (work_to_do) {
MarkObjectGroups();
work_to_do = !marking_stack.is_empty();
- ProcessMarkingStack(marking_visitor);
+ ProcessMarkingStack(visitor);
}
}
@@ -566,15 +631,14 @@
ASSERT(!marking_stack.overflowed());
- MarkingVisitor marking_visitor;
- MarkStrongRoots(&marking_visitor);
- ProcessMarkingStack(&marking_visitor);
+ RootMarkingVisitor root_visitor;
+ ProcessRoots(&root_visitor);
// The objects reachable from the roots are marked black, unreachable
// objects are white. Mark objects reachable from object groups with at
// least one marked object, and continue until no new objects are
// reachable from the object groups.
- ProcessObjectGroups(&marking_visitor);
+ ProcessObjectGroups(root_visitor.stack_visitor());
// The objects reachable from the roots or object groups are marked black,
// unreachable objects are white. Process objects reachable only from
@@ -583,12 +647,15 @@
// First we mark weak pointers not yet reachable.
GlobalHandles::MarkWeakRoots(&MustBeMarked);
// Then we process weak pointers and process the transitive closure.
- GlobalHandles::IterateWeakRoots(&marking_visitor);
- ProcessMarkingStack(&marking_visitor);
+ GlobalHandles::IterateWeakRoots(&root_visitor);
+ while (marking_stack.overflowed()) {
+ RefillMarkingStack();
+ EmptyMarkingStack(root_visitor.stack_visitor());
+ }
// Repeat the object groups to mark unmarked groups reachable from the
// weak roots.
- ProcessObjectGroups(&marking_visitor);
+ ProcessObjectGroups(root_visitor.stack_visitor());
// Prune the symbol table removing all symbols only pointed to by the
// symbol table. Cannot use SymbolTable::cast here because the symbol
diff --git a/src/mark-compact.h b/src/mark-compact.h
index d4dcdc7..7ab6d32 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -39,9 +39,11 @@
typedef void (*DeallocateFunction)(Address start, int size_in_bytes);
-// Forward declaration of visitor.
+// Forward declarations.
+class RootMarkingVisitor;
class MarkingVisitor;
+
// ----------------------------------------------------------------------------
// Mark-Compact collector
//
@@ -141,16 +143,11 @@
//
// after: live objects are marked.
+ friend class RootMarkingVisitor;
friend class MarkingVisitor;
// Marking operations for objects reachable from roots.
static void MarkLiveObjects();
- static void UnmarkLiveObjects();
-
- // Visit overflowed object, push overflowed object on the marking stack and
- // clear the overflow bit. If the marking stack is overflowed during this
- // process, return false;
- static bool VisitOverflowedObject(HeapObject* obj);
static void MarkUnmarkedObject(HeapObject* obj);
@@ -158,8 +155,8 @@
if (!obj->IsMarked()) MarkUnmarkedObject(obj);
}
- // Mark the heap roots.
- static void MarkStrongRoots(MarkingVisitor* marking_visitor);
+ // Mark the heap roots and all objects reachable from them.
+ static void ProcessRoots(RootMarkingVisitor* visitor);
// Mark objects in object groups that have at least one object in the
// group marked.
@@ -168,11 +165,22 @@
// Mark all objects in an object group with at least one marked
// object, then all objects reachable from marked objects in object
// groups, and repeat.
- static void ProcessObjectGroups(MarkingVisitor* marking_visitor);
+ static void ProcessObjectGroups(MarkingVisitor* visitor);
- // Mark all objects reachable (transitively) from objects in the
- // marking stack or marked as overflowed in the heap.
- static void ProcessMarkingStack(MarkingVisitor* marking_visitor);
+ // Mark objects reachable (transitively) from objects in the marking stack
+ // or overflowed in the heap.
+ static void ProcessMarkingStack(MarkingVisitor* visitor);
+
+ // Mark objects reachable (transitively) from objects in the marking
+ // stack. This function empties the marking stack, but may leave
+ // overflowed objects in the heap, in which case the marking stack's
+ // overflow flag will be set.
+ static void EmptyMarkingStack(MarkingVisitor* visitor);
+
+ // Refill the marking stack with overflowed objects from the heap. This
+ // function either leaves the marking stack full or clears the overflow
+ // flag on the marking stack.
+ static void RefillMarkingStack();
// Callback function for telling whether the object *p must be marked.
static bool MustBeMarked(Object** p);
diff --git a/src/math.js b/src/math.js
index eb4a4cc..12bf70d 100644
--- a/src/math.js
+++ b/src/math.js
@@ -41,9 +41,7 @@
%AddProperty(global, "Math", $Math, DONT_ENUM);
-// TODO(1240985): Make this work without arguments to the runtime
-// call.
-function $Math_random() { return %Math_random(0); }
+function $Math_random() { return %Math_random(); }
%AddProperty($Math, "random", $Math_random, DONT_ENUM);
function $Math_abs(x) {
diff --git a/src/messages.js b/src/messages.js
index 2641145..1630122 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -639,7 +639,7 @@
f.prototype.name = name;
f.prototype.constructor = f;
%SetCode(f, function(m) {
- if (%IsConstructCall(this)) {
+ if (%IsConstructCall()) {
if (!IS_UNDEFINED(m)) this.message = ToString(m);
} else {
return new f(m);
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index c70ab16..d12b7d3 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -594,16 +594,9 @@
void Code::CodePrint() {
HeapObject::PrintHeader("Code");
- PrintF("kind = %s", Kind2String(kind()));
-
- PrintF("\nInstructions (size = %d)\n", instruction_size());
- Disassembler::Decode(NULL /*use PrintF*/, this);
- PrintF("\n");
-
- PrintF("RelocInfo (size = %d)\n", relocation_size());
- for (RelocIterator it(this); !it.done(); it.next())
- it.rinfo()->Print();
- PrintF("\n");
+#ifdef ENABLE_DISASSEMBLER
+ Disassemble();
+#endif
}
diff --git a/src/objects.cc b/src/objects.cc
index 5527cfb..4bda9cc 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -37,6 +37,10 @@
#include "scopeinfo.h"
#include "string-stream.h"
+#ifdef ENABLE_DISASSEMBLER
+#include "disassembler.h"
+#endif
+
namespace v8 { namespace internal {
#ifdef DEBUG
@@ -985,7 +989,6 @@
Object* r = old_descriptors->CopyRemove(name);
if (r->IsFailure()) return r;
old_descriptors = DescriptorArray::cast(r);
- map()->set_instance_descriptors(old_descriptors);
old_name_index = DescriptorArray::kNotFound;
}
@@ -995,35 +998,35 @@
// Allocate new instance descriptors with (name, index) added
FieldDescriptor new_field(name, index, attributes);
Object* new_descriptors =
- map()->instance_descriptors()->CopyInsert(&new_field, true);
+ old_descriptors->CopyInsert(&new_field, true);
if (new_descriptors->IsFailure()) return new_descriptors;
// Only allow map transition if the object's map is NOT equal to the
// global object_function's map and there is not a transition for name.
bool allow_map_transition =
- !map()->instance_descriptors()->Contains(name) &&
+ !old_descriptors->Contains(name) &&
(Top::context()->global_context()->object_function()->map() != map());
ASSERT(allow_map_transition || !constant_transition);
if (map()->unused_property_fields() > 0) {
ASSERT(index < properties()->length());
// Allocate a new map for the object.
- Object* new_map = map()->Copy();
- if (new_map->IsFailure()) return new_map;
+ Object* r = map()->Copy();
+ if (r->IsFailure()) return r;
+ Map* new_map = Map::cast(r);
if (allow_map_transition) {
// Allocate new instance descriptors for the old map with map transition.
MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
- Object* old_descriptors = map()->instance_descriptors()->CopyInsert(&d);
- if (old_descriptors->IsFailure()) return old_descriptors;
- // We have now allocate all the necessary object and change can be
- // applied.
- map()->set_instance_descriptors(DescriptorArray::cast(old_descriptors));
+ Object* r = old_descriptors->CopyInsert(&d);
+ if (r->IsFailure()) return r;
+ old_descriptors = DescriptorArray::cast(r);
}
- Map::cast(new_map)->
- set_instance_descriptors(DescriptorArray::cast(new_descriptors));
- Map::cast(new_map)->
- set_unused_property_fields(map()->unused_property_fields() - 1);
- set_map(Map::cast(new_map));
+ // We have now allocated all the necessary objects.
+ // All the changes can be applied at once, so they are atomic.
+ map()->set_instance_descriptors(old_descriptors);
+ new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+ new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
+ set_map(new_map);
properties()->set(index, value);
} else {
ASSERT(map()->unused_property_fields() == 0);
@@ -1043,26 +1046,23 @@
FixedArray::cast(values)->set(index, value);
// Allocate a new map for the object.
- Object* new_map = map()->Copy();
- if (new_map->IsFailure()) return new_map;
+ Object* r = map()->Copy();
+ if (r->IsFailure()) return r;
+ Map* new_map = Map::cast(r);
if (allow_map_transition) {
MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
- // Allocate a new instance descriptors for the old map with map
- // transition.
- Object* old_descriptors = map()->instance_descriptors()->CopyInsert(&d);
- if (old_descriptors->IsFailure()) return old_descriptors;
-
- // We have now allocate all the necessary object and change can be
- // applied.
- map()->set_instance_descriptors(DescriptorArray::cast(old_descriptors));
+ // Allocate new instance descriptors for the old map with map transition.
+ Object* r = old_descriptors->CopyInsert(&d);
+ if (r->IsFailure()) return r;
+ old_descriptors = DescriptorArray::cast(r);
}
-
- Map::cast(new_map)->
- set_instance_descriptors(DescriptorArray::cast(new_descriptors));
- Map::cast(new_map)->
- set_unused_property_fields(kExtraFields - 1);
- set_map(Map::cast(new_map));
+ // We have now allocated all the necessary objects.
+ // All changes can be done at once, atomically.
+ map()->set_instance_descriptors(old_descriptors);
+ new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+ new_map->set_unused_property_fields(kExtraFields - 1);
+ set_map(new_map);
set_properties(FixedArray::cast(values));
}
@@ -1109,7 +1109,7 @@
ConstTransitionDescriptor mark(name);
new_descriptors = old_map->instance_descriptors()->CopyInsert(&mark, false);
if (new_descriptors->IsFailure()) {
- return new_descriptors;
+ return function; // We have accomplished the main goal, so return success.
}
old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
@@ -4083,6 +4083,20 @@
UNREACHABLE();
return NULL;
}
+
+
+void Code::Disassemble() {
+ PrintF("kind = %s", Kind2String(kind()));
+
+ PrintF("\nInstructions (size = %d)\n", instruction_size());
+ Disassembler::Decode(NULL, this);
+ PrintF("\n");
+
+ PrintF("RelocInfo (size = %d)\n", relocation_size());
+ for (RelocIterator it(this); !it.done(); it.next())
+ it.rinfo()->Print();
+ PrintF("\n");
+}
#endif // ENABLE_DISASSEMBLER
diff --git a/src/objects.h b/src/objects.h
index 4b1f8c8..e337b54 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -2030,6 +2030,7 @@
#ifdef ENABLE_DISASSEMBLER
// Printing
static const char* Kind2String(Kind kind);
+ void Disassemble();
#endif // ENABLE_DISASSEMBLER
// [instruction_size]: Size of the native instructions
@@ -2195,15 +2196,6 @@
inline byte bit_field();
inline void set_bit_field(byte value);
- // Tells whether this object has a special lookup behavior.
- void set_special_lookup() {
- set_bit_field(bit_field() | (1 << kHasSpecialLookup));
- }
-
- bool has_special_lookup() {
- return ((1 << kHasSpecialLookup) & bit_field()) != 0;
- }
-
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
// property is set to a value that is not a JSObject, the prototype
@@ -2343,7 +2335,7 @@
static const int kBitFieldOffset = kInstanceAttributesOffset + 3;
// Bit positions for bit field.
- static const int kHasSpecialLookup = 0;
+ static const int kUnused = 0; // To be used for marking recently used maps.
static const int kHasNonInstancePrototype = 1;
static const int kIsHiddenPrototype = 2;
static const int kHasNamedInterceptor = 3;
@@ -2374,7 +2366,7 @@
};
-// Script describes a script which has beed added to the VM.
+// Script describes a script which has been added to the VM.
class Script: public Struct {
public:
// [source]: the script source.
@@ -2528,8 +2520,6 @@
static const int kSize = kDebugInfoOffset + kPointerSize;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
-
// Bit positions in length_and_flg.
// The least significant bit is used as the flag.
static const int kFlagBit = 0;
@@ -2543,6 +2533,8 @@
static const int kIsTopLevelBit = 1;
static const int kStartPositionShift = 2;
static const int kStartPositionMask = ~((1 << kStartPositionShift) - 1);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
};
@@ -2652,8 +2644,9 @@
static const int kHeaderSize = kGlobalContextOffset + kPointerSize;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(GlobalObject);
friend class AGCCVersionRequiresThisClassToHaveAFriendSoHereItIs;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(GlobalObject);
};
@@ -3406,12 +3399,12 @@
static const int kSize = kFlagOffset + kPointerSize;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(AccessorInfo);
-
// Bit positions in flag.
static const int kAllCanReadBit = 0;
static const int kAllCanWriteBit = 1;
class AttributesField: public BitField<PropertyAttributes, 2, 3> {};
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AccessorInfo);
};
@@ -3561,12 +3554,12 @@
static const int kSize = kFlagOffset + kPointerSize;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(FunctionTemplateInfo);
-
// Bit position in the flag, from least significant bit position.
static const int kHiddenPrototypeBit = 0;
static const int kUndetectableBit = 1;
static const int kNeedsAccessCheckBit = 2;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FunctionTemplateInfo);
};
diff --git a/src/platform.h b/src/platform.h
index e7f1144..c5aea63 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -213,9 +213,9 @@
static double nan_value();
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
-
static const int msPerSecond = 1000;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
};
diff --git a/src/regexp-delay.js b/src/regexp-delay.js
index 4734833..320e65b 100644
--- a/src/regexp-delay.js
+++ b/src/regexp-delay.js
@@ -105,7 +105,7 @@
function RegExpConstructor(pattern, flags) {
- if (%IsConstructCall(this)) {
+ if (%IsConstructCall()) {
DoConstructRegExp(this, pattern, flags, true);
} else {
// RegExp : Called as function; see ECMA-262, section 15.10.3.1.
diff --git a/src/runtime.cc b/src/runtime.cc
index 5f22980..4d53ceb 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -201,17 +201,12 @@
static Object* Runtime_IsConstructCall(Arguments args) {
NoHandleAllocation ha;
+ ASSERT(args.length() == 0);
JavaScriptFrameIterator it;
return Heap::ToBoolean(it.frame()->IsConstructor());
}
-static Object* Runtime_GetBuiltins(Arguments args) {
- NoHandleAllocation ha;
- return Top::context()->builtins();
-}
-
-
static Object* Runtime_RegExpCompile(Arguments args) {
HandleScope scope; // create a new handle scope
ASSERT(args.length() == 3);
@@ -1875,7 +1870,7 @@
// with the exact length. This is implemented using a goto back
// to this label if we discover that the assumption doesn't hold.
// I apologize sincerely for this and will give a vaffel-is to
- // anyone who can implement it in a nicer way.
+ // the first person who can implement it in a nicer way.
try_convert:
// Allocate the resulting string.
@@ -2079,13 +2074,6 @@
}
-static Object* Runtime_NumberAlloc(Arguments args) {
- NoHandleAllocation ha;
- ASSERT(args.length() == 1);
- return Heap::AllocateHeapNumber(0);
-}
-
-
static Object* Runtime_NumberUnaryMinus(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -2539,8 +2527,9 @@
// Returns a number value with positive sign, greater than or equal to
// 0 but less than 1, chosen randomly.
-static Object* Runtime_Math_random(Arguments) {
+static Object* Runtime_Math_random(Arguments args) {
NoHandleAllocation ha;
+ ASSERT(args.length() == 0);
// To get much better precision, we combine the results of two
// invocations of random(). The result is computed by normalizing a
@@ -2704,7 +2693,7 @@
static Object* Runtime_GetCalledFunction(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 0);
StackFrameIterator it;
// Get past the JS-to-C exit frame.
ASSERT(it.frame()->is_exit());
@@ -3177,8 +3166,9 @@
}
-static Object* Runtime_DateCurrentTime(Arguments) {
+static Object* Runtime_DateCurrentTime(Arguments args) {
NoHandleAllocation ha;
+ ASSERT(args.length() == 0);
// According to ECMA-262, section 15.9.1, page 117, the precision of
// the number in a Date object representing a particular instant in
@@ -3217,7 +3207,7 @@
static Object* Runtime_DateLocalTimeOffset(Arguments args) {
NoHandleAllocation ha;
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 0);
return Heap::NumberFromDouble(OS::LocalTimeOffset());
}
@@ -3247,22 +3237,25 @@
}
-static Object* Runtime_NumberMaxValue(Arguments) {
+static Object* Runtime_NumberMaxValue(Arguments args) {
NoHandleAllocation ha;
+ ASSERT(args.length() == 0);
return Heap::number_max_value();
}
-static Object* Runtime_NumberMinValue(Arguments) {
+static Object* Runtime_NumberMinValue(Arguments args) {
NoHandleAllocation ha;
+ ASSERT(args.length() == 0);
return Heap::number_min_value();
}
-static Object* Runtime_NumberNaN(Arguments) {
+static Object* Runtime_NumberNaN(Arguments args) {
NoHandleAllocation ha;
+ ASSERT(args.length() == 0);
return Heap::nan_value();
}
@@ -3550,7 +3543,7 @@
static Object* Runtime_Break(Arguments args) {
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 0);
StackGuard::DebugBreak();
return Heap::undefined_value();
}
@@ -4262,7 +4255,7 @@
// Clear all stepping set by PrepareStep.
static Object* Runtime_ClearStepping(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 0);
Debug::ClearStepping();
return Heap::undefined_value();
}
@@ -4545,7 +4538,7 @@
static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 0);
// Perform two GCs to get rid of all unreferenced scripts. The first GC gets
// rid of all the cached script wrappes and the second gets rid of the
@@ -4773,6 +4766,7 @@
static Object* Runtime_SystemBreak(Arguments args) {
+ ASSERT(args.length() == 0);
CPU::DebugBreak();
return Heap::undefined_value();
}
@@ -4857,7 +4851,7 @@
// ListNatives is ONLY used by the fuzz-natives.js in debug mode
// Exclude the code in release mode.
static Object* Runtime_ListNatives(Arguments args) {
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 0);
HandleScope scope;
Handle<JSArray> result = Factory::NewJSArray(0);
int index = 0;
diff --git a/src/runtime.h b/src/runtime.h
index 0e0ae97..564a36f 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -52,11 +52,10 @@
\
F(IsInPrototypeChain, 2) \
\
- F(IsConstructCall, 1) \
+ F(IsConstructCall, 0) \
\
/* Utilities */ \
- F(GetBuiltins, 1) \
- F(GetCalledFunction, 1) \
+ F(GetCalledFunction, 0) \
F(GetFunctionDelegate, 1) \
F(NewArguments, 1) \
F(LazyCompile, 1) \
@@ -91,7 +90,6 @@
F(NumberMul, 2) \
F(NumberDiv, 2) \
F(NumberMod, 2) \
- F(NumberAlloc, 1) \
F(NumberUnaryMinus, 1) \
\
F(StringAdd, 2) \
@@ -127,7 +125,7 @@
F(Math_floor, 1) \
F(Math_log, 1) \
F(Math_pow, 2) \
- F(Math_random, 1) \
+ F(Math_random, 0) \
F(Math_round, 1) \
F(Math_sin, 1) \
F(Math_sqrt, 1) \
@@ -169,17 +167,17 @@
F(GetTemplateField, 2) \
\
/* Dates */ \
- F(DateCurrentTime, 1) \
+ F(DateCurrentTime, 0) \
F(DateParseString, 1) \
F(DateLocalTimezone, 1) \
- F(DateLocalTimeOffset, 1) \
+ F(DateLocalTimeOffset, 0) \
F(DateDaylightSavingsOffset, 1) \
\
/* Numbers */ \
F(NumberIsFinite, 1) \
- F(NumberMaxValue, 1) \
- F(NumberMinValue, 1) \
- F(NumberNaN, 1) \
+ F(NumberMaxValue, 0) \
+ F(NumberMinValue, 0) \
+ F(NumberNaN, 0) \
\
/* Globals */ \
F(CompileString, 2) \
@@ -205,7 +203,7 @@
/* Debugging */ \
F(AddDebugEventListener, 2) \
F(RemoveDebugEventListener, 1) \
- F(Break, 1) \
+ F(Break, 0) \
F(DebugGetLocalPropertyDetails, 2) \
F(DebugGetProperty, 2) \
F(DebugLocalPropertyNames, 1) \
@@ -228,14 +226,14 @@
F(ClearBreakPoint, 1) \
F(ChangeBreakOnException, 2) \
F(PrepareStep, 3) \
- F(ClearStepping, 1) \
+ F(ClearStepping, 0) \
F(DebugEvaluate, 4) \
F(DebugEvaluateGlobal, 3) \
- F(DebugGetLoadedScripts, 1) \
+ F(DebugGetLoadedScripts, 0) \
F(DebugReferencedBy, 3) \
F(DebugConstructedBy, 2) \
F(GetPrototype, 1) \
- F(SystemBreak, 1) \
+ F(SystemBreak, 0) \
\
/* Literals */ \
F(MaterializeRegExpLiteral, 4)\
@@ -263,7 +261,7 @@
F(DeclareGlobals, 3) \
F(DeclareContextSlot, 5) \
F(InitializeVarGlobal, -1 /* 1 or 2 */) \
- F(InitializeConstGlobal, -1 /* 1 or 2 */) \
+ F(InitializeConstGlobal, 2) \
F(InitializeConstContextSlot, 3) \
\
/* Debugging */ \
@@ -282,7 +280,7 @@
#ifdef DEBUG
#define RUNTIME_FUNCTION_LIST_DEBUG(F) \
/* Testing */ \
- F(ListNatives, 1)
+ F(ListNatives, 0)
#else
#define RUNTIME_FUNCTION_LIST_DEBUG(F)
#endif
diff --git a/src/runtime.js b/src/runtime.js
index e518c5b..37939e7 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -47,7 +47,7 @@
const $Number = global.Number;
const $Function = global.Function;
const $Boolean = global.Boolean;
-const $NaN = %NumberNaN(1);
+const $NaN = %NumberNaN();
// ECMA-262, section 11.9.1, page 55.
@@ -317,7 +317,7 @@
function CALL_NON_FUNCTION() {
- var callee = %GetCalledFunction(0);
+ var callee = %GetCalledFunction();
var delegate = %GetFunctionDelegate(callee);
if (!IS_FUNCTION(delegate)) {
throw %MakeTypeError('called_non_callable', [typeof callee]);
@@ -408,7 +408,7 @@
if (IS_NUMBER(x)) return x;
if (IS_STRING(x)) return %StringToNumber(x);
if (IS_BOOLEAN(x)) return x ? 1 : 0;
- if (IS_UNDEFINED(x)) return %NumberNaN(1);
+ if (IS_UNDEFINED(x)) return %NumberNaN();
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
};
diff --git a/src/serialize.cc b/src/serialize.cc
index 21b7bd5..d1501e0 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -1057,28 +1057,18 @@
writer_->PutInt(size >> kObjectAlignmentBits);
PutEncodedAddress(addr); // encodes AllocationSpace
- // Get the map's encoded address, possibly serializing it on first
- // visit. Note that we do not update obj->map(), since
- // it already contains the forwarding address of 'obj'.
- bool serialized;
- Address map_addr = Encode(map, &serialized);
-
// Visit all the pointers in the object other than the map. This
// will recursively serialize any as-yet-unvisited objects.
- obj->IterateBody(type, size, this);
+ obj->Iterate(this);
// Mark end of recursively embedded objects, start of object body.
writer_->PutC('|');
- // Write out the encoded address for the map.
- PutEncodedAddress(map_addr);
-
- // Write out the raw contents of the object following the map
- // pointer containing the now-updated pointers. No compression, but
+ // Write out the raw contents of the object. No compression, but
// fast to deserialize.
+ writer_->PutBytes(obj->address(), size);
+ // Update pointers and external references in the written object.
ReferenceUpdater updater(obj, this);
- obj->IterateBody(type, size, &updater);
- writer_->PutBytes(obj->address() + HeapObject::kSize,
- size - HeapObject::kSize);
+ obj->Iterate(&updater);
updater.Update(writer_->position() - size);
#ifdef DEBUG
@@ -1177,7 +1167,6 @@
GetHeader();
Heap::IterateRoots(this);
GetContextStack();
- Heap::RebuildRSets();
}
@@ -1364,16 +1353,9 @@
}
ASSERT(c == '|');
- // Read, resolve and set the map pointer: don't rely on map being initialized.
- Address map_addr = GetEncodedAddress();
- Map* map = reinterpret_cast<Map*>(Resolve(map_addr));
HeapObject* obj = reinterpret_cast<HeapObject*>(o);
- obj->set_map(map);
-
// Read the uninterpreted contents of the object after the map
- reader_.GetBytes(obj->address() + HeapObject::kSize,
- size - HeapObject::kSize);
-
+ reader_.GetBytes(obj->address(), size);
#ifdef DEBUG
if (expect_debug_information_) {
// Read in the epilogue to check that we're still synchronized
@@ -1382,7 +1364,9 @@
}
#endif
- // Resolve the encoded pointers we just read in
+ // Resolve the encoded pointers we just read in.
+ // Same as obj->Iterate(this), but doesn't rely on the map pointer being set.
+ VisitPointer(reinterpret_cast<Object**>(obj->address()));
obj->IterateBody(type, size, this);
if (type == CODE_TYPE) {
diff --git a/src/string.js b/src/string.js
index d390411..5902595 100644
--- a/src/string.js
+++ b/src/string.js
@@ -34,7 +34,7 @@
// Set the String function and constructor.
%SetCode($String, function(x) {
var value = %_ArgumentsLength() == 0 ? '' : ToString(x);
- if (%IsConstructCall(this)) {
+ if (%IsConstructCall()) {
%_SetValueOf(this, value);
} else {
return value;
@@ -349,7 +349,7 @@
var pat = ToString(searchString);
var index = (%_ArgumentsLength() > 1)
? ToNumber(%_Arguments(1) /* position */)
- : %NumberNaN(1);
+ : %NumberNaN();
var firstIndex;
if ($isNaN(index)) {
firstIndex = sub.length - pat.length;
diff --git a/src/stub-cache-arm.cc b/src/stub-cache-arm.cc
index b553306..91d9140 100644
--- a/src/stub-cache-arm.cc
+++ b/src/stub-cache-arm.cc
@@ -160,7 +160,8 @@
__ EnterJSFrame(0);
// Push the function on the stack and call the runtime function.
- __ Push(MemOperand(pp, 0));
+ __ ldr(r0, MemOperand(pp, 0));
+ __ push(r0);
__ CallRuntime(Runtime::kLazyCompile, 1);
// Move result to r1 and restore number of arguments.
@@ -181,14 +182,16 @@
JSObject* holder,
int index) {
// ----------- S t a t e -------------
- // -- r0: number of arguments
- // -- r1: receiver
// -- lr: return address
// -----------------------------------
HandleScope scope;
Label miss;
+ const int argc = arguments().immediate();
+
+ // Get the receiver of the function from the stack into r1.
+ __ ldr(r1, MemOperand(sp, argc * kPointerSize));
// Check that the receiver isn't a smi.
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -211,9 +214,11 @@
__ cmp(r2, Operand(JS_FUNCTION_TYPE));
__ b(ne, &miss);
+ // TODO(1233523): remove r0 after changing Jump to InvokeCode
+ // Setup argument length register.
+ __ mov(r0, Operand(argc));
// Patch the function on the stack; 1 ~ receiver.
- __ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
- __ str(r3, MemOperand(ip, 1 * kPointerSize));
+ __ str(r3, MemOperand(sp, (argc + 1) * kPointerSize));
// Setup the context and jump to the call code of the function (tail call).
__ ldr(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
@@ -237,13 +242,16 @@
JSFunction* function,
CheckType check) {
// ----------- S t a t e -------------
- // -- r1: receiver
// -- lr: return address
// -----------------------------------
HandleScope scope;
Label miss;
+ // Get the receiver from the stack
+ const int argc = arguments().immediate();
+ __ ldr(r1, MemOperand(sp, argc * kPointerSize));
+
// Check that the receiver isn't a smi.
if (check != NUMBER_CHECK) {
__ tst(r1, Operand(kSmiTagMask));
@@ -321,9 +329,6 @@
UNREACHABLE();
}
- // Number of arguments for this function.
- const int argc = arguments().immediate();
-
// Get the function and setup the context.
__ mov(r3, Operand(Handle<JSFunction>(function)));
__ ldr(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
@@ -350,8 +355,6 @@
JSObject* holder,
String* name) {
// ----------- S t a t e -------------
- // -- r0: number of arguments
- // -- r1: receiver
// -- lr: return address
// -----------------------------------
@@ -484,9 +487,10 @@
__ push(r2); // name
__ push(r0); // value
- // Do tail-call to the C builtin.
- __ mov(r0, Operand(3)); // not counting receiver
- __ JumpToBuiltin(ExternalReference(IC_Utility(IC::kStoreCallbackProperty)));
+ // Do tail-call to the runtime system.
+ ExternalReference store_callback_property =
+ ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
+ __ TailCallRuntime(store_callback_property, 4);
// Handle store cache miss.
__ bind(&miss);
@@ -537,11 +541,10 @@
__ push(r2); // name
__ push(r0); // value
- // Do tail-call to the C builtin.
- __ mov(r0, Operand(2)); // not counting receiver
- ExternalReference store_interceptor =
+ // Do tail-call to the runtime system.
+ ExternalReference store_ic_property =
ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
- __ JumpToBuiltin(store_interceptor);
+ __ TailCallRuntime(store_ic_property, 3);
// Handle store cache miss.
__ bind(&miss);
@@ -558,7 +561,6 @@
JSObject* holder,
int index) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -567,6 +569,8 @@
HandleScope scope;
Label miss;
+ __ ldr(r0, MemOperand(sp, 0));
+
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -597,7 +601,6 @@
JSObject* holder,
AccessorInfo* callback) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -606,6 +609,7 @@
HandleScope scope;
Label miss;
+ __ ldr(r0, MemOperand(sp, 0));
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -620,9 +624,10 @@
__ push(r2); // name
__ push(reg); // holder
- // Do tail-call to the C builtin.
- __ mov(r0, Operand(3)); // not counting receiver
- __ JumpToBuiltin(ExternalReference(IC_Utility(IC::kLoadCallbackProperty)));
+ // Do tail-call to the runtime system.
+ ExternalReference load_callback_property =
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+ __ TailCallRuntime(load_callback_property, 4);
// Handle load cache miss.
__ bind(&miss);
@@ -638,7 +643,6 @@
JSObject* holder,
Object* value) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -647,6 +651,7 @@
HandleScope scope;
Label miss;
+ __ ldr(r0, MemOperand(sp, 0));
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -672,7 +677,6 @@
JSObject* holder,
String* name) {
// ----------- S t a t e -------------
- // -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
@@ -681,6 +685,7 @@
HandleScope scope;
Label miss;
+ __ ldr(r0, MemOperand(sp, 0));
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -693,9 +698,10 @@
__ push(reg); // holder
__ push(r2); // name
- // Do tail-call to the C builtin.
- __ mov(r0, Operand(2)); // not counting receiver
- __ JumpToBuiltin(ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)));
+ // Do tail-call to the runtime system.
+ ExternalReference load_ic_property =
+ ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+ __ TailCallRuntime(load_ic_property, 3);
// Handle load cache miss.
__ bind(&miss);
diff --git a/src/stub-cache-ia32.cc b/src/stub-cache-ia32.cc
index a0ef7d8..4c84160 100644
--- a/src/stub-cache-ia32.cc
+++ b/src/stub-cache-ia32.cc
@@ -332,9 +332,10 @@
__ push(reg); // holder
__ push(scratch2); // restore return address
- // Do tail-call to the C builtin.
- __ mov(eax, 3); // not counting receiver
- __ JumpToBuiltin(ExternalReference(IC_Utility(IC::kLoadCallbackProperty)));
+ // Do tail-call to the runtime system.
+ ExternalReference load_callback_property =
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+ __ TailCallRuntime(load_callback_property, 4);
}
@@ -383,9 +384,10 @@
__ push(name); // name
__ push(scratch2); // restore return address
- // Do tail-call to the C builtin.
- __ mov(eax, 2); // not counting receiver
- __ JumpToBuiltin(ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)));
+ // Do tail-call to the runtime system.
+ ExternalReference load_ic_property =
+ ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+ __ TailCallRuntime(load_ic_property, 3);
}
@@ -672,9 +674,9 @@
__ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
// Perform call.
- __ mov(Operand(eax), Immediate(2)); // 2 arguments w/o receiver
ExternalReference load_interceptor =
ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+ __ mov(Operand(eax), Immediate(3));
__ mov(Operand(ebx), Immediate(load_interceptor));
CEntryStub stub;
@@ -780,9 +782,10 @@
__ push(eax); // value
__ push(ebx); // restore return address
- // Do tail-call to the C builtin.
- __ mov(eax, 3); // not counting receiver
- __ JumpToBuiltin(ExternalReference(IC_Utility(IC::kStoreCallbackProperty)));
+ // Do tail-call to the runtime system.
+ ExternalReference store_callback_property =
+ ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
+ __ TailCallRuntime(store_callback_property, 4);
// Handle store cache miss.
__ bind(&miss);
@@ -834,11 +837,10 @@
__ push(eax); // value
__ push(ebx); // restore return address
- // Do tail-call to the C builtin.
- __ mov(eax, 2); // not counting receiver
- ExternalReference store_interceptor =
+ // Do tail-call to the runtime system.
+ ExternalReference store_ic_property =
ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
- __ JumpToBuiltin(store_interceptor);
+ __ TailCallRuntime(store_ic_property, 3);
// Handle store cache miss.
__ bind(&miss);
diff --git a/src/utils.h b/src/utils.h
index f9bf028..e7d5633 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -412,13 +412,13 @@
char* Finalize();
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
-
char* buffer_;
int size_;
int position_;
bool is_finalized() const { return position_ < 0; }
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
};
} } // namespace v8::internal
diff --git a/src/v8.h b/src/v8.h
index c56f5b7..8cacc69 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -32,10 +32,14 @@
#ifndef V8_V8_H_
#define V8_V8_H_
-// Google3 uses NDEBUG.
-#if defined(GOOGLE3) && !defined(NDEBUG)
-#define DEBUG
+#if defined(GOOGLE3)
+// Google3 special flag handling.
+#if defined(DEBUG) && defined(NDEBUG)
+// If both are defined in Google3, then we are building an optimized v8 with
+// assertions enabled.
+#undef NDEBUG
#endif
+#endif // defined(GOOGLE3)
// V8 only uses DEBUG, but included external files
// may use NDEBUG - make sure they are consistent.
diff --git a/src/v8natives.js b/src/v8natives.js
index 6f1519b..3755f74 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -33,7 +33,7 @@
// const $Number = global.Number;
// const $Function = global.Function;
// const $Array = global.Array;
-// const $NaN = %NumberNaN(1);
+// const $NaN = %NumberNaN();
// ECMA 262 - 15.1.1.1.
@@ -99,7 +99,7 @@
%SetCode($Boolean, function(x) {
- if (%IsConstructCall(this)) {
+ if (%IsConstructCall()) {
%_SetValueOf(this, ToBoolean(x));
} else {
return ToBoolean(x);
@@ -185,7 +185,7 @@
%SetCode($Object, function(x) {
- if (%IsConstructCall(this)) {
+ if (%IsConstructCall()) {
if (x == null) return this;
return ToObject(x);
} else {
@@ -245,7 +245,7 @@
// Set the Number function and constructor.
%SetCode($Number, function(x) {
var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
- if (%IsConstructCall(this)) {
+ if (%IsConstructCall()) {
%_SetValueOf(this, value);
} else {
return value;
@@ -257,10 +257,10 @@
%AddProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
// ECMA-262 section 15.7.3.1.
-%AddProperty($Number, "MAX_VALUE", %NumberMaxValue(1), DONT_ENUM | DONT_DELETE | READ_ONLY);
+%AddProperty($Number, "MAX_VALUE", %NumberMaxValue(), DONT_ENUM | DONT_DELETE | READ_ONLY);
// ECMA-262 section 15.7.3.2.
-%AddProperty($Number, "MIN_VALUE", %NumberMinValue(1), DONT_ENUM | DONT_DELETE | READ_ONLY);
+%AddProperty($Number, "MIN_VALUE", %NumberMinValue(), DONT_ENUM | DONT_DELETE | READ_ONLY);
// ECMA-262 section 15.7.3.3.
%AddProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);