summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFeng Qian <fqian@google.com>2009-04-17 10:56:30 -0700
committerFeng Qian <fqian@google.com>2009-04-17 10:56:30 -0700
commit9d6c0fe1a576c623a6db3b95e0460519f984da64 (patch)
treeb7eb0f703cb467f01b29b67633532072c34536cf
parente62a68bd8f6c9cb81ff8757c55d64ae13a277eab (diff)
downloadexternal_webkit-9d6c0fe1a576c623a6db3b95e0460519f984da64.zip
external_webkit-9d6c0fe1a576c623a6db3b95e0460519f984da64.tar.gz
external_webkit-9d6c0fe1a576c623a6db3b95e0460519f984da64.tar.bz2
Update v8 source to bleeding_edge 1738.
Git thinks bug-269.js and func-name-inferrer.cc are similar because both has copyright info and small code size.
-rw-r--r--v8/ChangeLog40
-rw-r--r--v8/REVISION2
-rw-r--r--v8/SConstruct13
-rw-r--r--v8/samples/process.cc2
-rw-r--r--v8/src/SConscript3
-rw-r--r--v8/src/api.cc10
-rw-r--r--v8/src/assembler.cc36
-rw-r--r--v8/src/assembler.h19
-rw-r--r--v8/src/ast.h9
-rw-r--r--v8/src/builtins-arm.cc5
-rw-r--r--v8/src/codegen-arm.cc497
-rw-r--r--v8/src/codegen-arm.h13
-rw-r--r--v8/src/codegen-ia32.cc15
-rw-r--r--v8/src/codegen-ia32.h8
-rw-r--r--v8/src/codegen.cc9
-rw-r--r--v8/src/codegen.h5
-rw-r--r--v8/src/compiler.cc13
-rw-r--r--v8/src/constants-arm.h7
-rw-r--r--v8/src/d8-posix.cc20
-rw-r--r--v8/src/d8.cc67
-rw-r--r--v8/src/d8.h19
-rw-r--r--v8/src/debug-arm.cc2
-rw-r--r--v8/src/debug-delay.js22
-rw-r--r--v8/src/debug.cc38
-rw-r--r--v8/src/disasm-arm.cc9
-rw-r--r--v8/src/frames-arm.cc2
-rw-r--r--v8/src/frames-ia32.cc2
-rw-r--r--v8/src/frames-inl.h13
-rw-r--r--v8/src/frames.cc24
-rw-r--r--v8/src/frames.h12
-rw-r--r--v8/src/func-name-inferrer.cc75
-rw-r--r--v8/src/func-name-inferrer.h122
-rw-r--r--v8/src/globals.h11
-rw-r--r--v8/src/handles.cc33
-rw-r--r--v8/src/heap.cc40
-rw-r--r--v8/src/ic-arm.cc6
-rw-r--r--v8/src/log.cc29
-rw-r--r--v8/src/log.h5
-rw-r--r--v8/src/macro-assembler-arm.cc6
-rw-r--r--v8/src/macro-assembler-arm.h2
-rw-r--r--v8/src/mark-compact.cc24
-rw-r--r--v8/src/mirror-delay.js14
-rw-r--r--v8/src/mksnapshot.cc2
-rw-r--r--v8/src/objects-inl.h7
-rw-r--r--v8/src/objects.cc157
-rw-r--r--v8/src/objects.h35
-rw-r--r--v8/src/parser.cc4
-rw-r--r--v8/src/platform-freebsd.cc28
-rw-r--r--v8/src/platform-linux.cc65
-rw-r--r--v8/src/platform-macos.cc3
-rw-r--r--v8/src/platform-nullos.cc2
-rw-r--r--v8/src/platform-win32.cc5
-rw-r--r--v8/src/platform.h2
-rw-r--r--v8/src/prettyprinter.cc8
-rw-r--r--v8/src/rewriter.cc46
-rw-r--r--v8/src/runtime.cc23
-rw-r--r--v8/src/runtime.h6
-rw-r--r--v8/src/serialize.cc12
-rw-r--r--v8/src/simulator-arm.cc91
-rw-r--r--v8/src/simulator-arm.h6
-rw-r--r--v8/src/string-stream.cc32
-rw-r--r--v8/src/string-stream.h2
-rw-r--r--v8/src/stub-cache-arm.cc15
-rw-r--r--v8/src/top.cc6
-rw-r--r--v8/src/utils.h10
-rw-r--r--v8/src/virtual-frame-arm.cc3
-rw-r--r--v8/src/virtual-frame-arm.h2
-rw-r--r--v8/test/cctest/SConscript1
-rw-r--r--v8/test/cctest/test-api.cc108
-rw-r--r--v8/test/cctest/test-debug.cc206
-rw-r--r--v8/test/cctest/test-func-name-inference.cc250
-rw-r--r--v8/test/cctest/test-strings.cc57
-rw-r--r--v8/test/mjsunit/const-declaration.js172
-rw-r--r--v8/test/mjsunit/constant-folding.js25
-rw-r--r--v8/test/mjsunit/debug-handle.js92
-rw-r--r--v8/test/mjsunit/enumeration-order.js60
-rw-r--r--v8/test/mjsunit/eval-enclosing-function-name.js76
-rw-r--r--v8/test/mjsunit/mjsunit.js14
-rw-r--r--v8/test/mjsunit/mjsunit.status5
-rw-r--r--v8/test/mjsunit/negate.js6
-rw-r--r--v8/test/mjsunit/number-limits.js12
-rw-r--r--v8/test/mjsunit/override-read-only-property.js64
-rw-r--r--v8/test/mjsunit/receiver-in-with-calls.js47
-rw-r--r--v8/test/mjsunit/regexp-multiline-stack-trace.js2
-rw-r--r--v8/test/mjsunit/regress/regress-269.js (renamed from v8/test/mjsunit/bugs/bug-269.js)0
-rw-r--r--v8/test/mjsunit/regress/regress-312.js31
-rw-r--r--v8/test/mjsunit/smi-ops.js95
-rwxr-xr-x[-rw-r--r--]v8/test/mjsunit/string-match.js0
-rw-r--r--v8/test/mjsunit/testcfg.py10
-rw-r--r--v8/test/mjsunit/tools/codemap.js116
-rw-r--r--v8/test/mjsunit/tools/splaytree.js166
-rw-r--r--v8/tools/codemap.js205
-rw-r--r--v8/tools/jsmin.pycbin0 -> 6912 bytes
-rwxr-xr-xv8/tools/presubmit.py4
-rw-r--r--v8/tools/splaytree.js321
-rw-r--r--v8/tools/v8.xcodeproj/project.pbxproj14
-rw-r--r--v8/tools/visual_studio/common.vsprops2
-rw-r--r--v8/tools/visual_studio/v8_base.vcproj8
-rw-r--r--v8/tools/visual_studio/v8_base_arm.vcproj8
-rw-r--r--v8/tools/visual_studio/v8_cctest.vcproj4
100 files changed, 3348 insertions, 708 deletions
diff --git a/v8/ChangeLog b/v8/ChangeLog
index 5433a70..d5c30c7 100644
--- a/v8/ChangeLog
+++ b/v8/ChangeLog
@@ -1,3 +1,43 @@
+2009-04-15: Version 1.1.10
+
+ Fixed crash bug that occurred when loading a const variable in the
+ presence of eval.
+
+ Allowed using with and eval in registered extensions in debug mode
+ by fixing bogus assert.
+
+ Fixed the source position for function returns to enable the
+ debugger to break there.
+
+
+2009-04-14: Version 1.1.9
+
+ Made the stack traversal code in the profiler robust by avoiding
+ to look into the heap.
+
+ Added name inferencing for anonymous functions to facilitate
+ debugging and profiling.
+
+ Re-enabled stats timers in the developer shell (d8).
+
+ Fixed issue 303 by avoiding to shortcut cons-symbols.
+
+
+2009-04-11: Version 1.1.8
+
+ Changed test-debug/ThreadedDebugging to be non-flaky (issue 96).
+
+ Fixed step-in handling for Function.prototype.apply and call in
+ the debugger (issue 269).
+
+ Fixed v8::Object::DeleteHiddenValue to not bail out when there
+ are no hidden properties.
+
+ Added workaround for crash bug, where external symbol table
+ entries with deleted resources would lead to NPEs when looking
+ up in the symbol table.
+
+
2009-04-07: Version 1.1.7
Added support for easily importing additional environment
diff --git a/v8/REVISION b/v8/REVISION
index 7ea9da8..2996207 100644
--- a/v8/REVISION
+++ b/v8/REVISION
@@ -1 +1 @@
-http://v8.googlecode.com/svn/trunk@1682
+https://v8.googlecode.com/svn/branches/bleeding_edge@1738
diff --git a/v8/SConstruct b/v8/SConstruct
index 9654ebd..1024a5b 100644
--- a/v8/SConstruct
+++ b/v8/SConstruct
@@ -108,7 +108,7 @@ LIBRARY_FLAGS = {
'os:linux': {
'CCFLAGS': ['-ansi'],
'library:shared': {
- 'LIBS': ['pthread', 'rt']
+ 'LIBS': ['pthread']
}
},
'os:macos': {
@@ -142,7 +142,7 @@ LIBRARY_FLAGS = {
'DIALECTFLAGS': ['/nologo'],
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CXXFLAGS': ['$CCFLAGS', '/GR-', '/Gy'],
- 'CPPDEFINES': ['WIN32', '_USE_32BIT_TIME_T', 'PCRE_STATIC'],
+ 'CPPDEFINES': ['WIN32', '_USE_32BIT_TIME_T'],
'LINKFLAGS': ['/NOLOGO', '/MACHINE:X86', '/INCREMENTAL:NO',
'/NXCOMPAT', '/IGNORE:4221'],
'ARFLAGS': ['/NOLOGO'],
@@ -224,7 +224,7 @@ V8_EXTRA_FLAGS = {
MKSNAPSHOT_EXTRA_FLAGS = {
'gcc': {
'os:linux': {
- 'LIBS': ['pthread', 'rt'],
+ 'LIBS': ['pthread'],
},
'os:macos': {
'LIBS': ['pthread'],
@@ -238,6 +238,7 @@ MKSNAPSHOT_EXTRA_FLAGS = {
},
'msvc': {
'all': {
+ 'CPPDEFINES': ['_HAS_EXCEPTIONS=0'],
'LIBS': ['winmm', 'ws2_32']
}
}
@@ -268,7 +269,7 @@ CCTEST_EXTRA_FLAGS = {
'LIBPATH': [abspath('.')]
},
'os:linux': {
- 'LIBS': ['pthread', 'rt'],
+ 'LIBS': ['pthread'],
},
'os:macos': {
'LIBS': ['pthread'],
@@ -307,7 +308,7 @@ SAMPLE_FLAGS = {
'CCFLAGS': ['-fno-rtti', '-fno-exceptions']
},
'os:linux': {
- 'LIBS': ['pthread', 'rt'],
+ 'LIBS': ['pthread'],
},
'os:macos': {
'LIBS': ['pthread'],
@@ -387,7 +388,7 @@ D8_FLAGS = {
'LIBS': ['readline']
},
'os:linux': {
- 'LIBS': ['pthread', 'rt'],
+ 'LIBS': ['pthread'],
},
'os:macos': {
'LIBS': ['pthread'],
diff --git a/v8/samples/process.cc b/v8/samples/process.cc
index 6567f08..511e21a 100644
--- a/v8/samples/process.cc
+++ b/v8/samples/process.cc
@@ -27,8 +27,6 @@
#include <v8.h>
-// To avoid warnings from <map> on windows we disable exceptions.
-#define _HAS_EXCEPTIONS 0
#include <string>
#include <map>
diff --git a/v8/src/SConscript b/v8/src/SConscript
index 9b7ff02..97fb7d6 100644
--- a/v8/src/SConscript
+++ b/v8/src/SConscript
@@ -40,7 +40,8 @@ SOURCES = {
'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc',
'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc',
'debug-agent.cc', 'disassembler.cc', 'execution.cc', 'factory.cc',
- 'flags.cc', 'frames.cc', 'global-handles.cc', 'handles.cc', 'hashmap.cc',
+ 'flags.cc', 'frames.cc', 'func-name-inferrer.cc',
+ 'global-handles.cc', 'handles.cc', 'hashmap.cc',
'heap.cc', 'ic.cc', 'interpreter-irregexp.cc', 'jsregexp.cc',
'jump-target.cc', 'log.cc', 'mark-compact.cc', 'messages.cc', 'objects.cc',
'oprofile-agent.cc', 'parser.cc', 'property.cc', 'regexp-macro-assembler.cc',
diff --git a/v8/src/api.cc b/v8/src/api.cc
index 1ddb2c6..a5af312 100644
--- a/v8/src/api.cc
+++ b/v8/src/api.cc
@@ -2077,13 +2077,13 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
ON_BAILOUT("v8::DeleteHiddenValue()", return false);
ENTER_V8;
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- i::Handle<i::JSObject> hidden_props(
- i::JSObject::cast(*i::GetHiddenProperties(self, false)));
+ i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, false));
if (hidden_props->IsUndefined()) {
- return false;
+ return true;
}
+ i::Handle<i::JSObject> js_obj(i::JSObject::cast(*hidden_props));
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
- return i::DeleteProperty(hidden_props, key_obj)->IsTrue();
+ return i::DeleteProperty(js_obj, key_obj)->IsTrue();
}
@@ -2373,7 +2373,7 @@ bool v8::V8::Dispose() {
const char* v8::V8::GetVersion() {
- return "1.1.7";
+ return "1.1.11 (candidate)";
}
diff --git a/v8/src/assembler.cc b/v8/src/assembler.cc
index ad4b24c..977be7d 100644
--- a/v8/src/assembler.cc
+++ b/v8/src/assembler.cc
@@ -582,4 +582,40 @@ ExternalReference ExternalReference::debug_step_in_fp_address() {
return ExternalReference(Debug::step_in_fp_addr());
}
+
+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));
+}
+
} } // namespace v8::internal
diff --git a/v8/src/assembler.h b/v8/src/assembler.h
index 49c9b90..0352a70 100644
--- a/v8/src/assembler.h
+++ b/v8/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,22 +341,6 @@ class RelocIterator: public Malloced {
};
-// 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
@@ -417,6 +402,8 @@ class ExternalReference BASE_EMBEDDED {
// 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_;}
private:
diff --git a/v8/src/ast.h b/v8/src/ast.h
index 5dfd21d..b496816 100644
--- a/v8/src/ast.h
+++ b/v8/src/ast.h
@@ -1223,7 +1223,8 @@ class FunctionLiteral: public Expression {
end_position_(end_position),
is_expression_(is_expression),
loop_nesting_(0),
- function_token_position_(RelocInfo::kNoPosition) {
+ function_token_position_(RelocInfo::kNoPosition),
+ inferred_name_(Heap::empty_string()) {
#ifdef DEBUG
already_compiled_ = false;
#endif
@@ -1253,6 +1254,11 @@ class FunctionLiteral: public Expression {
bool loop_nesting() const { return loop_nesting_; }
void set_loop_nesting(int nesting) { loop_nesting_ = nesting; }
+ Handle<String> inferred_name() const { return inferred_name_; }
+ void set_inferred_name(Handle<String> inferred_name) {
+ inferred_name_ = inferred_name;
+ }
+
#ifdef DEBUG
void mark_as_compiled() {
ASSERT(!already_compiled_);
@@ -1273,6 +1279,7 @@ class FunctionLiteral: public Expression {
bool is_expression_;
int loop_nesting_;
int function_token_position_;
+ Handle<String> inferred_name_;
#ifdef DEBUG
bool already_compiled_;
#endif
diff --git a/v8/src/builtins-arm.cc b/v8/src/builtins-arm.cc
index 2e6f255..26ed45b 100644
--- a/v8/src/builtins-arm.cc
+++ b/v8/src/builtins-arm.cc
@@ -34,7 +34,7 @@
namespace v8 { namespace internal {
-#define __ masm->
+#define __ DEFINE_MASM(masm)
void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
@@ -218,8 +218,9 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ 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/v8/src/codegen-arm.cc b/v8/src/codegen-arm.cc
index 37a7cf2..2386b97 100644
--- a/v8/src/codegen-arm.cc
+++ b/v8/src/codegen-arm.cc
@@ -38,7 +38,8 @@
namespace v8 { namespace internal {
-#define __ masm_->
+#define __ DEFINE_MASM(masm_)
+
// -------------------------------------------------------------------------
// CodeGenState implementation.
@@ -653,37 +654,27 @@ void CodeGenerator::ToBoolean(JumpTarget* true_target,
}
-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 @@ class GenericBinaryOpStub : public CodeStub {
};
-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 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op) {
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 @@ class DeferredInlineSmiOperation: public DeferredCode {
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 @@ class DeferredInlineSmiOperation: public DeferredCode {
Token::Value op_;
int value_;
bool reversed_;
+ OverwriteMode overwrite_mode_;
};
@@ -844,7 +839,7 @@ void DeferredInlineSmiOperation::Generate() {
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 DeferredInlineSmiOperation::Generate() {
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 @@ void CodeGenerator::SmiOperation(Token::Value op,
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 @@ void CodeGenerator::SmiOperation(Token::Value op,
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 @@ void CodeGenerator::SmiOperation(Token::Value op,
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 @@ void CodeGenerator::SmiOperation(Token::Value op,
__ 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 @@ void CodeGenerator::SmiOperation(Token::Value op,
frame_->EmitPush(ip);
frame_->EmitPush(r0);
}
- GenericBinaryOperation(op);
+ GenericBinaryOperation(op, mode);
break;
}
@@ -1487,8 +1483,8 @@ void CodeGenerator::GenerateFastCaseSwitchJumpTable(
// 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);
@@ -2446,8 +2442,13 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
r1,
r2,
&slow));
+ if (potential_slot->var()->mode() == Variable::CONST) {
+ __ cmp(r0, Operand(Factory::the_hole_value()));
+ __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
+ }
// There is always control flow to slow from
- // ContextSlotOperandCheckExtensions.
+ // ContextSlotOperandCheckExtensions so we have to jump around
+ // it.
done.Jump();
}
}
@@ -2518,7 +2519,9 @@ void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot,
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));
@@ -2929,15 +2932,24 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
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);
}
}
@@ -3817,19 +3829,39 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
// 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);
}
@@ -4062,7 +4094,8 @@ bool CodeGenerator::HasValidEntryRegisters() { return true; }
#undef __
-#define __ masm->
+#define __ DEFINE_MASM(masm)
+
Handle<String> Reference::GetName() {
ASSERT(type_ == NAMED);
@@ -4300,167 +4333,80 @@ void Reference::SetValue(InitState init_state) {
}
-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).
- __ 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);
-
- // 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).
+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, 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);
+ __ push(r1);
+ __ push(r0);
+ __ mov(r0, Operand(1)); // Set number of arguments.
+ __ InvokeBuiltin(builtin, JUMP_JS); // Tail call.
- // 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);
+ }
}
@@ -4469,89 +4415,84 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
// 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, &not_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,
+ &not_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, &not_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,
+ &not_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, &not_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,
+ &not_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);
@@ -4561,7 +4502,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
default: UNREACHABLE();
}
- __ b(&exit);
+ __ Ret();
__ bind(&slow);
__ push(r1); // restore stack
__ push(r0);
@@ -4579,16 +4520,13 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
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);
@@ -4628,7 +4566,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
// 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
@@ -4640,13 +4578,13 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break;
default: UNREACHABLE();
}
- __ bind(&exit);
break;
}
default: UNREACHABLE();
}
- __ Ret();
+ // This code should be unreachable.
+ __ stop("Unreachable");
}
@@ -4716,7 +4654,9 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
__ 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));
+ if (kDebug && FLAG_debug_code) {
+ __ mov(lr, Operand(pc));
+ }
__ pop(pc);
}
@@ -4779,7 +4719,9 @@ void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
__ 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));
+ if (kDebug && FLAG_debug_code) {
+ __ mov(lr, Operand(pc));
+ }
__ pop(pc);
}
@@ -5038,9 +4980,11 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
}
__ 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
@@ -5052,6 +4996,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// 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);
@@ -5063,7 +5008,9 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// 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/v8/src/codegen-arm.h b/v8/src/codegen-arm.h
index 54c5e88..48b92ea 100644
--- a/v8/src/codegen-arm.h
+++ b/v8/src/codegen-arm.h
@@ -35,9 +35,6 @@ class DeferredCode;
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 };
@@ -160,7 +157,8 @@ class CodeGenerator: public AstVisitor {
int end_position,
bool is_expression,
bool is_toplevel,
- Handle<Script> script);
+ Handle<Script> script,
+ Handle<String> inferred_name);
// Accessors
MacroAssembler* masm() { return masm_; }
@@ -291,10 +289,13 @@ class CodeGenerator: public AstVisitor {
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/v8/src/codegen-ia32.cc b/v8/src/codegen-ia32.cc
index 714e5bd..47c3538 100644
--- a/v8/src/codegen-ia32.cc
+++ b/v8/src/codegen-ia32.cc
@@ -3286,8 +3286,14 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
ContextSlotOperandCheckExtensions(potential_slot,
value,
&slow));
+ if (potential_slot->var()->mode() == Variable::CONST) {
+ __ cmp(value.reg(), Factory::the_hole_value());
+ done.Branch(not_equal, &value);
+ __ mov(value.reg(), Factory::undefined_value());
+ }
// There is always control flow to slow from
- // ContextSlotOperandCheckExtensions.
+ // ContextSlotOperandCheckExtensions so we have to jump around
+ // it.
done.Jump(&value);
}
}
@@ -3927,6 +3933,9 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
} 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,
@@ -3939,7 +3948,9 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
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 &&
diff --git a/v8/src/codegen-ia32.h b/v8/src/codegen-ia32.h
index 165f877..a39bc58 100644
--- a/v8/src/codegen-ia32.h
+++ b/v8/src/codegen-ia32.h
@@ -35,9 +35,6 @@ class DeferredCode;
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 };
@@ -299,7 +296,8 @@ class CodeGenerator: public AstVisitor {
int end_position,
bool is_expression,
bool is_toplevel,
- Handle<Script> script);
+ Handle<Script> script,
+ Handle<String> inferred_name);
// Accessors
MacroAssembler* masm() { return masm_; }
@@ -434,7 +432,7 @@ class CodeGenerator: public AstVisitor {
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/v8/src/codegen.cc b/v8/src/codegen.cc
index c8f69c7..edc498d 100644
--- a/v8/src/codegen.cc
+++ b/v8/src/codegen.cc
@@ -230,7 +230,8 @@ void CodeGenerator::SetFunctionInfo(Handle<JSFunction> fun,
int end_position,
bool is_expression,
bool is_toplevel,
- Handle<Script> script) {
+ Handle<Script> script,
+ Handle<String> inferred_name) {
fun->shared()->set_length(length);
fun->shared()->set_formal_parameter_count(length);
fun->shared()->set_script(*script);
@@ -239,6 +240,7 @@ void CodeGenerator::SetFunctionInfo(Handle<JSFunction> fun,
fun->shared()->set_end_position(end_position);
fun->shared()->set_is_expression(is_expression);
fun->shared()->set_is_toplevel(is_toplevel);
+ fun->shared()->set_inferred_name(*inferred_name);
}
@@ -299,7 +301,8 @@ Handle<JSFunction> CodeGenerator::BuildBoilerplate(FunctionLiteral* node) {
CodeGenerator::SetFunctionInfo(function, node->num_parameters(),
node->function_token_position(),
node->start_position(), node->end_position(),
- node->is_expression(), false, script_);
+ node->is_expression(), false, script_,
+ node->inferred_name());
// Notify debugger that a new function has been added.
Debugger::OnNewFunction(function);
@@ -568,7 +571,7 @@ void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) {
void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) {
if (FLAG_debug_info) {
- int pos = fun->start_position();
+ int pos = fun->end_position();
if (pos != RelocInfo::kNoPosition) {
masm()->RecordStatementPosition(pos);
masm()->RecordPosition(pos);
diff --git a/v8/src/codegen.h b/v8/src/codegen.h
index dd43cc0..54fe330 100644
--- a/v8/src/codegen.h
+++ b/v8/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/v8/src/compiler.cc b/v8/src/compiler.cc
index ced094c..63fed4a 100644
--- a/v8/src/compiler.cc
+++ b/v8/src/compiler.cc
@@ -152,7 +152,8 @@ static Handle<JSFunction> MakeFunction(bool is_global,
CodeGenerator::SetFunctionInfo(fun, lit->scope()->num_parameters(),
RelocInfo::kNoPosition,
lit->start_position(), lit->end_position(),
- lit->is_expression(), true, script);
+ lit->is_expression(), true, script,
+ lit->inferred_name());
// Hint to the runtime system used when allocating space for initial
// property space by setting the expected number of properties for
@@ -316,20 +317,22 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
// name and line number. Check explicit whether logging is enabled as finding
// the line number is not for free.
if (Logger::is_enabled() || OProfileAgent::is_enabled()) {
+ Handle<String> func_name(lit->name()->length() > 0 ?
+ *lit->name() : shared->inferred_name());
if (script->name()->IsString()) {
int line_num = GetScriptLineNumber(script, start_position);
if (line_num > 0) {
line_num += script->line_offset()->value() + 1;
}
- LOG(CodeCreateEvent("LazyCompile", *code, *lit->name(),
+ LOG(CodeCreateEvent("LazyCompile", *code, *func_name,
String::cast(script->name()), line_num));
- OProfileAgent::CreateNativeCodeRegion(*lit->name(),
+ OProfileAgent::CreateNativeCodeRegion(*func_name,
String::cast(script->name()),
line_num, code->address(),
code->ExecutableSize());
} else {
- LOG(CodeCreateEvent("LazyCompile", *code, *lit->name()));
- OProfileAgent::CreateNativeCodeRegion(*lit->name(), code->address(),
+ LOG(CodeCreateEvent("LazyCompile", *code, *func_name));
+ OProfileAgent::CreateNativeCodeRegion(*func_name, code->address(),
code->ExecutableSize());
}
}
diff --git a/v8/src/constants-arm.h b/v8/src/constants-arm.h
index f553963..919a892 100644
--- a/v8/src/constants-arm.h
+++ b/v8/src/constants-arm.h
@@ -106,7 +106,12 @@ enum SoftwareInterruptCodes {
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/v8/src/d8-posix.cc b/v8/src/d8-posix.cc
index d7ea2ec..c2dc531 100644
--- a/v8/src/d8-posix.cc
+++ b/v8/src/d8-posix.cc
@@ -105,17 +105,17 @@ static int LengthWithoutIncompleteUtf8(char* buffer, int len) {
// Returns false on timeout, true on data ready.
static bool WaitOnFD(int fd,
int read_timeout,
- int* total_timeout,
+ int total_timeout,
struct timeval& start_time) {
fd_set readfds, writefds, exceptfds;
struct timeval timeout;
- if (*total_timeout != -1) {
+ int gone = 0;
+ if (total_timeout != -1) {
struct timeval time_now;
gettimeofday(&time_now, NULL);
int seconds = time_now.tv_sec - start_time.tv_sec;
- int gone = seconds * 1000 + (time_now.tv_usec - start_time.tv_usec) / 1000;
- if (gone >= *total_timeout) return false;
- *total_timeout -= gone;
+ gone = seconds * 1000 + (time_now.tv_usec - start_time.tv_usec) / 1000;
+ if (gone >= total_timeout) return false;
}
FD_ZERO(&readfds);
FD_ZERO(&writefds);
@@ -123,8 +123,8 @@ static bool WaitOnFD(int fd,
FD_SET(fd, &readfds);
FD_SET(fd, &exceptfds);
if (read_timeout == -1 ||
- (*total_timeout != -1 && *total_timeout < read_timeout)) {
- read_timeout = *total_timeout;
+ (total_timeout != -1 && total_timeout - gone < read_timeout)) {
+ read_timeout = total_timeout - gone;
}
timeout.tv_usec = (read_timeout % 1000) * 1000;
timeout.tv_sec = read_timeout / 1000;
@@ -306,7 +306,7 @@ static bool ChildLaunchedOK(int* exec_error_fds) {
static Handle<Value> GetStdout(int child_fd,
struct timeval& start_time,
int read_timeout,
- int* total_timeout) {
+ int total_timeout) {
Handle<String> accumulator = String::Empty();
const char* source = "function(a, b) { return a + b; }";
Handle<Value> cons_as_obj(Script::Compile(String::New(source))->Run());
@@ -332,7 +332,7 @@ static Handle<Value> GetStdout(int child_fd,
read_timeout,
total_timeout,
start_time) ||
- (TimeIsOut(start_time, *total_timeout))) {
+ (TimeIsOut(start_time, total_timeout))) {
return ThrowException(String::New("Timed out waiting for output"));
}
continue;
@@ -502,7 +502,7 @@ Handle<Value> Shell::System(const Arguments& args) {
Handle<Value> accumulator = GetStdout(stdout_fds[kReadFD],
start_time,
read_timeout,
- &total_timeout);
+ total_timeout);
if (accumulator->IsUndefined()) {
kill(pid, SIGINT); // On timeout, kill the subprocess.
return accumulator;
diff --git a/v8/src/d8.cc b/v8/src/d8.cc
index 934bcbd..9648168 100644
--- a/v8/src/d8.cc
+++ b/v8/src/d8.cc
@@ -268,12 +268,19 @@ Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
}
-int32_t* Counter::Bind(const char* name) {
+int32_t* Counter::Bind(const char* name, bool is_histogram) {
int i;
for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
name_[i] = static_cast<char>(name[i]);
name_[i] = '\0';
- return &counter_;
+ is_histogram_ = is_histogram;
+ return ptr();
+}
+
+
+void Counter::AddSample(int32_t sample) {
+ count_++;
+ sample_total_ += sample;
}
@@ -302,6 +309,8 @@ void Shell::MapCounters(const char* name) {
}
counters_ = static_cast<CounterCollection*>(memory);
V8::SetCounterFunction(LookupCounter);
+ V8::SetCreateHistogramFunction(CreateHistogram);
+ V8::SetAddHistogramSampleFunction(AddHistogramSample);
}
@@ -316,15 +325,44 @@ int CounterMap::Hash(const char* name) {
}
-int* Shell::LookupCounter(const char* name) {
+Counter* Shell::GetCounter(const char* name, bool is_histogram) {
Counter* counter = counter_map_->Lookup(name);
+
+ if (counter == NULL) {
+ counter = counters_->GetNextCounter();
+ if (counter != NULL) {
+ counter_map_->Set(name, counter);
+ counter->Bind(name, is_histogram);
+ }
+ } else {
+ ASSERT(counter->is_histogram() == is_histogram);
+ }
+ return counter;
+}
+
+
+int* Shell::LookupCounter(const char* name) {
+ Counter* counter = GetCounter(name, false);
+
if (counter != NULL) {
return counter->ptr();
+ } else {
+ return NULL;
}
- Counter* result = counters_->GetNextCounter();
- if (result == NULL) return NULL;
- counter_map_->Set(name, result);
- return result->Bind(name);
+}
+
+
+void* Shell::CreateHistogram(const char* name,
+ int min,
+ int max,
+ size_t buckets) {
+ return GetCounter(name, true);
+}
+
+
+void Shell::AddHistogramSample(void* histogram, int sample) {
+ Counter* counter = reinterpret_cast<Counter*>(histogram);
+ counter->AddSample(sample);
}
@@ -333,8 +371,12 @@ void Shell::Initialize() {
// Set up counters
if (i::FLAG_map_counters != NULL)
MapCounters(i::FLAG_map_counters);
- if (i::FLAG_dump_counters)
+ if (i::FLAG_dump_counters) {
V8::SetCounterFunction(LookupCounter);
+ V8::SetCreateHistogramFunction(CreateHistogram);
+ V8::SetAddHistogramSampleFunction(AddHistogramSample);
+ }
+
// Initialize the global objects
HandleScope scope;
Handle<ObjectTemplate> global_template = ObjectTemplate::New();
@@ -406,7 +448,14 @@ void Shell::OnExit() {
::printf("+----------------------------------------+-------------+\n");
for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
Counter* counter = i.CurrentValue();
- ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->value());
+ if (counter->is_histogram()) {
+ ::printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
+ ::printf("| t:%-36s | %11i |\n",
+ i.CurrentKey(),
+ counter->sample_total());
+ } else {
+ ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
+ }
}
::printf("+----------------------------------------+-------------+\n");
}
diff --git a/v8/src/d8.h b/v8/src/d8.h
index 54ae612..342a0d2 100644
--- a/v8/src/d8.h
+++ b/v8/src/d8.h
@@ -42,11 +42,16 @@ namespace i = v8::internal;
class Counter {
public:
static const int kMaxNameSize = 64;
- int32_t* Bind(const char* name);
- int32_t* ptr() { return &counter_; }
- int32_t value() { return counter_; }
+ int32_t* Bind(const char* name, bool histogram);
+ int32_t* ptr() { return &count_; }
+ int32_t count() { return count_; }
+ int32_t sample_total() { return sample_total_; }
+ bool is_histogram() { return is_histogram_; }
+ void AddSample(int32_t sample);
private:
- int32_t counter_;
+ int32_t count_;
+ int32_t sample_total_;
+ bool is_histogram_;
uint8_t name_[kMaxNameSize];
};
@@ -116,6 +121,11 @@ class Shell: public i::AllStatic {
static void Initialize();
static void OnExit();
static int* LookupCounter(const char* name);
+ static void* CreateHistogram(const char* name,
+ int min,
+ int max,
+ size_t buckets);
+ static void AddHistogramSample(void* histogram, int sample);
static void MapCounters(const char* name);
static Handle<String> ReadFile(const char* name);
static void RunShell();
@@ -179,6 +189,7 @@ class Shell: public i::AllStatic {
static CounterCollection local_counters_;
static CounterCollection* counters_;
static i::OS::MemoryMappedFile* counters_file_;
+ static Counter* GetCounter(const char* name, bool is_histogram);
};
diff --git a/v8/src/debug-arm.cc b/v8/src/debug-arm.cc
index 9fb77b7..f935a8f 100644
--- a/v8/src/debug-arm.cc
+++ b/v8/src/debug-arm.cc
@@ -58,7 +58,7 @@ bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
}
-#define __ masm->
+#define __ DEFINE_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
diff --git a/v8/src/debug-delay.js b/v8/src/debug-delay.js
index 9944fb3..10d0614 100644
--- a/v8/src/debug-delay.js
+++ b/v8/src/debug-delay.js
@@ -1547,20 +1547,24 @@ DebugCommandProcessor.prototype.lookupRequest_ = function(request, response) {
}
// 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;
};
diff --git a/v8/src/debug.cc b/v8/src/debug.cc
index 4901f5f..a4bb04d 100644
--- a/v8/src/debug.cc
+++ b/v8/src/debug.cc
@@ -1160,7 +1160,31 @@ void Debug::HandleStepIn(Handle<JSFunction> function,
if (fp == Debug::step_in_fp()) {
// Don't allow step into functions in the native context.
if (function->context()->global() != Top::context()->builtins()) {
- Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
+ if (function->shared()->code() ==
+ Builtins::builtin(Builtins::FunctionApply) ||
+ function->shared()->code() ==
+ Builtins::builtin(Builtins::FunctionCall)) {
+ // Handle function.apply and function.call separately to flood the
+ // function to be called and not the code for Builtins::FunctionApply or
+ // Builtins::FunctionCall. At the point of the call IC to call either
+ // Builtins::FunctionApply or Builtins::FunctionCall the expression
+ // stack has the following content:
+ // symbol "apply" or "call"
+ // function apply or call was called on
+ // receiver for apply or call (first parameter to apply or call)
+ // ... further arguments to apply or call.
+ JavaScriptFrameIterator it;
+ ASSERT(it.frame()->fp() == fp);
+ ASSERT(it.frame()->GetExpression(1)->IsJSFunction());
+ if (it.frame()->GetExpression(1)->IsJSFunction()) {
+ Handle<JSFunction>
+ actual_function(JSFunction::cast(it.frame()->GetExpression(1)));
+ Handle<SharedFunctionInfo> actual_shared(actual_function->shared());
+ Debug::FloodWithOneShot(actual_shared);
+ }
+ } else {
+ Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
+ }
}
}
}
@@ -1801,6 +1825,9 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
Debugger::host_dispatch_handler_(reinterpret_cast<void*>(dispatch),
Debugger::host_dispatch_handler_data_);
}
+ if (auto_continue && !HasCommands()) {
+ return;
+ }
continue;
}
@@ -2006,6 +2033,8 @@ void Debugger::ProcessCommand(Vector<const uint16_t> command) {
Logger::DebugTag("Put command on command_queue.");
command_queue_.Put(command_copy);
command_received_->Signal();
+
+ // Set the debug command break flag to have the command processed.
if (!Debug::InDebugger()) {
StackGuard::DebugCommand();
}
@@ -2018,7 +2047,7 @@ bool Debugger::HasCommands() {
void Debugger::ProcessHostDispatch(void* dispatch) {
-// Puts a host dispatch comming from the public API on the queue.
+ // 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;
@@ -2026,6 +2055,11 @@ void Debugger::ProcessHostDispatch(void* dispatch) {
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();
+ }
}
diff --git a/v8/src/disasm-arm.cc b/v8/src/disasm-arm.cc
index d19e042..3b7474d 100644
--- a/v8/src/disasm-arm.cc
+++ b/v8/src/disasm-arm.cc
@@ -261,6 +261,15 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) {
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/v8/src/frames-arm.cc b/v8/src/frames-arm.cc
index fe850a8..121fb75 100644
--- a/v8/src/frames-arm.cc
+++ b/v8/src/frames-arm.cc
@@ -80,7 +80,7 @@ int JavaScriptFrame::GetProvidedParametersCount() const {
Address JavaScriptFrame::GetCallerStackPointer() const {
int arguments;
- if (Heap::gc_state() != Heap::NOT_IN_GC) {
+ if (Heap::gc_state() != Heap::NOT_IN_GC || disable_heap_access_) {
// The arguments for cooked frames are traversed as if they were
// expression stack elements of the calling frame. The reason for
// this rather strange decision is that we cannot access the
diff --git a/v8/src/frames-ia32.cc b/v8/src/frames-ia32.cc
index 2b24777..1bc62ec 100644
--- a/v8/src/frames-ia32.cc
+++ b/v8/src/frames-ia32.cc
@@ -78,7 +78,7 @@ int JavaScriptFrame::GetProvidedParametersCount() const {
Address JavaScriptFrame::GetCallerStackPointer() const {
int arguments;
- if (Heap::gc_state() != Heap::NOT_IN_GC) {
+ if (Heap::gc_state() != Heap::NOT_IN_GC || disable_heap_access_) {
// The arguments for cooked frames are traversed as if they were
// expression stack elements of the calling frame. The reason for
// this rather strange decision is that we cannot access the
diff --git a/v8/src/frames-inl.h b/v8/src/frames-inl.h
index 07c8e4e..cb03e2f 100644
--- a/v8/src/frames-inl.h
+++ b/v8/src/frames-inl.h
@@ -169,19 +169,6 @@ inline bool JavaScriptFrame::has_adapted_arguments() const {
}
-inline bool JavaScriptFrame::is_at_function() const {
- Object* result = function_slot_object();
- // Verify that frame points at correct JS function object.
- // We are verifying that function object address and
- // the underlying map object address are valid, and that
- // function is really a function.
- return Heap::Contains(reinterpret_cast<Address>(result)) &&
- result->IsHeapObject() &&
- Heap::Contains(HeapObject::cast(result)->map()) &&
- result->IsJSFunction();
-}
-
-
inline Object* JavaScriptFrame::function() const {
Object* result = function_slot_object();
ASSERT(result->IsJSFunction());
diff --git a/v8/src/frames.cc b/v8/src/frames.cc
index a7da25a..88c723d 100644
--- a/v8/src/frames.cc
+++ b/v8/src/frames.cc
@@ -86,6 +86,7 @@ StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp)
if (use_top || fp != NULL) {
Reset();
}
+ JavaScriptFrame_.DisableHeapAccess();
}
#undef INITIALIZE_SINGLETON
@@ -208,7 +209,9 @@ void SafeStackFrameIterator::Advance() {
StackFrame* last_frame = iterator_.frame();
Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
// Before advancing to the next stack frame, perform pointer validity tests
- iteration_done_ = !IsValidFrame(last_frame) || !IsValidCaller(last_frame);
+ iteration_done_ = !IsValidFrame(last_frame) ||
+ !CanIterateHandles(last_frame, iterator_.handler()) ||
+ !IsValidCaller(last_frame);
if (iteration_done_) return;
iterator_.Advance();
@@ -219,12 +222,17 @@ void SafeStackFrameIterator::Advance() {
}
+bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
+ StackHandler* handler) {
+ // If StackIterator iterates over StackHandles, verify that
+ // StackHandlerIterator can be instantiated (see StackHandlerIterator
+ // constructor.)
+ return !is_valid_top_ || (frame->sp() <= handler->address());
+}
+
+
bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
- return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp()) &&
- // JavaScriptFrame uses function shared info to advance, hence it must
- // point to a valid function object.
- (!frame->is_java_script() ||
- reinterpret_cast<JavaScriptFrame*>(frame)->is_at_function());
+ return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
}
@@ -270,7 +278,7 @@ void SafeStackFrameIterator::Reset() {
SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
Address fp, Address sp, Address low_bound, Address high_bound) :
SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) {
- if (!done() && !frame()->is_at_function()) Advance();
+ if (!done() && !frame()->is_java_script()) Advance();
}
@@ -278,7 +286,7 @@ void SafeStackTraceFrameIterator::Advance() {
while (true) {
SafeJavaScriptFrameIterator::Advance();
if (done()) return;
- if (frame()->is_at_function()) return;
+ if (frame()->is_java_script()) return;
}
}
#endif
diff --git a/v8/src/frames.h b/v8/src/frames.h
index 78d8e72..8ab4be9 100644
--- a/v8/src/frames.h
+++ b/v8/src/frames.h
@@ -373,7 +373,6 @@ class JavaScriptFrame: public StandardFrame {
virtual Type type() const { return JAVA_SCRIPT; }
// Accessors.
- inline bool is_at_function() const;
inline Object* function() const;
inline Object* receiver() const;
inline void set_receiver(Object* value);
@@ -414,11 +413,19 @@ class JavaScriptFrame: public StandardFrame {
protected:
explicit JavaScriptFrame(StackFrameIterator* iterator)
- : StandardFrame(iterator) { }
+ : StandardFrame(iterator), disable_heap_access_(false) { }
virtual Address GetCallerStackPointer() const;
+ // When this mode is enabled it is not allowed to access heap objects.
+ // This is a special mode used when gathering stack samples in profiler.
+ // A shortcoming is that caller's SP value will be calculated incorrectly
+ // (see GetCallerStackPointer implementation), but it is not used for stack
+ // sampling.
+ void DisableHeapAccess() { disable_heap_access_ = true; }
+
private:
+ bool disable_heap_access_;
inline Object* function_slot_object() const;
friend class StackFrameIterator;
@@ -638,6 +645,7 @@ class SafeStackFrameIterator BASE_EMBEDDED {
bool IsValidStackAddress(Address addr) const {
return IsWithinBounds(low_bound_, high_bound_, addr);
}
+ bool CanIterateHandles(StackFrame* frame, StackHandler* handler);
bool IsValidFrame(StackFrame* frame) const;
bool IsValidCaller(StackFrame* frame);
diff --git a/v8/src/func-name-inferrer.cc b/v8/src/func-name-inferrer.cc
new file mode 100644
index 0000000..75f7a99
--- /dev/null
+++ b/v8/src/func-name-inferrer.cc
@@ -0,0 +1,75 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ast.h"
+#include "func-name-inferrer.h"
+
+namespace v8 { namespace internal {
+
+
+void FuncNameInferrer::PushEnclosingName(Handle<String> name) {
+ // Enclosing name is a name of a constructor function. To check
+ // that it is really a constructor, we check that it is not empty
+ // and starts with a capital letter.
+ if (name->length() > 0 && Runtime::IsUpperCaseChar(name->Get(0))) {
+ names_stack_.Add(name);
+ }
+}
+
+
+Handle<String> FuncNameInferrer::MakeNameFromStack() {
+ if (names_stack_.is_empty()) {
+ return Factory::empty_string();
+ } else {
+ return MakeNameFromStackHelper(1, names_stack_.at(0));
+ }
+}
+
+
+Handle<String> FuncNameInferrer::MakeNameFromStackHelper(int pos,
+ Handle<String> prev) {
+ if (pos >= names_stack_.length()) {
+ return prev;
+ } else {
+ Handle<String> curr = Factory::NewConsString(dot_, names_stack_.at(pos));
+ return MakeNameFromStackHelper(pos + 1, Factory::NewConsString(prev, curr));
+ }
+}
+
+
+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);
+}
+
+
+} } // namespace v8::internal
diff --git a/v8/src/func-name-inferrer.h b/v8/src/func-name-inferrer.h
new file mode 100644
index 0000000..d8270c3
--- /dev/null
+++ b/v8/src/func-name-inferrer.h
@@ -0,0 +1,122 @@
+// Copyright 2006-2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_FUNC_NAME_INFERRER_H_
+#define V8_FUNC_NAME_INFERRER_H_
+
+namespace v8 { namespace internal {
+
+// FuncNameInferrer is a stateful class that is used to perform name
+// inference for anonymous functions during static analysis of source code.
+// Inference is performed in cases when an anonymous function is assigned
+// to a variable or a property (see test-func-name-inference.cc for examples.)
+
+// The basic idea is that during AST traversal LHSs of expressions are
+// always visited before RHSs. Thus, during visiting the LHS, a name can be
+// collected, and during visiting the RHS, a function literal can be collected.
+// Inference is performed while leaving the assignment node.
+
+class FuncNameInferrer BASE_EMBEDDED {
+ public:
+ FuncNameInferrer() :
+ entries_stack_(10),
+ names_stack_(5),
+ funcs_to_infer_(4),
+ dot_(Factory::NewStringFromAscii(CStrVector("."))) {
+ }
+
+ bool IsOpen() const { return !entries_stack_.is_empty(); }
+
+ void PushEnclosingName(Handle<String> name);
+
+ void Enter() {
+ entries_stack_.Add(names_stack_.length());
+ }
+
+ void PushName(Handle<String> name) {
+ if (IsOpen()) {
+ names_stack_.Add(name);
+ }
+ }
+
+ void AddFunction(FunctionLiteral* func_to_infer) {
+ if (IsOpen()) {
+ funcs_to_infer_.Add(func_to_infer);
+ }
+ }
+
+ void InferAndLeave() {
+ ASSERT(IsOpen());
+ 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 InferFunctionsNames();
+
+ List<int> entries_stack_;
+ List<Handle<String> > names_stack_;
+ List<FunctionLiteral*> funcs_to_infer_;
+ Handle<String> dot_;
+
+ DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer);
+};
+
+
+// A wrapper class that automatically calls InferAndLeave when
+// leaving scope.
+class ScopedFuncNameInferrer BASE_EMBEDDED {
+ public:
+ explicit ScopedFuncNameInferrer(FuncNameInferrer* inferrer) :
+ inferrer_(inferrer),
+ is_entered_(false) {}
+ ~ScopedFuncNameInferrer() {
+ if (is_entered_) {
+ inferrer_->InferAndLeave();
+ }
+ }
+
+ void Enter() {
+ inferrer_->Enter();
+ is_entered_ = true;
+ }
+
+ private:
+ FuncNameInferrer* inferrer_;
+ bool is_entered_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFuncNameInferrer);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_FUNC_NAME_INFERRER_H_
diff --git a/v8/src/globals.h b/v8/src/globals.h
index 1579c3d..09af766 100644
--- a/v8/src/globals.h
+++ b/v8/src/globals.h
@@ -146,7 +146,6 @@ class Assembler;
class BreakableStatement;
class Code;
class CodeGenerator;
-class CodeRegion;
class CodeStub;
class Context;
class Debug;
@@ -514,6 +513,16 @@ inline Dest bit_cast(const Source& source) {
}
+#ifdef ARM_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 DEFINE_MASM(masm) masm->stop(__FILE_LINE__); masm->
+#else
+#define DEFINE_MASM(masm) masm->
+#endif
+
+
} } // namespace v8::internal
#endif // V8_GLOBALS_H_
diff --git a/v8/src/handles.cc b/v8/src/handles.cc
index 60d8236..a834564 100644
--- a/v8/src/handles.cc
+++ b/v8/src/handles.cc
@@ -212,10 +212,11 @@ Handle<Object> SetProperty(Handle<Object> object,
}
-Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object,
- Handle<String> key,
- Handle<Object> value,
- PropertyAttributes attributes) {
+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 +492,6 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object) {
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 +505,17 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object) {
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 +550,7 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object) {
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();
diff --git a/v8/src/heap.cc b/v8/src/heap.cc
index 26be5a4..7a8b728 100644
--- a/v8/src/heap.cc
+++ b/v8/src/heap.cc
@@ -374,9 +374,37 @@ void Heap::PerformScavenge() {
}
+#ifdef DEBUG
+// Helper class for verifying the symbol table.
+class SymbolTableVerifier : public ObjectVisitor {
+ public:
+ SymbolTableVerifier() { }
+ void VisitPointers(Object** start, Object** end) {
+ // Visit all HeapObject pointers in [start, end).
+ for (Object** p = start; p < end; p++) {
+ if ((*p)->IsHeapObject()) {
+ // Check that the symbol is actually a symbol.
+ ASSERT((*p)->IsNull() || (*p)->IsUndefined() || (*p)->IsSymbol());
+ }
+ }
+ }
+};
+#endif // DEBUG
+
+
+static void VerifySymbolTable() {
+#ifdef DEBUG
+ SymbolTableVerifier verifier;
+ SymbolTable* symbol_table = SymbolTable::cast(Heap::symbol_table());
+ symbol_table->IterateElements(&verifier);
+#endif // DEBUG
+}
+
+
void Heap::PerformGarbageCollection(AllocationSpace space,
GarbageCollector collector,
GCTracer* tracer) {
+ VerifySymbolTable();
if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
ASSERT(!allocation_allowed_);
global_gc_prologue_callback_();
@@ -421,6 +449,7 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
ASSERT(!allocation_allowed_);
global_gc_epilogue_callback_();
}
+ VerifySymbolTable();
}
@@ -813,12 +842,12 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
static inline bool IsShortcutCandidate(HeapObject* object, Map* map) {
- // A ConsString object with Heap::empty_string() as the right side
- // is a candidate for being shortcut by the scavenger.
+ STATIC_ASSERT(kNotStringTag != 0 && kSymbolTag != 0);
ASSERT(object->map() == map);
- if (map->instance_type() >= FIRST_NONSTRING_TYPE) return false;
- return (StringShape(map).representation_tag() == kConsStringTag) &&
- (ConsString::cast(object)->unchecked_second() == Heap::empty_string());
+ InstanceType type = map->instance_type();
+ if ((type & kShortcutTypeMask) != kShortcutTypeTag) return false;
+ ASSERT(object->IsString() && !object->IsSymbol());
+ return ConsString::cast(object)->unchecked_second() == Heap::empty_string();
}
@@ -1384,6 +1413,7 @@ Object* Heap::AllocateSharedFunctionInfo(Object* name) {
share->set_script(undefined_value());
share->set_start_position_and_type(0);
share->set_debug_info(undefined_value());
+ share->set_inferred_name(empty_string());
return result;
}
diff --git a/v8/src/ic-arm.cc b/v8/src/ic-arm.cc
index 4db3980..d407f85 100644
--- a/v8/src/ic-arm.cc
+++ b/v8/src/ic-arm.cc
@@ -39,7 +39,7 @@ namespace v8 { namespace internal {
// Static IC stub generators.
//
-#define __ masm->
+#define __ DEFINE_MASM(masm)
// Helper function used from LoadIC/CallIC GenerateNormal.
@@ -96,7 +96,9 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
// 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.
diff --git a/v8/src/log.cc b/v8/src/log.cc
index d9e304d..f23b73b 100644
--- a/v8/src/log.cc
+++ b/v8/src/log.cc
@@ -814,35 +814,6 @@ void Logger::CodeDeleteEvent(Address from) {
}
-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/v8/src/log.h b/v8/src/log.h
index bbcfa42..44c1957 100644
--- a/v8/src/log.h
+++ b/v8/src/log.h
@@ -174,11 +174,6 @@ class Logger {
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/v8/src/macro-assembler-arm.cc b/v8/src/macro-assembler-arm.cc
index 88a300b..ef2ffab 100644
--- a/v8/src/macro-assembler-arm.cc
+++ b/v8/src/macro-assembler-arm.cc
@@ -168,11 +168,11 @@ void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
}
-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
}
diff --git a/v8/src/macro-assembler-arm.h b/v8/src/macro-assembler-arm.h
index 4b999fd..60ef77a 100644
--- a/v8/src/macro-assembler-arm.h
+++ b/v8/src/macro-assembler-arm.h
@@ -86,7 +86,7 @@ class MacroAssembler: public Assembler {
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);
diff --git a/v8/src/mark-compact.cc b/v8/src/mark-compact.cc
index b369cac..c55345d 100644
--- a/v8/src/mark-compact.cc
+++ b/v8/src/mark-compact.cc
@@ -220,13 +220,7 @@ static inline HeapObject* ShortCircuitConsString(Object** p) {
MapWord map_word = object->map_word();
map_word.ClearMark();
InstanceType type = map_word.ToMap()->instance_type();
- if (type >= FIRST_NONSTRING_TYPE || (type & kIsSymbolMask) != 0) {
- return object;
- }
-
- StringRepresentationTag rep =
- static_cast<StringRepresentationTag>(type & kStringRepresentationMask);
- if (rep != kConsStringTag) return object;
+ if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object;
Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second();
if (reinterpret_cast<String*>(second) != Heap::empty_string()) return object;
@@ -410,15 +404,19 @@ class SymbolTableCleaner : public ObjectVisitor {
ExternalString::kResourceOffset -
kHeapObjectTag;
if (is_two_byte) {
- v8::String::ExternalStringResource* resource =
- *reinterpret_cast<v8::String::ExternalStringResource**>
+ v8::String::ExternalStringResource** resource =
+ reinterpret_cast<v8::String::ExternalStringResource**>
(resource_addr);
- delete resource;
+ delete *resource;
+ // Clear the resource pointer in the symbol.
+ *resource = NULL;
} else {
- v8::String::ExternalAsciiStringResource* resource =
- *reinterpret_cast<v8::String::ExternalAsciiStringResource**>
+ v8::String::ExternalAsciiStringResource** resource =
+ reinterpret_cast<v8::String::ExternalAsciiStringResource**>
(resource_addr);
- delete resource;
+ delete *resource;
+ // Clear the resource pointer in the symbol.
+ *resource = NULL;
}
}
// Set the entry to null_value (as deleted).
diff --git a/v8/src/mirror-delay.js b/v8/src/mirror-delay.js
index 916bc27..9c9d713 100644
--- a/v8/src/mirror-delay.js
+++ b/v8/src/mirror-delay.js
@@ -1715,8 +1715,8 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
// Collect the JSON property/value pairs in an array.
var content = new Array();
- // Add the handle for value mirrors.
- if (mirror.isValue()) {
+ // Add the mirror handle.
+ if (mirror.isValue() || mirror.isScript()) {
content.push(MakeJSONPair_('handle', NumberToJSON_(mirror.handle())));
}
@@ -1771,10 +1771,11 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
break;
case SCRIPT_TYPE:
- // Script is represented by name and source attributes.
+ // Script is represented by id, name and source attributes.
if (mirror.name()) {
content.push(MakeJSONPair_('name', StringToJSON_(mirror.name())));
}
+ content.push(MakeJSONPair_('id', NumberToJSON_(mirror.id())));
content.push(MakeJSONPair_('lineOffset',
NumberToJSON_(mirror.lineOffset())));
content.push(MakeJSONPair_('columnOffset',
@@ -1908,7 +1909,12 @@ JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
content.push(MakeJSONPair_('index', NumberToJSON_(mirror.index())));
content.push(MakeJSONPair_('receiver',
this.serializeReference(mirror.receiver())));
- content.push(MakeJSONPair_('func', this.serializeReference(mirror.func())));
+ var func = mirror.func();
+ content.push(MakeJSONPair_('func', this.serializeReference(func)));
+ if (func.script()) {
+ content.push(MakeJSONPair_('script',
+ this.serializeReference(func.script())));
+ }
content.push(MakeJSONPair_('constructCall',
BooleanToJSON_(mirror.isConstructCall())));
content.push(MakeJSONPair_('debuggerFrame',
diff --git a/v8/src/mksnapshot.cc b/v8/src/mksnapshot.cc
index 40a9019..4891f37 100644
--- a/v8/src/mksnapshot.cc
+++ b/v8/src/mksnapshot.cc
@@ -25,8 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// To avoid warnings from <map> on windows we disable exceptions.
-#define _HAS_EXCEPTIONS 0
#include <signal.h>
#include <string>
#include <map>
diff --git a/v8/src/objects-inl.h b/v8/src/objects-inl.h
index 762bb63..c2143ea 100644
--- a/v8/src/objects-inl.h
+++ b/v8/src/objects-inl.h
@@ -263,8 +263,7 @@ bool StringShape::IsSequentialAscii() {
bool StringShape::IsSequentialTwoByte() {
- return (type_ & (kStringRepresentationMask | kStringEncodingMask)) ==
- (kSeqStringTag | kTwoByteStringTag);
+ return full_representation_tag() == (kSeqStringTag | kTwoByteStringTag);
}
@@ -274,8 +273,7 @@ bool StringShape::IsExternalAscii() {
bool StringShape::IsExternalTwoByte() {
- return (type_ & (kStringRepresentationMask | kStringEncodingMask)) ==
- (kExternalStringTag | kTwoByteStringTag);
+ return full_representation_tag() == (kExternalStringTag | kTwoByteStringTag);
}
@@ -2077,6 +2075,7 @@ ACCESSORS(SharedFunctionInfo, function_data, Object,
ACCESSORS(SharedFunctionInfo, lazy_load_data, Object, kLazyLoadDataOffset)
ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset)
ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset)
+ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, hidden_prototype,
kHiddenPrototypeBit)
diff --git a/v8/src/objects.cc b/v8/src/objects.cc
index 6806829..3273291 100644
--- a/v8/src/objects.cc
+++ b/v8/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;
@@ -679,7 +663,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
SmartPointer<uc16> smart_chars = this->ToWideCString();
ASSERT(memcmp(*smart_chars,
resource->data(),
- resource->length()*sizeof(**smart_chars)) == 0);
+ resource->length() * sizeof(**smart_chars)) == 0);
}
#endif // DEBUG
@@ -3301,6 +3285,13 @@ Vector<const uc16> String::ToUC16Vector() {
}
ASSERT(string_tag == kExternalStringTag);
ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
+ // This is a workaround for Chromium bug 9746: http://crbug.com/9746
+ // For external strings with a deleted resource we return a special
+ // Vector which will not compare to any string when doing SymbolTable
+ // lookups.
+ if (ext->resource() == NULL) {
+ return Vector<const uc16>(NULL, length);
+ }
const uc16* start =
reinterpret_cast<const uc16*>(ext->resource()->data());
return Vector<const uc16>(start + offset, length);
@@ -3602,7 +3593,7 @@ void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
while (chars_read < max_chars) {
uint16_t c = data[offset];
if (c <= kMaxAsciiCharCode) {
- // Fast case for ASCII characters. Cursor is an input output argument.
+ // Fast case for ASCII characters. Cursor is an input output argument.
if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
rbb->util_buffer,
rbb->capacity,
@@ -4117,6 +4108,18 @@ static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
}
+// This is a workaround for Chromium bug 9746: http://crbug.com/9746
+// Returns true if this Vector matches the problem exposed in the bug.
+template <typename T>
+static bool CheckVectorForBug9746(Vector<T> vec) {
+ // The problem is that somehow external string entries in the symbol
+ // table can have their resources collected while they are still in the
+ // table. This should not happen according to the test in the function
+ // DisposeExternalString in api.cc, but we have evidence that it does.
+ return (vec.start() == NULL) ? true : false;
+}
+
+
static StringInputBuffer string_compare_buffer_b;
@@ -4127,7 +4130,9 @@ static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
VectorIterator<char> ib(b->ToAsciiVector());
return CompareStringContents(ia, &ib);
} else {
- VectorIterator<uc16> ib(b->ToUC16Vector());
+ Vector<const uc16> vb = b->ToUC16Vector();
+ if (CheckVectorForBug9746(vb)) return false;
+ VectorIterator<uc16> ib(vb);
return CompareStringContents(ia, &ib);
}
} else {
@@ -4169,7 +4174,9 @@ bool String::SlowEquals(String* other) {
return CompareRawStringContents(vec1, vec2);
} else {
VectorIterator<char> buf1(vec1);
- VectorIterator<uc16> ib(other->ToUC16Vector());
+ Vector<const uc16> vec2 = other->ToUC16Vector();
+ if (CheckVectorForBug9746(vec2)) return false;
+ VectorIterator<uc16> ib(vec2);
return CompareStringContents(&buf1, &ib);
}
} else {
@@ -4179,13 +4186,15 @@ bool String::SlowEquals(String* other) {
}
} else {
Vector<const uc16> vec1 = this->ToUC16Vector();
+ if (CheckVectorForBug9746(vec1)) return false;
if (other->IsFlat()) {
if (StringShape(other).IsAsciiRepresentation()) {
VectorIterator<uc16> buf1(vec1);
VectorIterator<char> ib(other->ToAsciiVector());
return CompareStringContents(&buf1, &ib);
} else {
- Vector<const uc16> vec2(other->ToUC16Vector());
+ Vector<const uc16> vec2 = other->ToUC16Vector();
+ if (CheckVectorForBug9746(vec2)) return false;
return CompareRawStringContents(vec1, vec2);
}
} else {
@@ -4230,6 +4239,18 @@ bool String::MarkAsUndetectable() {
bool String::IsEqualTo(Vector<const char> str) {
+ // This is a workaround for Chromium bug 9746: http://crbug.com/9746
+ // The problem is that somehow external string entries in the symbol
+ // table can have their resources deleted while they are still in the
+ // table. This should not happen according to the test in the function
+ // DisposeExternalString in api.cc but we have evidence that it does.
+ // Thus we add this bailout here.
+ StringShape shape(this);
+ if (shape.IsExternalTwoByte()) {
+ ExternalTwoByteString* ext = ExternalTwoByteString::cast(this);
+ if (ext->resource() == NULL) return false;
+ }
+
int slen = length();
Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
decoder->Reset(str.start(), str.length());
@@ -4604,7 +4625,7 @@ void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
IteratePointers(v, kNameOffset, kCodeOffset + kPointerSize);
IteratePointers(v, kInstanceClassNameOffset, kScriptOffset + kPointerSize);
- IteratePointer(v, kDebugInfoOffset);
+ IteratePointers(v, kDebugInfoOffset, kInferredNameOffset + kPointerSize);
}
@@ -5100,7 +5121,7 @@ bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
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);
}
@@ -5827,43 +5848,46 @@ int JSObject::NumberOfEnumProperties() {
}
-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;
}
@@ -5874,25 +5898,22 @@ void HeapSortPairs(FixedArray* content, FixedArray* smis) {
// 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;
}
}
@@ -5900,43 +5921,41 @@ void HeapSortPairs(FixedArray* content, FixedArray* smis) {
}
-// 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;
}
}
@@ -6267,7 +6286,7 @@ class SymbolKey : public HashTableKey {
if (StringShape(string_).IsCons()) {
ConsString* cons_string = ConsString::cast(string_);
cons_string->TryFlatten();
- if (cons_string->second() == Heap::empty_string()) {
+ if (cons_string->second()->length() == 0) {
string_ = cons_string->first();
}
}
@@ -6275,6 +6294,7 @@ class SymbolKey : public HashTableKey {
Map* map = Heap::SymbolMapForString(string_);
if (map != NULL) {
string_->set_map(map);
+ ASSERT(string_->IsSymbol());
return string_;
}
// Otherwise allocate a new symbol.
@@ -6723,7 +6743,7 @@ Object* Dictionary::GenerateNewEnumerationIndices() {
}
// 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++) {
@@ -6975,6 +6995,7 @@ void Dictionary::CopyKeysTo(FixedArray* storage, PropertyAttributes filter) {
if ((attr & filter) == 0) storage->set(index++, k);
}
}
+ storage->SortPairs(storage, index);
ASSERT(storage->length() >= index);
}
@@ -6996,7 +7017,7 @@ void Dictionary::CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array) {
}
}
}
- storage->SortPairs(sort_array);
+ storage->SortPairs(sort_array, sort_array->length());
ASSERT(storage->length() >= index);
}
diff --git a/v8/src/objects.h b/v8/src/objects.h
index 63480eb..b12875e 100644
--- a/v8/src/objects.h
+++ b/v8/src/objects.h
@@ -441,6 +441,19 @@ enum StringRepresentationTag {
kExternalStringTag = 0x3
};
+
+// A ConsString with an empty string as the right side is a candidate
+// for being shortcut by the garbage collector unless it is a
+// symbol. It's not common to have non-flat symbols, so we do not
+// shortcut them thereby avoiding turning symbols into strings. See
+// heap.cc and mark-compact.cc.
+const uint32_t kShortcutTypeMask =
+ kIsNotStringMask |
+ kIsSymbolMask |
+ kStringRepresentationMask;
+const uint32_t kShortcutTypeTag = kConsStringTag;
+
+
enum InstanceType {
SHORT_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSeqStringTag,
MEDIUM_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSeqStringTag,
@@ -1572,11 +1585,15 @@ class FixedArray: public Array {
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.
@@ -2665,6 +2682,13 @@ class SharedFunctionInfo: public HeapObject {
// [debug info]: Debug information.
DECL_ACCESSORS(debug_info, Object)
+ // [inferred name]: Name inferred from variable or property
+ // assignment of this function. Used to facilitate debugging and
+ // profiling of JavaScript code written in OO style, where almost
+ // all functions are anonymous but are assigned to object
+ // properties.
+ DECL_ACCESSORS(inferred_name, String)
+
// Position of the 'function' token in the script source.
inline int function_token_position();
inline void set_function_token_position(int function_token_position);
@@ -2724,7 +2748,8 @@ class SharedFunctionInfo: public HeapObject {
static const int kEndPositionOffset = kStartPositionAndTypeOffset + kIntSize;
static const int kFunctionTokenPositionOffset = kEndPositionOffset + kIntSize;
static const int kDebugInfoOffset = kFunctionTokenPositionOffset + kIntSize;
- static const int kSize = kDebugInfoOffset + kPointerSize;
+ static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize;
+ static const int kSize = kInferredNameOffset + kPointerSize;
private:
// Bit positions in length_and_flg.
diff --git a/v8/src/parser.cc b/v8/src/parser.cc
index fc0ca4d..9db10cf 100644
--- a/v8/src/parser.cc
+++ b/v8/src/parser.cc
@@ -2092,7 +2092,7 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
// code. If 'with' statements were allowed, the simplified setup of
// the runtime context chain would allow access to properties in the
// global object from within a 'with' statement.
- ASSERT(!Bootstrapper::IsActive());
+ ASSERT(extension_ != NULL || !Bootstrapper::IsActive());
Expect(Token::WITH, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
@@ -2761,7 +2761,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
if (var == NULL) {
// We do not allow direct calls to 'eval' in our internal
// JS files. Use builtin functions instead.
- ASSERT(!Bootstrapper::IsActive());
+ ASSERT(extension_ != NULL || !Bootstrapper::IsActive());
top_scope_->RecordEvalCall();
is_potentially_direct_eval = true;
}
diff --git a/v8/src/platform-freebsd.cc b/v8/src/platform-freebsd.cc
index 9209990..1e71704 100644
--- a/v8/src/platform-freebsd.cc
+++ b/v8/src/platform-freebsd.cc
@@ -262,7 +262,8 @@ void OS::LogSharedLibraryAddresses() {
}
-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 @@ void FreeBSDSemaphore::Wait() {
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(&current_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(&current_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/v8/src/platform-linux.cc b/v8/src/platform-linux.cc
index 5bbc895..9f5b9ac 100644
--- a/v8/src/platform-linux.cc
+++ b/v8/src/platform-linux.cc
@@ -262,9 +262,10 @@ void OS::LogSharedLibraryAddresses() {
}
-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 @@ void LinuxSemaphore::Wait() {
}
+#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(&current_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(&current_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);
@@ -552,9 +559,34 @@ Semaphore* OS::CreateSemaphore(int count) {
static Sampler* active_sampler_ = NULL;
+
+#if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
+// Android runs a fairly new Linux kernel, so signal info is there,
+// but the C library doesn't have the structs defined.
+
+struct sigcontext {
+ uint32_t trap_no;
+ uint32_t error_code;
+ uint32_t oldmask;
+ uint32_t gregs[16];
+ uint32_t arm_cpsr;
+ uint32_t fault_address;
+};
+typedef uint32_t __sigset_t;
+typedef struct sigcontext mcontext_t;
+typedef struct ucontext {
+ uint32_t uc_flags;
+ struct ucontext *uc_link;
+ stack_t uc_stack;
+ mcontext_t uc_mcontext;
+ __sigset_t uc_sigmask;
+} ucontext_t;
+enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11};
+
+#endif
+
+
static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
- // Ucontext is a glibc extension - no profiling on Android at the moment.
-#ifdef __GLIBC__
USE(info);
if (signal != SIGPROF) return;
if (active_sampler_ == NULL) return;
@@ -581,7 +613,6 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
sample.state = Logger::state();
active_sampler_->Tick(&sample);
-#endif
}
diff --git a/v8/src/platform-macos.cc b/v8/src/platform-macos.cc
index b13122f..7951543 100644
--- a/v8/src/platform-macos.cc
+++ b/v8/src/platform-macos.cc
@@ -212,10 +212,11 @@ int OS::ActivationFrameAlignment() {
}
-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/v8/src/platform-nullos.cc b/v8/src/platform-nullos.cc
index 3a50b9d..42583f1 100644
--- a/v8/src/platform-nullos.cc
+++ b/v8/src/platform-nullos.cc
@@ -215,7 +215,7 @@ void OS::LogSharedLibraryAddresses() {
}
-int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+int OS::StackWalk(Vector<OS::StackFrame> frames) {
UNIMPLEMENTED();
return 0;
}
diff --git a/v8/src/platform-win32.cc b/v8/src/platform-win32.cc
index 7177870..597a217 100644
--- a/v8/src/platform-win32.cc
+++ b/v8/src/platform-win32.cc
@@ -1161,7 +1161,7 @@ void OS::LogSharedLibraryAddresses() {
// 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 OS::StackWalk(OS::StackFrame* frames, int frames_size) {
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 @@ int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
#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/v8/src/platform.h b/v8/src/platform.h
index db4f2fd..b70095b 100644
--- a/v8/src/platform.h
+++ b/v8/src/platform.h
@@ -207,7 +207,7 @@ class OS {
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/v8/src/prettyprinter.cc b/v8/src/prettyprinter.cc
index 7f8c567..b58000a 100644
--- a/v8/src/prettyprinter.cc
+++ b/v8/src/prettyprinter.cc
@@ -646,7 +646,7 @@ AstPrinter::~AstPrinter() {
void AstPrinter::PrintIndented(const char* txt) {
for (int i = 0; i < indent_; i++) {
- Print(". ");
+ Print(". ");
}
Print(txt);
}
@@ -709,6 +709,7 @@ const char* AstPrinter::PrintProgram(FunctionLiteral* program) {
Init();
{ IndentedScope indent("FUNC");
PrintLiteralIndented("NAME", program->name(), true);
+ PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true);
PrintParameters(program->scope());
PrintDeclarations(program->scope()->declarations());
PrintStatements(program->body());
@@ -731,7 +732,7 @@ void AstPrinter::PrintParameters(Scope* scope) {
if (scope->num_parameters() > 0) {
IndentedScope indent("PARAMS");
for (int i = 0; i < scope->num_parameters(); i++) {
- PrintLiteralWithModeIndented("VAR ", scope->parameter(i),
+ PrintLiteralWithModeIndented("VAR", scope->parameter(i),
scope->parameter(i)->name(),
scope->parameter(i)->type());
}
@@ -885,6 +886,7 @@ void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
IndentedScope indent("FUNC LITERAL");
PrintLiteralIndented("NAME", node->name(), false);
+ PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false);
PrintParameters(node->scope());
// We don't want to see the function literal in this case: it
// will be printed via PrintProgram when the code for it is
@@ -1022,7 +1024,7 @@ void AstPrinter::VisitProperty(Property* node) {
Visit(node->obj());
Literal* literal = node->key()->AsLiteral();
if (literal != NULL && literal->handle()->IsSymbol()) {
- PrintLiteralIndented("LITERAL", literal->handle(), false);
+ PrintLiteralIndented("NAME", literal->handle(), false);
} else {
PrintIndentedVisit("KEY", node->key());
}
diff --git a/v8/src/rewriter.cc b/v8/src/rewriter.cc
index 1aa24aa..4e3676b 100644
--- a/v8/src/rewriter.cc
+++ b/v8/src/rewriter.cc
@@ -28,6 +28,7 @@
#include "v8.h"
#include "ast.h"
+#include "func-name-inferrer.h"
#include "scopes.h"
#include "rewriter.h"
@@ -36,7 +37,9 @@ namespace v8 { namespace internal {
class AstOptimizer: public AstVisitor {
public:
- explicit AstOptimizer() {
+ explicit AstOptimizer() {}
+ explicit AstOptimizer(Handle<String> enclosing_name) {
+ func_name_inferrer_.PushEnclosingName(enclosing_name);
}
void Optimize(ZoneList<Statement*>* statements);
@@ -45,6 +48,8 @@ class AstOptimizer: public AstVisitor {
// Used for loop condition analysis. Cleared before visiting a loop
// condition, set when a function literal is visited.
bool has_function_literal_;
+ // Helper object for function name inferring.
+ FuncNameInferrer func_name_inferrer_;
// Helpers
void OptimizeArguments(ZoneList<Expression*>* arguments);
@@ -185,8 +190,12 @@ void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) {
void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
- USE(node);
has_function_literal_ = true;
+
+ if (node->name()->length() == 0) {
+ // Anonymous function.
+ func_name_inferrer_.AddFunction(node);
+ }
}
@@ -216,6 +225,11 @@ void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
} else if (node->type()->IsLikelySmi()) {
var->type()->SetAsLikelySmi();
}
+
+ if (!var->is_this() &&
+ !Heap::result_symbol()->Equals(*var->name())) {
+ func_name_inferrer_.PushName(var->name());
+ }
}
}
@@ -224,6 +238,11 @@ void AstOptimizer::VisitLiteral(Literal* node) {
Handle<Object> literal = node->handle();
if (literal->IsSmi()) {
node->type()->SetAsLikelySmi();
+ } else if (literal->IsString()) {
+ Handle<String> lit_str(Handle<String>::cast(literal));
+ if (!Heap::prototype_symbol()->Equals(*lit_str)) {
+ func_name_inferrer_.PushName(lit_str);
+ }
}
}
@@ -239,9 +258,10 @@ void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) {
}
}
-
void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
for (int i = 0; i < node->properties()->length(); i++) {
+ ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
+ scoped_fni.Enter();
Visit(node->properties()->at(i)->key());
Visit(node->properties()->at(i)->value());
}
@@ -255,11 +275,14 @@ void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) {
void AstOptimizer::VisitAssignment(Assignment* node) {
+ ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
switch (node->op()) {
case Token::INIT_VAR:
case Token::INIT_CONST:
case Token::ASSIGN:
// No type can be infered from the general assignment.
+
+ scoped_fni.Enter();
break;
case Token::ASSIGN_BIT_OR:
case Token::ASSIGN_BIT_XOR:
@@ -368,6 +391,12 @@ void AstOptimizer::VisitCallNew(CallNew* node) {
void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
+ ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
+ if (Factory::InitializeVarGlobal_symbol()->Equals(*node->name()) &&
+ node->arguments()->length() >= 2 &&
+ node->arguments()->at(1)->AsFunctionLiteral() != NULL) {
+ scoped_fni.Enter();
+ }
OptimizeArguments(node->arguments());
}
@@ -794,13 +823,10 @@ bool Rewriter::Optimize(FunctionLiteral* function) {
ZoneList<Statement*>* body = function->body();
if (FLAG_optimize_ast && !body->is_empty()) {
- Scope* scope = function->scope();
- if (!scope->is_global_scope()) {
- AstOptimizer optimizer;
- optimizer.Optimize(body);
- if (optimizer.HasStackOverflow()) {
- return false;
- }
+ AstOptimizer optimizer(function->name());
+ optimizer.Optimize(body);
+ if (optimizer.HasStackOverflow()) {
+ return false;
}
}
return true;
diff --git a/v8/src/runtime.cc b/v8/src/runtime.cc
index 5962b2a..93c4b7a 100644
--- a/v8/src/runtime.cc
+++ b/v8/src/runtime.cc
@@ -3391,6 +3391,13 @@ static Object* Runtime_StringToUpperCase(Arguments args) {
}
+bool Runtime::IsUpperCaseChar(uint16_t ch) {
+ unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
+ int char_length = to_upper_mapping.get(ch, 0, chars);
+ return char_length == 0;
+}
+
+
static Object* Runtime_NumberToString(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -3475,6 +3482,7 @@ static Object* Runtime_NumberToSmi(Arguments args) {
return Heap::nan_value();
}
+
static Object* Runtime_NumberAdd(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -5921,8 +5929,8 @@ static Object* Runtime_GetCFrames(Arguments args) {
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();
}
@@ -6061,8 +6069,8 @@ static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
}
-static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
- int position) {
+Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
+ int position) {
// Iterate the heap looking for SharedFunctionInfo generated from the
// script. The inner most SharedFunctionInfo containing the source position
// for the requested break point is found.
@@ -6159,7 +6167,8 @@ static Object* Runtime_SetScriptBreakPoint(Arguments args) {
RUNTIME_ASSERT(wrapper->value()->IsScript());
Handle<Script> script(Script::cast(wrapper->value()));
- Object* result = FindSharedFunctionInfoInScript(script, source_position);
+ Object* result = Runtime::FindSharedFunctionInfoInScript(
+ script, source_position);
if (!result->IsUndefined()) {
Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
// Find position within function. The script position might be before the
@@ -6516,9 +6525,9 @@ static bool IsExternalStringValid(Object* str) {
return true;
}
if (StringShape(String::cast(str)).IsAsciiRepresentation()) {
- return ExternalAsciiString::cast(str)->resource() != 0;
+ return ExternalAsciiString::cast(str)->resource() != NULL;
} else if (StringShape(String::cast(str)).IsTwoByteRepresentation()) {
- return ExternalTwoByteString::cast(str)->resource() != 0;
+ return ExternalTwoByteString::cast(str)->resource() != NULL;
} else {
return true;
}
diff --git a/v8/src/runtime.h b/v8/src/runtime.h
index 486ffb3..657e5c5 100644
--- a/v8/src/runtime.h
+++ b/v8/src/runtime.h
@@ -355,6 +355,8 @@ class Runtime : public AllStatic {
static int StringMatch(Handle<String> sub, Handle<String> pat, int index);
+ static bool IsUpperCaseChar(uint16_t ch);
+
// TODO(1240886): The following three methods are *not* handle safe,
// but accept handle arguments. This seems fragile.
@@ -369,6 +371,10 @@ class Runtime : public AllStatic {
static Object* GetObjectProperty(Handle<Object> object, Handle<Object> key);
+ // This function is used in FunctionNameUsing* tests.
+ static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
+ int position);
+
// Helper functions used stubs.
static void PerformGC(Object* result);
};
diff --git a/v8/src/serialize.cc b/v8/src/serialize.cc
index 9a2be23..ef2517c 100644
--- a/v8/src/serialize.cc
+++ b/v8/src/serialize.cc
@@ -683,6 +683,18 @@ void ExternalReferenceTable::PopulateTable() {
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");
}
diff --git a/v8/src/simulator-arm.cc b/v8/src/simulator-arm.cc
index 5a61107..c35e229 100644
--- a/v8/src/simulator-arm.cc
+++ b/v8/src/simulator-arm.cc
@@ -90,12 +90,44 @@ Debugger::~Debugger() {
}
+
+#ifdef ARM_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, "Simulator hit %s\n", str);
+ fflush(coverage_log);
+ }
+ instr->SetInstructionBits(0xe1a00000); // Overwrite with nop.
+ }
+ sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
+}
+
+#else // ndef ARM_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 @@ Simulator::Simulator() {
// access violation if the simulator ever tries to execute it.
registers_[pc] = bad_lr;
registers_[lr] = bad_lr;
+ InitializeCoverage();
}
@@ -427,6 +460,37 @@ int32_t Simulator::get_pc() const {
}
+// 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 @@ typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1);
// 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 @@ void Simulator::SoftwareInterrupt(Instr* instr) {
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/v8/src/simulator-arm.h b/v8/src/simulator-arm.h
index 4f3c53d..5553ab2 100644
--- a/v8/src/simulator-arm.h
+++ b/v8/src/simulator-arm.h
@@ -174,6 +174,12 @@ class Simulator {
// 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/v8/src/string-stream.cc b/v8/src/string-stream.cc
index f311e20..2e0912f 100644
--- a/v8/src/string-stream.cc
+++ b/v8/src/string-stream.cc
@@ -57,19 +57,26 @@ NoAllocationStringAllocator::NoAllocationStringAllocator(char* memory,
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 @@ static bool IsControlChar(char c) {
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 @@ char* HeapStringAllocator::grow(unsigned* bytes) {
}
+// 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/v8/src/string-stream.h b/v8/src/string-stream.h
index 37ae93e..901f376 100644
--- a/v8/src/string-stream.h
+++ b/v8/src/string-stream.h
@@ -162,8 +162,8 @@ class StringStream {
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/v8/src/stub-cache-arm.cc b/v8/src/stub-cache-arm.cc
index 211b643..22ebe44 100644
--- a/v8/src/stub-cache-arm.cc
+++ b/v8/src/stub-cache-arm.cc
@@ -33,7 +33,7 @@
namespace v8 { namespace internal {
-#define __ masm->
+#define __ DEFINE_MASM(masm)
static void ProbeTable(MacroAssembler* masm,
@@ -183,7 +183,7 @@ void StubCompiler::GenerateLoadField(MacroAssembler* masm,
// 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 @@ void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
// 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 @@ void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
// 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 @@ void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
// 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 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
#undef __
-
-#define __ masm()->
+#define __ DEFINE_MASM(masm())
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
@@ -511,7 +510,7 @@ Object* CallStubCompiler::CompileCallField(Object* object,
// 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/v8/src/top.cc b/v8/src/top.cc
index a99e9ff..3c4b8dd 100644
--- a/v8/src/top.cc
+++ b/v8/src/top.cc
@@ -116,15 +116,15 @@ class PreallocatedMemoryThread: public Thread {
// 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_) {
diff --git a/v8/src/utils.h b/v8/src/utils.h
index f62b47a..e008c85 100644
--- a/v8/src/utils.h
+++ b/v8/src/utils.h
@@ -406,6 +406,16 @@ class EmbeddedVector : public Vector<T> {
};
+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/v8/src/virtual-frame-arm.cc b/v8/src/virtual-frame-arm.cc
index baf0814..df442e9 100644
--- a/v8/src/virtual-frame-arm.cc
+++ b/v8/src/virtual-frame-arm.cc
@@ -36,7 +36,8 @@ namespace v8 { namespace internal {
// -------------------------------------------------------------------------
// VirtualFrame implementation.
-#define __ masm_->
+#define __ DEFINE_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/v8/src/virtual-frame-arm.h b/v8/src/virtual-frame-arm.h
index f15eec2..af3c08c 100644
--- a/v8/src/virtual-frame-arm.h
+++ b/v8/src/virtual-frame-arm.h
@@ -85,7 +85,7 @@ class VirtualFrame : public Malloced {
}
bool is_used(Register reg) {
- return is_used(reg.code()) != kIllegalIndex;
+ return is_used(reg.code());
}
// Add extra in-memory elements to the top of the frame to match an actual
diff --git a/v8/test/cctest/SConscript b/v8/test/cctest/SConscript
index 091768f..f66f72b 100644
--- a/v8/test/cctest/SConscript
+++ b/v8/test/cctest/SConscript
@@ -42,6 +42,7 @@ SOURCES = {
'test-debug.cc',
'test-decls.cc',
'test-flags.cc',
+ 'test-func-name-inference.cc',
'test-hashmap.cc',
'test-heap.cc',
'test-list.cc',
diff --git a/v8/test/cctest/test-api.cc b/v8/test/cctest/test-api.cc
index dd705d2..13185ab 100644
--- a/v8/test/cctest/test-api.cc
+++ b/v8/test/cctest/test-api.cc
@@ -1293,6 +1293,9 @@ THREADED_TEST(HiddenProperties) {
i::Heap::CollectAllGarbage();
+ // Make sure delete of a non-existent hidden value works
+ CHECK(obj->DeleteHiddenValue(key));
+
CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
@@ -2492,6 +2495,44 @@ THREADED_TEST(SimpleExtensions) {
}
+static const char* kEvalExtensionSource =
+ "function UseEval() {"
+ " var x = 42;"
+ " return eval('x');"
+ "}";
+
+
+THREADED_TEST(UseEvalFromExtension) {
+ v8::HandleScope handle_scope;
+ v8::RegisterExtension(new Extension("evaltest", kEvalExtensionSource));
+ const char* extension_names[] = { "evaltest" };
+ v8::ExtensionConfiguration extensions(1, extension_names);
+ v8::Handle<Context> context = Context::New(&extensions);
+ Context::Scope lock(context);
+ v8::Handle<Value> result = Script::Compile(v8_str("UseEval()"))->Run();
+ CHECK_EQ(result, v8::Integer::New(42));
+}
+
+
+static const char* kWithExtensionSource =
+ "function UseWith() {"
+ " var x = 42;"
+ " with({x:87}) { return x; }"
+ "}";
+
+
+THREADED_TEST(UseWithFromExtension) {
+ v8::HandleScope handle_scope;
+ v8::RegisterExtension(new Extension("withtest", kWithExtensionSource));
+ const char* extension_names[] = { "withtest" };
+ v8::ExtensionConfiguration extensions(1, extension_names);
+ v8::Handle<Context> context = Context::New(&extensions);
+ Context::Scope lock(context);
+ v8::Handle<Value> result = Script::Compile(v8_str("UseWith()"))->Run();
+ CHECK_EQ(result, v8::Integer::New(87));
+}
+
+
THREADED_TEST(AutoExtensions) {
v8::HandleScope handle_scope;
Extension* extension = new Extension("autotest", kSimpleExtensionSource);
@@ -2884,7 +2925,19 @@ THREADED_TEST(Deleter) {
static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
ApiTestFuzzer::Fuzz();
- return v8::Undefined();
+ if (name->Equals(v8_str("foo")) ||
+ name->Equals(v8_str("bar")) ||
+ name->Equals(v8_str("baz"))) {
+ return v8::Undefined();
+ }
+ return v8::Handle<Value>();
+}
+
+
+static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
+ ApiTestFuzzer::Fuzz();
+ if (index == 0 || index == 1) return v8::Undefined();
+ return v8::Handle<Value>();
}
@@ -2901,8 +2954,8 @@ static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
ApiTestFuzzer::Fuzz();
v8::Handle<v8::Array> result = v8::Array::New(2);
- result->Set(v8::Integer::New(0), v8_str("hat"));
- result->Set(v8::Integer::New(1), v8_str("gyt"));
+ result->Set(v8::Integer::New(0), v8_str("0"));
+ result->Set(v8::Integer::New(1), v8_str("1"));
return result;
}
@@ -2911,21 +2964,56 @@ THREADED_TEST(Enumerators) {
v8::HandleScope scope;
v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
- obj->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL, IndexedEnum);
+ obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
LocalContext context;
context->Global()->Set(v8_str("k"), obj->NewInstance());
v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
+ "k[10] = 0;"
+ "k.a = 0;"
+ "k[5] = 0;"
+ "k.b = 0;"
+ "k[4294967295] = 0;"
+ "k.c = 0;"
+ "k[4294967296] = 0;"
+ "k.d = 0;"
+ "k[140000] = 0;"
+ "k.e = 0;"
+ "k[30000000000] = 0;"
+ "k.f = 0;"
"var result = [];"
"for (var prop in k) {"
" result.push(prop);"
"}"
"result"));
- CHECK_EQ(5, result->Length());
- CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(0)));
- CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(1)));
- CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(2)));
- CHECK_EQ(v8_str("hat"), result->Get(v8::Integer::New(3)));
- CHECK_EQ(v8_str("gyt"), result->Get(v8::Integer::New(4)));
+ // Check that we get all the property names returned including the
+ // ones from the enumerators in the right order: indexed properties
+ // in numerical order, indexed interceptor properties, named
+ // properties in insertion order, named interceptor properties.
+ // This order is not mandated by the spec, so this test is just
+ // documenting our behavior.
+ CHECK_EQ(17, result->Length());
+ // Indexed properties in numerical order.
+ CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
+ CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
+ CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
+ CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
+ // Indexed interceptor properties in the order they are returned
+ // from the enumerator interceptor.
+ CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
+ CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
+ // Named properties in insertion order.
+ CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
+ CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
+ CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
+ CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
+ CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
+ CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
+ CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
+ CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
+ // Named interceptor properties.
+ CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
+ CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
+ CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
}
diff --git a/v8/test/cctest/test-debug.cc b/v8/test/cctest/test-debug.cc
index 74d590e..e482c7f 100644
--- a/v8/test/cctest/test-debug.cc
+++ b/v8/test/cctest/test-debug.cc
@@ -498,7 +498,7 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
// ---
-// Source for The JavaScript function which picks out the function name on the
+// Source for The JavaScript function which picks out the function name of the
// top frame.
const char* frame_function_name_source =
"function frame_function_name(exec_state) {"
@@ -507,6 +507,24 @@ const char* frame_function_name_source =
v8::Local<v8::Function> frame_function_name;
+// Source for The JavaScript function which picks out the source line for the
+// top frame.
+const char* frame_source_line_source =
+ "function frame_source_line(exec_state) {"
+ " return exec_state.frame(0).sourceLine();"
+ "}";
+v8::Local<v8::Function> frame_source_line;
+
+
+// Source for The JavaScript function which picks out the source column for the
+// top frame.
+const char* frame_source_column_source =
+ "function frame_source_column(exec_state) {"
+ " return exec_state.frame(0).sourceColumn();"
+ "}";
+v8::Local<v8::Function> frame_source_column;
+
+
// Source for The JavaScript function which returns the number of frames.
static const char* frame_count_source =
"function frame_count(exec_state) {"
@@ -518,6 +536,10 @@ v8::Handle<v8::Function> frame_count;
// Global variable to store the last function hit - used by some tests.
char last_function_hit[80];
+// Global variables to store the last source position - used by some tests.
+int last_source_line = -1;
+int last_source_column = -1;
+
// Debug event handler which counts the break points which have been hit.
int break_point_hit_count = 0;
static void DebugEventBreakPointHitCount(v8::DebugEvent event,
@@ -544,6 +566,26 @@ static void DebugEventBreakPointHitCount(v8::DebugEvent event,
function_name->WriteAscii(last_function_hit);
}
}
+
+ if (!frame_source_line.IsEmpty()) {
+ // Get the source line.
+ const int argc = 1;
+ v8::Handle<v8::Value> argv[argc] = { exec_state };
+ v8::Handle<v8::Value> result = frame_source_line->Call(exec_state,
+ argc, argv);
+ CHECK(result->IsNumber());
+ last_source_line = result->Int32Value();
+ }
+
+ if (!frame_source_column.IsEmpty()) {
+ // Get the source column.
+ const int argc = 1;
+ v8::Handle<v8::Value> argv[argc] = { exec_state };
+ v8::Handle<v8::Value> result = frame_source_column->Call(exec_state,
+ argc, argv);
+ CHECK(result->IsNumber());
+ last_source_column = result->Int32Value();
+ }
}
}
@@ -994,6 +1036,17 @@ TEST(BreakPointReturn) {
break_point_hit_count = 0;
v8::HandleScope scope;
DebugLocalContext env;
+
+ // Create a functions for checking the source line and column when hitting
+ // a break point.
+ frame_source_line = CompileFunction(&env,
+ frame_source_line_source,
+ "frame_source_line");
+ frame_source_column = CompileFunction(&env,
+ frame_source_column_source,
+ "frame_source_column");
+
+
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
v8::Script::Compile(v8::String::New("function foo(){}"))->Run();
@@ -1008,8 +1061,12 @@ TEST(BreakPointReturn) {
int bp = SetBreakPoint(foo, 0);
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(1, break_point_hit_count);
+ CHECK_EQ(0, last_source_line);
+ CHECK_EQ(16, last_source_column);
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(2, break_point_hit_count);
+ CHECK_EQ(0, last_source_line);
+ CHECK_EQ(16, last_source_column);
// Run without breakpoints.
ClearBreakPoint(bp);
@@ -2406,6 +2463,96 @@ TEST(DebugStepNatives) {
}
+// Test that step in works with function.apply.
+TEST(DebugStepFunctionApply) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ // Create a function for testing stepping.
+ v8::Local<v8::Function> foo = CompileFunction(
+ &env,
+ "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
+ "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
+ "foo");
+
+ // Register a debug event listener which steps and counts.
+ v8::Debug::SetDebugEventListener(DebugEventStep);
+
+ step_action = StepIn;
+ break_point_hit_count = 0;
+ foo->Call(env->Global(), 0, NULL);
+
+ // With stepping all break locations are hit.
+ CHECK_EQ(6, break_point_hit_count);
+
+ v8::Debug::SetDebugEventListener(NULL);
+ CheckDebuggerUnloaded();
+
+ // Register a debug event listener which just counts.
+ v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
+
+ break_point_hit_count = 0;
+ foo->Call(env->Global(), 0, NULL);
+
+ // Without stepping only the debugger statement is hit.
+ CHECK_EQ(1, break_point_hit_count);
+
+ v8::Debug::SetDebugEventListener(NULL);
+ CheckDebuggerUnloaded();
+}
+
+
+// Test that step in works with function.call.
+TEST(DebugStepFunctionCall) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ // Create a function for testing stepping.
+ v8::Local<v8::Function> foo = CompileFunction(
+ &env,
+ "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
+ "function foo(a){ debugger;"
+ " if (a) {"
+ " bar.call(this, 1, 2, 3);"
+ " } else {"
+ " bar.call(this, 0);"
+ " }"
+ "}",
+ "foo");
+
+ // Register a debug event listener which steps and counts.
+ v8::Debug::SetDebugEventListener(DebugEventStep);
+ step_action = StepIn;
+
+ // Check stepping where the if condition in bar is false.
+ break_point_hit_count = 0;
+ foo->Call(env->Global(), 0, NULL);
+ CHECK_EQ(4, break_point_hit_count);
+
+ // Check stepping where the if condition in bar is true.
+ break_point_hit_count = 0;
+ const int argc = 1;
+ v8::Handle<v8::Value> argv[argc] = { v8::True() };
+ foo->Call(env->Global(), argc, argv);
+ CHECK_EQ(6, break_point_hit_count);
+
+ v8::Debug::SetDebugEventListener(NULL);
+ CheckDebuggerUnloaded();
+
+ // Register a debug event listener which just counts.
+ v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
+
+ break_point_hit_count = 0;
+ foo->Call(env->Global(), 0, NULL);
+
+ // Without stepping only the debugger statement is hit.
+ CHECK_EQ(1, break_point_hit_count);
+
+ v8::Debug::SetDebugEventListener(NULL);
+ CheckDebuggerUnloaded();
+}
+
+
// Test break on exceptions. For each exception break combination the number
// of debug event exception callbacks and message callbacks are collected. The
// number of debug event exception callbacks are used to check that the
@@ -3300,6 +3447,12 @@ class DebuggerThread : public v8::internal::Thread {
};
+static v8::Handle<v8::Value> ThreadedAtBarrier1(const v8::Arguments& args) {
+ threaded_debugging_barriers.barrier_1.Wait();
+ return v8::Undefined();
+}
+
+
static void ThreadedMessageHandler(const uint16_t* message, int length,
void *data) {
static char print_buffer[1000];
@@ -3313,7 +3466,7 @@ static void ThreadedMessageHandler(const uint16_t* message, int length,
void V8Thread::Run() {
- const char* source_1 =
+ const char* source =
"flag = true;\n"
"function bar( new_value ) {\n"
" flag = new_value;\n"
@@ -3323,19 +3476,25 @@ void V8Thread::Run() {
"function foo() {\n"
" var x = 1;\n"
" while ( flag == true ) {\n"
+ " if ( x == 1 ) {\n"
+ " ThreadedAtBarrier1();\n"
+ " }\n"
" x = x + 1;\n"
" }\n"
"}\n"
- "\n";
- const char* source_2 = "foo();\n";
+ "\n"
+ "foo();\n";
v8::HandleScope scope;
DebugLocalContext env;
v8::Debug::SetMessageHandler(&ThreadedMessageHandler);
+ v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+ global_template->Set(v8::String::New("ThreadedAtBarrier1"),
+ v8::FunctionTemplate::New(ThreadedAtBarrier1));
+ v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
+ v8::Context::Scope context_scope(context);
- CompileRun(source_1);
- threaded_debugging_barriers.barrier_1.Wait();
- CompileRun(source_2);
+ CompileRun(source);
}
void DebuggerThread::Run() {
@@ -3561,15 +3720,6 @@ TEST(SendCommandToUninitializedVM) {
}
-// Source for a JavaScript function which returns the source line for the top
-// frame.
-static const char* frame_source_line_source =
- "function frame_source_line(exec_state) {"
- " return exec_state.frame(0).sourceLine();"
- "}";
-v8::Handle<v8::Function> frame_source_line;
-
-
// Source for a JavaScript function which returns the data parameter of a
// function called in the context of the debugger. If no data parameter is
// passed it throws an exception.
@@ -3875,19 +4025,33 @@ TEST(DebuggerHostDispatch) {
"\"type\":\"request\","
"\"command\":\"continue\"}";
+ // Create an empty function to call for processing debug commands
+ v8::Local<v8::Function> empty =
+ CompileFunction(&env, "function empty(){}", "empty");
+
// Setup message and host dispatch handlers.
v8::Debug::SetMessageHandler(DummyMessageHandler);
v8::Debug::SetHostDispatchHandler(HostDispatchHandlerHitCount,
NULL);
- // Fill a host dispatch and a continue command on the command queue before
- // running some code.
+ // Send a host dispatch by itself.
+ v8::Debug::SendHostDispatch(NULL);
+ empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger.
+ CHECK_EQ(1, host_dispatch_hit_count);
+
+ // Fill a host dispatch and a continue command on the command queue.
v8::Debug::SendHostDispatch(NULL);
v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
- CompileRun("void 0");
+ empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger.
- // The host dispatch callback should be called.
- CHECK_EQ(1, host_dispatch_hit_count);
+ // Fill a continue command and a host dispatch on the command queue.
+ v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
+ v8::Debug::SendHostDispatch(NULL);
+ empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger.
+ empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger.
+
+ // All the host dispatch callback should be called.
+ CHECK_EQ(3, host_dispatch_hit_count);
}
diff --git a/v8/test/cctest/test-func-name-inference.cc b/v8/test/cctest/test-func-name-inference.cc
new file mode 100644
index 0000000..d91f75f
--- /dev/null
+++ b/v8/test/cctest/test-func-name-inference.cc
@@ -0,0 +1,250 @@
+// Copyright 2007-2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "runtime.h"
+#include "cctest.h"
+
+
+using ::v8::internal::Handle;
+using ::v8::internal::JSFunction;
+using ::v8::internal::Object;
+using ::v8::internal::Script;
+using ::v8::internal::SharedFunctionInfo;
+using ::v8::internal::String;
+
+namespace i = ::v8::internal;
+
+
+static v8::Persistent<v8::Context> env;
+
+
+static void InitializeVM() {
+ if (env.IsEmpty()) {
+ v8::HandleScope scope;
+ env = v8::Context::New();
+ }
+ v8::HandleScope scope;
+ env->Enter();
+}
+
+
+static void CheckFunctionName(v8::Handle<v8::Script> script,
+ const char* func_pos_src,
+ const char* ref_inferred_name) {
+ // Get script source.
+ Handle<JSFunction> fun = v8::Utils::OpenHandle(*script);
+ Handle<Script> i_script(Script::cast(fun->shared()->script()));
+ CHECK(i_script->source()->IsString());
+ Handle<String> script_src(String::cast(i_script->source()));
+
+ // Find the position of a given func source substring in the source.
+ Handle<String> func_pos_str =
+ i::Factory::NewStringFromAscii(i::CStrVector(func_pos_src));
+ int func_pos = i::Runtime::StringMatch(script_src, func_pos_str, 0);
+ CHECK_NE(0, func_pos);
+
+ // Obtain SharedFunctionInfo for the function.
+ Object* shared_func_info_ptr =
+ i::Runtime::FindSharedFunctionInfoInScript(i_script, func_pos);
+ CHECK(shared_func_info_ptr != i::Heap::undefined_value());
+ Handle<SharedFunctionInfo> shared_func_info(
+ SharedFunctionInfo::cast(shared_func_info_ptr));
+
+ // Verify inferred function name.
+ i::SmartPointer<char> inferred_name =
+ shared_func_info->inferred_name()->ToCString();
+ CHECK_EQ(ref_inferred_name, *inferred_name);
+}
+
+
+static v8::Handle<v8::Script> Compile(const char* src) {
+ return v8::Script::Compile(v8::String::New(src));
+}
+
+
+TEST(GlobalProperty) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "fun1 = function() { return 1; }\n"
+ "fun2 = function() { return 2; }\n");
+ CheckFunctionName(script, "return 1", "fun1");
+ CheckFunctionName(script, "return 2", "fun2");
+}
+
+
+TEST(GlobalVar) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "var fun1 = function() { return 1; }\n"
+ "var fun2 = function() { return 2; }\n");
+ CheckFunctionName(script, "return 1", "fun1");
+ CheckFunctionName(script, "return 2", "fun2");
+}
+
+
+TEST(LocalVar) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function outer() {\n"
+ " var fun1 = function() { return 1; }\n"
+ " var fun2 = function() { return 2; }\n"
+ "}");
+ CheckFunctionName(script, "return 1", "fun1");
+ CheckFunctionName(script, "return 2", "fun2");
+}
+
+
+TEST(InConstructor) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function MyClass() {\n"
+ " this.method1 = function() { return 1; }\n"
+ " this.method2 = function() { return 2; }\n"
+ "}");
+ CheckFunctionName(script, "return 1", "MyClass.method1");
+ CheckFunctionName(script, "return 2", "MyClass.method2");
+}
+
+
+TEST(Factory) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function createMyObj() {\n"
+ " var obj = {};\n"
+ " obj.method1 = function() { return 1; }\n"
+ " obj.method2 = function() { return 2; }\n"
+ " return obj;\n"
+ "}");
+ CheckFunctionName(script, "return 1", "obj.method1");
+ CheckFunctionName(script, "return 2", "obj.method2");
+}
+
+
+TEST(Static) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function MyClass() {}\n"
+ "MyClass.static1 = function() { return 1; }\n"
+ "MyClass.static2 = function() { return 2; }\n"
+ "MyClass.MyInnerClass = {}\n"
+ "MyClass.MyInnerClass.static3 = function() { return 3; }\n"
+ "MyClass.MyInnerClass.static4 = function() { return 4; }");
+ CheckFunctionName(script, "return 1", "MyClass.static1");
+ CheckFunctionName(script, "return 2", "MyClass.static2");
+ CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.static3");
+ CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.static4");
+}
+
+
+TEST(Prototype) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function MyClass() {}\n"
+ "MyClass.prototype.method1 = function() { return 1; }\n"
+ "MyClass.prototype.method2 = function() { return 2; }\n"
+ "MyClass.MyInnerClass = function() {}\n"
+ "MyClass.MyInnerClass.prototype.method3 = function() { return 3; }\n"
+ "MyClass.MyInnerClass.prototype.method4 = function() { return 4; }");
+ CheckFunctionName(script, "return 1", "MyClass.method1");
+ CheckFunctionName(script, "return 2", "MyClass.method2");
+ CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.method3");
+ CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.method4");
+}
+
+
+TEST(ObjectLiteral) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function MyClass() {}\n"
+ "MyClass.prototype = {\n"
+ " method1: function() { return 1; },\n"
+ " method2: function() { return 2; } }");
+ CheckFunctionName(script, "return 1", "MyClass.method1");
+ CheckFunctionName(script, "return 2", "MyClass.method2");
+}
+
+
+TEST(AsParameter) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function f1(a) { return a(); }\n"
+ "function f2(a, b) { return a() + b(); }\n"
+ "var result1 = f1(function() { return 1; })\n"
+ "var result2 = f2(function() { return 2; }, function() { return 3; })");
+ // Can't infer names here.
+ CheckFunctionName(script, "return 1", "");
+ CheckFunctionName(script, "return 2", "");
+ CheckFunctionName(script, "return 3", "");
+}
+
+
+TEST(MultipleFuncsConditional) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "fun1 = 0 ?\n"
+ " function() { return 1; } :\n"
+ " function() { return 2; }");
+ CheckFunctionName(script, "return 1", "fun1");
+ CheckFunctionName(script, "return 2", "fun1");
+}
+
+
+TEST(MultipleFuncsInLiteral) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "function MyClass() {}\n"
+ "MyClass.prototype = {\n"
+ " method1: 0 ? function() { return 1; } :\n"
+ " function() { return 2; } }");
+ CheckFunctionName(script, "return 1", "MyClass.method1");
+ CheckFunctionName(script, "return 2", "MyClass.method1");
+}
diff --git a/v8/test/cctest/test-strings.cc b/v8/test/cctest/test-strings.cc
index b38d645..3be5d62 100644
--- a/v8/test/cctest/test-strings.cc
+++ b/v8/test/cctest/test-strings.cc
@@ -387,3 +387,60 @@ TEST(Utf8Conversion) {
CHECK_EQ(kNoChar, buffer[j]);
}
}
+
+
+class TwoByteResource: public v8::String::ExternalStringResource {
+ public:
+ explicit TwoByteResource(const uint16_t* data, size_t length)
+ : data_(data), length_(length) { }
+ virtual ~TwoByteResource() { }
+
+ const uint16_t* data() const { return data_; }
+ size_t length() const { return length_; }
+
+ private:
+ const uint16_t* data_;
+ size_t length_;
+};
+
+
+TEST(ExternalCrBug9746) {
+ InitializeVM();
+ v8::HandleScope handle_scope;
+
+ // This set of tests verifies that the workaround for Chromium bug 9746
+ // works correctly. In certain situations the external resource of a symbol
+ // is collected while the symbol is still part of the symbol table.
+ static uint16_t two_byte_data[] = {
+ 't', 'w', 'o', '-', 'b', 'y', 't', 'e', ' ', 'd', 'a', 't', 'a'
+ };
+ static size_t two_byte_length =
+ sizeof(two_byte_data) / sizeof(two_byte_data[0]);
+ static const char* one_byte_data = "two-byte data";
+
+ // Allocate an external string resource and external string.
+ TwoByteResource* resource = new TwoByteResource(two_byte_data,
+ two_byte_length);
+ Handle<String> string = Factory::NewExternalStringFromTwoByte(resource);
+ Vector<const char> one_byte_vec = CStrVector(one_byte_data);
+ Handle<String> compare = Factory::NewStringFromAscii(one_byte_vec);
+
+ // Verify the correct behaviour before "collecting" the external resource.
+ CHECK(string->IsEqualTo(one_byte_vec));
+ CHECK(string->Equals(*compare));
+
+ // "Collect" the external resource manually by setting the external resource
+ // pointer to NULL. Then redo the comparisons, they should not match AND
+ // not crash.
+ Handle<ExternalTwoByteString> external(ExternalTwoByteString::cast(*string));
+ external->set_resource(NULL);
+ CHECK_EQ(false, string->IsEqualTo(one_byte_vec));
+#if !defined(DEBUG)
+ // These tests only work in non-debug as there are ASSERTs in the code that
+ // do prevent the ability to even get into the broken code when running the
+ // debug version of V8.
+ CHECK_EQ(false, string->Equals(*compare));
+ CHECK_EQ(false, compare->Equals(*string));
+ CHECK_EQ(false, string->Equals(Heap::empty_string()));
+#endif // !defined(DEBUG)
+}
diff --git a/v8/test/mjsunit/const-declaration.js b/v8/test/mjsunit/const-declaration.js
new file mode 100644
index 0000000..48c0cf2
--- /dev/null
+++ b/v8/test/mjsunit/const-declaration.js
@@ -0,0 +1,172 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test handling of const variables in various settings.
+
+(function () {
+ function f() {
+ function g() {
+ x = 42; // should be ignored
+ return x; // force x into context
+ }
+ x = 43; // should be ignored
+ assertEquals(undefined, g());
+ x = 44; // should be ignored
+ const x = 0;
+ x = 45; // should be ignored
+ assertEquals(0, g());
+ }
+ f();
+})();
+
+
+(function () {
+ function f() {
+ function g() {
+ with ({foo: 0}) {
+ x = 42; // should be ignored
+ return x; // force x into context
+ }
+ }
+ x = 43; // should be ignored
+ assertEquals(undefined, g());
+ x = 44; // should be ignored
+ const x = 0;
+ x = 45; // should be ignored
+ assertEquals(0, g());
+ }
+ f();
+})();
+
+
+(function () {
+ function f() {
+ function g(s) {
+ eval(s);
+ return x; // force x into context
+ }
+ x = 43; // should be ignored
+ assertEquals(undefined, g("x = 42;"));
+ x = 44; // should be ignored
+ const x = 0;
+ x = 45; // should be ignored
+ assertEquals(0, g("x = 46;"));
+ }
+ f();
+})();
+
+
+(function () {
+ function f() {
+ function g(s) {
+ with ({foo: 0}) {
+ eval(s);
+ return x; // force x into context
+ }
+ }
+ x = 43; // should be ignored
+ assertEquals(undefined, g("x = 42;"));
+ x = 44; // should be ignored
+ const x = 0;
+ x = 45; // should be ignored
+ assertEquals(0, g("x = 46;"));
+ }
+ f();
+})();
+
+
+(function () {
+ function f(s) {
+ function g() {
+ x = 42; // assign to global x, or to const x
+ return x;
+ }
+ x = 43; // declare global x
+ assertEquals(42, g());
+ x = 44; // assign to global x
+ eval(s);
+ x = 45; // should be ignored (assign to const x)
+ assertEquals(0, g());
+ }
+ f("const x = 0;");
+})();
+
+
+(function () {
+ function f(s) {
+ function g() {
+ with ({foo: 0}) {
+ x = 42; // assign to global x, or to const x
+ return x;
+ }
+ }
+ x = 43; // declare global x
+ assertEquals(42, g());
+ x = 44; // assign to global x
+ eval(s);
+ x = 45; // should be ignored (assign to const x)
+ assertEquals(0, g());
+ }
+ f("const x = 0;");
+})();
+
+
+(function () {
+ function f(s) {
+ function g(s) {
+ eval(s);
+ return x;
+ }
+ x = 43; // declare global x
+ assertEquals(42, g("x = 42;"));
+ x = 44; // assign to global x
+ eval(s);
+ x = 45; // should be ignored (assign to const x)
+ assertEquals(0, g("x = 46;"));
+ }
+ f("const x = 0;");
+})();
+
+
+(function () {
+ function f(s) {
+ function g(s) {
+ with ({foo: 0}) {
+ eval(s);
+ return x;
+ }
+ }
+ x = 43; // declare global x
+ assertEquals(42, g("x = 42;"));
+ x = 44; // assign to global x
+ eval(s);
+ x = 45; // should be ignored (assign to const x)
+ assertEquals(0, g("x = 46;"));
+ }
+ f("const x = 0;");
+})();
+
diff --git a/v8/test/mjsunit/constant-folding.js b/v8/test/mjsunit/constant-folding.js
index 41b632f..33984c1 100644
--- a/v8/test/mjsunit/constant-folding.js
+++ b/v8/test/mjsunit/constant-folding.js
@@ -168,4 +168,29 @@ function test() {
assertEquals(17, j, "switch with constant value");
}
+
+function TrueToString() {
+ return true.toString();
+}
+
+
+function FalseToString() {
+ return false.toString();
+}
+
+
+function BoolTest() {
+ assertEquals("true", TrueToString());
+ assertEquals("true", TrueToString());
+ assertEquals("true", TrueToString());
+ assertEquals("false", FalseToString());
+ assertEquals("false", FalseToString());
+ assertEquals("false", FalseToString());
+ Boolean.prototype.toString = function() { return "foo"; }
+ assertEquals("foo", TrueToString());
+ assertEquals("foo", FalseToString());
+}
+
+
test();
+BoolTest();
diff --git a/v8/test/mjsunit/debug-handle.js b/v8/test/mjsunit/debug-handle.js
index 64a68a8..c7ab76a 100644
--- a/v8/test/mjsunit/debug-handle.js
+++ b/v8/test/mjsunit/debug-handle.js
@@ -95,8 +95,8 @@ function listener(event, exec_state, event_data, data) {
// Test some illegal lookup requests.
lookupRequest(dcp, void 0, false);
- lookupRequest(dcp, '{"handle":"a"}', false);
- lookupRequest(dcp, '{"handle":-1}', false);
+ lookupRequest(dcp, '{"handles":["a"]}', false);
+ lookupRequest(dcp, '{"handles":[-1]}', false);
// Evaluate and get some handles.
var handle_o = evaluateRequest(dcp, '{"expression":"o"}');
@@ -109,24 +109,28 @@ function listener(event, exec_state, event_data, data) {
var response;
var count;
- response = lookupRequest(dcp, '{"handle":' + handle_o + '}', true);
- assertEquals(handle_o, response.body.handle);
+ response = lookupRequest(dcp, '{"handles":[' + handle_o + ']}', true);
+ var obj = response.body[handle_o];
+ assertTrue(!!obj, 'Object not found: ' + handle_o);
+ assertEquals(handle_o, obj.handle);
count = 0;
- for (i in response.body.properties) {
- switch (response.body.properties[i].name) {
+ for (i in obj.properties) {
+ switch (obj.properties[i].name) {
case 'o':
- response.body.properties[i].ref = handle_o;
+ obj.properties[i].ref = handle_o;
count++;
break;
case 'p':
- response.body.properties[i].ref = handle_p;
+ obj.properties[i].ref = handle_p;
count++;
break;
}
}
assertEquals(2, count, 'Either "o" or "p" not found');
- response = lookupRequest(dcp, '{"handle":' + handle_p + '}', true);
- assertEquals(handle_p, response.body.handle);
+ response = lookupRequest(dcp, '{"handles":[' + handle_p + ']}', true);
+ obj = response.body[handle_p];
+ assertTrue(!!obj, 'Object not found: ' + handle_p);
+ assertEquals(handle_p, obj.handle);
// Check handles for functions on the stack.
var handle_f = evaluateRequest(dcp, '{"expression":"f"}');
@@ -136,28 +140,31 @@ function listener(event, exec_state, event_data, data) {
assertFalse(handle_f == handle_g, "f and g have he same handle");
assertEquals(handle_g, handle_caller, "caller for f should be g");
- response = lookupRequest(dcp, '{"handle":' + handle_f + '}', true);
- assertEquals(handle_f, response.body.handle);
+ response = lookupRequest(dcp, '{"handles":[' + handle_f + ']}', true);
+ obj = response.body[handle_f];
+ assertEquals(handle_f, obj.handle);
+
count = 0;
- for (i in response.body.properties) {
- var arguments = '{"handle":' + response.body.properties[i].ref + '}'
- switch (response.body.properties[i].name) {
+ for (i in obj.properties) {
+ var ref = obj.properties[i].ref;
+ var arguments = '{"handles":[' + ref + ']}';
+ switch (obj.properties[i].name) {
case 'name':
var response_name;
response_name = lookupRequest(dcp, arguments, true);
- assertEquals('string', response_name.body.type);
- assertEquals("f", response_name.body.value);
+ assertEquals('string', response_name.body[ref].type);
+ assertEquals("f", response_name.body[ref].value);
count++;
break;
case 'length':
var response_length;
response_length = lookupRequest(dcp, arguments, true);
- assertEquals('number', response_length.body.type);
- assertEquals(1, response_length.body.value);
+ assertEquals('number', response_length.body[ref].type);
+ assertEquals(1, response_length.body[ref].value);
count++;
break;
case 'caller':
- assertEquals(handle_g, response.body.properties[i].ref);
+ assertEquals(handle_g, obj.properties[i].ref);
count++;
break;
}
@@ -165,6 +172,49 @@ function listener(event, exec_state, event_data, data) {
assertEquals(3, count, 'Either "name", "length" or "caller" not found');
+ // Resolve all at once.
+ var refs = [];
+ for (i in obj.properties) {
+ refs.push(obj.properties[i].ref);
+ }
+
+ var arguments = '{"handles":[' + refs.join(',') + ']}';
+ response = lookupRequest(dcp, arguments, true);
+ count = 0;
+ for (i in obj.properties) {
+ var ref = obj.properties[i].ref;
+ var val = response.body[ref];
+ assertTrue(!!val, 'Failed to lookup "' + obj.properties[i].name + '"');
+ switch (obj.properties[i].name) {
+ case 'name':
+ assertEquals('string', val.type);
+ assertEquals("f", val.value);
+ count++;
+ break;
+ case 'length':
+ assertEquals('number', val.type);
+ assertEquals(1, val.value);
+ count++;
+ break;
+ case 'caller':
+ assertEquals('function', val.type);
+ assertEquals(handle_g, ref);
+ count++;
+ break;
+ }
+ }
+ assertEquals(3, count, 'Either "name", "length" or "caller" not found');
+
+ count = 0;
+ for (var handle in response.body) {
+ assertTrue(refs.indexOf(parseInt(handle)) != -1,
+ 'Handle not in the request: ' + handle);
+ count++;
+ }
+ assertEquals(count, obj.properties.length,
+ 'Unexpected number of resolved objects');
+
+
// Indicate that all was processed.
listenerComplete = true;
}
@@ -195,5 +245,5 @@ p.p = p;
g(o);
// Make sure that the debug event listener vas invoked.
-assertTrue(listenerComplete, "listener did not run to completion");
+assertTrue(listenerComplete, "listener did not run to completion: " + exception);
assertFalse(exception, "exception in listener")
diff --git a/v8/test/mjsunit/enumeration-order.js b/v8/test/mjsunit/enumeration-order.js
index 699a636..a328121 100644
--- a/v8/test/mjsunit/enumeration-order.js
+++ b/v8/test/mjsunit/enumeration-order.js
@@ -26,17 +26,17 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function check_enumeration_order(obj) {
- var value = 0;
+ var value = 0;
for (var name in obj) assertTrue(value < obj[name]);
value = obj[name];
}
function make_object(size) {
var a = new Object();
-
+
for (var i = 0; i < size; i++) a["a_" + i] = i + 1;
check_enumeration_order(a);
-
+
for (var i = 0; i < size; i +=3) delete a["a_" + i];
check_enumeration_order(a);
}
@@ -51,9 +51,59 @@ function make_literal_object(size) {
code += "a_" + (size - 1) + " : " + size;
code += " }";
eval("var a = " + code);
- check_enumeration_order(a);
+ check_enumeration_order(a);
}
-// Validate the enumeration order for object literals up to 100 named properties.
+// Validate the enumeration order for object literals up to 100 named
+// properties.
for (var j = 1; j< 100; j++) make_literal_object(j);
+// We enumerate indexed properties in numerical order followed by
+// named properties in insertion order, followed by indexed properties
+// of the prototype object in numerical order, followed by named
+// properties of the prototype object in insertion order, and so on.
+//
+// This enumeration order is not required by the specification, so
+// this just documents our choice.
+var proto2 = {};
+proto2[140000] = 0;
+proto2.a = 0;
+proto2[2] = 0;
+proto2[3] = 0; // also on the 'proto1' object
+proto2.b = 0;
+proto2[4294967295] = 0;
+proto2.c = 0;
+proto2[4294967296] = 0;
+
+var proto1 = {};
+proto1[5] = 0;
+proto1.d = 0;
+proto1[3] = 0;
+proto1.e = 0;
+proto1.f = 0; // also on the 'o' object
+
+var o = {};
+o[-23] = 0;
+o[300000000000] = 0;
+o[23] = 0;
+o.f = 0;
+o.g = 0;
+o[-4] = 0;
+o[42] = 0;
+
+o.__proto__ = proto1;
+proto1.__proto__ = proto2;
+
+var expected = ['23', '42', // indexed from 'o'
+ '-23', '300000000000', 'f', 'g', '-4', // named from 'o'
+ '3', '5', // indexed from 'proto1'
+ 'd', 'e', // named from 'proto1'
+ '2', '140000', '4294967295', // indexed from 'proto2'
+ 'a', 'b', 'c', '4294967296']; // named from 'proto2'
+var actual = [];
+for (var p in o) actual.push(p);
+assertArrayEquals(expected, actual);
+
+
+
+
diff --git a/v8/test/mjsunit/eval-enclosing-function-name.js b/v8/test/mjsunit/eval-enclosing-function-name.js
new file mode 100644
index 0000000..422f03f
--- /dev/null
+++ b/v8/test/mjsunit/eval-enclosing-function-name.js
@@ -0,0 +1,76 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// From within 'eval', the name of the enclosing function should be
+// visible.
+
+var f = function y() { return typeof y; };
+assertEquals("function", f());
+
+
+f = function y() { return eval('typeof y'); };
+assertEquals("function", f());
+
+
+f = function y() { y = 3; return typeof y; };
+assertEquals("function", f());
+
+
+f = function y() { y += 3; return typeof y; };
+assertEquals("function", f());
+
+
+f = function y() { y &= y; return typeof y; };
+assertEquals("function", f());
+
+
+f = function y() { y = 3; return eval('typeof y'); }
+assertEquals("function", f());
+
+
+f = function y() { var y = 3; return typeof y; }
+assertEquals("number", f());
+
+
+f = function y() { var y = 3; return eval('typeof y'); }
+assertEquals("number", f());
+
+
+f = function y() { eval('y = 3'); return typeof y; }
+assertEquals("function", f());
+
+
+f = function y() { eval('y = 3'); return eval('typeof y'); }
+assertEquals("function", f());
+
+
+f = function y() { eval('var y = 3'); return typeof y; }
+assertEquals("number", f());
+
+
+f = function y() { eval('var y = 3'); return eval('typeof y'); }
+assertEquals("number", f());
diff --git a/v8/test/mjsunit/mjsunit.js b/v8/test/mjsunit/mjsunit.js
index 3570d68..370d491 100644
--- a/v8/test/mjsunit/mjsunit.js
+++ b/v8/test/mjsunit/mjsunit.js
@@ -113,6 +113,20 @@ function assertNaN(value, name_opt) {
}
+function assertNull(value, name_opt) {
+ if (value !== null) {
+ fail("null", value, name_opt);
+ }
+}
+
+
+function assertNotNull(value, name_opt) {
+ if (value === null) {
+ fail("not null", value, name_opt);
+ }
+}
+
+
function assertThrows(code) {
var threwException = true;
try {
diff --git a/v8/test/mjsunit/mjsunit.status b/v8/test/mjsunit/mjsunit.status
index 276f5a4..5a76078 100644
--- a/v8/test/mjsunit/mjsunit.status
+++ b/v8/test/mjsunit/mjsunit.status
@@ -36,9 +36,6 @@ fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm)
big-object-literal: PASS, SKIP if ($arch == arm)
-# Bug realiably triggers a debug assertion and crashed in release mode.
-bugs/bug-269: CRASH, FAIL if $mode == debug
-
[ $arch == arm ]
# Slow tests which times out in debug mode.
@@ -64,7 +61,7 @@ debug-stepin-constructor: CRASH, FAIL
debug-step: SKIP
debug-breakpoints: PASS || FAIL
debug-handle: CRASH, FAIL if $mode == debug
-bugs/bug-269: SKIP
+regress/regress-269: SKIP
# Bug number 130 http://code.google.com/p/v8/issues/detail?id=130
# Fails on real ARM hardware but not on the simulator.
diff --git a/v8/test/mjsunit/negate.js b/v8/test/mjsunit/negate.js
index 3bf4111..70daf24 100644
--- a/v8/test/mjsunit/negate.js
+++ b/v8/test/mjsunit/negate.js
@@ -30,9 +30,9 @@ const SMI_MIN = -(1 << 30);
function testmulneg(a, b) {
var base = a * b;
- assertEquals(-base, a * -b);
- assertEquals(-base, -a * b);
- assertEquals(base, -a * -b);
+ assertEquals(-base, a * -b, "a * -b where a = " + a + ", b = " + b);
+ assertEquals(-base, -a * b, "-a * b where a = " + a + ", b = " + b);
+ assertEquals(base, -a * -b, "*-a * -b where a = " + a + ", b = " + b);
}
testmulneg(2, 3);
diff --git a/v8/test/mjsunit/number-limits.js b/v8/test/mjsunit/number-limits.js
index 1d9a1e5..99ed4e1 100644
--- a/v8/test/mjsunit/number-limits.js
+++ b/v8/test/mjsunit/number-limits.js
@@ -33,10 +33,14 @@ function testLimits() {
var addAboveMax = Number.MAX_VALUE + 1/eps;
var mulBelowMin = Number.MIN_VALUE * (1 - eps);
var addBelowMin = Number.MIN_VALUE - eps;
- assertTrue(mulAboveMax == Number.MAX_VALUE || mulAboveMax == Infinity);
- assertTrue(addAboveMax == Number.MAX_VALUE || addAboveMax == Infinity);
- assertTrue(mulBelowMin == Number.MIN_VALUE || mulBelowMin <= 0);
- assertTrue(addBelowMin == Number.MIN_VALUE || addBelowMin <= 0);
+ assertTrue(mulAboveMax == Number.MAX_VALUE ||
+ mulAboveMax == Infinity, "mul" + i);
+ assertTrue(addAboveMax == Number.MAX_VALUE ||
+ addAboveMax == Infinity, "add" + i);
+ assertTrue(mulBelowMin == Number.MIN_VALUE ||
+ mulBelowMin <= 0, "mul2" + i);
+ assertTrue(addBelowMin == Number.MIN_VALUE ||
+ addBelowMin <= 0, "add2" + i);
}
}
diff --git a/v8/test/mjsunit/override-read-only-property.js b/v8/test/mjsunit/override-read-only-property.js
new file mode 100644
index 0000000..b8fa501
--- /dev/null
+++ b/v8/test/mjsunit/override-read-only-property.js
@@ -0,0 +1,64 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// According to ECMA-262, sections 8.6.2.2 and 8.6.2.3 you're not
+// allowed to override read-only properties, not even if the read-only
+// property is in the prototype chain.
+//
+// However, for compatibility with WebKit/JSC, we allow the overriding
+// of read-only properties in prototype chains.
+
+function F() {};
+F.prototype = Number;
+
+var original_number_max = Number.MAX_VALUE;
+
+// Assignment to a property which does not exist on the object itself,
+// but is read-only in a prototype takes effect.
+var f = new F();
+assertEquals(original_number_max, f.MAX_VALUE);
+f.MAX_VALUE = 42;
+assertEquals(42, f.MAX_VALUE);
+
+// Assignment to a property which does not exist on the object itself,
+// but is read-only in a prototype takes effect.
+f = new F();
+with (f) {
+ MAX_VALUE = 42;
+}
+assertEquals(42, f.MAX_VALUE);
+
+// Assignment to read-only property on the object itself is ignored.
+Number.MAX_VALUE = 42;
+assertEquals(original_number_max, Number.MAX_VALUE);
+
+// G should be read-only on the global object and the assignment is
+// ignored.
+(function G() {
+ eval("G = 42;");
+ assertTrue(typeof G === 'function');
+})();
diff --git a/v8/test/mjsunit/receiver-in-with-calls.js b/v8/test/mjsunit/receiver-in-with-calls.js
new file mode 100644
index 0000000..5f2bdac
--- /dev/null
+++ b/v8/test/mjsunit/receiver-in-with-calls.js
@@ -0,0 +1,47 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// When invoking functions from within a 'with' statement, we must set
+// the receiver to the object where we found the function.
+
+(function () {
+ var x = { get_this: function() { return this; } };
+ assertTrue(x === x.get_this());
+ with (x) assertTrue(x === get_this());
+})();
+
+
+assertTrue({ f: function() {
+ function g() { return this; };
+ return eval("g")();
+} }.f() == this);
+
+
+assertTrue({ f: function() {
+ function g() { return this; };
+ return eval("g()");
+} }.f() == this);
diff --git a/v8/test/mjsunit/regexp-multiline-stack-trace.js b/v8/test/mjsunit/regexp-multiline-stack-trace.js
index aa2de88..fc248ef 100644
--- a/v8/test/mjsunit/regexp-multiline-stack-trace.js
+++ b/v8/test/mjsunit/regexp-multiline-stack-trace.js
@@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// The flags below are to test the trace-calls functionality and the
+// preallocated meessage memory.
// Flags: --trace-calls --preallocate-message-memory
/**
diff --git a/v8/test/mjsunit/bugs/bug-269.js b/v8/test/mjsunit/regress/regress-269.js
index 49b24c0..49b24c0 100644
--- a/v8/test/mjsunit/bugs/bug-269.js
+++ b/v8/test/mjsunit/regress/regress-269.js
diff --git a/v8/test/mjsunit/regress/regress-312.js b/v8/test/mjsunit/regress/regress-312.js
new file mode 100644
index 0000000..0fb8c21
--- /dev/null
+++ b/v8/test/mjsunit/regress/regress-312.js
@@ -0,0 +1,31 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Should not trigger debug ASSERT.
+// See http://code.google.com/p/v8/issues/detail?id=312
+
+var o = { f: "x" ? function () {} : function () {} };
diff --git a/v8/test/mjsunit/smi-ops.js b/v8/test/mjsunit/smi-ops.js
index bdd7509..80d2012 100644
--- a/v8/test/mjsunit/smi-ops.js
+++ b/v8/test/mjsunit/smi-ops.js
@@ -100,3 +100,98 @@ assertEquals(SMI_MIN - ONE_HUNDRED, Sub100(SMI_MIN)); // overflow
assertEquals(ONE_HUNDRED - SMI_MIN, Sub100Reversed(SMI_MIN)); // overflow
assertEquals(42 - ONE_HUNDRED, Sub100(OBJ_42)); // non-smi
assertEquals(ONE_HUNDRED - 42, Sub100Reversed(OBJ_42)); // non-smi
+
+
+function Shr1(x) {
+ return x >>> 1;
+}
+
+function Shr100(x) {
+ return x >>> 100;
+}
+
+function Shr1Reversed(x) {
+ return 1 >>> x;
+}
+
+function Shr100Reversed(x) {
+ return 100 >>> x;
+}
+
+function Sar1(x) {
+ return x >> 1;
+}
+
+function Sar100(x) {
+ return x >> 100;
+}
+
+function Sar1Reversed(x) {
+ return 1 >> x;
+}
+
+function Sar100Reversed(x) {
+ return 100 >> x;
+}
+
+
+assertEquals(0, Shr1(1));
+assertEquals(0, Sar1(1));
+assertEquals(0, Shr1Reversed(2));
+assertEquals(0, Sar1Reversed(2));
+assertEquals(1610612736, Shr1(SMI_MIN));
+assertEquals(-536870912, Sar1(SMI_MIN));
+assertEquals(1, Shr1Reversed(SMI_MIN));
+assertEquals(1, Sar1Reversed(SMI_MIN));
+assertEquals(21, Shr1(OBJ_42));
+assertEquals(21, Sar1(OBJ_42));
+assertEquals(0, Shr1Reversed(OBJ_42));
+assertEquals(0, Sar1Reversed(OBJ_42));
+
+assertEquals(6, Shr100(100));
+assertEquals(6, Sar100(100));
+assertEquals(12, Shr100Reversed(99));
+assertEquals(12, Sar100Reversed(99));
+assertEquals(201326592, Shr100(SMI_MIN));
+assertEquals(-67108864, Sar100(SMI_MIN));
+assertEquals(100, Shr100Reversed(SMI_MIN));
+assertEquals(100, Sar100Reversed(SMI_MIN));
+assertEquals(2, Shr100(OBJ_42));
+assertEquals(2, Sar100(OBJ_42));
+assertEquals(0, Shr100Reversed(OBJ_42));
+assertEquals(0, Sar100Reversed(OBJ_42));
+
+
+function Xor1(x) {
+ return x ^ 1;
+}
+
+function Xor100(x) {
+ return x ^ 100;
+}
+
+function Xor1Reversed(x) {
+ return 1 ^ x;
+}
+
+function Xor100Reversed(x) {
+ return 100 ^ x;
+}
+
+
+assertEquals(0, Xor1(1));
+assertEquals(3, Xor1Reversed(2));
+assertEquals(SMI_MIN + 1, Xor1(SMI_MIN));
+assertEquals(SMI_MIN + 1, Xor1Reversed(SMI_MIN));
+assertEquals(43, Xor1(OBJ_42));
+assertEquals(43, Xor1Reversed(OBJ_42));
+
+assertEquals(0, Xor100(100));
+assertEquals(7, Xor100Reversed(99));
+assertEquals(-1073741724, Xor100(SMI_MIN));
+assertEquals(-1073741724, Xor100Reversed(SMI_MIN));
+assertEquals(78, Xor100(OBJ_42));
+assertEquals(78, Xor100Reversed(OBJ_42));
+
+var x = 0x23; var y = 0x35;
+assertEquals(0x16, x ^ y);
diff --git a/v8/test/mjsunit/string-match.js b/v8/test/mjsunit/string-match.js
index 202396d..202396d 100644..100755
--- a/v8/test/mjsunit/string-match.js
+++ b/v8/test/mjsunit/string-match.js
diff --git a/v8/test/mjsunit/testcfg.py b/v8/test/mjsunit/testcfg.py
index f65365d..9c7e028 100644
--- a/v8/test/mjsunit/testcfg.py
+++ b/v8/test/mjsunit/testcfg.py
@@ -32,6 +32,7 @@ import re
FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
+FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
class MjsunitTestCase(test.TestCase):
@@ -54,6 +55,12 @@ class MjsunitTestCase(test.TestCase):
flags_match = FLAGS_PATTERN.search(source)
if flags_match:
result += flags_match.group(1).strip().split()
+ files_match = FILES_PATTERN.search(source);
+ additional_files = []
+ if files_match:
+ additional_files += files_match.group(1).strip().split()
+ for a_file in additional_files:
+ result.append(join(dirname(self.config.root), '..', a_file))
framework = join(dirname(self.config.root), 'mjsunit', 'mjsunit.js')
result += [framework, self.file]
return result
@@ -76,7 +83,8 @@ class MjsunitTestConfiguration(test.TestConfiguration):
mjsunit = [current_path + [t] for t in self.Ls(self.root)]
regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
- all_tests = mjsunit + regress + bugs
+ tools = [current_path + ['tools', t] for t in self.Ls(join(self.root, 'tools'))]
+ all_tests = mjsunit + regress + bugs + tools
result = []
for test in all_tests:
if self.Contains(path, test):
diff --git a/v8/test/mjsunit/tools/codemap.js b/v8/test/mjsunit/tools/codemap.js
new file mode 100644
index 0000000..7f344a6
--- /dev/null
+++ b/v8/test/mjsunit/tools/codemap.js
@@ -0,0 +1,116 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Load Splay tree and CodeMap implementations from <project root>/tools.
+// Files: tools/splaytree.js tools/codemap.js
+
+
+function newCodeEntry(size, name) {
+ return new devtools.profiler.CodeMap.CodeEntry(size, name);
+};
+
+
+function assertEntry(codeMap, expected_name, addr) {
+ var entry = codeMap.findEntry(addr);
+ assertNotNull(entry, 'no entry at ' + addr.toString(16));
+ assertEquals(expected_name, entry.name, 'at ' + addr.toString(16));
+};
+
+
+function assertNoEntry(codeMap, addr) {
+ assertNull(codeMap.findEntry(addr), 'at ' + addr.toString(16));
+};
+
+
+(function testStaticCode() {
+ var codeMap = new devtools.profiler.CodeMap();
+ codeMap.addStaticCode(0x1500, newCodeEntry(0x3000, 'lib1'));
+ codeMap.addStaticCode(0x15500, newCodeEntry(0x5000, 'lib2'));
+ codeMap.addStaticCode(0x155500, newCodeEntry(0x10000, 'lib3'));
+ assertNoEntry(codeMap, 0);
+ assertNoEntry(codeMap, 0x1500 - 1);
+ assertEntry(codeMap, 'lib1', 0x1500);
+ assertEntry(codeMap, 'lib1', 0x1500 + 0x100);
+ assertEntry(codeMap, 'lib1', 0x1500 + 0x1000);
+ assertEntry(codeMap, 'lib1', 0x1500 + 0x3000 - 1);
+ assertNoEntry(codeMap, 0x1500 + 0x3000);
+ assertNoEntry(codeMap, 0x15500 - 1);
+ assertEntry(codeMap, 'lib2', 0x15500);
+ assertEntry(codeMap, 'lib2', 0x15500 + 0x100);
+ assertEntry(codeMap, 'lib2', 0x15500 + 0x1000);
+ assertEntry(codeMap, 'lib2', 0x15500 + 0x5000 - 1);
+ assertNoEntry(codeMap, 0x15500 + 0x5000);
+ assertNoEntry(codeMap, 0x155500 - 1);
+ assertEntry(codeMap, 'lib3', 0x155500);
+ assertEntry(codeMap, 'lib3', 0x155500 + 0x100);
+ assertEntry(codeMap, 'lib3', 0x155500 + 0x1000);
+ assertEntry(codeMap, 'lib3', 0x155500 + 0x10000 - 1);
+ assertNoEntry(codeMap, 0x155500 + 0x10000);
+ assertNoEntry(codeMap, 0xFFFFFFFF);
+})();
+
+
+(function testDynamicCode() {
+ var codeMap = new devtools.profiler.CodeMap();
+ codeMap.addCode(0x1500, newCodeEntry(0x200, 'code1'));
+ codeMap.addCode(0x1700, newCodeEntry(0x100, 'code2'));
+ codeMap.addCode(0x1900, newCodeEntry(0x50, 'code3'));
+ codeMap.addCode(0x1950, newCodeEntry(0x10, 'code4'));
+ assertNoEntry(codeMap, 0);
+ assertNoEntry(codeMap, 0x1500 - 1);
+ assertEntry(codeMap, 'code1', 0x1500);
+ assertEntry(codeMap, 'code1', 0x1500 + 0x100);
+ assertEntry(codeMap, 'code1', 0x1500 + 0x200 - 1);
+ assertEntry(codeMap, 'code2', 0x1700);
+ assertEntry(codeMap, 'code2', 0x1700 + 0x50);
+ assertEntry(codeMap, 'code2', 0x1700 + 0x100 - 1);
+ assertNoEntry(codeMap, 0x1700 + 0x100);
+ assertNoEntry(codeMap, 0x1900 - 1);
+ assertEntry(codeMap, 'code3', 0x1900);
+ assertEntry(codeMap, 'code3', 0x1900 + 0x28);
+ assertEntry(codeMap, 'code4', 0x1950);
+ assertEntry(codeMap, 'code4', 0x1950 + 0x7);
+ assertEntry(codeMap, 'code4', 0x1950 + 0x10 - 1);
+ assertNoEntry(codeMap, 0x1950 + 0x10);
+ assertNoEntry(codeMap, 0xFFFFFFFF);
+})();
+
+
+(function testCodeMovesAndDeletions() {
+ var codeMap = new devtools.profiler.CodeMap();
+ codeMap.addCode(0x1500, newCodeEntry(0x200, 'code1'));
+ codeMap.addCode(0x1700, newCodeEntry(0x100, 'code2'));
+ assertEntry(codeMap, 'code1', 0x1500);
+ assertEntry(codeMap, 'code2', 0x1700);
+ codeMap.moveCode(0x1500, 0x1800);
+ assertNoEntry(codeMap, 0x1500);
+ assertEntry(codeMap, 'code2', 0x1700);
+ assertEntry(codeMap, 'code1', 0x1800);
+ codeMap.deleteCode(0x1700);
+ assertNoEntry(codeMap, 0x1700);
+ assertEntry(codeMap, 'code1', 0x1800);
+})();
diff --git a/v8/test/mjsunit/tools/splaytree.js b/v8/test/mjsunit/tools/splaytree.js
new file mode 100644
index 0000000..3beba0b
--- /dev/null
+++ b/v8/test/mjsunit/tools/splaytree.js
@@ -0,0 +1,166 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Load the Splay tree implementation from <project root>/tools.
+// Files: tools/splaytree.js
+
+
+(function testIsEmpty() {
+ var tree = new goog.structs.SplayTree();
+ assertTrue(tree.isEmpty());
+ tree.insert(0, 'value');
+ assertFalse(tree.isEmpty());
+})();
+
+
+(function testExportValues() {
+ var tree = new goog.structs.SplayTree();
+ assertArrayEquals([], tree.exportValues());
+ tree.insert(0, 'value');
+ assertArrayEquals(['value'], tree.exportValues());
+ tree.insert(0, 'value');
+ assertArrayEquals(['value'], tree.exportValues());
+})();
+
+
+function createSampleTree() {
+ // Creates the following tree:
+ // 50
+ // / \
+ // 30 60
+ // / \ \
+ // 10 40 90
+ // \ / \
+ // 20 70 100
+ // / \
+ // 15 80
+ //
+ // We can't use the 'insert' method because it also uses 'splay_'.
+ return { key: 50, value: 50,
+ left: { key: 30, value: 30,
+ left: { key: 10, value: 10, left: null,
+ right: { key: 20, value: 20,
+ left: { key: 15, value: 15,
+ left: null, right: null },
+ right: null } },
+ right: { key: 40, value: 40, left: null, right: null } },
+ right: { key: 60, value: 60, left: null,
+ right: { key: 90, value: 90,
+ left: { key: 70, value: 70, left: null,
+ right: { key: 80, value: 80,
+ left: null, right: null } },
+ right: { key: 100, value: 100,
+ left: null, right: null } } } };
+};
+
+
+(function testSplay() {
+ var tree = new goog.structs.SplayTree();
+ tree.root_ = createSampleTree();
+ assertArrayEquals(['50', '30', '60', '10', '40', '90', '20', '70', '100', '15', '80'],
+ tree.exportValues());
+ tree.splay_(50);
+ assertArrayEquals(['50', '30', '60', '10', '40', '90', '20', '70', '100', '15', '80'],
+ tree.exportValues());
+ tree.splay_(80);
+ assertArrayEquals(['80', '60', '90', '50', '70', '100', '30', '10', '40', '20', '15'],
+ tree.exportValues());
+})();
+
+
+(function testInsert() {
+ var tree = new goog.structs.SplayTree();
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ assertArrayEquals(['left', 'root'], tree.exportValues());
+ tree.insert(7, 'right');
+ assertArrayEquals(['right', 'root', 'left'], tree.exportValues());
+})();
+
+
+(function testFind() {
+ var tree = new goog.structs.SplayTree();
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertEquals('root', tree.find(5).value);
+ assertEquals('left', tree.find(3).value);
+ assertEquals('right', tree.find(7).value);
+ assertEquals(null, tree.find(0));
+ assertEquals(null, tree.find(100));
+ assertEquals(null, tree.find(-100));
+})();
+
+
+(function testFindMin() {
+ var tree = new goog.structs.SplayTree();
+ assertEquals(null, tree.findMin());
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertEquals('left', tree.findMin().value);
+})();
+
+
+(function testFindMax() {
+ var tree = new goog.structs.SplayTree();
+ assertEquals(null, tree.findMax());
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertEquals('right', tree.findMax().value);
+})();
+
+
+(function testFindGreatestLessThan() {
+ var tree = new goog.structs.SplayTree();
+ assertEquals(null, tree.findGreatestLessThan(10));
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertEquals('right', tree.findGreatestLessThan(10).value);
+ assertEquals('right', tree.findGreatestLessThan(7).value);
+ assertEquals('root', tree.findGreatestLessThan(6).value);
+ assertEquals('left', tree.findGreatestLessThan(4).value);
+ assertEquals(null, tree.findGreatestLessThan(2));
+})();
+
+
+(function testRemove() {
+ var tree = new goog.structs.SplayTree();
+ assertThrows('tree.remove(5)');
+ tree.insert(5, 'root');
+ tree.insert(3, 'left');
+ tree.insert(7, 'right');
+ assertThrows('tree.remove(1)');
+ assertThrows('tree.remove(6)');
+ assertThrows('tree.remove(10)');
+ assertEquals('root', tree.remove(5).value);
+ assertEquals('left', tree.remove(3).value);
+ assertEquals('right', tree.remove(7).value);
+ assertArrayEquals([], tree.exportValues());
+})();
diff --git a/v8/tools/codemap.js b/v8/tools/codemap.js
new file mode 100644
index 0000000..f91d525
--- /dev/null
+++ b/v8/tools/codemap.js
@@ -0,0 +1,205 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Initlialize namespaces
+var devtools = devtools || {};
+devtools.profiler = devtools.profiler || {};
+
+
+/**
+ * Constructs a mapper that maps addresses into code entries.
+ *
+ * @constructor
+ */
+devtools.profiler.CodeMap = function() {
+ /**
+ * Dynamic code entries. Used for JIT compiled code.
+ */
+ this.dynamics_ = new goog.structs.SplayTree();
+
+ /**
+ * Deleted code entries. Used for code collected by the GC.
+ */
+ this.deleted_ = [];
+
+ /**
+ * Static code entries. Used for libraries code.
+ */
+ this.statics_ = new goog.structs.SplayTree();
+
+ /**
+ * Map of memory pages occupied with static code.
+ */
+ this.pages_ = [];
+};
+
+
+/**
+ * The number of alignment bits in a page address.
+ */
+devtools.profiler.CodeMap.PAGE_ALIGNMENT = 12;
+
+
+/**
+ * Page size in bytes.
+ */
+devtools.profiler.CodeMap.PAGE_SIZE =
+ 1 << devtools.profiler.CodeMap.PAGE_ALIGNMENT;
+
+
+/**
+ * Adds a dynamic (i.e. moveable and discardable) code entry.
+ *
+ * @param {number} start The starting address.
+ * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object.
+ */
+devtools.profiler.CodeMap.prototype.addCode = function(start, codeEntry) {
+ this.dynamics_.insert(start, codeEntry);
+};
+
+
+/**
+ * Moves a dynamic code entry. Throws an exception if there is no dynamic
+ * code entry with the specified starting address.
+ *
+ * @param {number} from The starting address of the entry being moved.
+ * @param {number} to The destination address.
+ */
+devtools.profiler.CodeMap.prototype.moveCode = function(from, to) {
+ var removedNode = this.dynamics_.remove(from);
+ this.dynamics_.insert(to, removedNode.value);
+};
+
+
+/**
+ * Discards a dynamic code entry. Throws an exception if there is no dynamic
+ * code entry with the specified starting address. The entry will still be
+ * returned from the 'getAllDynamicEntries' method.
+ *
+ * @param {number} start The starting address of the entry being deleted.
+ */
+devtools.profiler.CodeMap.prototype.deleteCode = function(start) {
+ var removedNode = this.dynamics_.remove(start);
+ this.deleted_.push(removedNode.value);
+};
+
+
+/**
+ * Adds a static code entry.
+ *
+ * @param {number} start The starting address.
+ * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object.
+ */
+devtools.profiler.CodeMap.prototype.addStaticCode = function(
+ start, codeEntry) {
+ this.markPages_(start, start + codeEntry.size);
+ this.statics_.insert(start, codeEntry);
+};
+
+
+/**
+ * @private
+ */
+devtools.profiler.CodeMap.prototype.markPages_ = function(start, end) {
+ for (var addr = start; addr <= end;
+ addr += devtools.profiler.CodeMap.PAGE_SIZE) {
+ this.pages_[addr >> devtools.profiler.CodeMap.PAGE_ALIGNMENT] = 1;
+ }
+};
+
+
+/**
+ * @private
+ */
+devtools.profiler.CodeMap.prototype.isAddressBelongsTo_ = function(addr, node) {
+ return addr >= node.key && addr < (node.key + node.value.size);
+};
+
+
+/**
+ * @private
+ */
+devtools.profiler.CodeMap.prototype.findInTree_ = function(tree, addr) {
+ var node = tree.findGreatestLessThan(addr);
+ return node && this.isAddressBelongsTo_(addr, node) ? node.value : null;
+};
+
+
+/**
+ * Finds a code entry that contains the specified address. Both static and
+ * dynamic code entries are considered.
+ *
+ * @param {number} addr Address.
+ */
+devtools.profiler.CodeMap.prototype.findEntry = function(addr) {
+ var pageAddr = addr >> devtools.profiler.CodeMap.PAGE_ALIGNMENT;
+ if (pageAddr in this.pages_) {
+ return this.findInTree_(this.statics_, addr);
+ }
+ var min = this.dynamics_.findMin();
+ var max = this.dynamics_.findMax();
+ if (max != null && addr < (max.key + max.value.size) && addr >= min.key) {
+ return this.findInTree_(this.dynamics_, addr);
+ }
+ return null;
+};
+
+
+/**
+ * Returns an array of all dynamic code entries, including deleted ones.
+ */
+devtools.profiler.CodeMap.prototype.getAllDynamicEntries = function() {
+ var dynamicEntries = this.dynamics_.exportValues();
+ return dynamicEntries.concat(this.deleted_);
+};
+
+
+/**
+ * Returns an array of all static code entries.
+ */
+devtools.profiler.CodeMap.prototype.getAllStaticEntries = function() {
+ return this.statics_.exportValues();
+};
+
+
+/**
+ * Creates a code entry object.
+ *
+ * @param {number} size Code entry size in bytes.
+ * @param {string} opt_name Code entry name.
+ * @constructor
+ */
+devtools.profiler.CodeMap.CodeEntry = function(size, opt_name) {
+ this.size = size;
+ this.name = opt_name || '';
+};
+
+
+devtools.profiler.CodeMap.CodeEntry.prototype.toString = function() {
+ return this.name + ': ' + this.size.toString(16);
+};
diff --git a/v8/tools/jsmin.pyc b/v8/tools/jsmin.pyc
new file mode 100644
index 0000000..341b5e1
--- /dev/null
+++ b/v8/tools/jsmin.pyc
Binary files differ
diff --git a/v8/tools/presubmit.py b/v8/tools/presubmit.py
index 27a3f2c..3e714de 100755
--- a/v8/tools/presubmit.py
+++ b/v8/tools/presubmit.py
@@ -35,6 +35,9 @@ import re
import sys
import subprocess
+# Disabled LINT rules and reason.
+# build/include_what_you_use: Started giving false positives for variables
+# named "string" and "map" assuming that you needed to include STL headers.
ENABLED_LINT_RULES = """
build/class
@@ -42,7 +45,6 @@ build/deprecated
build/endif_comment
build/forward_decl
build/include_order
-build/include_what_you_use
build/printf_format
build/storage_class
legal/copyright
diff --git a/v8/tools/splaytree.js b/v8/tools/splaytree.js
new file mode 100644
index 0000000..f3beb16
--- /dev/null
+++ b/v8/tools/splaytree.js
@@ -0,0 +1,321 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// A namespace stub. It will become more clear how to declare it properly
+// during integration of this script into Dev Tools.
+goog = { structs: {} };
+
+
+/**
+ * Constructs a Splay tree. A splay tree is a self-balancing binary
+ * search tree with the additional property that recently accessed
+ * elements are quick to access again. It performs basic operations
+ * such as insertion, look-up and removal in O(log(n)) amortized time.
+ *
+ * @constructor
+ */
+goog.structs.SplayTree = function() {
+};
+
+
+/**
+ * Pointer to the root node of the tree.
+ *
+ * @type {goog.structs.SplayTree.Node}
+ * @private
+ */
+goog.structs.SplayTree.prototype.root_ = null;
+
+
+/**
+ * @return {boolean} Whether the tree is empty.
+ */
+goog.structs.SplayTree.prototype.isEmpty = function() {
+ return !this.root_;
+};
+
+
+
+/**
+ * Inserts a node into the tree with the specified key and value if
+ * the tree does not already contain a node with the specified key. If
+ * the value is inserted, it becomes the root of the tree.
+ *
+ * @param {number} key Key to insert into the tree.
+ * @param {*} value Value to insert into the tree.
+ */
+goog.structs.SplayTree.prototype.insert = function(key, value) {
+ if (this.isEmpty()) {
+ this.root_ = new goog.structs.SplayTree.Node(key, value);
+ return;
+ }
+ // Splay on the key to move the last node on the search path for
+ // the key to the root of the tree.
+ this.splay_(key);
+ if (this.root_.key == key) {
+ return;
+ }
+ var node = new goog.structs.SplayTree.Node(key, value);
+ if (key > this.root_.key) {
+ node.left = this.root_;
+ node.right = this.root_.right;
+ this.root_.right = null;
+ } else {
+ node.right = this.root_;
+ node.left = this.root_.left;
+ this.root_.left = null;
+ }
+ this.root_ = node;
+};
+
+
+/**
+ * Removes a node with the specified key from the tree if the tree
+ * contains a node with this key. The removed node is returned. If the
+ * key is not found, an exception is thrown.
+ *
+ * @param {number} key Key to find and remove from the tree.
+ * @return {goog.structs.SplayTree.Node} The removed node.
+ */
+goog.structs.SplayTree.prototype.remove = function(key) {
+ if (this.isEmpty()) {
+ throw Error('Key not found: ' + key);
+ }
+ this.splay_(key);
+ if (this.root_.key != key) {
+ throw Error('Key not found: ' + key);
+ }
+ var removed = this.root_;
+ if (!this.root_.left) {
+ this.root_ = this.root_.right;
+ } else {
+ var right = this.root_.right;
+ this.root_ = this.root_.left;
+ // Splay to make sure that the new root has an empty right child.
+ this.splay_(key);
+ // Insert the original right child as the right child of the new
+ // root.
+ this.root_.right = right;
+ }
+ return removed;
+};
+
+
+/**
+ * Returns the node having the specified key or null if the tree doesn't contain
+ * a node with the specified key.
+ *
+ * @param {number} key Key to find in the tree.
+ * @return {goog.structs.SplayTree.Node} Node having the specified key.
+ */
+goog.structs.SplayTree.prototype.find = function(key) {
+ if (this.isEmpty()) {
+ return null;
+ }
+ this.splay_(key);
+ return this.root_.key == key ? this.root_ : null;
+};
+
+
+/**
+ * @return {goog.structs.SplayTree.Node} Node having the minimum key value.
+ */
+goog.structs.SplayTree.prototype.findMin = function() {
+ if (this.isEmpty()) {
+ return null;
+ }
+ var current = this.root_;
+ while (current.left) {
+ current = current.left;
+ }
+ return current;
+};
+
+
+/**
+ * @return {goog.structs.SplayTree.Node} Node having the maximum key value.
+ */
+goog.structs.SplayTree.prototype.findMax = function(opt_startNode) {
+ if (this.isEmpty()) {
+ return null;
+ }
+ var current = opt_startNode || this.root_;
+ while (current.right) {
+ current = current.right;
+ }
+ return current;
+};
+
+
+/**
+ * @return {goog.structs.SplayTree.Node} Node having the maximum key value that
+ * is less or equal to the specified key value.
+ */
+goog.structs.SplayTree.prototype.findGreatestLessThan = function(key) {
+ if (this.isEmpty()) {
+ return null;
+ }
+ // Splay on the key to move the node with the given key or the last
+ // node on the search path to the top of the tree.
+ this.splay_(key);
+ // Now the result is either the root node or the greatest node in
+ // the left subtree.
+ if (this.root_.key <= key) {
+ return this.root_;
+ } else if (this.root_.left) {
+ return this.findMax(this.root_.left);
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * @return {Array<*>} An array containing all the values of tree's nodes.
+ */
+goog.structs.SplayTree.prototype.exportValues = function() {
+ var result = [];
+ this.traverse_(function(node) { result.push(node.value); });
+ return result;
+};
+
+
+/**
+ * Perform the splay operation for the given key. Moves the node with
+ * the given key to the top of the tree. If no node has the given
+ * key, the last node on the search path is moved to the top of the
+ * tree. This is the simplified top-down splaying algorithm from:
+ * "Self-adjusting Binary Search Trees" by Sleator and Tarjan
+ *
+ * @param {number} key Key to splay the tree on.
+ * @private
+ */
+goog.structs.SplayTree.prototype.splay_ = function(key) {
+ if (this.isEmpty()) {
+ return;
+ }
+ // Create a dummy node. The use of the dummy node is a bit
+ // counter-intuitive: The right child of the dummy node will hold
+ // the L tree of the algorithm. The left child of the dummy node
+ // will hold the R tree of the algorithm. Using a dummy node, left
+ // and right will always be nodes and we avoid special cases.
+ var dummy, left, right;
+ dummy = left = right = new goog.structs.SplayTree.Node(null, null);
+ var current = this.root_;
+ while (true) {
+ if (key < current.key) {
+ if (!current.left) {
+ break;
+ }
+ if (key < current.left.key) {
+ // Rotate right.
+ var tmp = current.left;
+ current.left = tmp.right;
+ tmp.right = current;
+ current = tmp;
+ if (!current.left) {
+ break;
+ }
+ }
+ // Link right.
+ right.left = current;
+ right = current;
+ current = current.left;
+ } else if (key > current.key) {
+ if (!current.right) {
+ break;
+ }
+ if (key > current.right.key) {
+ // Rotate left.
+ var tmp = current.right;
+ current.right = tmp.left;
+ tmp.left = current;
+ current = tmp;
+ if (!current.right) {
+ break;
+ }
+ }
+ // Link left.
+ left.right = current;
+ left = current;
+ current = current.right;
+ } else {
+ break;
+ }
+ }
+ // Assemble.
+ left.right = current.left;
+ right.left = current.right;
+ current.left = dummy.right;
+ current.right = dummy.left;
+ this.root_ = current;
+};
+
+
+/**
+ * Performs a preorder traversal of the tree.
+ *
+ * @param {function(goog.structs.SplayTree.Node)} f Visitor function.
+ * @private
+ */
+goog.structs.SplayTree.prototype.traverse_ = function(f) {
+ var nodesToVisit = [this.root_];
+ while (nodesToVisit.length > 0) {
+ var node = nodesToVisit.shift();
+ if (node == null) {
+ continue;
+ }
+ f(node);
+ nodesToVisit.push(node.left);
+ nodesToVisit.push(node.right);
+ }
+};
+
+
+/**
+ * Constructs a Splay tree node.
+ *
+ * @param {number} key Key.
+ * @param {*} value Value.
+ */
+goog.structs.SplayTree.Node = function(key, value) {
+ this.key = key;
+ this.value = value;
+};
+
+
+/**
+ * @type {goog.structs.SplayTree.Node}
+ */
+goog.structs.SplayTree.Node.prototype.left = null;
+
+
+/**
+ * @type {goog.structs.SplayTree.Node}
+ */
+goog.structs.SplayTree.Node.prototype.right = null;
diff --git a/v8/tools/v8.xcodeproj/project.pbxproj b/v8/tools/v8.xcodeproj/project.pbxproj
index caa6b33..eba4ec7 100644
--- a/v8/tools/v8.xcodeproj/project.pbxproj
+++ b/v8/tools/v8.xcodeproj/project.pbxproj
@@ -202,6 +202,9 @@
89F23C9E0E78D5FD006B2466 /* macro-assembler-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1540E719B8F00D62E90 /* macro-assembler-arm.cc */; };
89F23C9F0E78D604006B2466 /* simulator-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF17D0E719B8F00D62E90 /* simulator-arm.cc */; };
89F23CA00E78D609006B2466 /* stub-cache-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */; };
+ 89FB0E3A0F8E533F00B04B3C /* d8-posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89FB0E360F8E531900B04B3C /* d8-posix.cc */; };
+ 9F92FAA90F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; };
+ 9F92FAAA0F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; };
9FC86ABD0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; };
9FC86ABE0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; };
/* End PBXBuildFile section */
@@ -517,6 +520,10 @@
89B12E8D0E7FF2A40080BA62 /* presubmit.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = presubmit.py; sourceTree = "<group>"; };
89F23C870E78D5B2006B2466 /* libv8-arm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libv8-arm.a"; sourceTree = BUILT_PRODUCTS_DIR; };
89F23C950E78D5B6006B2466 /* v8_shell-arm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "v8_shell-arm"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 89FB0E360F8E531900B04B3C /* d8-posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-posix.cc"; path = "../src/d8-posix.cc"; sourceTree = "<group>"; };
+ 89FB0E370F8E531900B04B3C /* d8-windows.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-windows.cc"; path = "../src/d8-windows.cc"; sourceTree = "<group>"; };
+ 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "func-name-inferrer.cc"; sourceTree = "<group>"; };
+ 9F92FAA80F8F28AD0089F02C /* func-name-inferrer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "func-name-inferrer.h"; sourceTree = "<group>"; };
9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "oprofile-agent.cc"; sourceTree = "<group>"; };
9FC86ABC0F5FEDAC00F22668 /* oprofile-agent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "oprofile-agent.h"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -689,6 +696,8 @@
897FF13B0E719B8F00D62E90 /* frames-inl.h */,
897FF13C0E719B8F00D62E90 /* frames.cc */,
897FF13D0E719B8F00D62E90 /* frames.h */,
+ 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */,
+ 9F92FAA80F8F28AD0089F02C /* func-name-inferrer.h */,
897FF13E0E719B8F00D62E90 /* global-handles.cc */,
897FF13F0E719B8F00D62E90 /* global-handles.h */,
897FF1400E719B8F00D62E90 /* globals.h */,
@@ -872,6 +881,8 @@
89A15C910EE46A1700B48DEB /* d8-readline.cc */,
893988150F2A3686007D5254 /* d8-debug.cc */,
893A72320F7B4AD700303DD2 /* d8-debug.h */,
+ 89FB0E360F8E531900B04B3C /* d8-posix.cc */,
+ 89FB0E370F8E531900B04B3C /* d8-windows.cc */,
89A15C920EE46A1700B48DEB /* d8.cc */,
89A15C930EE46A1700B48DEB /* d8.h */,
89A15C940EE46A1700B48DEB /* d8.js */,
@@ -1073,6 +1084,7 @@
8939880D0F2A362A007D5254 /* d8.cc in Sources */,
893988160F2A3688007D5254 /* d8-debug.cc in Sources */,
893988330F2A3B8F007D5254 /* d8-js.cc in Sources */,
+ 89FB0E3A0F8E533F00B04B3C /* d8-posix.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1111,6 +1123,7 @@
89A88E050E71A65D0043BA31 /* flags.cc in Sources */,
89A88E060E71A6600043BA31 /* frames-ia32.cc in Sources */,
89A88E070E71A6610043BA31 /* frames.cc in Sources */,
+ 9F92FAA90F8F28AD0089F02C /* func-name-inferrer.cc in Sources */,
89A88E080E71A6620043BA31 /* global-handles.cc in Sources */,
89A88E090E71A6640043BA31 /* handles.cc in Sources */,
89A88E0A0E71A6650043BA31 /* hashmap.cc in Sources */,
@@ -1211,6 +1224,7 @@
89F23C580E78D5B2006B2466 /* flags.cc in Sources */,
89F23C9C0E78D5F1006B2466 /* frames-arm.cc in Sources */,
89F23C5A0E78D5B2006B2466 /* frames.cc in Sources */,
+ 9F92FAAA0F8F28AD0089F02C /* func-name-inferrer.cc in Sources */,
89F23C5B0E78D5B2006B2466 /* global-handles.cc in Sources */,
89F23C5C0E78D5B2006B2466 /* handles.cc in Sources */,
89F23C5D0E78D5B2006B2466 /* hashmap.cc in Sources */,
diff --git a/v8/tools/visual_studio/common.vsprops b/v8/tools/visual_studio/common.vsprops
index 7e18f17..f131a4a 100644
--- a/v8/tools/visual_studio/common.vsprops
+++ b/v8/tools/visual_studio/common.vsprops
@@ -10,7 +10,7 @@
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="$(ProjectDir)\..\..\src;$(IntDir)\DerivedSources"
- PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_USE_32BIT_TIME_T;_HAS_EXCEPTIONS=0;PCRE_STATIC;ENABLE_LOGGING_AND_PROFILING"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_USE_32BIT_TIME_T;_HAS_EXCEPTIONS=0;ENABLE_LOGGING_AND_PROFILING"
MinimalRebuild="false"
ExceptionHandling="0"
RuntimeTypeInfo="false"
diff --git a/v8/tools/visual_studio/v8_base.vcproj b/v8/tools/visual_studio/v8_base.vcproj
index 81e1f09..776e628 100644
--- a/v8/tools/visual_studio/v8_base.vcproj
+++ b/v8/tools/visual_studio/v8_base.vcproj
@@ -417,6 +417,14 @@
>
</File>
<File
+ RelativePath="..\..\src\func-name-inferrer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\func-name-inferrer.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\global-handles.cc"
>
</File>
diff --git a/v8/tools/visual_studio/v8_base_arm.vcproj b/v8/tools/visual_studio/v8_base_arm.vcproj
index a03306d..a91d63a 100644
--- a/v8/tools/visual_studio/v8_base_arm.vcproj
+++ b/v8/tools/visual_studio/v8_base_arm.vcproj
@@ -413,6 +413,14 @@
>
</File>
<File
+ RelativePath="..\..\src\func-name-inferrer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\func-name-inferrer.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\global-handles.cc"
>
</File>
diff --git a/v8/tools/visual_studio/v8_cctest.vcproj b/v8/tools/visual_studio/v8_cctest.vcproj
index 859e445..5d49d24 100644
--- a/v8/tools/visual_studio/v8_cctest.vcproj
+++ b/v8/tools/visual_studio/v8_cctest.vcproj
@@ -186,6 +186,10 @@
>
</File>
<File
+ RelativePath="..\..\test\cctest\test-func-name-inference.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\test\cctest\test-hashmap.cc"
>
</File>