Reduced code size by using shorter instruction encoding when possible.
Added a --help option to the shell sample and to the d8 shell.
Added visual studio project files for building the ARM simulator.
Fixed a number of ARM simulator issues.
Fixed bug in out-of-memory handling on ARM.
Implemented shell support for passing arguments to a script from the command line.
Fixed bug in date code that made certain date functions return -0 instead of 0 for dates before the epoch.
Restricted applications of eval so it can only be used in the context of the associated global object.
Treat byte-order marks as whitespace characters.
git-svn-id: http://v8.googlecode.com/svn/trunk@768 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 1b8bdc4..e44ae59 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2008-11-17: Version 0.4.4
+
+ Reduced code size by using shorter instruction encoding when
+ possible.
+
+ Added a --help option to the shell sample and to the d8 shell.
+
+ Added visual studio project files for building the ARM simulator.
+
+ Fixed a number of ARM simulator issues.
+
+ Fixed bug in out-of-memory handling on ARM.
+
+ Implemented shell support for passing arguments to a script from
+ the command line.
+
+ Fixed bug in date code that made certain date functions return -0
+ instead of 0 for dates before the epoch.
+
+ Restricted applications of eval so it can only be used in the
+ context of the associated global object.
+
+ Treat byte-order marks as whitespace characters.
+
+
2008-11-04: Version 0.4.3
Added support for API accessors that prohibit overwriting by
diff --git a/SConstruct b/SConstruct
index c1a6ec2..9dd9268 100644
--- a/SConstruct
+++ b/SConstruct
@@ -106,7 +106,10 @@
'CPPDEFINES': ['BUILDING_V8_SHARED']
},
'arch:arm': {
- 'CPPDEFINES': ['ARM']
+ 'CPPDEFINES': ['ARM'],
+ # /wd4996 is to silence the warning about sscanf
+ # used by the arm simulator.
+ 'WARNINGFLAGS': ['/wd4996']
},
'disassembler:on': {
'CPPDEFINES': ['ENABLE_DISASSEMBLER']
diff --git a/include/v8-debug.h b/include/v8-debug.h
index f537d7d..c12c086 100644
--- a/include/v8-debug.h
+++ b/include/v8-debug.h
@@ -82,8 +82,8 @@
/**
* Debug event callback function.
*
- * \param event the debug event from which occoured (from the DebugEvent
- * enumeration)
+ * \param event the type of the debug event that triggered the callback
+ * (enum DebugEvent)
* \param exec_state execution state (JavaScript object)
* \param event_data event specific data (JavaScript object)
* \param data value passed by the user to AddDebugEventListener
@@ -122,9 +122,6 @@
// Remove a JavaScript debug event listener.
static void RemoveDebugEventListener(v8::Handle<v8::Function> that);
- // Generate a stack dump.
- static void StackDump();
-
// Break execution of JavaScript.
static void DebugBreak();
diff --git a/include/v8.h b/include/v8.h
index ec51ce6..c99dc5a 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -2052,6 +2052,7 @@
void* message_;
bool is_verbose_;
bool capture_message_;
+ void* js_handler_;
};
diff --git a/samples/shell.cc b/samples/shell.cc
index 0209410..39236a9 100644
--- a/samples/shell.cc
+++ b/samples/shell.cc
@@ -72,7 +72,7 @@
// alone JavaScript engines.
continue;
} else if (strncmp(str, "--", 2) == 0) {
- printf("Warning: unknown flag %s.\n", str);
+ printf("Warning: unknown flag %s.\nTry --help for options\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
// Execute argument given to -e option directly
v8::HandleScope handle_scope;
diff --git a/src/api.cc b/src/api.cc
index ba204ce..9fd5fb3 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1081,7 +1081,8 @@
exception_(i::Heap::the_hole_value()),
message_(i::Smi::FromInt(0)),
is_verbose_(false),
- capture_message_(true) {
+ capture_message_(true),
+ js_handler_(NULL) {
i::Top::RegisterTryCatchHandler(this);
}
@@ -2202,7 +2203,7 @@
const char* v8::V8::GetVersion() {
- return "0.4.3.1";
+ return "0.4.4";
}
diff --git a/src/assembler-ia32.cc b/src/assembler-ia32.cc
index fbe63de..264ef42 100644
--- a/src/assembler-ia32.cc
+++ b/src/assembler-ia32.cc
@@ -597,6 +597,14 @@
}
+void Assembler::mov(Register dst, const Immediate& x) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0xB8 | dst.code());
+ emit(x);
+}
+
+
void Assembler::mov(Register dst, Handle<Object> handle) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
@@ -613,6 +621,14 @@
}
+void Assembler::mov(Register dst, Register src) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0x89);
+ EMIT(0xC0 | src.code() << 3 | dst.code());
+}
+
+
void Assembler::mov(const Operand& dst, const Immediate& x) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
@@ -781,7 +797,7 @@
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x21);
- emit_operand(dst, src);
+ emit_operand(src, dst);
}
@@ -949,7 +965,7 @@
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x09);
- emit_operand(dst, src);
+ emit_operand(src, dst);
}
@@ -1077,7 +1093,7 @@
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x29);
- emit_operand(dst, src);
+ emit_operand(src, dst);
}
@@ -2017,18 +2033,6 @@
}
-void Assembler::emit_operand(const Operand& adr, Register reg) {
- adr.set_reg(reg);
- memmove(pc_, adr.buf_, adr.len_);
- pc_ += adr.len_;
- if (adr.len_ >= sizeof(int32_t) && adr.rmode_ != RelocInfo::NONE) {
- pc_ -= sizeof(int32_t); // pc_ must be *at* disp32
- RecordRelocInfo(adr.rmode_);
- pc_ += sizeof(int32_t);
- }
-}
-
-
void Assembler::emit_farith(int b1, int b2, int i) {
ASSERT(is_uint8(b1) && is_uint8(b2)); // wrong opcode
ASSERT(0 <= i && i < 8); // illegal stack offset
diff --git a/src/assembler-ia32.h b/src/assembler-ia32.h
index 8413104..9647446 100644
--- a/src/assembler-ia32.h
+++ b/src/assembler-ia32.h
@@ -453,8 +453,10 @@
void mov_w(const Operand& dst, Register src);
void mov(Register dst, int32_t imm32);
+ void mov(Register dst, const Immediate& x);
void mov(Register dst, Handle<Object> handle);
void mov(Register dst, const Operand& src);
+ void mov(Register dst, Register src);
void mov(const Operand& dst, const Immediate& x);
void mov(const Operand& dst, Handle<Object> handle);
void mov(const Operand& dst, Register src);
@@ -757,7 +759,6 @@
void emit_arith(int sel, Operand dst, const Immediate& x);
void emit_operand(Register reg, const Operand& adr);
- void emit_operand(const Operand& adr, Register reg);
void emit_farith(int b1, int b2, int i);
diff --git a/src/ast.h b/src/ast.h
index 4344535..b383f76 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1125,6 +1125,7 @@
start_position_(start_position),
end_position_(end_position),
is_expression_(is_expression),
+ loop_nesting_(0),
function_token_position_(RelocInfo::kNoPosition) {
}
@@ -1149,6 +1150,9 @@
bool AllowsLazyCompilation();
+ bool loop_nesting() const { return loop_nesting_; }
+ void set_loop_nesting(int nesting) { loop_nesting_ = nesting; }
+
private:
Handle<String> name_;
Scope* scope_;
@@ -1160,6 +1164,7 @@
int start_position_;
int end_position_;
bool is_expression_;
+ int loop_nesting_;
int function_token_position_;
};
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index d08baa1..ce25d00 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -205,11 +205,20 @@
Code* code = Code::cast(code_[i]);
Address pc = code->instruction_start() + pc_[i];
bool is_pc_relative = Bootstrapper::FixupFlagsIsPCRelative::decode(flags);
- if (is_pc_relative) {
- Assembler::set_target_address_at(pc, f->code()->instruction_start());
+ bool use_code_object = Bootstrapper::FixupFlagsUseCodeObject::decode(flags);
+
+ if (use_code_object) {
+ if (is_pc_relative) {
+ Assembler::set_target_address_at(
+ pc, reinterpret_cast<Address>(f->code()));
+ } else {
+ *reinterpret_cast<Object**>(pc) = f->code();
+ }
} else {
- *reinterpret_cast<Object**>(pc) = f->code();
+ ASSERT(is_pc_relative);
+ Assembler::set_target_address_at(pc, f->code()->instruction_start());
}
+
LOG(StringEvent("resolved", name));
}
Clear();
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index 0b0784e..908217d 100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -66,7 +66,8 @@
// Encoding/decoding support for fixup flags.
class FixupFlagsIsPCRelative: public BitField<bool, 0, 1> {};
- class FixupFlagsArgumentsCount: public BitField<uint32_t, 1, 32-1> {};
+ class FixupFlagsUseCodeObject: public BitField<bool, 1, 1> {};
+ class FixupFlagsArgumentsCount: public BitField<uint32_t, 2, 32-2> {};
};
}} // namespace v8::internal
diff --git a/src/builtins-ia32.cc b/src/builtins-ia32.cc
index 0de381c..55e10f3 100644
--- a/src/builtins-ia32.cc
+++ b/src/builtins-ia32.cc
@@ -129,7 +129,7 @@
// ebx: JSObject
// edi: start of next object
__ mov(Operand(ebx, JSObject::kMapOffset), eax);
- __ mov(Operand(ecx), Factory::empty_fixed_array());
+ __ mov(ecx, Factory::empty_fixed_array());
__ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
__ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
// Set extra fields in the newly allocated object.
@@ -137,7 +137,7 @@
// ebx: JSObject
// edi: start of next object
{ Label loop, entry;
- __ mov(Operand(edx), Factory::undefined_value());
+ __ mov(edx, Factory::undefined_value());
__ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
__ jmp(&entry);
__ bind(&loop);
@@ -198,7 +198,7 @@
// edi: FixedArray
// ecx: start of next object
{ Label loop, entry;
- __ mov(Operand(edx), Factory::undefined_value());
+ __ mov(edx, Factory::undefined_value());
__ lea(eax, Operand(edi, FixedArray::kHeaderSize));
__ jmp(&entry);
__ bind(&loop);
@@ -440,7 +440,7 @@
__ push(edi); // save edi across the call
__ push(ebx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
- __ mov(Operand(ebx), eax);
+ __ mov(ebx, eax);
__ pop(edi); // restore edi after the call
// Get the arguments count and untag it.
@@ -657,7 +657,7 @@
// arguments and the receiver.
ASSERT(kSmiTagSize == 1);
__ lea(ecx, Operand(eax, eax, times_1, kSmiTag));
- __ push(Operand(ecx));
+ __ push(ecx);
}
@@ -778,7 +778,7 @@
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ Set(eax, Immediate(0)); // no arguments
- __ mov(Operand(ebx), Immediate(ExternalReference::debug_break()));
+ __ mov(ebx, Immediate(ExternalReference::debug_break()));
CEntryDebugBreakStub ceb;
__ CallStub(&ceb);
diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc
index 4c2f465..e5120ae 100644
--- a/src/codegen-arm.cc
+++ b/src/codegen-arm.cc
@@ -35,6 +35,84 @@
namespace v8 { namespace internal {
+#define __ masm_->
+
+// -------------------------------------------------------------------------
+// VirtualFrame implementation.
+
+VirtualFrame::VirtualFrame(CodeGenerator* cgen) {
+ ASSERT(cgen->scope() != NULL);
+
+ masm_ = cgen->masm();
+ frame_local_count_ = cgen->scope()->num_stack_slots();
+ parameter_count_ = cgen->scope()->num_parameters();
+}
+
+
+void VirtualFrame::Enter() {
+ Comment cmnt(masm_, "[ Enter JS frame");
+#ifdef DEBUG
+ { Label done, fail;
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(eq, &fail);
+ __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+ __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+ __ cmp(r2, Operand(JS_FUNCTION_TYPE));
+ __ b(eq, &done);
+ __ bind(&fail);
+ __ stop("CodeGenerator::EnterJSFrame - r1 not a function");
+ __ bind(&done);
+ }
+#endif // DEBUG
+
+ __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+ // Adjust FP to point to saved FP.
+ __ add(fp, sp, Operand(2 * kPointerSize));
+}
+
+
+void VirtualFrame::Exit() {
+ Comment cmnt(masm_, "[ Exit JS frame");
+ // Drop the execution stack down to the frame pointer and restore the caller
+ // frame pointer and return address.
+ __ mov(sp, fp);
+ __ ldm(ia_w, sp, fp.bit() | lr.bit());
+}
+
+
+void VirtualFrame::AllocateLocals() {
+ if (frame_local_count_ > 0) {
+ Comment cmnt(masm_, "[ Allocate space for locals");
+ // Initialize stack slots with 'undefined' value.
+ __ mov(ip, Operand(Factory::undefined_value()));
+ for (int i = 0; i < frame_local_count_; i++) {
+ __ push(ip);
+ }
+ }
+}
+
+
+void VirtualFrame::Drop(int count) {
+ ASSERT(count >= 0);
+ if (count > 0) {
+ __ add(sp, sp, Operand(count * kPointerSize));
+ }
+}
+
+
+void VirtualFrame::Pop() { Drop(1); }
+
+
+void VirtualFrame::Pop(Register reg) {
+ __ pop(reg);
+}
+
+
+void VirtualFrame::Push(Register reg) {
+ __ push(reg);
+}
+
+
// -------------------------------------------------------------------------
// CodeGenState implementation.
@@ -67,11 +145,9 @@
}
-// -----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
// CodeGenerator implementation
-#define __ masm_->
-
CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
bool is_eval)
: is_eval_(is_eval),
@@ -79,6 +155,7 @@
deferred_(8),
masm_(new MacroAssembler(NULL, buffer_size)),
scope_(NULL),
+ frame_(NULL),
cc_reg_(al),
state_(NULL),
break_stack_height_(0) {
@@ -86,7 +163,6 @@
// Calling conventions:
-
// r0: the number of arguments
// fp: frame pointer
// sp: stack pointer
@@ -94,13 +170,17 @@
// cp: callee's context
void CodeGenerator::GenCode(FunctionLiteral* fun) {
- Scope* scope = fun->scope();
ZoneList<Statement*>* body = fun->body();
// Initialize state.
- { CodeGenState state(this);
- scope_ = scope;
- cc_reg_ = al;
+ ASSERT(scope_ == NULL);
+ scope_ = fun->scope();
+ ASSERT(frame_ == NULL);
+ VirtualFrame virtual_frame(this);
+ frame_ = &virtual_frame;
+ cc_reg_ = al;
+ {
+ CodeGenState state(this);
// Entry
// stack: function, receiver, arguments, return address
@@ -110,9 +190,7 @@
// pp: caller's parameter pointer
// cp: callee's context
- { Comment cmnt(masm_, "[ enter JS frame");
- EnterJSFrame();
- }
+ frame_->Enter();
// tos: code slot
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
@@ -122,20 +200,13 @@
#endif
// Allocate space for locals and initialize them.
- if (scope->num_stack_slots() > 0) {
- Comment cmnt(masm_, "[ allocate space for locals");
- // Initialize stack slots with 'undefined' value.
- __ mov(ip, Operand(Factory::undefined_value()));
- for (int i = 0; i < scope->num_stack_slots(); i++) {
- __ push(ip);
- }
- }
+ frame_->AllocateLocals();
- if (scope->num_heap_slots() > 0) {
+ if (scope_->num_heap_slots() > 0) {
// Allocate local context.
// Get outer context and create a new context based on it.
- __ ldr(r0, FunctionOperand());
- __ push(r0);
+ __ ldr(r0, frame_->Function());
+ frame_->Push(r0);
__ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result
if (kDebug) {
@@ -146,10 +217,10 @@
__ bind(&verified_true);
}
// Update context local.
- __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ str(cp, frame_->Context());
}
- // TODO(1241774): Improve this code!!!
+ // TODO(1241774): Improve this code:
// 1) only needed if we have a context
// 2) no need to recompute context ptr every single time
// 3) don't copy parameter operand code from SlotOperand!
@@ -164,12 +235,12 @@
// order: such a parameter is copied repeatedly into the same
// context location and thus the last value is what is seen inside
// the function.
- for (int i = 0; i < scope->num_parameters(); i++) {
- Variable* par = scope->parameter(i);
+ for (int i = 0; i < scope_->num_parameters(); i++) {
+ Variable* par = scope_->parameter(i);
Slot* slot = par->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
- ASSERT(!scope->is_global_scope()); // no parameters in global scope
- __ ldr(r1, ParameterOperand(i));
+ ASSERT(!scope_->is_global_scope()); // no parameters in global scope
+ __ ldr(r1, frame_->Parameter(i));
// Loads r2 with context; used below in RecordWrite.
__ str(r1, SlotOperand(slot, r2));
// Load the offset into r3.
@@ -181,59 +252,55 @@
}
}
- // Store the arguments object.
- // This must happen after context initialization because
- // the arguments array may be stored in the context!
- if (scope->arguments() != NULL) {
- ASSERT(scope->arguments_shadow() != NULL);
+ // Store the arguments object. This must happen after context
+ // initialization because the arguments object may be stored in the
+ // context.
+ if (scope_->arguments() != NULL) {
+ ASSERT(scope_->arguments_shadow() != NULL);
Comment cmnt(masm_, "[ allocate arguments object");
- { Reference shadow_ref(this, scope->arguments_shadow());
- { Reference arguments_ref(this, scope->arguments());
+ { Reference shadow_ref(this, scope_->arguments_shadow());
+ { Reference arguments_ref(this, scope_->arguments());
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
- __ ldr(r2, FunctionOperand());
+ __ ldr(r2, frame_->Function());
// The receiver is below the arguments, the return address,
// and the frame pointer on the stack.
- const int kReceiverDisplacement = 2 + scope->num_parameters();
+ const int kReceiverDisplacement = 2 + scope_->num_parameters();
__ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
- __ mov(r0, Operand(Smi::FromInt(scope->num_parameters())));
+ __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
__ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
__ CallStub(&stub);
- __ push(r0);
+ frame_->Push(r0);
arguments_ref.SetValue(NOT_CONST_INIT);
}
shadow_ref.SetValue(NOT_CONST_INIT);
}
- __ pop(r0); // Value is no longer needed.
+ frame_->Pop(); // Value is no longer needed.
}
- // Generate code to 'execute' declarations and initialize
- // functions (source elements). In case of an illegal
- // redeclaration we need to handle that instead of processing the
- // declarations.
- if (scope->HasIllegalRedeclaration()) {
+ // Generate code to 'execute' declarations and initialize functions
+ // (source elements). In case of an illegal redeclaration we need to
+ // handle that instead of processing the declarations.
+ if (scope_->HasIllegalRedeclaration()) {
Comment cmnt(masm_, "[ illegal redeclarations");
- scope->VisitIllegalRedeclaration(this);
+ scope_->VisitIllegalRedeclaration(this);
} else {
Comment cmnt(masm_, "[ declarations");
- // ProcessDeclarations calls DeclareGlobals indirectly
- ProcessDeclarations(scope->declarations());
-
- // Bail out if a stack-overflow exception occurred when
- // processing declarations.
+ ProcessDeclarations(scope_->declarations());
+ // Bail out if a stack-overflow exception occurred when processing
+ // declarations.
if (HasStackOverflow()) return;
}
if (FLAG_trace) {
- // Push a valid value as the parameter. The runtime call only uses
- // it as the return value to indicate non-failure.
__ CallRuntime(Runtime::kTraceEnter, 0);
+ // Ignore the return value.
}
CheckStack();
// Compile the body of the function in a vanilla state. Don't
// bother compiling all the code if the scope has an illegal
// redeclaration.
- if (!scope->HasIllegalRedeclaration()) {
+ if (!scope_->HasIllegalRedeclaration()) {
Comment cmnt(masm_, "[ function body");
#ifdef DEBUG
bool is_builtin = Bootstrapper::IsActive();
@@ -241,6 +308,7 @@
is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
if (should_trace) {
__ CallRuntime(Runtime::kDebugTrace, 0);
+ // Ignore the return value.
}
#endif
VisitStatements(body);
@@ -259,19 +327,20 @@
if (FLAG_trace) {
// Push the return value on the stack as the parameter.
// Runtime::TraceExit returns the parameter as it is.
- __ push(r0);
+ frame_->Push(r0);
__ CallRuntime(Runtime::kTraceExit, 1);
}
// Tear down the frame which will restore the caller's frame pointer and the
// link register.
- ExitJSFrame();
+ frame_->Exit();
__ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
__ mov(pc, lr);
// Code generation state must be reset.
scope_ = NULL;
+ frame_ = NULL;
ASSERT(!has_cc());
ASSERT(state_ == NULL);
}
@@ -290,13 +359,10 @@
int index = slot->index();
switch (slot->type()) {
case Slot::PARAMETER:
- return ParameterOperand(index);
+ return frame_->Parameter(index);
- case Slot::LOCAL: {
- ASSERT(0 <= index && index < scope()->num_stack_slots());
- const int kLocalOffset = JavaScriptFrameConstants::kLocal0Offset;
- return MemOperand(fp, kLocalOffset - index * kPointerSize);
- }
+ case Slot::LOCAL:
+ return frame_->Local(index);
case Slot::CONTEXT: {
// Follow the context chain if necessary.
@@ -331,16 +397,17 @@
}
-// 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'.
+// 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, has_cc() is true and cc_reg_ contains the condition to
+// test for 'true'.
void CodeGenerator::LoadCondition(Expression* x,
- TypeofState typeof_state,
- Label* true_target,
- Label* false_target,
- bool force_cc) {
+ TypeofState typeof_state,
+ Label* true_target,
+ Label* false_target,
+ bool force_cc) {
ASSERT(!has_cc());
{ CodeGenState new_state(this, typeof_state, true_target, false_target);
@@ -348,6 +415,13 @@
}
if (force_cc && !has_cc()) {
// Convert the TOS value to a boolean in the condition code register.
+ // Visiting an expression may possibly choose neither (a) to leave a
+ // value in the condition code register nor (b) to leave a value in TOS
+ // (eg, by compiling to only jumps to the targets). In that case the
+ // code generated by ToBoolean is wrong because it assumes the value of
+ // the expression in TOS. So long as there is always a value in TOS or
+ // the condition code register when control falls through to here (there
+ // is), the code generated by ToBoolean is dead and therefore safe.
ToBoolean(true_target, false_target);
}
ASSERT(has_cc() || !force_cc);
@@ -364,11 +438,11 @@
Label loaded, materialize_true;
__ b(cc_reg_, &materialize_true);
__ mov(r0, Operand(Factory::false_value()));
- __ push(r0);
+ frame_->Push(r0);
__ b(&loaded);
__ bind(&materialize_true);
__ mov(r0, Operand(Factory::true_value()));
- __ push(r0);
+ frame_->Push(r0);
__ bind(&loaded);
cc_reg_ = al;
}
@@ -384,7 +458,7 @@
if (true_target.is_linked()) {
__ bind(&true_target);
__ mov(r0, Operand(Factory::true_value()));
- __ push(r0);
+ frame_->Push(r0);
}
// if both "true" and "false" need to be reincarnated,
// jump across code for "false"
@@ -394,7 +468,7 @@
if (false_target.is_linked()) {
__ bind(&false_target);
__ mov(r0, Operand(Factory::false_value()));
- __ push(r0);
+ frame_->Push(r0);
}
// everything is loaded at this point
__ bind(&loaded);
@@ -405,14 +479,15 @@
void CodeGenerator::LoadGlobal() {
__ ldr(r0, GlobalObject());
- __ push(r0);
+ frame_->Push(r0);
}
-void CodeGenerator::LoadGlobalReceiver(Register s) {
- __ ldr(s, ContextOperand(cp, Context::GLOBAL_INDEX));
- __ ldr(s, FieldMemOperand(s, GlobalObject::kGlobalReceiverOffset));
- __ push(s);
+void CodeGenerator::LoadGlobalReceiver(Register scratch) {
+ __ ldr(scratch, ContextOperand(cp, Context::GLOBAL_INDEX));
+ __ ldr(scratch,
+ FieldMemOperand(scratch, GlobalObject::kGlobalReceiverOffset));
+ frame_->Push(scratch);
}
@@ -450,7 +525,6 @@
void CodeGenerator::LoadReference(Reference* ref) {
Comment cmnt(masm_, "[ LoadReference");
-
Expression* e = ref->expression();
Property* property = e->AsProperty();
Variable* var = e->AsVariableProxy()->AsVariable();
@@ -492,15 +566,13 @@
void CodeGenerator::UnloadReference(Reference* ref) {
+ // Pop a reference from the stack while preserving TOS.
Comment cmnt(masm_, "[ UnloadReference");
-
int size = ref->size();
- if (size <= 0) {
- // Do nothing. No popping is necessary.
- } else {
- __ pop(r0);
- __ add(sp, sp, Operand(size * kPointerSize));
- __ push(r0);
+ if (size > 0) {
+ frame_->Pop(r0);
+ frame_->Drop(size);
+ frame_->Push(r0);
}
}
@@ -509,10 +581,10 @@
// register to a boolean in the condition code register. The code
// may jump to 'false_target' in case the register converts to 'false'.
void CodeGenerator::ToBoolean(Label* true_target,
- Label* false_target) {
+ Label* false_target) {
// Note: The generated code snippet does not change stack variables.
// Only the condition code should be set.
- __ pop(r0);
+ frame_->Pop(r0);
// Fast case checks
@@ -535,10 +607,9 @@
__ b(eq, true_target);
// Slow case: call the runtime.
- __ push(r0);
+ frame_->Push(r0);
__ CallRuntime(Runtime::kToBool, 1);
-
- // Convert result (r0) to condition code
+ // Convert the result (r0) to a condition code.
__ cmp(r0, Operand(Factory::false_value()));
cc_reg_ = ne;
@@ -639,8 +710,8 @@
case Token::SHL:
case Token::SHR:
case Token::SAR: {
- __ pop(r0); // r0 : y
- __ pop(r1); // r1 : x
+ frame_->Pop(r0); // r0 : y
+ frame_->Pop(r1); // r1 : x
GenericBinaryOpStub stub(op);
__ CallStub(&stub);
break;
@@ -659,9 +730,9 @@
}
case Token::COMMA:
- __ pop(r0);
+ frame_->Pop(r0);
// simply discard left value
- __ pop();
+ frame_->Pop();
break;
default:
@@ -749,8 +820,8 @@
void CodeGenerator::SmiOperation(Token::Value op,
- Handle<Object> value,
- bool reversed) {
+ Handle<Object> value,
+ bool reversed) {
// NOTE: This is an attempt to inline (a bit) more of the code for
// some possible smi operations (like + and -) when (at least) one
// of the operands is a literal smi. With this optimization, the
@@ -763,7 +834,7 @@
int int_value = Smi::cast(*value)->value();
Label exit;
- __ pop(r0);
+ frame_->Pop(r0);
switch (op) {
case Token::ADD: {
@@ -816,8 +887,8 @@
case Token::SAR: {
if (reversed) {
__ mov(ip, Operand(value));
- __ push(ip);
- __ push(r0);
+ frame_->Push(ip);
+ frame_->Push(r0);
GenericBinaryOperation(op);
} else {
@@ -867,13 +938,13 @@
default:
if (!reversed) {
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(value));
- __ push(r0);
+ frame_->Push(r0);
} else {
__ mov(ip, Operand(value));
- __ push(ip);
- __ push(r0);
+ frame_->Push(ip);
+ frame_->Push(r0);
}
GenericBinaryOperation(op);
break;
@@ -895,18 +966,18 @@
// Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
if (cc == gt || cc == le) {
cc = ReverseCondition(cc);
- __ pop(r1);
- __ pop(r0);
+ frame_->Pop(r1);
+ frame_->Pop(r0);
} else {
- __ pop(r0);
- __ pop(r1);
+ frame_->Pop(r0);
+ frame_->Pop(r1);
}
__ orr(r2, r0, Operand(r1));
__ tst(r2, Operand(kSmiTagMask));
__ b(eq, &smi);
// Perform non-smi comparison by runtime call.
- __ push(r1);
+ frame_->Push(r1);
// Figure out which native to call and setup the arguments.
Builtins::JavaScript native;
@@ -923,14 +994,14 @@
ASSERT(cc == gt || cc == ge); // remaining cases
ncr = LESS;
}
- __ push(r0);
+ frame_->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(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(argc));
__ InvokeBuiltin(native, CALL_JS);
__ cmp(r0, Operand(0));
@@ -979,8 +1050,8 @@
__ CallStub(&call_function);
// Restore context and pop function from the stack.
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- __ pop(); // discard the TOS
+ __ ldr(cp, frame_->Context());
+ frame_->Pop(); // discard the TOS
}
@@ -1012,10 +1083,10 @@
void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
__ mov(r0, Operand(pairs));
- __ push(r0);
- __ push(cp);
+ frame_->Push(r0);
+ frame_->Push(cp);
__ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
- __ push(r0);
+ frame_->Push(r0);
__ CallRuntime(Runtime::kDeclareGlobals, 3);
// The result is discarded.
}
@@ -1035,26 +1106,26 @@
// during variable resolution and must have mode DYNAMIC.
ASSERT(var->mode() == Variable::DYNAMIC);
// For now, just do a runtime call.
- __ push(cp);
+ frame_->Push(cp);
__ mov(r0, Operand(var->name()));
- __ push(r0);
+ frame_->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;
__ mov(r0, Operand(Smi::FromInt(attr)));
- __ push(r0);
+ frame_->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) {
__ mov(r0, Operand(Factory::the_hole_value()));
- __ push(r0);
+ frame_->Push(r0);
} else if (node->fun() != NULL) {
Load(node->fun());
} else {
__ mov(r0, Operand(0)); // no initial value!
- __ push(r0);
+ frame_->Push(r0);
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
// Ignore the return value (declarations are statements).
@@ -1081,7 +1152,7 @@
// safe to pop the value lying on top of the reference before unloading
// the reference itself (which preserves the top of stack) because we
// know it is a zero-sized reference.
- __ pop();
+ frame_->Pop();
}
}
@@ -1092,7 +1163,7 @@
Expression* expression = node->expression();
expression->MarkAsStatement();
Load(expression);
- __ pop();
+ frame_->Pop();
}
@@ -1157,7 +1228,7 @@
if (has_cc()) {
cc_reg_ = al;
} else {
- __ pop(r0); // __ Pop(no_reg)
+ frame_->Pop();
}
}
@@ -1167,10 +1238,8 @@
void CodeGenerator::CleanStack(int num_bytes) {
- ASSERT(num_bytes >= 0);
- if (num_bytes > 0) {
- __ add(sp, sp, Operand(num_bytes));
- }
+ ASSERT(num_bytes % kPointerSize == 0);
+ frame_->Drop(num_bytes / kPointerSize);
}
@@ -1195,7 +1264,7 @@
if (FLAG_debug_info) RecordStatementPosition(node);
Load(node->expression());
// Move the function result into r0.
- __ pop(r0);
+ frame_->Pop(r0);
__ b(&function_return_);
}
@@ -1214,7 +1283,7 @@
__ bind(&verified_true);
}
// Update context local.
- __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ str(cp, frame_->Context());
}
@@ -1223,7 +1292,7 @@
// Pop context.
__ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
// Update context local.
- __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ str(cp, frame_->Context());
}
@@ -1246,7 +1315,7 @@
ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
- __ pop(r0);
+ frame_->Pop(r0);
// Test for a Smi value in a HeapNumber.
Label is_smi;
@@ -1256,7 +1325,7 @@
__ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag));
__ cmp(r1, Operand(HEAP_NUMBER_TYPE));
__ b(ne, fail_label);
- __ push(r0);
+ frame_->Push(r0);
__ CallRuntime(Runtime::kNumberToSmi, 1);
__ bind(&is_smi);
@@ -1324,8 +1393,8 @@
} else {
__ bind(&next);
next.Unuse();
- __ ldr(r0, MemOperand(sp, 0));
- __ push(r0); // duplicate TOS
+ __ ldr(r0, frame_->Top());
+ frame_->Push(r0); // duplicate TOS
Load(clause->label());
Comparison(eq, true);
Branch(false, &next);
@@ -1333,7 +1402,7 @@
// Entering the case statement for the first time. Remove the switch value
// from the stack.
- __ pop(r0);
+ frame_->Pop();
// Generate code for the body.
// This is also the target for the fall through from the previous case's
@@ -1352,7 +1421,7 @@
__ b(&default_case);
} else {
// Remove the switch value from the stack.
- __ pop(r0);
+ frame_->Pop();
}
__ bind(&fall_through);
@@ -1448,7 +1517,7 @@
// Get the object to enumerate over (converted to JSObject).
Load(node->enumerable());
- __ pop(r0);
+ frame_->Pop(r0);
// Both SpiderMonkey and kjs ignore null and undefined in contrast
// to the specification. 12.6.4 mandates a call to ToObject.
@@ -1473,7 +1542,7 @@
__ b(hs, &jsobject);
__ bind(&primitive);
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(0));
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
@@ -1481,8 +1550,8 @@
__ bind(&jsobject);
// Get the set of properties (as a FixedArray or Map).
- __ push(r0); // duplicate the object being enumerated
- __ push(r0);
+ frame_->Push(r0); // duplicate the object being enumerated
+ frame_->Push(r0);
__ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
// If we got a Map, we can do a fast modification check.
@@ -1499,28 +1568,28 @@
__ ldr(r2,
FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
- __ push(r0); // map
- __ push(r2); // enum cache bridge cache
+ frame_->Push(r0); // map
+ frame_->Push(r2); // enum cache bridge cache
__ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(Smi::FromInt(0)));
- __ push(r0);
+ frame_->Push(r0);
__ b(&entry);
__ bind(&fixed_array);
__ mov(r1, Operand(Smi::FromInt(0)));
- __ push(r1); // insert 0 in place of Map
- __ push(r0);
+ frame_->Push(r1); // insert 0 in place of Map
+ frame_->Push(r0);
// Push the length of the array and the initial index onto the stack.
__ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(Smi::FromInt(0))); // init index
- __ push(r0);
+ frame_->Push(r0);
__ b(&entry);
@@ -1531,9 +1600,9 @@
// Next.
__ bind(node->continue_target());
__ bind(&next);
- __ pop(r0);
+ frame_->Pop(r0);
__ add(r0, r0, Operand(Smi::FromInt(1)));
- __ push(r0);
+ frame_->Push(r0);
// Condition.
__ bind(&entry);
@@ -1543,31 +1612,31 @@
// 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
+ __ ldr(r0, frame_->Element(0)); // load the current count
+ __ ldr(r1, frame_->Element(1)); // load the length
__ cmp(r0, Operand(r1)); // compare to the array length
__ b(hs, &cleanup);
- __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
+ __ ldr(r0, frame_->Element(0));
// Get the i'th entry of the array.
- __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
+ __ ldr(r2, frame_->Element(2));
__ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
// Get Map or 0.
- __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
+ __ ldr(r2, frame_->Element(3));
// Check if this (still) matches the map of the enumerable.
// If not, we have to filter the key.
- __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
+ __ ldr(r1, frame_->Element(4));
__ 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).
- __ ldr(r0, MemOperand(sp, 4 * kPointerSize)); // push enumerable
- __ push(r0);
- __ push(r3); // push entry
+ __ ldr(r0, frame_->Element(4)); // push enumerable
+ frame_->Push(r0);
+ frame_->Push(r3); // push entry
__ mov(r0, Operand(1));
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS);
__ mov(r3, Operand(r0));
@@ -1581,12 +1650,12 @@
// Store the entry in the 'each' expression and take another spin in the loop.
// r3: i'th entry of the enum cache (or string there of)
- __ push(r3); // push entry
+ frame_->Push(r3); // push entry
{ Reference each(this, node->each());
if (!each.is_illegal()) {
if (each.size() > 0) {
- __ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
- __ push(r0);
+ __ ldr(r0, frame_->Element(each.size()));
+ frame_->Push(r0);
}
// If the reference was to a slot we rely on the convenient property
// that it doesn't matter whether a value (eg, r3 pushed above) is
@@ -1598,20 +1667,20 @@
// ie, now the topmost value of the non-zero sized reference), since
// we will discard the top of stack after unloading the reference
// anyway.
- __ pop(r0);
+ frame_->Pop(r0);
}
}
}
// Discard the i'th entry pushed above or else the remainder of the
// reference, whichever is currently on top of the stack.
- __ pop();
+ frame_->Pop();
CheckStack(); // TODO(1222600): ignore if body contains calls.
__ jmp(&loop);
// Cleanup.
__ bind(&cleanup);
__ bind(node->break_target());
- __ add(sp, sp, Operand(5 * kPointerSize));
+ frame_->Drop(5);
// Exit.
__ bind(&exit);
@@ -1626,11 +1695,10 @@
Label try_block, exit;
__ bl(&try_block);
-
// --- Catch block ---
+ frame_->Push(r0);
// Store the caught exception in the catch variable.
- __ push(r0);
{ Reference ref(this, node->catch_var());
ASSERT(ref.is_slot());
// Here we make use of the convenient property that it doesn't matter
@@ -1640,7 +1708,7 @@
}
// Remove the exception from the stack.
- __ pop();
+ frame_->Pop();
VisitStatements(node->catch_block()->statements());
__ b(&exit);
@@ -1667,7 +1735,7 @@
// Generate code for the statements in the try block.
VisitStatements(node->try_block()->statements());
- __ pop(r0); // Discard the result.
+ frame_->Pop(); // Discard the result.
// Stop the introduced shadowing and count the number of required unlinks.
// After shadowing stops, the original labels are unshadowed and the
@@ -1680,13 +1748,14 @@
// Unlink from try chain.
// TOS contains code slot
- const int kNextOffset = StackHandlerConstants::kNextOffset +
- StackHandlerConstants::kAddressDisplacement;
- __ ldr(r1, MemOperand(sp, kNextOffset)); // read next_sp
+ const int kNextIndex = (StackHandlerConstants::kNextOffset
+ + StackHandlerConstants::kAddressDisplacement)
+ / kPointerSize;
+ __ ldr(r1, frame_->Element(kNextIndex)); // read next_sp
__ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
__ str(r1, MemOperand(r3));
ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
- __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+ frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// Code slot popped.
if (nof_unlinks > 0) __ b(&exit);
@@ -1702,10 +1771,10 @@
__ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
__ ldr(sp, MemOperand(r3));
- __ ldr(r1, MemOperand(sp, kNextOffset));
+ __ ldr(r1, frame_->Element(kNextIndex));
__ str(r1, MemOperand(r3));
ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
- __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+ frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// Code slot popped.
__ b(shadows[i]->original_label());
@@ -1728,7 +1797,7 @@
__ bl(&try_block);
- __ push(r0); // save exception object on the stack
+ frame_->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);
@@ -1766,7 +1835,7 @@
// Set the state on the stack to FALLING.
__ mov(r0, Operand(Factory::undefined_value())); // fake TOS
- __ push(r0);
+ frame_->Push(r0);
__ mov(r2, Operand(Smi::FromInt(FALLING)));
if (nof_unlinks > 0) __ b(&unlink);
@@ -1778,11 +1847,11 @@
if (shadows[i]->original_label() == &function_return_) {
// If this label shadowed the function return, materialize the
// return value on the stack.
- __ push(r0);
+ frame_->Push(r0);
} else {
// Fake TOS for labels that shadowed breaks and continues.
__ mov(r0, Operand(Factory::undefined_value()));
- __ push(r0);
+ frame_->Push(r0);
}
__ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
__ b(&unlink);
@@ -1792,25 +1861,26 @@
// Unlink from try chain;
__ bind(&unlink);
- __ pop(r0); // Store TOS in r0 across stack manipulation
+ frame_->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)));
__ ldr(sp, MemOperand(r3));
- const int kNextOffset = StackHandlerConstants::kNextOffset +
- StackHandlerConstants::kAddressDisplacement;
- __ ldr(r1, MemOperand(sp, kNextOffset));
+ const int kNextIndex = (StackHandlerConstants::kNextOffset
+ + StackHandlerConstants::kAddressDisplacement)
+ / kPointerSize;
+ __ ldr(r1, frame_->Element(kNextIndex));
__ str(r1, MemOperand(r3));
ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
- __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+ frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// Code slot popped.
- __ push(r0);
+ frame_->Push(r0);
// --- Finally block ---
__ bind(&finally_block);
// Push the state on the stack.
- __ push(r2);
+ frame_->Push(r2);
// We keep two elements on the stack - the (possibly faked) result
// and the state - while evaluating the finally block. Record it, so
@@ -1823,8 +1893,8 @@
VisitStatements(node->finally_block()->statements());
// Restore state and return value or faked TOS.
- __ pop(r2);
- __ pop(r0);
+ frame_->Pop(r2);
+ frame_->Pop(r0);
break_stack_height_ -= kFinallyStackSize;
// Generate code to jump to the right destination for all used (formerly)
@@ -1848,7 +1918,7 @@
__ b(ne, &exit);
// Rethrow exception.
- __ push(r0);
+ frame_->Push(r0);
__ CallRuntime(Runtime::kReThrow, 1);
// Done.
@@ -1869,12 +1939,12 @@
// Push the boilerplate on the stack.
__ mov(r0, Operand(boilerplate));
- __ push(r0);
+ frame_->Push(r0);
// Create a new closure.
- __ push(cp);
+ frame_->Push(cp);
__ CallRuntime(Runtime::kNewClosure, 2);
- __ push(r0);
+ frame_->Push(r0);
}
@@ -1915,16 +1985,16 @@
ASSERT(slot->var()->mode() == Variable::DYNAMIC);
// For now, just do a runtime call.
- __ push(cp);
+ frame_->Push(cp);
__ mov(r0, Operand(slot->var()->name()));
- __ push(r0);
+ frame_->Push(r0);
if (typeof_state == INSIDE_TYPEOF) {
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
} else {
__ CallRuntime(Runtime::kLoadContextSlot, 2);
}
- __ push(r0);
+ frame_->Push(r0);
} else {
// Note: We would like to keep the assert below, but it fires because of
@@ -1933,16 +2003,16 @@
// Special handling for locals allocated in registers.
__ ldr(r0, SlotOperand(slot, r2));
- __ push(r0);
+ frame_->Push(r0);
if (slot->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);
+ frame_->Pop(r0);
__ cmp(r0, Operand(Factory::the_hole_value()));
__ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
- __ push(r0);
+ frame_->Push(r0);
}
}
}
@@ -1972,7 +2042,7 @@
void CodeGenerator::VisitLiteral(Literal* node) {
Comment cmnt(masm_, "[ Literal");
__ mov(r0, Operand(node->handle()));
- __ push(r0);
+ frame_->Push(r0);
}
@@ -1982,7 +2052,7 @@
// Retrieve the literal array and check the allocated entry.
// Load the function of this activation.
- __ ldr(r1, FunctionOperand());
+ __ ldr(r1, frame_->Function());
// Load the literals array of the function.
__ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
@@ -1998,19 +2068,19 @@
// If the entry is undefined we call the runtime system to computed
// the literal.
- __ push(r1); // literal array (0)
+ frame_->Push(r1); // literal array (0)
__ mov(r0, Operand(Smi::FromInt(node->literal_index())));
- __ push(r0); // literal index (1)
+ frame_->Push(r0); // literal index (1)
__ mov(r0, Operand(node->pattern())); // RegExp pattern (2)
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(node->flags())); // RegExp flags (3)
- __ push(r0);
+ frame_->Push(r0);
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
__ mov(r2, Operand(r0));
__ bind(&done);
// Push the literal.
- __ push(r2);
+ frame_->Push(r2);
}
@@ -2055,7 +2125,7 @@
// Retrieve the literal array and check the allocated entry.
// Load the function of this activation.
- __ ldr(r1, FunctionOperand());
+ __ ldr(r1, frame_->Function());
// Load the literals array of the function.
__ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
@@ -2072,11 +2142,11 @@
__ bind(deferred->exit());
// Push the object literal boilerplate.
- __ push(r2);
+ frame_->Push(r2);
// Clone the boilerplate object.
__ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
- __ push(r0); // save the result
+ frame_->Push(r0); // save the result
// r0: cloned object literal
for (int i = 0; i < node->properties()->length(); i++) {
@@ -2087,32 +2157,32 @@
case ObjectLiteral::Property::CONSTANT: break;
case ObjectLiteral::Property::COMPUTED: // fall through
case ObjectLiteral::Property::PROTOTYPE: {
- __ push(r0); // dup the result
+ frame_->Push(r0); // dup the result
Load(key);
Load(value);
__ CallRuntime(Runtime::kSetProperty, 3);
// restore r0
- __ ldr(r0, MemOperand(sp, 0));
+ __ ldr(r0, frame_->Top());
break;
}
case ObjectLiteral::Property::SETTER: {
- __ push(r0);
+ frame_->Push(r0);
Load(key);
__ mov(r0, Operand(Smi::FromInt(1)));
- __ push(r0);
+ frame_->Push(r0);
Load(value);
__ CallRuntime(Runtime::kDefineAccessor, 4);
- __ ldr(r0, MemOperand(sp, 0));
+ __ ldr(r0, frame_->Top());
break;
}
case ObjectLiteral::Property::GETTER: {
- __ push(r0);
+ frame_->Push(r0);
Load(key);
__ mov(r0, Operand(Smi::FromInt(0)));
- __ push(r0);
+ frame_->Push(r0);
Load(value);
__ CallRuntime(Runtime::kDefineAccessor, 4);
- __ ldr(r0, MemOperand(sp, 0));
+ __ ldr(r0, frame_->Top());
break;
}
}
@@ -2125,15 +2195,15 @@
// Call runtime to create the array literal.
__ mov(r0, Operand(node->literals()));
- __ push(r0);
+ frame_->Push(r0);
// Load the function of this frame.
- __ ldr(r0, FunctionOperand());
+ __ ldr(r0, frame_->Function());
__ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
- __ push(r0);
+ frame_->Push(r0);
__ CallRuntime(Runtime::kCreateArrayLiteral, 2);
// Push the resulting array literal on the stack.
- __ push(r0);
+ frame_->Push(r0);
// Generate code to set the elements in the array that are not
// literals.
@@ -2145,10 +2215,10 @@
if (value->AsLiteral() == NULL) {
// The property must be set by generated code.
Load(value);
- __ pop(r0);
+ frame_->Pop(r0);
// Fetch the object literal
- __ ldr(r1, MemOperand(sp, 0));
+ __ ldr(r1, frame_->Top());
// Get the elements array.
__ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
@@ -2181,12 +2251,12 @@
Literal* literal = node->value()->AsLiteral();
if (literal != NULL && literal->handle()->IsSmi()) {
SmiOperation(node->binary_op(), literal->handle(), false);
- __ push(r0);
+ frame_->Push(r0);
} else {
Load(node->value());
GenericBinaryOperation(node->binary_op());
- __ push(r0);
+ frame_->Push(r0);
}
}
@@ -2216,7 +2286,7 @@
Load(node->exception());
__ RecordPosition(node->position());
__ CallRuntime(Runtime::kThrow, 1);
- __ push(r0);
+ frame_->Push(r0);
}
@@ -2257,7 +2327,7 @@
// Push the name of the function and the receiver onto the stack.
__ mov(r0, Operand(var->name()));
- __ push(r0);
+ frame_->Push(r0);
// Pass the global object as the receiver and let the IC stub
// patch the stack to use the global proxy as 'this' in the
@@ -2271,10 +2341,10 @@
Handle<Code> stub = ComputeCallInitialize(args->length());
__ RecordPosition(node->position());
__ Call(stub, RelocInfo::CODE_TARGET_CONTEXT);
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ ldr(cp, frame_->Context());
// Remove the function from the stack.
- __ pop();
- __ push(r0);
+ frame_->Pop();
+ frame_->Push(r0);
} else if (var != NULL && var->slot() != NULL &&
var->slot()->type() == Slot::LOOKUP) {
@@ -2283,19 +2353,19 @@
// ----------------------------------
// Load the function
- __ push(cp);
+ frame_->Push(cp);
__ mov(r0, Operand(var->name()));
- __ push(r0);
+ frame_->Push(r0);
__ CallRuntime(Runtime::kLoadContextSlot, 2);
// r0: slot value; r1: receiver
// Load the receiver.
- __ push(r0); // function
- __ push(r1); // receiver
+ frame_->Push(r0); // function
+ frame_->Push(r1); // receiver
// Call the function.
CallWithArguments(args, node->position());
- __ push(r0);
+ frame_->Push(r0);
} else if (property != NULL) {
// Check if the key is a literal string.
@@ -2308,7 +2378,7 @@
// Push the name of the function and the receiver onto the stack.
__ mov(r0, Operand(literal->handle()));
- __ push(r0);
+ frame_->Push(r0);
Load(property->obj());
// Load the arguments.
@@ -2318,12 +2388,12 @@
Handle<Code> stub = ComputeCallInitialize(args->length());
__ RecordPosition(node->position());
__ Call(stub, RelocInfo::CODE_TARGET);
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ ldr(cp, frame_->Context());
// Remove the function from the stack.
- __ pop();
+ frame_->Pop();
- __ push(r0); // push after get rid of function from the stack
+ frame_->Push(r0); // push after get rid of function from the stack
} else {
// -------------------------------------------
@@ -2335,11 +2405,11 @@
ref.GetValue(NOT_INSIDE_TYPEOF); // receiver
// Pass receiver to called function.
- __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
- __ push(r0);
+ __ ldr(r0, frame_->Element(ref.size()));
+ frame_->Push(r0);
// Call the function.
CallWithArguments(args, node->position());
- __ push(r0);
+ frame_->Push(r0);
}
} else {
@@ -2355,7 +2425,7 @@
// Call the function.
CallWithArguments(args, node->position());
- __ push(r0);
+ frame_->Push(r0);
}
}
@@ -2383,7 +2453,7 @@
__ mov(r0, Operand(args->length()));
// Load the function into r1 as per calling convention.
- __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize));
+ __ ldr(r1, frame_->Element(args->length() + 1));
// Call the construct call builtin that handles allocation and
// constructor invocation.
@@ -2392,7 +2462,7 @@
RelocInfo::CONSTRUCT_CALL);
// Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
- __ str(r0, MemOperand(sp, 0 * kPointerSize));
+ __ str(r0, frame_->Top());
}
@@ -2400,7 +2470,7 @@
ASSERT(args->length() == 1);
Label leave;
Load(args->at(0));
- __ pop(r0); // r0 contains object.
+ frame_->Pop(r0); // r0 contains object.
// if (object->IsSmi()) return the object.
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &leave);
@@ -2413,7 +2483,7 @@
// Load the value.
__ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
__ bind(&leave);
- __ push(r0);
+ frame_->Push(r0);
}
@@ -2422,8 +2492,8 @@
Label leave;
Load(args->at(0)); // Load the object.
Load(args->at(1)); // Load the value.
- __ pop(r0); // r0 contains value
- __ pop(r1); // r1 contains object
+ frame_->Pop(r0); // r0 contains value
+ frame_->Pop(r1); // r1 contains object
// if (object->IsSmi()) return object.
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &leave);
@@ -2440,14 +2510,14 @@
__ RecordWrite(r1, r2, r3);
// Leave.
__ bind(&leave);
- __ push(r0);
+ frame_->Push(r0);
}
void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
- __ pop(r0);
+ frame_->Pop(r0);
__ tst(r0, Operand(kSmiTagMask));
cc_reg_ = eq;
}
@@ -2456,7 +2526,7 @@
void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
- __ pop(r0);
+ frame_->Pop(r0);
__ tst(r0, Operand(kSmiTagMask | 0x80000000));
cc_reg_ = eq;
}
@@ -2468,7 +2538,7 @@
void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
__ mov(r0, Operand(Factory::undefined_value()));
- __ push(r0);
+ frame_->Push(r0);
}
@@ -2479,7 +2549,7 @@
// We need the CC bits to come out as not_equal in the case where the
// object is a smi. This can't be done with the usual test opcode so
// we use XOR to get the right CC bits.
- __ pop(r0);
+ frame_->Pop(r0);
__ and_(r1, r0, Operand(kSmiTagMask));
__ eor(r1, r1, Operand(kSmiTagMask), SetCC);
__ b(ne, &answer);
@@ -2503,7 +2573,7 @@
// Call the shared stub to get to the arguments.length.
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
__ CallStub(&stub);
- __ push(r0);
+ frame_->Push(r0);
}
@@ -2513,13 +2583,13 @@
// Satisfy contract with ArgumentsAccessStub:
// Load the key into r1 and the formal parameters count into r0.
Load(args->at(0));
- __ pop(r1);
+ frame_->Pop(r1);
__ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
// Call the shared stub to get to arguments[key].
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
__ CallStub(&stub);
- __ push(r0);
+ frame_->Push(r0);
}
@@ -2529,8 +2599,8 @@
// Load the two objects into registers and perform the comparison.
Load(args->at(0));
Load(args->at(1));
- __ pop(r0);
- __ pop(r1);
+ frame_->Pop(r0);
+ frame_->Pop(r1);
__ cmp(r0, Operand(r1));
cc_reg_ = eq;
}
@@ -2549,25 +2619,25 @@
// Call the C runtime function.
__ CallRuntime(function, args->length());
- __ push(r0);
+ frame_->Push(r0);
} else {
// Prepare stack for calling JS runtime function.
__ mov(r0, Operand(node->name()));
- __ push(r0);
+ frame_->Push(r0);
// Push the builtins object found in the current global object.
__ ldr(r1, GlobalObject());
__ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
- __ push(r0);
+ frame_->Push(r0);
for (int i = 0; i < args->length(); i++) Load(args->at(i));
// Call the JS runtime function.
Handle<Code> stub = ComputeCallInitialize(args->length());
__ Call(stub, RelocInfo::CODE_TARGET);
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- __ pop();
- __ push(r0);
+ __ ldr(cp, frame_->Context());
+ frame_->Pop();
+ frame_->Push(r0);
}
}
@@ -2599,20 +2669,20 @@
if (variable->is_global()) {
LoadGlobal();
__ mov(r0, Operand(variable->name()));
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(1)); // not counting receiver
__ InvokeBuiltin(Builtins::DELETE, CALL_JS);
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
// lookup the context holding the named variable
- __ push(cp);
+ frame_->Push(cp);
__ mov(r0, Operand(variable->name()));
- __ push(r0);
+ frame_->Push(r0);
__ CallRuntime(Runtime::kLookupContext, 2);
// r0: context
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(variable->name()));
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(1)); // not counting receiver
__ InvokeBuiltin(Builtins::DELETE, CALL_JS);
@@ -2625,21 +2695,21 @@
} else {
// Default: Result of deleting expressions is true.
Load(node->expression()); // may have side-effects
- __ pop();
+ frame_->Pop();
__ mov(r0, Operand(Factory::true_value()));
}
- __ push(r0);
+ frame_->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
+ frame_->Push(r0); // r0 has result
} else {
Load(node->expression());
- __ pop(r0);
+ frame_->Pop(r0);
switch (op) {
case Token::NOT:
case Token::DELETE:
@@ -2660,7 +2730,7 @@
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &smi_label);
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(0)); // not counting receiver
__ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS);
@@ -2683,7 +2753,7 @@
Label continue_label;
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &continue_label);
- __ push(r0);
+ frame_->Push(r0);
__ mov(r0, Operand(0)); // not counting receiver
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
__ bind(&continue_label);
@@ -2692,7 +2762,7 @@
default:
UNREACHABLE();
}
- __ push(r0); // r0 has result
+ frame_->Push(r0); // r0 has result
}
}
@@ -2709,13 +2779,13 @@
// Postfix: Make room for the result.
if (is_postfix) {
__ mov(r0, Operand(0));
- __ push(r0);
+ frame_->Push(r0);
}
{ Reference target(this, node->expression());
if (target.is_illegal()) return;
target.GetValue(NOT_INSIDE_TYPEOF);
- __ pop(r0);
+ frame_->Pop(r0);
Label slow, exit;
@@ -2727,7 +2797,9 @@
__ b(ne, &slow);
// Postfix: Store the old value as the result.
- if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize));
+ if (is_postfix) {
+ __ str(r0, frame_->Element(target.size()));
+ }
// Perform optimistic increment/decrement.
if (is_increment) {
@@ -2754,7 +2826,7 @@
InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
__ CallStub(&stub);
// Store to result (on the stack).
- __ str(r0, MemOperand(sp, target.size() * kPointerSize));
+ __ str(r0, frame_->Element(target.size()));
}
// Compute the new value by calling the right JavaScript native.
@@ -2768,12 +2840,12 @@
// Store the new value in the target if not const.
__ bind(&exit);
- __ push(r0);
+ frame_->Push(r0);
if (!is_const) target.SetValue(NOT_CONST_INIT);
}
// Postfix: Discard the new value and use the old.
- if (is_postfix) __ pop(r0);
+ if (is_postfix) frame_->Pop(r0);
}
@@ -2814,8 +2886,8 @@
} else {
Label pop_and_continue, exit;
- __ ldr(r0, MemOperand(sp, 0)); // dup the stack top
- __ push(r0);
+ __ ldr(r0, frame_->Top()); // dup the stack top
+ frame_->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.
@@ -2824,7 +2896,7 @@
// Pop the result of evaluating the first part.
__ bind(&pop_and_continue);
- __ pop(r0);
+ frame_->Pop(r0);
// Evaluate right side expression.
__ bind(&is_true);
@@ -2855,8 +2927,8 @@
} else {
Label pop_and_continue, exit;
- __ ldr(r0, MemOperand(sp, 0));
- __ push(r0);
+ __ ldr(r0, frame_->Top());
+ frame_->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.
@@ -2865,7 +2937,7 @@
// Pop the result of evaluating the first part.
__ bind(&pop_and_continue);
- __ pop(r0);
+ frame_->Pop(r0);
// Evaluate right side expression.
__ bind(&is_false);
@@ -2894,14 +2966,14 @@
Load(node->right());
GenericBinaryOperation(node->op());
}
- __ push(r0);
+ frame_->Push(r0);
}
}
void CodeGenerator::VisitThisFunction(ThisFunction* node) {
- __ ldr(r0, FunctionOperand());
- __ push(r0);
+ __ ldr(r0, frame_->Function());
+ frame_->Push(r0);
}
@@ -2913,55 +2985,47 @@
Expression* right = node->right();
Token::Value op = node->op();
- // NOTE: To make null checks efficient, we check if either left or
- // right is the literal 'null'. If so, we optimize the code by
- // inlining a null check instead of calling the (very) general
- // runtime routine for checking equality.
-
+ // To make null checks efficient, we check if either left or right is the
+ // literal 'null'. If so, we optimize the code by inlining a null check
+ // instead of calling the (very) general runtime routine for checking
+ // equality.
if (op == Token::EQ || op == Token::EQ_STRICT) {
bool left_is_null =
- left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
+ left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
bool right_is_null =
- right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
- // The 'null' value is only equal to 'null' or 'undefined'.
+ right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
+ // The 'null' value can only be equal to 'null' or 'undefined'.
if (left_is_null || right_is_null) {
Load(left_is_null ? right : left);
- Label exit, undetectable;
- __ pop(r0);
+ frame_->Pop(r0);
__ cmp(r0, Operand(Factory::null_value()));
- // The 'null' value is only equal to 'undefined' if using
- // non-strict comparisons.
+ // The 'null' value is only equal to 'undefined' if using non-strict
+ // comparisons.
if (op != Token::EQ_STRICT) {
- __ b(eq, &exit);
+ __ b(eq, true_target());
+
__ cmp(r0, Operand(Factory::undefined_value()));
+ __ b(eq, true_target());
- // NOTE: it can be undetectable object.
- __ b(eq, &exit);
__ tst(r0, Operand(kSmiTagMask));
+ __ b(eq, false_target());
- __ b(ne, &undetectable);
- __ b(false_target());
-
- __ bind(&undetectable);
- __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
- __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
- __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
- __ cmp(r2, Operand(1 << Map::kIsUndetectable));
+ // It can be an undetectable object.
+ __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
+ __ ldrb(r0, FieldMemOperand(r0, Map::kBitFieldOffset));
+ __ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
+ __ cmp(r0, Operand(1 << Map::kIsUndetectable));
}
- __ bind(&exit);
-
cc_reg_ = eq;
return;
}
}
-
- // NOTE: To make typeof testing for natives implemented in
- // JavaScript really efficient, we generate special code for
- // expressions of the form: 'typeof <expression> == <string>'.
-
+ // To make typeof testing for natives implemented in JavaScript really
+ // efficient, we generate special code for expressions of the form:
+ // 'typeof <expression> == <string>'.
UnaryOperation* operation = left->AsUnaryOperation();
if ((op == Token::EQ || op == Token::EQ_STRICT) &&
(operation != NULL && operation->op() == Token::TYPEOF) &&
@@ -2971,7 +3035,7 @@
// Load the operand, move it to register r1.
LoadTypeofExpression(operation->expression());
- __ pop(r1);
+ frame_->Pop(r1);
if (check->Equals(Heap::number_symbol())) {
__ tst(r1, Operand(kSmiTagMask));
@@ -2986,7 +3050,7 @@
__ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
- // NOTE: it might be an undetectable string object
+ // It can be an undetectable string object.
__ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
__ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
__ cmp(r2, Operand(1 << Map::kIsUndetectable));
@@ -3009,7 +3073,7 @@
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, false_target());
- // NOTE: it can be undetectable object.
+ // It can be an undetectable object.
__ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
__ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
__ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
@@ -3033,7 +3097,7 @@
__ cmp(r1, Operand(Factory::null_value()));
__ b(eq, true_target());
- // NOTE: it might be an undetectable object.
+ // It can be an undetectable object.
__ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
__ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
__ cmp(r1, Operand(1 << Map::kIsUndetectable));
@@ -3046,8 +3110,8 @@
cc_reg_ = le;
} else {
- // Uncommon case: Typeof testing against a string literal that
- // is never returned from the typeof operator.
+ // Uncommon case: typeof testing against a string literal that is
+ // never returned from the typeof operator.
__ b(false_target());
}
return;
@@ -3083,7 +3147,7 @@
case Token::IN:
__ mov(r0, Operand(1)); // not counting receiver
__ InvokeBuiltin(Builtins::IN, CALL_JS);
- __ push(r0);
+ frame_->Push(r0);
break;
case Token::INSTANCEOF:
@@ -3108,34 +3172,6 @@
}
-void CodeGenerator::EnterJSFrame() {
-#if defined(DEBUG)
- { Label done, fail;
- __ tst(r1, Operand(kSmiTagMask));
- __ b(eq, &fail);
- __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
- __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
- __ cmp(r2, Operand(JS_FUNCTION_TYPE));
- __ b(eq, &done);
- __ bind(&fail);
- __ stop("CodeGenerator::EnterJSFrame - r1 not a function");
- __ bind(&done);
- }
-#endif // DEBUG
-
- __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
- __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP.
-}
-
-
-void CodeGenerator::ExitJSFrame() {
- // Drop the execution stack down to the frame pointer and restore the caller
- // frame pointer and return address.
- __ mov(sp, fp);
- __ ldm(ia_w, sp, fp.bit() | lr.bit());
-}
-
-
#undef __
#define __ masm->
@@ -3160,6 +3196,7 @@
ASSERT(!is_illegal());
ASSERT(!cgen_->has_cc());
MacroAssembler* masm = cgen_->masm();
+ VirtualFrame* frame = cgen_->frame();
Property* property = expression_->AsProperty();
if (property != NULL) {
__ RecordPosition(property->position());
@@ -3193,7 +3230,7 @@
} else {
__ Call(ic, RelocInfo::CODE_TARGET);
}
- __ push(r0);
+ frame->Push(r0);
break;
}
@@ -3202,10 +3239,16 @@
// distinction between expressions in a typeof and not in a typeof.
Comment cmnt(masm, "[ Load from keyed Property");
ASSERT(property != NULL);
- // TODO(1224671): Implement inline caching for keyed loads as on ia32.
- GetPropertyStub stub;
- __ CallStub(&stub);
- __ push(r0);
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+
+ Variable* var = expression_->AsVariableProxy()->AsVariable();
+ if (var != NULL) {
+ ASSERT(var->is_global());
+ __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+ } else {
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ }
+ frame->Push(r0);
break;
}
@@ -3219,6 +3262,7 @@
ASSERT(!is_illegal());
ASSERT(!cgen_->has_cc());
MacroAssembler* masm = cgen_->masm();
+ VirtualFrame* frame = cgen_->frame();
Property* property = expression_->AsProperty();
if (property != NULL) {
__ RecordPosition(property->position());
@@ -3233,9 +3277,9 @@
ASSERT(slot->var()->mode() == Variable::DYNAMIC);
// For now, just do a runtime call.
- __ push(cp);
+ frame->Push(cp);
__ mov(r0, Operand(slot->var()->name()));
- __ push(r0);
+ frame->Push(r0);
if (init_state == CONST_INIT) {
// Same as the case for a normal store, but ignores attribute
@@ -3259,7 +3303,7 @@
}
// Storing a variable must keep the (new) value on the expression
// stack. This is necessary for compiling assignment expressions.
- __ push(r0);
+ frame->Push(r0);
} else {
ASSERT(slot->var()->mode() != Variable::DYNAMIC);
@@ -3285,9 +3329,9 @@
// 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);
+ frame->Pop(r0);
__ str(r0, cgen_->SlotOperand(slot, r2));
- __ push(r0);
+ frame->Push(r0);
if (slot->type() == Slot::CONTEXT) {
// Skip write barrier if the written value is a smi.
__ tst(r0, Operand(kSmiTagMask));
@@ -3310,13 +3354,13 @@
case NAMED: {
Comment cmnt(masm, "[ Store to named Property");
// Call the appropriate IC code.
- __ pop(r0); // value
+ frame->Pop(r0); // value
// Setup the name register.
Handle<String> name(GetName());
__ mov(r2, Operand(name));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
- __ push(r0);
+ frame->Push(r0);
break;
}
@@ -3325,10 +3369,13 @@
Property* property = expression_->AsProperty();
ASSERT(property != NULL);
__ RecordPosition(property->position());
- __ pop(r0); // value
- SetPropertyStub stub;
- __ CallStub(&stub);
- __ push(r0);
+
+ // Call IC code.
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+ // TODO(1222589): Make the IC grab the values from the stack.
+ frame->Pop(r0); // value
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ frame->Push(r0);
break;
}
@@ -3813,8 +3860,16 @@
// Restore the stack to the address of the ENTRY handler
__ mov(sp, Operand(r3));
- // restore parameter- and frame-pointer and pop state.
- __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
+ // Stack layout at this point. See also PushTryHandler
+ // r3, sp -> next handler
+ // state (ENTRY)
+ // pp
+ // fp
+ // lr
+
+ // Discard ENTRY state (r2 is not used), and restore parameter-
+ // and frame-pointer and pop state.
+ __ ldm(ia_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit());
// Before returning we restore the context from the frame pointer if not NULL.
// The frame pointer is NULL in the exception handler of a JS entry frame.
__ cmp(fp, Operand(0));
@@ -4044,7 +4099,7 @@
// sets it to 0 to signal the existence of the JSEntry frame.
__ mov(ip, Operand(Top::pending_exception_address()));
__ str(r0, MemOperand(ip));
- __ mov(r0, Operand(Handle<Failure>(Failure::Exception())));
+ __ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
__ b(&exit);
// Invoke: Link this frame into the handler chain.
@@ -4229,7 +4284,10 @@
// Slow-case: Non-function called.
__ bind(&slow);
__ mov(r0, Operand(argc_)); // Setup the number of arguments.
- __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS);
+ __ mov(r2, Operand(0));
+ __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
+ __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)),
+ RelocInfo::CODE_TARGET);
}
diff --git a/src/codegen-arm.h b/src/codegen-arm.h
index 8058138..2b889cd 100644
--- a/src/codegen-arm.h
+++ b/src/codegen-arm.h
@@ -38,8 +38,62 @@
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+enum InitState { CONST_INIT, NOT_CONST_INIT };
+enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
-// -----------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------
+// Virtual frame
+
+class VirtualFrame BASE_EMBEDDED {
+ public:
+ explicit VirtualFrame(CodeGenerator* cgen);
+
+ void Enter();
+ void Exit();
+
+ void AllocateLocals();
+
+ MemOperand Top() const { return MemOperand(sp, 0); }
+
+ MemOperand Element(int index) const {
+ return MemOperand(sp, index * kPointerSize);
+ }
+
+ MemOperand Local(int index) const {
+ ASSERT(0 <= index && index < frame_local_count_);
+ return MemOperand(fp, kLocal0Offset - index * kPointerSize);
+ }
+
+ MemOperand Function() const { return MemOperand(fp, kFunctionOffset); }
+
+ MemOperand Context() const { return MemOperand(fp, kContextOffset); }
+
+ MemOperand Parameter(int index) const {
+ // Index -1 corresponds to the receiver.
+ ASSERT(-1 <= index && index <= parameter_count_);
+ return MemOperand(fp, (1 + parameter_count_ - index) * kPointerSize);
+ }
+
+ inline void Drop(int count);
+
+ inline void Pop();
+ inline void Pop(Register reg);
+
+ inline void Push(Register reg);
+
+ private:
+ static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
+ static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
+ static const int kContextOffset = StandardFrameConstants::kContextOffset;
+
+ MacroAssembler* masm_;
+ int frame_local_count_;
+ int parameter_count_;
+};
+
+
+// -------------------------------------------------------------------------
// Reference support
// A reference is a C++ stack-allocated object that keeps an ECMA
@@ -49,9 +103,6 @@
// For properties, we keep either one (named) or two (indexed) values
// on the execution stack to represent the reference.
-enum InitState { CONST_INIT, NOT_CONST_INIT };
-enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
-
class Reference BASE_EMBEDDED {
public:
// The values of the types is important, see size().
@@ -66,8 +117,8 @@
type_ = value;
}
- // The size of the reference or -1 if the reference is illegal.
- int size() const { return type_; }
+ // The size the reference takes up on the stack.
+ int size() const { return (type_ == ILLEGAL) ? 0 : type_; }
bool is_illegal() const { return type_ == ILLEGAL; }
bool is_slot() const { return type_ == SLOT; }
@@ -133,7 +184,7 @@
};
-// -----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
// CodeGenerator
class CodeGenerator: public Visitor {
@@ -156,6 +207,8 @@
// Accessors
MacroAssembler* masm() { return masm_; }
+ VirtualFrame* frame() const { return frame_; }
+
CodeGenState* state() { return state_; }
void set_state(CodeGenState* state) { state_ = state; }
@@ -193,20 +246,6 @@
void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
- // Support functions for accessing parameters and other operands.
- MemOperand ParameterOperand(int index) const {
- int num_parameters = scope()->num_parameters();
- // index -2 corresponds to the activated closure, -1 corresponds
- // to the receiver
- ASSERT(-2 <= index && index < num_parameters);
- int offset = (1 + num_parameters - index) * kPointerSize;
- return MemOperand(fp, offset);
- }
-
- MemOperand FunctionOperand() const {
- return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset);
- }
-
MemOperand ContextOperand(Register context, int index) const {
return MemOperand(context, Context::SlotOffset(index));
}
@@ -257,6 +296,7 @@
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
Handle<Code> ComputeCallInitialize(int argc);
+ Handle<Code> ComputeCallInitializeInLoop(int argc);
// Declare global variables and functions in the given array of
// name/value pairs.
@@ -341,11 +381,6 @@
// should be generated or not.
void RecordStatementPosition(Node* node);
- // Activation frames.
- void EnterJSFrame();
- void ExitJSFrame();
-
-
bool is_eval_; // Tells whether code is generated for eval.
Handle<Script> script_;
List<DeferredCode*> deferred_;
@@ -355,6 +390,7 @@
// Code generation state
Scope* scope_;
+ VirtualFrame* frame_;
Condition cc_reg_;
CodeGenState* state_;
bool is_inside_try_;
@@ -363,10 +399,8 @@
// Labels
Label function_return_;
+ friend class VirtualFrame;
friend class Reference;
- friend class Property;
- friend class VariableProxy;
- friend class Slot;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc
index cac0f44..230dc17 100644
--- a/src/codegen-ia32.cc
+++ b/src/codegen-ia32.cc
@@ -99,9 +99,7 @@
}
-void VirtualFrame::Pop() {
- __ add(Operand(esp), Immediate(kPointerSize));
-}
+void VirtualFrame::Pop() { Drop(1); }
void VirtualFrame::Pop(Register reg) {
@@ -199,6 +197,10 @@
VirtualFrame virtual_frame(this);
frame_ = &virtual_frame;
cc_reg_ = no_condition;
+
+ // Adjust for function-level loop nesting.
+ loop_nesting_ += fun->loop_nesting();
+
{
CodeGenState state(this);
@@ -267,10 +269,8 @@
__ int3();
__ bind(&verified_true);
}
-
// Update context local.
__ mov(frame_->Context(), esi);
- // Restore the arguments array pointer, if any.
}
// TODO(1241774): Improve this code:
@@ -310,10 +310,10 @@
// This section stores the pointer to the arguments object that
// was allocated and copied into above. If the address was not
// saved to TOS, we push ecx onto the stack.
-
- // Store the arguments object.
- // This must happen after context initialization because
- // the arguments object may be stored in the context
+ //
+ // Store the arguments object. This must happen after context
+ // initialization because the arguments object may be stored in the
+ // context.
if (arguments_object_allocated) {
ASSERT(scope_->arguments() != NULL);
ASSERT(scope_->arguments_shadow() != NULL);
@@ -341,18 +341,17 @@
frame_->Pop(); // Value is no longer needed.
}
- // Generate code to 'execute' declarations and initialize
- // functions (source elements). In case of an illegal
- // redeclaration we need to handle that instead of processing the
- // declarations.
+ // Generate code to 'execute' declarations and initialize functions
+ // (source elements). In case of an illegal redeclaration we need to
+ // handle that instead of processing the declarations.
if (scope_->HasIllegalRedeclaration()) {
Comment cmnt(masm_, "[ illegal redeclarations");
scope_->VisitIllegalRedeclaration(this);
} else {
Comment cmnt(masm_, "[ declarations");
ProcessDeclarations(scope_->declarations());
- // Bail out if a stack-overflow exception occurred when
- // processing declarations.
+ // Bail out if a stack-overflow exception occurred when processing
+ // declarations.
if (HasStackOverflow()) return;
}
@@ -388,11 +387,15 @@
}
}
+ // Adjust for function-level loop nesting.
+ loop_nesting_ -= fun->loop_nesting();
+
// Code generation state must be reset.
scope_ = NULL;
frame_ = NULL;
ASSERT(!has_cc());
ASSERT(state_ == NULL);
+ ASSERT(loop_nesting() == 0);
}
@@ -448,10 +451,11 @@
// 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,
-// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
+// (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 CodeGenerator::LoadCondition(Expression* x,
TypeofState typeof_state,
Label* true_target,
@@ -463,6 +467,14 @@
Visit(x);
}
if (force_cc && !has_cc()) {
+ // Convert the TOS value to a boolean in the condition code register.
+ // Visiting an expression may possibly choose neither (a) to leave a
+ // value in the condition code register nor (b) to leave a value in TOS
+ // (eg, by compiling to only jumps to the targets). In that case the
+ // code generated by ToBoolean is wrong because it assumes the value of
+ // the expression in TOS. So long as there is always a value in TOS or
+ // the condition code register when control falls through to here (there
+ // is), the code generated by ToBoolean is dead and therefore safe.
ToBoolean(true_target, false_target);
}
ASSERT(has_cc() || !force_cc);
@@ -476,7 +488,6 @@
if (has_cc()) {
// convert cc_reg_ into a bool
-
Label loaded, materialize_true;
__ j(cc_reg_, &materialize_true);
frame_->Push(Immediate(Factory::false_value()));
@@ -604,12 +615,10 @@
// Pop a reference from the stack while preserving TOS.
Comment cmnt(masm_, "[ UnloadReference");
int size = ref->size();
- if (size <= 0) {
- // Do nothing. No popping is necessary.
- } else if (size == 1) {
+ if (size == 1) {
frame_->Pop(eax);
__ mov(frame_->Top(), eax);
- } else {
+ } else if (size > 1) {
frame_->Pop(eax);
frame_->Drop(size);
frame_->Push(eax);
@@ -663,7 +672,7 @@
frame_->Push(eax); // Undo the pop(eax) from above.
ToBooleanStub stub;
__ CallStub(&stub);
- // Convert result (eax) to condition code.
+ // Convert the result (eax) to condition code.
__ test(eax, Operand(eax));
ASSERT(not_equal == not_zero);
@@ -1040,7 +1049,7 @@
} else {
deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode);
__ mov(edx, Operand(eax));
- __ mov(Operand(eax), Immediate(value));
+ __ mov(eax, Immediate(value));
__ sub(eax, Operand(edx));
}
__ j(overflow, deferred->enter(), not_taken);
@@ -1094,7 +1103,7 @@
__ j(not_zero, deferred->enter(), not_taken);
// tag result and store it in TOS (eax)
ASSERT(kSmiTagSize == times_2); // adjust code if not the case
- __ lea(eax, Operand(ebx, times_2, kSmiTag));
+ __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag));
__ bind(deferred->exit());
frame_->Push(eax);
}
@@ -1123,7 +1132,7 @@
__ j(not_zero, deferred->enter(), not_taken);
// tag result and store it in TOS (eax)
ASSERT(kSmiTagSize == times_2); // adjust code if not the case
- __ lea(eax, Operand(ebx, times_2, kSmiTag));
+ __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag));
__ bind(deferred->exit());
frame_->Push(eax);
}
@@ -1264,7 +1273,7 @@
CompareStub stub(cc_, strict_);
// Setup parameters and call stub.
__ mov(edx, Operand(eax));
- __ mov(Operand(eax), Immediate(Smi::FromInt(value_)));
+ __ Set(eax, Immediate(Smi::FromInt(value_)));
__ CallStub(&stub);
__ cmp(eax, 0);
// "result" is returned in the flags
@@ -1650,7 +1659,7 @@
__ j(greater_equal, fail_label, not_taken);
// 0 is placeholder.
- __ jmp(Operand(eax, times_2, 0x0, RelocInfo::INTERNAL_REFERENCE));
+ __ jmp(Operand(eax, eax, times_1, 0x0, RelocInfo::INTERNAL_REFERENCE));
// calculate address to overwrite later with actual address of table.
int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t);
@@ -2198,7 +2207,6 @@
frame_->Pop(Operand::StaticVariable(handler_address));
frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// Next_sp popped.
- // Preserve the TOS in a register across stack manipulation.
frame_->Push(eax);
// --- Finally block ---
@@ -2694,14 +2702,15 @@
// patch the stack to use the global proxy as 'this' in the
// invoked function.
LoadGlobal();
-
// Load the arguments.
for (int i = 0; i < args->length(); i++) {
Load(args->at(i));
}
// Setup the receiver register and call the IC initialization code.
- Handle<Code> stub = ComputeCallInitialize(args->length());
+ Handle<Code> stub = (loop_nesting() > 0)
+ ? ComputeCallInitializeInLoop(args->length())
+ : ComputeCallInitialize(args->length());
__ RecordPosition(node->position());
__ call(stub, RelocInfo::CODE_TARGET_CONTEXT);
__ mov(esi, frame_->Context());
@@ -2745,7 +2754,9 @@
for (int i = 0; i < args->length(); i++) Load(args->at(i));
// Call the IC initialization code.
- Handle<Code> stub = ComputeCallInitialize(args->length());
+ Handle<Code> stub = (loop_nesting() > 0)
+ ? ComputeCallInitializeInLoop(args->length())
+ : ComputeCallInitialize(args->length());
__ RecordPosition(node->position());
__ call(stub, RelocInfo::CODE_TARGET);
__ mov(esi, frame_->Context());
@@ -3522,54 +3533,47 @@
Expression* right = node->right();
Token::Value op = node->op();
- // NOTE: To make null checks efficient, we check if either left or
- // right is the literal 'null'. If so, we optimize the code by
- // inlining a null check instead of calling the (very) general
- // runtime routine for checking equality.
-
+ // To make null checks efficient, we check if either left or right is the
+ // literal 'null'. If so, we optimize the code by inlining a null check
+ // instead of calling the (very) general runtime routine for checking
+ // equality.
if (op == Token::EQ || op == Token::EQ_STRICT) {
bool left_is_null =
- left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
+ left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
bool right_is_null =
- right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
- // The 'null' value is only equal to 'null' or 'undefined'.
+ right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
+ // The 'null' value can only be equal to 'null' or 'undefined'.
if (left_is_null || right_is_null) {
Load(left_is_null ? right : left);
- Label exit, undetectable;
frame_->Pop(eax);
__ cmp(eax, Factory::null_value());
- // The 'null' value is only equal to 'undefined' if using
- // non-strict comparisons.
+ // The 'null' value is only equal to 'undefined' if using non-strict
+ // comparisons.
if (op != Token::EQ_STRICT) {
- __ j(equal, &exit);
+ __ j(equal, true_target());
+
__ cmp(eax, Factory::undefined_value());
+ __ j(equal, true_target());
- // NOTE: it can be an undetectable object.
- __ j(equal, &exit);
__ test(eax, Immediate(kSmiTagMask));
+ __ j(equal, false_target());
- __ j(not_equal, &undetectable);
- __ jmp(false_target());
-
- __ bind(&undetectable);
- __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
- __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
- __ and_(ecx, 1 << Map::kIsUndetectable);
- __ cmp(ecx, 1 << Map::kIsUndetectable);
+ // It can be an undetectable object.
+ __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
+ __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset));
+ __ and_(eax, 1 << Map::kIsUndetectable);
+ __ cmp(eax, 1 << Map::kIsUndetectable);
}
- __ bind(&exit);
-
cc_reg_ = equal;
return;
}
}
- // NOTE: To make typeof testing for natives implemented in
- // JavaScript really efficient, we generate special code for
- // expressions of the form: 'typeof <expression> == <string>'.
-
+ // To make typeof testing for natives implemented in JavaScript really
+ // efficient, we generate special code for expressions of the form:
+ // 'typeof <expression> == <string>'.
UnaryOperation* operation = left->AsUnaryOperation();
if ((op == Token::EQ || op == Token::EQ_STRICT) &&
(operation != NULL && operation->op() == Token::TYPEOF) &&
@@ -3577,7 +3581,7 @@
right->AsLiteral()->handle()->IsString())) {
Handle<String> check(String::cast(*right->AsLiteral()->handle()));
- // Load the operand, move it to register edx, and restore TOS.
+ // Load the operand and move it to register edx.
LoadTypeofExpression(operation->expression());
frame_->Pop(edx);
@@ -3594,7 +3598,7 @@
__ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
- // NOTE: it might be an undetectable string object
+ // It can be an undetectable string object.
__ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
__ and_(ecx, 1 << Map::kIsUndetectable);
__ cmp(ecx, 1 << Map::kIsUndetectable);
@@ -3617,7 +3621,7 @@
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, false_target());
- // NOTE: it can be an undetectable object.
+ // It can be an undetectable object.
__ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
__ and_(ecx, 1 << Map::kIsUndetectable);
@@ -3641,7 +3645,7 @@
__ cmp(edx, Factory::null_value());
__ j(equal, true_target());
- // NOTE: it might be an undetectable object
+ // It can be an undetectable object.
__ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset));
__ and_(edx, 1 << Map::kIsUndetectable);
__ cmp(edx, 1 << Map::kIsUndetectable);
@@ -3654,8 +3658,8 @@
cc_reg_ = less_equal;
} else {
- // Uncommon case: Typeof testing against a string literal that
- // is never returned from the typeof operator.
+ // Uncommon case: typeof testing against a string literal that is
+ // never returned from the typeof operator.
__ jmp(false_target());
}
return;
@@ -4062,7 +4066,7 @@
__ j(not_zero, slow);
// Tag the result and store it in register eax.
ASSERT(kSmiTagSize == times_2); // adjust code if not the case
- __ lea(eax, Operand(eax, times_2, kSmiTag));
+ __ lea(eax, Operand(eax, eax, times_1, kSmiTag));
break;
case Token::MOD:
@@ -4123,7 +4127,7 @@
}
// Tag the result and store it in register eax.
ASSERT(kSmiTagSize == times_2); // adjust code if not the case
- __ lea(eax, Operand(eax, times_2, kSmiTag));
+ __ lea(eax, Operand(eax, eax, times_1, kSmiTag));
break;
default:
@@ -4250,7 +4254,7 @@
// Tag smi result and return.
ASSERT(kSmiTagSize == times_2); // adjust code if not the case
- __ lea(eax, Operand(eax, times_2, kSmiTag));
+ __ lea(eax, Operand(eax, eax, times_1, kSmiTag));
__ ret(2 * kPointerSize);
// All ops except SHR return a signed int32 that we load in a HeapNumber.
@@ -4984,7 +4988,7 @@
// running with --gc-greedy set.
if (FLAG_gc_greedy) {
Failure* failure = Failure::RetryAfterGC(0);
- __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure)));
+ __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
}
GenerateCore(masm, &throw_normal_exception,
&throw_out_of_memory_exception,
@@ -5002,7 +5006,7 @@
// Do full GC and retry runtime call one final time.
Failure* failure = Failure::InternalError();
- __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure)));
+ __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
GenerateCore(masm,
&throw_normal_exception,
&throw_out_of_memory_exception,
@@ -5046,7 +5050,7 @@
// exception field in the JSEnv and return a failure sentinel.
ExternalReference pending_exception(Top::k_pending_exception_address);
__ mov(Operand::StaticVariable(pending_exception), eax);
- __ mov(eax, Handle<Failure>(Failure::Exception()));
+ __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
__ jmp(&exit);
// Invoke: Link this frame into the handler chain.
@@ -5068,10 +5072,10 @@
// stub, because the builtin stubs may not have been generated yet.
if (is_construct) {
ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
- __ mov(Operand(edx), Immediate(construct_entry));
+ __ mov(edx, Immediate(construct_entry));
} else {
ExternalReference entry(Builtins::JSEntryTrampoline);
- __ mov(Operand(edx), Immediate(entry));
+ __ mov(edx, Immediate(entry));
}
__ mov(edx, Operand(edx, 0)); // deref address
__ lea(edx, FieldOperand(edx, Code::kHeaderSize));
diff --git a/src/codegen-ia32.h b/src/codegen-ia32.h
index 39eea1b..ee6df47 100644
--- a/src/codegen-ia32.h
+++ b/src/codegen-ia32.h
@@ -121,8 +121,8 @@
type_ = value;
}
- // The size of the reference or -1 if the reference is illegal.
- int size() const { return type_; }
+ // The size the reference takes up on the stack.
+ int size() const { return (type_ == ILLEGAL) ? 0 : type_; }
bool is_illegal() const { return type_ == ILLEGAL; }
bool is_slot() const { return type_ == SLOT; }
@@ -320,6 +320,7 @@
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
Handle<Code> ComputeCallInitialize(int argc);
+ Handle<Code> ComputeCallInitializeInLoop(int argc);
// Declare global variables and functions in the given array of
// name/value pairs.
diff --git a/src/codegen.cc b/src/codegen.cc
index 70acf65..14c20dc 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -242,6 +242,15 @@
}
+Handle<Code> CodeGenerator::ComputeCallInitializeInLoop(int argc) {
+ // Force the creation of the corresponding stub outside loops,
+ // because it will be used when clearing the ICs later - when we
+ // don't know if we're inside a loop or not.
+ ComputeCallInitialize(argc);
+ CALL_HEAP_FUNCTION(StubCache::ComputeCallInitializeInLoop(argc), Code);
+}
+
+
void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
int length = declarations->length();
int globals = 0;
diff --git a/src/codegen.h b/src/codegen.h
index ca11c34..6b543eb 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -48,6 +48,7 @@
// CodeGenerator::GenCode
// CodeGenerator::BuildBoilerplate
// CodeGenerator::ComputeCallInitialize
+// CodeGenerator::ComputeCallInitializeInLoop
// CodeGenerator::ProcessDeclarations
// CodeGenerator::DeclareGlobals
// CodeGenerator::CheckForInlineRuntimeCall
diff --git a/src/compiler.cc b/src/compiler.cc
index 2a2bb87..eb76d38 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -66,7 +66,11 @@
#endif
// Optimize the AST.
- Rewriter::Optimize(literal);
+ if (!Rewriter::Optimize(literal)) {
+ // Signal a stack overflow by returning a null handle. The stack
+ // overflow exception will be thrown by the caller.
+ return Handle<Code>::null();
+ }
// Generate code and return it.
Handle<Code> result = CodeGenerator::MakeCode(literal, script, is_eval);
@@ -235,7 +239,8 @@
}
-bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared) {
+bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
+ int loop_nesting) {
ZoneScope zone_scope(DELETE_ON_EXIT);
// The VM is in the COMPILER state until exiting this function.
@@ -267,6 +272,9 @@
return false;
}
+ // Update the loop nesting in the function literal.
+ lit->set_loop_nesting(loop_nesting);
+
// Measure how long it takes to do the lazy compilation; only take
// the rest of the function into account to avoid overlap with the
// lazy parsing statistics.
diff --git a/src/compiler.h b/src/compiler.h
index 3bbc9aa..0f4143c 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -64,7 +64,7 @@
// Compile from function info (used for lazy compilation). Returns
// true on success and false if the compilation resulted in a stack
// overflow.
- static bool CompileLazy(Handle<SharedFunctionInfo> shared);
+ static bool CompileLazy(Handle<SharedFunctionInfo> shared, int loop_nesting);
};
} } // namespace v8::internal
diff --git a/src/constants-arm.h b/src/constants-arm.h
index a388009..c74708b 100644
--- a/src/constants-arm.h
+++ b/src/constants-arm.h
@@ -33,62 +33,74 @@
// Defines constants and accessor classes to assemble, disassemble and
// simulate ARM instructions.
//
+// Section references in the code refer to the "ARM Architecture Reference
+// Manual" from July 2005 (available at http://www.arm.com/miscPDFs/14128.pdf)
+//
// Constants for specific fields are defined in their respective named enums.
// General constants are in an anonymous enum in class Instr.
typedef unsigned char byte;
+// Values for the condition field as defined in section A3.2
enum Condition {
no_condition = -1,
- EQ = 0,
- NE = 1,
- CS = 2,
- CC = 3,
- MI = 4,
- PL = 5,
- VS = 6,
- VC = 7,
- HI = 8,
- LS = 9,
- GE = 10,
- LT = 11,
- GT = 12,
- LE = 13,
- AL = 14,
- special_condition = 15
+ EQ = 0, // equal
+ NE = 1, // not equal
+ CS = 2, // carry set/unsigned higher or same
+ CC = 3, // carry clear/unsigned lower
+ MI = 4, // minus/negative
+ PL = 5, // plus/positive or zero
+ VS = 6, // overflow
+ VC = 7, // no overflow
+ HI = 8, // unsigned higher
+ LS = 9, // unsigned lower or same
+ GE = 10, // signed greater than or equal
+ LT = 11, // signed less than
+ GT = 12, // signed greater than
+ LE = 13, // signed less than or equal
+ AL = 14, // always (unconditional)
+ special_condition = 15, // special condition (refer to section A3.2.1)
+ max_condition = 16
};
+// Opcodes for Data-processing instructions (instructions with a type 0 and 1)
+// as defined in section A3.4
enum Opcode {
no_operand = -1,
- AND = 0,
- EOR = 1,
- SUB = 2,
- RSB = 3,
- ADD = 4,
- ADC = 5,
- SBC = 6,
- RSC = 7,
- TST = 8,
- TEQ = 9,
- CMP = 10,
- CMN = 11,
- ORR = 12,
- MOV = 13,
- BIC = 14,
- MVN = 15
+ AND = 0, // Logical AND
+ EOR = 1, // Logical Exclusive OR
+ SUB = 2, // Subtract
+ RSB = 3, // Reverse Subtract
+ ADD = 4, // Add
+ ADC = 5, // Add with Carry
+ SBC = 6, // Subtract with Carry
+ RSC = 7, // Reverse Subtract with Carry
+ TST = 8, // Test
+ TEQ = 9, // Test Equivalence
+ CMP = 10, // Compare
+ CMN = 11, // Compare Negated
+ ORR = 12, // Logical (inclusive) OR
+ MOV = 13, // Move
+ BIC = 14, // Bit Clear
+ MVN = 15, // Move Not
+ max_operand = 16
};
+// Shifter types for Data-processing operands as defined in section A5.1.2.
enum Shift {
no_shift = -1,
- LSL = 0,
- LSR = 1,
- ASR = 2,
- ROR = 3
+ LSL = 0, // Logical shift left
+ LSR = 1, // Logical shift right
+ ASR = 2, // Arithmetic shift right
+ ROR = 3, // Rotate right
+ max_shift = 4
};
+// Special Software Interrupt codes when used in the presence of the ARM
+// simulator.
enum SoftwareInterruptCodes {
// transition to C code
call_rt_r5 = 0x10,
@@ -102,7 +114,17 @@
// The class Instr enables access to individual fields defined in the ARM
-// architecture.
+// architecture instruction set encoding as described in figure A3-1.
+//
+// Example: Test whether the instruction at ptr does set the condition code
+// bits.
+//
+// bool InstructionSetsConditionCodes(byte* ptr) {
+// Instr *instr = Instr::At(ptr);
+// int type = instr->TypeField();
+// return ((type == 0) || (type == 1)) && instr->HasS();
+// }
+//
class Instr {
public:
enum {
@@ -110,25 +132,29 @@
kPCReadOffset = 8
};
- // Get the raw instruction bits
+ // Get the raw instruction bits.
inline instr_t InstructionBits() const {
return *reinterpret_cast<const instr_t*>(this);
}
+ // Set the raw instruction bits to value.
inline void SetInstructionBits(instr_t value) {
*reinterpret_cast<instr_t*>(this) = value;
}
+ // Read one particular bit out of the instruction bits.
inline int Bit(int nr) const {
return (InstructionBits() >> nr) & 1;
}
+ // Read a bit field out of the instruction bits.
inline int Bits(int hi, int lo) const {
return (InstructionBits() >> lo) & ((2 << (hi - lo)) - 1);
}
// Accessors for the different named fields used in the ARM encoding.
+ // The naming of these accessor corresponds to figure A3-1.
// Generally applicable fields
inline Condition ConditionField() const {
return static_cast<Condition>(Bits(31, 28));
diff --git a/src/d8.cc b/src/d8.cc
index af6eb4c..480d4ae 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -235,6 +235,19 @@
utility_context_->SetSecurityToken(Undefined());
Context::Scope utility_scope(utility_context_);
+ i::JSArguments js_args = i::FLAG_js_arguments;
+ i::Handle<i::FixedArray> arguments_array =
+ i::Factory::NewFixedArray(js_args.argc());
+ for (int j = 0; j < js_args.argc(); j++) {
+ i::Handle<i::String> arg =
+ i::Factory::NewStringFromUtf8(i::CStrVector(js_args[j]));
+ arguments_array->set(j, *arg);
+ }
+ i::Handle<i::JSArray> arguments_jsarray =
+ i::Factory::NewJSArrayWithElements(arguments_array);
+ global_template->Set(String::New("arguments"),
+ Utils::ToLocal(arguments_jsarray));
+
// Install the debugger object in the utility scope
i::Debug::Load();
i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
@@ -318,6 +331,9 @@
int Shell::Main(int argc, char* argv[]) {
i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
+ if (i::FLAG_help) {
+ return 1;
+ }
Initialize();
bool run_shell = (argc == 1);
Context::Scope context_scope(evaluation_context_);
diff --git a/src/date-delay.js b/src/date-delay.js
index 3531266..c1b19e5 100644
--- a/src/date-delay.js
+++ b/src/date-delay.js
@@ -50,6 +50,8 @@
// ECMA 262 - 5.2
function Modulo(value, remainder) {
var mod = value % remainder;
+ // Guard against returning -0.
+ if (mod == 0) return 0;
return mod >= 0 ? mod : mod + remainder;
}
diff --git a/src/debug-delay.js b/src/debug-delay.js
index 783e4b7..4d583b7 100644
--- a/src/debug-delay.js
+++ b/src/debug-delay.js
@@ -357,15 +357,6 @@
}
-// Function called from the runtime to handle a debug request receiced from the
-// debugger. When this function is called the debugger is in the broken state
-// reflected by the exec_state parameter. When pending requests are handled the
-// parameter stopping indicate the expected running state.
-function ProcessDebugRequest(exec_state, request, stopping) {
- return exec_state.debugCommandProcessor().processDebugJSONRequest(request, stopping);
-}
-
-
Debug.addListener = function(listener, opt_data) {
if (!IS_FUNCTION(listener)) throw new Error('Parameters have wrong types.');
%AddDebugEventListener(listener, opt_data);
diff --git a/src/debug.cc b/src/debug.cc
index 33fafe7..7acc117 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -1135,7 +1135,7 @@
bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) {
if (shared->is_compiled()) return true;
- return CompileLazyShared(shared, CLEAR_EXCEPTION);
+ return CompileLazyShared(shared, CLEAR_EXCEPTION, 0);
}
@@ -1371,35 +1371,6 @@
}
-Handle<String> Debugger::ProcessRequest(Handle<Object> exec_state,
- Handle<Object> request,
- bool stopped) {
- // Get the function ProcessDebugRequest (declared in debug.js).
- Handle<JSFunction> process_denbug_request =
- Handle<JSFunction>(JSFunction::cast(
- Debug::debug_context()->global()->GetProperty(
- *Factory::LookupAsciiSymbol("ProcessDebugRequest"))));
-
- // Call ProcessDebugRequest expect String result. The ProcessDebugRequest
- // will never throw an exception (see debug.js).
- bool caught_exception;
- const int argc = 3;
- Object** argv[argc] = { exec_state.location(),
- request.location(),
- stopped ? Factory::true_value().location() :
- Factory::false_value().location()};
- Handle<Object> result = Execution::TryCall(process_denbug_request,
- Factory::undefined_value(),
- argc, argv,
- &caught_exception);
- if (caught_exception) {
- return Factory::empty_symbol();
- }
-
- return Handle<String>::cast(result);
-}
-
-
void Debugger::OnException(Handle<Object> exception, bool uncaught) {
HandleScope scope;
diff --git a/src/debug.h b/src/debug.h
index 69e2aaa..6833982 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -346,9 +346,6 @@
static Handle<Object> MakeCompileEvent(Handle<Script> script,
Handle<Object> script_function,
bool* caught_exception);
- static Handle<String> ProcessRequest(Handle<Object> exec_state,
- Handle<Object> request,
- bool stopped);
static void OnDebugBreak(Handle<Object> break_points_hit);
static void OnException(Handle<Object> exception, bool uncaught);
static void OnBeforeCompile(Handle<Script> script);
diff --git a/src/disasm-arm.cc b/src/disasm-arm.cc
index 4aa9b78..ff7b9ad 100644
--- a/src/disasm-arm.cc
+++ b/src/disasm-arm.cc
@@ -25,6 +25,28 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// A Disassembler object is used to disassemble a block of code instruction by
+// instruction. The default implementation of the NameConverter object can be
+// overriden to modify register names or to do symbol lookup on addresses.
+//
+// The example below will disassemble a block of code and print it to stdout.
+//
+// NameConverter converter;
+// Disassembler d(converter);
+// for (byte* pc = begin; pc < end;) {
+// char buffer[128];
+// buffer[0] = '\0';
+// byte* prev_pc = pc;
+// pc += d.InstructionDecode(buffer, sizeof buffer, pc);
+// printf("%p %08x %s\n",
+// prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
+// }
+//
+// The Disassembler class also has a convenience method to disassemble a block
+// of code into a FILE*, meaning that the above functionality could also be
+// achieved by just calling Disassembler::Disassemble(stdout, begin, end);
+
+
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
@@ -39,6 +61,7 @@
#include "macro-assembler.h"
#include "platform.h"
+
namespace assembler { namespace arm {
namespace v8i = v8::internal;
@@ -66,33 +89,49 @@
int InstructionDecode(byte* instruction);
private:
- const disasm::NameConverter& converter_;
- v8::internal::Vector<char> out_buffer_;
- int out_buffer_pos_;
-
+ // Bottleneck functions to print into the out_buffer.
void PrintChar(const char ch);
void Print(const char* str);
+ // Printing of common values.
void PrintRegister(int reg);
void PrintCondition(Instr* instr);
void PrintShiftRm(Instr* instr);
void PrintShiftImm(Instr* instr);
+ void PrintPU(Instr* instr);
+ void PrintSoftwareInterrupt(SoftwareInterruptCodes swi);
+ // Handle formatting of instructions and their options.
+ int FormatRegister(Instr* instr, const char* option);
int FormatOption(Instr* instr, const char* option);
void Format(Instr* instr, const char* format);
void Unknown(Instr* instr);
- void DecodeType0(Instr* instr);
- void DecodeType1(Instr* instr);
+ // Each of these functions decodes one particular instruction type, a 3-bit
+ // field in the instruction encoding.
+ // Types 0 and 1 are combined as they are largely the same except for the way
+ // they interpret the shifter operand.
+ void DecodeType01(Instr* instr);
void DecodeType2(Instr* instr);
void DecodeType3(Instr* instr);
void DecodeType4(Instr* instr);
void DecodeType5(Instr* instr);
void DecodeType6(Instr* instr);
void DecodeType7(Instr* instr);
+
+ const disasm::NameConverter& converter_;
+ v8::internal::Vector<char> out_buffer_;
+ int out_buffer_pos_;
+
+ DISALLOW_COPY_AND_ASSIGN(Decoder);
};
+// Support for assertions in the Decoder formatting functions.
+#define STRING_STARTS_WITH(string, compare_string) \
+ (strncmp(string, compare_string, strlen(compare_string)) == 0)
+
+
// Append the ch to the output buffer.
void Decoder::PrintChar(const char ch) {
out_buffer_[out_buffer_pos_++] = ch;
@@ -102,7 +141,7 @@
// Append the str to the output buffer.
void Decoder::Print(const char* str) {
char cur = *str++;
- while (cur != 0 && (out_buffer_pos_ < (out_buffer_.length()-1))) {
+ while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
PrintChar(cur);
cur = *str++;
}
@@ -110,9 +149,11 @@
}
-static const char* cond_names[16] = {
-"eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" ,
-"hi", "ls", "ge", "lt", "gt", "le", "", "invalid",
+// These condition names are defined in a way to match the native disassembler
+// formatting. See for example the command "objdump -d <binary file>".
+static const char* cond_names[max_condition] = {
+ "eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" ,
+ "hi", "ls", "ge", "lt", "gt", "le", "", "invalid",
};
@@ -128,7 +169,9 @@
}
-static const char* shift_names[4] = {
+// These shift names are defined in a way to match the native disassembler
+// formatting. See for example the command "objdump -d <binary file>".
+static const char* shift_names[max_shift] = {
"lsl", "lsr", "asr", "ror"
};
@@ -178,6 +221,100 @@
}
+// Print PU formatting to reduce complexity of FormatOption.
+void Decoder::PrintPU(Instr* instr) {
+ switch (instr->PUField()) {
+ case 0: {
+ Print("da");
+ break;
+ }
+ case 1: {
+ Print("ia");
+ break;
+ }
+ case 2: {
+ Print("db");
+ break;
+ }
+ case 3: {
+ Print("ib");
+ break;
+ }
+ default: {
+ UNREACHABLE();
+ break;
+ }
+ }
+}
+
+
+// Print SoftwareInterrupt codes. Factoring this out reduces the complexity of
+// the FormatOption method.
+void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) {
+ switch (swi) {
+ case call_rt_r5:
+ Print("call_rt_r5");
+ return;
+ case call_rt_r2:
+ Print("call_rt_r2");
+ return;
+ case break_point:
+ Print("break_point");
+ return;
+ default:
+ out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+ "%d",
+ swi);
+ return;
+ }
+}
+
+
+// Handle all register based formatting in this function to reduce the
+// complexity of FormatOption.
+int Decoder::FormatRegister(Instr* instr, const char* format) {
+ ASSERT(format[0] == 'r');
+ if (format[1] == 'n') { // 'rn: Rn register
+ int reg = instr->RnField();
+ PrintRegister(reg);
+ return 2;
+ } else if (format[1] == 'd') { // 'rd: Rd register
+ int reg = instr->RdField();
+ PrintRegister(reg);
+ return 2;
+ } else if (format[1] == 's') { // 'rs: Rs register
+ int reg = instr->RsField();
+ PrintRegister(reg);
+ return 2;
+ } else if (format[1] == 'm') { // 'rm: Rm register
+ int reg = instr->RmField();
+ PrintRegister(reg);
+ return 2;
+ } else if (format[1] == 'l') {
+ // 'rlist: register list for load and store multiple instructions
+ ASSERT(STRING_STARTS_WITH(format, "rlist"));
+ int rlist = instr->RlistField();
+ int reg = 0;
+ Print("{");
+ // Print register list in ascending order, by scanning the bit mask.
+ while (rlist != 0) {
+ if ((rlist & 1) != 0) {
+ PrintRegister(reg);
+ if ((rlist >> 1) != 0) {
+ Print(", ");
+ }
+ }
+ reg++;
+ rlist >>= 1;
+ }
+ Print("}");
+ return 5;
+ }
+ UNREACHABLE();
+ return -1;
+}
+
+
// FormatOption takes a formatting string and interprets it based on
// the current instructions. The format string points to the first
// character of the option string (the option escape has already been
@@ -192,20 +329,17 @@
Print("la");
}
return 1;
- break;
}
case 'b': { // 'b: byte loads or stores
if (instr->HasB()) {
Print("b");
}
return 1;
- break;
}
case 'c': { // 'cond: conditional execution
- ASSERT((format[1] == 'o') && (format[2] == 'n') && (format[3] =='d'));
+ ASSERT(STRING_STARTS_WITH(format, "cond"));
PrintCondition(instr);
return 4;
- break;
}
case 'h': { // 'h: halfword operation for extra loads and stores
if (instr->HasH()) {
@@ -214,172 +348,89 @@
Print("b");
}
return 1;
- break;
- }
- case 'i': { // 'imm: immediate value for data processing instructions
- ASSERT((format[1] == 'm') && (format[2] == 'm'));
- PrintShiftImm(instr);
- return 3;
- break;
}
case 'l': { // 'l: branch and link
if (instr->HasLink()) {
Print("l");
}
return 1;
- break;
}
- case 'm': { // 'msg: for simulator break instructions
- if (format[1] == 'e') {
- ASSERT((format[2] == 'm') && (format[3] == 'o') && (format[4] == 'p'));
+ case 'm': {
+ if (format[1] == 'e') { // 'memop: load/store instructions
+ ASSERT(STRING_STARTS_WITH(format, "memop"));
if (instr->HasL()) {
Print("ldr");
} else {
Print("str");
}
return 5;
- } else {
- ASSERT(format[1] == 's' && format[2] == 'g');
- byte* str =
- reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff);
- out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
- "%s", converter_.NameInCode(str));
- return 3;
}
- break;
+ // 'msg: for simulator break instructions
+ ASSERT(STRING_STARTS_WITH(format, "msg"));
+ byte* str =
+ reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff);
+ out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+ "%s", converter_.NameInCode(str));
+ return 3;
}
case 'o': {
- ASSERT(format[1] == 'f' && format[2] == 'f');
if (format[3] == '1') {
// 'off12: 12-bit offset for load and store instructions
- ASSERT(format[4] == '2');
+ ASSERT(STRING_STARTS_WITH(format, "off12"));
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"%d", instr->Offset12Field());
return 5;
- } else {
- // 'off8: 8-bit offset for extra load and store instructions
- ASSERT(format[3] == '8');
- int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField();
- out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
- "%d", offs8);
- return 4;
}
- break;
+ // 'off8: 8-bit offset for extra load and store instructions
+ ASSERT(STRING_STARTS_WITH(format, "off8"));
+ int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField();
+ out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+ "%d", offs8);
+ return 4;
}
case 'p': { // 'pu: P and U bits for load and store instructions
- ASSERT(format[1] == 'u');
- switch (instr->PUField()) {
- case 0: {
- Print("da");
- break;
- }
- case 1: {
- Print("ia");
- break;
- }
- case 2: {
- Print("db");
- break;
- }
- case 3: {
- Print("ib");
- break;
- }
- default: {
- UNREACHABLE();
- break;
- }
- }
+ ASSERT(STRING_STARTS_WITH(format, "pu"));
+ PrintPU(instr);
return 2;
- break;
}
case 'r': {
- if (format[1] == 'n') { // 'rn: Rn register
- int reg = instr->RnField();
- PrintRegister(reg);
- return 2;
- } else if (format[1] == 'd') { // 'rd: Rd register
- int reg = instr->RdField();
- PrintRegister(reg);
- return 2;
- } else if (format[1] == 's') { // 'rs: Rs register
- int reg = instr->RsField();
- PrintRegister(reg);
- return 2;
- } else if (format[1] == 'm') { // 'rm: Rm register
- int reg = instr->RmField();
- PrintRegister(reg);
- return 2;
- } else if (format[1] == 'l') {
- // 'rlist: register list for load and store multiple instructions
- ASSERT(format[2] == 'i' && format[3] == 's' && format[4] == 't');
- int rlist = instr->RlistField();
- int reg = 0;
- Print("{");
- while (rlist != 0) {
- if ((rlist & 1) != 0) {
- PrintRegister(reg);
- if ((rlist >> 1) != 0) {
- Print(", ");
- }
- }
- reg++;
- rlist >>= 1;
- }
- Print("}");
- return 5;
- } else {
- UNREACHABLE();
- }
- UNREACHABLE();
- return -1;
- break;
+ return FormatRegister(instr, format);
}
case 's': {
- if (format[1] == 'h') { // 'shift_rm: register shift operands
- ASSERT(format[2] == 'i' && format[3] == 'f' && format[4] == 't'
- && format[5] == '_' && format[6] == 'r' && format[7] == 'm');
- PrintShiftRm(instr);
- return 8;
- } else if (format[1] == 'w') {
- ASSERT(format[2] == 'i');
- SoftwareInterruptCodes swi = instr->SwiField();
- switch (swi) {
- case call_rt_r5:
- Print("call_rt_r5");
- break;
- case call_rt_r2:
- Print("call_rt_r2");
- break;
- case break_point:
- Print("break_point");
- break;
- default:
- out_buffer_pos_ += v8i::OS::SNPrintF(
- out_buffer_ + out_buffer_pos_,
- "%d",
- swi);
- break;
+ if (format[1] == 'h') { // 'shift_op or 'shift_rm
+ if (format[6] == 'o') { // 'shift_op
+ ASSERT(STRING_STARTS_WITH(format, "shift_op"));
+ if (instr->TypeField() == 0) {
+ PrintShiftRm(instr);
+ } else {
+ ASSERT(instr->TypeField() == 1);
+ PrintShiftImm(instr);
+ }
+ return 8;
+ } else { // 'shift_rm
+ ASSERT(STRING_STARTS_WITH(format, "shift_rm"));
+ PrintShiftRm(instr);
+ return 8;
}
+ } else if (format[1] == 'w') { // 'swi
+ ASSERT(STRING_STARTS_WITH(format, "swi"));
+ PrintSoftwareInterrupt(instr->SwiField());
return 3;
} else if (format[1] == 'i') { // 'sign: signed extra loads and stores
- ASSERT(format[2] == 'g' && format[3] == 'n');
+ ASSERT(STRING_STARTS_WITH(format, "sign"));
if (instr->HasSign()) {
Print("s");
}
return 4;
- break;
- } else { // 's: S field of data processing instructions
- if (instr->HasS()) {
- Print("s");
- }
- return 1;
}
- break;
+ // 's: S field of data processing instructions
+ if (instr->HasS()) {
+ Print("s");
+ }
+ return 1;
}
case 't': { // 'target: target of branch instructions
- ASSERT(format[1] == 'a' && format[2] == 'r' && format[3] == 'g'
- && format[4] == 'e' && format[5] == 't');
+ ASSERT(STRING_STARTS_WITH(format, "target"));
int off = (instr->SImmed24Field() << 2) + 8;
out_buffer_pos_ += v8i::OS::SNPrintF(
out_buffer_ + out_buffer_pos_,
@@ -387,7 +438,6 @@
off,
converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
return 6;
- break;
}
case 'u': { // 'u: signed or unsigned multiplies
if (instr->Bit(22) == 0) {
@@ -396,14 +446,12 @@
Print("s");
}
return 1;
- break;
}
case 'w': { // 'w: W field of load and store instructions
if (instr->HasW()) {
Print("!");
}
return 1;
- break;
}
default: {
UNREACHABLE();
@@ -439,8 +487,9 @@
}
-void Decoder::DecodeType0(Instr* instr) {
- if (instr->IsSpecialType0()) {
+void Decoder::DecodeType01(Instr* instr) {
+ int type = instr->TypeField();
+ if ((type == 0) && instr->IsSpecialType0()) {
// multiply instruction or extra loads and stores
if (instr->Bits(7, 4) == 9) {
if (instr->Bit(24) == 0) {
@@ -503,87 +552,83 @@
} else {
switch (instr->OpcodeField()) {
case AND: {
- Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "and'cond's 'rd, 'rn, 'shift_op");
break;
}
case EOR: {
- Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "eor'cond's 'rd, 'rn, 'shift_op");
break;
}
case SUB: {
- Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "sub'cond's 'rd, 'rn, 'shift_op");
break;
}
case RSB: {
- Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "rsb'cond's 'rd, 'rn, 'shift_op");
break;
}
case ADD: {
- Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "add'cond's 'rd, 'rn, 'shift_op");
break;
}
case ADC: {
- Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "adc'cond's 'rd, 'rn, 'shift_op");
break;
}
case SBC: {
- Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "sbc'cond's 'rd, 'rn, 'shift_op");
break;
}
case RSC: {
- Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "rsc'cond's 'rd, 'rn, 'shift_op");
break;
}
case TST: {
if (instr->HasS()) {
- Format(instr, "tst'cond 'rn, 'shift_rm");
+ Format(instr, "tst'cond 'rn, 'shift_op");
} else {
Unknown(instr); // not used by V8
- return;
}
break;
}
case TEQ: {
if (instr->HasS()) {
- Format(instr, "teq'cond 'rn, 'shift_rm");
+ Format(instr, "teq'cond 'rn, 'shift_op");
} else {
Unknown(instr); // not used by V8
- return;
}
break;
}
case CMP: {
if (instr->HasS()) {
- Format(instr, "cmp'cond 'rn, 'shift_rm");
+ Format(instr, "cmp'cond 'rn, 'shift_op");
} else {
Unknown(instr); // not used by V8
- return;
}
break;
}
case CMN: {
if (instr->HasS()) {
- Format(instr, "cmn'cond 'rn, 'shift_rm");
+ Format(instr, "cmn'cond 'rn, 'shift_op");
} else {
Unknown(instr); // not used by V8
- return;
}
break;
}
case ORR: {
- Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "orr'cond's 'rd, 'rn, 'shift_op");
break;
}
case MOV: {
- Format(instr, "mov'cond's 'rd, 'shift_rm");
+ Format(instr, "mov'cond's 'rd, 'shift_op");
break;
}
case BIC: {
- Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
+ Format(instr, "bic'cond's 'rd, 'rn, 'shift_op");
break;
}
case MVN: {
- Format(instr, "mvn'cond's 'rd, 'shift_rm");
+ Format(instr, "mvn'cond's 'rd, 'shift_op");
break;
}
default: {
@@ -596,107 +641,11 @@
}
-void Decoder::DecodeType1(Instr* instr) {
- switch (instr->OpcodeField()) {
- case AND: {
- Format(instr, "and'cond's 'rd, 'rn, 'imm");
- break;
- }
- case EOR: {
- Format(instr, "eor'cond's 'rd, 'rn, 'imm");
- break;
- }
- case SUB: {
- Format(instr, "sub'cond's 'rd, 'rn, 'imm");
- break;
- }
- case RSB: {
- Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
- break;
- }
- case ADD: {
- Format(instr, "add'cond's 'rd, 'rn, 'imm");
- break;
- }
- case ADC: {
- Format(instr, "adc'cond's 'rd, 'rn, 'imm");
- break;
- }
- case SBC: {
- Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
- break;
- }
- case RSC: {
- Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
- break;
- }
- case TST: {
- if (instr->HasS()) {
- Format(instr, "tst'cond 'rn, 'imm");
- } else {
- Unknown(instr); // not used by V8
- return;
- }
- break;
- }
- case TEQ: {
- if (instr->HasS()) {
- Format(instr, "teq'cond 'rn, 'imm");
- } else {
- Unknown(instr); // not used by V8
- return;
- }
- break;
- }
- case CMP: {
- if (instr->HasS()) {
- Format(instr, "cmp'cond 'rn, 'imm");
- } else {
- Unknown(instr); // not used by V8
- return;
- }
- break;
- }
- case CMN: {
- if (instr->HasS()) {
- Format(instr, "cmn'cond 'rn, 'imm");
- } else {
- Unknown(instr); // not used by V8
- return;
- }
- break;
- }
- case ORR: {
- Format(instr, "orr'cond's 'rd, 'rn, 'imm");
- break;
- }
- case MOV: {
- Format(instr, "mov'cond's 'rd, 'imm");
- break;
- }
- case BIC: {
- Format(instr, "bic'cond's 'rd, 'rn, 'imm");
- break;
- }
- case MVN: {
- Format(instr, "mvn'cond's 'rd, 'imm");
- break;
- }
- default: {
- // The Opcode field is a 4-bit field.
- UNREACHABLE();
- break;
- }
- }
-}
-
-
void Decoder::DecodeType2(Instr* instr) {
switch (instr->PUField()) {
case 0: {
if (instr->HasW()) {
Unknown(instr); // not used in V8
- return;
}
Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
break;
@@ -704,7 +653,6 @@
case 1: {
if (instr->HasW()) {
Unknown(instr); // not used in V8
- return;
}
Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
break;
@@ -798,12 +746,9 @@
return Instr::kInstrSize;
}
switch (instr->TypeField()) {
- case 0: {
- DecodeType0(instr);
- break;
- }
+ case 0:
case 1: {
- DecodeType1(instr);
+ DecodeType01(instr);
break;
}
case 2: {
@@ -848,8 +793,15 @@
namespace disasm {
-static const char* reg_names[16] = {
- "r0", "r1", "r2" , "r3" , "r4" , "r5" , "r6" , "r7" ,
+namespace v8i = v8::internal;
+
+
+static const int kMaxRegisters = 16;
+
+// These register names are defined in a way to match the native disassembler
+// formatting. See for example the command "objdump -d <binary file>".
+static const char* reg_names[kMaxRegisters] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc",
};
@@ -868,7 +820,7 @@
const char* NameConverter::NameOfCPURegister(int reg) const {
const char* result;
- if ((0 <= reg) && (reg < 16)) {
+ if ((0 <= reg) && (reg < kMaxRegisters)) {
result = reg_names[reg];
} else {
result = "noreg";
@@ -892,11 +844,6 @@
//------------------------------------------------------------------------------
-static NameConverter defaultConverter;
-
-Disassembler::Disassembler() : converter_(defaultConverter) {}
-
-
Disassembler::Disassembler(const NameConverter& converter)
: converter_(converter) {}
@@ -922,7 +869,8 @@
void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
- Disassembler d;
+ NameConverter converter;
+ Disassembler d(converter);
for (byte* pc = begin; pc < end;) {
v8::internal::EmbeddedVector<char, 128> buffer;
buffer[0] = '\0';
diff --git a/src/disasm-ia32.cc b/src/disasm-ia32.cc
index 1648d69..1764e52 100644
--- a/src/disasm-ia32.cc
+++ b/src/disasm-ia32.cc
@@ -1095,11 +1095,6 @@
//------------------------------------------------------------------------------
-static NameConverter defaultConverter;
-
-Disassembler::Disassembler() : converter_(defaultConverter) {}
-
-
Disassembler::Disassembler(const NameConverter& converter)
: converter_(converter) {}
@@ -1119,7 +1114,8 @@
/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
- Disassembler d;
+ NameConverter converter;
+ Disassembler d(converter);
for (byte* pc = begin; pc < end;) {
v8::internal::EmbeddedVector<char, 128> buffer;
buffer[0] = '\0';
diff --git a/src/disasm.h b/src/disasm.h
index 1b72ee1..1fd5519 100644
--- a/src/disasm.h
+++ b/src/disasm.h
@@ -49,9 +49,6 @@
// A generic Disassembler interface
class Disassembler {
public:
- // Uses default NameConverter.
- Disassembler();
-
// Caller deallocates converter.
explicit Disassembler(const NameConverter& converter);
@@ -70,6 +67,8 @@
static void Disassemble(FILE* f, byte* begin, byte* end);
private:
const NameConverter& converter_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Disassembler);
};
} // namespace disasm
diff --git a/src/disassembler.cc b/src/disassembler.cc
index 12183d5..53f594f 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -217,7 +217,7 @@
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
relocinfo.target_object()->ShortPrint(&accumulator);
- SmartPointer<char> obj_name = accumulator.ToCString();
+ SmartPointer<const char> obj_name = accumulator.ToCString();
out.AddFormatted(" ;; object: %s", *obj_name);
} else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
const char* reference_name =
diff --git a/src/execution.cc b/src/execution.cc
index 0598ad7..9f5bd83 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -96,16 +96,14 @@
ASSERT(*has_pending_exception == Top::has_pending_exception());
if (*has_pending_exception) {
Top::setup_external_caught();
- }
-
- // If the pending exception is OutOfMemoryException set out_of_memory in
- // the global context. Note: We have to mark the global context here
- // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
- // set it.
- if (*has_pending_exception) {
+ // If the pending exception is OutOfMemoryException set out_of_memory in
+ // the global context. Note: We have to mark the global context here
+ // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
+ // set it.
if (Top::pending_exception() == Failure::OutOfMemoryException()) {
Top::context()->mark_out_of_memory();
}
+ return Handle<Object>();
}
return Handle<Object>(value);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index c082a78..5c96429 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -69,10 +69,27 @@
#error No mode supplied when including flags.defs
#endif
+#ifdef FLAG_MODE_DECLARE
+// Structure used to hold a collection of arguments to the JavaScript code.
+struct JSArguments {
+public:
+ JSArguments();
+ JSArguments(int argc, const char** argv);
+ int argc() const;
+ const char** argv();
+ const char*& operator[](int idx);
+ JSArguments& operator=(JSArguments args);
+private:
+ int argc_;
+ const char** argv_;
+};
+#endif
+
#define DEFINE_bool(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt)
#define DEFINE_int(nam, def, cmt) FLAG(INT, int, nam, def, cmt)
#define DEFINE_float(nam, def, cmt) FLAG(FLOAT, double, nam, def, cmt)
#define DEFINE_string(nam, def, cmt) FLAG(STRING, const char*, nam, def, cmt)
+#define DEFINE_args(nam, def, cmt) FLAG(ARGS, JSArguments, nam, def, cmt)
//
// Flags in all modes.
@@ -200,7 +217,10 @@
// Dev shell flags
//
+DEFINE_bool(help, false, "Print usage message, including flags, on console")
DEFINE_bool(dump_counters, false, "Dump counters on exit")
+DEFINE_args(js_arguments, JSArguments(),
+ "Pass all remaining arguments to the script. Alias for \"--\".")
//
// Debug only flags
diff --git a/src/flags.cc b/src/flags.cc
index 73bb855..48b4ef7 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -31,6 +31,9 @@
#include "v8.h"
#include "platform.h"
+#include "smart-pointer.h"
+#include "string-stream.h"
+
namespace v8 { namespace internal {
@@ -48,7 +51,7 @@
// to the actual flag, default value, comment, etc. This is designed to be POD
// initialized as to avoid requiring static constructors.
struct Flag {
- enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING };
+ enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_ARGS };
FlagType type_; // What type of flag, bool, int, or string.
const char* name_; // Name of the flag, ex "my_flag".
@@ -82,6 +85,11 @@
return reinterpret_cast<const char**>(valptr_);
}
+ JSArguments* args_variable() const {
+ ASSERT(type_ == TYPE_ARGS);
+ return reinterpret_cast<JSArguments*>(valptr_);
+ }
+
bool bool_default() const {
ASSERT(type_ == TYPE_BOOL);
return *reinterpret_cast<const bool*>(defptr_);
@@ -102,6 +110,11 @@
return *reinterpret_cast<const char* const *>(defptr_);
}
+ JSArguments args_default() const {
+ ASSERT(type_ == TYPE_ARGS);
+ return *reinterpret_cast<const JSArguments*>(defptr_);
+ }
+
// Compare this flag's current value against the default.
bool IsDefault() const {
switch (type_) {
@@ -111,12 +124,15 @@
return *int_variable() == int_default();
case TYPE_FLOAT:
return *float_variable() == float_default();
- case TYPE_STRING:
+ case TYPE_STRING: {
const char* str1 = *string_variable();
const char* str2 = string_default();
if (str2 == NULL) return str1 == NULL;
if (str1 == NULL) return str2 == NULL;
return strcmp(str1, str2) == 0;
+ }
+ case TYPE_ARGS:
+ return args_variable()->argc() == 0;
}
UNREACHABLE();
return true;
@@ -137,6 +153,9 @@
case TYPE_STRING:
*string_variable() = string_default();
break;
+ case TYPE_ARGS:
+ *args_variable() = args_default();
+ break;
}
}
};
@@ -157,67 +176,81 @@
case Flag::TYPE_INT: return "int";
case Flag::TYPE_FLOAT: return "float";
case Flag::TYPE_STRING: return "string";
+ case Flag::TYPE_ARGS: return "arguments";
}
UNREACHABLE();
return NULL;
}
-static char* ToString(Flag* flag) {
- Vector<char> value;
+static SmartPointer<const char> ToString(Flag* flag) {
+ HeapStringAllocator string_allocator;
+ StringStream buffer(&string_allocator);
switch (flag->type()) {
case Flag::TYPE_BOOL:
- value = Vector<char>::New(6);
- OS::SNPrintF(value, "%s", (*flag->bool_variable() ? "true" : "false"));
+ buffer.Add("%s", (*flag->bool_variable() ? "true" : "false"));
break;
case Flag::TYPE_INT:
- value = Vector<char>::New(12);
- OS::SNPrintF(value, "%d", *flag->int_variable());
+ buffer.Add("%d", *flag->int_variable());
break;
case Flag::TYPE_FLOAT:
- value = Vector<char>::New(20);
- OS::SNPrintF(value, "%f", *flag->float_variable());
+ buffer.Add("%f", FmtElm(*flag->float_variable()));
break;
- case Flag::TYPE_STRING:
+ case Flag::TYPE_STRING: {
const char* str = *flag->string_variable();
- if (str) {
- int length = strlen(str) + 1;
- value = Vector<char>::New(length);
- OS::SNPrintF(value, "%s", str);
- } else {
- value = Vector<char>::New(5);
- OS::SNPrintF(value, "NULL");
+ buffer.Add("%s", str ? str : "NULL");
+ break;
+ }
+ case Flag::TYPE_ARGS: {
+ JSArguments args = *flag->args_variable();
+ if (args.argc() > 0) {
+ buffer.Add("%s", args[0]);
+ for (int i = 1; i < args.argc(); i++) {
+ buffer.Add(" %s", args[i]);
+ }
}
break;
+ }
}
- ASSERT(!value.is_empty());
- return value.start();
+ return buffer.ToCString();
}
// static
-List<char *>* FlagList::argv() {
- List<char *>* args = new List<char*>(8);
+List<const char*>* FlagList::argv() {
+ List<const char*>* args = new List<const char*>(8);
+ Flag* args_flag = NULL;
for (size_t i = 0; i < num_flags; ++i) {
Flag* f = &flags[i];
if (!f->IsDefault()) {
- Vector<char> cmdline_flag;
- if (f->type() != Flag::TYPE_BOOL || *(f->bool_variable())) {
- int length = strlen(f->name()) + 2 + 1;
- cmdline_flag = Vector<char>::New(length);
- OS::SNPrintF(cmdline_flag, "--%s", f->name());
- } else {
- int length = strlen(f->name()) + 4 + 1;
- cmdline_flag = Vector<char>::New(length);
- OS::SNPrintF(cmdline_flag, "--no%s", f->name());
+ if (f->type() == Flag::TYPE_ARGS) {
+ ASSERT(args_flag == NULL);
+ args_flag = f; // Must be last in arguments.
+ continue;
}
- args->Add(cmdline_flag.start());
+ HeapStringAllocator string_allocator;
+ StringStream buffer(&string_allocator);
+ if (f->type() != Flag::TYPE_BOOL || *(f->bool_variable())) {
+ buffer.Add("--%s", f->name());
+ } else {
+ buffer.Add("--no%s", f->name());
+ }
+ args->Add(buffer.ToCString().Detach());
if (f->type() != Flag::TYPE_BOOL) {
- args->Add(ToString(f));
+ args->Add(ToString(f).Detach());
}
}
}
-
+ if (args_flag != NULL) {
+ HeapStringAllocator string_allocator;
+ StringStream buffer(&string_allocator);
+ buffer.Add("--%s", args_flag->name());
+ args->Add(buffer.ToCString().Detach());
+ JSArguments jsargs = *args_flag->args_variable();
+ for (int j = 0; j < jsargs.argc(); j++) {
+ args->Add(OS::StrDup(jsargs[j]));
+ }
+ }
return args;
}
@@ -239,8 +272,14 @@
if (*arg == '-') {
// find the begin of the flag name
arg++; // remove 1st '-'
- if (*arg == '-')
+ if (*arg == '-') {
arg++; // remove 2nd '-'
+ if (arg[0] == '\0') {
+ const char* kJSArgumentsFlagName = "js_arguments";
+ *name = kJSArgumentsFlagName;
+ return;
+ }
+ }
if (arg[0] == 'n' && arg[1] == 'o') {
arg += 2; // remove "no"
*is_bool = true;
@@ -317,17 +356,21 @@
// sense there.
continue;
} else {
- fprintf(stderr, "Error: unrecognized flag %s\n", arg);
+ fprintf(stderr, "Error: unrecognized flag %s\n"
+ "Try --help for options\n", arg);
return j;
}
}
// if we still need a flag value, use the next argument if available
- if (flag->type() != Flag::TYPE_BOOL && value == NULL) {
+ if (flag->type() != Flag::TYPE_BOOL &&
+ flag->type() != Flag::TYPE_ARGS &&
+ value == NULL) {
if (i < *argc) {
value = argv[i++];
} else {
- fprintf(stderr, "Error: missing value for flag %s of type %s\n",
+ fprintf(stderr, "Error: missing value for flag %s of type %s\n"
+ "Try --help for options\n",
arg, Type2String(flag->type()));
return j;
}
@@ -348,21 +391,38 @@
case Flag::TYPE_STRING:
*flag->string_variable() = value;
break;
+ case Flag::TYPE_ARGS: {
+ int start_pos = (value == NULL) ? i : i - 1;
+ int js_argc = *argc - start_pos;
+ const char** js_argv = NewArray<const char*>(js_argc);
+ if (value != NULL) {
+ js_argv[0] = value;
+ }
+ for (int k = i; k < *argc; k++) {
+ js_argv[k - start_pos] = argv[k];
+ }
+ *flag->args_variable() = JSArguments(js_argc, js_argv);
+ i = *argc; // Consume all arguments
+ break;
+ }
}
// handle errors
if ((flag->type() == Flag::TYPE_BOOL && value != NULL) ||
(flag->type() != Flag::TYPE_BOOL && is_bool) ||
*endp != '\0') {
- fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
+ fprintf(stderr, "Error: illegal value for flag %s of type %s\n"
+ "Try --help for options\n",
arg, Type2String(flag->type()));
return j;
}
// remove the flag & value from the command
- if (remove_flags)
- while (j < i)
+ if (remove_flags) {
+ while (j < i) {
argv[j++] = NULL;
+ }
+ }
}
}
@@ -376,6 +436,9 @@
*argc = j;
}
+ if (FLAG_help) {
+ PrintHelp();
+ }
// parsed all flags successfully
return 0;
}
@@ -447,13 +510,38 @@
// static
void FlagList::PrintHelp() {
+ printf("Usage:\n");
+ printf(" shell [options] -e string\n");
+ printf(" execute string in V8\n");
+ printf(" shell [options] file1 file2 ... filek\n");
+ printf(" run JavaScript scripts in file1, file2, ..., filek\n");
+ printf(" shell [options]\n");
+ printf(" shell [options] --shell\n");
+ printf(" run an interactive JavaScript shell");
+ printf(" d8 [options] file\n");
+ printf(" d8 [options]\n");
+ printf(" run the new debugging shell\n\n");
+ printf("Options:\n");
for (size_t i = 0; i < num_flags; ++i) {
Flag* f = &flags[i];
- char* value = ToString(f);
- printf(" --%s (%s) type: %s default: %s\n",
- f->name(), f->comment(), Type2String(f->type()), value);
- DeleteArray(value);
+ SmartPointer<const char> value = ToString(f);
+ printf(" --%s (%s)\n type: %s default: %s\n",
+ f->name(), f->comment(), Type2String(f->type()), *value);
}
}
+JSArguments::JSArguments()
+ : argc_(0), argv_(NULL) {}
+JSArguments::JSArguments(int argc, const char** argv)
+ : argc_(argc), argv_(argv) {}
+int JSArguments::argc() const { return argc_; }
+const char** JSArguments::argv() { return argv_; }
+const char*& JSArguments::operator[](int idx) { return argv_[idx]; }
+JSArguments& JSArguments::operator=(JSArguments args) {
+ argc_ = args.argc_;
+ argv_ = args.argv_;
+ return *this;
+}
+
+
} } // namespace v8::internal
diff --git a/src/flags.h b/src/flags.h
index 813ea95..e6cbe3c 100644
--- a/src/flags.h
+++ b/src/flags.h
@@ -43,14 +43,15 @@
// argv array passed to the main function, e.g.
// ("--prof", "--log-file", "v8.prof", "--nolazy").
//
- // The caller is responsible for disposing the list.
- static List<char *>* argv();
+ // The caller is responsible for disposing the list, as well
+ // as every element of it.
+ static List<const char*>* argv();
// Set the flag values by parsing the command line. If remove_flags is
// set, the flags and associated values are removed from (argc,
// argv). Returns 0 if no error occurred. Otherwise, returns the argv
// index > 0 for the argument where an error occurred. In that case,
- // (argc, argv) will remain unchanged indepdendent of the remove_flags
+ // (argc, argv) will remain unchanged independent of the remove_flags
// value, and no assumptions about flag settings should be made.
//
// The following syntax for flags is accepted (both '-' and '--' are ok):
@@ -59,6 +60,7 @@
// --noflag (bool flags only)
// --flag=value (non-bool flags only, no spaces around '=')
// --flag value (non-bool flags only)
+ // -- (equivalent to --js_arguments, captures all remaining args)
static int SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags);
// Set the flag values by parsing the string str. Splits string into argc
diff --git a/src/global-handles.cc b/src/global-handles.cc
index bb36e35..29ad86e 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -96,6 +96,7 @@
// Make this handle weak.
void MakeWeak(void* parameter, WeakReferenceCallback callback) {
LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
+ ASSERT(state_ != DESTROYED);
if (state_ != WEAK && !IsNearDeath()) {
GlobalHandles::number_of_weak_handles_++;
if (object_->IsJSGlobalObject()) {
@@ -109,6 +110,7 @@
void ClearWeakness() {
LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
+ ASSERT(state_ != DESTROYED);
if (state_ == WEAK || IsNearDeath()) {
GlobalHandles::number_of_weak_handles_--;
if (object_->IsJSGlobalObject()) {
diff --git a/src/globals.h b/src/globals.h
index cc0dbde..387ed88 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -25,6 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifndef V8_GLOBALS_H_
+#define V8_GLOBALS_H_
+
// -----------------------------------------------------------------------------
// Types
// Windows is missing the stdint.h header file. Instead we define standard
@@ -58,9 +61,6 @@
// defined here because the platform code uses bool, and platform.h is
// include very early in the main include file.
-#ifndef V8_GLOBALS_H_
-#define V8_GLOBALS_H_
-
#ifdef USE_MYBOOL
typedef unsigned int __my_bool__;
#define bool __my_bool__ // use 'indirection' to avoid name clashes
@@ -282,6 +282,8 @@
enum InlineCacheState {
// Has never been executed.
UNINITIALIZED,
+ // Has never been executed, but is in a loop.
+ UNINITIALIZED_IN_LOOP,
// Has been executed but monomorhic state has been delayed.
PREMONOMORPHIC,
// Has been executed and only one receiver type has been seen.
diff --git a/src/handles-inl.h b/src/handles-inl.h
index 502aeab..0f804d7 100644
--- a/src/handles-inl.h
+++ b/src/handles-inl.h
@@ -36,6 +36,7 @@
template<class T>
Handle<T>::Handle(T* obj) {
+ ASSERT(!obj->IsFailure());
location_ = reinterpret_cast<T**>(HandleScope::CreateHandle(obj));
}
diff --git a/src/handles.cc b/src/handles.cc
index ada10f1..a33cbfc 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -422,10 +422,11 @@
bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag) {
+ ClearExceptionFlag flag,
+ int loop_nesting) {
// Compile the source information to a code object.
ASSERT(!shared->is_compiled());
- bool result = Compiler::CompileLazy(shared);
+ bool result = Compiler::CompileLazy(shared, loop_nesting);
ASSERT(result != Top::has_pending_exception());
if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception();
return result;
@@ -435,10 +436,16 @@
bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) {
// Compile the source information to a code object.
Handle<SharedFunctionInfo> shared(function->shared());
- return CompileLazyShared(shared, flag);
+ return CompileLazyShared(shared, flag, 0);
}
+bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag) {
+ // Compile the source information to a code object.
+ Handle<SharedFunctionInfo> shared(function->shared());
+ return CompileLazyShared(shared, flag, 1);
+}
+
OptimizedObjectForAddingMultipleProperties::
OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
bool condition) {
diff --git a/src/handles.h b/src/handles.h
index a9adf3d..6d75c77 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -194,9 +194,13 @@
// Do lazy compilation of the given function. Returns true on success
// and false if the compilation resulted in a stack overflow.
enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION };
+
bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag);
+ ClearExceptionFlag flag,
+ int loop_nesting);
+
bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag);
+bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag);
// These deal with lazily loaded properties.
void SetupLazy(Handle<JSFunction> fun,
diff --git a/src/ic-arm.cc b/src/ic-arm.cc
index ccaf277..92eb5d3 100644
--- a/src/ic-arm.cc
+++ b/src/ic-arm.cc
@@ -136,24 +136,9 @@
__ ldr(r0, MemOperand(sp, 0));
- // Check that the receiver isn't a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &miss);
-
- // Check that the object is a JS array.
- __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
- __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
- __ cmp(r1, Operand(JS_ARRAY_TYPE));
- __ b(ne, &miss);
-
- // Load length directly from the JS array.
- __ ldr(r0, FieldMemOperand(r0, JSArray::kLengthOffset));
- __ Ret();
-
- // Cache miss: Jump to runtime.
+ StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
- __ Jump(ic, RelocInfo::CODE_TARGET);
+ StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
}
@@ -185,7 +170,6 @@
// -- lr : return address
// -- [sp] : receiver
// -----------------------------------
-
Label miss, load_length, check_wrapper;
__ ldr(r0, MemOperand(sp, 0));
@@ -216,8 +200,7 @@
// Cache miss: Jump to runtime.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
- __ Jump(ic, RelocInfo::CODE_TARGET);
+ StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
}
@@ -509,33 +492,87 @@
// -- [sp] : receiver
// -----------------------------------
- __ ldr(r0, MemOperand(sp, 0));
- __ push(r0);
- __ push(r2);
+ __ ldr(r3, MemOperand(sp, 0));
+ __ stm(db_w, sp, r2.bit() | r3.bit());
// Perform tail call to the entry.
__ TailCallRuntime(f, 2);
}
-// TODO(1224671): ICs for keyed load/store is not implemented on ARM.
+// TODO(1224671): ICs for keyed load/store is not completed on ARM.
+Object* KeyedLoadIC_Miss(Arguments args);
+
+
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
+ Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
}
+
void KeyedLoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
+ // ---------- S t a t e --------------
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[4] : receiver
+ __ ldm(ia, sp, r2.bit() | r3.bit());
+ __ stm(db_w, sp, r2.bit() | r3.bit());
+
+ __ TailCallRuntime(f, 2);
}
+
+// TODO(1224671): implement the fast case.
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
+ // ---------- S t a t e --------------
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[4] : receiver
+
+ KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
}
+
void KeyedStoreIC::Generate(MacroAssembler* masm,
const ExternalReference& f) {
+ // ---------- S t a t e --------------
+ // -- r0 : value
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[1] : receiver
+
+ __ ldm(ia, sp, r2.bit() | r3.bit());
+ __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit());
+
+ __ TailCallRuntime(f, 3);
}
+
+// TODO(1224671): implement the fast case.
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
+ // ---------- S t a t e --------------
+ // -- r0 : value
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[1] : receiver
+
+ KeyedStoreIC::Generate(masm, ExternalReference(Runtime::kSetProperty));
}
+
void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
+ // ---------- S t a t e --------------
+ // -- r0 : value
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[1] : receiver
+ // ----------- S t a t e -------------
+
+ __ ldm(ia, sp, r2.bit() | r3.bit());
+ __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit());
+
+ // Perform tail call to the entry.
+ __ TailCallRuntime(
+ ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
}
diff --git a/src/ic-ia32.cc b/src/ic-ia32.cc
index 82eb14d..11e55a9 100644
--- a/src/ic-ia32.cc
+++ b/src/ic-ia32.cc
@@ -538,17 +538,17 @@
__ EnterInternalFrame();
// Push the receiver and the name of the function.
- __ push(Operand(edx));
- __ push(Operand(ebx));
+ __ push(edx);
+ __ push(ebx);
// Call the entry.
CEntryStub stub;
- __ mov(Operand(eax), Immediate(2));
- __ mov(Operand(ebx), Immediate(f));
+ __ mov(eax, Immediate(2));
+ __ mov(ebx, Immediate(f));
__ CallStub(&stub);
// Move result to edi and exit the internal frame.
- __ mov(Operand(edi), eax);
+ __ mov(edi, eax);
__ LeaveInternalFrame();
// Check if the receiver is a global object of some sort.
diff --git a/src/ic.cc b/src/ic.cc
index 2ec7b09..c0b7624 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -41,6 +41,7 @@
static char TransitionMarkFromState(IC::State state) {
switch (state) {
case UNINITIALIZED: return '0';
+ case UNINITIALIZED_IN_LOOP: return 'L';
case PREMONOMORPHIC: return '0';
case MONOMORPHIC: return '1';
case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
@@ -223,7 +224,8 @@
void CallIC::Clear(Address address, Code* target) {
- if (target->ic_state() == UNINITIALIZED) return;
+ State state = target->ic_state();
+ if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP) return;
Code* code = StubCache::FindCallInitialize(target->arguments_count());
SetTargetAtAddress(address, code);
}
@@ -434,8 +436,9 @@
if (code->IsFailure()) return;
// Patch the call site depending on the state of the cache.
- if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
- state == MONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
+ if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP ||
+ state == PREMONOMORPHIC || state == MONOMORPHIC ||
+ state == MONOMORPHIC_PROTOTYPE_FAILURE) {
set_target(Code::cast(code));
}
@@ -1044,7 +1047,17 @@
ASSERT(args.length() == 2);
CallIC ic;
IC::State state = IC::StateFrom(ic.target(), args[0]);
- return ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
+ Object* result =
+ ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
+ if (state != UNINITIALIZED_IN_LOOP || !result->IsJSFunction())
+ return result;
+
+ // Compile the function with the knowledge that it's called from
+ // within a loop. This enables further optimization of the function.
+ HandleScope scope;
+ Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result));
+ if (!function->is_compiled()) CompileLazyInLoop(function, CLEAR_EXCEPTION);
+ return *function;
}
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index c747020..2dd21bd 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -383,7 +383,8 @@
(error_message == NULL) ? "Unknown regexp error" : error_message)));
Handle<Object> regexp_err =
Factory::NewSyntaxError("malformed_regexp", array);
- return Handle<Object>(Top::Throw(*regexp_err));
+ Top::Throw(*regexp_err);
+ return Handle<Object>();
}
// Convert the return address to a ByteArray pointer.
diff --git a/src/log.cc b/src/log.cc
index bd85fea..803dfe8 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -728,7 +728,7 @@
stream.Put(*p);
}
}
- SmartPointer<char> expanded = stream.ToCString();
+ SmartPointer<const char> expanded = stream.ToCString();
logfile_ = OS::FOpen(*expanded, "w");
} else {
logfile_ = OS::FOpen(FLAG_logfile, "w");
diff --git a/src/log.h b/src/log.h
index 1fd2b75..eb082da 100644
--- a/src/log.h
+++ b/src/log.h
@@ -113,7 +113,6 @@
// snapshot.
static void Preamble(const char* content);
- // ==== Events that are always logged. ====
// Emits an event with a string value -> (name, value).
static void StringEvent(const char* name, const char* value);
diff --git a/src/macro-assembler-arm.cc b/src/macro-assembler-arm.cc
index 2e957e4..616a9bf 100644
--- a/src/macro-assembler-arm.cc
+++ b/src/macro-assembler-arm.cc
@@ -818,7 +818,8 @@
int argc = Builtins::GetArgumentsCount(id);
uint32_t flags =
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
- Bootstrapper::FixupFlagsIsPCRelative::encode(true);
+ Bootstrapper::FixupFlagsIsPCRelative::encode(true) |
+ Bootstrapper::FixupFlagsUseCodeObject::encode(false);
Unresolved entry = { pc_offset() - sizeof(Instr), flags, name };
unresolved_.Add(entry);
}
@@ -835,10 +836,13 @@
int argc = Builtins::GetArgumentsCount(id);
uint32_t flags =
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
- Bootstrapper::FixupFlagsIsPCRelative::encode(true);
+ Bootstrapper::FixupFlagsIsPCRelative::encode(true) |
+ Bootstrapper::FixupFlagsUseCodeObject::encode(true);
Unresolved entry = { pc_offset() - sizeof(Instr), flags, name };
unresolved_.Add(entry);
}
+
+ add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
}
diff --git a/src/macro-assembler-ia32.cc b/src/macro-assembler-ia32.cc
index 72808de..fd7e4d9 100644
--- a/src/macro-assembler-ia32.cc
+++ b/src/macro-assembler-ia32.cc
@@ -293,7 +293,7 @@
if (x.is_zero()) {
xor_(dst, Operand(dst)); // shorter than mov
} else {
- mov(Operand(dst), x);
+ mov(dst, x);
}
}
@@ -695,7 +695,7 @@
if (num_arguments > 0) {
add(Operand(esp), Immediate(num_arguments * kPointerSize));
}
- mov(Operand(eax), Immediate(Factory::undefined_value()));
+ mov(eax, Immediate(Factory::undefined_value()));
}
@@ -726,14 +726,14 @@
// 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));
+ Set(eax, Immediate(num_arguments));
JumpToBuiltin(ext);
}
void MacroAssembler::JumpToBuiltin(const ExternalReference& ext) {
// Set the entry point and jump to the C entry runtime stub.
- mov(Operand(ebx), Immediate(ext));
+ mov(ebx, Immediate(ext));
CEntryStub ces;
jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
}
@@ -787,7 +787,7 @@
Handle<Code> adaptor =
Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
if (!code_constant.is_null()) {
- mov(Operand(edx), Immediate(code_constant));
+ mov(edx, Immediate(code_constant));
add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
} else if (!code_operand.is_reg(edx)) {
mov(edx, code_operand);
@@ -873,7 +873,8 @@
if (!resolved) {
uint32_t flags =
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
- Bootstrapper::FixupFlagsIsPCRelative::encode(true);
+ Bootstrapper::FixupFlagsIsPCRelative::encode(true) |
+ Bootstrapper::FixupFlagsUseCodeObject::encode(false);
Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
unresolved_.Add(entry);
}
@@ -891,7 +892,8 @@
if (!resolved) {
uint32_t flags =
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
- Bootstrapper::FixupFlagsIsPCRelative::encode(false);
+ Bootstrapper::FixupFlagsIsPCRelative::encode(false) |
+ Bootstrapper::FixupFlagsUseCodeObject::encode(true);
Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
unresolved_.Add(entry);
}
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 0ec6bd0..de05339 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -152,8 +152,6 @@
space->PrepareForMarkCompact(compacting_collection_);
}
- Counters::global_objects.Set(0);
-
#ifdef DEBUG
live_bytes_ = 0;
live_young_objects_ = 0;
@@ -327,12 +325,10 @@
void VisitUnmarkedObject(HeapObject* obj) {
#ifdef DEBUG
ASSERT(Heap::Contains(obj));
- MarkCompactCollector::UpdateLiveObjectCount(obj);
ASSERT(!obj->IsMarked());
#endif
Map* map = obj->map();
- obj->SetMark();
- MarkCompactCollector::tracer()->increment_marked_count();
+ MarkCompactCollector::SetMark(obj);
// Mark the map pointer and the body.
MarkCompactCollector::MarkObject(map);
obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), this);
@@ -380,13 +376,9 @@
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();
+ MarkCompactCollector::SetMark(object);
// Mark the map pointer and body, and push them on the marking stack.
MarkCompactCollector::MarkObject(map);
object->IterateBody(map->instance_type(), object->SizeFromMap(map),
@@ -423,20 +415,14 @@
void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) {
-#ifdef DEBUG
- UpdateLiveObjectCount(object);
-#endif
ASSERT(!object->IsMarked());
- if (object->IsJSGlobalObject()) Counters::global_objects.Increment();
-
- tracer_->increment_marked_count();
ASSERT(Heap::Contains(object));
if (object->IsMap()) {
Map* map = Map::cast(object);
if (FLAG_cleanup_caches_in_maps_at_gc) {
map->ClearCodeCache();
}
- map->SetMark();
+ SetMark(map);
if (FLAG_collect_maps &&
map->instance_type() >= FIRST_JS_OBJECT_TYPE &&
map->instance_type() <= JS_FUNCTION_TYPE) {
@@ -445,7 +431,7 @@
marking_stack.Push(map);
}
} else {
- object->SetMark();
+ SetMark(object);
marking_stack.Push(object);
}
}
@@ -469,12 +455,7 @@
if (descriptors->IsMarked()) return;
// Empty descriptor array is marked as a root before any maps are marked.
ASSERT(descriptors != Heap::empty_descriptor_array());
-
- tracer_->increment_marked_count();
-#ifdef DEBUG
- UpdateLiveObjectCount(descriptors);
-#endif
- descriptors->SetMark();
+ SetMark(descriptors);
FixedArray* contents = reinterpret_cast<FixedArray*>(
descriptors->get(DescriptorArray::kContentArrayIndex));
@@ -482,11 +463,7 @@
ASSERT(!contents->IsMarked());
ASSERT(contents->IsFixedArray());
ASSERT(contents->length() >= 2);
- tracer_->increment_marked_count();
-#ifdef DEBUG
- UpdateLiveObjectCount(contents);
-#endif
- contents->SetMark();
+ SetMark(contents);
// Contents contains (value, details) pairs. If the details say
// that the type of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION,
// or NULL_DESCRIPTOR, we don't mark the value as live. Only for
@@ -498,11 +475,7 @@
if (details.type() < FIRST_PHANTOM_PROPERTY_TYPE) {
HeapObject* object = reinterpret_cast<HeapObject*>(contents->get(i));
if (object->IsHeapObject() && !object->IsMarked()) {
- tracer_->increment_marked_count();
-#ifdef DEBUG
- UpdateLiveObjectCount(object);
-#endif
- object->SetMark();
+ SetMark(object);
marking_stack.Push(object);
}
}
@@ -578,13 +551,9 @@
SymbolTable* symbol_table = SymbolTable::cast(Heap::symbol_table());
// 1. Mark the prefix of the symbol table gray.
symbol_table->IteratePrefix(visitor);
-#ifdef DEBUG
- UpdateLiveObjectCount(symbol_table);
-#endif
// 2. Mark the symbol table black (ie, do not push it on the marking stack
// or mark it overflowed).
- symbol_table->SetMark();
- tracer_->increment_marked_count();
+ SetMark(symbol_table);
// There may be overflowed objects in the heap. Visit them now.
while (marking_stack.overflowed()) {
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 2dcf433..22dd890 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -152,7 +152,15 @@
static void MarkUnmarkedObject(HeapObject* obj);
static inline void MarkObject(HeapObject* obj) {
- if (!obj->IsMarked()) MarkUnmarkedObject(obj);
+ if (!obj->IsMarked()) MarkUnmarkedObject(obj);
+ }
+
+ static inline void SetMark(HeapObject* obj) {
+ tracer_->increment_marked_count();
+#ifdef DEBUG
+ UpdateLiveObjectCount(obj);
+#endif
+ obj->SetMark();
}
// Creates back pointers for all map transitions, stores them in
diff --git a/src/messages.cc b/src/messages.cc
index 7edb07f..e6a5084 100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -108,13 +108,12 @@
Handle<Object> message =
Execution::Call(fun, Factory::undefined_value(), argc, argv,
&caught_exception);
- if (caught_exception) {
- // If creating the message (in JS code) resulted in an exception, we
- // skip doing the callback. This usually only happens in case of
- // stack overflow exceptions being thrown by the parser when the
- // stack is almost full.
- if (caught_exception) return Handle<Object>();
- }
+
+ // If creating the message (in JS code) resulted in an exception, we
+ // skip doing the callback. This usually only happens in case of
+ // stack overflow exceptions being thrown by the parser when the
+ // stack is almost full.
+ if (caught_exception) return Handle<Object>();
return message.EscapeFrom(&scope);
}
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index 275fb47..7fb4490 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -150,10 +150,10 @@
// Print the usage if an error occurs when parsing the command line
// flags or if the help flag is set.
int result = i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
- if (result > 0 || argc != 2 || i::FLAG_h) {
+ if (result > 0 || argc != 2 || i::FLAG_help) {
::printf("Usage: %s [flag] ... outfile\n", argv[0]);
i::FlagList::PrintHelp();
- return !i::FLAG_h;
+ return !i::FLAG_help;
}
v8::V8::SetCounterFunction(counter_callback);
diff --git a/src/objects.cc b/src/objects.cc
index 66be1db..511f9f7 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -199,11 +199,11 @@
Handle<JSFunction> fun(JSFunction::cast(getter));
Handle<Object> self(receiver);
bool has_pending_exception;
- Object* result =
- *Execution::Call(fun, self, 0, NULL, &has_pending_exception);
+ Handle<Object> result =
+ Execution::Call(fun, self, 0, NULL, &has_pending_exception);
// Check for pending exception and return the result.
if (has_pending_exception) return Failure::Exception();
- return result;
+ return *result;
}
// Getter is not a function.
return Heap::undefined_value();
@@ -3848,7 +3848,7 @@
const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
- if ((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask) == 0) {
+ if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
#endif
const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
int endpoint = length - kStepSize;
@@ -4603,6 +4603,7 @@
const char* Code::ICState2String(InlineCacheState state) {
switch (state) {
case UNINITIALIZED: return "UNINITIALIZED";
+ case UNINITIALIZED_IN_LOOP: return "UNINITIALIZED_IN_LOOP";
case PREMONOMORPHIC: return "PREMONOMORPHIC";
case MONOMORPHIC: return "MONOMORPHIC";
case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
diff --git a/src/rewriter.cc b/src/rewriter.cc
index d391d5d..c5ca7cd 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -761,17 +761,20 @@
}
-void Rewriter::Optimize(FunctionLiteral* function) {
+bool Rewriter::Optimize(FunctionLiteral* function) {
ZoneList<Statement*>* body = function->body();
- if (body->is_empty()) return;
- if (FLAG_optimize_ast) {
+ if (FLAG_optimize_ast && !body->is_empty()) {
Scope* scope = function->scope();
if (!scope->is_global_scope()) {
AstOptimizer optimizer;
optimizer.Optimize(body);
+ if (optimizer.HasStackOverflow()) {
+ return false;
+ }
}
}
+ return true;
}
diff --git a/src/rewriter.h b/src/rewriter.h
index d69ad5a..aa2f981 100644
--- a/src/rewriter.h
+++ b/src/rewriter.h
@@ -44,7 +44,7 @@
class Rewriter {
public:
static bool Process(FunctionLiteral* function);
- static void Optimize(FunctionLiteral* function);
+ static bool Optimize(FunctionLiteral* function);
};
diff --git a/src/runtime.cc b/src/runtime.cc
index 6fe7cc6..1d40e4c 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -296,7 +296,9 @@
Handle<String> pattern(raw_pattern);
CONVERT_CHECKED(String, raw_flags, args[2]);
Handle<String> flags(raw_flags);
- return *RegExpImpl::Compile(re, pattern, flags);
+ Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
+ if (result.is_null()) return Failure::Exception();
+ return *result;
}
@@ -5086,7 +5088,7 @@
if (!done) {
// If the candidate is not compiled compile it to reveal any inner
// functions which might contain the requested source position.
- CompileLazyShared(target, KEEP_EXCEPTION);
+ CompileLazyShared(target, KEEP_EXCEPTION, 0);
}
}
@@ -5392,6 +5394,7 @@
Handle<Object> evaluation_function =
Execution::Call(compiled_function, receiver, 0, NULL,
&has_pending_exception);
+ if (has_pending_exception) return Failure::Exception();
Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
function_context);
@@ -5403,6 +5406,7 @@
Handle<Object> result =
Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
argc, argv, &has_pending_exception);
+ if (has_pending_exception) return Failure::Exception();
return *result;
}
@@ -5448,6 +5452,7 @@
Handle<Object> result =
Execution::Call(compiled_function, receiver, 0, NULL,
&has_pending_exception);
+ if (has_pending_exception) return Failure::Exception();
return *result;
}
diff --git a/src/scanner.cc b/src/scanner.cc
index a6cc74a..3ae6936 100644
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -234,11 +234,25 @@
}
+static inline bool IsByteOrderMark(uc32 c) {
+ // The Unicode value U+FFFE is guaranteed never to be assigned as a
+ // Unicode character; this implies that in a Unicode context the
+ // 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF
+ // character expressed in little-endian byte order (since it could
+ // not be a U+FFFE character expressed in big-endian byte
+ // order). Nevertheless, we check for it to be compatible with
+ // Spidermonkey.
+ return c == 0xFEFF || c == 0xFFFE;
+}
+
+
void Scanner::SkipWhiteSpace(bool initial) {
has_line_terminator_before_next_ = initial;
while (true) {
- while (kIsWhiteSpace.get(c0_)) {
+ // We treat byte-order marks (BOMs) as whitespace for better
+ // compatibility with Spidermonkey and other JavaScript engines.
+ while (kIsWhiteSpace.get(c0_) || IsByteOrderMark(c0_)) {
// IsWhiteSpace() includes line terminators!
if (kIsLineTerminator.get(c0_))
// Ignore line terminators, but remember them. This is necessary
diff --git a/src/serialize.cc b/src/serialize.cc
index cd7a323..359d627 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -966,7 +966,7 @@
void Serializer::PutFlags() {
writer_->PutC('F');
- List<char*>* argv = FlagList::argv();
+ List<const char*>* argv = FlagList::argv();
writer_->PutInt(argv->length());
writer_->PutC('[');
for (int i = 0; i < argv->length(); i++) {
diff --git a/src/simulator-arm.cc b/src/simulator-arm.cc
index 37a8237..4203ad3 100644
--- a/src/simulator-arm.cc
+++ b/src/simulator-arm.cc
@@ -48,11 +48,7 @@
// SScanF not beeing implemented in a platform independent was through
// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
// Library does not provide vsscanf.
-#ifdef WIN32
-#define SScanF sscanf_s
-#else
#define SScanF sscanf // NOLINT
-#endif
// The Debugger class is used by the simulator while debugging simulated ARM
// code.
@@ -210,7 +206,8 @@
while (!done) {
if (last_pc != sim_->get_pc()) {
- disasm::Disassembler dasm;
+ disasm::NameConverter converter;
+ disasm::Disassembler dasm(converter);
// use a reasonably large buffer
v8::internal::EmbeddedVector<char, 256> buffer;
dasm.InstructionDecode(buffer,
@@ -265,7 +262,8 @@
PrintF("printobject value\n");
}
} else if (strcmp(cmd, "disasm") == 0) {
- disasm::Disassembler dasm;
+ disasm::NameConverter converter;
+ disasm::Disassembler dasm(converter);
// use a reasonably large buffer
v8::internal::EmbeddedVector<char, 256> buffer;
@@ -380,19 +378,20 @@
}
-// This is the Simulator singleton. Currently only one thread is supported by
-// V8. If we had multiple threads, then we should have a Simulator instance on
-// a per thread basis.
-static Simulator* the_sim = NULL;
+// Create one simulator per thread and keep it in thread local storage.
+static v8::internal::Thread::LocalStorageKey simulator_key =
+ v8::internal::Thread::CreateThreadLocalKey();
-
-// Get the active Simulator for the current thread. See comment above about
-// using a singleton currently.
+// Get the active Simulator for the current thread.
Simulator* Simulator::current() {
- if (the_sim == NULL) {
- the_sim = new Simulator();
+ Simulator* sim = reinterpret_cast<Simulator*>(
+ v8::internal::Thread::GetThreadLocal(simulator_key));
+ if (sim == NULL) {
+ // TODO(146): delete the simulator object when a thread goes away.
+ sim = new Simulator();
+ v8::internal::Thread::SetThreadLocal(simulator_key, sim);
}
- return the_sim;
+ return sim;
}
@@ -1441,7 +1440,8 @@
return;
}
if (::v8::internal::FLAG_trace_sim) {
- disasm::Disassembler dasm;
+ disasm::NameConverter converter;
+ disasm::Disassembler dasm(converter);
// use a reasonably large buffer
v8::internal::EmbeddedVector<char, 256> buffer;
dasm.InstructionDecode(buffer,
@@ -1492,7 +1492,7 @@
//
-void Simulator::execute() {
+void Simulator::Execute() {
// Get the PC to simulate. Cannot use the accessor here as we need the
// raw PC value and not the one used as input to arithmetic instructions.
int program_counter = get_pc();
@@ -1524,7 +1524,7 @@
}
-Object* Simulator::call(int32_t entry, int32_t p0, int32_t p1, int32_t p2,
+Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2,
int32_t p3, int32_t p4) {
// Setup parameters
set_register(r0, p0);
@@ -1567,7 +1567,7 @@
set_register(r11, callee_saved_value);
// Start the simulation
- execute();
+ Execute();
// Check that the callee-saved registers have been preserved.
CHECK_EQ(get_register(r4), callee_saved_value);
diff --git a/src/simulator-arm.h b/src/simulator-arm.h
index baefa5d..ccb3e80 100644
--- a/src/simulator-arm.h
+++ b/src/simulator-arm.h
@@ -54,7 +54,7 @@
// When running with the simulator transition into simulated execution at this
// point.
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
- assembler::arm::Simulator::current()->call((int32_t)entry, (int32_t)p0, \
+ assembler::arm::Simulator::current()->Call((int32_t)entry, (int32_t)p0, \
(int32_t)p1, (int32_t)p2, (int32_t)p3, (int32_t)p4)
// The simulator has its own stack. Thus it has a different stack limit from
@@ -103,12 +103,12 @@
uintptr_t StackLimit() const;
// Executes ARM instructions until the PC reaches end_sim_pc.
- void execute();
+ void Execute();
// V8 generally calls into generated code with 5 parameters. This is a
// convenience funtion, which sets up the simulator state and grabs the
// result on return.
- v8::internal::Object* call(int32_t entry, int32_t p0, int32_t p1,
+ v8::internal::Object* Call(int32_t entry, int32_t p0, int32_t p1,
int32_t p2, int32_t p3, int32_t p4);
private:
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 81cbea5..6a3737b 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -141,6 +141,13 @@
Add(formatted.start());
break;
}
+ case 'f': case 'g': case 'G': case 'e': case 'E': {
+ double value = current.data_.u_double_;
+ EmbeddedVector<char, 28> formatted;
+ OS::SNPrintF(formatted, temp.start(), value);
+ Add(formatted.start());
+ break;
+ }
default:
UNREACHABLE();
break;
@@ -207,11 +214,11 @@
}
-SmartPointer<char> StringStream::ToCString() {
+SmartPointer<const char> StringStream::ToCString() {
char* str = NewArray<char>(length_ + 1);
memcpy(str, buffer_, length_);
str[length_] = '\0';
- return SmartPointer<char>(str);
+ return SmartPointer<const char>(str);
}
diff --git a/src/string-stream.h b/src/string-stream.h
index 9cff319..2fb29af 100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -73,16 +73,18 @@
class FmtElm {
public:
FmtElm(int value) : type_(INT) { data_.u_int_ = value; } // NOLINT
+ explicit FmtElm(double value) : type_(DOUBLE) { data_.u_double_ = value; } // NOLINT
FmtElm(const char* value) : type_(C_STR) { data_.u_c_str_ = value; } // NOLINT
FmtElm(Object* value) : type_(OBJ) { data_.u_obj_ = value; } // NOLINT
FmtElm(Handle<Object> value) : type_(HANDLE) { data_.u_handle_ = value.location(); } // NOLINT
FmtElm(void* value) : type_(INT) { data_.u_int_ = reinterpret_cast<int>(value); } // NOLINT
private:
friend class StringStream;
- enum Type { INT, C_STR, OBJ, HANDLE };
+ enum Type { INT, DOUBLE, C_STR, OBJ, HANDLE };
Type type_;
union {
int u_int_;
+ double u_double_;
const char* u_c_str_;
Object* u_obj_;
Object** u_handle_;
@@ -116,7 +118,7 @@
void OutputToStdOut();
void Log();
Handle<String> ToString();
- SmartPointer<char> ToCString();
+ SmartPointer<const char> ToCString();
// Object printing support.
void PrintName(Object* o);
diff --git a/src/stub-cache-arm.cc b/src/stub-cache-arm.cc
index 2ef657e..e7fe0b9 100644
--- a/src/stub-cache-arm.cc
+++ b/src/stub-cache-arm.cc
@@ -169,6 +169,141 @@
}
+void StubCompiler::GenerateLoadField(MacroAssembler* masm,
+ JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ int index,
+ Label* miss_label) {
+ // Check that the receiver isn't a smi.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss_label);
+
+ // Check that the maps haven't changed.
+ Register reg =
+ __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+ GenerateFastPropertyLoad(masm, r0, reg, holder, index);
+ __ Ret();
+}
+
+
+void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
+ JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Object* value,
+ Label* miss_label) {
+ // Check that the receiver isn't a smi.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss_label);
+
+ // Check that the maps haven't changed.
+ Register reg =
+ __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+
+ // Return the constant value.
+ __ mov(r0, Operand(Handle<Object>(value)));
+ __ Ret();
+}
+
+
+void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
+ JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register name,
+ Register scratch1,
+ Register scratch2,
+ AccessorInfo* callback,
+ Label* miss_label) {
+ // Check that the receiver isn't a smi.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss_label);
+
+ // Check that the maps haven't changed.
+ Register reg =
+ __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+
+ // Push the arguments on the JS stack of the caller.
+ __ push(receiver); // receiver
+ __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
+ __ push(ip);
+ __ push(name); // name
+ __ push(reg); // holder
+
+ // Do tail-call to the runtime system.
+ ExternalReference load_callback_property =
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+ __ TailCallRuntime(load_callback_property, 4);
+}
+
+
+void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
+ JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register name,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
+ // Check that the receiver isn't a smi.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss_label);
+
+ // Check that the maps haven't changed.
+ Register reg =
+ __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+
+ // Push the arguments on the JS stack of the caller.
+ __ push(receiver); // receiver
+ __ push(reg); // holder
+ __ push(name); // name
+
+ // Do tail-call to the runtime system.
+ ExternalReference load_ic_property =
+ ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+ __ TailCallRuntime(load_ic_property, 3);
+}
+
+
+void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
+ Register receiver,
+ Register scratch,
+ Label* miss_label) {
+ // Check that the receiver isn't a smi.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss_label);
+
+ // Check that the object is a JS array.
+ __ ldr(scratch, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+ __ cmp(scratch, Operand(JS_ARRAY_TYPE));
+ __ b(ne, miss_label);
+
+ // Load length directly from the JS array.
+ __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
+ __ Ret();
+}
+
+
+void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
+ ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
+ Code* code = NULL;
+ if (kind == Code::LOAD_IC) {
+ code = Builtins::builtin(Builtins::LoadIC_Miss);
+ } else {
+ code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
+ }
+
+ Handle<Code> ic(code);
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
#undef __
#define __ masm()->
@@ -633,20 +768,9 @@
__ ldr(r0, MemOperand(sp, 0));
- // Check that the receiver isn't a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &miss);
-
- // Check that the maps haven't changed.
- Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
- GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
- __ Ret();
-
- // Handle load cache miss.
+ GenerateLoadField(masm(), object, holder, r0, r3, r1, index, &miss);
__ bind(&miss);
- __ ldr(r0, MemOperand(sp)); // restore receiver
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
- __ Jump(ic, RelocInfo::CODE_TARGET);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return GetCode(FIELD);
@@ -666,29 +790,9 @@
Label miss;
__ ldr(r0, MemOperand(sp, 0));
- // Check that the receiver isn't a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &miss);
-
- // Check that the maps haven't changed.
- Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
-
- // Push the arguments on the JS stack of the caller.
- __ push(r0); // receiver
- __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
- __ push(ip);
- __ push(r2); // name
- __ push(reg); // holder
-
- // 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.
+ GenerateLoadCallback(masm(), object, holder, r0, r2, r3, r1, callback, &miss);
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
- __ Jump(ic, RelocInfo::CODE_TARGET);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return GetCode(CALLBACKS);
@@ -708,21 +812,10 @@
Label miss;
__ ldr(r0, MemOperand(sp, 0));
- // Check that the receiver isn't a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &miss);
- // Check that the maps haven't changed.
- Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
-
- // Return the constant value.
- __ mov(r0, Operand(Handle<Object>(value)));
- __ Ret();
-
- // Handle load cache miss.
+ GenerateLoadConstant(masm(), object, holder, r0, r3, r1, value, &miss);
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
- __ Jump(ic, RelocInfo::CODE_TARGET);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return GetCode(CONSTANT_FUNCTION);
@@ -742,27 +835,10 @@
Label miss;
__ ldr(r0, MemOperand(sp, 0));
- // Check that the receiver isn't a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &miss);
- // Check that the maps haven't changed.
- Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
-
- // Push the arguments on the JS stack of the caller.
- __ push(r0); // receiver
- __ push(reg); // holder
- __ push(r2); // name
-
- // 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.
+ GenerateLoadInterceptor(masm(), object, holder, r0, r2, r3, r1, &miss);
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
- __ Jump(ic, RelocInfo::CODE_TARGET);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return GetCode(INTERCEPTOR);
@@ -775,8 +851,25 @@
JSObject* receiver,
JSObject* holder,
int index) {
- UNIMPLEMENTED();
- return Heap::undefined_value();
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[4] : receiver
+ // -----------------------------------
+ HandleScope scope;
+ Label miss;
+
+ __ ldr(r2, MemOperand(sp, 0));
+ __ ldr(r0, MemOperand(sp, kPointerSize));
+
+ __ cmp(r2, Operand(Handle<String>(name)));
+ __ b(ne, &miss);
+
+ GenerateLoadField(masm(), receiver, holder, r0, r3, r1, index, &miss);
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ return GetCode(FIELD);
}
@@ -784,8 +877,26 @@
JSObject* receiver,
JSObject* holder,
AccessorInfo* callback) {
- UNIMPLEMENTED();
- return Heap::undefined_value();
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[4] : receiver
+ // -----------------------------------
+ HandleScope scope;
+ Label miss;
+
+ __ ldr(r2, MemOperand(sp, 0));
+ __ ldr(r0, MemOperand(sp, kPointerSize));
+
+ __ cmp(r2, Operand(Handle<String>(name)));
+ __ b(ne, &miss);
+
+ GenerateLoadCallback(masm(), receiver, holder, r0, r2, r3,
+ r1, callback, &miss);
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ return GetCode(CALLBACKS);
}
@@ -793,45 +904,126 @@
JSObject* receiver,
JSObject* holder,
Object* value) {
- UNIMPLEMENTED();
- return Heap::undefined_value();
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[4] : receiver
+ // -----------------------------------
+ HandleScope scope;
+ Label miss;
+
+ // Check the key is the cached one
+ __ ldr(r2, MemOperand(sp, 0));
+ __ ldr(r0, MemOperand(sp, kPointerSize));
+
+ __ cmp(r2, Operand(Handle<String>(name)));
+ __ b(ne, &miss);
+
+ GenerateLoadConstant(masm(), receiver, holder, r0, r3, r1, value, &miss);
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(CONSTANT_FUNCTION);
}
Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
JSObject* holder,
String* name) {
- UNIMPLEMENTED();
- return Heap::undefined_value();
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[4] : receiver
+ // -----------------------------------
+ HandleScope scope;
+ Label miss;
+
+ // Check the key is the cached one
+ __ ldr(r2, MemOperand(sp, 0));
+ __ ldr(r0, MemOperand(sp, kPointerSize));
+
+ __ cmp(r2, Operand(Handle<String>(name)));
+ __ b(ne, &miss);
+
+ GenerateLoadInterceptor(masm(), receiver, holder, r0, r2, r3, r1, &miss);
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ return GetCode(INTERCEPTOR);
}
Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
- UNIMPLEMENTED();
- return Heap::undefined_value();
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[4] : receiver
+ // -----------------------------------
+ HandleScope scope;
+ Label miss;
+
+ // Check the key is the cached one
+ __ ldr(r2, MemOperand(sp, 0));
+ __ ldr(r0, MemOperand(sp, kPointerSize));
+
+ __ cmp(r2, Operand(Handle<String>(name)));
+ __ b(ne, &miss);
+
+ GenerateLoadArrayLength(masm(), r0, r3, &miss);
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ return GetCode(CALLBACKS);
}
+// TODO(1224671): implement the fast case.
Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
- UNIMPLEMENTED();
- return Heap::undefined_value();
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[4] : receiver
+ // -----------------------------------
+ HandleScope scope;
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ return GetCode(CALLBACKS);
}
+// TODO(1224671): implement the fast case.
Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
- UNIMPLEMENTED();
- return Heap::undefined_value();
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- sp[0] : key
+ // -- sp[4] : receiver
+ // -----------------------------------
+ HandleScope scope;
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ return GetCode(CALLBACKS);
}
+// TODO(1224671): implement the fast case.
Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
int index,
Map* transition,
String* name) {
- UNIMPLEMENTED();
- return Heap::undefined_value();
-}
+ // ----------- S t a t e -------------
+ // -- r0 : value
+ // -- r2 : name
+ // -- lr : return address
+ // -- [sp] : receiver
+ // -----------------------------------
+ HandleScope scope;
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+ // Return the generated code.
+ return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
+}
#undef __
diff --git a/src/stub-cache-ia32.cc b/src/stub-cache-ia32.cc
index 66e12d4..d15b19d 100644
--- a/src/stub-cache-ia32.cc
+++ b/src/stub-cache-ia32.cc
@@ -395,7 +395,7 @@
if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the propeties array.
- __ mov(Operand(ecx), Immediate(Handle<Map>(transition)));
+ __ mov(ecx, Immediate(Handle<Map>(transition)));
Handle<Code> ic(Builtins::builtin(storage_extend));
__ jmp(ic, RelocInfo::CODE_TARGET);
return;
@@ -628,7 +628,7 @@
}
// Get the function and setup the context.
- __ mov(Operand(edi), Immediate(Handle<JSFunction>(function)));
+ __ mov(edi, Immediate(Handle<JSFunction>(function)));
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Jump to the cached code (tail call).
@@ -681,14 +681,14 @@
// Perform call.
ExternalReference load_interceptor =
ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
- __ mov(Operand(eax), Immediate(3));
- __ mov(Operand(ebx), Immediate(load_interceptor));
+ __ mov(eax, Immediate(3));
+ __ mov(ebx, Immediate(load_interceptor));
CEntryStub stub;
__ CallStub(&stub);
// Move result to edi and restore receiver.
- __ mov(Operand(edi), eax);
+ __ mov(edi, eax);
__ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
// Exit frame.
@@ -750,7 +750,7 @@
// Handle store cache miss.
__ bind(&miss);
- __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
+ __ mov(ecx, Immediate(Handle<String>(name))); // restore name
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
__ jmp(ic, RelocInfo::CODE_TARGET);
@@ -807,7 +807,7 @@
// Handle store cache miss.
__ bind(&miss);
- __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
+ __ mov(ecx, Immediate(Handle<String>(name))); // restore name
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
__ jmp(ic, RelocInfo::CODE_TARGET);
@@ -862,7 +862,7 @@
// Handle store cache miss.
__ bind(&miss);
- __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
+ __ mov(ecx, Immediate(Handle<String>(name))); // restore name
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
__ jmp(ic, RelocInfo::CODE_TARGET);
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 2904889..3ee1b9e 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -543,6 +543,17 @@
}
+Object* StubCache::ComputeCallInitializeInLoop(int argc) {
+ Code::Flags flags =
+ Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED_IN_LOOP, NORMAL, argc);
+ Object* probe = ProbeCache(flags);
+ if (!probe->IsUndefined()) return probe;
+ StubCompiler compiler;
+ return FillCache(compiler.CompileCallInitialize(flags));
+}
+
+
+
Object* StubCache::ComputeCallPreMonomorphic(int argc) {
Code::Flags flags =
Code::ComputeFlags(Code::CALL_IC, PREMONOMORPHIC, NORMAL, argc);
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 5d67afe..66d03fe 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -148,6 +148,7 @@
// ---
static Object* ComputeCallInitialize(int argc);
+ static Object* ComputeCallInitializeInLoop(int argc);
static Object* ComputeCallPreMonomorphic(int argc);
static Object* ComputeCallNormal(int argc);
static Object* ComputeCallMegamorphic(int argc);
diff --git a/src/top.cc b/src/top.cc
index 29b7861..ace79a9 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -253,7 +253,30 @@
}
+// There are cases where the C stack is separated from JS stack (ARM simulator).
+// To figure out the order of top-most JS try-catch handler and the top-most C
+// try-catch handler, the C try-catch handler keeps a reference to the top-most
+// JS try_catch handler when it was created.
+//
+// Here is a picture to explain the idea:
+// Top::thread_local_.handler_ Top::thread_local_.try_catch_handler_
+//
+// | |
+// v v
+//
+// | JS handler | | C try_catch handler |
+// | next |--+ +-------- | js_handler_ |
+// | | | next_ |--+
+// | | |
+// | JS handler |--+ <---------+ |
+// | next |
+//
+// If the top-most JS try-catch handler is not equal to
+// Top::thread_local_.try_catch_handler_.js_handler_, it means the JS handler
+// is on the top. Otherwise, it means the C try-catch handler is on the top.
+//
void Top::RegisterTryCatchHandler(v8::TryCatch* that) {
+ that->js_handler_ = thread_local_.handler_; // casted to void*
thread_local_.try_catch_handler_ = that;
}
@@ -719,8 +742,7 @@
// address of the external handler so we can compare the address to
// determine which one is closer to the top of the stack.
bool has_external_handler = (thread_local_.try_catch_handler_ != NULL);
- Address external_handler_address =
- reinterpret_cast<Address>(thread_local_.try_catch_handler_);
+ v8::TryCatch* try_catch = thread_local_.try_catch_handler_;
// NOTE: The stack is assumed to grown towards lower addresses. If
// the handler is at a higher address than the external address it
@@ -732,10 +754,12 @@
}
// The exception has been externally caught if and only if there is
- // an external handler which is above any JavaScript try-catch but NOT
- // try-finally handlers.
+ // an external handler which is on top of the top-most try-catch
+ // handler.
+ //
+ // See comments in RegisterTryCatchHandler for details.
*is_caught_externally = has_external_handler &&
- (handler == NULL || handler->address() > external_handler_address);
+ (handler == NULL || handler == try_catch->js_handler_);
// If we have a try-catch handler then the exception is caught in
// JavaScript code.
@@ -745,7 +769,7 @@
// exception if it isn't caught by JavaScript code.
if (!has_external_handler) return is_uncaught_by_js;
- if (is_uncaught_by_js || handler->address() > external_handler_address) {
+ if (is_uncaught_by_js || handler == try_catch->js_handler_) {
// Only report the exception if the external handler is verbose.
return thread_local_.try_catch_handler_->is_verbose_;
} else {
diff --git a/src/v8-counters.h b/src/v8-counters.h
index 0505d20..0f5af8a 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -50,8 +50,6 @@
#define STATS_COUNTER_LIST_1(SC) \
/* Global Handle Count*/ \
SC(global_handles, V8.GlobalHandles) \
- /* Global Object Count */ \
- SC(global_objects, V8.GlobalObjects) \
/* Mallocs from PCRE */ \
SC(pcre_mallocs, V8.PcreMallocCount) \
/* OS Memory allocated */ \
diff --git a/src/v8.h b/src/v8.h
index 328c88c..3d84158 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -38,6 +38,10 @@
// If both are defined in Google3, then we are building an optimized v8 with
// assertions enabled.
#undef NDEBUG
+#elif !defined(DEBUG) && !defined(NDEBUG)
+// If neither is defined in Google3, then we are building a debug v8. Mark it
+// as such.
+#define DEBUG
#endif
#endif // defined(GOOGLE3)
diff --git a/src/v8natives.js b/src/v8natives.js
index 094d5ea..f3c98a5 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -105,6 +105,11 @@
function GlobalEval(x) {
if (!IS_STRING(x)) return x;
+ if (this !== %GlobalReceiver(global)) {
+ throw new $EvalError('The "this" object passed to eval must ' +
+ 'be the global object from which eval originated');
+ }
+
var f = %CompileString(x, 0, true);
if (!IS_FUNCTION(f)) return f;
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index b3f71d9..fc7cd6a 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -34,7 +34,6 @@
test-debug: SKIP
test-serialize: SKIP
-test-api: SKIP
# BUG(113): Test seems flaky on ARM.
test-spaces/LargeObjectSpace: PASS || FAIL
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 0e8a508..f3b018d 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -4078,6 +4078,14 @@
"with({x:2}){other.eval('x+y')}"));
result = script->Run();
CHECK_EQ(3, result->Int32Value());
+
+ // Check that you cannot use 'eval.call' with another object than the
+ // current global object.
+ v8::TryCatch try_catch;
+ script =
+ Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
+ result = script->Run();
+ CHECK(try_catch.HasCaught());
}
diff --git a/test/cctest/test-disasm-arm.cc b/test/cctest/test-disasm-arm.cc
index 7df292a..316b93a 100644
--- a/test/cctest/test-disasm-arm.cc
+++ b/test/cctest/test-disasm-arm.cc
@@ -50,7 +50,8 @@
bool DisassembleAndCompare(byte* pc, const char* compare_string) {
- disasm::Disassembler disasm;
+ disasm::NameConverter converter;
+ disasm::Disassembler disasm(converter);
EmbeddedVector<char, 128> disasm_buffer;
disasm.InstructionDecode(disasm_buffer, pc);
@@ -68,6 +69,9 @@
}
+// Setup V8 to a state where we can at least run the assembler and
+// disassembler. Declare the variables and allocate the data structures used
+// in the rest of the macros.
#define SETUP() \
InitializeVM(); \
Serializer::disable(); \
@@ -77,6 +81,10 @@
bool failure = false;
+// This macro assembles one instruction using the preallocated assembler and
+// disassembles the generated instruction, comparing the output to the expected
+// value. If the comparison fails an error message is printed, but the test
+// continues to run until the end.
#define COMPARE(asm_, compare_string) \
{ \
int pc_offset = assm.pc_offset(); \
@@ -86,8 +94,10 @@
}
-#define OUTPUT() \
- if (failure) { \
+// Verify that all invocations of the COMPARE macro passed successfully.
+// Exit with a failure if at least one of the tests failed.
+#define VERIFY_RUN() \
+if (failure) { \
V8_Fatal(__FILE__, __LINE__, "ARM Disassembler tests failed.\n"); \
}
@@ -239,7 +249,7 @@
COMPARE(mvn(r5, Operand(r4), SetCC, cc),
"31f05004 mvnccs r5, r4");
- OUTPUT();
+ VERIFY_RUN();
}
@@ -268,5 +278,5 @@
COMPARE(eor(r4, r1, Operand(0x10000000), SetCC, cc),
"32314201 eorccs r4, r1, #268435456");
- OUTPUT();
+ VERIFY_RUN();
}
diff --git a/test/cctest/test-flags.cc b/test/cctest/test-flags.cc
index a3aa4b2..9019a89 100644
--- a/test/cctest/test-flags.cc
+++ b/test/cctest/test-flags.cc
@@ -168,3 +168,67 @@
const char* str = " --testing-int-flag 0 --testing_float_flag ";
CHECK_EQ(3, FlagList::SetFlagsFromString(str, strlen(str)));
}
+
+
+TEST(FlagsJSArguments1) {
+ SetFlagsToDefault();
+ int argc = 6;
+ const char* argv[] = {"TestJSArgs1",
+ "--testing-int-flag", "42",
+ "--", "testing-float-flag", "7"};
+ CHECK_EQ(0, FlagList::SetFlagsFromCommandLine(&argc,
+ const_cast<char **>(argv),
+ true));
+ CHECK_EQ(42, FLAG_testing_int_flag);
+ CHECK_EQ(2.5, FLAG_testing_float_flag);
+ CHECK_EQ(2, FLAG_js_arguments.argc());
+ CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag"));
+ CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7"));
+ CHECK_EQ(1, argc);
+}
+
+
+TEST(FlagsJSArguments1b) {
+ SetFlagsToDefault();
+ const char* str = "--testing-int-flag 42 -- testing-float-flag 7";
+ CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+ CHECK_EQ(42, FLAG_testing_int_flag);
+ CHECK_EQ(2.5, FLAG_testing_float_flag);
+ CHECK_EQ(2, FLAG_js_arguments.argc());
+ CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag"));
+ CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7"));
+}
+
+
+TEST(FlagsJSArguments2) {
+ SetFlagsToDefault();
+ const char* str = "--testing-int-flag 42 --js-arguments testing-float-flag 7";
+ CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+ CHECK_EQ(42, FLAG_testing_int_flag);
+ CHECK_EQ(2.5, FLAG_testing_float_flag);
+ CHECK_EQ(2, FLAG_js_arguments.argc());
+ CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag"));
+ CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7"));
+}
+
+
+TEST(FlagsJSArguments3) {
+ SetFlagsToDefault();
+ const char* str = "--testing-int-flag 42 --js-arguments=testing-float-flag 7";
+ CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+ CHECK_EQ(42, FLAG_testing_int_flag);
+ CHECK_EQ(2.5, FLAG_testing_float_flag);
+ CHECK_EQ(2, FLAG_js_arguments.argc());
+ CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag"));
+ CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7"));
+}
+
+
+TEST(FlagsJSArguments4) {
+ SetFlagsToDefault();
+ const char* str = "--testing-int-flag 42 --";
+ CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+ CHECK_EQ(42, FLAG_testing_int_flag);
+ CHECK_EQ(0, FLAG_js_arguments.argc());
+}
+
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index a5448c4..6a6b379 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -570,10 +570,7 @@
js1_5/Regress/regress-303213: FAIL
-# Bug 1193440: Ignore Unicode BOM characters when scanning.
-ecma_3/extensions/regress-368516: FAIL
-
-# Bug 1202592:New ecma_3/String/15.5.4.11 is failing.
+# Bug 1202592: New ecma_3/String/15.5.4.11 is failing.
ecma_3/String/15.5.4.11: FAIL
# Bug 1202597: New js1_5/Expressions/regress-394673 is failing.
diff --git a/tools/visual_studio/arm.vsprops b/tools/visual_studio/arm.vsprops
new file mode 100644
index 0000000..0e37d41
--- /dev/null
+++ b/tools/visual_studio/arm.vsprops
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="arm"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="ARM"
+ DisableSpecificWarnings="4996"
+ />
+</VisualStudioPropertySheet>
diff --git a/tools/visual_studio/v8_arm.sln b/tools/visual_studio/v8_arm.sln
new file mode 100644
index 0000000..2dc6cf5
--- /dev/null
+++ b/tools/visual_studio/v8_arm.sln
@@ -0,0 +1,74 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8", "v8.vcproj", "{21E22961-22BF-4493-BD3A-868F93DA5179}"
+ ProjectSection(ProjectDependencies) = postProject
+ {EC8B7909-62AF-470D-A75D-E1D89C837142} = {EC8B7909-62AF-470D-A75D-E1D89C837142}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_shell_sample", "v8_shell_sample.vcproj", "{2DE20FFA-6F5E-48D9-84D8-09B044A5B119}"
+ ProjectSection(ProjectDependencies) = postProject
+ {EC8B7909-62AF-470D-A75D-E1D89C837142} = {EC8B7909-62AF-470D-A75D-E1D89C837142}
+ {21E22961-22BF-4493-BD3A-868F93DA5179} = {21E22961-22BF-4493-BD3A-868F93DA5179}
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{E131F77D-B713-48F3-B86D-097ECDCC4C3A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_process_sample", "v8_process_sample.vcproj", "{EF019874-D38A-40E3-B17C-DB5923F0A79C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {21E22961-22BF-4493-BD3A-868F93DA5179} = {21E22961-22BF-4493-BD3A-868F93DA5179}
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AD933CE2-1303-448E-89C8-60B1FDD18EC3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "d8", "d8.vcproj", "{7E4C7D2D-A4B9-40B9-8192-22654E626F6C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {21E22961-22BF-4493-BD3A-868F93DA5179} = {21E22961-22BF-4493-BD3A-868F93DA5179}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_base", "v8_base_arm.vcproj", "{EC8B7909-62AF-470D-A75D-E1D89C837142}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_cctest", "v8_cctest_arm.vcproj", "{97ECC711-7430-4FC4-90FD-004DA880E72A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {21E22961-22BF-4493-BD3A-868F93DA5179} = {21E22961-22BF-4493-BD3A-868F93DA5179}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {21E22961-22BF-4493-BD3A-868F93DA5179}.Debug|Win32.ActiveCfg = Debug|Win32
+ {21E22961-22BF-4493-BD3A-868F93DA5179}.Debug|Win32.Build.0 = Debug|Win32
+ {21E22961-22BF-4493-BD3A-868F93DA5179}.Release|Win32.ActiveCfg = Release|Win32
+ {21E22961-22BF-4493-BD3A-868F93DA5179}.Release|Win32.Build.0 = Release|Win32
+ {2DE20FFA-6F5E-48D9-84D8-09B044A5B119}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2DE20FFA-6F5E-48D9-84D8-09B044A5B119}.Debug|Win32.Build.0 = Debug|Win32
+ {2DE20FFA-6F5E-48D9-84D8-09B044A5B119}.Release|Win32.ActiveCfg = Release|Win32
+ {2DE20FFA-6F5E-48D9-84D8-09B044A5B119}.Release|Win32.Build.0 = Release|Win32
+ {EF019874-D38A-40E3-B17C-DB5923F0A79C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EF019874-D38A-40E3-B17C-DB5923F0A79C}.Debug|Win32.Build.0 = Debug|Win32
+ {EF019874-D38A-40E3-B17C-DB5923F0A79C}.Release|Win32.ActiveCfg = Release|Win32
+ {EF019874-D38A-40E3-B17C-DB5923F0A79C}.Release|Win32.Build.0 = Release|Win32
+ {7E4C7D2D-A4B9-40B9-8192-22654E626F6C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7E4C7D2D-A4B9-40B9-8192-22654E626F6C}.Debug|Win32.Build.0 = Debug|Win32
+ {7E4C7D2D-A4B9-40B9-8192-22654E626F6C}.Release|Win32.ActiveCfg = Release|Win32
+ {7E4C7D2D-A4B9-40B9-8192-22654E626F6C}.Release|Win32.Build.0 = Release|Win32
+ {EC8B7909-62AF-470D-A75D-E1D89C837142}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EC8B7909-62AF-470D-A75D-E1D89C837142}.Debug|Win32.Build.0 = Debug|Win32
+ {EC8B7909-62AF-470D-A75D-E1D89C837142}.Release|Win32.ActiveCfg = Release|Win32
+ {EC8B7909-62AF-470D-A75D-E1D89C837142}.Release|Win32.Build.0 = Release|Win32
+ {97ECC711-7430-4FC4-90FD-004DA880E72A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {97ECC711-7430-4FC4-90FD-004DA880E72A}.Debug|Win32.Build.0 = Debug|Win32
+ {97ECC711-7430-4FC4-90FD-004DA880E72A}.Release|Win32.ActiveCfg = Release|Win32
+ {97ECC711-7430-4FC4-90FD-004DA880E72A}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {2DE20FFA-6F5E-48D9-84D8-09B044A5B119} = {E131F77D-B713-48F3-B86D-097ECDCC4C3A}
+ {EF019874-D38A-40E3-B17C-DB5923F0A79C} = {E131F77D-B713-48F3-B86D-097ECDCC4C3A}
+ {97ECC711-7430-4FC4-90FD-004DA880E72A} = {AD933CE2-1303-448E-89C8-60B1FDD18EC3}
+ EndGlobalSection
+EndGlobal
diff --git a/tools/visual_studio/v8_base.vcproj b/tools/visual_studio/v8_base.vcproj
index 37e604d..f1d6d07 100644
--- a/tools/visual_studio/v8_base.vcproj
+++ b/tools/visual_studio/v8_base.vcproj
@@ -285,14 +285,6 @@
>
</File>
<File
- RelativePath="..\..\src\assembler-arm-inl.h"
- >
- </File>
- <File
- RelativePath="..\..\src\assembler-arm.h"
- >
- </File>
- <File
RelativePath="..\..\src\assembler-ia32-inl.h"
>
</File>
@@ -369,10 +361,6 @@
>
</File>
<File
- RelativePath="..\..\src\codegen-arm.h"
- >
- </File>
- <File
RelativePath="..\..\src\codegen-ia32.cc"
>
</File>
@@ -493,14 +481,6 @@
>
</File>
<File
- RelativePath="..\..\src\frames-arm-inl.h"
- >
- </File>
- <File
- RelativePath="..\..\src\frames-arm.h"
- >
- </File>
- <File
RelativePath="..\..\src\frames-ia32-inl.h"
>
</File>
@@ -613,10 +593,6 @@
>
</File>
<File
- RelativePath="..\..\src\macro-assembler-arm.h"
- >
- </File>
- <File
RelativePath="..\..\src\macro-assembler-ia32.cc"
>
</File>
diff --git a/tools/visual_studio/v8_base_arm.vcproj b/tools/visual_studio/v8_base_arm.vcproj
new file mode 100644
index 0000000..ca9dc95
--- /dev/null
+++ b/tools/visual_studio/v8_base_arm.vcproj
@@ -0,0 +1,916 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="v8_base"
+ ProjectGUID="{EC8B7909-62AF-470D-A75D-E1D89C837142}"
+ RootNamespace="v8_base"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets=".\common.vsprops;.\debug.vsprops;.\arm.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)\lib\v8_base.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets=".\common.vsprops;.\release.vsprops;.\arm.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="jscre"
+ >
+ <File
+ RelativePath="..\..\src\third_party\jscre\pcre_compile.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\src\third_party\jscre\pcre_exec.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\src\third_party\jscre\pcre_internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\third_party\jscre\pcre_tables.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\src\third_party\jscre\pcre_ucp_searchfuncs.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\src\third_party\jscre\pcre_xclass.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UndefinePreprocessorDefinitions="DEBUG"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="dtoa"
+ >
+ <File
+ RelativePath="..\..\src\dtoa-config.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableSpecificWarnings="4018;4244"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableSpecificWarnings="4018;4244"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="src"
+ >
+ <File
+ RelativePath="..\..\src\accessors.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\accessors.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\allocation.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\allocation.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\api.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\api.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\arguments.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\assembler-arm-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\assembler-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\assembler-arm.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\assembler.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\assembler.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\ast.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\ast.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\bootstrapper.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\bootstrapper.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\builtins-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\builtins.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\builtins.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\char-predicates-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\char-predicates.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\checks.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\checks.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\code-stubs.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\code-stubs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\code.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\codegen-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\codegen-arm.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\codegen-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\codegen.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\codegen.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\compilation-cache.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\compilation-cache.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\compiler.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\compiler.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\constants-arm.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\contexts.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\contexts.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\conversions-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\conversions.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\conversions.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\counters.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\counters.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\cpu-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\cpu.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\dateparser.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\dateparser.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\debug.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\debug.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\disassembler.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\disassembler.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\execution.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\execution.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\factory.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\factory.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\flags.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\flags.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\frames-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\frames-arm.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\frames-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\frames.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\frames.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\global-handles.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\global-handles.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\globals.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\handles-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\handles.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\handles.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\hashmap.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\hashmap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\heap-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\heap.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\heap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\ic-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\ic-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\ic.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\ic.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\interceptors.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\jsregexp.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\jsregexp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\list-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\list.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\log.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\log.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\macro-assembler-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\macro-assembler-arm.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\macro-assembler.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\mark-compact.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\mark-compact.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\memory.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\messages.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\messages.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\natives.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\objects-debug.cc"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\src\objects-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\objects.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\objects.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\parser.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\parser.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\platform-win32.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\platform.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\prettyprinter.cc"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\src\prettyprinter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\property.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\property.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\rewriter.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\rewriter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\runtime.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\runtime.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\scanner.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\scanner.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\scopeinfo.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\scopeinfo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\scopes.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\scopes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\serialize.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\serialize.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\shell.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\snapshot-common.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\snapshot.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\simulator-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\simulator-arm.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\spaces-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\spaces.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\spaces.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\string-stream.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\string-stream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\stub-cache-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\stub-cache.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\stub-cache.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\token.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\token.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\top.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\top.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\unicode-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\unicode.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\usage-analyzer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\usage-analyzer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\utils.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\utils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\v8-counters.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\v8-counters.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\v8.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\v8.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\v8threads.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\v8threads.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\variables.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\variables.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\zone-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\zone.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\zone.h"
+ >
+ </File>
+ <Filter
+ Name="third party"
+ >
+ <File
+ RelativePath="..\..\src\disasm-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\disasm.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="generated files"
+ >
+ <File
+ RelativePath="..\..\src\unicode.cc"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="include"
+ >
+ <File
+ RelativePath="..\..\include\debug.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\v8.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tools/visual_studio/v8_cctest_arm.vcproj b/tools/visual_studio/v8_cctest_arm.vcproj
new file mode 100644
index 0000000..44812f0
--- /dev/null
+++ b/tools/visual_studio/v8_cctest_arm.vcproj
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="v8_cctest"
+ ProjectGUID="{97ECC711-7430-4FC4-90FD-004DA880E72A}"
+ RootNamespace="v8_cctest"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\common.vsprops;.\debug.vsprops;.\arm.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\common.vsprops;.\release.vsprops;.\arm.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\test\cctest\cctest.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-alloc.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-api.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-assembler-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-ast.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-compiler.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-conversions.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-debug.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-decls.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-disasm-arm.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-flags.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-hashmap.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-heap.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-lock.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-mark-compact.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-platform-win32.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-serialize.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-spaces.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-strings.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\test\cctest\test-utils.cc"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>