Push version 1.2.0 to trunk.
Optimized floating-point operations on ARM.
Added a number of extensions to the debugger API.
Changed the enumeration order for unsigned integer keys to always be numerical order.
Added a "read" extension to the shell sample.
Added support for Array.prototype.reduce and Array.prototype.reduceRight.
Added an option to the SCons build to control Microsoft Visual C++ link-time code generation.
Fixed a number of bugs (in particular issue 315, issue 316, issue 317 and issue 318).
git-svn-id: http://v8.googlecode.com/svn/trunk@1781 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/accessors.cc b/src/accessors.cc
index d779eb2..2d6a3a1 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -252,6 +252,24 @@
//
+// Accessors::ScriptData
+//
+
+
+Object* Accessors::ScriptGetData(Object* object, void*) {
+ Object* script = JSValue::cast(object)->value();
+ return Script::cast(script)->data();
+}
+
+
+const AccessorDescriptor Accessors::ScriptData = {
+ ScriptGetData,
+ IllegalSetter,
+ 0
+};
+
+
+//
// Accessors::ScriptType
//
diff --git a/src/accessors.h b/src/accessors.h
index 938b014..d174c90 100644
--- a/src/accessors.h
+++ b/src/accessors.h
@@ -45,6 +45,7 @@
V(ScriptId) \
V(ScriptLineOffset) \
V(ScriptColumnOffset) \
+ V(ScriptData) \
V(ScriptType) \
V(ScriptLineEnds) \
V(ObjectPrototype)
@@ -84,6 +85,7 @@
static Object* ScriptGetSource(Object* object, void*);
static Object* ScriptGetLineOffset(Object* object, void*);
static Object* ScriptGetColumnOffset(Object* object, void*);
+ static Object* ScriptGetData(Object* object, void*);
static Object* ScriptGetType(Object* object, void*);
static Object* ScriptGetLineEnds(Object* object, void*);
static Object* ObjectGetPrototype(Object* receiver, void*);
diff --git a/src/api.cc b/src/api.cc
index a190b9c..449926c 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1108,6 +1108,19 @@
}
+void Script::SetData(v8::Handle<Value> data) {
+ ON_BAILOUT("v8::Script::SetData()", return);
+ LOG_API("Script::SetData");
+ {
+ HandleScope scope;
+ i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
+ i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
+ i::Handle<i::Script> script(i::Script::cast(fun->shared()->script()));
+ script->set_data(*raw_data);
+ }
+}
+
+
// --- E x c e p t i o n s ---
@@ -1199,6 +1212,22 @@
}
+v8::Handle<Value> Message::GetScriptData() const {
+ if (IsDeadCheck("v8::Message::GetScriptResourceData()")) {
+ return Local<Value>();
+ }
+ ENTER_V8;
+ HandleScope scope;
+ i::Handle<i::JSObject> obj =
+ i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
+ // Return this.script.data.
+ i::Handle<i::JSValue> script =
+ i::Handle<i::JSValue>::cast(GetProperty(obj, "script"));
+ i::Handle<i::Object> data(i::Script::cast(script->value())->data());
+ return scope.Close(Utils::ToLocal(data));
+}
+
+
static i::Handle<i::Object> CallV8HeapFunction(const char* name,
i::Handle<i::Object> recv,
int argc,
@@ -1806,6 +1835,26 @@
}
+bool v8::Object::ForceSet(v8::Handle<Value> key,
+ v8::Handle<Value> value,
+ v8::PropertyAttribute attribs) {
+ ON_BAILOUT("v8::Object::ForceSet()", return false);
+ ENTER_V8;
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+ i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
+ EXCEPTION_PREAMBLE();
+ i::Handle<i::Object> obj = i::ForceSetProperty(
+ self,
+ key_obj,
+ value_obj,
+ static_cast<PropertyAttributes>(attribs));
+ has_pending_exception = obj.is_null();
+ EXCEPTION_BAILOUT_CHECK(false);
+ return true;
+}
+
+
Local<Value> v8::Object::Get(v8::Handle<Value> key) {
ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>());
ENTER_V8;
@@ -2373,7 +2422,7 @@
const char* v8::V8::GetVersion() {
- return "1.1.10.4";
+ return "1.2.0";
}
@@ -3180,8 +3229,8 @@
// --- D e b u g S u p p o r t ---
-
-bool Debug::SetDebugEventListener(DebugEventCallback that, Handle<Value> data) {
+#ifdef ENABLE_DEBUGGER_SUPPORT
+bool Debug::SetDebugEventListener(EventCallback that, Handle<Value> data) {
EnsureInitialized("v8::Debug::SetDebugEventListener()");
ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false);
ENTER_V8;
@@ -3211,31 +3260,27 @@
}
-void Debug::SetMessageHandler(v8::DebugMessageHandler handler, void* data,
+void Debug::SetMessageHandler(v8::Debug::MessageHandler handler,
bool message_handler_thread) {
EnsureInitialized("v8::Debug::SetMessageHandler");
ENTER_V8;
- i::Debugger::SetMessageHandler(handler, data, message_handler_thread);
+ i::Debugger::SetMessageHandler(handler, message_handler_thread);
}
-void Debug::SendCommand(const uint16_t* command, int length) {
+void Debug::SendCommand(const uint16_t* command, int length,
+ ClientData* client_data) {
if (!i::V8::HasBeenSetup()) return;
- i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length));
+ i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length),
+ client_data);
}
-void Debug::SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
- void* data) {
+void Debug::SetHostDispatchHandler(HostDispatchHandler handler,
+ int period) {
EnsureInitialized("v8::Debug::SetHostDispatchHandler");
ENTER_V8;
- i::Debugger::SetHostDispatchHandler(handler, data);
-}
-
-
-void Debug::SendHostDispatch(void* dispatch) {
- if (!i::V8::HasBeenSetup()) return;
- i::Debugger::ProcessHostDispatch(dispatch);
+ i::Debugger::SetHostDispatchHandler(handler, period);
}
@@ -3263,7 +3308,7 @@
bool Debug::EnableAgent(const char* name, int port) {
return i::Debugger::StartAgent(name, port);
}
-
+#endif // ENABLE_DEBUGGER_SUPPORT
namespace internal {
diff --git a/src/array.js b/src/array.js
index d30a989..0adbf9d 100644
--- a/src/array.js
+++ b/src/array.js
@@ -879,6 +879,62 @@
}
+function ArrayReduce(callback, current) {
+ if (!IS_FUNCTION(callback)) {
+ throw MakeTypeError('called_non_callable', [callback]);
+ }
+ // Pull out the length so that modifications to the length in the
+ // loop will not affect the looping.
+ var length = this.length;
+ var i = 0;
+
+ find_initial: if (%_ArgumentsLength() < 2) {
+ for (; i < length; i++) {
+ current = this[i];
+ if (!IS_UNDEFINED(current) || i in this) {
+ i++;
+ break find_initial;
+ }
+ }
+ throw MakeTypeError('reduce_no_initial', []);
+ }
+
+ for (; i < length; i++) {
+ var element = this[i];
+ if (!IS_UNDEFINED(element) || i in this) {
+ current = callback.call(null, current, element, i, this);
+ }
+ }
+ return current;
+}
+
+function ArrayReduceRight(callback, current) {
+ if (!IS_FUNCTION(callback)) {
+ throw MakeTypeError('called_non_callable', [callback]);
+ }
+ var i = this.length - 1;
+
+ find_initial: if (%_ArgumentsLength() < 2) {
+ for (; i >= 0; i--) {
+ current = this[i];
+ if (!IS_UNDEFINED(current) || i in this) {
+ i--;
+ break find_initial;
+ }
+ }
+ throw MakeTypeError('reduce_no_initial', []);
+ }
+
+ for (; i >= 0; i--) {
+ var element = this[i];
+ if (!IS_UNDEFINED(element) || i in this) {
+ current = callback.call(null, current, element, i, this);
+ }
+ }
+ return current;
+}
+
+
// -------------------------------------------------------------------
@@ -917,7 +973,9 @@
"every", ArrayEvery,
"map", ArrayMap,
"indexOf", ArrayIndexOf,
- "lastIndexOf", ArrayLastIndexOf
+ "lastIndexOf", ArrayLastIndexOf,
+ "reduce", ArrayReduce,
+ "reduceRight", ArrayReduceRight
));
// Manipulate the length of some of the functions to meet
@@ -930,7 +988,9 @@
ArrayMap: 1,
ArrayIndexOf: 1,
ArrayLastIndexOf: 1,
- ArrayPush: 1
+ ArrayPush: 1,
+ ArrayReduce: 1,
+ ArrayReduceRight: 1
});
}
diff --git a/src/assembler-ia32.cc b/src/assembler-ia32.cc
index 8549261..3a2d3f8 100644
--- a/src/assembler-ia32.cc
+++ b/src/assembler-ia32.cc
@@ -283,6 +283,10 @@
*pc_++ = (x)
+#ifdef GENERATED_CODE_COVERAGE
+static void InitCoverageLog();
+#endif
+
// spare_buffer_
static byte* spare_buffer_ = NULL;
@@ -315,9 +319,11 @@
// Clear the buffer in debug mode unless it was provided by the
// caller in which case we can't be sure it's okay to overwrite
// existing code in it; see CodePatcher::CodePatcher(...).
- if (kDebug && own_buffer_) {
+#ifdef DEBUG
+ if (own_buffer_) {
memset(buffer_, 0xCC, buffer_size); // int3
}
+#endif
// setup buffer pointers
ASSERT(buffer_ != NULL);
@@ -329,6 +335,9 @@
current_position_ = RelocInfo::kNoPosition;
written_statement_position_ = current_statement_position_;
written_position_ = current_position_;
+#ifdef GENERATED_CODE_COVERAGE
+ InitCoverageLog();
+#endif
}
@@ -2073,9 +2082,9 @@
// Clear the buffer in debug mode. Use 'int3' instructions to make
// sure to get into problems if we ever run uninitialized code.
- if (kDebug) {
- memset(desc.buffer, 0xCC, desc.buffer_size);
- }
+#ifdef DEBUG
+ memset(desc.buffer, 0xCC, desc.buffer_size);
+#endif
// copy the data
int pc_delta = desc.buffer - buffer_;
@@ -2202,4 +2211,30 @@
long_at_put(position, label_loc);
}
+
+#ifdef GENERATED_CODE_COVERAGE
+static FILE* coverage_log = NULL;
+
+
+static void InitCoverageLog() {
+ char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
+ if (file_name != NULL) {
+ coverage_log = fopen(file_name, "aw+");
+ }
+}
+
+
+void LogGeneratedCodeCoverage(const char* file_line) {
+ const char* return_address = (&file_line)[-1];
+ char* push_insn = const_cast<char*>(return_address - 12);
+ push_insn[0] = 0xeb; // Relative branch insn.
+ push_insn[1] = 13; // Skip over coverage insns.
+ if (coverage_log != NULL) {
+ fprintf(coverage_log, "%s\n", file_line);
+ fflush(coverage_log);
+ }
+}
+
+#endif
+
} } // namespace v8::internal
diff --git a/src/assembler.cc b/src/assembler.cc
index ad4b24c..ec0e4fd 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -521,10 +521,10 @@
ExternalReference::ExternalReference(const IC_Utility& ic_utility)
: address_(ic_utility.address()) {}
-
+#ifdef ENABLE_DEBUGGER_SUPPORT
ExternalReference::ExternalReference(const Debug_Address& debug_address)
: address_(debug_address.address()) {}
-
+#endif
ExternalReference::ExternalReference(StatsCounter* counter)
: address_(reinterpret_cast<Address>(counter->GetInternalPointer())) {}
@@ -557,29 +557,71 @@
}
-ExternalReference ExternalReference::debug_break() {
- return ExternalReference(FUNCTION_ADDR(Debug::Break));
-}
-
-
ExternalReference ExternalReference::new_space_start() {
return ExternalReference(Heap::NewSpaceStart());
}
+
ExternalReference ExternalReference::new_space_allocation_top_address() {
return ExternalReference(Heap::NewSpaceAllocationTopAddress());
}
+
ExternalReference ExternalReference::heap_always_allocate_scope_depth() {
return ExternalReference(Heap::always_allocate_scope_depth_address());
}
+
ExternalReference ExternalReference::new_space_allocation_limit_address() {
return ExternalReference(Heap::NewSpaceAllocationLimitAddress());
}
+
+static double add_two_doubles(double x, double y) {
+ return x + y;
+}
+
+
+static double sub_two_doubles(double x, double y) {
+ return x - y;
+}
+
+
+static double mul_two_doubles(double x, double y) {
+ return x * y;
+}
+
+
+ExternalReference ExternalReference::double_fp_operation(
+ Token::Value operation) {
+ typedef double BinaryFPOperation(double x, double y);
+ BinaryFPOperation* function = NULL;
+ switch (operation) {
+ case Token::ADD:
+ function = &add_two_doubles;
+ break;
+ case Token::SUB:
+ function = &sub_two_doubles;
+ break;
+ case Token::MUL:
+ function = &mul_two_doubles;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return ExternalReference(FUNCTION_ADDR(function));
+}
+
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ExternalReference ExternalReference::debug_break() {
+ return ExternalReference(FUNCTION_ADDR(Debug::Break));
+}
+
+
ExternalReference ExternalReference::debug_step_in_fp_address() {
return ExternalReference(Debug::step_in_fp_addr());
}
+#endif
} } // namespace v8::internal
diff --git a/src/assembler.h b/src/assembler.h
index 49c9b90..8abdbc7 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -38,6 +38,7 @@
#include "runtime.h"
#include "top.h"
#include "zone-inl.h"
+#include "token.h"
namespace v8 { namespace internal {
@@ -340,29 +341,15 @@
};
-// A stack-allocated code region logs a name for the code generated
-// while the region is in effect. This information is used by the
-// profiler to categorize ticks within generated code.
-class CodeRegion BASE_EMBEDDED {
- public:
- inline CodeRegion(Assembler* assm, const char *name) : assm_(assm) {
- LOG(BeginCodeRegionEvent(this, assm, name));
- }
- inline ~CodeRegion() {
- LOG(EndCodeRegionEvent(this, assm_));
- }
- private:
- Assembler* assm_;
-};
-
-
//------------------------------------------------------------------------------
// External function
//----------------------------------------------------------------------------
class IC_Utility;
-class Debug_Address;
class SCTableReference;
+#ifdef ENABLE_DEBUGGER_SUPPORT
+class Debug_Address;
+#endif
// An ExternalReference represents a C++ address called from the generated
// code. All references to C++ functions and must be encapsulated in an
@@ -380,7 +367,9 @@
explicit ExternalReference(const IC_Utility& ic_utility);
+#ifdef ENABLE_DEBUGGER_SUPPORT
explicit ExternalReference(const Debug_Address& debug_address);
+#endif
explicit ExternalReference(StatsCounter* counter);
@@ -403,9 +392,6 @@
// Static variable RegExpStack::limit_address()
static ExternalReference address_of_regexp_stack_limit();
- // Function Debug::Break()
- static ExternalReference debug_break();
-
// Static variable Heap::NewSpaceStart()
static ExternalReference new_space_start();
static ExternalReference heap_always_allocate_scope_depth();
@@ -414,11 +400,18 @@
static ExternalReference new_space_allocation_top_address();
static ExternalReference new_space_allocation_limit_address();
- // Used to check if single stepping is enabled in generated code.
- static ExternalReference debug_step_in_fp_address();
+ static ExternalReference double_fp_operation(Token::Value operation);
Address address() const {return address_;}
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ // Function Debug::Break()
+ static ExternalReference debug_break();
+
+ // Used to check if single stepping is enabled in generated code.
+ static ExternalReference debug_step_in_fp_address();
+#endif
+
private:
explicit ExternalReference(void* address)
: address_(reinterpret_cast<Address>(address)) {}
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 0a0ed83..eebec74 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -832,12 +832,16 @@
bool Genesis::CompileNative(Vector<const char> name, Handle<String> source) {
HandleScope scope;
+#ifdef ENABLE_DEBUGGER_SUPPORT
Debugger::set_compiling_natives(true);
+#endif
bool result =
CompileScriptCached(name, source, &natives_cache, NULL, true);
ASSERT(Top::has_pending_exception() != result);
if (!result) Top::clear_pending_exception();
+#ifdef ENABLE_DEBUGGER_SUPPORT
Debugger::set_compiling_natives(false);
+#endif
return result;
}
@@ -1015,6 +1019,13 @@
Factory::LookupAsciiSymbol("column_offset"),
proxy_column_offset,
common_attributes);
+ Handle<Proxy> proxy_data = Factory::NewProxy(&Accessors::ScriptData);
+ script_descriptors =
+ Factory::CopyAppendProxyDescriptor(
+ script_descriptors,
+ Factory::LookupAsciiSymbol("data"),
+ proxy_data,
+ common_attributes);
Handle<Proxy> proxy_type = Factory::NewProxy(&Accessors::ScriptType);
script_descriptors =
Factory::CopyAppendProxyDescriptor(
@@ -1132,6 +1143,7 @@
Handle<JSObject>(js_global->builtins()), DONT_ENUM);
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Expose the debug global object in global if a name for it is specified.
if (FLAG_expose_debug_as != NULL && strlen(FLAG_expose_debug_as) != 0) {
// If loading fails we just bail out without installing the
@@ -1149,6 +1161,7 @@
SetProperty(js_global, debug_string,
Handle<Object>(Debug::debug_context()->global_proxy()), DONT_ENUM);
}
+#endif
return true;
}
diff --git a/src/builtins-arm.cc b/src/builtins-arm.cc
index 2e6f255..58eeca8 100644
--- a/src/builtins-arm.cc
+++ b/src/builtins-arm.cc
@@ -34,7 +34,7 @@
namespace v8 { namespace internal {
-#define __ masm->
+#define __ ACCESS_MASM(masm)
void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
@@ -218,8 +218,9 @@
__ mov(r5, Operand(r4));
__ mov(r6, Operand(r4));
__ mov(r7, Operand(r4));
- if (kR9Available == 1)
+ if (kR9Available == 1) {
__ mov(r9, Operand(r4));
+ }
// Invoke the code and pass argc as r0.
__ mov(r0, Operand(r3));
diff --git a/src/builtins-ia32.cc b/src/builtins-ia32.cc
index 0e9de8c..9baeb5e 100644
--- a/src/builtins-ia32.cc
+++ b/src/builtins-ia32.cc
@@ -32,7 +32,7 @@
namespace v8 { namespace internal {
-#define __ masm->
+#define __ ACCESS_MASM(masm)
void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
@@ -69,10 +69,12 @@
Label rt_call, allocated;
if (FLAG_inline_new) {
Label undo_allocation;
+#ifdef ENABLE_DEBUGGER_SUPPORT
ExternalReference debug_step_in_fp =
ExternalReference::debug_step_in_fp_address();
__ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
__ j(not_equal, &rt_call);
+#endif
// Check that function is not a Smi.
__ test(edi, Immediate(kSmiTagMask));
__ j(zero, &rt_call);
diff --git a/src/builtins.cc b/src/builtins.cc
index c3935f1..b27974f 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -559,6 +559,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
Debug::GenerateLoadICDebugBreak(masm);
}
@@ -597,7 +598,7 @@
static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
Debug::GenerateStubNoRegistersDebugBreak(masm);
}
-
+#endif
Object* Builtins::builtins_[builtin_count] = { NULL, };
const char* Builtins::names_[builtin_count] = { NULL, };
diff --git a/src/builtins.h b/src/builtins.h
index 853c90e..4e74a3c 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -83,6 +83,7 @@
V(FunctionApply, BUILTIN, UNINITIALIZED)
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Define list of builtins used by the debugger implemented in assembly.
#define BUILTIN_LIST_DEBUG_A(V) \
V(Return_DebugBreak, BUILTIN, DEBUG_BREAK) \
@@ -93,7 +94,9 @@
V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK) \
V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK) \
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK)
-
+#else
+#define BUILTIN_LIST_DEBUG_A(V)
+#endif
// Define list of builtins implemented in JavaScript.
#define BUILTINS_LIST_JS(V) \
diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc
index 6fdabc3..9337454 100644
--- a/src/codegen-arm.cc
+++ b/src/codegen-arm.cc
@@ -38,7 +38,8 @@
namespace v8 { namespace internal {
-#define __ masm_->
+#define __ ACCESS_MASM(masm_)
+
// -------------------------------------------------------------------------
// CodeGenState implementation.
@@ -146,13 +147,13 @@
frame_->EmitPush(r0);
frame_->CallRuntime(Runtime::kNewContext, 1); // r0 holds the result
- if (kDebug) {
- JumpTarget verified_true(this);
- __ cmp(r0, Operand(cp));
- verified_true.Branch(eq);
- __ stop("NewContext: r0 is expected to be the same as cp");
- verified_true.Bind();
- }
+#ifdef DEBUG
+ JumpTarget verified_true(this);
+ __ cmp(r0, Operand(cp));
+ verified_true.Branch(eq);
+ __ stop("NewContext: r0 is expected to be the same as cp");
+ verified_true.Bind();
+#endif
// Update context local.
__ str(cp, frame_->Context());
}
@@ -653,37 +654,27 @@
}
-class GetPropertyStub : public CodeStub {
- public:
- GetPropertyStub() { }
-
- private:
- Major MajorKey() { return GetProperty; }
- int MinorKey() { return 0; }
- void Generate(MacroAssembler* masm);
-};
-
-
-class SetPropertyStub : public CodeStub {
- public:
- SetPropertyStub() { }
-
- private:
- Major MajorKey() { return SetProperty; }
- int MinorKey() { return 0; }
- void Generate(MacroAssembler* masm);
-};
-
-
class GenericBinaryOpStub : public CodeStub {
public:
- explicit GenericBinaryOpStub(Token::Value op) : op_(op) { }
+ GenericBinaryOpStub(Token::Value op,
+ OverwriteMode mode)
+ : op_(op), mode_(mode) { }
private:
Token::Value op_;
+ OverwriteMode mode_;
+
+ // Minor key encoding in 16 bits.
+ class ModeBits: public BitField<OverwriteMode, 0, 2> {};
+ class OpBits: public BitField<Token::Value, 2, 14> {};
Major MajorKey() { return GenericBinaryOp; }
- int MinorKey() { return static_cast<int>(op_); }
+ int MinorKey() {
+ // Encode the parameters in a unique 16 bit value.
+ return OpBits::encode(op_)
+ | ModeBits::encode(mode_);
+ }
+
void Generate(MacroAssembler* masm);
const char* GetName() {
@@ -708,7 +699,8 @@
};
-void CodeGenerator::GenericBinaryOperation(Token::Value op) {
+void CodeGenerator::GenericBinaryOperation(Token::Value op,
+ OverwriteMode overwrite_mode) {
VirtualFrame::SpilledScope spilled_scope(this);
// sp[0] : y
// sp[1] : x
@@ -727,7 +719,7 @@
case Token::SAR: {
frame_->EmitPop(r0); // r0 : y
frame_->EmitPop(r1); // r1 : x
- GenericBinaryOpStub stub(op);
+ GenericBinaryOpStub stub(op, overwrite_mode);
frame_->CallStub(&stub, 0);
break;
}
@@ -767,11 +759,13 @@
DeferredInlineSmiOperation(CodeGenerator* generator,
Token::Value op,
int value,
- bool reversed)
+ bool reversed,
+ OverwriteMode overwrite_mode)
: DeferredCode(generator),
op_(op),
value_(value),
- reversed_(reversed) {
+ reversed_(reversed),
+ overwrite_mode_(overwrite_mode) {
set_comment("[ DeferredInlinedSmiOperation");
}
@@ -781,6 +775,7 @@
Token::Value op_;
int value_;
bool reversed_;
+ OverwriteMode overwrite_mode_;
};
@@ -844,7 +839,7 @@
break;
}
- GenericBinaryOpStub igostub(op_);
+ GenericBinaryOpStub igostub(op_, overwrite_mode_);
Result arg0 = generator()->allocator()->Allocate(r1);
ASSERT(arg0.is_valid());
Result arg1 = generator()->allocator()->Allocate(r0);
@@ -856,7 +851,8 @@
void CodeGenerator::SmiOperation(Token::Value op,
Handle<Object> value,
- bool reversed) {
+ bool reversed,
+ OverwriteMode mode) {
VirtualFrame::SpilledScope spilled_scope(this);
// NOTE: This is an attempt to inline (a bit) more of the code for
// some possible smi operations (like + and -) when (at least) one
@@ -875,7 +871,7 @@
switch (op) {
case Token::ADD: {
DeferredCode* deferred =
- new DeferredInlineSmiOperation(this, op, int_value, reversed);
+ new DeferredInlineSmiOperation(this, op, int_value, reversed, mode);
__ add(r0, r0, Operand(value), SetCC);
deferred->enter()->Branch(vs);
@@ -887,7 +883,7 @@
case Token::SUB: {
DeferredCode* deferred =
- new DeferredInlineSmiOperation(this, op, int_value, reversed);
+ new DeferredInlineSmiOperation(this, op, int_value, reversed, mode);
if (!reversed) {
__ sub(r0, r0, Operand(value), SetCC);
@@ -905,7 +901,7 @@
case Token::BIT_XOR:
case Token::BIT_AND: {
DeferredCode* deferred =
- new DeferredInlineSmiOperation(this, op, int_value, reversed);
+ new DeferredInlineSmiOperation(this, op, int_value, reversed, mode);
__ tst(r0, Operand(kSmiTagMask));
deferred->enter()->Branch(ne);
switch (op) {
@@ -925,12 +921,12 @@
__ mov(ip, Operand(value));
frame_->EmitPush(ip);
frame_->EmitPush(r0);
- GenericBinaryOperation(op);
+ GenericBinaryOperation(op, mode);
} else {
int shift_value = int_value & 0x1f; // least significant 5 bits
DeferredCode* deferred =
- new DeferredInlineSmiOperation(this, op, shift_value, false);
+ new DeferredInlineSmiOperation(this, op, shift_value, false, mode);
__ tst(r0, Operand(kSmiTagMask));
deferred->enter()->Branch(ne);
__ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags
@@ -982,7 +978,7 @@
frame_->EmitPush(ip);
frame_->EmitPush(r0);
}
- GenericBinaryOperation(op);
+ GenericBinaryOperation(op, mode);
break;
}
@@ -1427,13 +1423,13 @@
} else {
frame_->CallRuntime(Runtime::kPushContext, 1);
}
- if (kDebug) {
- JumpTarget verified_true(this);
- __ cmp(r0, Operand(cp));
- verified_true.Branch(eq);
- __ stop("PushContext: r0 is expected to be the same as cp");
- verified_true.Bind();
- }
+#ifdef DEBUG
+ JumpTarget verified_true(this);
+ __ cmp(r0, Operand(cp));
+ verified_true.Branch(eq);
+ __ stop("PushContext: r0 is expected to be the same as cp");
+ verified_true.Bind();
+#endif
// Update context local.
__ str(cp, frame_->Context());
ASSERT(frame_->height() == original_height);
@@ -1487,8 +1483,8 @@
// Test for a Smi value in a HeapNumber.
__ tst(r0, Operand(kSmiTagMask));
is_smi.Branch(eq);
- __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag));
- __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag));
+ __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+ __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
__ cmp(r1, Operand(HEAP_NUMBER_TYPE));
default_target->Branch(ne);
frame_->EmitPush(r0);
@@ -2339,7 +2335,9 @@
VirtualFrame::SpilledScope spilled_scope(this);
Comment cmnt(masm_, "[ DebuggerStatament");
CodeForStatementPosition(node);
+#ifdef ENABLE_DEBUGGER_SUPPORT
frame_->CallRuntime(Runtime::kDebugBreak, 0);
+#endif
// Ignore the return value.
ASSERT(frame_->height() == original_height);
}
@@ -2523,7 +2521,9 @@
if (s->is_eval_scope()) {
Label next, fast;
- if (!context.is(tmp)) __ mov(tmp, Operand(context));
+ if (!context.is(tmp)) {
+ __ mov(tmp, Operand(context));
+ }
__ bind(&next);
// Terminate at global context.
__ ldr(tmp2, FieldMemOperand(tmp, HeapObject::kMapOffset));
@@ -2934,15 +2934,24 @@
LoadAndSpill(node->value());
} else {
+ // +=, *= and similar binary assignments.
+ // Get the old value of the lhs.
target.GetValueAndSpill(NOT_INSIDE_TYPEOF);
Literal* literal = node->value()->AsLiteral();
+ bool overwrite =
+ (node->value()->AsBinaryOperation() != NULL &&
+ node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
if (literal != NULL && literal->handle()->IsSmi()) {
- SmiOperation(node->binary_op(), literal->handle(), false);
+ SmiOperation(node->binary_op(),
+ literal->handle(),
+ false,
+ overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE);
frame_->EmitPush(r0);
} else {
LoadAndSpill(node->value());
- GenericBinaryOperation(node->binary_op());
+ GenericBinaryOperation(node->binary_op(),
+ overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE);
frame_->EmitPush(r0);
}
}
@@ -3822,19 +3831,39 @@
// is a literal small integer.
Literal* lliteral = node->left()->AsLiteral();
Literal* rliteral = node->right()->AsLiteral();
+ // NOTE: The code below assumes that the slow cases (calls to runtime)
+ // never return a constant/immutable object.
+ bool overwrite_left =
+ (node->left()->AsBinaryOperation() != NULL &&
+ node->left()->AsBinaryOperation()->ResultOverwriteAllowed());
+ bool overwrite_right =
+ (node->right()->AsBinaryOperation() != NULL &&
+ node->right()->AsBinaryOperation()->ResultOverwriteAllowed());
if (rliteral != NULL && rliteral->handle()->IsSmi()) {
LoadAndSpill(node->left());
- SmiOperation(node->op(), rliteral->handle(), false);
+ SmiOperation(node->op(),
+ rliteral->handle(),
+ false,
+ overwrite_right ? OVERWRITE_RIGHT : NO_OVERWRITE);
} else if (lliteral != NULL && lliteral->handle()->IsSmi()) {
LoadAndSpill(node->right());
- SmiOperation(node->op(), lliteral->handle(), true);
+ SmiOperation(node->op(),
+ lliteral->handle(),
+ true,
+ overwrite_left ? OVERWRITE_LEFT : NO_OVERWRITE);
} else {
+ OverwriteMode overwrite_mode = NO_OVERWRITE;
+ if (overwrite_left) {
+ overwrite_mode = OVERWRITE_LEFT;
+ } else if (overwrite_right) {
+ overwrite_mode = OVERWRITE_RIGHT;
+ }
LoadAndSpill(node->left());
LoadAndSpill(node->right());
- GenericBinaryOperation(node->op());
+ GenericBinaryOperation(node->op(), overwrite_mode);
}
frame_->EmitPush(r0);
}
@@ -4067,7 +4096,8 @@
#undef __
-#define __ masm->
+#define __ ACCESS_MASM(masm)
+
Handle<String> Reference::GetName() {
ASSERT(type_ == NAMED);
@@ -4305,167 +4335,80 @@
}
-void GetPropertyStub::Generate(MacroAssembler* masm) {
- // sp[0]: key
- // sp[1]: receiver
- Label slow, fast;
- // Get the key and receiver object from the stack.
- __ ldm(ia, sp, r0.bit() | r1.bit());
- // Check that the key is a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(ne, &slow);
- __ mov(r0, Operand(r0, ASR, kSmiTagSize));
- // Check that the object isn't a smi.
- __ tst(r1, Operand(kSmiTagMask));
- __ b(eq, &slow);
-
- // Check that the object is some kind of JS object EXCEPT JS Value type.
- // In the case that the object is a value-wrapper object,
- // we enter the runtime system to make sure that indexing into string
- // objects work as intended.
- ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
- __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
- __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
- __ cmp(r2, Operand(JS_OBJECT_TYPE));
- __ b(lt, &slow);
-
- // Get the elements array of the object.
- __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
- // Check that the object is in fast mode (not dictionary).
- __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
- __ cmp(r3, Operand(Factory::hash_table_map()));
- __ b(eq, &slow);
- // Check that the key (index) is within bounds.
- __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
- __ cmp(r0, Operand(r3));
- __ b(lo, &fast);
-
- // Slow case: Push extra copies of the arguments (2).
+static void HandleBinaryOpSlowCases(MacroAssembler* masm,
+ Label* not_smi,
+ const Builtins::JavaScript& builtin,
+ Token::Value operation,
+ int swi_number,
+ OverwriteMode mode) {
+ Label slow;
+ if (mode == NO_OVERWRITE) {
+ __ bind(not_smi);
+ }
__ bind(&slow);
- __ ldm(ia, sp, r0.bit() | r1.bit());
- __ stm(db_w, sp, r0.bit() | r1.bit());
- // Do tail-call to runtime routine.
- __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2);
+ __ push(r1);
+ __ push(r0);
+ __ mov(r0, Operand(1)); // Set number of arguments.
+ __ InvokeBuiltin(builtin, JUMP_JS); // Tail call.
- // Fast case: Do the load.
- __ bind(&fast);
- __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag));
- __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
- __ cmp(r0, Operand(Factory::the_hole_value()));
- // In case the loaded value is the_hole we have to consult GetProperty
- // to ensure the prototype chain is searched.
- __ b(eq, &slow);
-
- __ StubReturn(1);
-}
-
-
-void SetPropertyStub::Generate(MacroAssembler* masm) {
- // r0 : value
- // sp[0] : key
- // sp[1] : receiver
-
- Label slow, fast, array, extra, exit;
- // Get the key and the object from the stack.
- __ ldm(ia, sp, r1.bit() | r3.bit()); // r1 = key, r3 = receiver
- // Check that the key is a smi.
- __ tst(r1, Operand(kSmiTagMask));
- __ b(ne, &slow);
- // Check that the object isn't a smi.
- __ tst(r3, Operand(kSmiTagMask));
- __ b(eq, &slow);
- // Get the type of the object from its map.
- __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
- __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
- // Check if the object is a JS array or not.
- __ cmp(r2, Operand(JS_ARRAY_TYPE));
- __ b(eq, &array);
- // Check that the object is some kind of JS object.
- __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
- __ b(lt, &slow);
-
-
- // Object case: Check key against length in the elements array.
- __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset));
- // Check that the object is in fast mode (not dictionary).
- __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
- __ cmp(r2, Operand(Factory::hash_table_map()));
- __ b(eq, &slow);
- // Untag the key (for checking against untagged length in the fixed array).
- __ mov(r1, Operand(r1, ASR, kSmiTagSize));
- // Compute address to store into and check array bounds.
- __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag));
- __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
- __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset));
- __ cmp(r1, Operand(ip));
- __ b(lo, &fast);
-
-
- // Slow case: Push extra copies of the arguments (3).
- __ bind(&slow);
- __ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object
- __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit());
- // Do tail-call to runtime routine.
- __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
-
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- // r0 == value, r1 == key, r2 == elements, r3 == object
- __ bind(&extra);
- __ b(ne, &slow); // do not leave holes in the array
- __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // untag
- __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset));
- __ cmp(r1, Operand(ip));
- __ b(hs, &slow);
- __ mov(r1, Operand(r1, LSL, kSmiTagSize)); // restore tag
- __ add(r1, r1, Operand(1 << kSmiTagSize)); // and increment
- __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset));
- __ mov(r3, Operand(r2));
- // NOTE: Computing the address to store into must take the fact
- // that the key has been incremented into account.
- int displacement = Array::kHeaderSize - kHeapObjectTag -
- ((1 << kSmiTagSize) * 2);
- __ add(r2, r2, Operand(displacement));
- __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
- __ b(&fast);
-
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode; if it is the
- // length is always a smi.
- // r0 == value, r3 == object
- __ bind(&array);
- __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset));
- __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
- __ cmp(r1, Operand(Factory::hash_table_map()));
- __ b(eq, &slow);
-
- // Check the key against the length in the array, compute the
- // address to store into and fall through to fast case.
- __ ldr(r1, MemOperand(sp));
- // r0 == value, r1 == key, r2 == elements, r3 == object.
- __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset));
- __ cmp(r1, Operand(ip));
- __ b(hs, &extra);
- __ mov(r3, Operand(r2));
- __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag));
- __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
-
-
- // Fast case: Do the store.
- // r0 == value, r2 == address to store into, r3 == elements
- __ bind(&fast);
- __ str(r0, MemOperand(r2));
- // Skip write barrier if the written value is a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &exit);
- // Update write barrier for the elements array address.
- __ sub(r1, r2, Operand(r3));
- __ RecordWrite(r3, r1, r2);
- __ bind(&exit);
- __ StubReturn(1);
+ // Could it be a double-double op? If we already have a place to put
+ // the answer then we can do the op and skip the builtin and runtime call.
+ if (mode != NO_OVERWRITE) {
+ __ bind(not_smi);
+ __ tst(r0, Operand(kSmiTagMask));
+ __ b(eq, &slow); // We can't handle a Smi-double combination yet.
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(eq, &slow); // We can't handle a Smi-double combination yet.
+ // Get map of r0 into r2.
+ __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
+ // Get type of r0 into r3.
+ __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+ __ cmp(r3, Operand(HEAP_NUMBER_TYPE));
+ __ b(ne, &slow);
+ // Get type of r1 into r3.
+ __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
+ // Check they are both the same map (heap number map).
+ __ cmp(r2, r3);
+ __ b(ne, &slow);
+ // Both are doubles.
+ // Calling convention says that second double is in r2 and r3.
+ __ ldr(r2, FieldMemOperand(r0, HeapNumber::kValueOffset));
+ __ ldr(r3, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize));
+ __ push(lr);
+ if (mode == OVERWRITE_LEFT) {
+ __ push(r1);
+ } else {
+ __ push(r0);
+ }
+ // Calling convention says that first double is in r0 and r1.
+ __ ldr(r0, FieldMemOperand(r1, HeapNumber::kValueOffset));
+ __ ldr(r1, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize));
+ // Call C routine that may not cause GC or other trouble.
+ __ mov(r5, Operand(ExternalReference::double_fp_operation(operation)));
+#if !defined(__arm__)
+ // Notify the simulator that we are calling an add routine in C.
+ __ swi(swi_number);
+#else
+ // Actually call the add routine written in C.
+ __ Call(r5);
+#endif
+ // Store answer in the overwritable heap number.
+ __ pop(r4);
+#if !defined(__ARM_EABI__) && defined(__arm__)
+ // Double returned in fp coprocessor register 0 and 1, encoded as register
+ // cr8. Offsets must be divisible by 4 for coprocessor so we need to
+ // substract the tag from r4.
+ __ sub(r5, r4, Operand(kHeapObjectTag));
+ __ stc(p1, cr8, MemOperand(r5, HeapNumber::kValueOffset));
+#else
+ // Double returned in fp coprocessor register 0 and 1.
+ __ str(r0, FieldMemOperand(r4, HeapNumber::kValueOffset));
+ __ str(r1, FieldMemOperand(r4, HeapNumber::kValueOffset + kPointerSize));
+#endif
+ __ mov(r0, Operand(r4));
+ // And we are done.
+ __ pop(pc);
+ }
}
@@ -4474,89 +4417,84 @@
// r0 : y
// result : r0
+ // All ops need to know whether we are dealing with two Smis. Set up r2 to
+ // tell us that.
+ __ orr(r2, r1, Operand(r0)); // r2 = x | y;
+
switch (op_) {
case Token::ADD: {
- Label slow, exit;
- // fast path
- __ orr(r2, r1, Operand(r0)); // r2 = x | y;
- __ add(r0, r1, Operand(r0), SetCC); // add y optimistically
- // go slow-path in case of overflow
- __ b(vs, &slow);
- // go slow-path in case of non-smi operands
- ASSERT(kSmiTag == 0); // adjust code below
+ Label not_smi;
+ // Fast path.
+ ASSERT(kSmiTag == 0); // Adjust code below.
__ tst(r2, Operand(kSmiTagMask));
- __ b(eq, &exit);
- // slow path
- __ bind(&slow);
- __ sub(r0, r0, Operand(r1)); // revert optimistic add
- __ push(r1);
- __ push(r0);
- __ mov(r0, Operand(1)); // set number of arguments
- __ InvokeBuiltin(Builtins::ADD, JUMP_JS);
- // done
- __ bind(&exit);
+ __ b(ne, ¬_smi);
+ __ add(r0, r1, Operand(r0), SetCC); // Add y optimistically.
+ // Return if no overflow.
+ __ Ret(vc);
+ __ sub(r0, r0, Operand(r1)); // Revert optimistic add.
+
+ HandleBinaryOpSlowCases(masm,
+ ¬_smi,
+ Builtins::ADD,
+ Token::ADD,
+ assembler::arm::simulator_fp_add,
+ mode_);
break;
}
case Token::SUB: {
- Label slow, exit;
- // fast path
- __ orr(r2, r1, Operand(r0)); // r2 = x | y;
- __ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically
- // go slow-path in case of overflow
- __ b(vs, &slow);
- // go slow-path in case of non-smi operands
- ASSERT(kSmiTag == 0); // adjust code below
+ Label not_smi;
+ // Fast path.
+ ASSERT(kSmiTag == 0); // Adjust code below.
__ tst(r2, Operand(kSmiTagMask));
- __ mov(r0, Operand(r3), LeaveCC, eq); // conditionally set r0 to result
- __ b(eq, &exit);
- // slow path
- __ bind(&slow);
- __ push(r1);
- __ push(r0);
- __ mov(r0, Operand(1)); // set number of arguments
- __ InvokeBuiltin(Builtins::SUB, JUMP_JS);
- // done
- __ bind(&exit);
+ __ b(ne, ¬_smi);
+ __ sub(r0, r1, Operand(r0), SetCC); // Subtract y optimistically.
+ // Return if no overflow.
+ __ Ret(vc);
+ __ sub(r0, r1, Operand(r0)); // Revert optimistic subtract.
+
+ HandleBinaryOpSlowCases(masm,
+ ¬_smi,
+ Builtins::SUB,
+ Token::SUB,
+ assembler::arm::simulator_fp_sub,
+ mode_);
break;
}
case Token::MUL: {
- Label slow, exit;
- // tag check
- __ orr(r2, r1, Operand(r0)); // r2 = x | y;
+ Label not_smi, slow;
ASSERT(kSmiTag == 0); // adjust code below
__ tst(r2, Operand(kSmiTagMask));
- __ b(ne, &slow);
- // remove tag from one operand (but keep sign), so that result is smi
+ __ b(ne, ¬_smi);
+ // Remove tag from one operand (but keep sign), so that result is Smi.
__ mov(ip, Operand(r0, ASR, kSmiTagSize));
- // do multiplication
- __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1
- // go slow on overflows (overflow bit is not set)
+ // Do multiplication
+ __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1.
+ // Go slow on overflows (overflow bit is not set).
__ mov(ip, Operand(r3, ASR, 31));
__ cmp(ip, Operand(r2)); // no overflow if higher 33 bits are identical
__ b(ne, &slow);
- // go slow on zero result to handle -0
+ // Go slow on zero result to handle -0.
__ tst(r3, Operand(r3));
__ mov(r0, Operand(r3), LeaveCC, ne);
- __ b(ne, &exit);
- // slow case
+ __ Ret(ne);
+ // Slow case.
__ bind(&slow);
- __ push(r1);
- __ push(r0);
- __ mov(r0, Operand(1)); // set number of arguments
- __ InvokeBuiltin(Builtins::MUL, JUMP_JS);
- // done
- __ bind(&exit);
+
+ HandleBinaryOpSlowCases(masm,
+ ¬_smi,
+ Builtins::MUL,
+ Token::MUL,
+ assembler::arm::simulator_fp_mul,
+ mode_);
break;
}
case Token::BIT_OR:
case Token::BIT_AND:
case Token::BIT_XOR: {
- Label slow, exit;
- // tag check
- __ orr(r2, r1, Operand(r0)); // r2 = x | y;
+ Label slow;
ASSERT(kSmiTag == 0); // adjust code below
__ tst(r2, Operand(kSmiTagMask));
__ b(ne, &slow);
@@ -4566,7 +4504,7 @@
case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
default: UNREACHABLE();
}
- __ b(&exit);
+ __ Ret();
__ bind(&slow);
__ push(r1); // restore stack
__ push(r0);
@@ -4584,16 +4522,13 @@
default:
UNREACHABLE();
}
- __ bind(&exit);
break;
}
case Token::SHL:
case Token::SHR:
case Token::SAR: {
- Label slow, exit;
- // tag check
- __ orr(r2, r1, Operand(r0)); // r2 = x | y;
+ Label slow;
ASSERT(kSmiTag == 0); // adjust code below
__ tst(r2, Operand(kSmiTagMask));
__ b(ne, &slow);
@@ -4633,7 +4568,7 @@
// tag result and store it in r0
ASSERT(kSmiTag == 0); // adjust code below
__ mov(r0, Operand(r3, LSL, kSmiTagSize));
- __ b(&exit);
+ __ Ret();
// slow case
__ bind(&slow);
__ push(r1); // restore stack
@@ -4645,13 +4580,13 @@
case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break;
default: UNREACHABLE();
}
- __ bind(&exit);
break;
}
default: UNREACHABLE();
}
- __ Ret();
+ // This code should be unreachable.
+ __ stop("Unreachable");
}
@@ -4721,7 +4656,11 @@
__ mov(cp, Operand(0), LeaveCC, eq);
// Restore cp otherwise.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
- if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
+#ifdef DEBUG
+ if (FLAG_debug_code) {
+ __ mov(lr, Operand(pc));
+ }
+#endif
__ pop(pc);
}
@@ -4784,7 +4723,11 @@
__ mov(cp, Operand(0), LeaveCC, eq);
// Restore cp otherwise.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
- if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
+#ifdef DEBUG
+ if (FLAG_debug_code) {
+ __ mov(lr, Operand(pc));
+ }
+#endif
__ pop(pc);
}
@@ -5043,9 +4986,11 @@
}
__ ldr(ip, MemOperand(ip)); // deref address
- // Branch and link to JSEntryTrampoline
+ // Branch and link to JSEntryTrampoline. We don't use the double underscore
+ // macro for the add instruction because we don't want the coverage tool
+ // inserting instructions here after we read the pc.
__ mov(lr, Operand(pc));
- __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
+ masm->add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
// Unlink this frame from the handler chain. When reading the
// address of the next handler, there is no need to use the address
@@ -5057,6 +5002,7 @@
// No need to restore registers
__ add(sp, sp, Operand(StackHandlerConstants::kSize));
+
__ bind(&exit); // r0 holds result
// Restore the top frame descriptors from the stack.
__ pop(r3);
@@ -5068,7 +5014,9 @@
// Restore callee-saved registers and return.
#ifdef DEBUG
- if (FLAG_debug_code) __ mov(lr, Operand(pc));
+ if (FLAG_debug_code) {
+ __ mov(lr, Operand(pc));
+ }
#endif
__ ldm(ia_w, sp, kCalleeSaved | pc.bit());
}
diff --git a/src/codegen-arm.h b/src/codegen-arm.h
index b072f75..48b92ea 100644
--- a/src/codegen-arm.h
+++ b/src/codegen-arm.h
@@ -35,9 +35,6 @@
class RegisterAllocator;
class RegisterFile;
-// 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 };
@@ -292,10 +289,13 @@
void ToBoolean(JumpTarget* true_target, JumpTarget* false_target);
- void GenericBinaryOperation(Token::Value op);
+ void GenericBinaryOperation(Token::Value op, OverwriteMode overwrite_mode);
void Comparison(Condition cc, bool strict = false);
- void SmiOperation(Token::Value op, Handle<Object> value, bool reversed);
+ void SmiOperation(Token::Value op,
+ Handle<Object> value,
+ bool reversed,
+ OverwriteMode mode);
void CallWithArguments(ZoneList<Expression*>* arguments, int position);
diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc
index 663f235..fb2f8bf 100644
--- a/src/codegen-ia32.cc
+++ b/src/codegen-ia32.cc
@@ -37,7 +37,7 @@
namespace v8 { namespace internal {
-#define __ masm_->
+#define __ ACCESS_MASM(masm_)
// -------------------------------------------------------------------------
// CodeGenState implementation.
@@ -1274,12 +1274,9 @@
smi_value,
overwrite_mode);
__ Set(answer.reg(), Immediate(value));
- if (operand->is_register()) {
- __ sub(answer.reg(), Operand(operand->reg()));
- } else {
- ASSERT(operand->is_constant());
- __ sub(Operand(answer.reg()), Immediate(operand->handle()));
- }
+ // We are in the reversed case so they can't both be Smi constants.
+ ASSERT(operand->is_register());
+ __ sub(answer.reg(), Operand(operand->reg()));
} else {
operand->ToRegister();
frame_->Spill(operand->reg());
@@ -1374,23 +1371,26 @@
operand->ToRegister();
__ test(operand->reg(), Immediate(kSmiTagMask));
deferred->enter()->Branch(not_zero, operand, not_taken);
- Result answer = allocator()->Allocate();
- ASSERT(answer.is_valid());
- __ mov(answer.reg(), operand->reg());
- ASSERT(kSmiTag == 0); // adjust code if not the case
- // We do no shifts, only the Smi conversion, if shift_value is 1.
- if (shift_value == 0) {
- __ sar(answer.reg(), kSmiTagSize);
- } else if (shift_value > 1) {
- __ shl(answer.reg(), shift_value - 1);
+ if (shift_value != 0) {
+ Result answer = allocator()->Allocate();
+ ASSERT(answer.is_valid());
+ __ mov(answer.reg(), operand->reg());
+ ASSERT(kSmiTag == 0); // adjust code if not the case
+ // We do no shifts, only the Smi conversion, if shift_value is 1.
+ if (shift_value > 1) {
+ __ shl(answer.reg(), shift_value - 1);
+ }
+ // Convert int result to Smi, checking that it is in int range.
+ ASSERT(kSmiTagSize == times_2); // adjust code if not the case
+ __ add(answer.reg(), Operand(answer.reg()));
+ deferred->enter()->Branch(overflow, operand, not_taken);
+ operand->Unuse();
+ deferred->BindExit(&answer);
+ frame_->Push(&answer);
+ } else {
+ deferred->BindExit(operand);
+ frame_->Push(operand);
}
- // Convert int result to Smi, checking that it is in int range.
- ASSERT(kSmiTagSize == times_2); // adjust code if not the case
- __ add(answer.reg(), Operand(answer.reg()));
- deferred->enter()->Branch(overflow, operand, not_taken);
- operand->Unuse();
- deferred->BindExit(&answer);
- frame_->Push(&answer);
}
break;
}
@@ -1411,11 +1411,7 @@
deferred->enter()->Branch(not_zero, operand, not_taken);
frame_->Spill(operand->reg());
if (op == Token::BIT_AND) {
- if (int_value == 0) {
- __ xor_(Operand(operand->reg()), operand->reg());
- } else {
- __ and_(Operand(operand->reg()), Immediate(value));
- }
+ __ and_(Operand(operand->reg()), Immediate(value));
} else if (op == Token::BIT_XOR) {
if (int_value != 0) {
__ xor_(Operand(operand->reg()), Immediate(value));
@@ -2009,18 +2005,18 @@
// Add a label for checking the size of the code used for returning.
Label check_exit_codesize;
- __ bind(&check_exit_codesize);
+ masm_->bind(&check_exit_codesize);
// Leave the frame and return popping the arguments and the
// receiver.
frame_->Exit();
- __ ret((scope_->num_parameters() + 1) * kPointerSize);
+ masm_->ret((scope_->num_parameters() + 1) * kPointerSize);
DeleteFrame();
// Check that the size of the code used for returning matches what is
// expected by the debugger.
ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
- __ SizeOfCodeGeneratedSince(&check_exit_codesize));
+ masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
}
@@ -2143,7 +2139,7 @@
times_1, 0x0, RelocInfo::INTERNAL_REFERENCE));
smi_value.Unuse();
// Calculate address to overwrite later with actual address of table.
- int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t);
+ int32_t jump_table_ref = masm_->pc_offset() - sizeof(int32_t);
__ Align(4);
Label table_start;
__ bind(&table_start);
@@ -3179,10 +3175,12 @@
ASSERT(!in_spilled_code());
Comment cmnt(masm_, "[ DebuggerStatement");
CodeForStatementPosition(node);
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Spill everything, even constants, to the frame.
frame_->SpillAll();
frame_->CallRuntime(Runtime::kDebugBreak, 0);
// Ignore the return value.
+#endif
}
@@ -3384,7 +3382,9 @@
// Loop up the context chain. There is no frame effect so it is
// safe to use raw labels here.
Label next, fast;
- if (!context.reg().is(tmp.reg())) __ mov(tmp.reg(), context.reg());
+ if (!context.reg().is(tmp.reg())) {
+ __ mov(tmp.reg(), context.reg());
+ }
__ bind(&next);
// Terminate at global context.
__ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset),
@@ -3933,6 +3933,9 @@
} else {
Literal* literal = node->value()->AsLiteral();
+ bool overwrite_value =
+ (node->value()->AsBinaryOperation() != NULL &&
+ node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
Variable* right_var = node->value()->AsVariableProxy()->AsVariable();
// There are two cases where the target is not read in the right hand
// side, that are easy to test for: the right hand side is a literal,
@@ -3945,7 +3948,9 @@
target.GetValue(NOT_INSIDE_TYPEOF);
}
Load(node->value());
- GenericBinaryOperation(node->binary_op(), node->type());
+ GenericBinaryOperation(node->binary_op(),
+ node->type(),
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
}
if (var != NULL &&
@@ -5268,8 +5273,11 @@
// instruction.
ASSERT(value.is_register() && value.reg().is(eax));
// The delta from the start of the map-compare instruction to the
- // test eax instruction.
- int delta_to_patch_site = __ SizeOfCodeGeneratedSince(patch_site());
+ // test eax instruction. We use masm_ directly here instead of the
+ // double underscore macro because the macro sometimes uses macro
+ // expansion to turn into something that can't return a value. This
+ // is encountered when doing generated code coverage tests.
+ int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site());
__ test(value.reg(), Immediate(-delta_to_patch_site));
__ IncrementCounter(&Counters::keyed_load_inline_miss, 1);
@@ -5284,7 +5292,7 @@
#undef __
-#define __ masm->
+#define __ ACCESS_MASM(masm)
Handle<String> Reference::GetName() {
ASSERT(type_ == NAMED);
@@ -5369,7 +5377,9 @@
// Initially, use an invalid map. The map is patched in the IC
// initialization code.
__ bind(deferred->patch_site());
- __ cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
+ // Use masm-> here instead of the double underscore macro since extra
+ // coverage code can interfere with the patching.
+ masm->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
Immediate(Factory::null_value()));
deferred->enter()->Branch(not_equal, &receiver, &key, not_taken);
@@ -5566,7 +5576,7 @@
#undef __
-#define __ masm_->
+#define __ ACCESS_MASM(masm_)
Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left,
Result* right) {
@@ -5900,7 +5910,7 @@
#undef __
-#define __ masm->
+#define __ ACCESS_MASM(masm)
void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
// Perform fast-case smi code for the operation (eax <op> ebx) and
@@ -6225,7 +6235,9 @@
}
// SHR should return uint32 - go to runtime for non-smi/negative result.
- if (op_ == Token::SHR) __ bind(&non_smi_result);
+ if (op_ == Token::SHR) {
+ __ bind(&non_smi_result);
+ }
__ mov(eax, Operand(esp, 1 * kPointerSize));
__ mov(edx, Operand(esp, 2 * kPointerSize));
break;
diff --git a/src/codegen-ia32.h b/src/codegen-ia32.h
index 24a57a0..a39bc58 100644
--- a/src/codegen-ia32.h
+++ b/src/codegen-ia32.h
@@ -35,9 +35,6 @@
class RegisterAllocator;
class RegisterFile;
-// 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 };
@@ -435,7 +432,7 @@
void GenericBinaryOperation(
Token::Value op,
SmiAnalysis* type,
- const OverwriteMode overwrite_mode = NO_OVERWRITE);
+ OverwriteMode overwrite_mode);
// If possible, combine two constant smi values using op to produce
// a smi result, and push it on the virtual frame, all at compile time.
diff --git a/src/codegen.cc b/src/codegen.cc
index edc498d..ed7ee2f 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -304,8 +304,10 @@
node->is_expression(), false, script_,
node->inferred_name());
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Notify debugger that a new function has been added.
Debugger::OnNewFunction(function);
+#endif
// Set the expected number of properties for instances and return
// the resulting function.
diff --git a/src/codegen.h b/src/codegen.h
index dd43cc0..54fe330 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -71,6 +71,11 @@
// CodeForStatementPosition
// CodeForSourcePosition
+
+// Mode to overwrite BinaryExpression values.
+enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+
+
#ifdef ARM
#include "codegen-arm.h"
#else
diff --git a/src/compiler.cc b/src/compiler.cc
index 63fed4a..62e838e 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -92,8 +92,10 @@
StackGuard guard;
PostponeInterruptsScope postpone;
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Notify debugger
Debugger::OnBeforeCompile(script);
+#endif
// Only allow non-global compiles for eval.
ASSERT(is_eval || is_global);
@@ -160,8 +162,10 @@
// the instances of the function.
SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Notify debugger
Debugger::OnAfterCompile(script, fun);
+#endif
return fun;
}
diff --git a/src/constants-arm.h b/src/constants-arm.h
index f553963..919a892 100644
--- a/src/constants-arm.h
+++ b/src/constants-arm.h
@@ -106,7 +106,12 @@
call_rt_r5 = 0x10,
call_rt_r2 = 0x11,
// break point
- break_point = 0x20
+ break_point = 0x20,
+ // FP operations. These simulate calling into C for a moment to do fp ops.
+ // They should trash all caller-save registers.
+ simulator_fp_add = 0x21,
+ simulator_fp_sub = 0x22,
+ simulator_fp_mul = 0x23
};
diff --git a/src/d8.cc b/src/d8.cc
index 9648168..70143c3 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -163,6 +163,22 @@
}
+Handle<Value> Shell::Read(const Arguments& args) {
+ if (args.Length() != 1) {
+ return ThrowException(String::New("Bad parameters"));
+ }
+ String::Utf8Value file(args[0]);
+ if (*file == NULL) {
+ return ThrowException(String::New("Error loading file"));
+ }
+ Handle<String> source = ReadFile(*file);
+ if (source.IsEmpty()) {
+ return ThrowException(String::New("Error loading file"));
+ }
+ return source;
+}
+
+
Handle<Value> Shell::Load(const Arguments& args) {
for (int i = 0; i < args.Length(); i++) {
HandleScope handle_scope;
@@ -246,6 +262,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
Context::Scope context_scope(utility_context_);
Handle<Object> global = utility_context_->Global();
@@ -266,6 +283,7 @@
Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
return val;
}
+#endif
int32_t* Counter::Bind(const char* name, bool is_histogram) {
@@ -381,6 +399,7 @@
HandleScope scope;
Handle<ObjectTemplate> global_template = ObjectTemplate::New();
global_template->Set(String::New("print"), FunctionTemplate::New(Print));
+ global_template->Set(String::New("read"), FunctionTemplate::New(Read));
global_template->Set(String::New("load"), FunctionTemplate::New(Load));
global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
global_template->Set(String::New("version"), FunctionTemplate::New(Version));
@@ -406,11 +425,13 @@
global_template->Set(String::New("arguments"),
Utils::ToLocal(arguments_jsarray));
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Install the debugger object in the utility scope
i::Debug::Load();
i::JSObject* debug = i::Debug::debug_context()->global();
utility_context_->Global()->Set(String::New("$debug"),
Utils::ToLocal(&debug));
+#endif
// Run the d8 shell utility script in the utility context
int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
@@ -436,8 +457,10 @@
evaluation_context_ = Context::New(NULL, global_template);
evaluation_context_->SetSecurityToken(Undefined());
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Set the security token of the debug context to allow access.
i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
+#endif
}
@@ -555,6 +578,8 @@
Handle<ObjectTemplate> global_template = ObjectTemplate::New();
global_template->Set(String::New("print"),
FunctionTemplate::New(Shell::Print));
+ global_template->Set(String::New("read"),
+ FunctionTemplate::New(Shell::Read));
global_template->Set(String::New("load"),
FunctionTemplate::New(Shell::Load));
global_template->Set(String::New("yield"),
@@ -690,6 +715,7 @@
Locker::StartPreemption(preemption_interval);
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Run the remote debugger if requested.
if (i::FLAG_remote_debugger) {
RunRemoteDebugger(i::FLAG_debugger_port);
@@ -705,6 +731,7 @@
if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
v8::Debug::SetDebugEventListener(HandleDebugEvent);
}
+#endif
}
if (run_shell)
RunShell();
diff --git a/src/d8.h b/src/d8.h
index 342a0d2..092e3a3 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -132,13 +132,16 @@
static int Main(int argc, char* argv[]);
static Handle<Array> GetCompletions(Handle<String> text,
Handle<String> full);
+#ifdef ENABLE_DEBUGGER_SUPPORT
static Handle<Object> DebugMessageDetails(Handle<String> message);
static Handle<Value> DebugCommandToJSONRequest(Handle<String> command);
+#endif
static Handle<Value> Print(const Arguments& args);
static Handle<Value> Yield(const Arguments& args);
static Handle<Value> Quit(const Arguments& args);
static Handle<Value> Version(const Arguments& args);
+ static Handle<Value> Read(const Arguments& args);
static Handle<Value> Load(const Arguments& args);
// The OS object on the global object contains methods for performing
// operating system calls:
diff --git a/src/d8.js b/src/d8.js
index e2766d0..ea2fb44 100644
--- a/src/d8.js
+++ b/src/d8.js
@@ -653,17 +653,47 @@
// Process arguments if any.
if (args && args.length > 0) {
var target = args;
+ var type = 'function';
+ var line;
+ var column;
var condition;
+ var pos;
- var pos = args.indexOf(' ');
+ // Check for breakpoint condition.
+ pos = args.indexOf(' ');
if (pos > 0) {
target = args.substring(0, pos);
condition = args.substring(pos + 1, args.length);
}
+ // Check for script breakpoint (name:line[:column]). If no ':' in break
+ // specification it is considered a function break point.
+ pos = target.indexOf(':');
+ if (pos > 0) {
+ type = 'script';
+ var tmp = target.substring(pos + 1, target.length);
+ target = target.substring(0, pos);
+
+ // Check for both line and column.
+ pos = tmp.indexOf(':');
+ if (pos > 0) {
+ column = parseInt(tmp.substring(pos + 1, tmp.length)) - 1;
+ line = parseInt(tmp.substring(0, pos)) - 1;
+ } else {
+ line = parseInt(tmp) - 1;
+ }
+ } else if (target[0] == '#' && target[target.length - 1] == '#') {
+ type = 'handle';
+ target = target.substring(1, target.length - 1);
+ } else {
+ type = 'function';
+ }
+
request.arguments = {};
- request.arguments.type = 'function';
+ request.arguments.type = type;
request.arguments.target = target;
+ request.arguments.line = line;
+ request.arguments.column = column;
request.arguments.condition = condition;
} else {
throw new Error('Invalid break arguments.');
@@ -721,6 +751,9 @@
}
print('break location [condition]');
+ print(' break on named function: location is a function name');
+ print(' break on function: location is #<id>#');
+ print(' break on script position: location is name:line[:column]');
print('clear <breakpoint #>');
print('backtrace [from frame #] [to frame #]]');
print('frame <frame #>');
diff --git a/src/debug-agent.cc b/src/debug-agent.cc
index e865e0e..9838746 100644
--- a/src/debug-agent.cc
+++ b/src/debug-agent.cc
@@ -29,16 +29,18 @@
#include "v8.h"
#include "debug-agent.h"
+#ifdef ENABLE_DEBUGGER_SUPPORT
namespace v8 { namespace internal {
-
// Public V8 debugger API message handler function. This function just delegates
// to the debugger agent through it's data parameter.
void DebuggerAgentMessageHandler(const uint16_t* message, int length,
- void *data) {
- reinterpret_cast<DebuggerAgent*>(data)->DebuggerMessage(message, length);
+ v8::Debug::ClientData* client_data) {
+ DebuggerAgent::instance_->DebuggerMessage(message, length);
}
+// static
+DebuggerAgent* DebuggerAgent::instance_ = NULL;
// Debugger agent main thread.
void DebuggerAgent::Run() {
@@ -410,5 +412,6 @@
return total_received;
}
-
} } // namespace v8::internal
+
+#endif // ENABLE_DEBUGGER_SUPPORT
diff --git a/src/debug-agent.h b/src/debug-agent.h
index 177af0c..08f1372 100644
--- a/src/debug-agent.h
+++ b/src/debug-agent.h
@@ -28,12 +28,12 @@
#ifndef V8_V8_DEBUG_AGENT_H_
#define V8_V8_DEBUG_AGENT_H_
+#ifdef ENABLE_DEBUGGER_SUPPORT
#include "../include/v8-debug.h"
#include "platform.h"
namespace v8 { namespace internal {
-
// Forward decelrations.
class DebuggerAgentSession;
@@ -46,8 +46,14 @@
: name_(StrDup(name)), port_(port),
server_(OS::CreateSocket()), terminate_(false),
session_access_(OS::CreateMutex()), session_(NULL),
- terminate_now_(OS::CreateSemaphore(0)) {}
- ~DebuggerAgent() { delete server_; }
+ terminate_now_(OS::CreateSemaphore(0)) {
+ ASSERT(instance_ == NULL);
+ instance_ = this;
+ }
+ ~DebuggerAgent() {
+ instance_ = NULL;
+ delete server_;
+ }
void Shutdown();
@@ -66,9 +72,11 @@
DebuggerAgentSession* session_; // Current active session if any.
Semaphore* terminate_now_; // Semaphore to signal termination.
+ static DebuggerAgent* instance_;
+
friend class DebuggerAgentSession;
friend void DebuggerAgentMessageHandler(const uint16_t* message, int length,
- void *data);
+ v8::Debug::ClientData* client_data);
DISALLOW_COPY_AND_ASSIGN(DebuggerAgent);
};
@@ -111,7 +119,8 @@
static int ReceiveAll(const Socket* conn, char* data, int len);
};
-
} } // namespace v8::internal
+#endif // ENABLE_DEBUGGER_SUPPORT
+
#endif // V8_V8_DEBUG_AGENT_H_
diff --git a/src/debug-arm.cc b/src/debug-arm.cc
index 9fb77b7..f86f981 100644
--- a/src/debug-arm.cc
+++ b/src/debug-arm.cc
@@ -32,7 +32,7 @@
namespace v8 { namespace internal {
-
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Currently debug break is not supported in frame exit code on ARM.
bool BreakLocationIterator::IsDebugBreakAtReturn() {
return false;
@@ -58,7 +58,7 @@
}
-#define __ masm->
+#define __ ACCESS_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
@@ -191,5 +191,6 @@
#undef __
+#endif // ENABLE_DEBUGGER_SUPPORT
} } // namespace v8::internal
diff --git a/src/debug-delay.js b/src/debug-delay.js
index 9944fb3..6cb5e7f 100644
--- a/src/debug-delay.js
+++ b/src/debug-delay.js
@@ -1021,6 +1021,9 @@
columnOffset: script.columnOffset(),
lineCount: script.lineCount(),
};
+ if (!IS_UNDEFINED(script.data())) {
+ o.data = script.data();
+ }
if (include_source) {
o.source = script.source();
}
@@ -1270,11 +1273,12 @@
var ignoreCount = request.arguments.ignoreCount;
// Check for legal arguments.
- if (!type || !target) {
+ if (!type || IS_UNDEFINED(target)) {
response.failed('Missing argument "type" or "target"');
return;
}
- if (type != 'function' && type != 'script' && type != 'scriptId') {
+ if (type != 'function' && type != 'handle' &&
+ type != 'script' && type != 'scriptId') {
response.failed('Illegal type "' + type + '"');
return;
}
@@ -1303,6 +1307,20 @@
// Set function break point.
break_point_number = Debug.setBreakPoint(f, line, column, condition);
+ } else if (type == 'handle') {
+ // Find the object pointed by the specified handle.
+ var handle = parseInt(target, 10);
+ var mirror = LookupMirror(handle);
+ if (!mirror) {
+ return response.failed('Object #' + handle + '# not found');
+ }
+ if (!mirror.isFunction()) {
+ return response.failed('Object #' + handle + '# is not a function');
+ }
+
+ // Set function break point.
+ break_point_number = Debug.setBreakPoint(mirror.value(),
+ line, column, condition);
} else if (type == 'script') {
// set script break point.
break_point_number =
@@ -1547,20 +1565,24 @@
}
// Pull out arguments.
- var handle = request.arguments.handle;
+ var handles = request.arguments.handles;
// Check for legal arguments.
- if (IS_UNDEFINED(handle)) {
- return response.failed('Argument "handle" missing');
+ if (IS_UNDEFINED(handles)) {
+ return response.failed('Argument "handles" missing');
}
- // Lookup handle.
- var mirror = LookupMirror(handle);
- if (mirror) {
- response.body = mirror;
- } else {
- return response.failed('Object #' + handle + '# not found');
+ // Lookup handles.
+ var mirrors = {};
+ for (var i = 0; i < handles.length; i++) {
+ var handle = handles[i];
+ var mirror = LookupMirror(handle);
+ if (!mirror) {
+ return response.failed('Object #' + handle + '# not found');
+ }
+ mirrors[handle] = mirror;
}
+ response.body = mirrors;
};
@@ -1675,6 +1697,9 @@
script.lineOffset = scripts[i].line_offset;
script.columnOffset = scripts[i].column_offset;
script.lineCount = scripts[i].lineCount();
+ if (scripts[i].data) {
+ script.data = scripts[i].data;
+ }
if (includeSource) {
script.source = scripts[i].source;
} else {
diff --git a/src/debug-ia32.cc b/src/debug-ia32.cc
index 6d59889..9503cfc 100644
--- a/src/debug-ia32.cc
+++ b/src/debug-ia32.cc
@@ -33,6 +33,7 @@
namespace v8 { namespace internal {
+#ifdef ENABLE_DEBUGGER_SUPPORT
// A debug break in the frame exit code is identified by a call instruction.
bool BreakLocationIterator::IsDebugBreakAtReturn() {
@@ -67,7 +68,7 @@
}
-#define __ masm->
+#define __ ACCESS_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
@@ -214,5 +215,6 @@
#undef __
+#endif // ENABLE_DEBUGGER_SUPPORT
} } // namespace v8::internal
diff --git a/src/debug.cc b/src/debug.cc
index a4bb04d..32a96a8 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -35,12 +35,15 @@
#include "debug.h"
#include "execution.h"
#include "global-handles.h"
+#include "ic.h"
+#include "ic-inl.h"
#include "natives.h"
#include "stub-cache.h"
#include "log.h"
namespace v8 { namespace internal {
+#ifdef ENABLE_DEBUGGER_SUPPORT
static void PrintLn(v8::Local<v8::Value> value) {
v8::Local<v8::String> s = value->ToString();
char* data = NewArray<char>(s->Length() + 1);
@@ -288,14 +291,8 @@
// Patch the frame exit code with a break point.
SetDebugBreakAtReturn();
} else {
- // Patch the original code with the current address as the current address
- // might have changed by the inline caching since the code was copied.
- original_rinfo()->set_target_address(rinfo()->target_address());
-
- // Patch the code to invoke the builtin debug break function matching the
- // calling convention used by the call site.
- Handle<Code> dbgbrk_code(Debug::FindDebugBreak(rinfo()));
- rinfo()->set_target_address(dbgbrk_code->entry());
+ // Patch the IC call.
+ SetDebugBreakAtIC();
}
ASSERT(IsDebugBreak());
}
@@ -306,8 +303,8 @@
// Restore the frame exit code.
ClearDebugBreakAtReturn();
} else {
- // Patch the code to the original invoke.
- rinfo()->set_target_address(original_rinfo()->target_address());
+ // Patch the IC call.
+ ClearDebugBreakAtIC();
}
ASSERT(!IsDebugBreak());
}
@@ -360,6 +357,39 @@
}
+void BreakLocationIterator::SetDebugBreakAtIC() {
+ // Patch the original code with the current address as the current address
+ // might have changed by the inline caching since the code was copied.
+ original_rinfo()->set_target_address(rinfo()->target_address());
+
+ RelocInfo::Mode mode = rmode();
+ if (RelocInfo::IsCodeTarget(mode)) {
+ Address target = rinfo()->target_address();
+ Handle<Code> code(Code::GetCodeFromTargetAddress(target));
+
+ // Patch the code to invoke the builtin debug break function matching the
+ // calling convention used by the call site.
+ Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode));
+ rinfo()->set_target_address(dbgbrk_code->entry());
+
+ // For stubs that refer back to an inlined version clear the cached map for
+ // the inlined case to always go through the IC. As long as the break point
+ // is set the patching performed by the runtime system will take place in
+ // the code copy and will therefore have no effect on the running code
+ // keeping it from using the inlined code.
+ if (code->is_keyed_load_stub() && KeyedLoadIC::HasInlinedVersion(pc())) {
+ KeyedLoadIC::ClearInlinedVersion(pc());
+ }
+ }
+}
+
+
+void BreakLocationIterator::ClearDebugBreakAtIC() {
+ // Patch the code to the original invoke.
+ rinfo()->set_target_address(original_rinfo()->target_address());
+}
+
+
Object* BreakLocationIterator::BreakPointObjects() {
return debug_info_->GetBreakPointObjects(code_position());
}
@@ -1055,48 +1085,42 @@
// Find the builtin to use for invoking the debug break
-Handle<Code> Debug::FindDebugBreak(RelocInfo* rinfo) {
+Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
// Find the builtin debug break function matching the calling convention
// used by the call site.
- RelocInfo::Mode mode = rinfo->rmode();
-
- if (RelocInfo::IsCodeTarget(mode)) {
- Address target = rinfo->target_address();
- Code* code = Code::GetCodeFromTargetAddress(target);
- if (code->is_inline_cache_stub()) {
- if (code->is_call_stub()) {
- return ComputeCallDebugBreak(code->arguments_count());
- }
- if (code->is_load_stub()) {
- return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
- }
- if (code->is_store_stub()) {
- return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
- }
- if (code->is_keyed_load_stub()) {
- Handle<Code> result =
- Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
- return result;
- }
- if (code->is_keyed_store_stub()) {
- Handle<Code> result =
- Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
- return result;
- }
+ if (code->is_inline_cache_stub()) {
+ if (code->is_call_stub()) {
+ return ComputeCallDebugBreak(code->arguments_count());
}
- if (RelocInfo::IsConstructCall(mode)) {
+ if (code->is_load_stub()) {
+ return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
+ }
+ if (code->is_store_stub()) {
+ return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
+ }
+ if (code->is_keyed_load_stub()) {
Handle<Code> result =
- Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
+ Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
return result;
}
- if (code->kind() == Code::STUB) {
- ASSERT(code->major_key() == CodeStub::CallFunction ||
- code->major_key() == CodeStub::StackCheck);
+ if (code->is_keyed_store_stub()) {
Handle<Code> result =
- Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
+ Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
return result;
}
}
+ if (RelocInfo::IsConstructCall(mode)) {
+ Handle<Code> result =
+ Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
+ return result;
+ }
+ if (code->kind() == Code::STUB) {
+ ASSERT(code->major_key() == CodeStub::CallFunction ||
+ code->major_key() == CodeStub::StackCheck);
+ Handle<Code> result =
+ Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
+ return result;
+ }
UNREACHABLE();
return Handle<Code>::null();
@@ -1397,11 +1421,10 @@
bool Debugger::is_loading_debugger_ = false;
bool Debugger::never_unload_debugger_ = false;
DebugMessageThread* Debugger::message_thread_ = NULL;
-v8::DebugMessageHandler Debugger::message_handler_ = NULL;
+v8::Debug::MessageHandler Debugger::message_handler_ = NULL;
bool Debugger::message_handler_cleared_ = false;
-void* Debugger::message_handler_data_ = NULL;
-v8::DebugHostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
-void* Debugger::host_dispatch_handler_data_ = NULL;
+v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
+int Debugger::host_dispatch_micros_ = 100 * 1000;
DebuggerAgent* Debugger::agent_ = NULL;
LockingMessageQueue Debugger::command_queue_(kQueueInitialSize);
LockingMessageQueue Debugger::message_queue_(kQueueInitialSize);
@@ -1703,8 +1726,8 @@
if (event_listener_->IsProxy()) {
// C debug event listener.
Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_));
- v8::DebugEventCallback callback =
- FUNCTION_CAST<v8::DebugEventCallback>(callback_obj->proxy());
+ v8::Debug::EventCallback callback =
+ FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy());
callback(event,
v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)),
@@ -1805,32 +1828,31 @@
// Process requests from the debugger.
while (true) {
// Wait for new command in the queue.
- command_received_->Wait();
+ if (Debugger::host_dispatch_handler_) {
+ // In case there is a host dispatch - do periodic dispatches.
+ if (!command_received_->Wait(host_dispatch_micros_)) {
+ // Timout expired, do the dispatch.
+ Debugger::host_dispatch_handler_();
+ continue;
+ }
+ } else {
+ // In case there is no host dispatch - just wait.
+ command_received_->Wait();
+ }
// The debug command interrupt flag might have been set when the command was
// added.
StackGuard::Continue(DEBUGCOMMAND);
// Get the command from the queue.
- Vector<uint16_t> command = command_queue_.Get();
+ Message command = command_queue_.Get();
Logger::DebugTag("Got request from command queue, in interactive loop.");
if (!Debugger::IsDebuggerActive()) {
+ // Delete command text and user data.
+ command.Dispose();
return;
}
- // Check if the command is a host dispatch.
- if (command[0] == 0) {
- if (Debugger::host_dispatch_handler_) {
- int32_t dispatch = (command[1] << 16) | command[2];
- Debugger::host_dispatch_handler_(reinterpret_cast<void*>(dispatch),
- Debugger::host_dispatch_handler_data_);
- }
- if (auto_continue && !HasCommands()) {
- return;
- }
- continue;
- }
-
// Invoke JavaScript to process the debug request.
v8::Local<v8::String> fun_name;
v8::Local<v8::Function> fun;
@@ -1838,8 +1860,10 @@
v8::TryCatch try_catch;
fun_name = v8::String::New("processDebugRequest");
fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
- request = v8::String::New(reinterpret_cast<uint16_t*>(command.start()),
- command.length());
+
+ request = v8::String::New(command.text().start(),
+ command.text().length());
+ command.text().Dispose();
static const int kArgc = 1;
v8::Handle<Value> argv[kArgc] = { request };
v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
@@ -1875,13 +1899,8 @@
response = try_catch.Exception()->ToString();
}
- // Convert text result to C string.
- v8::String::Value val(response);
- Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
- response->Length());
-
// Return the result.
- SendMessage(str);
+ SendMessage(Message::NewOutput(response, command.client_data()));
// Return from debug event processing if either the VM is put into the
// runnning state (through a continue command) or auto continue is active
@@ -1927,12 +1946,11 @@
}
-void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void* data,
+void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler,
bool message_handler_thread) {
ScopedLock with(debugger_access_);
message_handler_ = handler;
- message_handler_data_ = data;
if (handler != NULL) {
if (!message_thread_ && message_handler_thread) {
message_thread_ = new DebugMessageThread();
@@ -1951,10 +1969,10 @@
}
-void Debugger::SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
- void* data) {
+void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
+ int period) {
host_dispatch_handler_ = handler;
- host_dispatch_handler_data_ = data;
+ host_dispatch_micros_ = period * 1000;
}
@@ -1962,26 +1980,28 @@
// public API. Messages are kept internally as Vector<uint16_t> strings, which
// are allocated in various places and deallocated by the calling function
// sometime after this call.
-void Debugger::InvokeMessageHandler(Vector<uint16_t> message) {
+void Debugger::InvokeMessageHandler(Message message) {
ScopedLock with(debugger_access_);
if (message_handler_ != NULL) {
- message_handler_(message.start(), message.length(), message_handler_data_);
+ message_handler_(message.text().start(),
+ message.text().length(),
+ message.client_data());
}
+ message.Dispose();
}
-void Debugger::SendMessage(Vector<uint16_t> message) {
+void Debugger::SendMessage(Message message) {
if (message_thread_ == NULL) {
// If there is no message thread just invoke the message handler from the
// V8 thread.
InvokeMessageHandler(message);
} else {
- // Put a copy of the message coming from V8 on the queue. The new copy of
- // the event string is destroyed by the message thread.
- Vector<uint16_t> message_copy = message.Clone();
+ // Put the message coming from V8 on the queue. The text and user data will
+ // be destroyed by the message thread.
Logger::DebugTag("Put message on event message_queue.");
- message_queue_.Put(message_copy);
+ message_queue_.Put(message);
message_received_->Signal();
}
}
@@ -2004,12 +2024,11 @@
if (FLAG_trace_debug_json) {
PrintLn(json_event_string);
}
- v8::String::Value val(json_event_string);
- Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
- json_event_string->Length());
- SendMessage(str);
+ SendMessage(Message::NewOutput(
+ json_event_string,
+ NULL /* no user data since there was no request */));
} else {
- SendMessage(Vector<uint16_t>::empty());
+ SendMessage(Message::NewEmptyMessage());
}
} else {
PrintLn(try_catch.Exception());
@@ -2025,13 +2044,15 @@
// by the API client thread. This is where the API client hands off
// processing of the command to the DebugMessageThread thread.
// The new copy of the command is destroyed in HandleCommand().
-void Debugger::ProcessCommand(Vector<const uint16_t> command) {
- // Make a copy of the command. Need to cast away const for Clone to work.
- Vector<uint16_t> command_copy =
+void Debugger::ProcessCommand(Vector<const uint16_t> command,
+ v8::Debug::ClientData* client_data) {
+ // Need to cast away const.
+ Message message = Message::NewCommand(
Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
- command.length()).Clone();
+ command.length()),
+ client_data);
Logger::DebugTag("Put command on command_queue.");
- command_queue_.Put(command_copy);
+ command_queue_.Put(message);
command_received_->Signal();
// Set the debug command break flag to have the command processed.
@@ -2046,23 +2067,6 @@
}
-void Debugger::ProcessHostDispatch(void* dispatch) {
- // Puts a host dispatch comming from the public API on the queue.
- uint16_t hack[3];
- hack[0] = 0;
- hack[1] = reinterpret_cast<uint32_t>(dispatch) >> 16;
- hack[2] = reinterpret_cast<uint32_t>(dispatch) & 0xFFFF;
- Logger::DebugTag("Put dispatch on command_queue.");
- command_queue_.Put(Vector<uint16_t>(hack, 3).Clone());
- command_received_->Signal();
-
- // Set the debug command break flag to have the host dispatch processed.
- if (!Debug::InDebugger()) {
- StackGuard::DebugCommand();
- }
-}
-
-
bool Debugger::IsDebuggerActive() {
ScopedLock with(debugger_access_);
@@ -2133,9 +2137,11 @@
// Wait and Get are paired so that semaphore count equals queue length.
Debugger::message_received_->Wait();
Logger::DebugTag("Get message from event message_queue.");
- Vector<uint16_t> message = Debugger::message_queue_.Get();
- if (message.length() > 0) {
+ Message message = Debugger::message_queue_.Get();
+ if (message.text().length() > 0) {
Debugger::InvokeMessageHandler(message);
+ } else {
+ message.Dispose();
}
}
}
@@ -2143,22 +2149,72 @@
void DebugMessageThread::Stop() {
keep_running_ = false;
- Debugger::SendMessage(Vector<uint16_t>(NULL, 0));
+ Debugger::SendMessage(Message::NewEmptyMessage());
Join();
}
+Message::Message() : text_(Vector<uint16_t>::empty()),
+ client_data_(NULL) {
+}
+
+
+Message::Message(const Vector<uint16_t>& text,
+ v8::Debug::ClientData* data)
+ : text_(text),
+ client_data_(data) {
+}
+
+
+Message::~Message() {
+}
+
+
+void Message::Dispose() {
+ text_.Dispose();
+ delete client_data_;
+ client_data_ = NULL;
+}
+
+
+Message Message::NewCommand(const Vector<uint16_t>& command,
+ v8::Debug::ClientData* data) {
+ return Message(command.Clone(), data);
+}
+
+
+Message Message::NewOutput(v8::Handle<v8::String> output,
+ v8::Debug::ClientData* data) {
+ Vector<uint16_t> text;
+ if (!output.IsEmpty()) {
+ // Do not include trailing '\0'.
+ text = Vector<uint16_t>::New(output->Length());
+ output->Write(text.start(), 0, output->Length());
+ }
+ return Message(text, data);
+}
+
+
+Message Message::NewEmptyMessage() {
+ return Message();
+}
+
+
MessageQueue::MessageQueue(int size) : start_(0), end_(0), size_(size) {
- messages_ = NewArray<Vector<uint16_t> >(size);
+ messages_ = NewArray<Message>(size);
}
MessageQueue::~MessageQueue() {
+ while (!IsEmpty()) {
+ Message m = Get();
+ m.Dispose();
+ }
DeleteArray(messages_);
}
-Vector<uint16_t> MessageQueue::Get() {
+Message MessageQueue::Get() {
ASSERT(!IsEmpty());
int result = start_;
start_ = (start_ + 1) % size_;
@@ -2166,7 +2222,7 @@
}
-void MessageQueue::Put(const Vector<uint16_t>& message) {
+void MessageQueue::Put(const Message& message) {
if ((end_ + 1) % size_ == start_) {
Expand();
}
@@ -2180,9 +2236,11 @@
while (!IsEmpty()) {
new_queue.Put(Get());
}
- Vector<uint16_t>* array_to_free = messages_;
+ Message* array_to_free = messages_;
*this = new_queue;
new_queue.messages_ = array_to_free;
+ // Make the new_queue empty so that it doesn't call Dispose on any messages.
+ new_queue.start_ = new_queue.end_;
// Automatic destructor called on new_queue, freeing array_to_free.
}
@@ -2203,18 +2261,18 @@
}
-Vector<uint16_t> LockingMessageQueue::Get() {
+Message LockingMessageQueue::Get() {
ScopedLock sl(lock_);
- Vector<uint16_t> result = queue_.Get();
- Logger::DebugEvent("Get", result);
+ Message result = queue_.Get();
+ Logger::DebugEvent("Get", result.text());
return result;
}
-void LockingMessageQueue::Put(const Vector<uint16_t>& message) {
+void LockingMessageQueue::Put(const Message& message) {
ScopedLock sl(lock_);
queue_.Put(message);
- Logger::DebugEvent("Put", message);
+ Logger::DebugEvent("Put", message.text());
}
@@ -2223,5 +2281,6 @@
queue_.Clear();
}
+#endif // ENABLE_DEBUGGER_SUPPORT
} } // namespace v8::internal
diff --git a/src/debug.h b/src/debug.h
index 8822c50..ffd3da9 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -28,7 +28,6 @@
#ifndef V8_V8_DEBUG_H_
#define V8_V8_DEBUG_H_
-#include "../include/v8-debug.h"
#include "assembler.h"
#include "code-stubs.h"
#include "debug-agent.h"
@@ -38,6 +37,8 @@
#include "string-stream.h"
#include "v8threads.h"
+#ifdef ENABLE_DEBUGGER_SUPPORT
+#include "../include/v8-debug.h"
namespace v8 { namespace internal {
@@ -131,6 +132,10 @@
private:
void SetDebugBreak();
void ClearDebugBreak();
+
+ void SetDebugBreakAtIC();
+ void ClearDebugBreakAtIC();
+
bool IsDebugBreakAtReturn();
void SetDebugBreakAtReturn();
void ClearDebugBreakAtReturn();
@@ -204,7 +209,7 @@
static bool IsBreakStub(Code* code);
// Find the builtin to use for invoking the debug break
- static Handle<Code> FindDebugBreak(RelocInfo* rinfo);
+ static Handle<Code> FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode);
static Handle<Object> GetSourceBreakLocations(
Handle<SharedFunctionInfo> shared);
@@ -396,6 +401,32 @@
};
+// Message send by user to v8 debugger or debugger output message.
+// In addition to command text it may contain a pointer to some user data
+// which are expected to be passed along with the command reponse to message
+// handler.
+class Message {
+ public:
+ static Message NewCommand(const Vector<uint16_t>& command,
+ v8::Debug::ClientData* data);
+ static Message NewOutput(v8::Handle<v8::String> output,
+ v8::Debug::ClientData* data);
+ static Message NewEmptyMessage();
+ Message();
+ ~Message();
+
+ // Deletes user data and disposes of the text.
+ void Dispose();
+ Vector<uint16_t> text() const { return text_; }
+ v8::Debug::ClientData* client_data() const { return client_data_; }
+ private:
+ Message(const Vector<uint16_t>& text,
+ v8::Debug::ClientData* data);
+
+ Vector<uint16_t> text_;
+ v8::Debug::ClientData* client_data_;
+};
+
// A Queue of Vector<uint16_t> objects. A thread-safe version is
// LockingMessageQueue, based on this class.
class MessageQueue BASE_EMBEDDED {
@@ -403,14 +434,14 @@
explicit MessageQueue(int size);
~MessageQueue();
bool IsEmpty() const { return start_ == end_; }
- Vector<uint16_t> Get();
- void Put(const Vector<uint16_t>& message);
+ Message Get();
+ void Put(const Message& message);
void Clear() { start_ = end_ = 0; } // Queue is empty after Clear().
private:
// Doubles the size of the message queue, and copies the messages.
void Expand();
- Vector<uint16_t>* messages_;
+ Message* messages_;
int start_;
int end_;
int size_; // The size of the queue buffer. Queue can hold size-1 messages.
@@ -426,8 +457,8 @@
explicit LockingMessageQueue(int size);
~LockingMessageQueue();
bool IsEmpty() const;
- Vector<uint16_t> Get();
- void Put(const Vector<uint16_t>& message);
+ Message Get();
+ void Put(const Message& message);
void Clear();
private:
MessageQueue queue_;
@@ -472,29 +503,29 @@
Handle<Object> event_data,
bool auto_continue);
static void SetEventListener(Handle<Object> callback, Handle<Object> data);
- static void SetMessageHandler(v8::DebugMessageHandler handler, void* data,
+ static void SetMessageHandler(v8::Debug::MessageHandler handler,
bool message_handler_thread);
static void TearDown();
- static void SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
- void* data);
+ static void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
+ int period);
// Invoke the message handler function.
- static void InvokeMessageHandler(Vector< uint16_t> message);
+ static void InvokeMessageHandler(Message message);
// Send a message to the message handler eiher through the message thread or
// directly.
- static void SendMessage(Vector<uint16_t> message);
+ static void SendMessage(Message message);
// Send the JSON message for a debug event.
static bool SendEventMessage(Handle<Object> event_data);
// Add a debugger command to the command queue.
- static void ProcessCommand(Vector<const uint16_t> command);
+ static void ProcessCommand(Vector<const uint16_t> command,
+ v8::Debug::ClientData* client_data = NULL);
// Check whether there are commands in the command queue.
static bool HasCommands();
- static void ProcessHostDispatch(void* dispatch);
static Handle<Object> Call(Handle<JSFunction> fun,
Handle<Object> data,
bool* pending_exception);
@@ -538,11 +569,10 @@
static bool is_loading_debugger_; // Are we loading the debugger?
static bool never_unload_debugger_; // Can we unload the debugger?
static DebugMessageThread* message_thread_;
- static v8::DebugMessageHandler message_handler_;
+ static v8::Debug::MessageHandler message_handler_;
static bool message_handler_cleared_; // Was message handler cleared?
- static void* message_handler_data_;
- static v8::DebugHostDispatchHandler host_dispatch_handler_;
- static void* host_dispatch_handler_data_;
+ static v8::Debug::HostDispatchHandler host_dispatch_handler_;
+ static int host_dispatch_micros_;
static DebuggerAgent* agent_;
@@ -719,4 +749,6 @@
} } // namespace v8::internal
+#endif // ENABLE_DEBUGGER_SUPPORT
+
#endif // V8_V8_DEBUG_H_
diff --git a/src/disasm-arm.cc b/src/disasm-arm.cc
index d19e042..3b7474d 100644
--- a/src/disasm-arm.cc
+++ b/src/disasm-arm.cc
@@ -261,6 +261,15 @@
case break_point:
Print("break_point");
return;
+ case simulator_fp_add:
+ Print("simulator_fp_add");
+ return;
+ case simulator_fp_mul:
+ Print("simulator_fp_mul");
+ return;
+ case simulator_fp_sub:
+ Print("simulator_fp_sub");
+ return;
default:
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"%d",
diff --git a/src/execution.cc b/src/execution.cc
index 03017d0..1d4d9ef 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -305,6 +305,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
bool StackGuard::IsDebugBreak() {
ExecutionAccess access;
return thread_local_.interrupt_flags_ & DEBUGBREAK;
@@ -331,7 +332,7 @@
set_limits(kInterruptLimit, access);
}
}
-
+#endif
void StackGuard::Continue(InterruptFlag after_what) {
ExecutionAccess access;
@@ -539,6 +540,7 @@
ContextSwitcher::PreemptionReceived();
+#ifdef ENABLE_DEBUGGER_SUPPORT
if (Debug::InDebugger()) {
// If currently in the debugger don't do any actual preemption but record
// that preemption occoured while in the debugger.
@@ -548,11 +550,17 @@
v8::Unlocker unlocker;
Thread::YieldCPU();
}
+#else
+ // Perform preemption.
+ v8::Unlocker unlocker;
+ Thread::YieldCPU();
+#endif
return Heap::undefined_value();
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
Object* Execution::DebugBreakHelper() {
// Just continue if breaks are disabled.
if (Debug::disable_break()) {
@@ -598,12 +606,14 @@
// Return to continue execution.
return Heap::undefined_value();
}
-
+#endif
Object* Execution::HandleStackGuardInterrupt() {
+#ifdef ENABLE_DEBUGGER_SUPPORT
if (StackGuard::IsDebugBreak() || StackGuard::IsDebugCommand()) {
DebugBreakHelper();
}
+#endif
if (StackGuard::IsPreempted()) RuntimePreempt();
if (StackGuard::IsInterrupted()) {
// interrupt
@@ -626,7 +636,7 @@
v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) {
// All allocation spaces other than NEW_SPACE have the same effect.
- Heap::CollectGarbage(0, OLD_DATA_SPACE);
+ Heap::CollectAllGarbage();
return v8::Undefined();
}
diff --git a/src/execution.h b/src/execution.h
index 6531572..6f2f689 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -118,8 +118,9 @@
Handle<JSFunction> fun,
Handle<Object> pos,
Handle<Object> is_global);
-
+#ifdef ENABLE_DEBUGGER_SUPPORT
static Object* DebugBreakHelper();
+#endif
// If the stack guard is triggered, but it is not an actual
// stack overflow, then handle the interruption accordingly.
@@ -158,11 +159,13 @@
static void Preempt();
static bool IsInterrupted();
static void Interrupt();
- static bool IsDebugBreak();
- static void DebugBreak();
- static bool IsDebugCommand();
- static void DebugCommand();
static void Continue(InterruptFlag after_what);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ static void DebugBreak();
+ static void DebugCommand();
+ static bool IsDebugBreak();
+ static bool IsDebugCommand();
+#endif
private:
// You should hold the ExecutionAccess lock when calling this method.
diff --git a/src/factory.cc b/src/factory.cc
index e29c84d..c849ab7 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -173,6 +173,7 @@
script->set_id(Heap::last_script_id());
script->set_line_offset(Smi::FromInt(0));
script->set_column_offset(Smi::FromInt(0));
+ script->set_data(Heap::undefined_value());
script->set_type(Smi::FromInt(SCRIPT_TYPE_NORMAL));
script->set_wrapper(*Factory::NewProxy(0, TENURED));
script->set_line_ends(Heap::undefined_value());
@@ -671,6 +672,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
Handle<DebugInfo> Factory::NewDebugInfo(Handle<SharedFunctionInfo> shared) {
// Get the original code of the function.
Handle<Code> code(shared->code());
@@ -700,6 +702,7 @@
return debug_info;
}
+#endif
Handle<JSObject> Factory::NewArgumentsObject(Handle<Object> callee,
diff --git a/src/factory.h b/src/factory.h
index 2564c3c..54f2089 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -310,8 +310,9 @@
uint32_t key,
Handle<Object> value);
+#ifdef ENABLE_DEBUGGER_SUPPORT
static Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
-
+#endif
// Return a map using the map cache in the global context.
// The key the an ordered set of property names.
diff --git a/src/frames.cc b/src/frames.cc
index 88c723d..1eedbf6 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -647,10 +647,10 @@
handler->Iterate(v);
// Make sure that there's the entry frame does not contain more than
// one stack handler.
- if (kDebug) {
- it.Advance();
- ASSERT(it.done());
- }
+#ifdef DEBUG
+ it.Advance();
+ ASSERT(it.done());
+#endif
}
diff --git a/src/func-name-inferrer.cc b/src/func-name-inferrer.cc
index ef0c7db..75f7a99 100644
--- a/src/func-name-inferrer.cc
+++ b/src/func-name-inferrer.cc
@@ -63,11 +63,12 @@
}
-void FuncNameInferrer::MaybeInferFunctionName() {
- if (func_to_infer_ != NULL) {
- func_to_infer_->set_inferred_name(MakeNameFromStack());
- func_to_infer_ = NULL;
+void FuncNameInferrer::InferFunctionsNames() {
+ Handle<String> func_name = MakeNameFromStack();
+ for (int i = 0; i < funcs_to_infer_.length(); ++i) {
+ funcs_to_infer_[i]->set_inferred_name(func_name);
}
+ funcs_to_infer_.Rewind(0);
}
diff --git a/src/func-name-inferrer.h b/src/func-name-inferrer.h
index 9dcf7c5..d8270c3 100644
--- a/src/func-name-inferrer.h
+++ b/src/func-name-inferrer.h
@@ -45,7 +45,7 @@
FuncNameInferrer() :
entries_stack_(10),
names_stack_(5),
- func_to_infer_(NULL),
+ funcs_to_infer_(4),
dot_(Factory::NewStringFromAscii(CStrVector("."))) {
}
@@ -57,39 +57,34 @@
entries_stack_.Add(names_stack_.length());
}
- void Leave() {
- ASSERT(IsOpen());
- names_stack_.Rewind(entries_stack_.RemoveLast());
- }
-
void PushName(Handle<String> name) {
if (IsOpen()) {
names_stack_.Add(name);
}
}
- void SetFuncToInfer(FunctionLiteral* func_to_infer) {
+ void AddFunction(FunctionLiteral* func_to_infer) {
if (IsOpen()) {
- // If we encounter another function literal after already having
- // encountered one, the second one replaces the first.
- func_to_infer_ = func_to_infer;
+ funcs_to_infer_.Add(func_to_infer);
}
}
void InferAndLeave() {
ASSERT(IsOpen());
- MaybeInferFunctionName();
- Leave();
+ if (!funcs_to_infer_.is_empty()) {
+ InferFunctionsNames();
+ }
+ names_stack_.Rewind(entries_stack_.RemoveLast());
}
private:
Handle<String> MakeNameFromStack();
Handle<String> MakeNameFromStackHelper(int pos, Handle<String> prev);
- void MaybeInferFunctionName();
+ void InferFunctionsNames();
List<int> entries_stack_;
List<Handle<String> > names_stack_;
- FunctionLiteral* func_to_infer_;
+ List<FunctionLiteral*> funcs_to_infer_;
Handle<String> dot_;
DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer);
diff --git a/src/globals.h b/src/globals.h
index 1579c3d..fbbe7c9 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -80,12 +80,6 @@
// -----------------------------------------------------------------------------
// Constants
-#ifdef DEBUG
-const bool kDebug = true;
-#else
-const bool kDebug = false;
-#endif // DEBUG
-
const int KB = 1024;
const int MB = KB * KB;
const int GB = KB * KB * KB;
@@ -146,7 +140,6 @@
class BreakableStatement;
class Code;
class CodeGenerator;
-class CodeRegion;
class CodeStub;
class Context;
class Debug;
diff --git a/src/handles.cc b/src/handles.cc
index 60d8236..99161ce 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -212,10 +212,20 @@
}
-Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object,
- Handle<String> key,
- Handle<Object> value,
- PropertyAttributes attributes) {
+Handle<Object> ForceSetProperty(Handle<JSObject> object,
+ Handle<Object> key,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ CALL_HEAP_FUNCTION(
+ Runtime::ForceSetObjectProperty(object, key, value, attributes), Object);
+}
+
+
+Handle<Object> IgnoreAttributesAndSetLocalProperty(
+ Handle<JSObject> object,
+ Handle<String> key,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
CALL_HEAP_FUNCTION(object->
IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object);
}
@@ -491,17 +501,6 @@
break;
}
- // Compute the property keys.
- content = UnionOfKeys(content, GetEnumPropertyKeys(current));
-
- // Add the property keys from the interceptor.
- if (current->HasNamedInterceptor()) {
- v8::Handle<v8::Array> result =
- GetKeysForNamedInterceptor(object, current);
- if (!result.IsEmpty())
- content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
- }
-
// Compute the element keys.
Handle<FixedArray> element_keys =
Factory::NewFixedArray(current->NumberOfEnumElements());
@@ -515,6 +514,17 @@
if (!result.IsEmpty())
content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
}
+
+ // Compute the property keys.
+ content = UnionOfKeys(content, GetEnumPropertyKeys(current));
+
+ // Add the property keys from the interceptor.
+ if (current->HasNamedInterceptor()) {
+ v8::Handle<v8::Array> result =
+ GetKeysForNamedInterceptor(object, current);
+ if (!result.IsEmpty())
+ content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
+ }
}
}
return content;
@@ -549,7 +559,7 @@
index++;
}
}
- (*storage)->SortPairs(*sort_array);
+ (*storage)->SortPairs(*sort_array, sort_array->length());
Handle<FixedArray> bridge_storage =
Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
DescriptorArray* desc = object->map()->instance_descriptors();
@@ -651,6 +661,7 @@
// We shouldn't get here if compiling the script failed.
ASSERT(!boilerplate.is_null());
+#ifdef ENABLE_DEBUGGER_SUPPORT
// When the debugger running in its own context touches lazy loaded
// functions loading can be triggered. In that case ensure that the
// execution of the boilerplate is in the correct context.
@@ -659,6 +670,7 @@
Top::context() == *Debug::debug_context()) {
Top::set_context(*compile_context);
}
+#endif
// Reset the lazy load data before running the script to make sure
// not to get recursive lazy loading.
diff --git a/src/handles.h b/src/handles.h
index c8e534e..9cc1db4 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -196,6 +196,11 @@
Handle<Object> value,
PropertyAttributes attributes);
+Handle<Object> ForceSetProperty(Handle<JSObject> object,
+ Handle<Object> key,
+ Handle<Object> value,
+ PropertyAttributes attributes);
+
Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object,
Handle<String> key,
Handle<Object> value,
diff --git a/src/heap.cc b/src/heap.cc
index 7a8b728..a57884c 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2679,7 +2679,10 @@
SYNCHRONIZE_TAG("bootstrapper");
Top::Iterate(v);
SYNCHRONIZE_TAG("top");
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
Debug::Iterate(v);
+#endif
SYNCHRONIZE_TAG("debug");
CompilationCache::Iterate(v);
SYNCHRONIZE_TAG("compilationcache");
diff --git a/src/ic-arm.cc b/src/ic-arm.cc
index 4db3980..ad6eb2c 100644
--- a/src/ic-arm.cc
+++ b/src/ic-arm.cc
@@ -39,7 +39,7 @@
// Static IC stub generators.
//
-#define __ masm->
+#define __ ACCESS_MASM(masm)
// Helper function used from LoadIC/CallIC GenerateNormal.
@@ -96,7 +96,9 @@
// Compute the masked index: (hash + i + i * i) & mask.
__ ldr(t1, FieldMemOperand(r2, String::kLengthOffset));
__ mov(t1, Operand(t1, LSR, String::kHashShift));
- if (i > 0) __ add(t1, t1, Operand(Dictionary::GetProbeOffset(i)));
+ if (i > 0) {
+ __ add(t1, t1, Operand(Dictionary::GetProbeOffset(i)));
+ }
__ and_(t1, t1, Operand(r3));
// Scale the index by multiplying by the element size.
@@ -505,6 +507,8 @@
// TODO(181): Implement map patching once loop nesting is tracked on
// the ARM platform so we can generate inlined fast-case code for
// array indexing in loops.
+bool KeyedLoadIC::HasInlinedVersion(Address address) { return false; }
+void KeyedLoadIC::ClearInlinedVersion(Address address) { }
void KeyedLoadIC::PatchInlinedMapCheck(Address address, Object* value) { }
diff --git a/src/ic-ia32.cc b/src/ic-ia32.cc
index 9060f2d..664303f 100644
--- a/src/ic-ia32.cc
+++ b/src/ic-ia32.cc
@@ -38,7 +38,7 @@
// Static IC stub generators.
//
-#define __ masm->
+#define __ ACCESS_MASM(masm)
// Helper function used to load a property from a dictionary backing storage.
@@ -91,7 +91,9 @@
// Compute the masked index: (hash + i + i * i) & mask.
__ mov(r1, FieldOperand(name, String::kLengthOffset));
__ shr(r1, String::kHashShift);
- if (i > 0) __ add(Operand(r1), Immediate(Dictionary::GetProbeOffset(i)));
+ if (i > 0) {
+ __ add(Operand(r1), Immediate(Dictionary::GetProbeOffset(i)));
+ }
__ and_(r1, Operand(r2));
// Scale the index by multiplying by the element size.
@@ -727,8 +729,24 @@
}
+// One byte opcode for test eax,0xXXXXXXXX.
+static const byte kTestEaxByte = 0xA9;
+
+
+bool KeyedLoadIC::HasInlinedVersion(Address address) {
+ Address test_instruction_address = address + 4; // 4 = stub address
+ return *test_instruction_address == kTestEaxByte;
+}
+
+
+void KeyedLoadIC::ClearInlinedVersion(Address address) {
+ // Insert null as the map to check for to make sure the map check fails
+ // sending control flow to the IC instead of the inlined version.
+ PatchInlinedMapCheck(address, Heap::null_value());
+}
+
+
void KeyedLoadIC::PatchInlinedMapCheck(Address address, Object* value) {
- static const byte kTestEaxByte = 0xA9;
Address test_instruction_address = address + 4; // 4 = stub address
// The keyed load has a fast inlined case if the IC call instruction
// is immediately followed by a test instruction.
@@ -742,7 +760,7 @@
// bytes of the 7-byte operand-immediate compare instruction, so
// we add 3 to the offset to get the map address.
Address map_address = test_instruction_address + offset_value + 3;
- // patch the map check.
+ // Patch the map check.
(*(reinterpret_cast<Object**>(map_address))) = value;
}
}
diff --git a/src/ic-inl.h b/src/ic-inl.h
index f5ce0ad..bb56962 100644
--- a/src/ic-inl.h
+++ b/src/ic-inl.h
@@ -39,6 +39,7 @@
// Get the address of the call.
Address result = pc() - Assembler::kTargetAddrToReturnAddrDist;
+#ifdef ENABLE_DEBUGGER_SUPPORT
// First check if any break points are active if not just return the address
// of the call.
if (!Debug::has_break_points()) return result;
@@ -55,6 +56,9 @@
// No break point here just return the address of the call.
return result;
}
+#else
+ return result;
+#endif
}
diff --git a/src/ic.cc b/src/ic.cc
index d7bd764..51768d7 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -100,6 +100,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
Address IC::OriginalCodeAddress() {
HandleScope scope;
// Compute the JavaScript frame for the frame pointer of this IC
@@ -126,7 +127,7 @@
int delta = original_code->instruction_start() - code->instruction_start();
return addr + delta;
}
-
+#endif
IC::State IC::StateFrom(Code* target, Object* receiver) {
IC::State state = target->ic_state();
@@ -236,7 +237,7 @@
// Make sure to also clear the map used in inline fast cases. If we
// do not clear these maps, cached code can keep objects alive
// through the embedded maps.
- PatchInlinedMapCheck(address, Heap::null_value());
+ ClearInlinedVersion(address);
SetTargetAtAddress(address, initialize_stub());
}
@@ -356,6 +357,7 @@
if (opt->IsJSFunction()) return opt;
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Handle stepping into a function if step into is active.
if (Debug::StepInActive()) {
// Protect the result in a handle as the debugger can allocate and might
@@ -365,6 +367,7 @@
Debug::HandleStepIn(function, fp(), false);
return *function;
}
+#endif
return result;
}
diff --git a/src/ic.h b/src/ic.h
index bbe1f6d..11d47ae 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -107,9 +107,11 @@
Address fp() const { return fp_; }
Address pc() const { return *pc_address_; }
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Computes the address in the original code when the code running is
// containing break points (calls to DebugBreakXXX builtins).
Address OriginalCodeAddress();
+#endif
// Set the call-site target.
void set_target(Code* code) { SetTargetAtAddress(address(), code); }
@@ -252,6 +254,12 @@
static void GeneratePreMonomorphic(MacroAssembler* masm);
static void GenerateGeneric(MacroAssembler* masm);
+ // Check if this IC corresponds to an inlined version.
+ static bool HasInlinedVersion(Address address);
+
+ // Clear the use of the inlined version.
+ static void ClearInlinedVersion(Address address);
+
private:
static void Generate(MacroAssembler* masm, const ExternalReference& f);
diff --git a/src/jump-target-arm.cc b/src/jump-target-arm.cc
index 3ce5f30..6d375e5 100644
--- a/src/jump-target-arm.cc
+++ b/src/jump-target-arm.cc
@@ -35,7 +35,7 @@
// -------------------------------------------------------------------------
// JumpTarget implementation.
-#define __ masm_->
+#define __ ACCESS_MASM(masm_)
void JumpTarget::DoJump() {
ASSERT(cgen_ != NULL);
diff --git a/src/jump-target-ia32.cc b/src/jump-target-ia32.cc
index 8afb0a8..a1049b2 100644
--- a/src/jump-target-ia32.cc
+++ b/src/jump-target-ia32.cc
@@ -35,7 +35,7 @@
// -------------------------------------------------------------------------
// JumpTarget implementation.
-#define __ masm_->
+#define __ ACCESS_MASM(masm_)
void JumpTarget::DoJump() {
ASSERT(cgen_ != NULL);
diff --git a/src/log.cc b/src/log.cc
index d9e304d..f23b73b 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -814,35 +814,6 @@
}
-void Logger::BeginCodeRegionEvent(CodeRegion* region,
- Assembler* masm,
- const char* name) {
-#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
- LogMessageBuilder msg;
- msg.Append("begin-code-region,0x%x,0x%x,0x%x,%s\n",
- reinterpret_cast<unsigned int>(region),
- reinterpret_cast<unsigned int>(masm),
- masm->pc_offset(),
- name);
- msg.WriteToLogFile();
-#endif
-}
-
-
-void Logger::EndCodeRegionEvent(CodeRegion* region, Assembler* masm) {
-#ifdef ENABLE_LOGGING_AND_PROFILING
- if (logfile_ == NULL || !FLAG_log_code) return;
- LogMessageBuilder msg;
- msg.Append("end-code-region,0x%x,0x%x,0x%x\n",
- reinterpret_cast<unsigned int>(region),
- reinterpret_cast<unsigned int>(masm),
- masm->pc_offset());
- msg.WriteToLogFile();
-#endif
-}
-
-
void Logger::ResourceEvent(const char* name, const char* tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (logfile_ == NULL || !FLAG_log) return;
diff --git a/src/log.h b/src/log.h
index bbcfa42..44c1957 100644
--- a/src/log.h
+++ b/src/log.h
@@ -174,11 +174,6 @@
static void CodeMoveEvent(Address from, Address to);
// Emits a code delete event.
static void CodeDeleteEvent(Address from);
- // Emits region delimiters
- static void BeginCodeRegionEvent(CodeRegion* region,
- Assembler* masm,
- const char* name);
- static void EndCodeRegionEvent(CodeRegion* region, Assembler* masm);
// ==== Events logged by --log-gc. ====
// Heap sampling events: start, end, and individual types.
diff --git a/src/macro-assembler-arm.cc b/src/macro-assembler-arm.cc
index 88a300b..365c1ad 100644
--- a/src/macro-assembler-arm.cc
+++ b/src/macro-assembler-arm.cc
@@ -168,11 +168,11 @@
}
-void MacroAssembler::Ret() {
+void MacroAssembler::Ret(Condition cond) {
#if USE_BX
- bx(lr);
+ bx(lr, cond);
#else
- mov(pc, Operand(lr));
+ mov(pc, Operand(lr), LeaveCC, cond);
#endif
}
@@ -320,16 +320,19 @@
add(r6, fp, Operand(r4, LSL, kPointerSizeLog2));
add(r6, r6, Operand(ExitFrameConstants::kPPDisplacement - kPointerSize));
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Save the state of all registers to the stack from the memory
// location. This is needed to allow nested break points.
if (type == StackFrame::EXIT_DEBUG) {
// Use sp as base to push.
CopyRegistersFromMemoryToStack(sp, kJSCallerSaved);
}
+#endif
}
void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Restore the memory copy of the registers by digging them out from
// the stack. This is needed to allow nested break points.
if (type == StackFrame::EXIT_DEBUG) {
@@ -339,6 +342,7 @@
add(r3, fp, Operand(kOffset));
CopyRegistersFromStackToMemory(r3, r2, kJSCallerSaved);
}
+#endif
// Clear top frame.
mov(r3, Operand(0));
@@ -348,9 +352,9 @@
// Restore current context from top and clear it in debug mode.
mov(ip, Operand(ExternalReference(Top::k_context_address)));
ldr(cp, MemOperand(ip));
- if (kDebug) {
- str(r3, MemOperand(ip));
- }
+#ifdef DEBUG
+ str(r3, MemOperand(ip));
+#endif
// Pop the arguments, restore registers, and return.
mov(sp, Operand(fp)); // respect ABI stack constraint
@@ -491,6 +495,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::SaveRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of registers to memory location.
@@ -548,7 +553,7 @@
}
}
}
-
+#endif
void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) {
@@ -674,10 +679,10 @@
// Load current lexical context from the stack frame.
ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
// In debug mode, make sure the lexical context is set.
- if (kDebug) {
- cmp(scratch, Operand(0));
- Check(ne, "we should not have an empty lexical context");
- }
+#ifdef DEBUG
+ cmp(scratch, Operand(0));
+ Check(ne, "we should not have an empty lexical context");
+#endif
// Load the global context of the current context.
int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
diff --git a/src/macro-assembler-arm.h b/src/macro-assembler-arm.h
index 4b999fd..d3835be 100644
--- a/src/macro-assembler-arm.h
+++ b/src/macro-assembler-arm.h
@@ -86,7 +86,7 @@
void Call(Register target, Condition cond = al);
void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
- void Ret();
+ void Ret(Condition cond = al);
// Jumps to the label at the index given by the Smi in "index".
void SmiJumpTable(Register index, Vector<Label*> targets);
@@ -138,6 +138,7 @@
InvokeFlag flag);
+#ifdef ENABLE_DEBUGGER_SUPPORT
// ---------------------------------------------------------------------------
// Debugger Support
@@ -147,7 +148,7 @@
void CopyRegistersFromStackToMemory(Register base,
Register scratch,
RegList regs);
-
+#endif
// ---------------------------------------------------------------------------
// Exception handling
@@ -297,6 +298,15 @@
}
+#ifdef GENERATED_CODE_COVERAGE
+#define CODE_COVERAGE_STRINGIFY(x) #x
+#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
+#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
+#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
+#else
+#define ACCESS_MASM(masm) masm->
+#endif
+
} } // namespace v8::internal
diff --git a/src/macro-assembler-ia32.cc b/src/macro-assembler-ia32.cc
index 4fad3be..d6d5800 100644
--- a/src/macro-assembler-ia32.cc
+++ b/src/macro-assembler-ia32.cc
@@ -216,6 +216,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::SaveRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of registers to memory location.
@@ -290,7 +291,7 @@
}
}
}
-
+#endif
void MacroAssembler::Set(Register dst, const Immediate& x) {
if (x.is_zero()) {
@@ -378,6 +379,7 @@
mov(edi, Operand(eax));
lea(esi, Operand(ebp, eax, times_4, offset));
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Save the state of all registers to the stack from the memory
// location. This is needed to allow nested break points.
if (type == StackFrame::EXIT_DEBUG) {
@@ -389,6 +391,7 @@
// associated with this issue).
PushRegistersFromMemory(kJSCallerSaved);
}
+#endif
// Reserve space for two arguments: argc and argv.
sub(Operand(esp), Immediate(2 * kPointerSize));
@@ -406,6 +409,7 @@
void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Restore the memory copy of the registers by digging them out from
// the stack. This is needed to allow nested break points.
if (type == StackFrame::EXIT_DEBUG) {
@@ -416,6 +420,7 @@
lea(ebx, Operand(ebp, kOffset));
CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
}
+#endif
// Get the return address from the stack and restore the frame pointer.
mov(ecx, Operand(ebp, 1 * kPointerSize));
@@ -427,9 +432,9 @@
// Restore current context from top and clear it in debug mode.
ExternalReference context_address(Top::k_context_address);
mov(esi, Operand::StaticVariable(context_address));
- if (kDebug) {
- mov(Operand::StaticVariable(context_address), Immediate(0));
- }
+#ifdef DEBUG
+ mov(Operand::StaticVariable(context_address), Immediate(0));
+#endif
// Push the return address to get ready to return.
push(ecx);
diff --git a/src/macro-assembler-ia32.h b/src/macro-assembler-ia32.h
index 40aa84a..ae3a853 100644
--- a/src/macro-assembler-ia32.h
+++ b/src/macro-assembler-ia32.h
@@ -73,7 +73,7 @@
Register value,
Register scratch);
-
+#ifdef ENABLE_DEBUGGER_SUPPORT
// ---------------------------------------------------------------------------
// Debugger Support
@@ -84,7 +84,7 @@
void CopyRegistersFromStackToMemory(Register base,
Register scratch,
RegList regs);
-
+#endif
// ---------------------------------------------------------------------------
// Activation frames
@@ -343,6 +343,29 @@
return Operand(object, index, scale, offset - kHeapObjectTag);
}
+
+#ifdef GENERATED_CODE_COVERAGE
+extern void LogGeneratedCodeCoverage(const char* file_line);
+#define CODE_COVERAGE_STRINGIFY(x) #x
+#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
+#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
+#define ACCESS_MASM(masm) { \
+ byte* ia32_coverage_function = \
+ reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
+ masm->pushfd(); \
+ masm->pushad(); \
+ masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__))); \
+ masm->call(ia32_coverage_function, RelocInfo::RUNTIME_ENTRY); \
+ masm->pop(eax); \
+ masm->popad(); \
+ masm->popfd(); \
+ } \
+ masm->
+#else
+#define ACCESS_MASM(masm) masm->
+#endif
+
+
} } // namespace v8::internal
#endif // V8_MACRO_ASSEMBLER_IA32_H_
diff --git a/src/messages.js b/src/messages.js
index cd9a1e8..fa6fb1f 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -98,6 +98,7 @@
instanceof_function_expected: "Expecting a function in instanceof check, but got %0",
instanceof_nonobject_proto: "Function has non-object prototype '%0' in instanceof check",
null_to_object: "Cannot convert null to object",
+ reduce_no_initial: "Reduce of empty array with no initial value",
// RangeError
invalid_array_length: "Invalid array length",
invalid_array_apply_length: "Function.prototype.apply supports only up to 1024 arguments",
diff --git a/src/mirror-delay.js b/src/mirror-delay.js
index 9c9d713..dc4d7eb 100644
--- a/src/mirror-delay.js
+++ b/src/mirror-delay.js
@@ -1582,6 +1582,11 @@
};
+ScriptMirror.prototype.data = function() {
+ return this.script_.data;
+};
+
+
ScriptMirror.prototype.scriptType = function() {
return this.script_.type;
};
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index f40fd3e..635ef0f 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -924,7 +924,11 @@
VerifyPointer(name());
line_offset()->SmiVerify();
column_offset()->SmiVerify();
+ VerifyPointer(data());
+ VerifyPointer(wrapper());
type()->SmiVerify();
+ VerifyPointer(line_ends());
+ VerifyPointer(id());
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index c2143ea..73b9c84 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2053,10 +2053,12 @@
ACCESSORS(Script, id, Object, kIdOffset)
ACCESSORS(Script, line_offset, Smi, kLineOffsetOffset)
ACCESSORS(Script, column_offset, Smi, kColumnOffsetOffset)
+ACCESSORS(Script, data, Object, kDataOffset)
ACCESSORS(Script, wrapper, Proxy, kWrapperOffset)
ACCESSORS(Script, type, Smi, kTypeOffset)
ACCESSORS(Script, line_ends, Object, kLineEndsOffset)
+#ifdef ENABLE_DEBUGGER_SUPPORT
ACCESSORS(DebugInfo, shared, SharedFunctionInfo, kSharedFunctionInfoIndex)
ACCESSORS(DebugInfo, original_code, Code, kOriginalCodeIndex)
ACCESSORS(DebugInfo, code, Code, kPatchedCodeIndex)
@@ -2066,6 +2068,7 @@
ACCESSORS(BreakPointInfo, source_position, Smi, kSourcePositionIndex)
ACCESSORS(BreakPointInfo, statement_position, Smi, kStatementPositionIndex)
ACCESSORS(BreakPointInfo, break_point_objects, Object, kBreakPointObjectsIndex)
+#endif
ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset)
ACCESSORS(SharedFunctionInfo, instance_class_name, Object,
diff --git a/src/objects.cc b/src/objects.cc
index 9c640f4..31c5bab 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -43,22 +43,6 @@
namespace v8 { namespace internal {
-#define FIELD_ADDR(p, offset) \
- (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
-
-
-#define WRITE_FIELD(p, offset, value) \
- (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value)
-
-
-#define WRITE_INT_FIELD(p, offset, value) \
- (*reinterpret_cast<int*>(FIELD_ADDR(p, offset)) = value)
-
-
-#define WRITE_BARRIER(object, offset) \
- Heap::RecordWrite(object->address(), offset);
-
-
// Getters and setters are stored in a fixed array property. These are
// constants for their indices.
const int kGetterIndex = 0;
@@ -1800,6 +1784,17 @@
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(result, name, value);
}
+
+ if (IsJSGlobalProxy()) {
+ Object* proto = GetPrototype();
+ if (proto->IsNull()) return value;
+ ASSERT(proto->IsJSGlobalObject());
+ return JSObject::cast(proto)->IgnoreAttributesAndSetLocalProperty(
+ name,
+ value,
+ attributes);
+ }
+
// Check for accessor in prototype chain removed here in clone.
if (result->IsNotFound()) {
return AddProperty(name, value, attributes);
@@ -1820,20 +1815,16 @@
return AddFastPropertyUsingMap(result->GetTransitionMap(),
name,
value);
- } else {
- return ConvertDescriptorToField(name, value, attributes);
}
+ return ConvertDescriptorToField(name, value, attributes);
case CONSTANT_FUNCTION:
if (value == result->GetConstantFunction()) return value;
// Only replace the function if necessary.
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case CALLBACKS:
- return SetPropertyWithCallback(result->GetCallbackObject(),
- name,
- value,
- result->holder());
case INTERCEPTOR:
- return SetPropertyWithInterceptor(name, value, attributes);
+ // Override callback in clone
+ return ConvertDescriptorToField(name, value, attributes);
case CONSTANT_TRANSITION:
// Replace with a MAP_TRANSITION to a new map with a FIELD, even
// if the value is a function.
@@ -4678,6 +4669,7 @@
it.rinfo()->set_target_object(code);
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
if (Debug::has_break_points()) {
for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN));
!it.done();
@@ -4691,6 +4683,7 @@
}
}
}
+#endif
set_ic_flag(IC_TARGET_IS_OBJECT);
}
@@ -4712,10 +4705,12 @@
v->VisitCodeTarget(it.rinfo());
} else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
v->VisitExternalReference(it.rinfo()->target_reference_address());
+#ifdef ENABLE_DEBUGGER_SUPPORT
} else if (Debug::has_break_points() &&
RelocInfo::IsJSReturn(rmode) &&
it.rinfo()->IsCallInstruction()) {
v->VisitDebugTarget(it.rinfo());
+#endif
} else if (rmode == RelocInfo::RUNTIME_ENTRY) {
v->VisitRuntimeEntry(it.rinfo());
}
@@ -4740,6 +4735,7 @@
it.rinfo()->set_target_address(code->instruction_start());
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
if (Debug::has_break_points()) {
for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN));
!it.done();
@@ -4751,6 +4747,7 @@
}
}
}
+#endif
set_ic_flag(IC_TARGET_IS_ADDRESS);
}
@@ -5138,7 +5135,7 @@
VMState state(EXTERNAL);
result = getter(index, info);
}
- if (!result.IsEmpty()) return !result->IsUndefined();
+ if (!result.IsEmpty()) return true;
}
return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
}
@@ -5861,43 +5858,46 @@
}
-void FixedArray::Swap(int i, int j) {
+void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
Object* temp = get(i);
set(i, get(j));
set(j, temp);
+ if (this != numbers) {
+ temp = numbers->get(i);
+ numbers->set(i, numbers->get(j));
+ numbers->set(j, temp);
+ }
}
-static void InsertionSortPairs(FixedArray* content, FixedArray* smis) {
- int len = smis->length();
+static void InsertionSortPairs(FixedArray* content,
+ FixedArray* numbers,
+ int len) {
for (int i = 1; i < len; i++) {
int j = i;
while (j > 0 &&
- Smi::cast(smis->get(j-1))->value() >
- Smi::cast(smis->get(j))->value()) {
- smis->Swap(j-1, j);
- content->Swap(j-1, j);
+ (NumberToUint32(numbers->get(j - 1)) >
+ NumberToUint32(numbers->get(j)))) {
+ content->SwapPairs(numbers, j - 1, j);
j--;
}
}
}
-void HeapSortPairs(FixedArray* content, FixedArray* smis) {
+void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
// In-place heap sort.
- ASSERT(content->length() == smis->length());
- int len = smis->length();
+ ASSERT(content->length() == numbers->length());
// Bottom-up max-heap construction.
for (int i = 1; i < len; ++i) {
int child_index = i;
while (child_index > 0) {
int parent_index = ((child_index + 1) >> 1) - 1;
- int parent_value = Smi::cast(smis->get(parent_index))->value();
- int child_value = Smi::cast(smis->get(child_index))->value();
+ uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
+ uint32_t child_value = NumberToUint32(numbers->get(child_index));
if (parent_value < child_value) {
- content->Swap(parent_index, child_index);
- smis->Swap(parent_index, child_index);
+ content->SwapPairs(numbers, parent_index, child_index);
} else {
break;
}
@@ -5908,25 +5908,22 @@
// Extract elements and create sorted array.
for (int i = len - 1; i > 0; --i) {
// Put max element at the back of the array.
- content->Swap(0, i);
- smis->Swap(0, i);
+ content->SwapPairs(numbers, 0, i);
// Sift down the new top element.
int parent_index = 0;
while (true) {
int child_index = ((parent_index + 1) << 1) - 1;
if (child_index >= i) break;
- uint32_t child1_value = Smi::cast(smis->get(child_index))->value();
- uint32_t child2_value = Smi::cast(smis->get(child_index + 1))->value();
- uint32_t parent_value = Smi::cast(smis->get(parent_index))->value();
+ uint32_t child1_value = NumberToUint32(numbers->get(child_index));
+ uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
+ uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
if (child_index + 1 >= i || child1_value > child2_value) {
if (parent_value > child1_value) break;
- content->Swap(parent_index, child_index);
- smis->Swap(parent_index, child_index);
+ content->SwapPairs(numbers, parent_index, child_index);
parent_index = child_index;
} else {
if (parent_value > child2_value) break;
- content->Swap(parent_index, child_index + 1);
- smis->Swap(parent_index, child_index + 1);
+ content->SwapPairs(numbers, parent_index, child_index + 1);
parent_index = child_index + 1;
}
}
@@ -5934,43 +5931,41 @@
}
-// Sort this array and the smis as pairs wrt. the (distinct) smis.
-void FixedArray::SortPairs(FixedArray* smis) {
- ASSERT(this->length() == smis->length());
- int len = smis->length();
+// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
+void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
+ ASSERT(this->length() == numbers->length());
// For small arrays, simply use insertion sort.
if (len <= 10) {
- InsertionSortPairs(this, smis);
+ InsertionSortPairs(this, numbers, len);
return;
}
// Check the range of indices.
- int min_index = Smi::cast(smis->get(0))->value();
- int max_index = min_index;
- int i;
+ uint32_t min_index = NumberToUint32(numbers->get(0));
+ uint32_t max_index = min_index;
+ uint32_t i;
for (i = 1; i < len; i++) {
- if (Smi::cast(smis->get(i))->value() < min_index) {
- min_index = Smi::cast(smis->get(i))->value();
- } else if (Smi::cast(smis->get(i))->value() > max_index) {
- max_index = Smi::cast(smis->get(i))->value();
+ if (NumberToUint32(numbers->get(i)) < min_index) {
+ min_index = NumberToUint32(numbers->get(i));
+ } else if (NumberToUint32(numbers->get(i)) > max_index) {
+ max_index = NumberToUint32(numbers->get(i));
}
}
if (max_index - min_index + 1 == len) {
// Indices form a contiguous range, unless there are duplicates.
- // Do an in-place linear time sort assuming distinct smis, but
+ // Do an in-place linear time sort assuming distinct numbers, but
// avoid hanging in case they are not.
for (i = 0; i < len; i++) {
- int p;
- int j = 0;
+ uint32_t p;
+ uint32_t j = 0;
// While the current element at i is not at its correct position p,
// swap the elements at these two positions.
- while ((p = Smi::cast(smis->get(i))->value() - min_index) != i &&
+ while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
j++ < len) {
- this->Swap(i, p);
- smis->Swap(i, p);
+ SwapPairs(numbers, i, p);
}
}
} else {
- HeapSortPairs(this, smis);
+ HeapSortPairs(this, numbers, len);
return;
}
}
@@ -6758,7 +6753,7 @@
}
// Sort the arrays wrt. enumeration order.
- iteration_order->SortPairs(enumeration_order);
+ iteration_order->SortPairs(enumeration_order, enumeration_order->length());
// Overwrite the enumeration_order with the enumeration indices.
for (int i = 0; i < length; i++) {
@@ -7010,6 +7005,7 @@
if ((attr & filter) == 0) storage->set(index++, k);
}
}
+ storage->SortPairs(storage, index);
ASSERT(storage->length() >= index);
}
@@ -7031,7 +7027,7 @@
}
}
}
- storage->SortPairs(sort_array);
+ storage->SortPairs(sort_array, sort_array->length());
ASSERT(storage->length() >= index);
}
@@ -7176,6 +7172,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Check if there is a break point at this code position.
bool DebugInfo::HasBreakPoint(int code_position) {
// Get the break point info object for this code position.
@@ -7419,6 +7416,6 @@
// Multiple break points.
return FixedArray::cast(break_point_objects())->length();
}
-
+#endif
} } // namespace v8::internal
diff --git a/src/objects.h b/src/objects.h
index ade282b..db3c449 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -389,7 +389,7 @@
// Note that for subtle reasons related to the ordering or numerical values of
// type tags, elements in this list have to be added to the INSTANCE_TYPE_LIST
// manually.
-#define STRUCT_LIST(V) \
+#define STRUCT_LIST_ALL(V) \
V(ACCESSOR_INFO, AccessorInfo, accessor_info) \
V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info) \
V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info) \
@@ -398,10 +398,19 @@
V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \
V(SIGNATURE_INFO, SignatureInfo, signature_info) \
V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \
- V(DEBUG_INFO, DebugInfo, debug_info) \
- V(BREAK_POINT_INFO, BreakPointInfo, break_point_info) \
V(SCRIPT, Script, script)
+#ifdef ENABLE_DEBUGGER_SUPPORT
+#define STRUCT_LIST_DEBUGGER(V) \
+ V(DEBUG_INFO, DebugInfo, debug_info) \
+ V(BREAK_POINT_INFO, BreakPointInfo, break_point_info)
+#else
+#define STRUCT_LIST_DEBUGGER(V)
+#endif
+
+#define STRUCT_LIST(V) \
+ STRUCT_LIST_ALL(V) \
+ STRUCT_LIST_DEBUGGER(V)
// We use the full 8 bits of the instance_type field to encode heap object
// instance types. The high-order bit (bit 7) is set if the object is not a
@@ -1585,11 +1594,15 @@
bool IsEqualTo(FixedArray* other);
#endif
- // Swap two elements.
- void Swap(int i, int j);
+ // Swap two elements in a pair of arrays. If this array and the
+ // numbers array are the same object, the elements are only swapped
+ // once.
+ void SwapPairs(FixedArray* numbers, int i, int j);
- // Sort this array and the smis as pairs wrt. the smis.
- void SortPairs(FixedArray* smis);
+ // Sort prefix of this array and the numbers array as pairs wrt. the
+ // numbers. If the numbers array and the this array are the same
+ // object, the prefix of this array is sorted.
+ void SortPairs(FixedArray* numbers, uint32_t len);
protected:
// Set operation on FixedArray without using write barriers.
@@ -2590,6 +2603,9 @@
// extracted.
DECL_ACCESSORS(column_offset, Smi)
+ // [data]: additional data associated with this script.
+ DECL_ACCESSORS(data, Object)
+
// [wrapper]: the wrapper cache.
DECL_ACCESSORS(wrapper, Proxy)
@@ -2610,7 +2626,8 @@
static const int kNameOffset = kSourceOffset + kPointerSize;
static const int kLineOffsetOffset = kNameOffset + kPointerSize;
static const int kColumnOffsetOffset = kLineOffsetOffset + kPointerSize;
- static const int kWrapperOffset = kColumnOffsetOffset + kPointerSize;
+ static const int kDataOffset = kColumnOffsetOffset + kPointerSize;
+ static const int kWrapperOffset = kDataOffset + kPointerSize;
static const int kTypeOffset = kWrapperOffset + kPointerSize;
static const int kLineEndsOffset = kTypeOffset + kPointerSize;
static const int kIdOffset = kLineEndsOffset + kPointerSize;
@@ -4147,6 +4164,7 @@
};
+#ifdef ENABLE_DEBUGGER_SUPPORT
// The DebugInfo class holds additional information for a function being
// debugged.
class DebugInfo: public Struct {
@@ -4252,6 +4270,7 @@
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BreakPointInfo);
};
+#endif // ENABLE_DEBUGGER_SUPPORT
#undef DECL_BOOLEAN_ACCESSORS
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 9209990..1e71704 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -262,7 +262,8 @@
}
-int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+int OS::StackWalk(Vector<OS::StackFrame> frames) {
+ int frames_size = frames.length();
void** addresses = NewArray<void*>(frames_size);
int frames_count = backtrace(addresses, frames_size);
@@ -502,27 +503,24 @@
bool FreeBSDSemaphore::Wait(int timeout) {
const long kOneSecondMicros = 1000000; // NOLINT
- const long kOneSecondNanos = 1000000000; // NOLINT
// Split timeout into second and nanosecond parts.
- long nanos = (timeout % kOneSecondMicros) * 1000; // NOLINT
- time_t secs = timeout / kOneSecondMicros;
+ struct timeval delta;
+ delta.tv_usec = timeout % kOneSecondMicros;
+ delta.tv_sec = timeout / kOneSecondMicros;
- // Get the current real time clock.
- struct timespec ts;
- if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
+ struct timeval current_time;
+ // Get the current time.
+ if (gettimeofday(¤t_time, NULL) == -1) {
return false;
}
- // Calculate realtime for end of timeout.
- ts.tv_nsec += nanos;
- if (ts.tv_nsec >= kOneSecondNanos) {
- ts.tv_nsec -= kOneSecondNanos;
- ts.tv_nsec++;
- }
- ts.tv_sec += secs;
+ // Calculate time for end of timeout.
+ struct timeval end_time;
+ timeradd(¤t_time, &delta, &end_time);
- // Wait for semaphore signalled or timeout.
+ struct timespec ts;
+ TIMEVAL_TO_TIMESPEC(&end_time, &ts);
while (true) {
int result = sem_timedwait(&sem_, &ts);
if (result == 0) return true; // Successfully got semaphore.
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index f9a5dea..9f5b9ac 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -262,9 +262,10 @@
}
-int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+int OS::StackWalk(Vector<OS::StackFrame> frames) {
// backtrace is a glibc extension.
#ifdef __GLIBC__
+ int frames_size = frames.length();
void** addresses = NewArray<void*>(frames_size);
int frames_count = backtrace(addresses, frames_size);
@@ -506,28 +507,34 @@
}
+#ifndef TIMEVAL_TO_TIMESPEC
+#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+} while (false)
+#endif
+
+
bool LinuxSemaphore::Wait(int timeout) {
const long kOneSecondMicros = 1000000; // NOLINT
- const long kOneSecondNanos = 1000000000; // NOLINT
// Split timeout into second and nanosecond parts.
- long nanos = (timeout % kOneSecondMicros) * 1000; // NOLINT
- time_t secs = timeout / kOneSecondMicros;
+ struct timeval delta;
+ delta.tv_usec = timeout % kOneSecondMicros;
+ delta.tv_sec = timeout / kOneSecondMicros;
- // Get the current realtime clock.
- struct timespec ts;
- if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
+ struct timeval current_time;
+ // Get the current time.
+ if (gettimeofday(¤t_time, NULL) == -1) {
return false;
}
- // Calculate real time for end of timeout.
- ts.tv_nsec += nanos;
- if (ts.tv_nsec >= kOneSecondNanos) {
- ts.tv_nsec -= kOneSecondNanos;
- ts.tv_nsec++;
- }
- ts.tv_sec += secs;
+ // Calculate time for end of timeout.
+ struct timeval end_time;
+ timeradd(¤t_time, &delta, &end_time);
+ struct timespec ts;
+ TIMEVAL_TO_TIMESPEC(&end_time, &ts);
// Wait for semaphore signalled or timeout.
while (true) {
int result = sem_timedwait(&sem_, &ts);
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index b13122f..7951543 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -212,10 +212,11 @@
}
-int OS::StackWalk(StackFrame* frames, int frames_size) {
+int OS::StackWalk(Vector<StackFrame> frames) {
#ifndef MAC_OS_X_VERSION_10_5
return 0;
#else
+ int frames_size = frames.length();
void** addresses = NewArray<void*>(frames_size);
int frames_count = backtrace(addresses, frames_size);
diff --git a/src/platform-nullos.cc b/src/platform-nullos.cc
index 3a50b9d..42583f1 100644
--- a/src/platform-nullos.cc
+++ b/src/platform-nullos.cc
@@ -215,7 +215,7 @@
}
-int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+int OS::StackWalk(Vector<OS::StackFrame> frames) {
UNIMPLEMENTED();
return 0;
}
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 7177870..597a217 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -1161,7 +1161,7 @@
// it is triggered by the use of inline assembler.
#pragma warning(push)
#pragma warning(disable : 4748)
-int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+int OS::StackWalk(Vector<OS::StackFrame> frames) {
BOOL ok;
// Load the required functions from DLL's.
@@ -1201,6 +1201,7 @@
int frames_count = 0;
// Collect stack frames.
+ int frames_size = frames.length();
while (frames_count < frames_size) {
ok = _StackWalk64(
IMAGE_FILE_MACHINE_I386, // MachineType
@@ -1284,7 +1285,7 @@
#else // __MINGW32__
void OS::LogSharedLibraryAddresses() { }
-int OS::StackWalk(OS::StackFrame* frames, int frames_size) { return 0; }
+int OS::StackWalk(Vector<OS::StackFrame> frames) { return 0; }
#endif // __MINGW32__
diff --git a/src/platform.h b/src/platform.h
index db4f2fd..b70095b 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -207,7 +207,7 @@
char text[kStackWalkMaxTextLen];
};
- static int StackWalk(StackFrame* frames, int frames_size);
+ static int StackWalk(Vector<StackFrame> frames);
// Factory method for creating platform dependent Mutex.
// Please use delete to reclaim the storage for the returned Mutex.
diff --git a/src/regexp-macro-assembler-ia32.cc b/src/regexp-macro-assembler-ia32.cc
index c2f76b4..8c92091 100644
--- a/src/regexp-macro-assembler-ia32.cc
+++ b/src/regexp-macro-assembler-ia32.cc
@@ -86,7 +86,7 @@
* byte* stack_area_top)
*/
-#define __ masm_->
+#define __ ACCESS_MASM(masm_)
RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
Mode mode,
diff --git a/src/rewriter.cc b/src/rewriter.cc
index 6641f26..4e3676b 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -194,7 +194,7 @@
if (node->name()->length() == 0) {
// Anonymous function.
- func_name_inferrer_.SetFuncToInfer(node);
+ func_name_inferrer_.AddFunction(node);
}
}
@@ -282,10 +282,7 @@
case Token::ASSIGN:
// No type can be infered from the general assignment.
- if (node->value()->AsFunctionLiteral() != NULL ||
- node->value()->AsObjectLiteral() != NULL) {
- scoped_fni.Enter();
- }
+ scoped_fni.Enter();
break;
case Token::ASSIGN_BIT_OR:
case Token::ASSIGN_BIT_XOR:
diff --git a/src/runtime.cc b/src/runtime.cc
index ab25c9e..2b350a5 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2688,6 +2688,59 @@
}
+Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
+ Handle<Object> key,
+ Handle<Object> value,
+ PropertyAttributes attr) {
+ HandleScope scope;
+
+ // Check if the given key is an array index.
+ uint32_t index;
+ if (Array::IndexFromObject(*key, &index)) {
+ ASSERT(attr == NONE);
+
+ // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
+ // of a string using [] notation. We need to support this too in
+ // JavaScript.
+ // In the case of a String object we just need to redirect the assignment to
+ // the underlying string if the index is in range. Since the underlying
+ // string does nothing with the assignment then we can ignore such
+ // assignments.
+ if (js_object->IsStringObjectWithCharacterAt(index)) {
+ return *value;
+ }
+
+ return js_object->SetElement(index, *value);
+ }
+
+ if (key->IsString()) {
+ if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
+ ASSERT(attr == NONE);
+ return js_object->SetElement(index, *value);
+ } else {
+ Handle<String> key_string = Handle<String>::cast(key);
+ key_string->TryFlattenIfNotFlat();
+ return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
+ *value,
+ attr);
+ }
+ }
+
+ // Call-back into JavaScript to convert the key to a string.
+ bool has_pending_exception = false;
+ Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
+ if (has_pending_exception) return Failure::Exception();
+ Handle<String> name = Handle<String>::cast(converted);
+
+ if (name->AsArrayIndex(&index)) {
+ ASSERT(attr == NONE);
+ return js_object->SetElement(index, *value);
+ } else {
+ return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
+ }
+}
+
+
static Object* Runtime_SetProperty(Arguments args) {
NoHandleAllocation ha;
RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
@@ -3482,6 +3535,7 @@
return Heap::nan_value();
}
+
static Object* Runtime_NumberAdd(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -4158,10 +4212,12 @@
JSFunction* function = JSFunction::cast(constructor);
// Handle stepping into constructors if step into is active.
+#ifdef ENABLE_DEBUGGER_SUPPORT
if (Debug::StepInActive()) {
HandleScope scope;
Debug::HandleStepIn(Handle<JSFunction>(function), 0, true);
}
+#endif
if (function->has_initial_map() &&
function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
@@ -4525,12 +4581,6 @@
}
-static Object* Runtime_DebugBreak(Arguments args) {
- ASSERT(args.length() == 0);
- return Execution::DebugBreakHelper();
-}
-
-
static Object* Runtime_StackGuard(Arguments args) {
ASSERT(args.length() == 1);
@@ -4892,26 +4942,6 @@
}
-static Object* Runtime_CompileScript(Arguments args) {
- HandleScope scope;
- ASSERT(args.length() == 4);
-
- CONVERT_ARG_CHECKED(String, source, 0);
- CONVERT_ARG_CHECKED(String, script, 1);
- CONVERT_CHECKED(Smi, line_attrs, args[2]);
- int line = line_attrs->value();
- CONVERT_CHECKED(Smi, col_attrs, args[3]);
- int col = col_attrs->value();
- Handle<JSFunction> boilerplate =
- Compiler::Compile(source, script, line, col, NULL, NULL);
- if (boilerplate.is_null()) return Failure::Exception();
- Handle<JSFunction> fun =
- Factory::NewFunctionFromBoilerplate(boilerplate,
- Handle<Context>(Top::context()));
- return *fun;
-}
-
-
static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
// This utility adjusts the property attributes for newly created Function
// object ("new Function(...)") by changing the map.
@@ -5316,6 +5346,13 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
+static Object* Runtime_DebugBreak(Arguments args) {
+ ASSERT(args.length() == 0);
+ return Execution::DebugBreakHelper();
+}
+
+
// Helper functions for wrapping and unwrapping stack frame ids.
static Smi* WrapFrameId(StackFrame::Id id) {
ASSERT(IsAligned(OffsetFrom(id), 4));
@@ -5928,8 +5965,8 @@
if (result->IsFailure()) return result;
static const int kMaxCFramesSize = 200;
- OS::StackFrame frames[kMaxCFramesSize];
- int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
+ ScopedVector<OS::StackFrame> frames(kMaxCFramesSize);
+ int frames_count = OS::StackWalk(frames);
if (frames_count == OS::kStackWalkError) {
return Heap::undefined_value();
}
@@ -6796,6 +6833,22 @@
}
+static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
+#ifdef DEBUG
+ HandleScope scope;
+ ASSERT(args.length() == 1);
+ // Get the function and make sure it is compiled.
+ CONVERT_ARG_CHECKED(JSFunction, func, 0);
+ if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
+ return Failure::Exception();
+ }
+ func->code()->PrintLn();
+#endif // DEBUG
+ return Heap::undefined_value();
+}
+#endif // ENABLE_DEBUGGER_SUPPORT
+
+
// Finds the script object from the script data. NOTE: This operation uses
// heap traversal to find the function generated for the source position
// for the requested break point. For lazily compiled functions several heap
@@ -6845,21 +6898,6 @@
}
-static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
-#ifdef DEBUG
- HandleScope scope;
- ASSERT(args.length() == 1);
- // Get the function and make sure it is compiled.
- CONVERT_ARG_CHECKED(JSFunction, func, 0);
- if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
- return Failure::Exception();
- }
- func->code()->PrintLn();
-#endif // DEBUG
- return Heap::undefined_value();
-}
-
-
static Object* Runtime_Abort(Arguments args) {
ASSERT(args.length() == 2);
OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
diff --git a/src/runtime.h b/src/runtime.h
index 657e5c5..6bd19f6 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -195,7 +195,6 @@
\
/* Globals */ \
F(CompileString, 2) \
- F(CompileScript, 4) \
F(GlobalPrint, 1) \
\
/* Eval */ \
@@ -215,42 +214,6 @@
F(DefineAccessor, -1 /* 4 or 5 */) \
F(LookupAccessor, 3) \
\
- /* Debugging */ \
- F(SetDebugEventListener, 2) \
- F(Break, 0) \
- F(DebugGetPropertyDetails, 2) \
- F(DebugGetProperty, 2) \
- F(DebugLocalPropertyNames, 1) \
- F(DebugLocalElementNames, 1) \
- F(DebugPropertyTypeFromDetails, 1) \
- F(DebugPropertyAttributesFromDetails, 1) \
- F(DebugPropertyIndexFromDetails, 1) \
- F(DebugInterceptorInfo, 1) \
- F(DebugNamedInterceptorPropertyNames, 1) \
- F(DebugIndexedInterceptorElementNames, 1) \
- F(DebugNamedInterceptorPropertyValue, 2) \
- F(DebugIndexedInterceptorElementValue, 2) \
- F(CheckExecutionState, 1) \
- F(GetFrameCount, 1) \
- F(GetFrameDetails, 2) \
- F(GetCFrames, 1) \
- F(GetThreadCount, 1) \
- F(GetThreadDetails, 2) \
- F(GetBreakLocations, 1) \
- F(SetFunctionBreakPoint, 3) \
- F(SetScriptBreakPoint, 3) \
- F(ClearBreakPoint, 1) \
- F(ChangeBreakOnException, 2) \
- F(PrepareStep, 3) \
- F(ClearStepping, 0) \
- F(DebugEvaluate, 4) \
- F(DebugEvaluateGlobal, 3) \
- F(DebugGetLoadedScripts, 0) \
- F(DebugReferencedBy, 3) \
- F(DebugConstructedBy, 2) \
- F(DebugGetPrototype, 1) \
- F(SystemBreak, 0) \
- \
/* Literals */ \
F(MaterializeRegExpLiteral, 4)\
F(CreateArrayLiteralBoilerplate, 3) \
@@ -290,8 +253,6 @@
F(DebugTrace, 0) \
F(TraceEnter, 0) \
F(TraceExit, 1) \
- F(DebugBreak, 0) \
- F(FunctionGetAssemblerCode, 1) \
F(Abort, 2) \
/* Logging */ \
F(Log, 2) \
@@ -299,6 +260,48 @@
/* Pseudo functions - handled as macros by parser */ \
F(IS_VAR, 1)
+#ifdef ENABLE_DEBUGGER_SUPPORT
+#define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) \
+ /* Debugger support*/ \
+ F(DebugBreak, 0) \
+ F(SetDebugEventListener, 2) \
+ F(Break, 0) \
+ F(DebugGetPropertyDetails, 2) \
+ F(DebugGetProperty, 2) \
+ F(DebugLocalPropertyNames, 1) \
+ F(DebugLocalElementNames, 1) \
+ F(DebugPropertyTypeFromDetails, 1) \
+ F(DebugPropertyAttributesFromDetails, 1) \
+ F(DebugPropertyIndexFromDetails, 1) \
+ F(DebugInterceptorInfo, 1) \
+ F(DebugNamedInterceptorPropertyNames, 1) \
+ F(DebugIndexedInterceptorElementNames, 1) \
+ F(DebugNamedInterceptorPropertyValue, 2) \
+ F(DebugIndexedInterceptorElementValue, 2) \
+ F(CheckExecutionState, 1) \
+ F(GetFrameCount, 1) \
+ F(GetFrameDetails, 2) \
+ F(GetCFrames, 1) \
+ F(GetThreadCount, 1) \
+ F(GetThreadDetails, 2) \
+ F(GetBreakLocations, 1) \
+ F(SetFunctionBreakPoint, 3) \
+ F(SetScriptBreakPoint, 3) \
+ F(ClearBreakPoint, 1) \
+ F(ChangeBreakOnException, 2) \
+ F(PrepareStep, 3) \
+ F(ClearStepping, 0) \
+ F(DebugEvaluate, 4) \
+ F(DebugEvaluateGlobal, 3) \
+ F(DebugGetLoadedScripts, 0) \
+ F(DebugReferencedBy, 3) \
+ F(DebugConstructedBy, 2) \
+ F(DebugGetPrototype, 1) \
+ F(SystemBreak, 0) \
+ F(FunctionGetAssemblerCode, 1)
+#else
+#define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F)
+#endif
#ifdef DEBUG
#define RUNTIME_FUNCTION_LIST_DEBUG(F) \
@@ -316,7 +319,8 @@
#define RUNTIME_FUNCTION_LIST(F) \
RUNTIME_FUNCTION_LIST_ALWAYS(F) \
- RUNTIME_FUNCTION_LIST_DEBUG(F)
+ RUNTIME_FUNCTION_LIST_DEBUG(F) \
+ RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F)
// ----------------------------------------------------------------------------
// Runtime provides access to all C++ runtime functions.
@@ -369,6 +373,11 @@
Handle<Object> value,
PropertyAttributes attr);
+ static Object* ForceSetObjectProperty(Handle<JSObject> object,
+ Handle<Object> key,
+ Handle<Object> value,
+ PropertyAttributes attr);
+
static Object* GetObjectProperty(Handle<Object> object, Handle<Object> key);
// This function is used in FunctionNameUsing* tests.
diff --git a/src/serialize.cc b/src/serialize.cc
index 9a2be23..e15c003 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -548,6 +548,7 @@
AddFromId(ref_table[i].type, ref_table[i].id, ref_table[i].name);
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Debug addresses
Add(Debug_Address(Debug::k_after_break_target_address).address(),
DEBUG_ADDRESS,
@@ -567,6 +568,7 @@
Debug::k_register_address << kDebugIdShift | i,
name.start());
}
+#endif
// Stat counters
struct StatsRefTableEntry {
@@ -659,10 +661,6 @@
UNCLASSIFIED,
4,
"RegExpStack::limit_address()");
- Add(ExternalReference::debug_break().address(),
- UNCLASSIFIED,
- 5,
- "Debug::Break()");
Add(ExternalReference::new_space_start().address(),
UNCLASSIFIED,
6,
@@ -679,10 +677,28 @@
UNCLASSIFIED,
9,
"Heap::NewSpaceAllocationTopAddress()");
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ Add(ExternalReference::debug_break().address(),
+ UNCLASSIFIED,
+ 5,
+ "Debug::Break()");
Add(ExternalReference::debug_step_in_fp_address().address(),
UNCLASSIFIED,
10,
"Debug::step_in_fp_addr()");
+ Add(ExternalReference::double_fp_operation(Token::ADD).address(),
+ UNCLASSIFIED,
+ 11,
+ "add_two_doubles");
+ Add(ExternalReference::double_fp_operation(Token::SUB).address(),
+ UNCLASSIFIED,
+ 12,
+ "sub_two_doubles");
+ Add(ExternalReference::double_fp_operation(Token::MUL).address(),
+ UNCLASSIFIED,
+ 13,
+ "mul_two_doubles");
+#endif
}
diff --git a/src/simulator-arm.cc b/src/simulator-arm.cc
index 5a61107..7d96b3a 100644
--- a/src/simulator-arm.cc
+++ b/src/simulator-arm.cc
@@ -90,12 +90,44 @@
}
+
+#ifdef GENERATED_CODE_COVERAGE
+static FILE* coverage_log = NULL;
+
+
+static void InitializeCoverage() {
+ char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
+ if (file_name != NULL) {
+ coverage_log = fopen(file_name, "aw+");
+ }
+}
+
+
+void Debugger::Stop(Instr* instr) {
+ char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff);
+ if (strlen(str) > 0) {
+ if (coverage_log != NULL) {
+ fprintf(coverage_log, "%s\n", str);
+ fflush(coverage_log);
+ }
+ instr->SetInstructionBits(0xe1a00000); // Overwrite with nop.
+ }
+ sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
+}
+
+#else // ndef GENERATED_CODE_COVERAGE
+
+static void InitializeCoverage() {
+}
+
+
void Debugger::Stop(Instr* instr) {
const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff);
PrintF("Simulator hit %s\n", str);
sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
Debug();
}
+#endif
static const char* reg_names[] = { "r0", "r1", "r2", "r3",
@@ -375,6 +407,7 @@
// access violation if the simulator ever tries to execute it.
registers_[pc] = bad_lr;
registers_[lr] = bad_lr;
+ InitializeCoverage();
}
@@ -427,6 +460,37 @@
}
+// For use in calls that take two double values, constructed from r0, r1, r2
+// and r3.
+void Simulator::GetFpArgs(double* x, double* y) {
+ // We use a char buffer to get around the strict-aliasing rules which
+ // otherwise allow the compiler to optimize away the copy.
+ char buffer[2 * sizeof(registers_[0])];
+ // Registers 0 and 1 -> x.
+ memcpy(buffer, registers_, sizeof(buffer));
+ memcpy(x, buffer, sizeof(buffer));
+ // Registers 2 and 3 -> y.
+ memcpy(buffer, registers_ + 2, sizeof(buffer));
+ memcpy(y, buffer, sizeof(buffer));
+}
+
+
+void Simulator::SetFpResult(const double& result) {
+ char buffer[2 * sizeof(registers_[0])];
+ memcpy(buffer, &result, sizeof(buffer));
+ // result -> registers 0 and 1.
+ memcpy(registers_, buffer, sizeof(buffer));
+}
+
+
+void Simulator::TrashCallerSaveRegisters() {
+ // We don't trash the registers with the return value.
+ registers_[2] = 0x50Bad4U;
+ registers_[3] = 0x50Bad4U;
+ registers_[12] = 0x50Bad4U;
+}
+
+
// The ARM cannot do unaligned reads and writes. On some ARM platforms an
// interrupt is caused. On others it does a funky rotation thing. For now we
// simply disallow unaligned reads, but at some point we may want to move to
@@ -862,7 +926,8 @@
// Software interrupt instructions are used by the simulator to call into the
// C-based V8 runtime.
void Simulator::SoftwareInterrupt(Instr* instr) {
- switch (instr->SwiField()) {
+ int swi = instr->SwiField();
+ switch (swi) {
case call_rt_r5: {
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(get_register(r5));
@@ -894,6 +959,30 @@
dbg.Debug();
break;
}
+ {
+ double x, y, z;
+ case simulator_fp_add:
+ GetFpArgs(&x, &y);
+ z = x + y;
+ SetFpResult(z);
+ TrashCallerSaveRegisters();
+ set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
+ break;
+ case simulator_fp_sub:
+ GetFpArgs(&x, &y);
+ z = x - y;
+ SetFpResult(z);
+ TrashCallerSaveRegisters();
+ set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
+ break;
+ case simulator_fp_mul:
+ GetFpArgs(&x, &y);
+ z = x * y;
+ SetFpResult(z);
+ TrashCallerSaveRegisters();
+ set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
+ break;
+ }
default: {
UNREACHABLE();
break;
diff --git a/src/simulator-arm.h b/src/simulator-arm.h
index 4f3c53d..5553ab2 100644
--- a/src/simulator-arm.h
+++ b/src/simulator-arm.h
@@ -174,6 +174,12 @@
// Executes one instruction.
void InstructionDecode(Instr* instr);
+ // For use in calls that take two double values, constructed from r0, r1, r2
+ // and r3.
+ void GetFpArgs(double* x, double* y);
+ void SetFpResult(const double& result);
+ void TrashCallerSaveRegisters();
+
// architecture state
int32_t registers_[16];
bool n_flag_;
diff --git a/src/string-stream.cc b/src/string-stream.cc
index f311e20..2e0912f 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -57,19 +57,26 @@
bool StringStream::Put(char c) {
- if (space() == 0) return false;
- if (length_ >= capacity_ - 1) {
+ if (full()) return false;
+ ASSERT(length_ < capacity_);
+ // Since the trailing '\0' is not accounted for in length_ fullness is
+ // indicated by a difference of 1 between length_ and capacity_. Thus when
+ // reaching a difference of 2 we need to grow the buffer.
+ if (length_ == capacity_ - 2) {
unsigned new_capacity = capacity_;
char* new_buffer = allocator_->grow(&new_capacity);
if (new_capacity > capacity_) {
capacity_ = new_capacity;
buffer_ = new_buffer;
} else {
- // Indicate truncation with dots.
- memset(cursor(), '.', space());
- length_ = capacity_;
- buffer_[length_ - 2] = '\n';
- buffer_[length_ - 1] = '\0';
+ // Reached the end of the available buffer.
+ ASSERT(capacity_ >= 5);
+ length_ = capacity_ - 1; // Indicate fullness of the stream.
+ buffer_[length_ - 4] = '.';
+ buffer_[length_ - 3] = '.';
+ buffer_[length_ - 2] = '.';
+ buffer_[length_ - 1] = '\n';
+ buffer_[length_] = '\0';
return false;
}
}
@@ -95,8 +102,7 @@
void StringStream::Add(Vector<const char> format, Vector<FmtElm> elms) {
// If we already ran out of space then return immediately.
- if (space() == 0)
- return;
+ if (full()) return;
int offset = 0;
int elm = 0;
while (offset < format.length()) {
@@ -564,12 +570,10 @@
}
+// Only grow once to the maximum allowable size.
char* NoAllocationStringAllocator::grow(unsigned* bytes) {
- unsigned new_bytes = *bytes * 2;
- if (new_bytes > size_) {
- new_bytes = size_;
- }
- *bytes = new_bytes;
+ ASSERT(size_ >= *bytes);
+ *bytes = size_;
return space_;
}
diff --git a/src/string-stream.h b/src/string-stream.h
index 37ae93e..901f376 100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -162,8 +162,8 @@
unsigned length_; // does not include terminating 0-character
char* buffer_;
+ bool full() const { return (capacity_ - length_) == 1; }
int space() const { return capacity_ - length_; }
- char* cursor() const { return buffer_ + length_; }
DISALLOW_IMPLICIT_CONSTRUCTORS(StringStream);
};
diff --git a/src/stub-cache-arm.cc b/src/stub-cache-arm.cc
index 211b643..56afa02 100644
--- a/src/stub-cache-arm.cc
+++ b/src/stub-cache-arm.cc
@@ -33,7 +33,7 @@
namespace v8 { namespace internal {
-#define __ masm->
+#define __ ACCESS_MASM(masm)
static void ProbeTable(MacroAssembler* masm,
@@ -183,7 +183,7 @@
// Check that the maps haven't changed.
Register reg =
- __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+ masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
GenerateFastPropertyLoad(masm, r0, reg, holder, index);
__ Ret();
}
@@ -203,7 +203,7 @@
// Check that the maps haven't changed.
Register reg =
- __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+ masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Return the constant value.
__ mov(r0, Operand(Handle<Object>(value)));
@@ -226,7 +226,7 @@
// Check that the maps haven't changed.
Register reg =
- __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+ masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller.
__ push(receiver); // receiver
@@ -256,7 +256,7 @@
// Check that the maps haven't changed.
Register reg =
- __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+ masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller.
__ push(receiver); // receiver
@@ -456,8 +456,7 @@
#undef __
-
-#define __ masm()->
+#define __ ACCESS_MASM(masm())
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
@@ -511,7 +510,7 @@
// Do the right check and compute the holder register.
Register reg =
- __ CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
+ masm()->CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
// Check that the function really is a function.
diff --git a/src/stub-cache-ia32.cc b/src/stub-cache-ia32.cc
index 19777e6..bdfc3d6 100644
--- a/src/stub-cache-ia32.cc
+++ b/src/stub-cache-ia32.cc
@@ -33,7 +33,7 @@
namespace v8 { namespace internal {
-#define __ masm->
+#define __ ACCESS_MASM(masm)
static void ProbeTable(MacroAssembler* masm,
@@ -256,7 +256,7 @@
// Check that the maps haven't changed.
Register reg =
- __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+ masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Get the value from the properties.
GenerateFastPropertyLoad(masm, eax, reg, holder, index);
@@ -279,7 +279,7 @@
// Check that the maps haven't changed.
Register reg =
- __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+ masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller.
__ pop(scratch2); // remove return address
@@ -310,7 +310,7 @@
// Check that the maps haven't changed.
Register reg =
- __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+ masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Return the constant value.
__ mov(eax, Handle<Object>(value));
@@ -332,7 +332,7 @@
// Check that the maps haven't changed.
Register reg =
- __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+ masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller.
__ pop(scratch2); // remove return address
@@ -440,7 +440,7 @@
#undef __
-#define __ masm()->
+#define __ ACCESS_MASM(masm())
// TODO(1241006): Avoid having lazy compile stubs specialized by the
@@ -485,7 +485,7 @@
// Do the right check and compute the holder register.
Register reg =
- __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+ masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
@@ -656,7 +656,7 @@
// Check that maps have not changed and compute the holder register.
Register reg =
- __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+ masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
// Enter an internal frame.
__ EnterInternalFrame();
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 35e3d42..6811fd2 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -594,6 +594,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
Object* StubCache::ComputeCallDebugBreak(int argc) {
Code::Flags flags =
Code::ComputeFlags(Code::CALL_IC, DEBUG_BREAK, NORMAL, argc);
@@ -612,6 +613,7 @@
StubCompiler compiler;
return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
}
+#endif
Object* StubCache::ComputeLazyCompile(int argc) {
@@ -836,6 +838,7 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
HandleScope scope;
Debug::GenerateCallICDebugBreak(masm());
@@ -864,6 +867,7 @@
}
return result;
}
+#endif
Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) {
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 05845e5..824f4ff 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -157,8 +157,10 @@
// Finds the Code object stored in the Heap::non_monomorphic_cache().
static Code* FindCallInitialize(int argc);
+#ifdef ENABLE_DEBUGGER_SUPPORT
static Object* ComputeCallDebugBreak(int argc);
static Object* ComputeCallDebugPrepareStepIn(int argc);
+#endif
static Object* ComputeLazyCompile(int argc);
@@ -288,8 +290,10 @@
Object* CompileCallNormal(Code::Flags flags);
Object* CompileCallMegamorphic(Code::Flags flags);
Object* CompileCallMiss(Code::Flags flags);
+#ifdef ENABLE_DEBUGGER_SUPPORT
Object* CompileCallDebugBreak(Code::Flags flags);
Object* CompileCallDebugPrepareStepIn(Code::Flags flags);
+#endif
Object* CompileLazyCompile(Code::Flags flags);
// Static functions for generating parts of stubs.
diff --git a/src/top.cc b/src/top.cc
index a99e9ff..96f98a5 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -116,15 +116,15 @@
// When the thread starts running it will allocate a fixed number of bytes
// on the stack and publish the location of this memory for others to use.
void Run() {
- EmbeddedVector<char, 32 * 1024> local_buffer;
+ EmbeddedVector<char, 15 * 1024> local_buffer;
// Initialize the buffer with a known good value.
OS::StrNCpy(local_buffer, "Trace data was not generated.\n",
local_buffer.length());
// Publish the local buffer and signal its availability.
- data_ = &local_buffer[0];
- length_ = sizeof(local_buffer);
+ data_ = local_buffer.start();
+ length_ = local_buffer.length();
data_ready_semaphore_->Signal();
while (keep_running_) {
@@ -728,8 +728,10 @@
bool should_return_exception = ShouldReportException(&is_caught_externally);
bool report_exception = !is_out_of_memory && should_return_exception;
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Notify debugger of exception.
Debugger::OnException(exception_handle, report_exception);
+#endif
// Generate the message.
Handle<Object> message_obj;
diff --git a/src/utils.h b/src/utils.h
index f62b47a..e008c85 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -406,6 +406,16 @@
};
+template <typename T>
+class ScopedVector : public Vector<T> {
+ public:
+ explicit ScopedVector(int length) : Vector<T>(NewArray<T>(length), length) { }
+ ~ScopedVector() {
+ DeleteArray(this->start());
+ }
+};
+
+
inline Vector<const char> CStrVector(const char* data) {
return Vector<const char>(data, strlen(data));
}
diff --git a/src/v8.cc b/src/v8.cc
index 9158b52..fbe3d5d 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -72,7 +72,9 @@
v8::Locker::StartPreemption(100);
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
Debug::Setup(create_heap_objects);
+#endif
StubCache::Initialize(create_heap_objects);
// If we are deserializing, read the state into the now-empty heap.
@@ -111,7 +113,9 @@
Heap::TearDown();
Logger::TearDown();
+#ifdef ENABLE_DEBUGGER_SUPPORT
Debugger::TearDown();
+#endif
has_been_setup_ = false;
has_been_disposed_ = true;
diff --git a/src/v8.h b/src/v8.h
index 4cf0b70..4ced0d2 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -51,6 +51,11 @@
#error both DEBUG and NDEBUG are set
#endif
+// Enable debugger support by default, unless it is in ANDROID
+#if !defined(ENABLE_DEBUGGER_SUPPORT) && !defined(ANDROID)
+#define ENABLE_DEBUGGER_SUPPORT
+#endif
+
// Basic includes
#include "../include/v8.h"
#include "globals.h"
diff --git a/src/v8threads.cc b/src/v8threads.cc
index e8f6f9b..2439476 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -144,7 +144,9 @@
char* from = state->data();
from = HandleScopeImplementer::RestoreThread(from);
from = Top::RestoreThread(from);
+#ifdef ENABLE_DEBUGGER_SUPPORT
from = Debug::RestoreDebug(from);
+#endif
from = StackGuard::RestoreStackGuard(from);
from = RegExpStack::RestoreStack(from);
from = Bootstrapper::RestoreState(from);
@@ -172,7 +174,9 @@
static int ArchiveSpacePerThread() {
return HandleScopeImplementer::ArchiveSpacePerThread() +
Top::ArchiveSpacePerThread() +
+#ifdef ENABLE_DEBUGGER_SUPPORT
Debug::ArchiveSpacePerThread() +
+#endif
StackGuard::ArchiveSpacePerThread() +
RegExpStack::ArchiveSpacePerThread() +
Bootstrapper::ArchiveSpacePerThread();
@@ -259,7 +263,9 @@
char* to = state->data();
to = HandleScopeImplementer::ArchiveThread(to);
to = Top::ArchiveThread(to);
+#ifdef ENABLE_DEBUGGER_SUPPORT
to = Debug::ArchiveDebug(to);
+#endif
to = StackGuard::ArchiveStackGuard(to);
to = RegExpStack::ArchiveStack(to);
to = Bootstrapper::ArchiveState(to);
diff --git a/src/virtual-frame-arm.cc b/src/virtual-frame-arm.cc
index baf0814..b794d8b 100644
--- a/src/virtual-frame-arm.cc
+++ b/src/virtual-frame-arm.cc
@@ -36,7 +36,8 @@
// -------------------------------------------------------------------------
// VirtualFrame implementation.
-#define __ masm_->
+#define __ ACCESS_MASM(masm_)
+
// On entry to a function, the virtual frame already contains the
// receiver and the parameters. All initial frame elements are in
diff --git a/src/virtual-frame-ia32.cc b/src/virtual-frame-ia32.cc
index eb3befc..3647ca5 100644
--- a/src/virtual-frame-ia32.cc
+++ b/src/virtual-frame-ia32.cc
@@ -33,7 +33,7 @@
namespace v8 { namespace internal {
-#define __ masm_->
+#define __ ACCESS_MASM(masm_)
// -------------------------------------------------------------------------
// VirtualFrame implementation.