summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deps/v8/.gitignore1
-rw-r--r--deps/v8/ChangeLog28
-rw-r--r--deps/v8/include/v8.h18
-rw-r--r--deps/v8/src/api.cc12
-rw-r--r--deps/v8/src/apinatives.js14
-rw-r--r--deps/v8/src/arm/code-stubs-arm.cc68
-rw-r--r--deps/v8/src/arm/deoptimizer-arm.cc2
-rw-r--r--deps/v8/src/arm/frames-arm.h11
-rw-r--r--deps/v8/src/arm/full-codegen-arm.cc16
-rw-r--r--deps/v8/src/arm/lithium-arm.cc20
-rw-r--r--deps/v8/src/arm/lithium-arm.h23
-rw-r--r--deps/v8/src/arm/lithium-codegen-arm.cc108
-rw-r--r--deps/v8/src/arm/macro-assembler-arm.cc86
-rw-r--r--deps/v8/src/arm/stub-cache-arm.cc46
-rw-r--r--deps/v8/src/ast-inl.h3
-rw-r--r--deps/v8/src/ast.cc2
-rw-r--r--deps/v8/src/ast.h22
-rw-r--r--deps/v8/src/bootstrapper.cc11
-rw-r--r--deps/v8/src/code-stubs.cc20
-rw-r--r--deps/v8/src/code-stubs.h6
-rwxr-xr-xdeps/v8/src/compiler.cc10
-rw-r--r--deps/v8/src/contexts.cc23
-rw-r--r--deps/v8/src/contexts.h4
-rw-r--r--deps/v8/src/d8.cc1
-rw-r--r--deps/v8/src/d8.h4
-rw-r--r--deps/v8/src/d8.js3
-rw-r--r--deps/v8/src/disassembler.cc36
-rw-r--r--deps/v8/src/elements.cc80
-rw-r--r--deps/v8/src/elements.h4
-rw-r--r--deps/v8/src/extensions/experimental/datetime-format.cc2
-rw-r--r--deps/v8/src/factory.cc22
-rw-r--r--deps/v8/src/factory.h7
-rw-r--r--deps/v8/src/flag-definitions.h2
-rw-r--r--deps/v8/src/frames-inl.h9
-rw-r--r--deps/v8/src/frames.h3
-rw-r--r--deps/v8/src/full-codegen.cc96
-rw-r--r--deps/v8/src/full-codegen.h53
-rw-r--r--deps/v8/src/heap.cc43
-rw-r--r--deps/v8/src/heap.h14
-rw-r--r--deps/v8/src/hydrogen-instructions.cc37
-rw-r--r--deps/v8/src/hydrogen-instructions.h36
-rw-r--r--deps/v8/src/hydrogen.cc37
-rw-r--r--deps/v8/src/hydrogen.h3
-rw-r--r--deps/v8/src/ia32/assembler-ia32.cc12
-rw-r--r--deps/v8/src/ia32/assembler-ia32.h10
-rw-r--r--deps/v8/src/ia32/code-stubs-ia32.cc80
-rw-r--r--deps/v8/src/ia32/disasm-ia32.cc12
-rw-r--r--deps/v8/src/ia32/frames-ia32.h11
-rw-r--r--deps/v8/src/ia32/full-codegen-ia32.cc17
-rw-r--r--deps/v8/src/ia32/lithium-codegen-ia32.cc162
-rw-r--r--deps/v8/src/ia32/lithium-codegen-ia32.h2
-rw-r--r--deps/v8/src/ia32/lithium-ia32.cc26
-rw-r--r--deps/v8/src/ia32/lithium-ia32.h33
-rw-r--r--deps/v8/src/ia32/macro-assembler-ia32.cc53
-rw-r--r--deps/v8/src/ia32/stub-cache-ia32.cc97
-rw-r--r--deps/v8/src/isolate.cc6
-rw-r--r--deps/v8/src/liveobjectlist.cc194
-rw-r--r--deps/v8/src/liveobjectlist.h4
-rw-r--r--deps/v8/src/messages.js1
-rw-r--r--deps/v8/src/mips/frames-mips.h9
-rw-r--r--deps/v8/src/mips/full-codegen-mips.cc10
-rw-r--r--deps/v8/src/mips/macro-assembler-mips.cc92
-rw-r--r--deps/v8/src/mips/stub-cache-mips.cc10
-rw-r--r--deps/v8/src/mirror-debugger.js3
-rw-r--r--deps/v8/src/mksnapshot.cc2
-rw-r--r--deps/v8/src/objects-inl.h22
-rw-r--r--deps/v8/src/objects.cc39
-rw-r--r--deps/v8/src/objects.h49
-rw-r--r--deps/v8/src/parser.cc282
-rw-r--r--deps/v8/src/parser.h22
-rw-r--r--deps/v8/src/platform-linux.cc2
-rw-r--r--deps/v8/src/preparser-api.cc1
-rw-r--r--deps/v8/src/preparser.cc56
-rw-r--r--deps/v8/src/preparser.h18
-rw-r--r--deps/v8/src/prettyprinter.cc19
-rw-r--r--deps/v8/src/rewriter.cc10
-rw-r--r--deps/v8/src/runtime-profiler.h6
-rw-r--r--deps/v8/src/runtime.cc83
-rw-r--r--deps/v8/src/runtime.h1
-rw-r--r--deps/v8/src/scanner-base.cc136
-rw-r--r--deps/v8/src/scanner-base.h11
-rw-r--r--deps/v8/src/scopeinfo.cc2
-rw-r--r--deps/v8/src/scopeinfo.h2
-rw-r--r--deps/v8/src/scopes.cc66
-rw-r--r--deps/v8/src/scopes.h12
-rw-r--r--deps/v8/src/serialize.cc58
-rw-r--r--deps/v8/src/serialize.h47
-rw-r--r--deps/v8/src/token.h1
-rw-r--r--deps/v8/src/variables.cc3
-rw-r--r--deps/v8/src/variables.h13
-rw-r--r--deps/v8/src/version.cc4
-rw-r--r--deps/v8/src/weakmap.js11
-rw-r--r--deps/v8/src/x64/code-stubs-x64.cc78
-rw-r--r--deps/v8/src/x64/frames-x64.h13
-rw-r--r--deps/v8/src/x64/full-codegen-x64.cc16
-rw-r--r--deps/v8/src/x64/lithium-codegen-x64.cc129
-rw-r--r--deps/v8/src/x64/lithium-codegen-x64.h2
-rw-r--r--deps/v8/src/x64/lithium-x64.cc27
-rw-r--r--deps/v8/src/x64/lithium-x64.h33
-rw-r--r--deps/v8/src/x64/macro-assembler-x64.cc69
-rw-r--r--deps/v8/src/x64/stub-cache-x64.cc4
-rw-r--r--deps/v8/src/zone.cc53
-rw-r--r--deps/v8/src/zone.h6
-rw-r--r--deps/v8/test/cctest/test-accessors.cc2
-rw-r--r--deps/v8/test/cctest/test-api.cc113
-rw-r--r--deps/v8/test/cctest/test-circular-queue.cc2
-rw-r--r--deps/v8/test/cctest/test-cpu-profiler.cc2
-rw-r--r--deps/v8/test/cctest/test-heap-profiler.cc2
-rw-r--r--deps/v8/test/cctest/test-lockers.cc4
-rw-r--r--deps/v8/test/cctest/test-log-stack-tracer.cc2
-rw-r--r--deps/v8/test/cctest/test-log.cc2
-rwxr-xr-xdeps/v8/test/cctest/test-parsing.cc8
-rw-r--r--deps/v8/test/cctest/test-profile-generator.cc2
-rw-r--r--deps/v8/test/cctest/test-unbound-queue.cc2
-rw-r--r--deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js224
-rw-r--r--deps/v8/test/mjsunit/external-array.js20
-rw-r--r--deps/v8/test/mjsunit/fuzz-natives.js1
-rw-r--r--deps/v8/test/mjsunit/harmony/block-lazy-compile.js50
-rw-r--r--deps/v8/test/mjsunit/harmony/block-let-declaration.js67
-rw-r--r--deps/v8/test/mjsunit/harmony/block-scoping.js216
-rw-r--r--deps/v8/test/mjsunit/harmony/debug-blockscopes.js389
-rw-r--r--deps/v8/test/mjsunit/harmony/debug-evaluate-blockscopes.js64
-rw-r--r--deps/v8/test/mjsunit/harmony/typeof.js35
-rw-r--r--deps/v8/test/mjsunit/harmony/weakmaps.js17
-rw-r--r--deps/v8/test/mjsunit/math-floor.js34
-rw-r--r--deps/v8/test/mjsunit/math-round.js25
-rw-r--r--deps/v8/test/mjsunit/regress/regress-1592.js45
-rw-r--r--deps/v8/test/mjsunit/with-leave.js161
-rw-r--r--deps/v8/tools/gyp/v8.gyp1
129 files changed, 3261 insertions, 1527 deletions
diff --git a/deps/v8/.gitignore b/deps/v8/.gitignore
index d09889b90..253639dc5 100644
--- a/deps/v8/.gitignore
+++ b/deps/v8/.gitignore
@@ -21,6 +21,7 @@ shell
shell_g
/build/gyp
/obj/
+/out/
/test/es5conform/data/
/test/mozilla/data/
/test/sputnik/sputniktests/
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog
index d05b70eae..6d188b89d 100644
--- a/deps/v8/ChangeLog
+++ b/deps/v8/ChangeLog
@@ -1,3 +1,31 @@
+2011-08-17: Version 3.5.6
+
+ Fixed issue that could cause crashes when running with --heap-stats.
+
+ Fixed compilation on Linux 2.6.9 and older.
+
+ Fixed live-object-list to work with isolates.
+
+ Fixed memory leaks in zones and isolates.
+
+ Fixed a performance regression for TypedArrays on x64.
+
+ Stability improvements on all platforms.
+
+
+2011-08-15: Version 3.5.5
+
+ Fixed bugs involving negative zero and the optimizing compiler.
+
+ Fixed optimized version of Function.apply(x, arguments). (issue 1592)
+
+ Eliminated uses of deprecated ARM instructions.
+
+ Sped up Math.floor by using SSE 4.1 roundsd instruction on ia32.
+
+ Removed restriction on the size of disassembled code that is printed.
+
+
2011-08-10: Version 3.5.4
Added a preliminary implementation of ES Harmony weak maps. Weak
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h
index d1bceca3f..e722d34e6 100644
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -171,12 +171,12 @@ template <class T> class Handle {
/**
* Creates an empty handle.
*/
- inline Handle();
+ inline Handle() : val_(0) {}
/**
* Creates a new handle for the specified value.
*/
- inline explicit Handle(T* val) : val_(val) { }
+ inline explicit Handle(T* val) : val_(val) {}
/**
* Creates a handle for the contents of the specified handle. This
@@ -203,14 +203,14 @@ template <class T> class Handle {
*/
inline bool IsEmpty() const { return val_ == 0; }
- inline T* operator->() const { return val_; }
-
- inline T* operator*() const { return val_; }
-
/**
* Sets the handle to be empty. IsEmpty() will then return true.
*/
- inline void Clear() { this->val_ = 0; }
+ inline void Clear() { val_ = 0; }
+
+ inline T* operator->() const { return val_; }
+
+ inline T* operator*() const { return val_; }
/**
* Checks whether two handles are the same.
@@ -3827,10 +3827,6 @@ class Internals {
template <class T>
-Handle<T>::Handle() : val_(0) { }
-
-
-template <class T>
Local<T>::Local() : Handle<T>() { }
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index 7355cd61c..5a5f14dc6 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -35,6 +35,7 @@
#include "debug.h"
#include "deoptimizer.h"
#include "execution.h"
+#include "flags.h"
#include "global-handles.h"
#include "heap-profiler.h"
#include "messages.h"
@@ -1405,7 +1406,7 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
ScriptData* ScriptData::PreCompile(const char* input, int length) {
i::Utf8ToUC16CharacterStream stream(
reinterpret_cast<const unsigned char*>(input), length);
- return i::ParserApi::PreParse(&stream, NULL);
+ return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping);
}
@@ -1414,10 +1415,10 @@ ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
if (str->IsExternalTwoByteString()) {
i::ExternalTwoByteStringUC16CharacterStream stream(
i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length());
- return i::ParserApi::PreParse(&stream, NULL);
+ return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping);
} else {
i::GenericStringUC16CharacterStream stream(str, 0, str->length());
- return i::ParserApi::PreParse(&stream, NULL);
+ return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping);
}
}
@@ -3163,10 +3164,9 @@ static i::Context* GetCreationContext(i::JSObject* object) {
i::Object* constructor = object->map()->constructor();
i::JSFunction* function;
if (!constructor->IsJSFunction()) {
- // API functions have null as a constructor,
+ // Functions have null as a constructor,
// but any JSFunction knows its context immediately.
- ASSERT(object->IsJSFunction() &&
- i::JSFunction::cast(object)->shared()->IsApiFunction());
+ ASSERT(object->IsJSFunction());
function = i::JSFunction::cast(object);
} else {
function = i::JSFunction::cast(constructor);
diff --git a/deps/v8/src/apinatives.js b/deps/v8/src/apinatives.js
index c00195d83..e94da9f06 100644
--- a/deps/v8/src/apinatives.js
+++ b/deps/v8/src/apinatives.js
@@ -49,7 +49,10 @@ function Instantiate(data, name) {
return InstantiateFunction(data, name);
case kNewObjectTag:
var Constructor = %GetTemplateField(data, kApiConstructorOffset);
- var result = Constructor ? new (Instantiate(Constructor))() : {};
+ // Note: Do not directly use a function template as a condition, our
+ // internal ToBoolean doesn't handle that!
+ var result = typeof Constructor === 'undefined' ?
+ {} : new (Instantiate(Constructor))();
ConfigureTemplateInstance(result, data);
result = %ToFastProperties(result);
return result;
@@ -74,13 +77,18 @@ function InstantiateFunction(data, name) {
cache[serialNumber] = fun;
var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset);
var flags = %GetTemplateField(data, kApiFlagOffset);
- fun.prototype = prototype ? Instantiate(prototype) : {};
+ // Note: Do not directly use an object template as a condition, our
+ // internal ToBoolean doesn't handle that!
+ fun.prototype = typeof prototype === 'undefined' ?
+ {} : Instantiate(prototype);
if (flags & (1 << kReadOnlyPrototypeBit)) {
%FunctionSetReadOnlyPrototype(fun);
}
%SetProperty(fun.prototype, "constructor", fun, DONT_ENUM);
var parent = %GetTemplateField(data, kApiParentTemplateOffset);
- if (parent) {
+ // Note: Do not directly use a function template as a condition, our
+ // internal ToBoolean doesn't handle that!
+ if (!(typeof parent === 'undefined')) {
var parent_fun = Instantiate(parent);
fun.prototype.__proto__ = parent_fun.prototype;
}
diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc
index 161421e34..82fa8ceaf 100644
--- a/deps/v8/src/arm/code-stubs-arm.cc
+++ b/deps/v8/src/arm/code-stubs-arm.cc
@@ -1613,14 +1613,14 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
const Register map = r9.is(tos_) ? r7 : r9;
// undefined -> false.
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
+ CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value.
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
+ CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
+ CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
+ CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true
@@ -1635,12 +1635,13 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
if (types_.NeedsMap()) {
__ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
- __ tst(ip, Operand(1 << Map::kIsUndetectable));
- // Undetectable -> false.
- __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
- __ Ret(ne);
+ if (types_.CanBeUndetectable()) {
+ __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
+ __ tst(ip, Operand(1 << Map::kIsUndetectable));
+ // Undetectable -> false.
+ __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+ __ Ret(ne);
+ }
}
if (types_.Contains(SPEC_OBJECT)) {
@@ -1648,10 +1649,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
// tos_ contains the correct non-zero return value already.
__ Ret(ge);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> patch.
- __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
- __ b(ge, &patch);
}
if (types_.Contains(STRING)) {
@@ -1659,10 +1656,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
__ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
__ Ret(lt); // the string length is OK as the return value
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> patch
- __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
- __ b(lt, &patch);
}
if (types_.Contains(HEAP_NUMBER)) {
@@ -1679,30 +1672,17 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN
__ Ret();
__ bind(&not_heap_number);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> patch
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- __ b(eq, &patch);
- }
-
- if (types_.Contains(INTERNAL_OBJECT)) {
- // Internal objects -> true.
- __ mov(tos_, Operand(1, RelocInfo::NONE));
- __ Ret();
}
- if (!types_.IsAll()) {
- __ bind(&patch);
- GenerateTypeTransition(masm);
- }
+ __ bind(&patch);
+ GenerateTypeTransition(masm);
}
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
- bool result,
- Label* patch) {
+ bool result) {
if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_.
__ LoadRoot(ip, value);
@@ -1713,12 +1693,6 @@ void ToBooleanStub::CheckOddball(MacroAssembler* masm,
__ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq);
}
__ Ret(eq);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // If we see an unexpected oddball and handle internal objects, we must
- // patch because the code for internal objects doesn't handle it explictly.
- __ LoadRoot(ip, value);
- __ cmp(tos_, ip);
- __ b(eq, patch);
}
}
@@ -6341,12 +6315,8 @@ void DirectCEntryStub::Generate(MacroAssembler* masm) {
void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
ExternalReference function) {
- __ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()),
- RelocInfo::CODE_TARGET));
__ mov(r2, Operand(function));
- // Push return address (accessible to GC through exit frame pc).
- __ str(pc, MemOperand(sp, 0));
- __ Jump(r2); // Call the api function.
+ GenerateCall(masm, r2);
}
@@ -6355,8 +6325,14 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
__ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()),
RelocInfo::CODE_TARGET));
// Push return address (accessible to GC through exit frame pc).
- __ str(pc, MemOperand(sp, 0));
+ // Note that using pc with str is deprecated.
+ Label start;
+ __ bind(&start);
+ __ add(ip, pc, Operand(Assembler::kInstrSize));
+ __ str(ip, MemOperand(sp, 0));
__ Jump(target); // Call the C++ function.
+ ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta,
+ masm->SizeOfCodeGeneratedSince(&start));
}
diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc
index 9d9c045ff..00357f76d 100644
--- a/deps/v8/src/arm/deoptimizer-arm.cc
+++ b/deps/v8/src/arm/deoptimizer-arm.cc
@@ -593,6 +593,8 @@ void Deoptimizer::EntryGenerator::Generate() {
__ vstm(db_w, sp, first, last);
// Push all 16 registers (needed to populate FrameDescription::registers_).
+ // TODO(1588) Note that using pc with stm is deprecated, so we should perhaps
+ // handle this a bit differently.
__ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit());
const int kSavedRegistersAreaSize =
diff --git a/deps/v8/src/arm/frames-arm.h b/deps/v8/src/arm/frames-arm.h
index 84e108b3d..26bbd82d0 100644
--- a/deps/v8/src/arm/frames-arm.h
+++ b/deps/v8/src/arm/frames-arm.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -93,10 +93,11 @@ static const int kNumSafepointSavedRegisters =
class StackHandlerConstants : public AllStatic {
public:
- static const int kNextOffset = 0 * kPointerSize;
- static const int kStateOffset = 1 * kPointerSize;
- static const int kFPOffset = 2 * kPointerSize;
- static const int kPCOffset = 3 * kPointerSize;
+ static const int kNextOffset = 0 * kPointerSize;
+ static const int kStateOffset = 1 * kPointerSize;
+ static const int kContextOffset = 2 * kPointerSize;
+ static const int kFPOffset = 3 * kPointerSize;
+ static const int kPCOffset = 4 * kPointerSize;
static const int kSize = kPCOffset + kPointerSize;
};
diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc
index cdfc0a9ac..3116ca455 100644
--- a/deps/v8/src/arm/full-codegen-arm.cc
+++ b/deps/v8/src/arm/full-codegen-arm.cc
@@ -742,9 +742,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ mov(r2, Operand(variable->name()));
// Declaration nodes are always introduced in one of two modes.
ASSERT(mode == Variable::VAR ||
- mode == Variable::CONST);
- PropertyAttributes attr =
- (mode == Variable::VAR) ? NONE : READ_ONLY;
+ mode == Variable::CONST ||
+ mode == Variable::LET);
+ PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
__ mov(r1, Operand(Smi::FromInt(attr)));
// Push initial value, if any.
// Note: For variables we must not push an initial value (such as
@@ -4030,6 +4030,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
__ b(eq, if_true);
__ CompareRoot(r0, Heap::kFalseValueRootIndex);
Split(eq, if_true, if_false, fall_through);
+ } else if (FLAG_harmony_typeof &&
+ check->Equals(isolate()->heap()->null_symbol())) {
+ __ CompareRoot(r0, Heap::kNullValueRootIndex);
+ Split(eq, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
__ b(eq, if_true);
@@ -4047,8 +4051,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
} else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(r0, if_false);
- __ CompareRoot(r0, Heap::kNullValueRootIndex);
- __ b(eq, if_true);
+ if (!FLAG_harmony_typeof) {
+ __ CompareRoot(r0, Heap::kNullValueRootIndex);
+ __ b(eq, if_true);
+ }
// Check for JS objects => true.
__ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(lt, if_false);
diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc
index 1eb4aff2b..65ef3e6e1 100644
--- a/deps/v8/src/arm/lithium-arm.cc
+++ b/deps/v8/src/arm/lithium-arm.cc
@@ -1039,13 +1039,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
: instr->SecondSuccessor();
return new LGoto(successor->block_id());
}
- LInstruction* branch = new LBranch(UseRegister(v));
- // When we handle all cases, we never deopt, so we don't need to assign the
- // environment then. Note that we map the "empty" case to the "all" case in
- // the code generator.
- ToBooleanStub::Types types = instr->expected_input_types();
- bool all_cases_handled = types.IsAll() || types.IsEmpty();
- return all_cases_handled ? branch : AssignEnvironment(branch);
+ return AssignEnvironment(new LBranch(UseRegister(v)));
}
@@ -1515,16 +1509,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
-LInstruction* LChunkBuilder::DoExternalArrayLength(
- HExternalArrayLength* instr) {
+LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
+ HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LExternalArrayLength(array));
-}
-
-
-LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
- LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LFixedArrayLength(array));
+ return DefineAsRegister(new LFixedArrayBaseLength(array));
}
diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h
index 70c348de6..3632c8cf4 100644
--- a/deps/v8/src/arm/lithium-arm.h
+++ b/deps/v8/src/arm/lithium-arm.h
@@ -92,8 +92,7 @@ class LCodeGen;
V(DivI) \
V(DoubleToI) \
V(ElementsKind) \
- V(ExternalArrayLength) \
- V(FixedArrayLength) \
+ V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
@@ -915,25 +914,15 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
};
-class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
+class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LExternalArrayLength(LOperand* value) {
+ explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value;
}
- DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
- DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
-};
-
-
-class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LFixedArrayLength(LOperand* value) {
- inputs_[0] = value;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
- DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
+ DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
+ "fixed-array-base-length")
+ DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
};
diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc
index 3f3f31acc..4e135d66b 100644
--- a/deps/v8/src/arm/lithium-codegen-arm.cc
+++ b/deps/v8/src/arm/lithium-codegen-arm.cc
@@ -1378,17 +1378,10 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
}
-void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
+void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
- __ ldr(result, FieldMemOperand(array, ExternalArray::kLengthOffset));
-}
-
-
-void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
- Register result = ToRegister(instr->result());
- Register array = ToRegister(instr->InputAt(0));
- __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset));
+ __ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset));
}
@@ -1583,46 +1576,18 @@ void LCodeGen::DoBranch(LBranch* instr) {
// undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ b(eq, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen undefined for the first time -> deopt.
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// Boolean -> its value.
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ b(eq, true_label);
__ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ b(eq, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ CompareRoot(reg, Heap::kTrueValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
- __ CompareRoot(reg, Heap::kFalseValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
}
-
-#if 0
- if (expected.Contains(ToBooleanStub::BOOLEAN)) {
- // false -> false.
- __ CompareRoot(reg, Heap::kFalseValueRootIndex);
- __ b(eq, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ CompareRoot(reg, Heap::kFalseValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
- }
-#endif
-
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex);
__ b(eq, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen null for the first time -> deopt.
- __ CompareRoot(reg, Heap::kNullValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
}
if (expected.Contains(ToBooleanStub::SMI)) {
@@ -1639,20 +1604,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
const Register map = scratch0();
if (expected.NeedsMap()) {
__ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
- __ tst(ip, Operand(1 << Map::kIsUndetectable));
- __ b(ne, false_label);
+
+ if (expected.CanBeUndetectable()) {
+ // Undetectable -> false.
+ __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
+ __ tst(ip, Operand(1 << Map::kIsUndetectable));
+ __ b(ne, false_label);
+ }
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true.
__ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
__ b(ge, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> deopt.
- __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
- DeoptimizeIf(ge, instr->environment());
}
if (expected.Contains(ToBooleanStub::STRING)) {
@@ -1665,10 +1629,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ b(ne, true_label);
__ b(false_label);
__ bind(&not_string);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> deopt
- __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
- DeoptimizeIf(lt, instr->environment());
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@@ -1683,19 +1643,10 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ b(eq, false_label); // +0, -0 -> false.
__ b(true_label);
__ bind(&not_heap_number);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> deopt.
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- DeoptimizeIf(eq, instr->environment());
}
- if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // internal objects -> true
- __ b(true_label);
- } else {
- // We've seen something for the first time -> deopt.
- DeoptimizeIf(al, instr->environment());
- }
+ // We've seen something for the first time -> deopt.
+ DeoptimizeIf(al, instr->environment());
}
}
}
@@ -3014,19 +2965,18 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
- Register scratch1 = result;
- Register scratch2 = scratch0();
+ Register scratch = scratch0();
Label done, check_sign_on_zero;
// Extract exponent bits.
- __ vmov(scratch1, input.high());
- __ ubfx(scratch2,
- scratch1,
+ __ vmov(result, input.high());
+ __ ubfx(scratch,
+ result,
HeapNumber::kExponentShift,
HeapNumber::kExponentBits);
// If the number is in ]-0.5, +0.5[, the result is +/- 0.
- __ cmp(scratch2, Operand(HeapNumber::kExponentBias - 2));
+ __ cmp(scratch, Operand(HeapNumber::kExponentBias - 2));
__ mov(result, Operand(0), LeaveCC, le);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ b(le, &check_sign_on_zero);
@@ -3036,19 +2986,19 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
// The following conversion will not work with numbers
// outside of ]-2^32, 2^32[.
- __ cmp(scratch2, Operand(HeapNumber::kExponentBias + 32));
+ __ cmp(scratch, Operand(HeapNumber::kExponentBias + 32));
DeoptimizeIf(ge, instr->environment());
// Save the original sign for later comparison.
- __ and_(scratch2, scratch1, Operand(HeapNumber::kSignMask));
+ __ and_(scratch, result, Operand(HeapNumber::kSignMask));
__ Vmov(double_scratch0(), 0.5);
__ vadd(input, input, double_scratch0());
// Check sign of the result: if the sign changed, the input
// value was in ]0.5, 0[ and the result should be -0.
- __ vmov(scratch1, input.high());
- __ eor(scratch1, scratch1, Operand(scratch2), SetCC);
+ __ vmov(result, input.high());
+ __ eor(result, result, Operand(scratch), SetCC);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(mi, instr->environment());
} else {
@@ -3059,8 +3009,8 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
__ EmitVFPTruncate(kRoundToMinusInf,
double_scratch0().low(),
input,
- scratch1,
- scratch2);
+ result,
+ scratch);
DeoptimizeIf(ne, instr->environment());
__ vmov(result, double_scratch0().low());
@@ -3069,8 +3019,8 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
__ cmp(result, Operand(0));
__ b(ne, &done);
__ bind(&check_sign_on_zero);
- __ vmov(scratch1, input.high());
- __ tst(scratch1, Operand(HeapNumber::kSignMask));
+ __ vmov(scratch, input.high());
+ __ tst(scratch, Operand(HeapNumber::kSignMask));
DeoptimizeIf(ne, instr->environment());
}
__ bind(&done);
@@ -4395,6 +4345,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
__ CompareRoot(input, Heap::kFalseValueRootIndex);
final_branch_condition = eq;
+ } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
+ __ CompareRoot(input, Heap::kNullValueRootIndex);
+ final_branch_condition = eq;
+
} else if (type_name->Equals(heap()->undefined_symbol())) {
__ CompareRoot(input, Heap::kUndefinedValueRootIndex);
__ b(eq, true_label);
@@ -4413,8 +4367,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
} else if (type_name->Equals(heap()->object_symbol())) {
__ JumpIfSmi(input, false_label);
- __ CompareRoot(input, Heap::kNullValueRootIndex);
- __ b(eq, true_label);
+ if (!FLAG_harmony_typeof) {
+ __ CompareRoot(input, Heap::kNullValueRootIndex);
+ __ b(eq, true_label);
+ }
__ CompareObjectType(input, input, scratch,
FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(lt, false_label);
diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc
index c34a57920..88477bb7f 100644
--- a/deps/v8/src/arm/macro-assembler-arm.cc
+++ b/deps/v8/src/arm/macro-assembler-arm.cc
@@ -1102,7 +1102,13 @@ void MacroAssembler::DebugBreak() {
void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) {
// Adjust this code if not the case.
- ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
+
// The pc (return address) is passed in register lr.
if (try_location == IN_JAVASCRIPT) {
if (type == TRY_CATCH_HANDLER) {
@@ -1110,14 +1116,10 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
} else {
mov(r3, Operand(StackHandler::TRY_FINALLY));
}
- ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize
- && StackHandlerConstants::kFPOffset == 2 * kPointerSize
- && StackHandlerConstants::kPCOffset == 3 * kPointerSize);
- stm(db_w, sp, r3.bit() | fp.bit() | lr.bit());
+ stm(db_w, sp, r3.bit() | cp.bit() | fp.bit() | lr.bit());
// Save the current handler as the next handler.
mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(r1, MemOperand(r3));
- ASSERT(StackHandlerConstants::kNextOffset == 0);
push(r1);
// Link this handler as the new current one.
str(sp, MemOperand(r3));
@@ -1127,16 +1129,13 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
// The frame pointer does not point to a JS frame so we save NULL
// for fp. We expect the code throwing an exception to check fp
// before dereferencing it to restore the context.
- mov(ip, Operand(0, RelocInfo::NONE)); // To save a NULL frame pointer.
- mov(r6, Operand(StackHandler::ENTRY));
- ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize
- && StackHandlerConstants::kFPOffset == 2 * kPointerSize
- && StackHandlerConstants::kPCOffset == 3 * kPointerSize);
- stm(db_w, sp, r6.bit() | ip.bit() | lr.bit());
+ mov(r5, Operand(StackHandler::ENTRY)); // State.
+ mov(r6, Operand(Smi::FromInt(0))); // Indicates no context.
+ mov(r7, Operand(0, RelocInfo::NONE)); // NULL frame pointer.
+ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | lr.bit());
// Save the current handler as the next handler.
mov(r7, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(r6, MemOperand(r7));
- ASSERT(StackHandlerConstants::kNextOffset == 0);
push(r6);
// Link this handler as the new current one.
str(sp, MemOperand(r7));
@@ -1145,7 +1144,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() {
- ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r1);
mov(ip, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
@@ -1154,39 +1153,40 @@ void MacroAssembler::PopTryHandler() {
void MacroAssembler::Throw(Register value) {
+ // Adjust this code if not the case.
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// r0 is expected to hold the exception.
if (!value.is(r0)) {
mov(r0, value);
}
- // Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
-
// Drop the sp to the top of the handler.
mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(sp, MemOperand(r3));
- // Restore the next handler and frame pointer, discard handler state.
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+ // Restore the next handler.
pop(r2);
str(r2, MemOperand(r3));
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
- ldm(ia_w, sp, r3.bit() | fp.bit()); // r3: discarded state.
-
- // Before returning we restore the context from the frame pointer if
- // not NULL. The frame pointer is NULL in the exception handler of a
- // JS entry frame.
- cmp(fp, Operand(0, RelocInfo::NONE));
- // Set cp to NULL if fp is NULL.
- mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq);
- // Restore cp otherwise.
- ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
+
+ // Restore context and frame pointer, discard state (r3).
+ ldm(ia_w, sp, r3.bit() | cp.bit() | fp.bit());
+
+ // If the handler is a JS frame, restore the context to the frame.
+ // (r3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any
+ // of them.
+ cmp(r3, Operand(StackHandler::ENTRY));
+ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
+
#ifdef DEBUG
if (emit_debug_code()) {
mov(lr, Operand(pc));
}
#endif
- STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(pc);
}
@@ -1194,8 +1194,12 @@ void MacroAssembler::Throw(Register value) {
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) {
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
-
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// r0 is expected to hold the exception.
if (!value.is(r0)) {
mov(r0, value);
@@ -1220,7 +1224,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r2);
str(r2, MemOperand(r3));
@@ -1242,26 +1245,17 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
// Stack layout at this point. See also StackHandlerConstants.
// sp -> state (ENTRY)
+ // cp
// fp
// lr
- // Discard handler state (r2 is not used) and restore frame pointer.
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
- ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state.
- // Before returning we restore the context from the frame pointer if
- // not NULL. The frame pointer is NULL in the exception handler of a
- // JS entry frame.
- cmp(fp, Operand(0, RelocInfo::NONE));
- // Set cp to NULL if fp is NULL.
- mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq);
- // Restore cp otherwise.
- ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
+ // Restore context and frame pointer, discard state (r2).
+ ldm(ia_w, sp, r2.bit() | cp.bit() | fp.bit());
#ifdef DEBUG
if (emit_debug_code()) {
mov(lr, Operand(pc));
}
#endif
- STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(pc);
}
diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc
index 2c60b28a5..1767b9d5b 100644
--- a/deps/v8/src/arm/stub-cache-arm.cc
+++ b/deps/v8/src/arm/stub-cache-arm.cc
@@ -3489,9 +3489,9 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// Check that the index is in range.
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
- __ cmp(ip, Operand(key, ASR, kSmiTagSize));
+ __ cmp(key, ip);
// Unsigned comparison catches both negative and too-large values.
- __ b(lo, &miss_force_generic);
+ __ b(hs, &miss_force_generic);
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage
@@ -3811,22 +3811,20 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
// Check that the key is a smi.
__ JumpIfNotSmi(key, &miss_force_generic);
+ __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
+
// Check that the index is in range
- __ SmiUntag(r4, key);
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
- __ cmp(r4, ip);
+ __ cmp(key, ip);
// Unsigned comparison catches both negative and too-large values.
__ b(hs, &miss_force_generic);
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.
// r3: external array.
- // r4: key (integer).
if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
// Double to pixel conversion is only implemented in the runtime for now.
__ JumpIfNotSmi(value, &slow);
@@ -3837,32 +3835,32 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage.
- // r4: key (integer).
// r5: value (integer).
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
// Clamp the value to [0..255].
__ Usat(r5, 8, Operand(r5));
- __ strb(r5, MemOperand(r3, r4, LSL, 0));
+ __ strb(r5, MemOperand(r3, key, LSR, 1));
break;
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ strb(r5, MemOperand(r3, r4, LSL, 0));
+ __ strb(r5, MemOperand(r3, key, LSR, 1));
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ strh(r5, MemOperand(r3, r4, LSL, 1));
+ __ strh(r5, MemOperand(r3, key, LSL, 0));
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ str(r5, MemOperand(r3, r4, LSL, 2));
+ __ str(r5, MemOperand(r3, key, LSL, 1));
break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
+ __ SmiUntag(r4, key);
StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
break;
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- __ add(r3, r3, Operand(r4, LSL, 3));
+ __ add(r3, r3, Operand(key, LSL, 2));
// r3: effective address of the double element
FloatingPointHelper::Destination destination;
if (CpuFeatures::IsSupported(VFP3)) {
@@ -3895,7 +3893,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
// r3: external array.
- // r4: index (integer).
__ bind(&check_heap_number);
__ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
__ b(ne, &slow);
@@ -3903,7 +3900,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage.
- // r4: key (integer).
// The WebGL specification leaves the behavior of storing NaN and
// +/-Infinity into integer arrays basically undefined. For more
@@ -3916,13 +3912,13 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// include -kHeapObjectTag into it.
__ sub(r5, r0, Operand(kHeapObjectTag));
__ vldr(d0, r5, HeapNumber::kValueOffset);
- __ add(r5, r3, Operand(r4, LSL, 2));
+ __ add(r5, r3, Operand(key, LSL, 1));
__ vcvt_f32_f64(s0, d0);
__ vstr(s0, r5, 0);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
__ sub(r5, r0, Operand(kHeapObjectTag));
__ vldr(d0, r5, HeapNumber::kValueOffset);
- __ add(r5, r3, Operand(r4, LSL, 3));
+ __ add(r5, r3, Operand(key, LSL, 2));
__ vstr(d0, r5, 0);
} else {
// Hoisted load. vldr requires offset to be a multiple of 4 so we can
@@ -3934,15 +3930,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ strb(r5, MemOperand(r3, r4, LSL, 0));
+ __ strb(r5, MemOperand(r3, key, LSR, 1));
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ strh(r5, MemOperand(r3, r4, LSL, 1));
+ __ strh(r5, MemOperand(r3, key, LSL, 0));
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ str(r5, MemOperand(r3, r4, LSL, 2));
+ __ str(r5, MemOperand(r3, key, LSL, 1));
break;
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
@@ -4004,7 +4000,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
__ bind(&done);
- __ str(r5, MemOperand(r3, r4, LSL, 2));
+ __ str(r5, MemOperand(r3, key, LSL, 1));
// Entry registers are intact, r0 holds the value which is the return
// value.
__ Ret();
@@ -4017,7 +4013,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
__ b(&done);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
- __ add(r7, r3, Operand(r4, LSL, 3));
+ __ add(r7, r3, Operand(key, LSL, 2));
// r7: effective address of destination element.
__ str(r6, MemOperand(r7, 0));
__ str(r5, MemOperand(r7, Register::kSizeInBytes));
@@ -4073,15 +4069,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ strb(r5, MemOperand(r3, r4, LSL, 0));
+ __ strb(r5, MemOperand(r3, key, LSR, 1));
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ strh(r5, MemOperand(r3, r4, LSL, 1));
+ __ strh(r5, MemOperand(r3, key, LSL, 0));
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ str(r5, MemOperand(r3, r4, LSL, 2));
+ __ str(r5, MemOperand(r3, key, LSL, 1));
break;
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
diff --git a/deps/v8/src/ast-inl.h b/deps/v8/src/ast-inl.h
index c750e6b03..731ad2ff3 100644
--- a/deps/v8/src/ast-inl.h
+++ b/deps/v8/src/ast-inl.h
@@ -50,7 +50,8 @@ Block::Block(Isolate* isolate,
bool is_initializer_block)
: BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY),
statements_(capacity),
- is_initializer_block_(is_initializer_block) {
+ is_initializer_block_(is_initializer_block),
+ block_scope_(NULL) {
}
diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc
index 2df62ee96..3e6d856ce 100644
--- a/deps/v8/src/ast.cc
+++ b/deps/v8/src/ast.cc
@@ -426,7 +426,7 @@ bool ForInStatement::IsInlineable() const {
}
-bool EnterWithContextStatement::IsInlineable() const {
+bool WithStatement::IsInlineable() const {
return false;
}
diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h
index b4705f6ab..4031b7d81 100644
--- a/deps/v8/src/ast.h
+++ b/deps/v8/src/ast.h
@@ -60,7 +60,7 @@ namespace internal {
V(ContinueStatement) \
V(BreakStatement) \
V(ReturnStatement) \
- V(EnterWithContextStatement) \
+ V(WithStatement) \
V(ExitContextStatement) \
V(SwitchStatement) \
V(DoWhileStatement) \
@@ -359,9 +359,13 @@ class Block: public BreakableStatement {
ZoneList<Statement*>* statements() { return &statements_; }
bool is_initializer_block() const { return is_initializer_block_; }
+ Scope* block_scope() const { return block_scope_; }
+ void set_block_scope(Scope* block_scope) { block_scope_ = block_scope; }
+
private:
ZoneList<Statement*> statements_;
bool is_initializer_block_;
+ Scope* block_scope_;
};
@@ -371,9 +375,11 @@ class Declaration: public AstNode {
: proxy_(proxy),
mode_(mode),
fun_(fun) {
- ASSERT(mode == Variable::VAR || mode == Variable::CONST);
+ ASSERT(mode == Variable::VAR ||
+ mode == Variable::CONST ||
+ mode == Variable::LET);
// At the moment there are no "const functions"'s in JavaScript...
- ASSERT(fun == NULL || mode == Variable::VAR);
+ ASSERT(fun == NULL || mode == Variable::VAR || mode == Variable::LET);
}
DECLARE_NODE_TYPE(Declaration)
@@ -627,19 +633,21 @@ class ReturnStatement: public Statement {
};
-class EnterWithContextStatement: public Statement {
+class WithStatement: public Statement {
public:
- explicit EnterWithContextStatement(Expression* expression)
- : expression_(expression) { }
+ WithStatement(Expression* expression, Statement* statement)
+ : expression_(expression), statement_(statement) { }
- DECLARE_NODE_TYPE(EnterWithContextStatement)
+ DECLARE_NODE_TYPE(WithStatement)
Expression* expression() const { return expression_; }
+ Statement* statement() const { return statement_; }
virtual bool IsInlineable() const;
private:
Expression* expression_;
+ Statement* statement_;
};
diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc
index a5cb55525..4f7cf4094 100644
--- a/deps/v8/src/bootstrapper.cc
+++ b/deps/v8/src/bootstrapper.cc
@@ -1198,10 +1198,9 @@ void Genesis::InitializeExperimentalGlobal() {
// TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no
// longer need to live behind a flag, so WeakMap gets added to the snapshot.
if (FLAG_harmony_weakmaps) { // -- W e a k M a p
- Handle<JSFunction> weakmap_fun =
- InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
- isolate->initial_object_prototype(),
- Builtins::kIllegal, true);
+ InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
+ isolate->initial_object_prototype(),
+ Builtins::kIllegal, true);
}
}
@@ -1587,8 +1586,6 @@ bool Genesis::InstallNatives() {
global_context()->set_string_function_prototype_map(
HeapObject::cast(string_function->initial_map()->prototype())->map());
- InstallBuiltinFunctionIds();
-
// Install Function.prototype.call and apply.
{ Handle<String> key = factory()->function_class_symbol();
Handle<JSFunction> function =
@@ -1622,6 +1619,8 @@ bool Genesis::InstallNatives() {
apply->shared()->set_length(2);
}
+ InstallBuiltinFunctionIds();
+
// Create a constructor for RegExp results (a variant of Array that
// predefines the two properties index and match).
{
diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc
index 0cba275c3..5535d171b 100644
--- a/deps/v8/src/code-stubs.cc
+++ b/deps/v8/src/code-stubs.cc
@@ -340,12 +340,11 @@ void ToBooleanStub::Types::Print(StringStream* stream) const {
if (IsEmpty()) stream->Add("None");
if (Contains(UNDEFINED)) stream->Add("Undefined");
if (Contains(BOOLEAN)) stream->Add("Bool");
- if (Contains(SMI)) stream->Add("Smi");
if (Contains(NULL_TYPE)) stream->Add("Null");
+ if (Contains(SMI)) stream->Add("Smi");
if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
if (Contains(STRING)) stream->Add("String");
if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
- if (Contains(INTERNAL_OBJECT)) stream->Add("InternalObject");
}
@@ -385,12 +384,14 @@ bool ToBooleanStub::Types::Record(Handle<Object> object) {
return !object->IsUndetectableObject() &&
String::cast(*object)->length() != 0;
} else if (object->IsHeapNumber()) {
+ ASSERT(!object->IsUndetectableObject());
Add(HEAP_NUMBER);
double value = HeapNumber::cast(*object)->value();
- return !object->IsUndetectableObject() && value != 0 && !isnan(value);
+ return value != 0 && !isnan(value);
} else {
- Add(INTERNAL_OBJECT);
- return !object->IsUndetectableObject();
+ // We should never see an internal object at runtime here!
+ UNREACHABLE();
+ return true;
}
}
@@ -398,8 +399,13 @@ bool ToBooleanStub::Types::Record(Handle<Object> object) {
bool ToBooleanStub::Types::NeedsMap() const {
return Contains(ToBooleanStub::SPEC_OBJECT)
|| Contains(ToBooleanStub::STRING)
- || Contains(ToBooleanStub::HEAP_NUMBER)
- || Contains(ToBooleanStub::INTERNAL_OBJECT);
+ || Contains(ToBooleanStub::HEAP_NUMBER);
+}
+
+
+bool ToBooleanStub::Types::CanBeUndetectable() const {
+ return Contains(ToBooleanStub::SPEC_OBJECT)
+ || Contains(ToBooleanStub::STRING);
}
diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h
index 43b958b43..89e99a8d0 100644
--- a/deps/v8/src/code-stubs.h
+++ b/deps/v8/src/code-stubs.h
@@ -908,7 +908,6 @@ class ToBooleanStub: public CodeStub {
SPEC_OBJECT,
STRING,
HEAP_NUMBER,
- INTERNAL_OBJECT,
NUMBER_OF_TYPES
};
@@ -922,7 +921,6 @@ class ToBooleanStub: public CodeStub {
explicit Types(byte bits) : set_(bits) {}
bool IsEmpty() const { return set_.IsEmpty(); }
- bool IsAll() const { return ToByte() == ((1 << NUMBER_OF_TYPES) - 1); }
bool Contains(Type type) const { return set_.Contains(type); }
void Add(Type type) { set_.Add(type); }
byte ToByte() const { return set_.ToIntegral(); }
@@ -930,6 +928,7 @@ class ToBooleanStub: public CodeStub {
void TraceTransition(Types to) const;
bool Record(Handle<Object> object);
bool NeedsMap() const;
+ bool CanBeUndetectable() const;
private:
EnumSet<Type, byte> set_;
@@ -956,8 +955,7 @@ class ToBooleanStub: public CodeStub {
void CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
- bool result,
- Label* patch);
+ bool result);
void GenerateTypeTransition(MacroAssembler* masm);
Register tos_;
diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc
index a87eecc3c..c7e78067c 100755
--- a/deps/v8/src/compiler.cc
+++ b/deps/v8/src/compiler.cc
@@ -478,15 +478,21 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
// that would be compiled lazily anyway, so we skip the preparse step
// in that case too.
ScriptDataImpl* pre_data = input_pre_data;
+ bool harmony_block_scoping = natives != NATIVES_CODE &&
+ FLAG_harmony_block_scoping;
if (pre_data == NULL
&& source_length >= FLAG_min_preparse_length) {
if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
- pre_data = ParserApi::PartialPreParse(&stream, extension);
+ pre_data = ParserApi::PartialPreParse(&stream,
+ extension,
+ harmony_block_scoping);
} else {
GenericStringUC16CharacterStream stream(source, 0, source->length());
- pre_data = ParserApi::PartialPreParse(&stream, extension);
+ pre_data = ParserApi::PartialPreParse(&stream,
+ extension,
+ harmony_block_scoping);
}
}
diff --git a/deps/v8/src/contexts.cc b/deps/v8/src/contexts.cc
index d066d3476..c0e724253 100644
--- a/deps/v8/src/contexts.cc
+++ b/deps/v8/src/contexts.cc
@@ -109,7 +109,7 @@ Handle<Object> Context::Lookup(Handle<String> name,
}
// Check extension/with/global object.
- if (context->has_extension()) {
+ if (!context->IsBlockContext() && context->has_extension()) {
if (context->IsCatchContext()) {
// Catch contexts have the variable name in the extension slot.
if (name->Equals(String::cast(context->extension()))) {
@@ -121,6 +121,9 @@ Handle<Object> Context::Lookup(Handle<String> name,
return context;
}
} else {
+ ASSERT(context->IsGlobalContext() ||
+ context->IsFunctionContext() ||
+ context->IsWithContext());
// Global, function, and with contexts may have an object in the
// extension slot.
Handle<JSObject> extension(JSObject::cast(context->extension()),
@@ -145,11 +148,20 @@ Handle<Object> Context::Lookup(Handle<String> name,
}
}
- // Only functions can have locals, parameters, and a function name.
- if (context->IsFunctionContext()) {
+ // Check serialized scope information of functions and blocks. Only
+ // functions can have parameters, and a function name.
+ if (context->IsFunctionContext() || context->IsBlockContext()) {
// We may have context-local slots. Check locals in the context.
- Handle<SerializedScopeInfo> scope_info(
- context->closure()->shared()->scope_info(), isolate);
+ Handle<SerializedScopeInfo> scope_info;
+ if (context->IsFunctionContext()) {
+ scope_info = Handle<SerializedScopeInfo>(
+ context->closure()->shared()->scope_info(), isolate);
+ } else {
+ ASSERT(context->IsBlockContext());
+ scope_info = Handle<SerializedScopeInfo>(
+ SerializedScopeInfo::cast(context->extension()), isolate);
+ }
+
Variable::Mode mode;
int index = scope_info->ContextSlotIndex(*name, &mode);
ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
@@ -168,6 +180,7 @@ Handle<Object> Context::Lookup(Handle<String> name,
switch (mode) {
case Variable::INTERNAL: // Fall through.
case Variable::VAR:
+ case Variable::LET:
*attributes = NONE;
break;
case Variable::CONST:
diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h
index 53b40f127..3d9e7f4bf 100644
--- a/deps/v8/src/contexts.h
+++ b/deps/v8/src/contexts.h
@@ -295,6 +295,10 @@ class Context: public FixedArray {
Map* map = this->map();
return map == map->GetHeap()->with_context_map();
}
+ bool IsBlockContext() {
+ Map* map = this->map();
+ return map == map->GetHeap()->block_context_map();
+ }
// Tells whether the global context is marked with out of memory.
inline bool has_out_of_memory();
diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc
index 3b9c183c2..780b0c071 100644
--- a/deps/v8/src/d8.cc
+++ b/deps/v8/src/d8.cc
@@ -740,6 +740,7 @@ Persistent<Context> Shell::CreateEvaluationContext() {
// Initialize the global objects
Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
Persistent<Context> context = Context::New(NULL, global_template);
+ ASSERT(!context.IsEmpty());
Context::Scope scope(context);
#ifndef V8_SHARED
diff --git a/deps/v8/src/d8.h b/deps/v8/src/d8.h
index 40cc83b05..28321f56d 100644
--- a/deps/v8/src/d8.h
+++ b/deps/v8/src/d8.h
@@ -39,10 +39,6 @@
namespace v8 {
-#ifndef V8_SHARED
-namespace i = v8::internal;
-#endif // V8_SHARED
-
#ifndef V8_SHARED
// A single counter in a counter collection.
diff --git a/deps/v8/src/d8.js b/deps/v8/src/d8.js
index 033455e9d..3523e54ab 100644
--- a/deps/v8/src/d8.js
+++ b/deps/v8/src/d8.js
@@ -103,7 +103,8 @@ Debug.ScopeType = { Global: 0,
Local: 1,
With: 2,
Closure: 3,
- Catch: 4 };
+ Catch: 4,
+ Block: 5 };
// Current debug state.
diff --git a/deps/v8/src/disassembler.cc b/deps/v8/src/disassembler.cc
index 368c3a89c..79076d6ab 100644
--- a/deps/v8/src/disassembler.cc
+++ b/deps/v8/src/disassembler.cc
@@ -97,14 +97,17 @@ const char* V8NameConverter::NameInCode(byte* addr) const {
}
-static void DumpBuffer(FILE* f, char* buff) {
+static void DumpBuffer(FILE* f, StringBuilder* out) {
if (f == NULL) {
- PrintF("%s", buff);
+ PrintF("%s\n", out->Finalize());
} else {
- fprintf(f, "%s", buff);
+ fprintf(f, "%s\n", out->Finalize());
}
+ out->Reset();
}
+
+
static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
static const int kRelocInfoPosition = 57;
@@ -119,6 +122,7 @@ static int DecodeIt(FILE* f,
v8::internal::EmbeddedVector<char, 128> decode_buffer;
v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
+ StringBuilder out(out_buffer.start(), out_buffer.length());
byte* pc = begin;
disasm::Disassembler d(converter);
RelocIterator* it = NULL;
@@ -181,17 +185,12 @@ static int DecodeIt(FILE* f,
}
}
- StringBuilder out(out_buffer.start(), out_buffer.length());
-
// Comments.
for (int i = 0; i < comments.length(); i++) {
- out.AddFormatted(" %s\n", comments[i]);
+ out.AddFormatted(" %s", comments[i]);
+ DumpBuffer(f, &out);
}
- // Write out comments, resets outp so that we can format the next line.
- DumpBuffer(f, out.Finalize());
- out.Reset();
-
// Instruction address and instruction offset.
out.AddFormatted("%p %4d ", prev_pc, prev_pc - begin);
@@ -209,7 +208,7 @@ static int DecodeIt(FILE* f,
out.AddPadding(' ', kRelocInfoPosition - out.position());
} else {
// Additional reloc infos are printed on separate lines.
- out.AddFormatted("\n");
+ DumpBuffer(f, &out);
out.AddPadding(' ', kRelocInfoPosition);
}
@@ -299,9 +298,18 @@ static int DecodeIt(FILE* f,
out.AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode));
}
}
- out.AddString("\n");
- DumpBuffer(f, out.Finalize());
- out.Reset();
+ DumpBuffer(f, &out);
+ }
+
+ // Emit comments following the last instruction (if any).
+ if (it != NULL) {
+ for ( ; !it->done(); it->next()) {
+ if (RelocInfo::IsComment(it->rinfo()->rmode())) {
+ out.AddFormatted(" %s",
+ reinterpret_cast<const char*>(it->rinfo()->data()));
+ DumpBuffer(f, &out);
+ }
+ }
}
delete it;
diff --git a/deps/v8/src/elements.cc b/deps/v8/src/elements.cc
index 9cfcceec2..9927cd5ce 100644
--- a/deps/v8/src/elements.cc
+++ b/deps/v8/src/elements.cc
@@ -75,9 +75,8 @@ class ElementsAccessorBase : public ElementsAccessor {
virtual MaybeObject* GetWithReceiver(JSObject* obj,
Object* receiver,
uint32_t index) {
- if (index < ElementsAccessorSubclass::GetLength(obj)) {
- BackingStoreClass* backing_store =
- ElementsAccessorSubclass::GetBackingStore(obj);
+ BackingStoreClass* backing_store = BackingStoreClass::cast(obj->elements());
+ if (index < ElementsAccessorSubclass::GetLength(backing_store)) {
return backing_store->get(index);
}
return obj->GetHeap()->the_hole_value();
@@ -87,39 +86,39 @@ class ElementsAccessorBase : public ElementsAccessor {
uint32_t index,
JSReceiver::DeleteMode mode) = 0;
- virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other,
- FixedArray* keys) {
- int len0 = keys->length();
+ virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from,
+ FixedArray* to) {
+ int len0 = to->length();
#ifdef DEBUG
if (FLAG_enable_slow_asserts) {
for (int i = 0; i < len0; i++) {
- ASSERT(keys->get(i)->IsString() || keys->get(i)->IsNumber());
+ ASSERT(!to->get(i)->IsTheHole());
}
}
#endif
- int len1 = ElementsAccessorSubclass::GetCapacity(other);
+ BackingStoreClass* backing_store = BackingStoreClass::cast(from);
+ int len1 = ElementsAccessorSubclass::GetCapacity(backing_store);
// Optimize if 'other' is empty.
- // We cannot optimize if 'this' is empty, as other may have holes
- // or non keys.
- if (len1 == 0) return keys;
+ // We cannot optimize if 'this' is empty, as other may have holes.
+ if (len1 == 0) return to;
// Compute how many elements are not in other.
int extra = 0;
for (int y = 0; y < len1; y++) {
Object* value;
MaybeObject* maybe_value =
- ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y);
+ ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y);
if (!maybe_value->ToObject(&value)) return maybe_value;
- if (!value->IsTheHole() && !HasKey(keys, value)) extra++;
+ if (!value->IsTheHole() && !HasKey(to, value)) extra++;
}
- if (extra == 0) return keys;
+ if (extra == 0) return to;
// Allocate the result
FixedArray* result;
MaybeObject* maybe_obj =
- other->GetHeap()->AllocateFixedArray(len0 + extra);
+ backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
// Fill in the content
@@ -127,20 +126,19 @@ class ElementsAccessorBase : public ElementsAccessor {
AssertNoAllocation no_gc;
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
for (int i = 0; i < len0; i++) {
- Object* e = keys->get(i);
+ Object* e = to->get(i);
ASSERT(e->IsString() || e->IsNumber());
result->set(i, e, mode);
}
}
- // Fill in the extra keys.
+ // Fill in the extra values.
int index = 0;
for (int y = 0; y < len1; y++) {
MaybeObject* maybe_value =
- ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y);
+ ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y);
Object* value;
if (!maybe_value->ToObject(&value)) return maybe_value;
- if (!value->IsTheHole() && !HasKey(keys, value)) {
- ASSERT(value->IsString() || value->IsNumber());
+ if (!value->IsTheHole() && !HasKey(to, value)) {
result->set(len0 + index, value);
index++;
}
@@ -149,23 +147,18 @@ class ElementsAccessorBase : public ElementsAccessor {
return result;
}
- static uint32_t GetCapacity(JSObject* obj) {
- return ElementsAccessorSubclass::GetBackingStore(obj)->length();
+ static uint32_t GetLength(BackingStoreClass* backing_store) {
+ return backing_store->length();
}
- static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) {
- BackingStoreClass* backing_store =
- ElementsAccessorSubclass::GetBackingStore(obj);
- return backing_store->get(index);
- }
-
- protected:
- static BackingStoreClass* GetBackingStore(JSObject* obj) {
- return BackingStoreClass::cast(obj->elements());
+ static uint32_t GetCapacity(BackingStoreClass* backing_store) {
+ return GetLength(backing_store);
}
- static uint32_t GetLength(JSObject* obj) {
- return ElementsAccessorSubclass::GetBackingStore(obj)->length();
+ static MaybeObject* GetElementAtCapacityIndex(
+ BackingStoreClass* backing_store,
+ int index) {
+ return backing_store->get(index);
}
private:
@@ -255,9 +248,8 @@ class ExternalElementsAccessor
virtual MaybeObject* GetWithReceiver(JSObject* obj,
Object* receiver,
uint32_t index) {
- if (index < ExternalElementsAccessorSubclass::GetLength(obj)) {
- ExternalArray* backing_store =
- ExternalElementsAccessorSubclass::GetBackingStore(obj);
+ ExternalArray* backing_store = ExternalArray::cast(obj->elements());
+ if (index < ExternalElementsAccessorSubclass::GetLength(backing_store)) {
return backing_store->get(index);
} else {
return obj->GetHeap()->undefined_value();
@@ -412,16 +404,16 @@ class DictionaryElementsAccessor
index);
}
- static uint32_t GetCapacity(JSObject* obj) {
- return obj->element_dictionary()->Capacity();
+ static uint32_t GetCapacity(NumberDictionary* dict) {
+ return dict->Capacity();
}
- static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) {
- NumberDictionary* dict = obj->element_dictionary();
+ static MaybeObject* GetElementAtCapacityIndex(NumberDictionary* dict,
+ int index) {
if (dict->IsKey(dict->KeyAt(index))) {
return dict->ValueAt(index);
} else {
- return obj->GetHeap()->the_hole_value();
+ return dict->GetHeap()->the_hole_value();
}
}
};
@@ -434,7 +426,7 @@ class NonStrictArgumentsElementsAccessor
virtual MaybeObject* GetWithReceiver(JSObject* obj,
Object* receiver,
uint32_t index) {
- FixedArray* parameter_map = GetBackingStore(obj);
+ FixedArray* parameter_map = FixedArray::cast(obj->elements());
uint32_t length = parameter_map->length();
Object* probe =
(index < length - 2) ? parameter_map->get(index + 2) : NULL;
@@ -482,13 +474,13 @@ class NonStrictArgumentsElementsAccessor
return obj->GetHeap()->true_value();
}
- static uint32_t GetCapacity(JSObject* obj) {
+ static uint32_t GetCapacity(FixedArray* obj) {
// TODO(danno): Return max of parameter map length or backing store
// capacity.
return 0;
}
- static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) {
+ static MaybeObject* GetElementAtCapacityIndex(FixedArray* obj, int index) {
// TODO(danno): Return either value from parameter map of backing
// store value at index.
return obj->GetHeap()->the_hole_value();
diff --git a/deps/v8/src/elements.h b/deps/v8/src/elements.h
index f64244e95..74e4ad665 100644
--- a/deps/v8/src/elements.h
+++ b/deps/v8/src/elements.h
@@ -47,8 +47,8 @@ class ElementsAccessor {
uint32_t index,
JSReceiver::DeleteMode mode) = 0;
- virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other,
- FixedArray* keys) = 0;
+ virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from,
+ FixedArray* to) = 0;
// Returns a shared ElementsAccessor for the specified ElementsKind.
static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) {
diff --git a/deps/v8/src/extensions/experimental/datetime-format.cc b/deps/v8/src/extensions/experimental/datetime-format.cc
index 7f4630297..94a29ac0a 100644
--- a/deps/v8/src/extensions/experimental/datetime-format.cc
+++ b/deps/v8/src/extensions/experimental/datetime-format.cc
@@ -135,7 +135,7 @@ v8::Handle<v8::Value> DateTimeFormat::GetMonths(const v8::Arguments& args) {
v8::Handle<v8::Value> DateTimeFormat::GetWeekdays(const v8::Arguments& args) {
icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
if (!date_format) {
- ThrowUnexpectedObjectError();
+ return ThrowUnexpectedObjectError();
}
const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();
diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc
index 05dd5c966..ee5c37bf0 100644
--- a/deps/v8/src/factory.cc
+++ b/deps/v8/src/factory.cc
@@ -34,6 +34,7 @@
#include "macro-assembler.h"
#include "objects.h"
#include "objects-visiting.h"
+#include "scopeinfo.h"
namespace v8 {
namespace internal {
@@ -291,6 +292,19 @@ Handle<Context> Factory::NewWithContext(Handle<JSFunction> function,
}
+Handle<Context> Factory::NewBlockContext(
+ Handle<JSFunction> function,
+ Handle<Context> previous,
+ Handle<SerializedScopeInfo> scope_info) {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateBlockContext(*function,
+ *previous,
+ *scope_info),
+ Context);
+}
+
+
Handle<Struct> Factory::NewStruct(InstanceType type) {
CALL_HEAP_FUNCTION(
isolate(),
@@ -734,6 +748,14 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
}
+Handle<SerializedScopeInfo> Factory::NewSerializedScopeInfo(int length) {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateSerializedScopeInfo(length),
+ SerializedScopeInfo);
+}
+
+
Handle<Code> Factory::NewCode(const CodeDesc& desc,
Code::Flags flags,
Handle<Object> self_ref,
diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h
index 3217ca906..a69b05b38 100644
--- a/deps/v8/src/factory.h
+++ b/deps/v8/src/factory.h
@@ -167,6 +167,11 @@ class Factory {
Handle<Context> previous,
Handle<JSObject> extension);
+ // Create a 'block' context.
+ Handle<Context> NewBlockContext(Handle<JSFunction> function,
+ Handle<Context> previous,
+ Handle<SerializedScopeInfo> scope_info);
+
// Return the Symbol matching the passed in string.
Handle<String> SymbolFromString(Handle<String> value);
@@ -277,6 +282,8 @@ class Factory {
Handle<Context> context,
PretenureFlag pretenure = TENURED);
+ Handle<SerializedScopeInfo> NewSerializedScopeInfo(int length);
+
Handle<Code> NewCode(const CodeDesc& desc,
Code::Flags flags,
Handle<Object> self_reference,
diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h
index 2ea9651b6..2d8f6fa95 100644
--- a/deps/v8/src/flag-definitions.h
+++ b/deps/v8/src/flag-definitions.h
@@ -97,8 +97,10 @@ private:
#define FLAG FLAG_FULL
// Flags for experimental language features.
+DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof")
DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps")
+DEFINE_bool(harmony_block_scoping, false, "enable harmony block scoping")
// Flags for experimental implementation features.
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
diff --git a/deps/v8/src/frames-inl.h b/deps/v8/src/frames-inl.h
index 595180624..7ba79bf1b 100644
--- a/deps/v8/src/frames-inl.h
+++ b/deps/v8/src/frames-inl.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -67,6 +67,7 @@ inline bool StackHandler::includes(Address address) const {
inline void StackHandler::Iterate(ObjectVisitor* v, Code* holder) const {
+ v->VisitPointer(context_address());
StackFrame::IteratePc(v, pc_address(), holder);
}
@@ -82,6 +83,12 @@ inline StackHandler::State StackHandler::state() const {
}
+inline Object** StackHandler::context_address() const {
+ const int offset = StackHandlerConstants::kContextOffset;
+ return reinterpret_cast<Object**>(address() + offset);
+}
+
+
inline Address* StackHandler::pc_address() const {
const int offset = StackHandlerConstants::kPCOffset;
return reinterpret_cast<Address*>(address() + offset);
diff --git a/deps/v8/src/frames.h b/deps/v8/src/frames.h
index f542a92d9..4f94ebc7d 100644
--- a/deps/v8/src/frames.h
+++ b/deps/v8/src/frames.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -114,6 +114,7 @@ class StackHandler BASE_EMBEDDED {
// Accessors.
inline State state() const;
+ inline Object** context_address() const;
inline Address* pc_address() const;
DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc
index e5375fc3a..732a8fe7d 100644
--- a/deps/v8/src/full-codegen.cc
+++ b/deps/v8/src/full-codegen.cc
@@ -35,6 +35,7 @@
#include "macro-assembler.h"
#include "prettyprinter.h"
#include "scopes.h"
+#include "scopeinfo.h"
#include "stub-cache.h"
namespace v8 {
@@ -90,8 +91,7 @@ void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
}
-void BreakableStatementChecker::VisitEnterWithContextStatement(
- EnterWithContextStatement* stmt) {
+void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) {
Visit(stmt->expression());
}
@@ -317,7 +317,6 @@ unsigned FullCodeGenerator::EmitStackCheckTable() {
// field, and then a sequence of entries. Each entry is a pair of AST id
// and code-relative pc offset.
masm()->Align(kIntSize);
- masm()->RecordComment("[ Stack check table");
unsigned offset = masm()->pc_offset();
unsigned length = stack_checks_.length();
__ dd(length);
@@ -325,7 +324,6 @@ unsigned FullCodeGenerator::EmitStackCheckTable() {
__ dd(stack_checks_[i].id);
__ dd(stack_checks_[i].pc_and_state);
}
- masm()->RecordComment("]");
return offset;
}
@@ -847,8 +845,23 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
Breakable nested_statement(this, stmt);
SetStatementPosition(stmt);
+ Scope* saved_scope = scope();
+ if (stmt->block_scope() != NULL) {
+ { Comment cmnt(masm_, "[ Extend block context");
+ scope_ = stmt->block_scope();
+ __ Push(scope_->GetSerializedScopeInfo());
+ PushFunctionArgumentForContextAllocation();
+ __ CallRuntime(Runtime::kPushBlockContext, 2);
+ StoreToFrameField(StandardFrameConstants::kContextOffset,
+ context_register());
+ }
+ { Comment cmnt(masm_, "[ Declarations");
+ VisitDeclarations(scope_->declarations());
+ }
+ }
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
VisitStatements(stmt->statements());
+ scope_ = saved_scope;
__ bind(nested_statement.break_target());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
}
@@ -900,16 +913,24 @@ void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
SetStatementPosition(stmt);
NestedStatement* current = nesting_stack_;
int stack_depth = 0;
+ int context_length = 0;
// When continuing, we clobber the unpredictable value in the accumulator
// with one that's safe for GC. If we hit an exit from the try block of
// try...finally on our way out, we will unconditionally preserve the
// accumulator on the stack.
ClearAccumulator();
while (!current->IsContinueTarget(stmt->target())) {
- stack_depth = current->Exit(stack_depth);
- current = current->outer();
+ current = current->Exit(&stack_depth, &context_length);
}
__ Drop(stack_depth);
+ if (context_length > 0) {
+ while (context_length > 0) {
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX);
+ --context_length;
+ }
+ StoreToFrameField(StandardFrameConstants::kContextOffset,
+ context_register());
+ }
Iteration* loop = current->AsIteration();
__ jmp(loop->continue_target());
@@ -921,16 +942,24 @@ void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
SetStatementPosition(stmt);
NestedStatement* current = nesting_stack_;
int stack_depth = 0;
+ int context_length = 0;
// When breaking, we clobber the unpredictable value in the accumulator
// with one that's safe for GC. If we hit an exit from the try block of
// try...finally on our way out, we will unconditionally preserve the
// accumulator on the stack.
ClearAccumulator();
while (!current->IsBreakTarget(stmt->target())) {
- stack_depth = current->Exit(stack_depth);
- current = current->outer();
+ current = current->Exit(&stack_depth, &context_length);
}
__ Drop(stack_depth);
+ if (context_length > 0) {
+ while (context_length > 0) {
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX);
+ --context_length;
+ }
+ StoreToFrameField(StandardFrameConstants::kContextOffset,
+ context_register());
+ }
Breakable* target = current->AsBreakable();
__ jmp(target->break_target());
@@ -946,9 +975,9 @@ void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
// Exit all nested statements.
NestedStatement* current = nesting_stack_;
int stack_depth = 0;
+ int context_length = 0;
while (current != NULL) {
- stack_depth = current->Exit(stack_depth);
- current = current->outer();
+ current = current->Exit(&stack_depth, &context_length);
}
__ Drop(stack_depth);
@@ -956,9 +985,8 @@ void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
}
-void FullCodeGenerator::VisitEnterWithContextStatement(
- EnterWithContextStatement* stmt) {
- Comment cmnt(masm_, "[ EnterWithContextStatement");
+void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
+ Comment cmnt(masm_, "[ WithStatement");
SetStatementPosition(stmt);
VisitForStackValue(stmt->expression());
@@ -966,6 +994,15 @@ void FullCodeGenerator::VisitEnterWithContextStatement(
__ CallRuntime(Runtime::kPushWithContext, 2);
decrement_stack_height();
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
+
+ { WithOrCatch body(this);
+ Visit(stmt->statement());
+ }
+
+ // Pop context.
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX);
+ // Update local stack frame context field.
+ StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
}
@@ -1124,7 +1161,9 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
Scope* saved_scope = scope();
scope_ = stmt->scope();
ASSERT(scope_->declarations()->is_empty());
- Visit(stmt->catch_block());
+ { WithOrCatch body(this);
+ Visit(stmt->catch_block());
+ }
scope_ = saved_scope;
__ jmp(&done);
@@ -1170,8 +1209,8 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
Label try_handler_setup;
const int original_stack_height = stack_height();
const int finally_block_stack_height = original_stack_height + 2;
- const int try_block_stack_height = original_stack_height + 4;
- STATIC_ASSERT(StackHandlerConstants::kSize / kPointerSize == 4);
+ const int try_block_stack_height = original_stack_height + 5;
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
// Setup the try-handler chain. Use a call to
// Jump to try-handler setup and try-block code. Use call to put try-handler
@@ -1300,20 +1339,33 @@ void FullCodeGenerator::VisitThrow(Throw* expr) {
}
-int FullCodeGenerator::TryFinally::Exit(int stack_depth) {
+FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
+ int* stack_depth,
+ int* context_length) {
// The macros used here must preserve the result register.
- __ Drop(stack_depth);
+ __ Drop(*stack_depth);
__ PopTryHandler();
+ *stack_depth = 0;
+
+ Register context = FullCodeGenerator::context_register();
+ while (*context_length > 0) {
+ codegen_->LoadContextField(context, Context::PREVIOUS_INDEX);
+ --(*context_length);
+ }
+
__ Call(finally_entry_);
- return 0;
+ return previous_;
}
-int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
+FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit(
+ int* stack_depth,
+ int* context_length) {
// The macros used here must preserve the result register.
- __ Drop(stack_depth);
+ __ Drop(*stack_depth);
__ PopTryHandler();
- return 0;
+ *stack_depth = 0;
+ return previous_;
}
diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h
index 9bd6e5e4d..2fc055366 100644
--- a/deps/v8/src/full-codegen.h
+++ b/deps/v8/src/full-codegen.h
@@ -140,25 +140,19 @@ class FullCodeGenerator: public AstVisitor {
virtual bool IsContinueTarget(Statement* target) { return false; }
virtual bool IsBreakTarget(Statement* target) { return false; }
- // Generate code to leave the nested statement. This includes
- // cleaning up any stack elements in use and restoring the
- // stack to the expectations of the surrounding statements.
- // Takes a number of stack elements currently on top of the
- // nested statement's stack, and returns a number of stack
- // elements left on top of the surrounding statement's stack.
- // The generated code must preserve the result register (which
- // contains the value in case of a return).
- virtual int Exit(int stack_depth) {
- // Default implementation for the case where there is
- // nothing to clean up.
- return stack_depth;
+ // Notify the statement that we are exiting it via break, continue, or
+ // return and give it a chance to generate cleanup code. Return the
+ // next outer statement in the nesting stack. We accumulate in
+ // *stack_depth the amount to drop the stack and in *context_length the
+ // number of context chain links to unwind as we traverse the nesting
+ // stack from an exit to its target.
+ virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
+ return previous_;
}
- NestedStatement* outer() { return previous_; }
protected:
MacroAssembler* masm() { return codegen_->masm(); }
- private:
FullCodeGenerator* codegen_;
NestedStatement* previous_;
DISALLOW_COPY_AND_ASSIGN(NestedStatement);
@@ -207,7 +201,7 @@ class FullCodeGenerator: public AstVisitor {
virtual ~TryCatch() {}
virtual TryCatch* AsTryCatch() { return this; }
Label* catch_entry() { return catch_entry_; }
- virtual int Exit(int stack_depth);
+ virtual NestedStatement* Exit(int* stack_depth, int* context_length);
private:
Label* catch_entry_;
DISALLOW_COPY_AND_ASSIGN(TryCatch);
@@ -221,7 +215,7 @@ class FullCodeGenerator: public AstVisitor {
virtual ~TryFinally() {}
virtual TryFinally* AsTryFinally() { return this; }
Label* finally_entry() { return finally_entry_; }
- virtual int Exit(int stack_depth);
+ virtual NestedStatement* Exit(int* stack_depth, int* context_length);
private:
Label* finally_entry_;
DISALLOW_COPY_AND_ASSIGN(TryFinally);
@@ -235,8 +229,9 @@ class FullCodeGenerator: public AstVisitor {
explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
virtual ~Finally() {}
virtual Finally* AsFinally() { return this; }
- virtual int Exit(int stack_depth) {
- return stack_depth + kFinallyStackElementCount;
+ virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
+ *stack_depth += kFinallyStackElementCount;
+ return previous_;
}
private:
// Number of extra stack slots occupied during a finally block.
@@ -254,14 +249,32 @@ class FullCodeGenerator: public AstVisitor {
: Iteration(codegen, statement) { }
virtual ~ForIn() {}
virtual ForIn* AsForIn() { return this; }
- virtual int Exit(int stack_depth) {
- return stack_depth + kForInStackElementCount;
+ virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
+ *stack_depth += kForInStackElementCount;
+ return previous_;
}
private:
static const int kForInStackElementCount = 5;
DISALLOW_COPY_AND_ASSIGN(ForIn);
};
+
+ // A WithOrCatch represents being inside the body of a with or catch
+ // statement. Exiting the body needs to remove a link from the context
+ // chain.
+ class WithOrCatch : public NestedStatement {
+ public:
+ explicit WithOrCatch(FullCodeGenerator* codegen)
+ : NestedStatement(codegen) {
+ }
+ virtual ~WithOrCatch() {}
+
+ virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
+ ++(*context_length);
+ return previous_;
+ }
+ };
+
// The forward bailout stack keeps track of the expressions that can
// bail out to just before the control flow is split in a child
// node. The stack elements are linked together through the parent
diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc
index dbf3b95a9..e080cde32 100644
--- a/deps/v8/src/heap.cc
+++ b/deps/v8/src/heap.cc
@@ -1745,6 +1745,12 @@ bool Heap::CreateInitialMaps() {
set_fixed_cow_array_map(Map::cast(obj));
ASSERT(fixed_array_map() != fixed_cow_array_map());
+ { MaybeObject* maybe_obj =
+ AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_serialized_scope_info_map(Map::cast(obj));
+
{ MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
if (!maybe_obj->ToObject(&obj)) return false;
}
@@ -1910,6 +1916,12 @@ bool Heap::CreateInitialMaps() {
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false;
}
+ set_block_context_map(Map::cast(obj));
+
+ { MaybeObject* maybe_obj =
+ AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
Map* global_context_map = Map::cast(obj);
global_context_map->set_visitor_id(StaticVisitorBase::kVisitGlobalContext);
set_global_context_map(global_context_map);
@@ -4017,6 +4029,37 @@ MaybeObject* Heap::AllocateWithContext(JSFunction* function,
}
+MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
+ Context* previous,
+ SerializedScopeInfo* scope_info) {
+ Object* result;
+ { MaybeObject* maybe_result =
+ AllocateFixedArray(scope_info->NumberOfContextSlots());
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ // TODO(keuchel): properly initialize context slots.
+ Context* context = reinterpret_cast<Context*>(result);
+ context->set_map(block_context_map());
+ context->set_closure(function);
+ context->set_previous(previous);
+ context->set_extension(scope_info);
+ context->set_global(previous->global());
+ return context;
+}
+
+
+MaybeObject* Heap::AllocateSerializedScopeInfo(int length) {
+ Object* result;
+ { MaybeObject* maybe_result = AllocateFixedArray(length, TENURED);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ SerializedScopeInfo* scope_info =
+ reinterpret_cast<SerializedScopeInfo*>(result);
+ scope_info->set_map(serialized_scope_info_map());
+ return scope_info;
+}
+
+
MaybeObject* Heap::AllocateStruct(InstanceType type) {
Map* map;
switch (type) {
diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h
index 4f4ef14dd..c4ee4dbe2 100644
--- a/deps/v8/src/heap.h
+++ b/deps/v8/src/heap.h
@@ -65,6 +65,7 @@ inline Heap* _inline_get_heap_();
V(Map, heap_number_map, HeapNumberMap) \
V(Map, global_context_map, GlobalContextMap) \
V(Map, fixed_array_map, FixedArrayMap) \
+ V(Map, serialized_scope_info_map, SerializedScopeInfoMap) \
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \
@@ -111,6 +112,7 @@ inline Heap* _inline_get_heap_();
V(Map, function_context_map, FunctionContextMap) \
V(Map, catch_context_map, CatchContextMap) \
V(Map, with_context_map, WithContextMap) \
+ V(Map, block_context_map, BlockContextMap) \
V(Map, code_map, CodeMap) \
V(Map, oddball_map, OddballMap) \
V(Map, global_property_cell_map, GlobalPropertyCellMap) \
@@ -160,6 +162,7 @@ inline Heap* _inline_get_heap_();
V(length_symbol, "length") \
V(name_symbol, "name") \
V(native_symbol, "native") \
+ V(null_symbol, "null") \
V(number_symbol, "number") \
V(Number_symbol, "Number") \
V(nan_symbol, "NaN") \
@@ -220,7 +223,8 @@ inline Heap* _inline_get_heap_();
V(closure_symbol, "(closure)") \
V(use_strict, "use strict") \
V(dot_symbol, ".") \
- V(anonymous_function_symbol, "(anonymous function)")
+ V(anonymous_function_symbol, "(anonymous function)") \
+ V(block_scope_symbol, ".block")
// Forward declarations.
class GCTracer;
@@ -483,6 +487,9 @@ class Heap {
// Allocates an empty code cache.
MUST_USE_RESULT MaybeObject* AllocateCodeCache();
+ // Allocates a serialized scope info.
+ MUST_USE_RESULT MaybeObject* AllocateSerializedScopeInfo(int length);
+
// Allocates an empty PolymorphicCodeCache.
MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache();
@@ -668,6 +675,11 @@ class Heap {
Context* previous,
JSObject* extension);
+ // Allocate a block context.
+ MUST_USE_RESULT MaybeObject* AllocateBlockContext(JSFunction* function,
+ Context* previous,
+ SerializedScopeInfo* info);
+
// Allocates a new utility object in the old generation.
MUST_USE_RESULT MaybeObject* AllocateStruct(InstanceType type);
diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc
index 2be2a0325..71c59b5d9 100644
--- a/deps/v8/src/hydrogen-instructions.cc
+++ b/deps/v8/src/hydrogen-instructions.cc
@@ -635,6 +635,12 @@ void HBinaryCall::PrintDataTo(StringStream* stream) {
}
+void HBoundsCheck::PrintDataTo(StringStream* stream) {
+ index()->PrintNameTo(stream);
+ stream->Add(" ");
+ length()->PrintNameTo(stream);
+}
+
void HCallConstantFunction::PrintDataTo(StringStream* stream) {
if (IsApplyFunction()) {
stream->Add("optimized apply ");
@@ -862,19 +868,10 @@ void HInstanceOf::PrintDataTo(StringStream* stream) {
Range* HValue::InferRange() {
- if (representation().IsTagged()) {
- // Tagged values are always in int32 range when converted to integer,
- // but they can contain -0.
- Range* result = new Range();
- result->set_can_be_minus_zero(true);
- return result;
- } else if (representation().IsNone()) {
- return NULL;
- } else {
- // Untagged integer32 cannot be -0 and we don't compute ranges for
- // untagged doubles.
- return new Range();
- }
+ // Untagged integer32 cannot be -0, all other representations can.
+ Range* result = new Range();
+ result->set_can_be_minus_zero(!representation().IsInteger32());
+ return result;
}
@@ -1373,6 +1370,20 @@ bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
}
+void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) {
+ object()->PrintNameTo(stream);
+ stream->Add(" .");
+ stream->Add(*String::cast(*name())->ToCString());
+}
+
+
+void HLoadNamedGeneric::PrintDataTo(StringStream* stream) {
+ object()->PrintNameTo(stream);
+ stream->Add(" .");
+ stream->Add(*String::cast(*name())->ToCString());
+}
+
+
void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
stream->Add("[");
diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h
index 23c0ae664..e7a9104e8 100644
--- a/deps/v8/src/hydrogen-instructions.h
+++ b/deps/v8/src/hydrogen-instructions.h
@@ -104,8 +104,7 @@ class LChunkBuilder;
V(Div) \
V(ElementsKind) \
V(EnterInlined) \
- V(ExternalArrayLength) \
- V(FixedArrayLength) \
+ V(FixedArrayBaseLength) \
V(ForceRepresentation) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
@@ -1702,9 +1701,9 @@ class HJSArrayLength: public HTemplateInstruction<2> {
};
-class HFixedArrayLength: public HUnaryOperation {
+class HFixedArrayBaseLength: public HUnaryOperation {
public:
- explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) {
+ explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kDependsOnArrayLengths);
@@ -1714,28 +1713,7 @@ class HFixedArrayLength: public HUnaryOperation {
return Representation::Tagged();
}
- DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength)
-
- protected:
- virtual bool DataEquals(HValue* other) { return true; }
-};
-
-
-class HExternalArrayLength: public HUnaryOperation {
- public:
- explicit HExternalArrayLength(HValue* value) : HUnaryOperation(value) {
- set_representation(Representation::Integer32());
- // The result of this instruction is idempotent as long as its inputs don't
- // change. The length of a pixel array cannot change once set, so it's not
- // necessary to introduce a kDependsOnArrayLengths or any other dependency.
- SetFlag(kUseGVN);
- }
-
- virtual Representation RequiredInputRepresentation(int index) const {
- return Representation::Tagged();
- }
-
- DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength)
+ DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength)
protected:
virtual bool DataEquals(HValue* other) { return true; }
@@ -2471,6 +2449,8 @@ class HBoundsCheck: public HTemplateInstruction<2> {
return Representation::Integer32();
}
+ virtual void PrintDataTo(StringStream* stream);
+
HValue* index() { return OperandAt(0); }
HValue* length() { return OperandAt(1); }
@@ -3438,6 +3418,8 @@ class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> {
return Representation::Tagged();
}
+ virtual void PrintDataTo(StringStream* stream);
+
DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic)
static const int kMaxLoadPolymorphism = 4;
@@ -3471,6 +3453,8 @@ class HLoadNamedGeneric: public HTemplateInstruction<2> {
return Representation::Tagged();
}
+ virtual void PrintDataTo(StringStream* stream);
+
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
private:
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc
index be56c673b..ca0aebbbb 100644
--- a/deps/v8/src/hydrogen.cc
+++ b/deps/v8/src/hydrogen.cc
@@ -2480,6 +2480,9 @@ void HGraphBuilder::VisitBlock(Block* stmt) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ if (stmt->block_scope() != NULL) {
+ return Bailout("ScopedBlock");
+ }
BreakAndContinueInfo break_info(stmt);
{ BreakAndContinueScope push(&break_info, this);
CHECK_BAILOUT(VisitStatements(stmt->statements()));
@@ -2631,12 +2634,11 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
}
-void HGraphBuilder::VisitEnterWithContextStatement(
- EnterWithContextStatement* stmt) {
+void HGraphBuilder::VisitWithStatement(WithStatement* stmt) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- return Bailout("EnterWithContextStatement");
+ return Bailout("WithStatement");
}
@@ -3940,7 +3942,7 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
HInstruction* length = NULL;
HInstruction* checked_key = NULL;
if (map->has_external_array_elements()) {
- length = AddInstruction(new(zone()) HExternalArrayLength(elements));
+ length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
HLoadExternalArrayPointer* external_elements =
new(zone()) HLoadExternalArrayPointer(elements);
@@ -3952,7 +3954,7 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
if (map->instance_type() == JS_ARRAY_TYPE) {
length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck));
} else {
- length = AddInstruction(new(zone()) HFixedArrayLength(elements));
+ length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
}
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
if (is_store) {
@@ -4024,7 +4026,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
&& todo_external_array) {
HInstruction* length =
- AddInstruction(new(zone()) HExternalArrayLength(elements));
+ AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
external_elements = new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
@@ -4088,7 +4090,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
if_jsarray->Goto(join);
set_current_block(if_fastobject);
- length = AddInstruction(new(zone()) HFixedArrayLength(elements));
+ length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
if (is_store) {
if (fast_double_elements) {
@@ -4762,10 +4764,17 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
Property* prop = callee->AsProperty();
ASSERT(prop != NULL);
- if (info()->scope()->arguments() == NULL) return false;
+ if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
+ return false;
+ }
+ Handle<Map> function_map = expr->GetReceiverTypes()->first();
+ if (function_map->instance_type() != JS_FUNCTION_TYPE ||
+ !expr->target()->shared()->HasBuiltinFunctionId() ||
+ expr->target()->shared()->builtin_function_id() != kFunctionApply) {
+ return false;
+ }
- Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
- if (!name->IsEqualTo(CStrVector("apply"))) return false;
+ if (info()->scope()->arguments() == NULL) return false;
ZoneList<Expression*>* args = expr->arguments();
if (args->length() != 2) return false;
@@ -4775,9 +4784,6 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
HValue* arg_two_value = environment()->Lookup(arg_two->var());
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
- if (!expr->IsMonomorphic() ||
- expr->check_type() != RECEIVER_MAP_CHECK) return false;
-
// Our implementation of arguments (based on this stack frame or an
// adapter below it) does not work for inlined functions.
if (function_state()->outer() != NULL) {
@@ -4794,10 +4800,7 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
HValue* receiver = Pop();
HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
- AddCheckConstantFunction(expr,
- function,
- expr->GetReceiverTypes()->first(),
- true);
+ AddCheckConstantFunction(expr, function, function_map, true);
HInstruction* result =
new(zone()) HApplyArguments(function, receiver, length, elements);
result->set_position(expr->position());
diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h
index 05c42dd7f..99225511c 100644
--- a/deps/v8/src/hydrogen.h
+++ b/deps/v8/src/hydrogen.h
@@ -874,7 +874,10 @@ class HGraphBuilder: public AstVisitor {
bool is_store);
bool TryArgumentsAccess(Property* expr);
+
+ // Try to optimize fun.apply(receiver, arguments) pattern.
bool TryCallApply(Call* expr);
+
bool TryInline(Call* expr);
bool TryInlineBuiltinFunction(Call* expr,
HValue* receiver,
diff --git a/deps/v8/src/ia32/assembler-ia32.cc b/deps/v8/src/ia32/assembler-ia32.cc
index 0dc519407..999647487 100644
--- a/deps/v8/src/ia32/assembler-ia32.cc
+++ b/deps/v8/src/ia32/assembler-ia32.cc
@@ -1957,6 +1957,18 @@ void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
}
+void Assembler::roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode) {
+ ASSERT(CpuFeatures::IsEnabled(SSE4_1));
+ EnsureSpace ensure_space(this);
+ EMIT(0x66);
+ EMIT(0x0F);
+ EMIT(0x3A);
+ EMIT(0x0B);
+ emit_sse_operand(dst, src);
+ // Mask precision exeption.
+ EMIT(static_cast<byte>(mode) | 0x8);
+}
+
void Assembler::movmskpd(Register dst, XMMRegister src) {
ASSERT(CpuFeatures::IsEnabled(SSE2));
EnsureSpace ensure_space(this);
diff --git a/deps/v8/src/ia32/assembler-ia32.h b/deps/v8/src/ia32/assembler-ia32.h
index da38e138d..c186094b3 100644
--- a/deps/v8/src/ia32/assembler-ia32.h
+++ b/deps/v8/src/ia32/assembler-ia32.h
@@ -941,6 +941,16 @@ class Assembler : public AssemblerBase {
void andpd(XMMRegister dst, XMMRegister src);
void ucomisd(XMMRegister dst, XMMRegister src);
+
+ enum RoundingMode {
+ kRoundToNearest = 0x0,
+ kRoundDown = 0x1,
+ kRoundUp = 0x2,
+ kRoundToZero = 0x3
+ };
+
+ void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
+
void movmskpd(Register dst, XMMRegister src);
void cmpltsd(XMMRegister dst, XMMRegister src);
diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc
index ed7e56c11..e39d11445 100644
--- a/deps/v8/src/ia32/code-stubs-ia32.cc
+++ b/deps/v8/src/ia32/code-stubs-ia32.cc
@@ -249,20 +249,20 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
}
// undefined -> false
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
+ CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
+ CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
+ CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
+ CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true
Label not_smi;
__ JumpIfNotSmi(argument, &not_smi, Label::kNear);
- // argument contains the correct return value already
+ // argument contains the correct return value already.
if (!tos_.is(argument)) {
__ mov(tos_, argument);
}
@@ -276,15 +276,16 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
if (types_.NeedsMap()) {
__ mov(map, FieldOperand(argument, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ test_b(FieldOperand(map, Map::kBitFieldOffset),
- 1 << Map::kIsUndetectable);
- // Undetectable -> false.
- Label not_undetectable;
- __ j(zero, &not_undetectable, Label::kNear);
- __ Set(tos_, Immediate(0));
- __ ret(1 * kPointerSize);
- __ bind(&not_undetectable);
+ if (types_.CanBeUndetectable()) {
+ __ test_b(FieldOperand(map, Map::kBitFieldOffset),
+ 1 << Map::kIsUndetectable);
+ // Undetectable -> false.
+ Label not_undetectable;
+ __ j(zero, &not_undetectable, Label::kNear);
+ __ Set(tos_, Immediate(0));
+ __ ret(1 * kPointerSize);
+ __ bind(&not_undetectable);
+ }
}
if (types_.Contains(SPEC_OBJECT)) {
@@ -292,13 +293,12 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
Label not_js_object;
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(below, &not_js_object, Label::kNear);
- __ Set(tos_, Immediate(1));
+ // argument contains the correct return value already.
+ if (!tos_.is(argument)) {
+ __ Set(tos_, Immediate(1));
+ }
__ ret(1 * kPointerSize);
__ bind(&not_js_object);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> patch.
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- __ j(above_equal, &patch, Label::kNear);
}
if (types_.Contains(STRING)) {
@@ -309,10 +309,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ mov(tos_, FieldOperand(argument, String::kLengthOffset));
__ ret(1 * kPointerSize); // the string length is OK as the return value
__ bind(&not_string);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> patch
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- __ j(below, &patch, Label::kNear);
}
if (types_.Contains(HEAP_NUMBER)) {
@@ -324,50 +320,42 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ fld_d(FieldOperand(argument, HeapNumber::kValueOffset));
__ FCmp();
__ j(zero, &false_result, Label::kNear);
- __ Set(tos_, Immediate(1));
+ // argument contains the correct return value already.
+ if (!tos_.is(argument)) {
+ __ Set(tos_, Immediate(1));
+ }
__ ret(1 * kPointerSize);
__ bind(&false_result);
__ Set(tos_, Immediate(0));
__ ret(1 * kPointerSize);
__ bind(&not_heap_number);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> patch
- __ cmp(map, factory->heap_number_map());
- __ j(equal, &patch, Label::kNear);
- }
-
- if (types_.Contains(INTERNAL_OBJECT)) {
- // internal objects -> true
- __ Set(tos_, Immediate(1));
- __ ret(1 * kPointerSize);
}
- if (!types_.IsAll()) {
- __ bind(&patch);
- GenerateTypeTransition(masm);
- }
+ __ bind(&patch);
+ GenerateTypeTransition(masm);
}
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
- bool result,
- Label* patch) {
+ bool result) {
const Register argument = eax;
if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_.
Label different_value;
__ CompareRoot(argument, value);
__ j(not_equal, &different_value, Label::kNear);
- __ Set(tos_, Immediate(result ? 1 : 0));
+ if (!result) {
+ // If we have to return zero, there is no way around clearing tos_.
+ __ Set(tos_, Immediate(0));
+ } else if (!tos_.is(argument)) {
+ // If we have to return non-zero, we can re-use the argument if it is the
+ // same register as the result, because we never see Smi-zero here.
+ __ Set(tos_, Immediate(1));
+ }
__ ret(1 * kPointerSize);
__ bind(&different_value);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // If we see an unexpected oddball and handle internal objects, we must
- // patch because the code for internal objects doesn't handle it explictly.
- __ CompareRoot(argument, value);
- __ j(equal, patch);
}
}
diff --git a/deps/v8/src/ia32/disasm-ia32.cc b/deps/v8/src/ia32/disasm-ia32.cc
index 900668fbd..a936277b2 100644
--- a/deps/v8/src/ia32/disasm-ia32.cc
+++ b/deps/v8/src/ia32/disasm-ia32.cc
@@ -1141,7 +1141,17 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
}
} else if (*data == 0x3A) {
data++;
- if (*data == 0x16) {
+ if (*data == 0x0B) {
+ data++;
+ int mod, regop, rm;
+ get_modrm(*data, &mod, &regop, &rm);
+ int8_t imm8 = static_cast<int8_t>(data[1]);
+ AppendToBuffer("roundsd %s,%s,%d",
+ NameOfXMMRegister(regop),
+ NameOfXMMRegister(rm),
+ static_cast<int>(imm8));
+ data += 2;
+ } else if (*data == 0x16) {
data++;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
diff --git a/deps/v8/src/ia32/frames-ia32.h b/deps/v8/src/ia32/frames-ia32.h
index bc65ddfad..2f1b2a96d 100644
--- a/deps/v8/src/ia32/frames-ia32.h
+++ b/deps/v8/src/ia32/frames-ia32.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -58,10 +58,11 @@ static const int kNumSafepointRegisters = 8;
class StackHandlerConstants : public AllStatic {
public:
- static const int kNextOffset = 0 * kPointerSize;
- static const int kFPOffset = 1 * kPointerSize;
- static const int kStateOffset = 2 * kPointerSize;
- static const int kPCOffset = 3 * kPointerSize;
+ static const int kNextOffset = 0 * kPointerSize;
+ static const int kContextOffset = 1 * kPointerSize;
+ static const int kFPOffset = 2 * kPointerSize;
+ static const int kStateOffset = 3 * kPointerSize;
+ static const int kPCOffset = 4 * kPointerSize;
static const int kSize = kPCOffset + kPointerSize;
};
diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc
index 994c9ff61..bb75b1e6a 100644
--- a/deps/v8/src/ia32/full-codegen-ia32.cc
+++ b/deps/v8/src/ia32/full-codegen-ia32.cc
@@ -737,8 +737,10 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ push(esi);
__ push(Immediate(variable->name()));
// Declaration nodes are always introduced in one of two modes.
- ASSERT(mode == Variable::VAR || mode == Variable::CONST);
- PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
+ ASSERT(mode == Variable::VAR ||
+ mode == Variable::CONST ||
+ mode == Variable::LET);
+ PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
__ push(Immediate(Smi::FromInt(attr)));
// Push initial value, if any.
// Note: For variables we must not push an initial value (such as
@@ -3830,7 +3832,6 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
const char* comment) {
- // TODO(svenpanne): Allowing format strings in Comment would be nice here...
Comment cmt(masm_, comment);
bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
UnaryOverwriteMode overwrite =
@@ -4105,6 +4106,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
__ j(equal, if_true);
__ cmp(eax, isolate()->factory()->false_value());
Split(equal, if_true, if_false, fall_through);
+ } else if (FLAG_harmony_typeof &&
+ check->Equals(isolate()->heap()->null_symbol())) {
+ __ cmp(eax, isolate()->factory()->null_value());
+ Split(equal, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ cmp(eax, isolate()->factory()->undefined_value());
__ j(equal, if_true);
@@ -4120,8 +4125,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Split(above_equal, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(eax, if_false);
- __ cmp(eax, isolate()->factory()->null_value());
- __ j(equal, if_true);
+ if (!FLAG_harmony_typeof) {
+ __ cmp(eax, isolate()->factory()->null_value());
+ __ j(equal, if_true);
+ }
__ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
__ j(below, if_false);
__ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc
index c0f4e71ca..71fe8d95e 100644
--- a/deps/v8/src/ia32/lithium-codegen-ia32.cc
+++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc
@@ -1211,17 +1211,11 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
}
-void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
+void LCodeGen::DoFixedArrayBaseLength(
+ LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
- __ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
-}
-
-
-void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
- Register result = ToRegister(instr->result());
- Register array = ToRegister(instr->InputAt(0));
- __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
+ __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
}
@@ -1412,40 +1406,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
// undefined -> false.
__ cmp(reg, factory()->undefined_value());
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen undefined for the first time -> deopt.
- __ cmp(reg, factory()->undefined_value());
- DeoptimizeIf(equal, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// true -> true.
__ cmp(reg, factory()->true_value());
__ j(equal, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ cmp(reg, factory()->true_value());
- DeoptimizeIf(equal, instr->environment());
- }
-
- if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// false -> false.
__ cmp(reg, factory()->false_value());
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ cmp(reg, factory()->false_value());
- DeoptimizeIf(equal, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false.
__ cmp(reg, factory()->null_value());
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen null for the first time -> deopt.
- __ cmp(reg, factory()->null_value());
- DeoptimizeIf(equal, instr->environment());
}
if (expected.Contains(ToBooleanStub::SMI)) {
@@ -1459,26 +1432,24 @@ void LCodeGen::DoBranch(LBranch* instr) {
DeoptimizeIf(zero, instr->environment());
}
- Register map = no_reg;
+ Register map = no_reg; // Keep the compiler happy.
if (expected.NeedsMap()) {
map = ToRegister(instr->TempAt(0));
ASSERT(!map.is(reg));
__ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ test_b(FieldOperand(map, Map::kBitFieldOffset),
- 1 << Map::kIsUndetectable);
- // Undetectable -> false.
- __ j(not_zero, false_label);
+
+ if (expected.CanBeUndetectable()) {
+ // Undetectable -> false.
+ __ test_b(FieldOperand(map, Map::kBitFieldOffset),
+ 1 << Map::kIsUndetectable);
+ __ j(not_zero, false_label);
+ }
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true.
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(above_equal, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> deopt.
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- DeoptimizeIf(above_equal, instr->environment());
}
if (expected.Contains(ToBooleanStub::STRING)) {
@@ -1490,10 +1461,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ j(not_zero, true_label);
__ jmp(false_label);
__ bind(&not_string);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> deopt
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- DeoptimizeIf(below, instr->environment());
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@@ -1508,20 +1475,10 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ j(zero, false_label);
__ jmp(true_label);
__ bind(&not_heap_number);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> deopt.
- __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
- factory()->heap_number_map());
- DeoptimizeIf(equal, instr->environment());
}
- if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // internal objects -> true
- __ jmp(true_label);
- } else {
- // We've seen something for the first time -> deopt.
- DeoptimizeIf(no_condition, instr->environment());
- }
+ // We've seen something for the first time -> deopt.
+ DeoptimizeIf(no_condition, instr->environment());
}
}
}
@@ -2302,16 +2259,13 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
- Register elements = ToRegister(instr->elements());
- Register key = ToRegister(instr->key());
Register result = ToRegister(instr->result());
- ASSERT(result.is(elements));
// Load the result.
- __ mov(result, FieldOperand(elements,
- key,
- times_pointer_size,
- FixedArray::kHeaderSize));
+ __ mov(result,
+ BuildFastArrayOperand(instr->elements(), instr->key(),
+ JSObject::FAST_ELEMENTS,
+ FixedArray::kHeaderSize - kHeapObjectTag));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
@@ -2344,22 +2298,22 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Operand LCodeGen::BuildFastArrayOperand(
- LOperand* external_pointer,
+ LOperand* elements_pointer,
LOperand* key,
JSObject::ElementsKind elements_kind,
uint32_t offset) {
- Register external_pointer_reg = ToRegister(external_pointer);
+ Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) {
int constant_value = ToInteger32(LConstantOperand::cast(key));
if (constant_value & 0xF0000000) {
Abort("array index constant value too big");
}
- return Operand(external_pointer_reg,
+ return Operand(elements_pointer_reg,
constant_value * (1 << shift_size) + offset);
} else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
- return Operand(external_pointer_reg, ToRegister(key), scale_factor, offset);
+ return Operand(elements_pointer_reg, ToRegister(key), scale_factor, offset);
}
}
@@ -2756,23 +2710,53 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
- __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
- __ ucomisd(input_reg, xmm_scratch);
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- DeoptimizeIf(below_equal, instr->environment());
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatures::Scope scope(SSE4_1);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ // Deoptimize on negative zero.
+ Label non_zero;
+ __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
+ __ ucomisd(input_reg, xmm_scratch);
+ __ j(not_equal, &non_zero, Label::kNear);
+ __ movmskpd(output_reg, input_reg);
+ __ test(output_reg, Immediate(1));
+ DeoptimizeIf(not_zero, instr->environment());
+ __ bind(&non_zero);
+ }
+ __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
+ __ cvttsd2si(output_reg, Operand(xmm_scratch));
+ // Overflow is signalled with minint.
+ __ cmp(output_reg, 0x80000000u);
+ DeoptimizeIf(equal, instr->environment());
} else {
+ Label done;
+ // Deoptimize on negative numbers.
+ __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
+ __ ucomisd(input_reg, xmm_scratch);
DeoptimizeIf(below, instr->environment());
- }
- // Use truncating instruction (OK because input is positive).
- __ cvttsd2si(output_reg, Operand(input_reg));
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ // Check for negative zero.
+ Label positive_sign;
+ __ j(above, &positive_sign, Label::kNear);
+ __ movmskpd(output_reg, input_reg);
+ __ test(output_reg, Immediate(1));
+ DeoptimizeIf(not_zero, instr->environment());
+ __ Set(output_reg, Immediate(0));
+ __ jmp(&done, Label::kNear);
+ __ bind(&positive_sign);
+ }
- // Overflow is signalled with minint.
- __ cmp(output_reg, 0x80000000u);
- DeoptimizeIf(equal, instr->environment());
-}
+ // Use truncating instruction (OK because input is positive).
+ __ cvttsd2si(output_reg, Operand(input_reg));
+ // Overflow is signalled with minint.
+ __ cmp(output_reg, 0x80000000u);
+ DeoptimizeIf(equal, instr->environment());
+ __ bind(&done);
+ }
+}
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
XMMRegister xmm_scratch = xmm0;
@@ -2783,13 +2767,11 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
// xmm_scratch = 0.5
ExternalReference one_half = ExternalReference::address_of_one_half();
__ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
-
__ ucomisd(xmm_scratch, input_reg);
__ j(above, &below_half);
// input = input + 0.5
__ addsd(input_reg, xmm_scratch);
-
// Compute Math.floor(value + 0.5).
// Use truncating instruction (OK because input is positive).
__ cvttsd2si(output_reg, Operand(input_reg));
@@ -3108,8 +3090,14 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
- __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
- DeoptimizeIf(above_equal, instr->environment());
+ if (instr->index()->IsConstantOperand()) {
+ __ cmp(ToOperand(instr->length()),
+ ToImmediate(LConstantOperand::cast(instr->index())));
+ DeoptimizeIf(below_equal, instr->environment());
+ } else {
+ __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
+ DeoptimizeIf(above_equal, instr->environment());
+ }
}
@@ -4200,6 +4188,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
__ cmp(input, factory()->false_value());
final_branch_condition = equal;
+ } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
+ __ cmp(input, factory()->null_value());
+ final_branch_condition = equal;
+
} else if (type_name->Equals(heap()->undefined_symbol())) {
__ cmp(input, factory()->undefined_value());
__ j(equal, true_label);
@@ -4218,8 +4210,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
} else if (type_name->Equals(heap()->object_symbol())) {
__ JumpIfSmi(input, false_label);
- __ cmp(input, factory()->null_value());
- __ j(equal, true_label);
+ if (!FLAG_harmony_typeof) {
+ __ cmp(input, factory()->null_value());
+ __ j(equal, true_label);
+ }
__ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
__ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h
index c568bef5b..d26f24555 100644
--- a/deps/v8/src/ia32/lithium-codegen-ia32.h
+++ b/deps/v8/src/ia32/lithium-codegen-ia32.h
@@ -222,7 +222,7 @@ class LCodeGen BASE_EMBEDDED {
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
int ToInteger32(LConstantOperand* op) const;
- Operand BuildFastArrayOperand(LOperand* external_pointer,
+ Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
JSObject::ElementsKind elements_kind,
uint32_t offset);
diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc
index 07867c70f..bb92e89d3 100644
--- a/deps/v8/src/ia32/lithium-ia32.cc
+++ b/deps/v8/src/ia32/lithium-ia32.cc
@@ -1047,10 +1047,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
// involving maps).
bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
LOperand* temp = needs_temp ? TempRegister() : NULL;
- LInstruction* branch = new LBranch(UseRegister(v), temp);
- // When we handle all cases, we never deopt, so we don't need to assign the
- // environment then.
- return expected.IsAll() ? branch : AssignEnvironment(branch);
+ return AssignEnvironment(new LBranch(UseRegister(v), temp));
}
@@ -1541,16 +1538,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
-LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
+LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
+ HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LFixedArrayLength(array));
-}
-
-
-LInstruction* LChunkBuilder::DoExternalArrayLength(
- HExternalArrayLength* instr) {
- LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LExternalArrayLength(array));
+ return DefineAsRegister(new LFixedArrayBaseLength(array));
}
@@ -1568,8 +1559,9 @@ LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
- return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
- UseAtStart(instr->length())));
+ return AssignEnvironment(new LBoundsCheck(
+ UseRegisterOrConstantAtStart(instr->index()),
+ UseAtStart(instr->length())));
}
@@ -1890,9 +1882,9 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
ASSERT(instr->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* obj = UseRegisterAtStart(instr->object());
- LOperand* key = UseRegisterAtStart(instr->key());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
- return AssignEnvironment(DefineSameAsFirst(result));
+ return AssignEnvironment(DefineAsRegister(result));
}
diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h
index efa048dd2..e752b714e 100644
--- a/deps/v8/src/ia32/lithium-ia32.h
+++ b/deps/v8/src/ia32/lithium-ia32.h
@@ -86,8 +86,7 @@ class LCodeGen;
V(DivI) \
V(DoubleToI) \
V(ElementsKind) \
- V(ExternalArrayLength) \
- V(FixedArrayLength) \
+ V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
@@ -922,25 +921,15 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
};
-class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
+class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LExternalArrayLength(LOperand* value) {
+ explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value;
}
- DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
- DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
-};
-
-
-class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LFixedArrayLength(LOperand* value) {
- inputs_[0] = value;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
- DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
+ DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
+ "fixed-array-base-length")
+ DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
};
@@ -2248,14 +2237,18 @@ class LChunkBuilder BASE_EMBEDDED {
template<int I, int T>
LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr,
XMMRegister reg);
+ // Assigns an environment to an instruction. An instruction which can
+ // deoptimize must have an environment.
LInstruction* AssignEnvironment(LInstruction* instr);
+ // Assigns a pointer map to an instruction. An instruction which can
+ // trigger a GC or a lazy deoptimization must have a pointer map.
LInstruction* AssignPointerMap(LInstruction* instr);
enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
- // By default we assume that instruction sequences generated for calls
- // cannot deoptimize eagerly and we do not attach environment to this
- // instruction.
+ // Marks a call for the register allocator. Assigns a pointer map to
+ // support GC and lazy deoptimization. Assigns an environment to support
+ // eager deoptimization if CAN_DEOPTIMIZE_EAGERLY.
LInstruction* MarkAsCall(
LInstruction* instr,
HInstruction* hinstr,
diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc
index acb670b70..04e6cde4e 100644
--- a/deps/v8/src/ia32/macro-assembler-ia32.cc
+++ b/deps/v8/src/ia32/macro-assembler-ia32.cc
@@ -542,7 +542,12 @@ void MacroAssembler::LeaveApiExitFrame() {
void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) {
// Adjust this code if not the case.
- ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// The pc (return address) is already on TOS.
if (try_location == IN_JAVASCRIPT) {
if (type == TRY_CATCH_HANDLER) {
@@ -551,6 +556,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
push(Immediate(StackHandler::TRY_FINALLY));
}
push(ebp);
+ push(esi);
} else {
ASSERT(try_location == IN_JS_ENTRY);
// The frame pointer does not point to a JS frame so we save NULL
@@ -558,6 +564,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
// before dereferencing it to restore the context.
push(Immediate(StackHandler::ENTRY));
push(Immediate(0)); // NULL frame pointer.
+ push(Immediate(Smi::FromInt(0))); // No context.
}
// Save the current handler as the next handler.
push(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
@@ -570,7 +577,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() {
- ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
isolate())));
add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
@@ -579,8 +586,12 @@ void MacroAssembler::PopTryHandler() {
void MacroAssembler::Throw(Register value) {
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
-
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// eax must hold the exception.
if (!value.is(eax)) {
mov(eax, value);
@@ -591,24 +602,21 @@ void MacroAssembler::Throw(Register value) {
isolate());
mov(esp, Operand::StaticVariable(handler_address));
- // Restore next handler and frame pointer, discard handler state.
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+ // Restore next handler, context, and frame pointer; discard handler state.
pop(Operand::StaticVariable(handler_address));
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize);
- pop(ebp);
- pop(edx); // Remove state.
+ pop(esi); // Context.
+ pop(ebp); // Frame pointer.
+ pop(edx); // State.
- // Before returning we restore the context from the frame pointer if
- // not NULL. The frame pointer is NULL in the exception handler of
- // a JS entry frame.
- Set(esi, Immediate(0)); // Tentatively set context pointer to NULL.
+ // If the handler is a JS frame, restore the context to the frame.
+ // (edx == ENTRY) == (ebp == 0) == (esi == 0), so we could test any
+ // of them.
Label skip;
- cmp(ebp, 0);
+ cmp(Operand(edx), Immediate(StackHandler::ENTRY));
j(equal, &skip, Label::kNear);
- mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
bind(&skip);
- STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
ret(0);
}
@@ -616,7 +624,12 @@ void MacroAssembler::Throw(Register value) {
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) {
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// eax must hold the exception.
if (!value.is(eax)) {
@@ -642,7 +655,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(Operand::StaticVariable(handler_address));
if (type == OUT_OF_MEMORY) {
@@ -660,15 +672,14 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
mov(Operand::StaticVariable(pending_exception), eax);
}
- // Clear the context pointer.
+ // Discard the context saved in the handler and clear the context pointer.
+ pop(edx);
Set(esi, Immediate(0));
// Restore fp from handler and discard handler state.
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize);
pop(ebp);
pop(edx); // State.
- STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
ret(0);
}
diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc
index 73f42a3d1..4a37b07c7 100644
--- a/deps/v8/src/ia32/stub-cache-ia32.cc
+++ b/deps/v8/src/ia32/stub-cache-ia32.cc
@@ -3400,37 +3400,37 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ JumpIfNotSmi(eax, &miss_force_generic);
// Check that the index is in range.
- __ mov(ecx, eax);
- __ SmiUntag(ecx); // Untag the index.
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
- __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
+ __ cmp(eax, FieldOperand(ebx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &miss_force_generic);
__ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
// ebx: base pointer of external storage
switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS:
- __ movsx_b(eax, Operand(ebx, ecx, times_1, 0));
+ __ SmiUntag(eax); // Untag the index.
+ __ movsx_b(eax, Operand(ebx, eax, times_1, 0));
break;
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- __ movzx_b(eax, Operand(ebx, ecx, times_1, 0));
+ __ SmiUntag(eax); // Untag the index.
+ __ movzx_b(eax, Operand(ebx, eax, times_1, 0));
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
- __ movsx_w(eax, Operand(ebx, ecx, times_2, 0));
+ __ movsx_w(eax, Operand(ebx, eax, times_1, 0));
break;
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ movzx_w(eax, Operand(ebx, ecx, times_2, 0));
+ __ movzx_w(eax, Operand(ebx, eax, times_1, 0));
break;
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
case JSObject::EXTERNAL_INT_ELEMENTS:
- __ mov(ecx, Operand(ebx, ecx, times_4, 0));
+ __ mov(ecx, Operand(ebx, eax, times_2, 0));
break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- __ fld_s(Operand(ebx, ecx, times_4, 0));
+ __ fld_s(Operand(ebx, eax, times_2, 0));
break;
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- __ fld_d(Operand(ebx, ecx, times_8, 0));
+ __ fld_d(Operand(ebx, eax, times_4, 0));
break;
default:
UNREACHABLE();
@@ -3556,9 +3556,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Check that the index is in range.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
- __ mov(ebx, ecx);
- __ SmiUntag(ebx);
- __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
+ __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &slow);
@@ -3568,7 +3566,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// edx: receiver
// ecx: key
// edi: elements array
- // ebx: untagged index
if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
__ JumpIfNotSmi(eax, &slow);
} else {
@@ -3576,44 +3573,39 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
}
// smi case
- __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed.
- __ SmiUntag(ecx);
+ __ mov(ebx, eax); // Preserve the value in eax as the return value.
+ __ SmiUntag(ebx);
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
- // ecx: base pointer of external storage
+ // edi: base pointer of external storage
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- { // Clamp the value to [0..255].
- Label done;
- __ test(ecx, Immediate(0xFFFFFF00));
- __ j(zero, &done, Label::kNear);
- __ setcc(negative, ecx); // 1 if negative, 0 if positive.
- __ dec_b(ecx); // 0 if negative, 255 if positive.
- __ bind(&done);
- }
- __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+ __ ClampUint8(ebx);
+ __ SmiUntag(ecx);
+ __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+ __ SmiUntag(ecx);
+ __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
+ __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- __ mov(Operand(edi, ebx, times_4, 0), ecx);
+ __ mov(Operand(edi, ecx, times_2, 0), ebx);
break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
// Need to perform int-to-float conversion.
- __ push(ecx);
+ __ push(ebx);
__ fild_s(Operand(esp, 0));
- __ pop(ecx);
+ __ pop(ebx);
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
- __ fstp_s(Operand(edi, ebx, times_4, 0));
+ __ fstp_s(Operand(edi, ecx, times_2, 0));
} else { // elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS.
- __ fstp_d(Operand(edi, ebx, times_8, 0));
+ __ fstp_d(Operand(edi, ecx, times_4, 0));
}
break;
default:
@@ -3629,7 +3621,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// edx: receiver
// ecx: key
// edi: elements array
- // ebx: untagged index
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
Immediate(masm->isolate()->factory()->heap_number_map()));
__ j(not_equal, &slow);
@@ -3638,15 +3629,14 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// +/-Infinity into integer arrays basically undefined. For more
// reproducible behavior, convert these to zero.
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
- // ebx: untagged index
// edi: base pointer of external storage
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
- __ fstp_s(Operand(edi, ebx, times_4, 0));
+ __ fstp_s(Operand(edi, ecx, times_2, 0));
__ ret(0);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
- __ fstp_d(Operand(edi, ebx, times_8, 0));
+ __ fstp_d(Operand(edi, ecx, times_4, 0));
__ ret(0);
} else {
// Perform float-to-int conversion with truncation (round-to-zero)
@@ -3661,27 +3651,20 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
elements_kind != JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
ASSERT(CpuFeatures::IsSupported(SSE2));
CpuFeatures::Scope scope(SSE2);
- __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset));
+ __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
// ecx: untagged integer value
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- { // Clamp the value to [0..255].
- Label done;
- __ test(ecx, Immediate(0xFFFFFF00));
- __ j(zero, &done, Label::kNear);
- __ setcc(negative, ecx); // 1 if negative, 0 if positive.
- __ dec_b(ecx); // 0 if negative, 255 if positive.
- __ bind(&done);
- }
- __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
- break;
+ __ ClampUint8(ebx);
+ // Fall through.
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+ __ SmiUntag(ecx);
+ __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
+ __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
break;
default:
UNREACHABLE();
@@ -3698,7 +3681,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ sub(Operand(esp), Immediate(2 * kPointerSize));
__ fisttp_d(Operand(esp, 0));
- __ pop(ecx);
+ __ pop(ebx);
__ add(Operand(esp), Immediate(kPointerSize));
} else {
ASSERT(CpuFeatures::IsSupported(SSE2));
@@ -3709,15 +3692,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Note: we could do better for signed int arrays.
__ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
// We will need the key if we have to make the slow runtime call.
- __ push(ecx);
- __ LoadPowerOf2(xmm1, ecx, 31);
- __ pop(ecx);
+ __ push(ebx);
+ __ LoadPowerOf2(xmm1, ebx, 31);
+ __ pop(ebx);
__ ucomisd(xmm1, xmm0);
__ j(above_equal, &slow);
- __ cvttsd2si(ecx, Operand(xmm0));
+ __ cvttsd2si(ebx, Operand(xmm0));
}
- // ecx: untagged integer value
- __ mov(Operand(edi, ebx, times_4, 0), ecx);
+ // ebx: untagged integer value
+ __ mov(Operand(edi, ecx, times_2, 0), ebx);
}
__ ret(0); // Return original value.
}
diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc
index 9ca61177b..eae812bcd 100644
--- a/deps/v8/src/isolate.cc
+++ b/deps/v8/src/isolate.cc
@@ -1533,6 +1533,9 @@ void Isolate::SetIsolateThreadLocals(Isolate* isolate,
Isolate::~Isolate() {
TRACE_ISOLATE(destructor);
+ // Has to be called while counters_ are still alive.
+ zone_.DeleteKeptSegment();
+
delete unicode_cache_;
unicode_cache_ = NULL;
@@ -1591,6 +1594,9 @@ Isolate::~Isolate() {
delete global_handles_;
global_handles_ = NULL;
+ delete external_reference_table_;
+ external_reference_table_ = NULL;
+
#ifdef ENABLE_DEBUGGER_SUPPORT
delete debugger_;
debugger_ = NULL;
diff --git a/deps/v8/src/liveobjectlist.cc b/deps/v8/src/liveobjectlist.cc
index e382a0645..451a28ab7 100644
--- a/deps/v8/src/liveobjectlist.cc
+++ b/deps/v8/src/liveobjectlist.cc
@@ -36,11 +36,12 @@
#include "global-handles.h"
#include "heap.h"
#include "inspector.h"
+#include "isolate.h"
#include "list-inl.h"
#include "liveobjectlist-inl.h"
#include "string-stream.h"
-#include "top.h"
#include "v8utils.h"
+#include "v8conversions.h"
namespace v8 {
namespace internal {
@@ -109,7 +110,7 @@ typedef int (*RawComparer)(const void*, const void*);
\
v(Context, "meta: Context") \
v(ByteArray, "meta: ByteArray") \
- v(PixelArray, "meta: PixelArray") \
+ v(ExternalPixelArray, "meta: PixelArray") \
v(ExternalArray, "meta: ExternalArray") \
v(FixedArray, "meta: FixedArray") \
v(String, "String") \
@@ -211,8 +212,9 @@ static AllocationSpace FindSpaceFor(String* space_str) {
static bool InSpace(AllocationSpace space, HeapObject *heap_obj) {
+ Heap* heap = ISOLATE->heap();
if (space != LO_SPACE) {
- return Heap::InSpace(heap_obj, space);
+ return heap->InSpace(heap_obj, space);
}
// This is an optimization to speed up the check for an object in the LO
@@ -224,11 +226,11 @@ static bool InSpace(AllocationSpace space, HeapObject *heap_obj) {
int first_space = static_cast<int>(FIRST_SPACE);
int last_space = static_cast<int>(LO_SPACE);
for (int sp = first_space; sp < last_space; sp++) {
- if (Heap::InSpace(heap_obj, static_cast<AllocationSpace>(sp))) {
+ if (heap->InSpace(heap_obj, static_cast<AllocationSpace>(sp))) {
return false;
}
}
- SLOW_ASSERT(Heap::InSpace(heap_obj, LO_SPACE));
+ SLOW_ASSERT(heap->InSpace(heap_obj, LO_SPACE));
return true;
}
@@ -285,7 +287,7 @@ LolFilter::LolFilter(Handle<JSObject> filter_obj)
void LolFilter::InitTypeFilter(Handle<JSObject> filter_obj) {
- Handle<String> type_sym = Factory::LookupAsciiSymbol("type");
+ Handle<String> type_sym = FACTORY->LookupAsciiSymbol("type");
MaybeObject* maybe_result = filter_obj->GetProperty(*type_sym);
Object* type_obj;
if (maybe_result->ToObject(&type_obj)) {
@@ -301,7 +303,7 @@ void LolFilter::InitTypeFilter(Handle<JSObject> filter_obj) {
void LolFilter::InitSpaceFilter(Handle<JSObject> filter_obj) {
- Handle<String> space_sym = Factory::LookupAsciiSymbol("space");
+ Handle<String> space_sym = FACTORY->LookupAsciiSymbol("space");
MaybeObject* maybe_result = filter_obj->GetProperty(*space_sym);
Object* space_obj;
if (maybe_result->ToObject(&space_obj)) {
@@ -317,7 +319,7 @@ void LolFilter::InitSpaceFilter(Handle<JSObject> filter_obj) {
void LolFilter::InitPropertyFilter(Handle<JSObject> filter_obj) {
- Handle<String> prop_sym = Factory::LookupAsciiSymbol("prop");
+ Handle<String> prop_sym = FACTORY->LookupAsciiSymbol("prop");
MaybeObject* maybe_result = filter_obj->GetProperty(*prop_sym);
Object* prop_obj;
if (maybe_result->ToObject(&prop_obj)) {
@@ -571,7 +573,9 @@ static bool AddObjDetail(Handle<FixedArray> arr,
Handle<JSObject> detail,
Handle<String> desc,
Handle<Object> error) {
- detail = Factory::NewJSObject(Top::object_function());
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ detail = factory->NewJSObject(isolate->object_function());
if (detail->IsFailure()) {
error = detail;
return false;
@@ -586,7 +590,7 @@ static bool AddObjDetail(Handle<FixedArray> arr,
desc_str = buffer;
size = obj->Size();
}
- desc = Factory::NewStringFromAscii(CStrVector(desc_str));
+ desc = factory->NewStringFromAscii(CStrVector(desc_str));
if (desc->IsFailure()) {
error = desc;
return false;
@@ -663,10 +667,13 @@ class LolDumpWriter: public DumpWriter {
int index = 0;
int count = 0;
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+
// Prefetch some needed symbols.
- Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
- Handle<String> desc_sym = Factory::LookupAsciiSymbol("desc");
- Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
+ Handle<String> id_sym = factory->LookupAsciiSymbol("id");
+ Handle<String> desc_sym = factory->LookupAsciiSymbol("desc");
+ Handle<String> size_sym = factory->LookupAsciiSymbol("size");
// Fill the array with the lol object details.
Handle<JSObject> detail;
@@ -1089,7 +1096,9 @@ static int CountHeapObjects() {
// Captures a current snapshot of all objects in the heap.
MaybeObject* LiveObjectList::Capture() {
- HandleScope scope;
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope scope(isolate);
// Count the number of objects in the heap.
int total_count = CountHeapObjects();
@@ -1139,11 +1148,11 @@ MaybeObject* LiveObjectList::Capture() {
#endif
}
- Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
- Handle<String> count_sym = Factory::LookupAsciiSymbol("count");
- Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
+ Handle<String> id_sym = factory->LookupAsciiSymbol("id");
+ Handle<String> count_sym = factory->LookupAsciiSymbol("count");
+ Handle<String> size_sym = factory->LookupAsciiSymbol("size");
- Handle<JSObject> result = Factory::NewJSObject(Top::object_function());
+ Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
if (result->IsFailure()) return Object::cast(*result);
{ MaybeObject* maybe_result = result->SetProperty(*id_sym,
@@ -1259,7 +1268,10 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
int start,
int dump_limit,
LolFilter* filter) {
- HandleScope scope;
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+
+ HandleScope scope(isolate);
// Calculate the number of entries of the dump.
int count = -1;
@@ -1277,7 +1289,7 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
}
// Allocate an array to hold the result.
- Handle<FixedArray> elements_arr = Factory::NewFixedArray(dump_limit);
+ Handle<FixedArray> elements_arr = factory->NewFixedArray(dump_limit);
if (elements_arr->IsFailure()) return Object::cast(*elements_arr);
// Fill in the dump.
@@ -1292,11 +1304,11 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
MaybeObject* maybe_result;
// Allocate the result body.
- Handle<JSObject> body = Factory::NewJSObject(Top::object_function());
+ Handle<JSObject> body = factory->NewJSObject(isolate->object_function());
if (body->IsFailure()) return Object::cast(*body);
// Set the updated body.count.
- Handle<String> count_sym = Factory::LookupAsciiSymbol("count");
+ Handle<String> count_sym = factory->LookupAsciiSymbol("count");
maybe_result = body->SetProperty(*count_sym,
Smi::FromInt(count),
NONE,
@@ -1305,7 +1317,7 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
// Set the updated body.size if appropriate.
if (size >= 0) {
- Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
+ Handle<String> size_sym = factory->LookupAsciiSymbol("size");
maybe_result = body->SetProperty(*size_sym,
Smi::FromInt(size),
NONE,
@@ -1314,7 +1326,7 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
}
// Set body.first_index.
- Handle<String> first_sym = Factory::LookupAsciiSymbol("first_index");
+ Handle<String> first_sym = factory->LookupAsciiSymbol("first_index");
maybe_result = body->SetProperty(*first_sym,
Smi::FromInt(start),
NONE,
@@ -1322,12 +1334,12 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
if (maybe_result->IsFailure()) return maybe_result;
// Allocate the JSArray of the elements.
- Handle<JSObject> elements = Factory::NewJSObject(Top::array_function());
+ Handle<JSObject> elements = factory->NewJSObject(isolate->array_function());
if (elements->IsFailure()) return Object::cast(*elements);
Handle<JSArray>::cast(elements)->SetContent(*elements_arr);
// Set body.elements.
- Handle<String> elements_sym = Factory::LookupAsciiSymbol("elements");
+ Handle<String> elements_sym = factory->LookupAsciiSymbol("elements");
maybe_result = body->SetProperty(*elements_sym,
*elements,
NONE,
@@ -1381,6 +1393,9 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
LiveObjectSummary summary(filter);
writer->Write(&summary);
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+
// The result body will look like this:
// body: {
// count: <total_count>,
@@ -1398,21 +1413,21 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
// }
// Prefetch some needed symbols.
- Handle<String> desc_sym = Factory::LookupAsciiSymbol("desc");
- Handle<String> count_sym = Factory::LookupAsciiSymbol("count");
- Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
- Handle<String> summary_sym = Factory::LookupAsciiSymbol("summary");
+ Handle<String> desc_sym = factory->LookupAsciiSymbol("desc");
+ Handle<String> count_sym = factory->LookupAsciiSymbol("count");
+ Handle<String> size_sym = factory->LookupAsciiSymbol("size");
+ Handle<String> summary_sym = factory->LookupAsciiSymbol("summary");
// Allocate the summary array.
int entries_count = summary.GetNumberOfEntries();
Handle<FixedArray> summary_arr =
- Factory::NewFixedArray(entries_count);
+ factory->NewFixedArray(entries_count);
if (summary_arr->IsFailure()) return Object::cast(*summary_arr);
int idx = 0;
for (int i = 0; i < LiveObjectSummary::kNumberOfEntries; i++) {
// Allocate the summary record.
- Handle<JSObject> detail = Factory::NewJSObject(Top::object_function());
+ Handle<JSObject> detail = factory->NewJSObject(isolate->object_function());
if (detail->IsFailure()) return Object::cast(*detail);
// Fill in the summary record.
@@ -1420,7 +1435,7 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
int count = summary.Count(type);
if (count) {
const char* desc_cstr = GetObjectTypeDesc(type);
- Handle<String> desc = Factory::LookupAsciiSymbol(desc_cstr);
+ Handle<String> desc = factory->LookupAsciiSymbol(desc_cstr);
int size = summary.Size(type);
maybe_result = detail->SetProperty(*desc_sym,
@@ -1444,12 +1459,13 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
}
// Wrap the summary fixed array in a JS array.
- Handle<JSObject> summary_obj = Factory::NewJSObject(Top::array_function());
+ Handle<JSObject> summary_obj =
+ factory->NewJSObject(isolate->array_function());
if (summary_obj->IsFailure()) return Object::cast(*summary_obj);
Handle<JSArray>::cast(summary_obj)->SetContent(*summary_arr);
// Create the body object.
- Handle<JSObject> body = Factory::NewJSObject(Top::object_function());
+ Handle<JSObject> body = factory->NewJSObject(isolate->object_function());
if (body->IsFailure()) return Object::cast(*body);
// Fill out the body object.
@@ -1470,9 +1486,9 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
if (is_tracking_roots) {
int found_root = summary.found_root();
int found_weak_root = summary.found_weak_root();
- Handle<String> root_sym = Factory::LookupAsciiSymbol("found_root");
+ Handle<String> root_sym = factory->LookupAsciiSymbol("found_root");
Handle<String> weak_root_sym =
- Factory::LookupAsciiSymbol("found_weak_root");
+ factory->LookupAsciiSymbol("found_weak_root");
maybe_result = body->SetProperty(*root_sym,
Smi::FromInt(found_root),
NONE,
@@ -1499,7 +1515,10 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
// Note: only dumps the section starting at start_idx and only up to
// dump_limit entries.
MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) {
- HandleScope scope;
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+
+ HandleScope scope(isolate);
MaybeObject* maybe_result;
int total_count = LiveObjectList::list_count();
@@ -1519,13 +1538,13 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) {
}
// Allocate an array to hold the result.
- Handle<FixedArray> list = Factory::NewFixedArray(dump_count);
+ Handle<FixedArray> list = factory->NewFixedArray(dump_count);
if (list->IsFailure()) return Object::cast(*list);
// Prefetch some needed symbols.
- Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
- Handle<String> count_sym = Factory::LookupAsciiSymbol("count");
- Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
+ Handle<String> id_sym = factory->LookupAsciiSymbol("id");
+ Handle<String> count_sym = factory->LookupAsciiSymbol("count");
+ Handle<String> size_sym = factory->LookupAsciiSymbol("size");
// Fill the array with the lol details.
int idx = 0;
@@ -1543,7 +1562,8 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) {
int size;
count = lol->GetTotalObjCountAndSize(&size);
- Handle<JSObject> detail = Factory::NewJSObject(Top::object_function());
+ Handle<JSObject> detail =
+ factory->NewJSObject(isolate->object_function());
if (detail->IsFailure()) return Object::cast(*detail);
maybe_result = detail->SetProperty(*id_sym,
@@ -1568,10 +1588,10 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) {
}
// Return the result as a JS array.
- Handle<JSObject> lols = Factory::NewJSObject(Top::array_function());
+ Handle<JSObject> lols = factory->NewJSObject(isolate->array_function());
Handle<JSArray>::cast(lols)->SetContent(*list);
- Handle<JSObject> result = Factory::NewJSObject(Top::object_function());
+ Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
if (result->IsFailure()) return Object::cast(*result);
maybe_result = result->SetProperty(*count_sym,
@@ -1580,14 +1600,14 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) {
kNonStrictMode);
if (maybe_result->IsFailure()) return maybe_result;
- Handle<String> first_sym = Factory::LookupAsciiSymbol("first_index");
+ Handle<String> first_sym = factory->LookupAsciiSymbol("first_index");
maybe_result = result->SetProperty(*first_sym,
Smi::FromInt(start_idx),
NONE,
kNonStrictMode);
if (maybe_result->IsFailure()) return maybe_result;
- Handle<String> lists_sym = Factory::LookupAsciiSymbol("lists");
+ Handle<String> lists_sym = factory->LookupAsciiSymbol("lists");
maybe_result = result->SetProperty(*lists_sym,
*lols,
NONE,
@@ -1618,7 +1638,7 @@ Object* LiveObjectList::GetObj(int obj_id) {
if (element != NULL) {
return Object::cast(element->obj_);
}
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
@@ -1639,8 +1659,11 @@ Object* LiveObjectList::GetObjId(Handle<String> address) {
SmartPointer<char> addr_str =
address->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ Isolate* isolate = Isolate::Current();
+
// Extract the address value from the string.
- int value = static_cast<int>(StringToInt(*address, 16));
+ int value =
+ static_cast<int>(StringToInt(isolate->unicode_cache(), *address, 16));
Object* obj = reinterpret_cast<Object*>(value);
return Smi::FromInt(GetObjId(obj));
}
@@ -1760,10 +1783,13 @@ int LiveObjectList::GetRetainers(Handle<HeapObject> target,
Handle<String> desc;
Handle<HeapObject> retainer;
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+
// Prefetch some needed symbols.
- Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
- Handle<String> desc_sym = Factory::LookupAsciiSymbol("desc");
- Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
+ Handle<String> id_sym = factory->LookupAsciiSymbol("id");
+ Handle<String> desc_sym = factory->LookupAsciiSymbol("desc");
+ Handle<String> size_sym = factory->LookupAsciiSymbol("size");
NoHandleAllocation ha;
int count = 0;
@@ -1774,7 +1800,7 @@ int LiveObjectList::GetRetainers(Handle<HeapObject> target,
// Iterate roots.
LolVisitor lol_visitor(*target, target);
- Heap::IterateStrongRoots(&lol_visitor, VISIT_ALL);
+ isolate->heap()->IterateStrongRoots(&lol_visitor, VISIT_ALL);
if (!AddRootRetainerIfFound(lol_visitor,
filter,
summary,
@@ -1794,7 +1820,7 @@ int LiveObjectList::GetRetainers(Handle<HeapObject> target,
}
lol_visitor.reset();
- Heap::IterateWeakRoots(&lol_visitor, VISIT_ALL);
+ isolate->heap()->IterateWeakRoots(&lol_visitor, VISIT_ALL);
if (!AddRootRetainerIfFound(lol_visitor,
filter,
summary,
@@ -1903,11 +1929,15 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id,
int start,
int dump_limit,
Handle<JSObject> filter_obj) {
- HandleScope scope;
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Heap* heap = isolate->heap();
+
+ HandleScope scope(isolate);
// Get the target object.
HeapObject* heap_obj = HeapObject::cast(GetObj(obj_id));
- if (heap_obj == Heap::undefined_value()) {
+ if (heap_obj == heap->undefined_value()) {
return heap_obj;
}
@@ -1915,7 +1945,7 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id,
// Get the constructor function for context extension and arguments array.
JSObject* arguments_boilerplate =
- Top::context()->global_context()->arguments_boilerplate();
+ isolate->context()->global_context()->arguments_boilerplate();
JSFunction* arguments_function =
JSFunction::cast(arguments_boilerplate->map()->constructor());
@@ -1937,7 +1967,7 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id,
// Set body.id.
Handle<JSObject> body = Handle<JSObject>(JSObject::cast(body_obj));
- Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
+ Handle<String> id_sym = factory->LookupAsciiSymbol("id");
maybe_result = body->SetProperty(*id_sym,
Smi::FromInt(obj_id),
NONE,
@@ -1952,13 +1982,17 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id,
Object* LiveObjectList::PrintObj(int obj_id) {
Object* obj = GetObj(obj_id);
if (!obj) {
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
EmbeddedVector<char, 128> temp_filename;
static int temp_count = 0;
const char* path_prefix = ".";
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Heap* heap = isolate->heap();
+
if (FLAG_lol_workdir) {
path_prefix = FLAG_lol_workdir;
}
@@ -1987,13 +2021,13 @@ Object* LiveObjectList::PrintObj(int obj_id) {
if (resource->exists() && !resource->is_empty()) {
ASSERT(resource->IsAscii());
Handle<String> dump_string =
- Factory::NewExternalStringFromAscii(resource);
- ExternalStringTable::AddString(*dump_string);
+ factory->NewExternalStringFromAscii(resource);
+ heap->external_string_table()->AddString(*dump_string);
return *dump_string;
} else {
delete resource;
}
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
@@ -2081,6 +2115,10 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
FILE* f = OS::FOpen(temp_filename.start(), "w+");
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Heap* heap = isolate->heap();
+
// Save the previous verbosity.
bool prev_verbosity = FLAG_use_verbose_printer;
FLAG_use_verbose_printer = false;
@@ -2096,15 +2134,14 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
// Check for ObjectGroups that references this object.
// TODO(mlam): refactor this to be more modular.
{
- List<ObjectGroup*>* groups = GlobalHandles::ObjectGroups();
+ List<ObjectGroup*>* groups = isolate->global_handles()->object_groups();
for (int i = 0; i < groups->length(); i++) {
ObjectGroup* group = groups->at(i);
if (group == NULL) continue;
bool found_group = false;
- List<Object**>& objects = group->objects_;
- for (int j = 0; j < objects.length(); j++) {
- Object* object = *objects[j];
+ for (size_t j = 0; j < group->length_; j++) {
+ Object* object = *(group->objects_[j]);
HeapObject* hobj = HeapObject::cast(object);
if (obj2 == hobj) {
found_group = true;
@@ -2117,8 +2154,8 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
"obj %p is a member of object group %p {\n",
reinterpret_cast<void*>(obj2),
reinterpret_cast<void*>(group));
- for (int j = 0; j < objects.length(); j++) {
- Object* object = *objects[j];
+ for (size_t j = 0; j < group->length_; j++) {
+ Object* object = *(group->objects_[j]);
if (!object->IsHeapObject()) continue;
HeapObject* hobj = HeapObject::cast(object);
@@ -2143,12 +2180,12 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
}
PrintF(f, "path from roots to obj %p\n", reinterpret_cast<void*>(obj2));
- Heap::IterateRoots(&tracer, VISIT_ONLY_STRONG);
+ heap->IterateRoots(&tracer, VISIT_ONLY_STRONG);
found = tracer.found();
if (!found) {
PrintF(f, " No paths found. Checking symbol tables ...\n");
- SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
+ SymbolTable* symbol_table = HEAP->raw_unchecked_symbol_table();
tracer.VisitPointers(reinterpret_cast<Object**>(&symbol_table),
reinterpret_cast<Object**>(&symbol_table)+1);
found = tracer.found();
@@ -2161,7 +2198,7 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
if (!found) {
PrintF(f, " No paths found. Checking weak roots ...\n");
// Check weak refs next.
- GlobalHandles::IterateWeakRoots(&tracer);
+ isolate->global_handles()->IterateWeakRoots(&tracer);
found = tracer.found();
}
@@ -2191,13 +2228,13 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
if (resource->exists() && !resource->is_empty()) {
ASSERT(resource->IsAscii());
Handle<String> path_string =
- Factory::NewExternalStringFromAscii(resource);
- ExternalStringTable::AddString(*path_string);
+ factory->NewExternalStringFromAscii(resource);
+ heap->external_string_table()->AddString(*path_string);
return *path_string;
} else {
delete resource;
}
- return Heap::undefined_value();
+ return heap->undefined_value();
}
@@ -2210,13 +2247,13 @@ Object* LiveObjectList::GetPath(int obj_id1,
HeapObject* obj1 = NULL;
if (obj_id1 != 0) {
obj1 = HeapObject::cast(GetObj(obj_id1));
- if (obj1 == Heap::undefined_value()) {
+ if (obj1 == HEAP->undefined_value()) {
return obj1;
}
}
HeapObject* obj2 = HeapObject::cast(GetObj(obj_id2));
- if (obj2 == Heap::undefined_value()) {
+ if (obj2 == HEAP->undefined_value()) {
return obj2;
}
@@ -2570,12 +2607,13 @@ void LiveObjectList::Verify(bool match_heap_exactly) {
void LiveObjectList::VerifyNotInFromSpace() {
OS::Print("VerifyNotInFromSpace() ...\n");
LolIterator it(NULL, last());
+ Heap* heap = ISOLATE->heap();
int i = 0;
for (it.Init(); !it.Done(); it.Next()) {
HeapObject* heap_obj = it.Obj();
- if (Heap::InFromSpace(heap_obj)) {
+ if (heap->InFromSpace(heap_obj)) {
OS::Print(" ERROR: VerifyNotInFromSpace: [%d] obj %p in From space %p\n",
- i++, heap_obj, Heap::new_space()->FromSpaceLow());
+ i++, heap_obj, heap->new_space()->FromSpaceLow());
}
}
}
diff --git a/deps/v8/src/liveobjectlist.h b/deps/v8/src/liveobjectlist.h
index 23e418d6d..542482d9c 100644
--- a/deps/v8/src/liveobjectlist.h
+++ b/deps/v8/src/liveobjectlist.h
@@ -237,10 +237,10 @@ class UpdateLiveObjectListVisitor: public ObjectVisitor {
// to live new space objects, and not actually keep them alive.
void UpdatePointer(Object** p) {
Object* object = *p;
- if (!Heap::InNewSpace(object)) return;
+ if (!HEAP->InNewSpace(object)) return;
HeapObject* heap_obj = HeapObject::cast(object);
- ASSERT(Heap::InFromSpace(heap_obj));
+ ASSERT(HEAP->InFromSpace(heap_obj));
// We use the first word (where the map pointer usually is) of a heap
// object to record the forwarding pointer. A forwarding pointer can
diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js
index 6603185a3..58c9a5302 100644
--- a/deps/v8/src/messages.js
+++ b/deps/v8/src/messages.js
@@ -247,6 +247,7 @@ function FormatMessage(message) {
strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"],
strict_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
strict_caller: ["Illegal access to a strict mode caller function."],
+ unprotected_let: ["Illegal let declaration in unprotected statement context."],
};
}
var message_type = %MessageGetType(message);
diff --git a/deps/v8/src/mips/frames-mips.h b/deps/v8/src/mips/frames-mips.h
index 2e720fb17..8c605a39d 100644
--- a/deps/v8/src/mips/frames-mips.h
+++ b/deps/v8/src/mips/frames-mips.h
@@ -121,10 +121,11 @@ static const int kSafepointRegisterStackIndexMap[kNumRegs] = {
class StackHandlerConstants : public AllStatic {
public:
- static const int kNextOffset = 0 * kPointerSize;
- static const int kStateOffset = 1 * kPointerSize;
- static const int kFPOffset = 2 * kPointerSize;
- static const int kPCOffset = 3 * kPointerSize;
+ static const int kNextOffset = 0 * kPointerSize;
+ static const int kStateOffset = 1 * kPointerSize;
+ static const int kContextOffset = 2 * kPointerSize;
+ static const int kFPOffset = 3 * kPointerSize;
+ static const int kPCOffset = 4 * kPointerSize;
static const int kSize = kPCOffset + kPointerSize;
};
diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc
index 4943a03a1..d8909c9dd 100644
--- a/deps/v8/src/mips/full-codegen-mips.cc
+++ b/deps/v8/src/mips/full-codegen-mips.cc
@@ -4052,6 +4052,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
__ Branch(if_true, eq, v0, Operand(at));
__ LoadRoot(at, Heap::kFalseValueRootIndex);
Split(eq, v0, Operand(at), if_true, if_false, fall_through);
+ } else if (FLAG_harmony_typeof &&
+ check->Equals(isolate()->heap()->null_symbol())) {
+ __ LoadRoot(at, Heap::kNullValueRootIndex);
+ Split(eq, v0, Operand(at), if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at));
@@ -4069,8 +4073,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
} else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(v0, if_false);
- __ LoadRoot(at, Heap::kNullValueRootIndex);
- __ Branch(if_true, eq, v0, Operand(at));
+ if (!FLAG_harmony_typeof) {
+ __ LoadRoot(at, Heap::kNullValueRootIndex);
+ __ Branch(if_true, eq, v0, Operand(at));
+ }
// Check for JS objects => true.
__ GetObjectType(v0, v0, a1);
__ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc
index 5e8d676ac..76b713f51 100644
--- a/deps/v8/src/mips/macro-assembler-mips.cc
+++ b/deps/v8/src/mips/macro-assembler-mips.cc
@@ -2244,7 +2244,13 @@ void MacroAssembler::DebugBreak() {
void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) {
// Adjust this code if not the case.
- ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
+
// The return address is passed in register ra.
if (try_location == IN_JAVASCRIPT) {
if (type == TRY_CATCH_HANDLER) {
@@ -2252,19 +2258,16 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
} else {
li(t0, Operand(StackHandler::TRY_FINALLY));
}
- ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize
- && StackHandlerConstants::kFPOffset == 2 * kPointerSize
- && StackHandlerConstants::kPCOffset == 3 * kPointerSize
- && StackHandlerConstants::kNextOffset == 0 * kPointerSize);
// Save the current handler as the next handler.
li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
lw(t1, MemOperand(t2));
addiu(sp, sp, -StackHandlerConstants::kSize);
- sw(ra, MemOperand(sp, 12));
- sw(fp, MemOperand(sp, 8));
- sw(t0, MemOperand(sp, 4));
- sw(t1, MemOperand(sp, 0));
+ sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset));
+ sw(fp, MemOperand(sp, StackHandlerConstants::kFPOffset));
+ sw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
+ sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset));
+ sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset));
// Link this handler as the new current one.
sw(sp, MemOperand(t2));
@@ -2272,11 +2275,6 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
} else {
// Must preserve a0-a3, and s0 (argv).
ASSERT(try_location == IN_JS_ENTRY);
- ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize
- && StackHandlerConstants::kFPOffset == 2 * kPointerSize
- && StackHandlerConstants::kPCOffset == 3 * kPointerSize
- && StackHandlerConstants::kNextOffset == 0 * kPointerSize);
-
// The frame pointer does not point to a JS frame so we save NULL
// for fp. We expect the code throwing an exception to check fp
// before dereferencing it to restore the context.
@@ -2286,11 +2284,14 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
lw(t1, MemOperand(t2));
+ ASSERT(Smi::FromInt(0) == 0); // Used for no context.
+
addiu(sp, sp, -StackHandlerConstants::kSize);
- sw(ra, MemOperand(sp, 12));
- sw(zero_reg, MemOperand(sp, 8));
- sw(t0, MemOperand(sp, 4));
- sw(t1, MemOperand(sp, 0));
+ sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset));
+ sw(zero_reg, MemOperand(sp, StackHandlerConstants::kFPOffset));
+ sw(zero_reg, MemOperand(sp, StackHandlerConstants::kContextOffset));
+ sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset));
+ sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset));
// Link this handler as the new current one.
sw(sp, MemOperand(t2));
@@ -2299,7 +2300,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() {
- ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a1);
Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
@@ -2312,28 +2313,31 @@ void MacroAssembler::Throw(Register value) {
Move(v0, value);
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// Drop the sp to the top of the handler.
li(a3, Operand(ExternalReference(Isolate::k_handler_address,
- isolate())));
+ isolate())));
lw(sp, MemOperand(a3));
- // Restore the next handler and frame pointer, discard handler state.
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+ // Restore the next handler.
pop(a2);
sw(a2, MemOperand(a3));
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
- MultiPop(a3.bit() | fp.bit());
- // Before returning we restore the context from the frame pointer if
- // not NULL. The frame pointer is NULL in the exception handler of a
- // JS entry frame.
- // Set cp to NULL if fp is NULL.
+ // Restore context and frame pointer, discard state (a3).
+ MultiPop(a3.bit() | cp.bit() | fp.bit());
+
+ // If the handler is a JS frame, restore the context to the frame.
+ // (a3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any
+ // of them.
Label done;
- Branch(USE_DELAY_SLOT, &done, eq, fp, Operand(zero_reg));
- mov(cp, zero_reg); // In branch delay slot.
- lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ Branch(&done, eq, fp, Operand(zero_reg));
+ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
bind(&done);
#ifdef DEBUG
@@ -2355,7 +2359,6 @@ void MacroAssembler::Throw(Register value) {
}
#endif
- STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(t9); // 2 instructions: lw, add sp.
Jump(t9); // 2 instructions: jr, nop (in delay slot).
@@ -2370,7 +2373,12 @@ void MacroAssembler::Throw(Register value) {
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) {
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// v0 is expected to hold the exception.
Move(v0, value);
@@ -2393,7 +2401,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a2);
sw(a2, MemOperand(a3));
@@ -2415,20 +2422,12 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
// Stack layout at this point. See also StackHandlerConstants.
// sp -> state (ENTRY)
+ // cp
// fp
// ra
- // Discard handler state (a2 is not used) and restore frame pointer.
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
- MultiPop(a2.bit() | fp.bit()); // a2: discarded state.
- // Before returning we restore the context from the frame pointer if
- // not NULL. The frame pointer is NULL in the exception handler of a
- // JS entry frame.
- Label cp_null;
- Branch(USE_DELAY_SLOT, &cp_null, eq, fp, Operand(zero_reg));
- mov(cp, zero_reg); // In the branch delay slot.
- lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- bind(&cp_null);
+ // Restore context and frame pointer, discard state (r2).
+ MultiPop(a2.bit() | cp.bit() | fp.bit());
#ifdef DEBUG
// When emitting debug_code, set ra as return address for the jump.
@@ -2448,7 +2447,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
addiu(ra, ra, kOffsetRaBytes);
}
#endif
- STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(t9); // 2 instructions: lw, add sp.
Jump(t9); // 2 instructions: jr, nop (in delay slot).
diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc
index 84ff991ce..ec63551b1 100644
--- a/deps/v8/src/mips/stub-cache-mips.cc
+++ b/deps/v8/src/mips/stub-cache-mips.cc
@@ -3494,7 +3494,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
__ sra(t2, key, kSmiTagSize);
// Unsigned comparison catches both negative and too-large values.
- __ Branch(&miss_force_generic, Uless, t1, Operand(t2));
+ __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
__ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
// a3: base pointer of external storage
@@ -3822,16 +3822,16 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
- // Check that the key is a smi.
+ // Check that the key is a smi.
__ JumpIfNotSmi(key, &miss_force_generic);
+ __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
+
// Check that the index is in range.
__ SmiUntag(t0, key);
__ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
- __ Branch(&miss_force_generic, Ugreater_equal, t0, Operand(t1));
+ __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.
diff --git a/deps/v8/src/mirror-debugger.js b/deps/v8/src/mirror-debugger.js
index bad08002d..e3f3c48bb 100644
--- a/deps/v8/src/mirror-debugger.js
+++ b/deps/v8/src/mirror-debugger.js
@@ -195,7 +195,8 @@ ScopeType = { Global: 0,
Local: 1,
With: 2,
Closure: 3,
- Catch: 4 };
+ Catch: 4,
+ Block: 5 };
// Mirror hierarchy:
diff --git a/deps/v8/src/mksnapshot.cc b/deps/v8/src/mksnapshot.cc
index c5ce12f0e..4f5fe96a9 100644
--- a/deps/v8/src/mksnapshot.cc
+++ b/deps/v8/src/mksnapshot.cc
@@ -40,8 +40,6 @@
#include "serialize.h"
#include "list.h"
-// use explicit namespace to avoid clashing with types in namespace v8
-namespace i = v8::internal;
using namespace v8;
static const unsigned int kMaxCounters = 256;
diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h
index 70ed47be1..c5fda89e4 100644
--- a/deps/v8/src/objects-inl.h
+++ b/deps/v8/src/objects-inl.h
@@ -552,7 +552,8 @@ bool Object::IsContext() {
return (map == heap->function_context_map() ||
map == heap->catch_context_map() ||
map == heap->with_context_map() ||
- map == heap->global_context_map());
+ map == heap->global_context_map() ||
+ map == heap->block_context_map());
}
return false;
}
@@ -565,6 +566,13 @@ bool Object::IsGlobalContext() {
}
+bool Object::IsSerializedScopeInfo() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map() ==
+ HeapObject::cast(this)->GetHeap()->serialized_scope_info_map();
+}
+
+
bool Object::IsJSFunction() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE;
@@ -1335,14 +1343,14 @@ int HeapNumber::get_sign() {
ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
-HeapObject* JSObject::elements() {
+FixedArrayBase* JSObject::elements() {
Object* array = READ_FIELD(this, kElementsOffset);
ASSERT(array->HasValidElements());
- return reinterpret_cast<HeapObject*>(array);
+ return static_cast<FixedArrayBase*>(array);
}
-void JSObject::set_elements(HeapObject* value, WriteBarrierMode mode) {
+void JSObject::set_elements(FixedArrayBase* value, WriteBarrierMode mode) {
ASSERT(map()->has_fast_elements() ==
(value->map() == GetHeap()->fixed_array_map() ||
value->map() == GetHeap()->fixed_cow_array_map()));
@@ -2114,12 +2122,6 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
-SMI_ACCESSORS(ByteArray, length, kLengthOffset)
-
-// TODO(1493): Investigate if it's possible to s/INT/SMI/ here (and
-// subsequently unify H{Fixed,External}ArrayLength).
-INT_ACCESSORS(ExternalArray, length, kLengthOffset)
-
SMI_ACCESSORS(String, length, kLengthOffset)
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index e35274d0a..337dd65db 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -2318,7 +2318,8 @@ MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
if (has_exception) return Failure::Exception();
Object* bool_result = result->ToBoolean();
- if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
+ if (mode == STRICT_DELETION &&
+ bool_result == isolate->heap()->false_value()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
"handler_failed", HandleVector(args, ARRAY_SIZE(args)));
@@ -3167,9 +3168,10 @@ MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
ASSERT(result->IsBoolean());
return *v8::Utils::OpenHandle(*result);
}
- MaybeObject* raw_result = GetElementsAccessor()->Delete(*this_handle,
- index,
- NORMAL_DELETION);
+ MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
+ *this_handle,
+ index,
+ NORMAL_DELETION);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return raw_result;
}
@@ -4637,7 +4639,20 @@ MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
- return array->GetElementsAccessor()->AddJSArrayKeysToFixedArray(array, this);
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_result =
+ accessor->AddElementsToFixedArray(array->elements(), this);
+ FixedArray* result;
+ if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
+#ifdef DEBUG
+ if (FLAG_enable_slow_asserts) {
+ for (int i = 0; i < result->length(); i++) {
+ Object* current = result->get(i);
+ ASSERT(current->IsNumber() || current->IsString());
+ }
+ }
+#endif
+ return result;
}
@@ -6961,12 +6976,16 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
if (0 == deopt_count) return;
- PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
+ PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc",
+ FLAG_print_code_verbose ? "commands" : "");
for (int i = 0; i < deopt_count; i++) {
PrintF(out, "%6d %6d %6d",
i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
- if (!FLAG_print_code_verbose) continue;
+ if (!FLAG_print_code_verbose) {
+ PrintF(out, "\n");
+ continue;
+ }
// Print details of the frame translation.
int translation_index = TranslationIndex(i)->value();
TranslationIterator iterator(TranslationByteArray(), translation_index);
@@ -8403,14 +8422,14 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
return isolate->Throw(*error);
}
}
- Object* new_dictionary;
+ FixedArrayBase* new_dictionary;
MaybeObject* maybe = dictionary->AtNumberPut(index, value);
- if (!maybe->ToObject(&new_dictionary)) return maybe;
+ if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
if (dictionary != NumberDictionary::cast(new_dictionary)) {
if (is_arguments) {
elements->set(1, new_dictionary);
} else {
- set_elements(HeapObject::cast(new_dictionary));
+ set_elements(new_dictionary);
}
dictionary = NumberDictionary::cast(new_dictionary);
}
diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h
index ff13aedcc..93f7a1d11 100644
--- a/deps/v8/src/objects.h
+++ b/deps/v8/src/objects.h
@@ -62,17 +62,8 @@
// - JSMessageObject
// - JSProxy
// - JSFunctionProxy
-// - ByteArray
-// - ExternalArray
-// - ExternalPixelArray
-// - ExternalByteArray
-// - ExternalUnsignedByteArray
-// - ExternalShortArray
-// - ExternalUnsignedShortArray
-// - ExternalIntArray
-// - ExternalUnsignedIntArray
-// - ExternalFloatArray
// - FixedArrayBase
+// - ByteArray
// - FixedArray
// - DescriptorArray
// - HashTable
@@ -85,6 +76,15 @@
// - JSFunctionResultCache
// - SerializedScopeInfo
// - FixedDoubleArray
+// - ExternalArray
+// - ExternalPixelArray
+// - ExternalByteArray
+// - ExternalUnsignedByteArray
+// - ExternalShortArray
+// - ExternalUnsignedShortArray
+// - ExternalIntArray
+// - ExternalUnsignedIntArray
+// - ExternalFloatArray
// - String
// - SeqString
// - SeqAsciiString
@@ -322,6 +322,7 @@ static const int kVariableSizeSentinel = 0;
V(POLYMORPHIC_CODE_CACHE_TYPE) \
\
V(FIXED_ARRAY_TYPE) \
+ V(FIXED_DOUBLE_ARRAY_TYPE) \
V(SHARED_FUNCTION_INFO_TYPE) \
\
V(JS_MESSAGE_OBJECT_TYPE) \
@@ -635,10 +636,11 @@ enum CompareResult {
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
+class DictionaryElementsAccessor;
class ElementsAccessor;
-class StringStream;
+class FixedArrayBase;
class ObjectVisitor;
-class DictionaryElementsAccessor;
+class StringStream;
struct ValueInfo : public Malloced {
ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { }
@@ -743,6 +745,7 @@ class MaybeObject BASE_EMBEDDED {
V(FixedDoubleArray) \
V(Context) \
V(GlobalContext) \
+ V(SerializedScopeInfo) \
V(JSFunction) \
V(Code) \
V(Oddball) \
@@ -1492,7 +1495,7 @@ class JSObject: public JSReceiver {
// In the slow mode the elements is either a NumberDictionary, an
// ExternalArray, or a FixedArray parameter map for a (non-strict)
// arguments object.
- DECL_ACCESSORS(elements, HeapObject)
+ DECL_ACCESSORS(elements, FixedArrayBase)
inline void initialize_elements();
MUST_USE_RESULT inline MaybeObject* ResetElements();
inline ElementsKind GetElementsKind();
@@ -2084,6 +2087,7 @@ class FixedArrayBase: public HeapObject {
static const int kHeaderSize = kLengthOffset + kPointerSize;
};
+
class FixedDoubleArray;
// FixedArray describes fixed-sized arrays with element type Object*.
@@ -3053,12 +3057,8 @@ class NormalizedMapCache: public FixedArray {
// ByteArray represents fixed sized byte arrays. Used by the outside world,
// such as PCRE, and also by the memory allocator and garbage collector to
// fill in free blocks in the heap.
-class ByteArray: public HeapObject {
+class ByteArray: public FixedArrayBase {
public:
- // [length]: length of the array.
- inline int length();
- inline void set_length(int value);
-
// Setter and getter.
inline byte get(int index);
inline void set(int index, byte value);
@@ -3103,10 +3103,6 @@ class ByteArray: public HeapObject {
#endif
// Layout description.
- // Length is smi tagged when it is stored.
- static const int kLengthOffset = HeapObject::kHeaderSize;
- static const int kHeaderSize = kLengthOffset + kPointerSize;
-
static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
// Maximal memory consumption for a single ByteArray.
@@ -3130,11 +3126,8 @@ class ByteArray: public HeapObject {
// Out-of-range values passed to the setter are converted via a C
// cast, not clamping. Out-of-range indices cause exceptions to be
// raised rather than being silently ignored.
-class ExternalArray: public HeapObject {
+class ExternalArray: public FixedArrayBase {
public:
- // [length]: length of the array.
- inline int length();
- inline void set_length(int value);
inline bool is_the_hole(int index) { return false; }
@@ -3149,9 +3142,8 @@ class ExternalArray: public HeapObject {
static const int kMaxLength = 0x3fffffff;
// ExternalArray headers are not quadword aligned.
- static const int kLengthOffset = HeapObject::kHeaderSize;
static const int kExternalPointerOffset =
- POINTER_SIZE_ALIGN(kLengthOffset + kIntSize);
+ POINTER_SIZE_ALIGN(FixedArrayBase::kLengthOffset + kPointerSize);
static const int kHeaderSize = kExternalPointerOffset + kPointerSize;
static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
@@ -4444,6 +4436,7 @@ class Script: public Struct {
#define FUNCTIONS_WITH_ID_LIST(V) \
V(Array.prototype, push, ArrayPush) \
V(Array.prototype, pop, ArrayPop) \
+ V(Function.prototype, apply, FunctionApply) \
V(String.prototype, charCodeAt, StringCharCodeAt) \
V(String.prototype, charAt, StringCharAt) \
V(String, fromCharCode, StringFromCharCode) \
diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc
index f32e9177b..844dd7060 100644
--- a/deps/v8/src/parser.cc
+++ b/deps/v8/src/parser.cc
@@ -584,7 +584,8 @@ Parser::Parser(Handle<Script> script,
pre_data_(pre_data),
fni_(NULL),
stack_overflow_(false),
- parenthesized_function_(false) {
+ parenthesized_function_(false),
+ harmony_block_scoping_(false) {
AstNode::ResetIds();
}
@@ -809,6 +810,10 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
isolate()->Throw(*result, &location);
}
+void Parser::SetHarmonyBlockScoping(bool block_scoping) {
+ scanner().SetHarmonyBlockScoping(block_scoping);
+ harmony_block_scoping_ = block_scoping;
+}
// Base class containing common code for the different finder classes used by
// the parser.
@@ -1089,6 +1094,25 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder {
};
+Statement* Parser::ParseSourceElement(ZoneStringList* labels,
+ bool* ok) {
+ if (peek() == Token::FUNCTION) {
+ // FunctionDeclaration is only allowed in the context of SourceElements
+ // (Ecma 262 5th Edition, clause 14):
+ // SourceElement:
+ // Statement
+ // FunctionDeclaration
+ // Common language extension is to allow function declaration in place
+ // of any statement. This language extension is disabled in strict mode.
+ return ParseFunctionDeclaration(ok);
+ } else if (peek() == Token::LET) {
+ return ParseVariableStatement(kSourceElement, ok);
+ } else {
+ return ParseStatement(labels, ok);
+ }
+}
+
+
void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
int end_token,
bool* ok) {
@@ -1112,21 +1136,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
}
Scanner::Location token_loc = scanner().peek_location();
-
- Statement* stat;
- if (peek() == Token::FUNCTION) {
- // FunctionDeclaration is only allowed in the context of SourceElements
- // (Ecma 262 5th Edition, clause 14):
- // SourceElement:
- // Statement
- // FunctionDeclaration
- // Common language extension is to allow function declaration in place
- // of any statement. This language extension is disabled in strict mode.
- stat = ParseFunctionDeclaration(CHECK_OK);
- } else {
- stat = ParseStatement(NULL, CHECK_OK);
- }
-
+ Statement* stat = ParseSourceElement(NULL, CHECK_OK);
if (stat == NULL || stat->IsEmpty()) {
directive_prologue = false; // End of directive prologue.
continue;
@@ -1214,7 +1224,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
case Token::CONST: // fall through
case Token::VAR:
- stmt = ParseVariableStatement(ok);
+ stmt = ParseVariableStatement(kStatement, ok);
break;
case Token::SEMICOLON:
@@ -1309,9 +1319,9 @@ VariableProxy* Parser::Declare(Handle<String> name,
bool resolve,
bool* ok) {
Variable* var = NULL;
- // If we are inside a function, a declaration of a variable
- // is a truly local variable, and the scope of the variable
- // is always the function scope.
+ // If we are inside a function, a declaration of a var/const variable is a
+ // truly local variable, and the scope of the variable is always the function
+ // scope.
// If a function scope exists, then we can statically declare this
// variable and also set its mode. In any case, a Declaration node
@@ -1321,24 +1331,28 @@ VariableProxy* Parser::Declare(Handle<String> name,
// to the calling function context.
// Similarly, strict mode eval scope does not leak variable declarations to
// the caller's scope so we declare all locals, too.
- Scope* declaration_scope = top_scope_->DeclarationScope();
+
+ Scope* declaration_scope = mode == Variable::LET ? top_scope_
+ : top_scope_->DeclarationScope();
if (declaration_scope->is_function_scope() ||
- declaration_scope->is_strict_mode_eval_scope()) {
+ declaration_scope->is_strict_mode_eval_scope() ||
+ declaration_scope->is_block_scope()) {
// Declare the variable in the function scope.
var = declaration_scope->LocalLookup(name);
if (var == NULL) {
// Declare the name.
var = declaration_scope->DeclareLocal(name, mode);
} else {
- // The name was declared before; check for conflicting
- // re-declarations. If the previous declaration was a const or the
- // current declaration is a const then we have a conflict. There is
- // similar code in runtime.cc in the Declare functions.
- if ((mode == Variable::CONST) || (var->mode() == Variable::CONST)) {
- // We only have vars and consts in declarations.
+ // The name was declared before; check for conflicting re-declarations.
+ // We have a conflict if either of the declarations is not a var. There
+ // is similar code in runtime.cc in the Declare functions.
+ if ((mode != Variable::VAR) || (var->mode() != Variable::VAR)) {
+ // We only have vars, consts and lets in declarations.
ASSERT(var->mode() == Variable::VAR ||
- var->mode() == Variable::CONST);
- const char* type = (var->mode() == Variable::VAR) ? "var" : "const";
+ var->mode() == Variable::CONST ||
+ var->mode() == Variable::LET);
+ const char* type = (var->mode() == Variable::VAR) ? "var" :
+ (var->mode() == Variable::CONST) ? "const" : "let";
Handle<String> type_string =
isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
Expression* expression =
@@ -1481,12 +1495,15 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) {
// Even if we're not at the top-level of the global or a function
// scope, we treat is as such and introduce the function with it's
// initial value upon entering the corresponding scope.
- Declare(name, Variable::VAR, fun, true, CHECK_OK);
+ Variable::Mode mode = harmony_block_scoping_ ? Variable::LET : Variable::VAR;
+ Declare(name, mode, fun, true, CHECK_OK);
return EmptyStatement();
}
Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
+ if (harmony_block_scoping_) return ParseScopedBlock(labels, ok);
+
// Block ::
// '{' Statement* '}'
@@ -1510,12 +1527,65 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
}
-Block* Parser::ParseVariableStatement(bool* ok) {
+Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
+ // Construct block expecting 16 statements.
+ Block* body = new(zone()) Block(isolate(), labels, 16, false);
+ Scope* saved_scope = top_scope_;
+ Scope* block_scope = NewScope(top_scope_,
+ Scope::BLOCK_SCOPE,
+ inside_with());
+ body->set_block_scope(block_scope);
+ block_scope->DeclareLocal(isolate()->factory()->block_scope_symbol(),
+ Variable::VAR);
+ if (top_scope_->is_strict_mode()) {
+ block_scope->EnableStrictMode();
+ }
+ top_scope_ = block_scope;
+
+ // Parse the statements and collect escaping labels.
+ TargetCollector collector;
+ Target target(&this->target_stack_, &collector);
+ Expect(Token::LBRACE, CHECK_OK);
+ {
+ Target target_body(&this->target_stack_, body);
+ InitializationBlockFinder block_finder(top_scope_, target_stack_);
+
+ while (peek() != Token::RBRACE) {
+ Statement* stat = ParseSourceElement(NULL, CHECK_OK);
+ if (stat && !stat->IsEmpty()) {
+ body->AddStatement(stat);
+ block_finder.Update(stat);
+ }
+ }
+ }
+ Expect(Token::RBRACE, CHECK_OK);
+
+ // Create exit block.
+ Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
+ exit->AddStatement(new(zone()) ExitContextStatement());
+
+ // Create a try-finally statement.
+ TryFinallyStatement* try_finally =
+ new(zone()) TryFinallyStatement(body, exit);
+ try_finally->set_escaping_targets(collector.targets());
+ top_scope_ = saved_scope;
+
+ // Create a result block.
+ Block* result = new(zone()) Block(isolate(), NULL, 1, false);
+ result->AddStatement(try_finally);
+ return result;
+}
+
+
+Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
+ bool* ok) {
// VariableStatement ::
// VariableDeclarations ';'
Handle<String> ignore;
- Block* result = ParseVariableDeclarations(true, &ignore, CHECK_OK);
+ Block* result = ParseVariableDeclarations(var_context,
+ &ignore,
+ CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
@@ -1532,7 +1602,7 @@ bool Parser::IsEvalOrArguments(Handle<String> string) {
// *var is untouched; in particular, it is the caller's responsibility
// to initialize it properly. This mechanism is used for the parsing
// of 'for-in' loops.
-Block* Parser::ParseVariableDeclarations(bool accept_IN,
+Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
Handle<String>* out,
bool* ok) {
// VariableDeclarations ::
@@ -1540,25 +1610,36 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
Variable::Mode mode = Variable::VAR;
bool is_const = false;
- Scope* declaration_scope = top_scope_->DeclarationScope();
if (peek() == Token::VAR) {
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
Consume(Token::CONST);
- if (declaration_scope->is_strict_mode()) {
+ if (top_scope_->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false;
return NULL;
}
mode = Variable::CONST;
is_const = true;
+ } else if (peek() == Token::LET) {
+ Consume(Token::LET);
+ if (var_context != kSourceElement &&
+ var_context != kForStatement) {
+ ASSERT(var_context == kStatement);
+ ReportMessage("unprotected_let", Vector<const char*>::empty());
+ *ok = false;
+ return NULL;
+ }
+ mode = Variable::LET;
} else {
UNREACHABLE(); // by current callers
}
- // The scope of a variable/const declared anywhere inside a function
+ Scope* declaration_scope = mode == Variable::LET
+ ? top_scope_ : top_scope_->DeclarationScope();
+ // The scope of a var/const declared variable anywhere inside a function
// is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
- // transform a source-level variable/const declaration into a (Function)
+ // transform a source-level var/const declaration into a (Function)
// Scope declaration, and rewrite the source-level initialization into an
// assignment statement. We use a block to collect multiple assignments.
//
@@ -1642,7 +1723,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
if (peek() == Token::ASSIGN) {
Expect(Token::ASSIGN, CHECK_OK);
position = scanner().location().beg_pos;
- value = ParseAssignmentExpression(accept_IN, CHECK_OK);
+ value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
// Don't infer if it is "a = function(){...}();"-like expression.
if (fni_ != NULL &&
value->AsCall() == NULL &&
@@ -1956,41 +2037,6 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
}
-Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
- // Parse the statement and collect escaping labels.
- TargetCollector collector;
- Statement* stat;
- { Target target(&this->target_stack_, &collector);
- with_nesting_level_++;
- top_scope_->DeclarationScope()->RecordWithStatement();
- stat = ParseStatement(labels, CHECK_OK);
- with_nesting_level_--;
- }
- // Create resulting block with two statements.
- // 1: Evaluate the with expression.
- // 2: The try-finally block evaluating the body.
- Block* result = new(zone()) Block(isolate(), NULL, 2, false);
-
- if (result != NULL) {
- result->AddStatement(new(zone()) EnterWithContextStatement(obj));
-
- // Create body block.
- Block* body = new(zone()) Block(isolate(), NULL, 1, false);
- body->AddStatement(stat);
-
- // Create exit block.
- Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
- exit->AddStatement(new(zone()) ExitContextStatement());
-
- // Return a try-finally statement.
- TryFinallyStatement* wrapper = new(zone()) TryFinallyStatement(body, exit);
- wrapper->set_escaping_targets(collector.targets());
- result->AddStatement(wrapper);
- }
- return result;
-}
-
-
Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
// WithStatement ::
// 'with' '(' Expression ')' Statement
@@ -2007,7 +2053,11 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- return WithHelper(expr, labels, CHECK_OK);
+ ++with_nesting_level_;
+ top_scope_->DeclarationScope()->RecordWithStatement();
+ Statement* stmt = ParseStatement(labels, CHECK_OK);
+ --with_nesting_level_;
+ return new(zone()) WithStatement(expr, stmt);
}
@@ -2142,39 +2192,22 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::RPAREN, CHECK_OK);
if (peek() == Token::LBRACE) {
- // Rewrite the catch body B to a single statement block
- // { try B finally { PopContext }}.
- Block* inner_body;
- // We need to collect escapes from the body for both the inner
- // try/finally used to pop the catch context and any possible outer
- // try/finally.
- TargetCollector inner_collector;
- { Target target(&this->target_stack_, &catch_collector);
- { Target target(&this->target_stack_, &inner_collector);
- catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
- if (top_scope_->is_strict_mode()) {
- catch_scope->EnableStrictMode();
- }
- catch_variable = catch_scope->DeclareLocal(name, Variable::VAR);
-
- Scope* saved_scope = top_scope_;
- top_scope_ = catch_scope;
- inner_body = ParseBlock(NULL, CHECK_OK);
- top_scope_ = saved_scope;
- }
+ // Rewrite the catch body { B } to a block:
+ // { { B } ExitContext; }.
+ Target target(&this->target_stack_, &catch_collector);
+ catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
+ if (top_scope_->is_strict_mode()) {
+ catch_scope->EnableStrictMode();
}
-
- // Create exit block.
- Block* inner_finally = new(zone()) Block(isolate(), NULL, 1, false);
- inner_finally->AddStatement(new(zone()) ExitContextStatement());
-
- // Create a try/finally statement.
- TryFinallyStatement* inner_try_finally =
- new(zone()) TryFinallyStatement(inner_body, inner_finally);
- inner_try_finally->set_escaping_targets(inner_collector.targets());
-
- catch_block = new(zone()) Block(isolate(), NULL, 1, false);
- catch_block->AddStatement(inner_try_finally);
+ catch_variable = catch_scope->DeclareLocal(name, Variable::VAR);
+ catch_block = new(zone()) Block(isolate(), NULL, 2, false);
+
+ Scope* saved_scope = top_scope_;
+ top_scope_ = catch_scope;
+ Block* catch_body = ParseBlock(NULL, CHECK_OK);
+ top_scope_ = saved_scope;
+ catch_block->AddStatement(catch_body);
+ catch_block->AddStatement(new(zone()) ExitContextStatement());
} else {
Expect(Token::LBRACE, CHECK_OK);
}
@@ -2290,7 +2323,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
if (peek() == Token::VAR || peek() == Token::CONST) {
Handle<String> name;
Block* variable_statement =
- ParseVariableDeclarations(false, &name, CHECK_OK);
+ ParseVariableDeclarations(kForStatement, &name, CHECK_OK);
if (peek() == Token::IN && !name.is_null()) {
VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
@@ -3649,8 +3682,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
}
int num_parameters = 0;
- // Function declarations are hoisted.
- Scope* scope = (type == FunctionLiteral::DECLARATION)
+ // Function declarations are function scoped in normal mode, so they are
+ // hoisted. In harmony block scoping mode they are block scoped, so they
+ // are not hoisted.
+ Scope* scope = (type == FunctionLiteral::DECLARATION &&
+ !harmony_block_scoping_)
? NewScope(top_scope_->DeclarationScope(), Scope::FUNCTION_SCOPE, false)
: NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8);
@@ -3952,7 +3988,7 @@ Literal* Parser::GetLiteralNumber(double value) {
}
-// Parses and identifier that is valid for the current scope, in particular it
+// Parses an identifier that is valid for the current scope, in particular it
// fails on strict mode future reserved keywords in a strict scope.
Handle<String> Parser::ParseIdentifier(bool* ok) {
if (top_scope_->is_strict_mode()) {
@@ -5033,9 +5069,11 @@ int ScriptDataImpl::ReadNumber(byte** source) {
// Create a Scanner for the preparser to use as input, and preparse the source.
static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
bool allow_lazy,
- ParserRecorder* recorder) {
+ ParserRecorder* recorder,
+ bool harmony_block_scoping) {
Isolate* isolate = Isolate::Current();
JavaScriptScanner scanner(isolate->unicode_cache());
+ scanner.SetHarmonyBlockScoping(harmony_block_scoping);
scanner.Initialize(source);
intptr_t stack_limit = isolate->stack_guard()->real_climit();
if (!preparser::PreParser::PreParseProgram(&scanner,
@@ -5056,7 +5094,8 @@ static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
// Preparse, but only collect data that is immediately useful,
// even if the preparser data is only used once.
ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
- v8::Extension* extension) {
+ v8::Extension* extension,
+ bool harmony_block_scoping) {
bool allow_lazy = FLAG_lazy && (extension == NULL);
if (!allow_lazy) {
// Partial preparsing is only about lazily compiled functions.
@@ -5064,16 +5103,17 @@ ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
return NULL;
}
PartialParserRecorder recorder;
- return DoPreParse(source, allow_lazy, &recorder);
+ return DoPreParse(source, allow_lazy, &recorder, harmony_block_scoping);
}
ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
- v8::Extension* extension) {
+ v8::Extension* extension,
+ bool harmony_block_scoping) {
Handle<Script> no_script;
bool allow_lazy = FLAG_lazy && (extension == NULL);
CompleteParserRecorder recorder;
- return DoPreParse(source, allow_lazy, &recorder);
+ return DoPreParse(source, allow_lazy, &recorder, harmony_block_scoping);
}
@@ -5103,15 +5143,22 @@ bool ParserApi::Parse(CompilationInfo* info) {
ASSERT(info->function() == NULL);
FunctionLiteral* result = NULL;
Handle<Script> script = info->script();
+ bool harmony_block_scoping = !info->is_native() &&
+ FLAG_harmony_block_scoping;
if (info->is_lazy()) {
Parser parser(script, true, NULL, NULL);
+ parser.SetHarmonyBlockScoping(harmony_block_scoping);
result = parser.ParseLazy(info);
} else {
// Whether we allow %identifier(..) syntax.
bool allow_natives_syntax =
info->allows_natives_syntax() || FLAG_allow_natives_syntax;
ScriptDataImpl* pre_data = info->pre_parse_data();
- Parser parser(script, allow_natives_syntax, info->extension(), pre_data);
+ Parser parser(script,
+ allow_natives_syntax,
+ info->extension(),
+ pre_data);
+ parser.SetHarmonyBlockScoping(harmony_block_scoping);
if (pre_data != NULL && pre_data->has_error()) {
Scanner::Location loc = pre_data->MessageLocation();
const char* message = pre_data->BuildMessage();
@@ -5130,7 +5177,6 @@ bool ParserApi::Parse(CompilationInfo* info) {
info->StrictMode());
}
}
-
info->SetFunction(result);
return (result != NULL);
}
diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h
index 535b63945..686dac85a 100644
--- a/deps/v8/src/parser.h
+++ b/deps/v8/src/parser.h
@@ -164,12 +164,14 @@ class ParserApi {
// Generic preparser generating full preparse data.
static ScriptDataImpl* PreParse(UC16CharacterStream* source,
- v8::Extension* extension);
+ v8::Extension* extension,
+ bool harmony_block_scoping);
// Preparser that only does preprocessing that makes sense if only used
// immediately after.
static ScriptDataImpl* PartialPreParse(UC16CharacterStream* source,
- v8::Extension* extension);
+ v8::Extension* extension,
+ bool harmony_block_scoping);
};
// ----------------------------------------------------------------------------
@@ -435,6 +437,7 @@ class Parser {
void ReportMessageAt(Scanner::Location loc,
const char* message,
Vector<Handle<String> > args);
+ void SetHarmonyBlockScoping(bool block_scoping);
private:
// Limit on number of function parameters is chosen arbitrarily.
@@ -451,6 +454,12 @@ class Parser {
PARSE_EAGERLY
};
+ enum VariableDeclarationContext {
+ kSourceElement,
+ kStatement,
+ kForStatement
+ };
+
Isolate* isolate() { return isolate_; }
Zone* zone() { return isolate_->zone(); }
@@ -479,12 +488,15 @@ class Parser {
// for failure at the call sites.
void* ParseSourceElements(ZoneList<Statement*>* processor,
int end_token, bool* ok);
+ Statement* ParseSourceElement(ZoneStringList* labels, bool* ok);
Statement* ParseStatement(ZoneStringList* labels, bool* ok);
Statement* ParseFunctionDeclaration(bool* ok);
Statement* ParseNativeDeclaration(bool* ok);
Block* ParseBlock(ZoneStringList* labels, bool* ok);
- Block* ParseVariableStatement(bool* ok);
- Block* ParseVariableDeclarations(bool accept_IN,
+ Block* ParseScopedBlock(ZoneStringList* labels, bool* ok);
+ Block* ParseVariableStatement(VariableDeclarationContext var_context,
+ bool* ok);
+ Block* ParseVariableDeclarations(VariableDeclarationContext var_context,
Handle<String>* out,
bool* ok);
Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels,
@@ -493,7 +505,6 @@ class Parser {
Statement* ParseContinueStatement(bool* ok);
Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok);
Statement* ParseReturnStatement(bool* ok);
- Block* WithHelper(Expression* obj, ZoneStringList* labels, bool* ok);
Statement* ParseWithStatement(ZoneStringList* labels, bool* ok);
CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok);
@@ -715,6 +726,7 @@ class Parser {
// Heuristically that means that the function will be called immediately,
// so never lazily compile it.
bool parenthesized_function_;
+ bool harmony_block_scoping_;
friend class LexicalScope;
};
diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc
index 37330be82..362bf47cc 100644
--- a/deps/v8/src/platform-linux.cc
+++ b/deps/v8/src/platform-linux.cc
@@ -676,9 +676,11 @@ static void* ThreadEntry(void* arg) {
// This is also initialized by the first argument to pthread_create() but we
// don't know which thread will run first (the original thread or the new
// one) so we initialize it here too.
+#ifdef PR_SET_NAME
prctl(PR_SET_NAME,
reinterpret_cast<unsigned long>(thread->name()), // NOLINT
0, 0, 0);
+#endif
thread->data()->thread_ = pthread_self();
ASSERT(thread->data()->thread_ != kNoThread);
thread->Run();
diff --git a/deps/v8/src/preparser-api.cc b/deps/v8/src/preparser-api.cc
index e0ab5001f..80656d5d1 100644
--- a/deps/v8/src/preparser-api.cc
+++ b/deps/v8/src/preparser-api.cc
@@ -28,6 +28,7 @@
#include "../include/v8-preparser.h"
#include "globals.h"
+#include "flags.h"
#include "checks.h"
#include "allocation.h"
#include "utils.h"
diff --git a/deps/v8/src/preparser.cc b/deps/v8/src/preparser.cc
index c741b4655..1a3dd737c 100644
--- a/deps/v8/src/preparser.cc
+++ b/deps/v8/src/preparser.cc
@@ -56,8 +56,6 @@ namespace preparser {
// That means that contextual checks (like a label being declared where
// it is used) are generally omitted.
-namespace i = ::v8::internal;
-
void PreParser::ReportUnexpectedToken(i::Token::Value token) {
// We don't report stack overflows here, to avoid increasing the
// stack depth even further. Instead we report it after parsing is
@@ -114,6 +112,16 @@ void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
#undef DUMMY
+PreParser::Statement PreParser::ParseSourceElement(bool* ok) {
+ switch (peek()) {
+ case i::Token::LET:
+ return ParseVariableStatement(kSourceElement, ok);
+ default:
+ return ParseStatement(ok);
+ }
+}
+
+
PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
bool* ok) {
// SourceElements ::
@@ -121,7 +129,7 @@ PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
bool allow_directive_prologue = true;
while (peek() != end_token) {
- Statement statement = ParseStatement(CHECK_OK);
+ Statement statement = ParseSourceElement(CHECK_OK);
if (allow_directive_prologue) {
if (statement.IsUseStrictLiteral()) {
set_strict_mode();
@@ -174,7 +182,7 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
case i::Token::CONST:
case i::Token::VAR:
- return ParseVariableStatement(ok);
+ return ParseVariableStatement(kStatement, ok);
case i::Token::SEMICOLON:
Next();
@@ -260,7 +268,7 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) {
Expect(i::Token::LBRACE, CHECK_OK);
while (peek() != i::Token::RBRACE) {
i::Scanner::Location start_location = scanner_->peek_location();
- Statement statement = ParseStatement(CHECK_OK);
+ Statement statement = ParseSourceElement(CHECK_OK);
i::Scanner::Location end_location = scanner_->location();
if (strict_mode() && statement.IsFunctionDeclaration()) {
ReportMessageAt(start_location.beg_pos, end_location.end_pos,
@@ -274,11 +282,15 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) {
}
-PreParser::Statement PreParser::ParseVariableStatement(bool* ok) {
+PreParser::Statement PreParser::ParseVariableStatement(
+ VariableDeclarationContext var_context,
+ bool* ok) {
// VariableStatement ::
// VariableDeclarations ';'
- Statement result = ParseVariableDeclarations(true, NULL, CHECK_OK);
+ Statement result = ParseVariableDeclarations(var_context,
+ NULL,
+ CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
@@ -289,9 +301,10 @@ PreParser::Statement PreParser::ParseVariableStatement(bool* ok) {
// *var is untouched; in particular, it is the caller's responsibility
// to initialize it properly. This mechanism is also used for the parsing
// of 'for-in' loops.
-PreParser::Statement PreParser::ParseVariableDeclarations(bool accept_IN,
- int* num_decl,
- bool* ok) {
+PreParser::Statement PreParser::ParseVariableDeclarations(
+ VariableDeclarationContext var_context,
+ int* num_decl,
+ bool* ok) {
// VariableDeclarations ::
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
@@ -306,13 +319,25 @@ PreParser::Statement PreParser::ParseVariableDeclarations(bool accept_IN,
return Statement::Default();
}
Consume(i::Token::CONST);
+ } else if (peek() == i::Token::LET) {
+ if (var_context != kSourceElement &&
+ var_context != kForStatement) {
+ i::Scanner::Location location = scanner_->peek_location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "unprotected_let", NULL);
+ *ok = false;
+ return Statement::Default();
+ }
+ Consume(i::Token::LET);
} else {
*ok = false;
return Statement::Default();
}
- // The scope of a variable/const declared anywhere inside a function
- // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). .
+ // The scope of a var/const declared variable anywhere inside a function
+ // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope
+ // of a let declared variable is the scope of the immediately enclosing
+ // block.
int nvars = 0; // the number of variables declared
do {
// Parse variable name.
@@ -328,7 +353,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(bool accept_IN,
nvars++;
if (peek() == i::Token::ASSIGN) {
Expect(i::Token::ASSIGN, CHECK_OK);
- ParseAssignmentExpression(accept_IN, CHECK_OK);
+ ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
}
} while (peek() == i::Token::COMMA);
@@ -537,9 +562,10 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
Expect(i::Token::FOR, CHECK_OK);
Expect(i::Token::LPAREN, CHECK_OK);
if (peek() != i::Token::SEMICOLON) {
- if (peek() == i::Token::VAR || peek() == i::Token::CONST) {
+ if (peek() == i::Token::VAR || peek() == i::Token::CONST ||
+ peek() == i::Token::LET) {
int decl_count;
- ParseVariableDeclarations(false, &decl_count, CHECK_OK);
+ ParseVariableDeclarations(kForStatement, &decl_count, CHECK_OK);
if (peek() == i::Token::IN && decl_count == 1) {
Expect(i::Token::IN, CHECK_OK);
ParseExpression(true, CHECK_OK);
diff --git a/deps/v8/src/preparser.h b/deps/v8/src/preparser.h
index 3d72c97e2..cd0a530e8 100644
--- a/deps/v8/src/preparser.h
+++ b/deps/v8/src/preparser.h
@@ -77,6 +77,12 @@ class PreParser {
kFunctionScope
};
+ enum VariableDeclarationContext {
+ kSourceElement,
+ kStatement,
+ kForStatement
+ };
+
class Expression;
class Identifier {
@@ -344,7 +350,8 @@ class PreParser {
strict_mode_violation_type_(NULL),
stack_overflow_(false),
allow_lazy_(true),
- parenthesized_function_(false) { }
+ parenthesized_function_(false),
+ harmony_block_scoping_(scanner->HarmonyBlockScoping()) { }
// Preparse the program. Only called in PreParseProgram after creating
// the instance.
@@ -377,12 +384,16 @@ class PreParser {
// which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites.
+ Statement ParseSourceElement(bool* ok);
SourceElements ParseSourceElements(int end_token, bool* ok);
Statement ParseStatement(bool* ok);
Statement ParseFunctionDeclaration(bool* ok);
Statement ParseBlock(bool* ok);
- Statement ParseVariableStatement(bool* ok);
- Statement ParseVariableDeclarations(bool accept_IN, int* num_decl, bool* ok);
+ Statement ParseVariableStatement(VariableDeclarationContext var_context,
+ bool* ok);
+ Statement ParseVariableDeclarations(VariableDeclarationContext var_context,
+ int* num_decl,
+ bool* ok);
Statement ParseExpressionOrLabelledStatement(bool* ok);
Statement ParseIfStatement(bool* ok);
Statement ParseContinueStatement(bool* ok);
@@ -496,6 +507,7 @@ class PreParser {
bool stack_overflow_;
bool allow_lazy_;
bool parenthesized_function_;
+ bool harmony_block_scoping_;
};
} } // v8::preparser
diff --git a/deps/v8/src/prettyprinter.cc b/deps/v8/src/prettyprinter.cc
index f18b3203e..b03429341 100644
--- a/deps/v8/src/prettyprinter.cc
+++ b/deps/v8/src/prettyprinter.cc
@@ -123,11 +123,11 @@ void PrettyPrinter::VisitReturnStatement(ReturnStatement* node) {
}
-void PrettyPrinter::VisitEnterWithContextStatement(
- EnterWithContextStatement* node) {
- Print("<enter with context> (");
+void PrettyPrinter::VisitWithStatement(WithStatement* node) {
+ Print("with (");
Visit(node->expression());
Print(") ");
+ Visit(node->statement());
}
@@ -798,9 +798,10 @@ void AstPrinter::VisitReturnStatement(ReturnStatement* node) {
}
-void AstPrinter::VisitEnterWithContextStatement(
- EnterWithContextStatement* node) {
- PrintIndentedVisit("ENTER WITH CONTEXT", node->expression());
+void AstPrinter::VisitWithStatement(WithStatement* node) {
+ IndentedScope indent(this, "WITH");
+ PrintIndentedVisit("OBJECT", node->expression());
+ PrintIndentedVisit("BODY", node->statement());
}
@@ -1194,10 +1195,10 @@ void JsonAstBuilder::VisitReturnStatement(ReturnStatement* stmt) {
}
-void JsonAstBuilder::VisitEnterWithContextStatement(
- EnterWithContextStatement* stmt) {
- TagScope tag(this, "EnterWithContextStatement");
+void JsonAstBuilder::VisitWithStatement(WithStatement* stmt) {
+ TagScope tag(this, "WithStatement");
Visit(stmt->expression());
+ Visit(stmt->statement());
}
diff --git a/deps/v8/src/rewriter.cc b/deps/v8/src/rewriter.cc
index e8ca5b9de..ad6ce056b 100644
--- a/deps/v8/src/rewriter.cc
+++ b/deps/v8/src/rewriter.cc
@@ -197,13 +197,17 @@ void Processor::VisitBreakStatement(BreakStatement* node) {
}
+void Processor::VisitWithStatement(WithStatement* node) {
+ bool set_after_body = is_set_;
+ Visit(node->statement());
+ is_set_ = is_set_ && set_after_body;
+}
+
+
// Do nothing:
void Processor::VisitDeclaration(Declaration* node) {}
void Processor::VisitEmptyStatement(EmptyStatement* node) {}
void Processor::VisitReturnStatement(ReturnStatement* node) {}
-void Processor::VisitEnterWithContextStatement(
- EnterWithContextStatement* node) {
-}
void Processor::VisitExitContextStatement(ExitContextStatement* node) {}
void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
diff --git a/deps/v8/src/runtime-profiler.h b/deps/v8/src/runtime-profiler.h
index 3f3ab0773..15c209713 100644
--- a/deps/v8/src/runtime-profiler.h
+++ b/deps/v8/src/runtime-profiler.h
@@ -94,12 +94,6 @@ class RuntimeProfiler {
private:
static const int kSamplerWindowSize = 16;
- static const int kStateWindowSize = 128;
-
- enum SamplerState {
- IN_NON_JS_STATE = 0,
- IN_JS_STATE = 1
- };
static void HandleWakeUp(Isolate* isolate);
diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc
index 82733a7c1..f629970ff 100644
--- a/deps/v8/src/runtime.cc
+++ b/deps/v8/src/runtime.cc
@@ -4853,7 +4853,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
return isolate->heap()->boolean_symbol();
}
if (heap_obj->IsNull()) {
- return isolate->heap()->object_symbol();
+ return FLAG_harmony_typeof
+ ? isolate->heap()->null_symbol()
+ : isolate->heap()->object_symbol();
}
ASSERT(heap_obj->IsUndefined());
return isolate->heap()->undefined_symbol();
@@ -8314,6 +8316,30 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 2);
+ SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
+ JSFunction* function;
+ if (args[1]->IsSmi()) {
+ // A smi sentinel indicates a context nested inside global code rather
+ // than some function. There is a canonical empty function that can be
+ // gotten from the global context.
+ function = isolate->context()->global_context()->closure();
+ } else {
+ function = JSFunction::cast(args[1]);
+ }
+ Context* context;
+ MaybeObject* maybe_context =
+ isolate->heap()->AllocateBlockContext(function,
+ isolate->context(),
+ scope_info);
+ if (!maybe_context->To(&context)) return maybe_context;
+ isolate->set_context(context);
+ return context;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
@@ -9654,7 +9680,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSArray, from, args[0]);
CONVERT_CHECKED(JSArray, to, args[1]);
- HeapObject* new_elements = from->elements();
+ FixedArrayBase* new_elements = from->elements();
MaybeObject* maybe_new_map;
if (new_elements->map() == isolate->heap()->fixed_array_map() ||
new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
@@ -10639,6 +10665,34 @@ static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
}
+// Create a plain JSObject which materializes the block scope for the specified
+// block context.
+static Handle<JSObject> MaterializeBlockScope(
+ Isolate* isolate,
+ Handle<Context> context) {
+ ASSERT(context->IsBlockContext());
+ Handle<SerializedScopeInfo> serialized_scope_info(
+ SerializedScopeInfo::cast(context->extension()));
+ ScopeInfo<> scope_info(*serialized_scope_info);
+
+ // Allocate and initialize a JSObject with all the arguments, stack locals
+ // heap locals and extension properties of the debugged function.
+ Handle<JSObject> block_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
+
+ // Fill all context locals.
+ if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
+ if (!CopyContextLocalsToScopeObject(isolate,
+ serialized_scope_info, scope_info,
+ context, block_scope)) {
+ return Handle<JSObject>();
+ }
+ }
+
+ return block_scope;
+}
+
+
// Iterate over the actual scopes visible from a stack frame. All scopes are
// backed by an actual context except the local scope, which is inserted
// "artifically" in the context chain.
@@ -10649,7 +10703,8 @@ class ScopeIterator {
ScopeTypeLocal,
ScopeTypeWith,
ScopeTypeClosure,
- ScopeTypeCatch
+ ScopeTypeCatch,
+ ScopeTypeBlock
};
ScopeIterator(Isolate* isolate,
@@ -10675,8 +10730,10 @@ class ScopeIterator {
} else if (context_->IsFunctionContext()) {
at_local_ = true;
} else if (context_->closure() != *function_) {
- // The context_ is a with or catch block from the outer function.
- ASSERT(context_->IsWithContext() || context_->IsCatchContext());
+ // The context_ is a block or with or catch block from the outer function.
+ ASSERT(context_->IsWithContext() ||
+ context_->IsCatchContext() ||
+ context_->IsBlockContext());
at_local_ = true;
}
}
@@ -10731,6 +10788,9 @@ class ScopeIterator {
if (context_->IsCatchContext()) {
return ScopeTypeCatch;
}
+ if (context_->IsBlockContext()) {
+ return ScopeTypeBlock;
+ }
ASSERT(context_->IsWithContext());
return ScopeTypeWith;
}
@@ -10751,6 +10811,8 @@ class ScopeIterator {
case ScopeIterator::ScopeTypeClosure:
// Materialize the content of the closure scope into a JSObject.
return MaterializeClosure(isolate_, CurrentContext());
+ case ScopeIterator::ScopeTypeBlock:
+ return MaterializeBlockScope(isolate_, CurrentContext());
}
UNREACHABLE();
return Handle<JSObject>();
@@ -11307,7 +11369,18 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate,
new_previous,
name,
thrown_object);
+ } else if (current->IsBlockContext()) {
+ Handle<SerializedScopeInfo> scope_info(
+ SerializedScopeInfo::cast(current->extension()));
+ new_current =
+ isolate->factory()->NewBlockContext(function, new_previous, scope_info);
+ // Copy context slots.
+ int num_context_slots = scope_info->NumberOfContextSlots();
+ for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
+ new_current->set(i, current->get(i));
+ }
} else {
+ ASSERT(current->IsWithContext());
Handle<JSObject> extension(JSObject::cast(current->extension()));
new_current =
isolate->factory()->NewWithContext(function, new_previous, extension);
diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h
index a52672ad7..06d368454 100644
--- a/deps/v8/src/runtime.h
+++ b/deps/v8/src/runtime.h
@@ -310,6 +310,7 @@ namespace internal {
F(NewFunctionContext, 1, 1) \
F(PushWithContext, 2, 1) \
F(PushCatchContext, 3, 1) \
+ F(PushBlockContext, 2, 1) \
F(DeleteContextSlot, 2, 1) \
F(LoadContextSlot, 2, 2) \
F(LoadContextSlotNoReferenceError, 2, 2) \
diff --git a/deps/v8/src/scanner-base.cc b/deps/v8/src/scanner-base.cc
index e4590b126..2ecbfd2a9 100644
--- a/deps/v8/src/scanner-base.cc
+++ b/deps/v8/src/scanner-base.cc
@@ -74,7 +74,9 @@ uc32 Scanner::ScanHexEscape(uc32 c, int length) {
// JavaScriptScanner
JavaScriptScanner::JavaScriptScanner(UnicodeCache* scanner_contants)
- : Scanner(scanner_contants), octal_pos_(Location::invalid()) { }
+ : Scanner(scanner_contants),
+ octal_pos_(Location::invalid()),
+ harmony_block_scoping_(false) { }
void JavaScriptScanner::Initialize(UC16CharacterStream* source) {
@@ -813,71 +815,73 @@ uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() {
// ----------------------------------------------------------------------------
// Keyword Matcher
-#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
- KEYWORD_GROUP('b') \
- KEYWORD("break", BREAK) \
- KEYWORD_GROUP('c') \
- KEYWORD("case", CASE) \
- KEYWORD("catch", CATCH) \
- KEYWORD("class", FUTURE_RESERVED_WORD) \
- KEYWORD("const", CONST) \
- KEYWORD("continue", CONTINUE) \
- KEYWORD_GROUP('d') \
- KEYWORD("debugger", DEBUGGER) \
- KEYWORD("default", DEFAULT) \
- KEYWORD("delete", DELETE) \
- KEYWORD("do", DO) \
- KEYWORD_GROUP('e') \
- KEYWORD("else", ELSE) \
- KEYWORD("enum", FUTURE_RESERVED_WORD) \
- KEYWORD("export", FUTURE_RESERVED_WORD) \
- KEYWORD("extends", FUTURE_RESERVED_WORD) \
- KEYWORD_GROUP('f') \
- KEYWORD("false", FALSE_LITERAL) \
- KEYWORD("finally", FINALLY) \
- KEYWORD("for", FOR) \
- KEYWORD("function", FUNCTION) \
- KEYWORD_GROUP('i') \
- KEYWORD("if", IF) \
- KEYWORD("implements", FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("import", FUTURE_RESERVED_WORD) \
- KEYWORD("in", IN) \
- KEYWORD("instanceof", INSTANCEOF) \
- KEYWORD("interface", FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('l') \
- KEYWORD("let", FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('n') \
- KEYWORD("new", NEW) \
- KEYWORD("null", NULL_LITERAL) \
- KEYWORD_GROUP('p') \
- KEYWORD("package", FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("private", FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("protected", FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("public", FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('r') \
- KEYWORD("return", RETURN) \
- KEYWORD_GROUP('s') \
- KEYWORD("static", FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("super", FUTURE_RESERVED_WORD) \
- KEYWORD("switch", SWITCH) \
- KEYWORD_GROUP('t') \
- KEYWORD("this", THIS) \
- KEYWORD("throw", THROW) \
- KEYWORD("true", TRUE_LITERAL) \
- KEYWORD("try", TRY) \
- KEYWORD("typeof", TYPEOF) \
- KEYWORD_GROUP('v') \
- KEYWORD("var", VAR) \
- KEYWORD("void", VOID) \
- KEYWORD_GROUP('w') \
- KEYWORD("while", WHILE) \
- KEYWORD("with", WITH) \
- KEYWORD_GROUP('y') \
- KEYWORD("yield", FUTURE_STRICT_RESERVED_WORD)
+#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
+ KEYWORD_GROUP('b') \
+ KEYWORD("break", Token::BREAK) \
+ KEYWORD_GROUP('c') \
+ KEYWORD("case", Token::CASE) \
+ KEYWORD("catch", Token::CATCH) \
+ KEYWORD("class", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("const", Token::CONST) \
+ KEYWORD("continue", Token::CONTINUE) \
+ KEYWORD_GROUP('d') \
+ KEYWORD("debugger", Token::DEBUGGER) \
+ KEYWORD("default", Token::DEFAULT) \
+ KEYWORD("delete", Token::DELETE) \
+ KEYWORD("do", Token::DO) \
+ KEYWORD_GROUP('e') \
+ KEYWORD("else", Token::ELSE) \
+ KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("export", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD_GROUP('f') \
+ KEYWORD("false", Token::FALSE_LITERAL) \
+ KEYWORD("finally", Token::FINALLY) \
+ KEYWORD("for", Token::FOR) \
+ KEYWORD("function", Token::FUNCTION) \
+ KEYWORD_GROUP('i') \
+ KEYWORD("if", Token::IF) \
+ KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("import", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("in", Token::IN) \
+ KEYWORD("instanceof", Token::INSTANCEOF) \
+ KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('l') \
+ KEYWORD("let", harmony_block_scoping \
+ ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('n') \
+ KEYWORD("new", Token::NEW) \
+ KEYWORD("null", Token::NULL_LITERAL) \
+ KEYWORD_GROUP('p') \
+ KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('r') \
+ KEYWORD("return", Token::RETURN) \
+ KEYWORD_GROUP('s') \
+ KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("super", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("switch", Token::SWITCH) \
+ KEYWORD_GROUP('t') \
+ KEYWORD("this", Token::THIS) \
+ KEYWORD("throw", Token::THROW) \
+ KEYWORD("true", Token::TRUE_LITERAL) \
+ KEYWORD("try", Token::TRY) \
+ KEYWORD("typeof", Token::TYPEOF) \
+ KEYWORD_GROUP('v') \
+ KEYWORD("var", Token::VAR) \
+ KEYWORD("void", Token::VOID) \
+ KEYWORD_GROUP('w') \
+ KEYWORD("while", Token::WHILE) \
+ KEYWORD("with", Token::WITH) \
+ KEYWORD_GROUP('y') \
+ KEYWORD("yield", Token::FUTURE_STRICT_RESERVED_WORD)
static Token::Value KeywordOrIdentifierToken(const char* input,
- int input_length) {
+ int input_length,
+ bool harmony_block_scoping) {
ASSERT(input_length >= 1);
const int kMinLength = 2;
const int kMaxLength = 10;
@@ -906,7 +910,7 @@ static Token::Value KeywordOrIdentifierToken(const char* input,
(keyword_length <= 7 || input[7] == keyword[7]) && \
(keyword_length <= 8 || input[8] == keyword[8]) && \
(keyword_length <= 9 || input[9] == keyword[9])) { \
- return Token::token; \
+ return token; \
} \
}
KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
@@ -947,7 +951,9 @@ Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
if (next_.literal_chars->is_ascii()) {
Vector<const char> chars = next_.literal_chars->ascii_literal();
- return KeywordOrIdentifierToken(chars.start(), chars.length());
+ return KeywordOrIdentifierToken(chars.start(),
+ chars.length(),
+ harmony_block_scoping_);
}
return Token::IDENTIFIER;
diff --git a/deps/v8/src/scanner-base.h b/deps/v8/src/scanner-base.h
index d3776e5f8..3e1772a3d 100644
--- a/deps/v8/src/scanner-base.h
+++ b/deps/v8/src/scanner-base.h
@@ -507,6 +507,14 @@ class JavaScriptScanner : public Scanner {
// tokens, which is what it is used for.
void SeekForward(int pos);
+ bool HarmonyBlockScoping() const {
+ return harmony_block_scoping_;
+ }
+ void SetHarmonyBlockScoping(bool block_scoping) {
+ harmony_block_scoping_ = block_scoping;
+ }
+
+
protected:
bool SkipWhiteSpace();
Token::Value SkipSingleLineComment();
@@ -540,6 +548,9 @@ class JavaScriptScanner : public Scanner {
// Whether there is a multi-line comment that contains a
// line-terminator after the current token, and before the next.
bool has_multiline_comment_before_next_;
+ // Whether we scan 'let' as a keyword for harmony block scoped
+ // let bindings.
+ bool harmony_block_scoping_;
};
} } // namespace v8::internal
diff --git a/deps/v8/src/scopeinfo.cc b/deps/v8/src/scopeinfo.cc
index 3e18368f7..0eacc83c7 100644
--- a/deps/v8/src/scopeinfo.cc
+++ b/deps/v8/src/scopeinfo.cc
@@ -313,7 +313,7 @@ Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
stack_slots_.length();
Handle<SerializedScopeInfo> data(
- SerializedScopeInfo::cast(*FACTORY->NewFixedArray(length, TENURED)));
+ SerializedScopeInfo::cast(*FACTORY->NewSerializedScopeInfo(length)));
AssertNoAllocation nogc;
Object** p0 = data->data_start();
diff --git a/deps/v8/src/scopeinfo.h b/deps/v8/src/scopeinfo.h
index 86c33f61f..1c61f1115 100644
--- a/deps/v8/src/scopeinfo.h
+++ b/deps/v8/src/scopeinfo.h
@@ -107,7 +107,7 @@ class SerializedScopeInfo : public FixedArray {
public :
static SerializedScopeInfo* cast(Object* object) {
- ASSERT(object->IsFixedArray());
+ ASSERT(object->IsSerializedScopeInfo());
return reinterpret_cast<SerializedScopeInfo*>(object);
}
diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc
index 390a0b6e1..ddde48a77 100644
--- a/deps/v8/src/scopes.cc
+++ b/deps/v8/src/scopes.cc
@@ -146,7 +146,9 @@ Scope::Scope(Scope* outer_scope, Type type)
}
-Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info)
+Scope::Scope(Scope* inner_scope,
+ Type type,
+ Handle<SerializedScopeInfo> scope_info)
: isolate_(Isolate::Current()),
inner_scopes_(4),
variables_(),
@@ -156,7 +158,7 @@ Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info)
decls_(4),
already_resolved_(true) {
ASSERT(!scope_info.is_null());
- SetDefaults(FUNCTION_SCOPE, NULL, scope_info);
+ SetDefaults(type, NULL, scope_info);
if (scope_info->HasHeapAllocatedLocals()) {
num_heap_slots_ = scope_info_->NumberOfContextSlots();
}
@@ -232,8 +234,13 @@ Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
if (context->IsFunctionContext()) {
SerializedScopeInfo* scope_info =
context->closure()->shared()->scope_info();
- current_scope =
- new Scope(current_scope, Handle<SerializedScopeInfo>(scope_info));
+ current_scope = new Scope(current_scope, FUNCTION_SCOPE,
+ Handle<SerializedScopeInfo>(scope_info));
+ } else if (context->IsBlockContext()) {
+ SerializedScopeInfo* scope_info =
+ SerializedScopeInfo::cast(context->extension());
+ current_scope = new Scope(current_scope, BLOCK_SCOPE,
+ Handle<SerializedScopeInfo>(scope_info));
} else {
ASSERT(context->IsCatchContext());
String* name = String::cast(context->extension());
@@ -294,10 +301,13 @@ void Scope::Initialize(bool inside_with) {
// instead load them directly from the stack. Currently, the only
// such parameter is 'this' which is passed on the stack when
// invoking scripts
- if (is_catch_scope()) {
+ if (is_catch_scope() || is_block_scope()) {
ASSERT(outer_scope() != NULL);
receiver_ = outer_scope()->receiver();
} else {
+ ASSERT(is_function_scope() ||
+ is_global_scope() ||
+ is_eval_scope());
Variable* var =
variables_.Declare(this,
isolate_->factory()->this_symbol(),
@@ -387,7 +397,9 @@ Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) {
// This function handles VAR and CONST modes. DYNAMIC variables are
// introduces during variable allocation, INTERNAL variables are allocated
// explicitly, and TEMPORARY variables are allocated via NewTemporary().
- ASSERT(mode == Variable::VAR || mode == Variable::CONST);
+ ASSERT(mode == Variable::VAR ||
+ mode == Variable::CONST ||
+ mode == Variable::LET);
++num_var_or_const_;
return variables_.Declare(this, name, mode, true, Variable::NORMAL);
}
@@ -559,13 +571,22 @@ int Scope::ContextChainLength(Scope* scope) {
Scope* Scope::DeclarationScope() {
Scope* scope = this;
- while (scope->is_catch_scope()) {
+ while (scope->is_catch_scope() ||
+ scope->is_block_scope()) {
scope = scope->outer_scope();
}
return scope;
}
+Handle<SerializedScopeInfo> Scope::GetSerializedScopeInfo() {
+ if (scope_info_.is_null()) {
+ scope_info_ = SerializedScopeInfo::Create(this);
+ }
+ return scope_info_;
+}
+
+
#ifdef DEBUG
static const char* Header(Scope::Type type) {
switch (type) {
@@ -573,6 +594,7 @@ static const char* Header(Scope::Type type) {
case Scope::FUNCTION_SCOPE: return "function";
case Scope::GLOBAL_SCOPE: return "global";
case Scope::CATCH_SCOPE: return "catch";
+ case Scope::BLOCK_SCOPE: return "block";
}
UNREACHABLE();
return NULL;
@@ -598,9 +620,11 @@ static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
PrintF("; // ");
if (var->rewrite() != NULL) {
PrintF("%s, ", printer->Print(var->rewrite()));
- if (var->is_accessed_from_inner_scope()) PrintF(", ");
+ if (var->is_accessed_from_inner_function_scope()) PrintF(", ");
+ }
+ if (var->is_accessed_from_inner_function_scope()) {
+ PrintF("inner scope access");
}
- if (var->is_accessed_from_inner_scope()) PrintF("inner scope access");
PrintF("\n");
}
}
@@ -721,7 +745,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
// another variable that is introduced dynamically via an 'eval' call
// or a 'with' statement).
Variable* Scope::LookupRecursive(Handle<String> name,
- bool inner_lookup,
+ bool from_inner_function,
Variable** invalidated_local) {
// If we find a variable, but the current scope calls 'eval', the found
// variable may not be the correct one (the 'eval' may introduce a
@@ -737,7 +761,7 @@ Variable* Scope::LookupRecursive(Handle<String> name,
// (Even if there is an 'eval' in this scope which introduces the
// same variable again, the resulting variable remains the same.
// Note that enclosing 'with' statements are handled at the call site.)
- if (!inner_lookup)
+ if (!from_inner_function)
return var;
} else {
@@ -753,7 +777,10 @@ Variable* Scope::LookupRecursive(Handle<String> name,
var = function_;
} else if (outer_scope_ != NULL) {
- var = outer_scope_->LookupRecursive(name, true, invalidated_local);
+ var = outer_scope_->LookupRecursive(
+ name,
+ is_function_scope() || from_inner_function,
+ invalidated_local);
// We may have found a variable in an outer scope. However, if
// the current scope is inside a 'with', the actual variable may
// be a property introduced via the 'with' statement. Then, the
@@ -770,8 +797,8 @@ Variable* Scope::LookupRecursive(Handle<String> name,
ASSERT(var != NULL);
// If this is a lookup from an inner scope, mark the variable.
- if (inner_lookup) {
- var->MarkAsAccessedFromInnerScope();
+ if (from_inner_function) {
+ var->MarkAsAccessedFromInnerFunctionScope();
}
// If the variable we have found is just a guess, invalidate the
@@ -922,11 +949,12 @@ bool Scope::MustAllocate(Variable* var) {
// via an eval() call. This is only possible if the variable has a
// visible name.
if ((var->is_this() || var->name()->length() > 0) &&
- (var->is_accessed_from_inner_scope() ||
+ (var->is_accessed_from_inner_function_scope() ||
scope_calls_eval_ ||
inner_scope_calls_eval_ ||
scope_contains_with_ ||
- is_catch_scope())) {
+ is_catch_scope() ||
+ is_block_scope())) {
var->set_is_used(true);
}
// Global variables do not need to be allocated.
@@ -943,8 +971,8 @@ bool Scope::MustAllocateInContext(Variable* var) {
// Exceptions: temporary variables are never allocated in a context;
// catch-bound variables are always allocated in a context.
if (var->mode() == Variable::TEMPORARY) return false;
- if (is_catch_scope()) return true;
- return var->is_accessed_from_inner_scope() ||
+ if (is_catch_scope() || is_block_scope()) return true;
+ return var->is_accessed_from_inner_function_scope() ||
scope_calls_eval_ ||
inner_scope_calls_eval_ ||
scope_contains_with_ ||
@@ -1010,7 +1038,7 @@ void Scope::AllocateParameterLocals() {
if (uses_nonstrict_arguments) {
// Give the parameter a use from an inner scope, to force allocation
// to the context.
- var->MarkAsAccessedFromInnerScope();
+ var->MarkAsAccessedFromInnerFunctionScope();
}
if (MustAllocate(var)) {
diff --git a/deps/v8/src/scopes.h b/deps/v8/src/scopes.h
index d4eb17cd5..c2c41799b 100644
--- a/deps/v8/src/scopes.h
+++ b/deps/v8/src/scopes.h
@@ -93,7 +93,8 @@ class Scope: public ZoneObject {
EVAL_SCOPE, // The top-level scope for an eval source.
FUNCTION_SCOPE, // The top-level scope for a function.
GLOBAL_SCOPE, // The top-level scope for a program or a top-level eval.
- CATCH_SCOPE // The scope introduced by catch.
+ CATCH_SCOPE, // The scope introduced by catch.
+ BLOCK_SCOPE // The scope introduced by a new block.
};
Scope(Scope* outer_scope, Type type);
@@ -204,6 +205,7 @@ class Scope: public ZoneObject {
bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
bool is_catch_scope() const { return type_ == CATCH_SCOPE; }
+ bool is_block_scope() const { return type_ == BLOCK_SCOPE; }
bool is_strict_mode() const { return strict_mode_; }
bool is_strict_mode_eval_scope() const {
return is_eval_scope() && is_strict_mode();
@@ -294,6 +296,8 @@ class Scope: public ZoneObject {
// where var declarations will be hoisted to in the implementation.
Scope* DeclarationScope();
+ Handle<SerializedScopeInfo> GetSerializedScopeInfo();
+
// ---------------------------------------------------------------------------
// Strict mode support.
bool IsDeclared(Handle<String> name) {
@@ -397,7 +401,7 @@ class Scope: public ZoneObject {
// Variable resolution.
Variable* LookupRecursive(Handle<String> name,
- bool inner_lookup,
+ bool from_inner_function,
Variable** invalidated_local);
void ResolveVariable(Scope* global_scope,
Handle<Context> context,
@@ -425,8 +429,8 @@ class Scope: public ZoneObject {
void AllocateVariablesRecursively();
private:
- // Construct a function scope based on the scope info.
- Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info);
+ // Construct a function or block scope based on the scope info.
+ Scope(Scope* inner_scope, Type type, Handle<SerializedScopeInfo> scope_info);
// Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name);
diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc
index 8cde580fb..094ad20b2 100644
--- a/deps/v8/src/serialize.cc
+++ b/deps/v8/src/serialize.cc
@@ -62,57 +62,15 @@ static int* GetInternalPointer(StatsCounter* counter) {
}
-// ExternalReferenceTable is a helper class that defines the relationship
-// between external references and their encodings. It is used to build
-// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
-class ExternalReferenceTable {
- public:
- static ExternalReferenceTable* instance(Isolate* isolate) {
- ExternalReferenceTable* external_reference_table =
- isolate->external_reference_table();
- if (external_reference_table == NULL) {
- external_reference_table = new ExternalReferenceTable(isolate);
- isolate->set_external_reference_table(external_reference_table);
- }
- return external_reference_table;
- }
-
- int size() const { return refs_.length(); }
-
- Address address(int i) { return refs_[i].address; }
-
- uint32_t code(int i) { return refs_[i].code; }
-
- const char* name(int i) { return refs_[i].name; }
-
- int max_id(int code) { return max_id_[code]; }
-
- private:
- explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) {
- PopulateTable(isolate);
+ExternalReferenceTable* ExternalReferenceTable::instance(Isolate* isolate) {
+ ExternalReferenceTable* external_reference_table =
+ isolate->external_reference_table();
+ if (external_reference_table == NULL) {
+ external_reference_table = new ExternalReferenceTable(isolate);
+ isolate->set_external_reference_table(external_reference_table);
}
- ~ExternalReferenceTable() { }
-
- struct ExternalReferenceEntry {
- Address address;
- uint32_t code;
- const char* name;
- };
-
- void PopulateTable(Isolate* isolate);
-
- // For a few types of references, we can get their address from their id.
- void AddFromId(TypeCode type,
- uint16_t id,
- const char* name,
- Isolate* isolate);
-
- // For other types of references, the caller will figure out the address.
- void Add(Address address, TypeCode type, uint16_t id, const char* name);
-
- List<ExternalReferenceEntry> refs_;
- int max_id_[kTypeCodeCount];
-};
+ return external_reference_table;
+}
void ExternalReferenceTable::AddFromId(TypeCode type,
diff --git a/deps/v8/src/serialize.h b/deps/v8/src/serialize.h
index d83722d00..66d6fb511 100644
--- a/deps/v8/src/serialize.h
+++ b/deps/v8/src/serialize.h
@@ -60,6 +60,52 @@ const int kDebugRegisterBits = 4;
const int kDebugIdShift = kDebugRegisterBits;
+// ExternalReferenceTable is a helper class that defines the relationship
+// between external references and their encodings. It is used to build
+// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
+class ExternalReferenceTable {
+ public:
+ static ExternalReferenceTable* instance(Isolate* isolate);
+
+ ~ExternalReferenceTable() { }
+
+ int size() const { return refs_.length(); }
+
+ Address address(int i) { return refs_[i].address; }
+
+ uint32_t code(int i) { return refs_[i].code; }
+
+ const char* name(int i) { return refs_[i].name; }
+
+ int max_id(int code) { return max_id_[code]; }
+
+ private:
+ explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) {
+ PopulateTable(isolate);
+ }
+
+ struct ExternalReferenceEntry {
+ Address address;
+ uint32_t code;
+ const char* name;
+ };
+
+ void PopulateTable(Isolate* isolate);
+
+ // For a few types of references, we can get their address from their id.
+ void AddFromId(TypeCode type,
+ uint16_t id,
+ const char* name,
+ Isolate* isolate);
+
+ // For other types of references, the caller will figure out the address.
+ void Add(Address address, TypeCode type, uint16_t id, const char* name);
+
+ List<ExternalReferenceEntry> refs_;
+ int max_id_[kTypeCodeCount];
+};
+
+
class ExternalReferenceEncoder {
public:
ExternalReferenceEncoder();
@@ -544,6 +590,7 @@ class PartialSerializer : public Serializer {
ASSERT(!o->IsScript());
return o->IsString() || o->IsSharedFunctionInfo() ||
o->IsHeapNumber() || o->IsCode() ||
+ o->IsSerializedScopeInfo() ||
o->map() == HEAP->fixed_cow_array_map();
}
diff --git a/deps/v8/src/token.h b/deps/v8/src/token.h
index 7e6c18cfe..33af7fe6b 100644
--- a/deps/v8/src/token.h
+++ b/deps/v8/src/token.h
@@ -168,6 +168,7 @@ namespace internal {
T(FUTURE_RESERVED_WORD, NULL, 0) \
T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
K(CONST, "const", 0) \
+ K(LET, "let", 0) \
\
/* Illegal token - not able to scan. */ \
T(ILLEGAL, "ILLEGAL", 0) \
diff --git a/deps/v8/src/variables.cc b/deps/v8/src/variables.cc
index 67150ea13..69495bb40 100644
--- a/deps/v8/src/variables.cc
+++ b/deps/v8/src/variables.cc
@@ -41,6 +41,7 @@ const char* Variable::Mode2String(Mode mode) {
switch (mode) {
case VAR: return "VAR";
case CONST: return "CONST";
+ case LET: return "LET";
case DYNAMIC: return "DYNAMIC";
case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL";
case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL";
@@ -92,7 +93,7 @@ Variable::Variable(Scope* scope,
local_if_not_shadowed_(NULL),
rewrite_(NULL),
is_valid_LHS_(is_valid_LHS),
- is_accessed_from_inner_scope_(false),
+ is_accessed_from_inner_function_scope_(false),
is_used_(false) {
// names must be canonicalized for fast equality checks
ASSERT(name->IsSymbol());
diff --git a/deps/v8/src/variables.h b/deps/v8/src/variables.h
index a9c06d1ee..e92ba6d39 100644
--- a/deps/v8/src/variables.h
+++ b/deps/v8/src/variables.h
@@ -46,6 +46,8 @@ class Variable: public ZoneObject {
CONST, // declared via 'const' declarations
+ LET, // declared via 'let' declarations
+
// Variables introduced by the compiler:
DYNAMIC, // always require dynamic lookup (we don't know
// the declaration)
@@ -95,11 +97,12 @@ class Variable: public ZoneObject {
Handle<String> name() const { return name_; }
Mode mode() const { return mode_; }
- bool is_accessed_from_inner_scope() const {
- return is_accessed_from_inner_scope_;
+ bool is_accessed_from_inner_function_scope() const {
+ return is_accessed_from_inner_function_scope_;
}
- void MarkAsAccessedFromInnerScope() {
- is_accessed_from_inner_scope_ = true;
+ void MarkAsAccessedFromInnerFunctionScope() {
+ ASSERT(mode_ != TEMPORARY);
+ is_accessed_from_inner_function_scope_ = true;
}
bool is_used() { return is_used_; }
void set_is_used(bool flag) { is_used_ = flag; }
@@ -156,7 +159,7 @@ class Variable: public ZoneObject {
bool is_valid_LHS_;
// Usage info.
- bool is_accessed_from_inner_scope_; // set by variable resolver
+ bool is_accessed_from_inner_function_scope_; // set by variable resolver
bool is_used_;
};
diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc
index 83836f620..c39af566f 100644
--- a/deps/v8/src/version.cc
+++ b/deps/v8/src/version.cc
@@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 5
-#define BUILD_NUMBER 4
-#define PATCH_LEVEL 3
+#define BUILD_NUMBER 6
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/deps/v8/src/weakmap.js b/deps/v8/src/weakmap.js
index 15056c7f8..70210b98d 100644
--- a/deps/v8/src/weakmap.js
+++ b/deps/v8/src/weakmap.js
@@ -33,14 +33,13 @@ const $WeakMap = global.WeakMap;
// -------------------------------------------------------------------
-// Set the WeakMap function and constructor.
-%SetCode($WeakMap, function(x) {
+function WeakMapConstructor() {
if (%_IsConstructCall()) {
%WeakMapInitialize(this);
} else {
return new $WeakMap();
}
-});
+}
function WeakMapGet(key) {
@@ -82,6 +81,12 @@ function WeakMapDelete(key) {
// -------------------------------------------------------------------
function SetupWeakMap() {
+ // Setup the WeakMap constructor function.
+ %SetCode($WeakMap, WeakMapConstructor);
+
+ // Setup the WeakMap prototype object.
+ %FunctionSetPrototype($WeakMap, new $WeakMap());
+
// Setup the non-enumerable functions on the WeakMap prototype object.
InstallFunctionsOnHiddenPrototype($WeakMap.prototype, DONT_ENUM, $Array(
"get", WeakMapGet,
diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc
index 56fbf9a33..94ed0cb55 100644
--- a/deps/v8/src/x64/code-stubs-x64.cc
+++ b/deps/v8/src/x64/code-stubs-x64.cc
@@ -242,14 +242,14 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
}
// undefined -> false
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
+ CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
+ CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
+ CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
+ CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true
@@ -269,15 +269,16 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
if (types_.NeedsMap()) {
__ movq(map, FieldOperand(argument, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ testb(FieldOperand(map, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsUndetectable));
- // Undetectable -> false.
- Label not_undetectable;
- __ j(zero, &not_undetectable, Label::kNear);
- __ Set(tos_, 0);
- __ ret(1 * kPointerSize);
- __ bind(&not_undetectable);
+ if (types_.CanBeUndetectable()) {
+ __ testb(FieldOperand(map, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ // Undetectable -> false.
+ Label not_undetectable;
+ __ j(zero, &not_undetectable, Label::kNear);
+ __ Set(tos_, 0);
+ __ ret(1 * kPointerSize);
+ __ bind(&not_undetectable);
+ }
}
if (types_.Contains(SPEC_OBJECT)) {
@@ -285,13 +286,12 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
Label not_js_object;
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(below, &not_js_object, Label::kNear);
- __ Set(tos_, 1);
+ // argument contains the correct return value already.
+ if (!tos_.is(argument)) {
+ __ Set(tos_, 1);
+ }
__ ret(1 * kPointerSize);
__ bind(&not_js_object);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> patch.
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- __ j(above_equal, &patch, Label::kNear);
}
if (types_.Contains(STRING)) {
@@ -302,10 +302,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ movq(tos_, FieldOperand(argument, String::kLengthOffset));
__ ret(1 * kPointerSize); // the string length is OK as the return value
__ bind(&not_string);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> patch
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- __ j(below, &patch, Label::kNear);
}
if (types_.Contains(HEAP_NUMBER)) {
@@ -316,50 +312,42 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ xorps(xmm0, xmm0);
__ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset));
__ j(zero, &false_result, Label::kNear);
- __ Set(tos_, 1);
+ // argument contains the correct return value already.
+ if (!tos_.is(argument)) {
+ __ Set(tos_, 1);
+ }
__ ret(1 * kPointerSize);
__ bind(&false_result);
__ Set(tos_, 0);
__ ret(1 * kPointerSize);
__ bind(&not_heap_number);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> patch
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- __ j(equal, &patch, Label::kNear);
- }
-
- if (types_.Contains(INTERNAL_OBJECT)) {
- // internal objects -> true
- __ Set(tos_, 1);
- __ ret(1 * kPointerSize);
}
- if (!types_.IsAll()) {
- __ bind(&patch);
- GenerateTypeTransition(masm);
- }
+ __ bind(&patch);
+ GenerateTypeTransition(masm);
}
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
- bool result,
- Label* patch) {
+ bool result) {
const Register argument = rax;
if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_.
Label different_value;
__ CompareRoot(argument, value);
__ j(not_equal, &different_value, Label::kNear);
- __ Set(tos_, result ? 1 : 0);
+ if (!result) {
+ // If we have to return zero, there is no way around clearing tos_.
+ __ Set(tos_, 0);
+ } else if (!tos_.is(argument)) {
+ // If we have to return non-zero, we can re-use the argument if it is the
+ // same register as the result, because we never see Smi-zero here.
+ __ Set(tos_, 1);
+ }
__ ret(1 * kPointerSize);
__ bind(&different_value);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // If we see an unexpected oddball and handle internal objects, we must
- // patch because the code for internal objects doesn't handle it explictly.
- __ CompareRoot(argument, value);
- __ j(equal, patch);
}
}
diff --git a/deps/v8/src/x64/frames-x64.h b/deps/v8/src/x64/frames-x64.h
index b14267c82..7012c76f0 100644
--- a/deps/v8/src/x64/frames-x64.h
+++ b/deps/v8/src/x64/frames-x64.h
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -50,12 +50,13 @@ static const int kNumSafepointRegisters = 16;
class StackHandlerConstants : public AllStatic {
public:
- static const int kNextOffset = 0 * kPointerSize;
- static const int kFPOffset = 1 * kPointerSize;
- static const int kStateOffset = 2 * kPointerSize;
- static const int kPCOffset = 3 * kPointerSize;
+ static const int kNextOffset = 0 * kPointerSize;
+ static const int kContextOffset = 1 * kPointerSize;
+ static const int kFPOffset = 2 * kPointerSize;
+ static const int kStateOffset = 3 * kPointerSize;
+ static const int kPCOffset = 4 * kPointerSize;
- static const int kSize = 4 * kPointerSize;
+ static const int kSize = kPCOffset + kPointerSize;
};
diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc
index 0f7e5b3d7..d0c71be12 100644
--- a/deps/v8/src/x64/full-codegen-x64.cc
+++ b/deps/v8/src/x64/full-codegen-x64.cc
@@ -712,8 +712,10 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ push(rsi);
__ Push(variable->name());
// Declaration nodes are always introduced in one of two modes.
- ASSERT(mode == Variable::VAR || mode == Variable::CONST);
- PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
+ ASSERT(mode == Variable::VAR ||
+ mode == Variable::CONST ||
+ mode == Variable::LET);
+ PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
__ Push(Smi::FromInt(attr));
// Push initial value, if any.
// Note: For variables we must not push an initial value (such as
@@ -3971,6 +3973,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
__ j(equal, if_true);
__ CompareRoot(rax, Heap::kFalseValueRootIndex);
Split(equal, if_true, if_false, fall_through);
+ } else if (FLAG_harmony_typeof &&
+ check->Equals(isolate()->heap()->null_symbol())) {
+ __ CompareRoot(rax, Heap::kNullValueRootIndex);
+ Split(equal, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(equal, if_true);
@@ -3987,8 +3993,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Split(above_equal, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(rax, if_false);
- __ CompareRoot(rax, Heap::kNullValueRootIndex);
- __ j(equal, if_true);
+ if (!FLAG_harmony_typeof) {
+ __ CompareRoot(rax, Heap::kNullValueRootIndex);
+ __ j(equal, if_true);
+ }
__ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
__ j(below, if_false);
__ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc
index ce6a9105f..acbac44fc 100644
--- a/deps/v8/src/x64/lithium-codegen-x64.cc
+++ b/deps/v8/src/x64/lithium-codegen-x64.cc
@@ -1216,17 +1216,10 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
}
-void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
+void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
- __ movq(result, FieldOperand(array, FixedArray::kLengthOffset));
-}
-
-
-void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
- Register result = ToRegister(instr->result());
- Register array = ToRegister(instr->InputAt(0));
- __ movl(result, FieldOperand(array, ExternalPixelArray::kLengthOffset));
+ __ movq(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
}
@@ -1410,40 +1403,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
// undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen undefined for the first time -> deopt.
- __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// true -> true.
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ j(equal, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ CompareRoot(reg, Heap::kTrueValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
- }
-
- if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// false -> false.
__ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ CompareRoot(reg, Heap::kFalseValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex);
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen null for the first time -> deopt.
- __ CompareRoot(reg, Heap::kNullValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
}
if (expected.Contains(ToBooleanStub::SMI)) {
@@ -1460,21 +1432,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
const Register map = kScratchRegister;
if (expected.NeedsMap()) {
__ movq(map, FieldOperand(reg, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ testb(FieldOperand(map, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsUndetectable));
- // Undetectable -> false.
- __ j(not_zero, false_label);
+
+ if (expected.CanBeUndetectable()) {
+ // Undetectable -> false.
+ __ testb(FieldOperand(map, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ __ j(not_zero, false_label);
+ }
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true.
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(above_equal, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> deopt.
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- DeoptimizeIf(above_equal, instr->environment());
}
if (expected.Contains(ToBooleanStub::STRING)) {
@@ -1486,10 +1456,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ j(not_zero, true_label);
__ jmp(false_label);
__ bind(&not_string);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> deopt
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- DeoptimizeIf(below, instr->environment());
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@@ -1502,19 +1468,10 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ j(zero, false_label);
__ jmp(true_label);
__ bind(&not_heap_number);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> deopt.
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- DeoptimizeIf(equal, instr->environment());
}
- if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // internal objects -> true
- __ jmp(true_label);
- } else {
- // We've seen something for the first time -> deopt.
- DeoptimizeIf(no_condition, instr->environment());
- }
+ // We've seen something for the first time -> deopt.
+ DeoptimizeIf(no_condition, instr->environment());
}
}
}
@@ -2305,16 +2262,13 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
- Register elements = ToRegister(instr->elements());
- Register key = ToRegister(instr->key());
Register result = ToRegister(instr->result());
- ASSERT(result.is(elements));
// Load the result.
- __ movq(result, FieldOperand(elements,
- key,
- times_pointer_size,
- FixedArray::kHeaderSize));
+ __ movq(result,
+ BuildFastArrayOperand(instr->elements(), instr->key(),
+ JSObject::FAST_ELEMENTS,
+ FixedArray::kHeaderSize - kHeapObjectTag));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
@@ -2348,22 +2302,22 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Operand LCodeGen::BuildFastArrayOperand(
- LOperand* external_pointer,
+ LOperand* elements_pointer,
LOperand* key,
JSObject::ElementsKind elements_kind,
uint32_t offset) {
- Register external_pointer_reg = ToRegister(external_pointer);
+ Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) {
int constant_value = ToInteger32(LConstantOperand::cast(key));
if (constant_value & 0xF0000000) {
Abort("array index constant value too big");
}
- return Operand(external_pointer_reg,
+ return Operand(elements_pointer_reg,
constant_value * (1 << shift_size) + offset);
} else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
- return Operand(external_pointer_reg, ToRegister(key),
+ return Operand(elements_pointer_reg, ToRegister(key),
scale_factor, offset);
}
}
@@ -2759,6 +2713,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
+ Label done;
if (CpuFeatures::IsSupported(SSE4_1)) {
CpuFeatures::Scope scope(SSE4_1);
@@ -2773,13 +2728,20 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
__ cmpl(output_reg, Immediate(0x80000000));
DeoptimizeIf(equal, instr->environment());
} else {
+ // Deoptimize on negative inputs.
__ xorps(xmm_scratch, xmm_scratch); // Zero the register.
__ ucomisd(input_reg, xmm_scratch);
-
+ DeoptimizeIf(below, instr->environment());
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- DeoptimizeIf(below_equal, instr->environment());
- } else {
- DeoptimizeIf(below, instr->environment());
+ // Check for negative zero.
+ Label positive_sign;
+ __ j(above, &positive_sign, Label::kNear);
+ __ movmskpd(output_reg, input_reg);
+ __ testq(output_reg, Immediate(1));
+ DeoptimizeIf(not_zero, instr->environment());
+ __ Set(output_reg, 0);
+ __ jmp(&done);
+ __ bind(&positive_sign);
}
// Use truncating instruction (OK because input is positive).
@@ -2789,6 +2751,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
__ cmpl(output_reg, Immediate(0x80000000));
DeoptimizeIf(equal, instr->environment());
}
+ __ bind(&done);
}
@@ -3137,12 +3100,22 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
- if (instr->length()->IsRegister()) {
- __ cmpq(ToRegister(instr->index()), ToRegister(instr->length()));
+ if (instr->index()->IsConstantOperand()) {
+ if (instr->length()->IsRegister()) {
+ __ cmpq(ToRegister(instr->length()),
+ Immediate(ToInteger32(LConstantOperand::cast(instr->index()))));
+ } else {
+ __ cmpq(ToOperand(instr->length()),
+ Immediate(ToInteger32(LConstantOperand::cast(instr->index()))));
+ }
} else {
- __ cmpq(ToRegister(instr->index()), ToOperand(instr->length()));
+ if (instr->length()->IsRegister()) {
+ __ cmpq(ToRegister(instr->length()), ToRegister(instr->index()));
+ } else {
+ __ cmpq(ToOperand(instr->length()), ToRegister(instr->index()));
+ }
}
- DeoptimizeIf(above_equal, instr->environment());
+ DeoptimizeIf(below_equal, instr->environment());
}
@@ -4008,6 +3981,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
__ CompareRoot(input, Heap::kFalseValueRootIndex);
final_branch_condition = equal;
+ } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
+ __ CompareRoot(input, Heap::kNullValueRootIndex);
+ final_branch_condition = equal;
+
} else if (type_name->Equals(heap()->undefined_symbol())) {
__ CompareRoot(input, Heap::kUndefinedValueRootIndex);
__ j(equal, true_label);
@@ -4025,8 +4002,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
} else if (type_name->Equals(heap()->object_symbol())) {
__ JumpIfSmi(input, false_label);
- __ CompareRoot(input, Heap::kNullValueRootIndex);
- __ j(equal, true_label);
+ if (!FLAG_harmony_typeof) {
+ __ CompareRoot(input, Heap::kNullValueRootIndex);
+ __ j(equal, true_label);
+ }
__ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
__ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
diff --git a/deps/v8/src/x64/lithium-codegen-x64.h b/deps/v8/src/x64/lithium-codegen-x64.h
index d7c72b544..0622e9d28 100644
--- a/deps/v8/src/x64/lithium-codegen-x64.h
+++ b/deps/v8/src/x64/lithium-codegen-x64.h
@@ -216,7 +216,7 @@ class LCodeGen BASE_EMBEDDED {
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
Operand BuildFastArrayOperand(
- LOperand* external_pointer,
+ LOperand* elements_pointer,
LOperand* key,
JSObject::ElementsKind elements_kind,
uint32_t offset);
diff --git a/deps/v8/src/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc
index 7f4490f6d..9d08d3762 100644
--- a/deps/v8/src/x64/lithium-x64.cc
+++ b/deps/v8/src/x64/lithium-x64.cc
@@ -1036,11 +1036,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
: instr->SecondSuccessor();
return new LGoto(successor->block_id());
}
- LInstruction* branch = new LBranch(UseRegister(v));
- // When we handle all cases, we never deopt, so we don't need to assign the
- // environment then.
- bool all_cases_handled = instr->expected_input_types().IsAll();
- return all_cases_handled ? branch : AssignEnvironment(branch);
+ return AssignEnvironment(new LBranch(UseRegister(v)));
}
@@ -1502,16 +1498,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
-LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
+LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
+ HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LFixedArrayLength(array));
-}
-
-
-LInstruction* LChunkBuilder::DoExternalArrayLength(
- HExternalArrayLength* instr) {
- LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LExternalArrayLength(array));
+ return DefineAsRegister(new LFixedArrayBaseLength(array));
}
@@ -1529,8 +1519,9 @@ LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
- return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
- Use(instr->length())));
+ return AssignEnvironment(new LBoundsCheck(
+ UseRegisterOrConstantAtStart(instr->index()),
+ Use(instr->length())));
}
@@ -1829,9 +1820,9 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
ASSERT(instr->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* obj = UseRegisterAtStart(instr->object());
- LOperand* key = UseRegisterAtStart(instr->key());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
- return AssignEnvironment(DefineSameAsFirst(result));
+ return AssignEnvironment(DefineAsRegister(result));
}
diff --git a/deps/v8/src/x64/lithium-x64.h b/deps/v8/src/x64/lithium-x64.h
index 12bdfb28a..b570672f6 100644
--- a/deps/v8/src/x64/lithium-x64.h
+++ b/deps/v8/src/x64/lithium-x64.h
@@ -92,8 +92,7 @@ class LCodeGen;
V(DivI) \
V(DoubleToI) \
V(ElementsKind) \
- V(ExternalArrayLength) \
- V(FixedArrayLength) \
+ V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
@@ -913,25 +912,15 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
};
-class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
+class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LExternalArrayLength(LOperand* value) {
+ explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value;
}
- DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
- DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
-};
-
-
-class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LFixedArrayLength(LOperand* value) {
- inputs_[0] = value;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
- DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
+ DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
+ "fixed-array-base-length")
+ DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
};
@@ -2135,14 +2124,18 @@ class LChunkBuilder BASE_EMBEDDED {
template<int I, int T>
LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr,
XMMRegister reg);
+ // Assigns an environment to an instruction. An instruction which can
+ // deoptimize must have an environment.
LInstruction* AssignEnvironment(LInstruction* instr);
+ // Assigns a pointer map to an instruction. An instruction which can
+ // trigger a GC or a lazy deoptimization must have a pointer map.
LInstruction* AssignPointerMap(LInstruction* instr);
enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
- // By default we assume that instruction sequences generated for calls
- // cannot deoptimize eagerly and we do not attach environment to this
- // instruction.
+ // Marks a call for the register allocator. Assigns a pointer map to
+ // support GC and lazy deoptimization. Assigns an environment to support
+ // eager deoptimization if CAN_DEOPTIMIZE_EAGERLY.
LInstruction* MarkAsCall(
LInstruction* instr,
HInstruction* hinstr,
diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc
index 2b15553f1..e4a76270a 100644
--- a/deps/v8/src/x64/macro-assembler-x64.cc
+++ b/deps/v8/src/x64/macro-assembler-x64.cc
@@ -2387,18 +2387,15 @@ Operand MacroAssembler::SafepointRegisterSlot(Register reg) {
void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) {
// Adjust this code if not the case.
- ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// The pc (return address) is already on TOS. This code pushes state,
- // frame pointer and current handler. Check that they are expected
- // next on the stack, in that order.
- ASSERT_EQ(StackHandlerConstants::kStateOffset,
- StackHandlerConstants::kPCOffset - kPointerSize);
- ASSERT_EQ(StackHandlerConstants::kFPOffset,
- StackHandlerConstants::kStateOffset - kPointerSize);
- ASSERT_EQ(StackHandlerConstants::kNextOffset,
- StackHandlerConstants::kFPOffset - kPointerSize);
-
+ // frame pointer, context, and current handler.
if (try_location == IN_JAVASCRIPT) {
if (type == TRY_CATCH_HANDLER) {
push(Immediate(StackHandler::TRY_CATCH));
@@ -2406,6 +2403,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
push(Immediate(StackHandler::TRY_FINALLY));
}
push(rbp);
+ push(rsi);
} else {
ASSERT(try_location == IN_JS_ENTRY);
// The frame pointer does not point to a JS frame so we save NULL
@@ -2413,6 +2411,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
// before dereferencing it to restore the context.
push(Immediate(StackHandler::ENTRY));
push(Immediate(0)); // NULL frame pointer.
+ Push(Smi::FromInt(0)); // No context.
}
// Save the current handler.
Operand handler_operand =
@@ -2435,12 +2434,13 @@ void MacroAssembler::PopTryHandler() {
void MacroAssembler::Throw(Register value) {
- // Check that stack should contain next handler, frame pointer, state and
- // return address in that order.
- STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize ==
- StackHandlerConstants::kStateOffset);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize ==
- StackHandlerConstants::kPCOffset);
+ // Adjust this code if not the case.
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// Keep thrown value in rax.
if (!value.is(rax)) {
movq(rax, value);
@@ -2451,23 +2451,32 @@ void MacroAssembler::Throw(Register value) {
movq(rsp, handler_operand);
// get next in chain
pop(handler_operand);
- pop(rbp); // pop frame pointer
- pop(rdx); // remove state
+ pop(rsi); // Context.
+ pop(rbp); // Frame pointer.
+ pop(rdx); // State.
- // Before returning we restore the context from the frame pointer if not NULL.
- // The frame pointer is NULL in the exception handler of a JS entry frame.
- Set(rsi, 0); // Tentatively set context pointer to NULL
+ // If the handler is a JS frame, restore the context to the frame.
+ // (rdx == ENTRY) == (rbp == 0) == (rsi == 0), so we could test any
+ // of them.
Label skip;
- cmpq(rbp, Immediate(0));
+ cmpq(rdx, Immediate(StackHandler::ENTRY));
j(equal, &skip, Label::kNear);
- movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
bind(&skip);
+
ret(0);
}
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) {
+ // Adjust this code if not the case.
+ STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// Keep thrown value in rax.
if (!value.is(rax)) {
movq(rax, value);
@@ -2507,19 +2516,13 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Store(pending_exception, rax);
}
- // Clear the context pointer.
+ // Discard the context saved in the handler and clear the context pointer.
+ pop(rdx);
Set(rsi, 0);
- // Restore registers from handler.
- STATIC_ASSERT(StackHandlerConstants::kNextOffset + kPointerSize ==
- StackHandlerConstants::kFPOffset);
- pop(rbp); // FP
- STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize ==
- StackHandlerConstants::kStateOffset);
- pop(rdx); // State
+ pop(rbp); // Restore frame pointer.
+ pop(rdx); // Discard state.
- STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize ==
- StackHandlerConstants::kPCOffset);
ret(0);
}
diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc
index e195aecc3..cfd19bf14 100644
--- a/deps/v8/src/x64/stub-cache-x64.cc
+++ b/deps/v8/src/x64/stub-cache-x64.cc
@@ -3244,7 +3244,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// Check that the index is in range.
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ SmiToInteger32(rcx, rax);
- __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
+ __ cmpq(rax, FieldOperand(rbx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &miss_force_generic);
@@ -3379,7 +3379,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Check that the index is in range.
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ SmiToInteger32(rdi, rcx); // Untag the index.
- __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset));
+ __ cmpq(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &miss_force_generic);
diff --git a/deps/v8/src/zone.cc b/deps/v8/src/zone.cc
index 42ce8c5cb..7574778f5 100644
--- a/deps/v8/src/zone.cc
+++ b/deps/v8/src/zone.cc
@@ -34,24 +34,6 @@ namespace v8 {
namespace internal {
-Zone::Zone()
- : zone_excess_limit_(256 * MB),
- segment_bytes_allocated_(0),
- position_(0),
- limit_(0),
- scope_nesting_(0),
- segment_head_(NULL) {
-}
-unsigned Zone::allocation_size_ = 0;
-
-
-ZoneScope::~ZoneScope() {
- ASSERT_EQ(Isolate::Current(), isolate_);
- if (ShouldDeleteOnExit()) isolate_->zone()->DeleteAll();
- isolate_->zone()->scope_nesting_--;
-}
-
-
// Segments represent chunks of memory: They have starting address
// (encoded in the this pointer) and a size in bytes. Segments are
// chained together forming a LIFO structure with the newest segment
@@ -60,6 +42,11 @@ ZoneScope::~ZoneScope() {
class Segment {
public:
+ void Initialize(Segment* next, int size) {
+ next_ = next;
+ size_ = size;
+ }
+
Segment* next() const { return next_; }
void clear_next() { next_ = NULL; }
@@ -77,19 +64,33 @@ class Segment {
Segment* next_;
int size_;
-
- friend class Zone;
};
+Zone::Zone()
+ : zone_excess_limit_(256 * MB),
+ segment_bytes_allocated_(0),
+ position_(0),
+ limit_(0),
+ scope_nesting_(0),
+ segment_head_(NULL) {
+}
+unsigned Zone::allocation_size_ = 0;
+
+ZoneScope::~ZoneScope() {
+ ASSERT_EQ(Isolate::Current(), isolate_);
+ if (ShouldDeleteOnExit()) isolate_->zone()->DeleteAll();
+ isolate_->zone()->scope_nesting_--;
+}
+
+
// Creates a new segment, sets it size, and pushes it to the front
// of the segment chain. Returns the new segment.
Segment* Zone::NewSegment(int size) {
Segment* result = reinterpret_cast<Segment*>(Malloced::New(size));
adjust_segment_bytes_allocated(size);
if (result != NULL) {
- result->next_ = segment_head_;
- result->size_ = size;
+ result->Initialize(segment_head_, size);
segment_head_ = result;
}
return result;
@@ -155,6 +156,14 @@ void Zone::DeleteAll() {
}
+void Zone::DeleteKeptSegment() {
+ if (segment_head_ != NULL) {
+ DeleteSegment(segment_head_, segment_head_->size());
+ segment_head_ = NULL;
+ }
+}
+
+
Address Zone::NewExpand(int size) {
// Make sure the requested size is already properly aligned and that
// there isn't enough room in the Zone to satisfy the request.
diff --git a/deps/v8/src/zone.h b/deps/v8/src/zone.h
index abb53ad46..faad3b7cc 100644
--- a/deps/v8/src/zone.h
+++ b/deps/v8/src/zone.h
@@ -65,9 +65,13 @@ class Zone {
template <typename T>
inline T* NewArray(int length);
- // Delete all objects and free all memory allocated in the Zone.
+ // Deletes all objects and free all memory allocated in the Zone. Keeps one
+ // small (size <= kMaximumKeptSegmentSize) segment around if it finds one.
void DeleteAll();
+ // Deletes the last small segment kept around by DeleteAll().
+ void DeleteKeptSegment();
+
// Returns true if more memory has been allocated in zones than
// the limit allows.
inline bool excess_allocation();
diff --git a/deps/v8/test/cctest/test-accessors.cc b/deps/v8/test/cctest/test-accessors.cc
index 028f82f3d..d95536d2d 100644
--- a/deps/v8/test/cctest/test-accessors.cc
+++ b/deps/v8/test/cctest/test-accessors.cc
@@ -44,8 +44,6 @@ using ::v8::Function;
using ::v8::AccessorInfo;
using ::v8::Extension;
-namespace i = ::v8::internal;
-
static v8::Handle<Value> handle_property(Local<String> name,
const AccessorInfo&) {
ApiTestFuzzer::Fuzz();
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc
index c694ae38a..d5e17b89a 100644
--- a/deps/v8/test/cctest/test-api.cc
+++ b/deps/v8/test/cctest/test-api.cc
@@ -72,8 +72,6 @@ using ::v8::Undefined;
using ::v8::V8;
using ::v8::Value;
-namespace i = ::i;
-
static void ExpectString(const char* code, const char* expected) {
Local<Value> result = CompileRun(code);
@@ -331,16 +329,14 @@ static uint16_t* AsciiToTwoByteString(const char* source) {
class TestResource: public String::ExternalStringResource {
public:
- static int dispose_count;
-
- explicit TestResource(uint16_t* data)
- : data_(data), length_(0) {
+ explicit TestResource(uint16_t* data, int* counter = NULL)
+ : data_(data), length_(0), counter_(counter) {
while (data[length_]) ++length_;
}
~TestResource() {
i::DeleteArray(data_);
- ++dispose_count;
+ if (counter_ != NULL) ++*counter_;
}
const uint16_t* data() const {
@@ -353,23 +349,18 @@ class TestResource: public String::ExternalStringResource {
private:
uint16_t* data_;
size_t length_;
+ int* counter_;
};
-int TestResource::dispose_count = 0;
-
-
class TestAsciiResource: public String::ExternalAsciiStringResource {
public:
- static int dispose_count;
-
- explicit TestAsciiResource(const char* data)
- : data_(data),
- length_(strlen(data)) { }
+ explicit TestAsciiResource(const char* data, int* counter = NULL)
+ : data_(data), length_(strlen(data)), counter_(counter) { }
~TestAsciiResource() {
i::DeleteArray(data_);
- ++dispose_count;
+ if (counter_ != NULL) ++*counter_;
}
const char* data() const {
@@ -382,20 +373,18 @@ class TestAsciiResource: public String::ExternalAsciiStringResource {
private:
const char* data_;
size_t length_;
+ int* counter_;
};
-int TestAsciiResource::dispose_count = 0;
-
-
THREADED_TEST(ScriptUsingStringResource) {
- TestResource::dispose_count = 0;
+ int dispose_count = 0;
const char* c_source = "1 + 2 * 3";
uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
{
v8::HandleScope scope;
LocalContext env;
- TestResource* resource = new TestResource(two_byte_source);
+ TestResource* resource = new TestResource(two_byte_source, &dispose_count);
Local<String> source = String::NewExternal(resource);
Local<Script> script = Script::Compile(source);
Local<Value> value = script->Run();
@@ -405,37 +394,38 @@ THREADED_TEST(ScriptUsingStringResource) {
CHECK_EQ(resource,
static_cast<TestResource*>(source->GetExternalStringResource()));
HEAP->CollectAllGarbage(false);
- CHECK_EQ(0, TestResource::dispose_count);
+ CHECK_EQ(0, dispose_count);
}
v8::internal::Isolate::Current()->compilation_cache()->Clear();
HEAP->CollectAllGarbage(false);
- CHECK_EQ(1, TestResource::dispose_count);
+ CHECK_EQ(1, dispose_count);
}
THREADED_TEST(ScriptUsingAsciiStringResource) {
- TestAsciiResource::dispose_count = 0;
+ int dispose_count = 0;
const char* c_source = "1 + 2 * 3";
{
v8::HandleScope scope;
LocalContext env;
Local<String> source =
- String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
+ String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
+ &dispose_count));
Local<Script> script = Script::Compile(source);
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
HEAP->CollectAllGarbage(false);
- CHECK_EQ(0, TestAsciiResource::dispose_count);
+ CHECK_EQ(0, dispose_count);
}
i::Isolate::Current()->compilation_cache()->Clear();
HEAP->CollectAllGarbage(false);
- CHECK_EQ(1, TestAsciiResource::dispose_count);
+ CHECK_EQ(1, dispose_count);
}
THREADED_TEST(ScriptMakingExternalString) {
- TestResource::dispose_count = 0;
+ int dispose_count = 0;
uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
{
v8::HandleScope scope;
@@ -444,23 +434,24 @@ THREADED_TEST(ScriptMakingExternalString) {
// Trigger GCs so that the newly allocated string moves to old gen.
HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
- bool success = source->MakeExternal(new TestResource(two_byte_source));
+ bool success = source->MakeExternal(new TestResource(two_byte_source,
+ &dispose_count));
CHECK(success);
Local<Script> script = Script::Compile(source);
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
HEAP->CollectAllGarbage(false);
- CHECK_EQ(0, TestResource::dispose_count);
+ CHECK_EQ(0, dispose_count);
}
i::Isolate::Current()->compilation_cache()->Clear();
HEAP->CollectAllGarbage(false);
- CHECK_EQ(1, TestResource::dispose_count);
+ CHECK_EQ(1, dispose_count);
}
THREADED_TEST(ScriptMakingExternalAsciiString) {
- TestAsciiResource::dispose_count = 0;
+ int dispose_count = 0;
const char* c_source = "1 + 2 * 3";
{
v8::HandleScope scope;
@@ -470,18 +461,18 @@ THREADED_TEST(ScriptMakingExternalAsciiString) {
HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
bool success = source->MakeExternal(
- new TestAsciiResource(i::StrDup(c_source)));
+ new TestAsciiResource(i::StrDup(c_source), &dispose_count));
CHECK(success);
Local<Script> script = Script::Compile(source);
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
HEAP->CollectAllGarbage(false);
- CHECK_EQ(0, TestAsciiResource::dispose_count);
+ CHECK_EQ(0, dispose_count);
}
i::Isolate::Current()->compilation_cache()->Clear();
HEAP->CollectAllGarbage(false);
- CHECK_EQ(1, TestAsciiResource::dispose_count);
+ CHECK_EQ(1, dispose_count);
}
@@ -605,49 +596,52 @@ THREADED_TEST(UsingExternalAsciiString) {
THREADED_TEST(ScavengeExternalString) {
- TestResource::dispose_count = 0;
+ int dispose_count = 0;
bool in_new_space = false;
{
v8::HandleScope scope;
uint16_t* two_byte_string = AsciiToTwoByteString("test string");
Local<String> string =
- String::NewExternal(new TestResource(two_byte_string));
+ String::NewExternal(new TestResource(two_byte_string,
+ &dispose_count));
i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
HEAP->CollectGarbage(i::NEW_SPACE);
in_new_space = HEAP->InNewSpace(*istring);
CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
- CHECK_EQ(0, TestResource::dispose_count);
+ CHECK_EQ(0, dispose_count);
}
HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
- CHECK_EQ(1, TestResource::dispose_count);
+ CHECK_EQ(1, dispose_count);
}
THREADED_TEST(ScavengeExternalAsciiString) {
- TestAsciiResource::dispose_count = 0;
+ int dispose_count = 0;
bool in_new_space = false;
{
v8::HandleScope scope;
const char* one_byte_string = "test string";
Local<String> string = String::NewExternal(
- new TestAsciiResource(i::StrDup(one_byte_string)));
+ new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
HEAP->CollectGarbage(i::NEW_SPACE);
in_new_space = HEAP->InNewSpace(*istring);
CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
- CHECK_EQ(0, TestAsciiResource::dispose_count);
+ CHECK_EQ(0, dispose_count);
}
HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
- CHECK_EQ(1, TestAsciiResource::dispose_count);
+ CHECK_EQ(1, dispose_count);
}
class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
public:
+ // Only used by non-threaded tests, so it can use static fields.
static int dispose_calls;
+ static int dispose_count;
TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
- : TestAsciiResource(data),
+ : TestAsciiResource(data, &dispose_count),
dispose_(dispose) { }
void Dispose() {
@@ -659,6 +653,7 @@ class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
};
+int TestAsciiResourceWithDisposeControl::dispose_count = 0;
int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
@@ -666,7 +661,7 @@ TEST(ExternalStringWithDisposeHandling) {
const char* c_source = "1 + 2 * 3";
// Use a stack allocated external string resource allocated object.
- TestAsciiResource::dispose_count = 0;
+ TestAsciiResourceWithDisposeControl::dispose_count = 0;
TestAsciiResourceWithDisposeControl::dispose_calls = 0;
TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
{
@@ -678,15 +673,15 @@ TEST(ExternalStringWithDisposeHandling) {
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
HEAP->CollectAllGarbage(false);
- CHECK_EQ(0, TestAsciiResource::dispose_count);
+ CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
}
i::Isolate::Current()->compilation_cache()->Clear();
HEAP->CollectAllGarbage(false);
CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
- CHECK_EQ(0, TestAsciiResource::dispose_count);
+ CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
// Use a heap allocated external string resource allocated object.
- TestAsciiResource::dispose_count = 0;
+ TestAsciiResourceWithDisposeControl::dispose_count = 0;
TestAsciiResourceWithDisposeControl::dispose_calls = 0;
TestAsciiResource* res_heap =
new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
@@ -699,12 +694,12 @@ TEST(ExternalStringWithDisposeHandling) {
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
HEAP->CollectAllGarbage(false);
- CHECK_EQ(0, TestAsciiResource::dispose_count);
+ CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
}
i::Isolate::Current()->compilation_cache()->Clear();
HEAP->CollectAllGarbage(false);
CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
- CHECK_EQ(1, TestAsciiResource::dispose_count);
+ CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
}
@@ -14595,6 +14590,24 @@ THREADED_TEST(CreationContext) {
}
+THREADED_TEST(CreationContextOfJsFunction) {
+ HandleScope handle_scope;
+ Persistent<Context> context = Context::New();
+ InstallContextId(context, 1);
+
+ Local<Object> function;
+ {
+ Context::Scope scope(context);
+ function = CompileRun("function foo() {}; foo").As<Object>();
+ }
+
+ CHECK(function->CreationContext() == context);
+ CheckContextId(function, 1);
+
+ context.Dispose();
+}
+
+
Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
const AccessorInfo& info) {
if (index == 42) return v8_str("yes");
diff --git a/deps/v8/test/cctest/test-circular-queue.cc b/deps/v8/test/cctest/test-circular-queue.cc
index c4e5c4c24..2861b1f76 100644
--- a/deps/v8/test/cctest/test-circular-queue.cc
+++ b/deps/v8/test/cctest/test-circular-queue.cc
@@ -6,8 +6,6 @@
#include "circular-queue-inl.h"
#include "cctest.h"
-namespace i = v8::internal;
-
using i::SamplingCircularQueue;
diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc
index 9ff2a171a..81c487da8 100644
--- a/deps/v8/test/cctest/test-cpu-profiler.cc
+++ b/deps/v8/test/cctest/test-cpu-profiler.cc
@@ -7,8 +7,6 @@
#include "cctest.h"
#include "../include/v8-profiler.h"
-namespace i = v8::internal;
-
using i::CodeEntry;
using i::CpuProfile;
using i::CpuProfiler;
diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc
index 8675a0146..169e6dcbd 100644
--- a/deps/v8/test/cctest/test-heap-profiler.cc
+++ b/deps/v8/test/cctest/test-heap-profiler.cc
@@ -10,8 +10,6 @@
#include "utils-inl.h"
#include "../include/v8-profiler.h"
-namespace i = v8::internal;
-
namespace {
class NamedEntriesDetector {
diff --git a/deps/v8/test/cctest/test-lockers.cc b/deps/v8/test/cctest/test-lockers.cc
index 2b184e913..d61fde250 100644
--- a/deps/v8/test/cctest/test-lockers.cc
+++ b/deps/v8/test/cctest/test-lockers.cc
@@ -54,10 +54,6 @@ using ::v8::String;
using ::v8::Value;
using ::v8::V8;
-namespace i = ::i;
-
-
-
// Migrating an isolate
class KangarooThread : public v8::internal::Thread {
diff --git a/deps/v8/test/cctest/test-log-stack-tracer.cc b/deps/v8/test/cctest/test-log-stack-tracer.cc
index 2bcb3fe0b..f536e6b19 100644
--- a/deps/v8/test/cctest/test-log-stack-tracer.cc
+++ b/deps/v8/test/cctest/test-log-stack-tracer.cc
@@ -54,8 +54,6 @@ using v8::internal::JSFunction;
using v8::internal::StackTracer;
using v8::internal::TickSample;
-namespace i = v8::internal;
-
static v8::Persistent<v8::Context> env;
diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc
index 262e7bb50..dfbc733e0 100644
--- a/deps/v8/test/cctest/test-log.cc
+++ b/deps/v8/test/cctest/test-log.cc
@@ -23,8 +23,6 @@ using v8::internal::EmbeddedVector;
using v8::internal::Logger;
using v8::internal::StrLength;
-namespace i = v8::internal;
-
namespace {
class ScopedLoggerInitializer {
diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc
index fe738768d..8b6afdc59 100755
--- a/deps/v8/test/cctest/test-parsing.cc
+++ b/deps/v8/test/cctest/test-parsing.cc
@@ -40,8 +40,6 @@
#include "preparser.h"
#include "cctest.h"
-namespace i = ::v8::internal;
-
TEST(ScanKeywords) {
struct KeywordToken {
const char* keyword;
@@ -66,6 +64,8 @@ TEST(ScanKeywords) {
{
i::Utf8ToUC16CharacterStream stream(keyword, length);
i::JavaScriptScanner scanner(&unicode_cache);
+ // The scanner should parse 'let' as Token::LET for this test.
+ scanner.SetHarmonyBlockScoping(true);
scanner.Initialize(&stream);
CHECK_EQ(key_token.token, scanner.Next());
CHECK_EQ(i::Token::EOS, scanner.Next());
@@ -289,7 +289,7 @@ TEST(RegressChromium62639) {
i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(program),
static_cast<unsigned>(strlen(program)));
i::ScriptDataImpl* data =
- i::ParserApi::PreParse(&stream, NULL);
+ i::ParserApi::PreParse(&stream, NULL, false);
CHECK(data->HasError());
delete data;
}
@@ -313,7 +313,7 @@ TEST(Regress928) {
i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(program),
static_cast<unsigned>(strlen(program)));
i::ScriptDataImpl* data =
- i::ParserApi::PartialPreParse(&stream, NULL);
+ i::ParserApi::PartialPreParse(&stream, NULL, false);
CHECK(!data->HasError());
data->Initialize();
diff --git a/deps/v8/test/cctest/test-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc
index 6d3044317..250ebd4a5 100644
--- a/deps/v8/test/cctest/test-profile-generator.cc
+++ b/deps/v8/test/cctest/test-profile-generator.cc
@@ -7,8 +7,6 @@
#include "cctest.h"
#include "../include/v8-profiler.h"
-namespace i = v8::internal;
-
using i::CodeEntry;
using i::CodeMap;
using i::CpuProfile;
diff --git a/deps/v8/test/cctest/test-unbound-queue.cc b/deps/v8/test/cctest/test-unbound-queue.cc
index df5509ef8..3dc87ae24 100644
--- a/deps/v8/test/cctest/test-unbound-queue.cc
+++ b/deps/v8/test/cctest/test-unbound-queue.cc
@@ -6,8 +6,6 @@
#include "unbound-queue-inl.h"
#include "cctest.h"
-namespace i = v8::internal;
-
using i::UnboundQueue;
diff --git a/deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js b/deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js
new file mode 100644
index 000000000..a407c531a
--- /dev/null
+++ b/deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js
@@ -0,0 +1,224 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug --harmony-block-scoping
+// The functions used for testing backtraces. They are at the top to make the
+// testing of source line/column easier.
+
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug;
+
+var test_name;
+var listener_delegate;
+var listener_called;
+var exception;
+var begin_test_count = 0;
+var end_test_count = 0;
+var break_count = 0;
+
+
+// Debug event listener which delegates.
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ break_count++;
+ listener_called = true;
+ listener_delegate(exec_state);
+ }
+ } catch (e) {
+ exception = e;
+ }
+}
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+
+// Initialize for a new test.
+function BeginTest(name) {
+ test_name = name;
+ listener_delegate = null;
+ listener_called = false;
+ exception = null;
+ begin_test_count++;
+}
+
+
+// Check result of a test.
+function EndTest() {
+ assertTrue(listener_called, "listerner not called for " + test_name);
+ assertNull(exception, test_name);
+ end_test_count++;
+}
+
+
+// Check that the scope chain contains the expected types of scopes.
+function CheckScopeChain(scopes, exec_state) {
+ assertEquals(scopes.length, exec_state.frame().scopeCount());
+ for (var i = 0; i < scopes.length; i++) {
+ var scope = exec_state.frame().scope(i);
+ assertTrue(scope.isScope());
+ assertEquals(scopes[i], scope.scopeType());
+
+ // Check the global object when hitting the global scope.
+ if (scopes[i] == debug.ScopeType.Global) {
+ // Objects don't have same class (one is "global", other is "Object",
+ // so just check the properties directly.
+ assertPropertiesEqual(this, scope.scopeObject().value());
+ }
+ }
+
+ // Get the debug command processor.
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
+
+ // Send a scopes request and check the result.
+ var json;
+ var request_json = '{"seq":0,"type":"request","command":"scopes"}';
+ var response_json = dcp.processDebugJSONRequest(request_json);
+ var response = JSON.parse(response_json);
+ assertEquals(scopes.length, response.body.scopes.length);
+ for (var i = 0; i < scopes.length; i++) {
+ assertEquals(i, response.body.scopes[i].index);
+ assertEquals(scopes[i], response.body.scopes[i].type);
+ if (scopes[i] == debug.ScopeType.Local ||
+ scopes[i] == debug.ScopeType.Closure) {
+ assertTrue(response.body.scopes[i].object.ref < 0);
+ } else {
+ assertTrue(response.body.scopes[i].object.ref >= 0);
+ }
+ var found = false;
+ for (var j = 0; j < response.refs.length && !found; j++) {
+ found = response.refs[j].handle == response.body.scopes[i].object.ref;
+ }
+ assertTrue(found, "Scope object " + response.body.scopes[i].object.ref + " not found");
+ }
+}
+
+// Check that the content of the scope is as expected. For functions just check
+// that there is a function.
+function CheckScopeContent(content, number, exec_state) {
+ var scope = exec_state.frame().scope(number);
+ var count = 0;
+ for (var p in content) {
+ var property_mirror = scope.scopeObject().property(p);
+ if (property_mirror.isUndefined()) {
+ print('property ' + p + ' not found in scope');
+ }
+ assertFalse(property_mirror.isUndefined(), 'property ' + p + ' not found in scope');
+ if (typeof(content[p]) === 'function') {
+ assertTrue(property_mirror.value().isFunction());
+ } else {
+ assertEquals(content[p], property_mirror.value().value(), 'property ' + p + ' has unexpected value');
+ }
+ count++;
+ }
+
+ // 'arguments' and might be exposed in the local and closure scope. Just
+ // ignore this.
+ var scope_size = scope.scopeObject().properties().length;
+ if (!scope.scopeObject().property('arguments').isUndefined()) {
+ scope_size--;
+ }
+ // Also ignore synthetic variable from catch block.
+ if (!scope.scopeObject().property('.catch-var').isUndefined()) {
+ scope_size--;
+ }
+ // Skip property with empty name.
+ if (!scope.scopeObject().property('').isUndefined()) {
+ scope_size--;
+ }
+ // Also ignore synthetic variable from block scopes.
+ if (!scope.scopeObject().property('.block').isUndefined()) {
+ scope_size--;
+ }
+
+ if (count != scope_size) {
+ print('Names found in scope:');
+ var names = scope.scopeObject().propertyNames();
+ for (var i = 0; i < names.length; i++) {
+ print(names[i]);
+ }
+ }
+ assertEquals(count, scope_size);
+
+ // Get the debug command processor.
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
+
+ // Send a scope request for information on a single scope and check the
+ // result.
+ var request_json = '{"seq":0,"type":"request","command":"scope","arguments":{"number":';
+ request_json += scope.scopeIndex();
+ request_json += '}}';
+ var response_json = dcp.processDebugJSONRequest(request_json);
+ var response = JSON.parse(response_json);
+ assertEquals(scope.scopeType(), response.body.type);
+ assertEquals(number, response.body.index);
+ if (scope.scopeType() == debug.ScopeType.Local ||
+ scope.scopeType() == debug.ScopeType.Closure) {
+ assertTrue(response.body.object.ref < 0);
+ } else {
+ assertTrue(response.body.object.ref >= 0);
+ }
+ var found = false;
+ for (var i = 0; i < response.refs.length && !found; i++) {
+ found = response.refs[i].handle == response.body.object.ref;
+ }
+ assertTrue(found, "Scope object " + response.body.object.ref + " not found");
+}
+
+
+// Simple closure formed by returning an inner function referering to an outer
+// block local variable and an outer function's parameter. Due to VM
+// optimizations parts of the actual closure is missing from the debugger
+// information.
+BeginTest("Closure 1");
+
+function closure_1(a) {
+ var x = 2;
+ let y = 3;
+ if (true) {
+ let z = 4;
+ function f() {
+ debugger;
+ return a + x + y + z;
+ };
+ return f;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Local,
+ debug.ScopeType.Block,
+ debug.ScopeType.Closure,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({}, 0, exec_state);
+ CheckScopeContent({z:4}, 1, exec_state);
+ CheckScopeContent({a:1,x:2,y:3}, 2, exec_state);
+};
+closure_1(1)();
+EndTest();
diff --git a/deps/v8/test/mjsunit/external-array.js b/deps/v8/test/mjsunit/external-array.js
index 94105ec9d..d7e9de029 100644
--- a/deps/v8/test/mjsunit/external-array.js
+++ b/deps/v8/test/mjsunit/external-array.js
@@ -190,9 +190,19 @@ function run_test(test_func, array, expected_result) {
gc(); // Makes V8 forget about type information for test_func.
}
+function run_bounds_test(test_func, array, expected_result) {
+ assertEquals(undefined, a[kElementCount]);
+ a[kElementCount] = 456;
+ assertEquals(undefined, a[kElementCount]);
+ assertEquals(undefined, a[kElementCount+1]);
+ a[kElementCount+1] = 456;
+ assertEquals(undefined, a[kElementCount+1]);
+}
+
for (var t = 0; t < types.length; t++) {
var type = types[t];
var a = new type(kElementCount);
+
for (var i = 0; i < kElementCount; i++) {
a[i] = i;
}
@@ -220,6 +230,16 @@ for (var t = 0; t < types.length; t++) {
assertTrue(delete a.length);
a.length = 2;
assertEquals(2, a.length);
+
+ // Make sure bounds checks are handled correctly for external arrays.
+ run_bounds_test(a);
+ run_bounds_test(a);
+ run_bounds_test(a);
+ %OptimizeFunctionOnNextCall(run_bounds_test);
+ run_bounds_test(a);
+ %DeoptimizeFunction(run_bounds_test);
+ gc(); // Makes V8 forget about type information for test_func.
+
}
function array_load_set_smi_check(a) {
diff --git a/deps/v8/test/mjsunit/fuzz-natives.js b/deps/v8/test/mjsunit/fuzz-natives.js
index ffa92684d..f8f0a28e7 100644
--- a/deps/v8/test/mjsunit/fuzz-natives.js
+++ b/deps/v8/test/mjsunit/fuzz-natives.js
@@ -146,6 +146,7 @@ var knownProblems = {
"NewStrictArgumentsFast": true,
"PushWithContext": true,
"PushCatchContext": true,
+ "PushBlockContext": true,
"LazyCompile": true,
"LazyRecompile": true,
"NotifyDeoptimized": true,
diff --git a/deps/v8/test/mjsunit/harmony/block-lazy-compile.js b/deps/v8/test/mjsunit/harmony/block-lazy-compile.js
new file mode 100644
index 000000000..a6efcbfd1
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/block-lazy-compile.js
@@ -0,0 +1,50 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+// Test deserialization of block contexts during lazy compilation
+// of closures.
+
+function f() {
+ var g;
+ {
+ // TODO(keuchel): introduce let
+ var x = 0;
+ g = function () {
+ x = x + 1;
+ return x;
+ }
+ }
+ return g;
+}
+
+var o = f();
+assertEquals(1, o());
+assertEquals(2, o());
+assertEquals(3, o());
+%OptimizeFunctionOnNextCall(o);
+assertEquals(4, o());
diff --git a/deps/v8/test/mjsunit/harmony/block-let-declaration.js b/deps/v8/test/mjsunit/harmony/block-let-declaration.js
new file mode 100644
index 000000000..19c943f14
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/block-let-declaration.js
@@ -0,0 +1,67 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-block-scoping
+
+// Test let declarations in various settings.
+
+// Global
+let x;
+let y = 2;
+
+// Block local
+{
+ let y;
+ let x = 3;
+}
+
+assertEquals(undefined, x);
+assertEquals(2,y);
+
+if (true) {
+ let y;
+ assertEquals(undefined, y);
+}
+
+function TestLocalThrows(str, expect) {
+ assertThrows("(function(){" + str + "})()", expect);
+}
+
+function TestLocalDoesNotThrow(str) {
+ assertDoesNotThrow("(function(){" + str + "})()");
+}
+
+// Unprotected statement
+TestLocalThrows("if (true) let x;", SyntaxError);
+TestLocalThrows("with ({}) let x;", SyntaxError);
+TestLocalThrows("do let x; while (false)", SyntaxError);
+TestLocalThrows("while (false) let x;", SyntaxError);
+
+TestLocalDoesNotThrow("if (true) var x;");
+TestLocalDoesNotThrow("with ({}) var x;");
+TestLocalDoesNotThrow("do var x; while (false)");
+TestLocalDoesNotThrow("while (false) var x;");
diff --git a/deps/v8/test/mjsunit/harmony/block-scoping.js b/deps/v8/test/mjsunit/harmony/block-scoping.js
new file mode 100644
index 000000000..266e38072
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/block-scoping.js
@@ -0,0 +1,216 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --harmony-block-scoping
+// Test functionality of block scopes.
+
+// Hoisting of var declarations.
+function f1() {
+ {
+ var x = 1;
+ var y;
+ }
+ assertEquals(1, x)
+ assertEquals(undefined, y)
+}
+f1();
+
+
+// Dynamic lookup in and through block contexts.
+function f2(one) {
+ var x = one + 1;
+ let y = one + 2;
+ {
+ let z = one + 3;
+ assertEquals(1, eval('one'));
+ assertEquals(2, eval('x'));
+ assertEquals(3, eval('y'));
+ assertEquals(4, eval('z'));
+ }
+}
+f2(1);
+
+
+// Lookup in and through block contexts.
+function f3(one) {
+ var x = one + 1;
+ let y = one + 2;
+ {
+ let z = one + 3;
+ assertEquals(1, one);
+ assertEquals(2, x);
+ assertEquals(3, y);
+ assertEquals(4, z);
+ }
+}
+f3(1);
+
+
+// Dynamic lookup from closure.
+function f4(one) {
+ var x = one + 1;
+ let y = one + 2;
+ {
+ let z = one + 3;
+ function f() {
+ assertEquals(1, eval('one'));
+ assertEquals(2, eval('x'));
+ assertEquals(3, eval('y'));
+ assertEquals(4, eval('z'));
+ };
+ }
+}
+f4(1);
+
+
+// Lookup from closure.
+function f5(one) {
+ var x = one + 1;
+ let y = one + 2;
+ {
+ let z = one + 3;
+ function f() {
+ assertEquals(1, one);
+ assertEquals(2, x);
+ assertEquals(3, y);
+ assertEquals(4, z);
+ };
+ }
+}
+f5(1);
+
+
+// Return from block.
+function f6() {
+ let x = 1;
+ {
+ let y = 2;
+ return x + y;
+ }
+}
+assertEquals(3, f6(6));
+
+
+// Variable shadowing and lookup.
+function f7(a) {
+ let b = 1;
+ var c = 1;
+ var d = 1;
+ { // let variables shadowing argument, let and var variables
+ let a = 2;
+ let b = 2;
+ let c = 2;
+ assertEquals(2,a);
+ assertEquals(2,b);
+ assertEquals(2,c);
+ }
+ try {
+ throw 'stuff1';
+ } catch (a) {
+ assertEquals('stuff1',a);
+ // catch variable shadowing argument
+ a = 2;
+ assertEquals(2,a);
+ {
+ // let variable shadowing catch variable
+ let a = 3;
+ assertEquals(3,a);
+ try {
+ throw 'stuff2';
+ } catch (a) {
+ assertEquals('stuff2',a);
+ // catch variable shadowing let variable
+ a = 4;
+ assertEquals(4,a);
+ }
+ assertEquals(3,a);
+ }
+ assertEquals(2,a);
+ }
+ try {
+ throw 'stuff3';
+ } catch (c) {
+ // catch variable shadowing var variable
+ assertEquals('stuff3',c);
+ try {
+ throw 'stuff4';
+ } catch(c) {
+ assertEquals('stuff4',c);
+ // catch variable shadowing catch variable
+ c = 3;
+ assertEquals(3,c);
+ }
+ (function(c) {
+ // argument shadowing catch variable
+ c = 3;
+ assertEquals(3,c);
+ })();
+ assertEquals('stuff3', c);
+ (function() {
+ // var variable shadowing catch variable
+ var c = 3;
+ })();
+ assertEquals('stuff3', c);
+ c = 2;
+ }
+ assertEquals(1,c);
+ (function(a,b,c) {
+ // arguments shadowing argument, let and var variable
+ a = 2;
+ b = 2;
+ c = 2;
+ assertEquals(2,a);
+ assertEquals(2,b);
+ assertEquals(2,c);
+ // var variable shadowing var variable
+ var d = 2;
+ })(1,1);
+ assertEquals(1,a);
+ assertEquals(1,b);
+ assertEquals(1,c);
+ assertEquals(1,d);
+}
+f7(1);
+
+
+// Ensure let variables are block local and var variables function local.
+function f8() {
+ var let_accessors = [];
+ var var_accessors = [];
+ for (var i = 0; i < 10; i++) {
+ let x = i;
+ var y = i;
+ let_accessors[i] = function() { return x; }
+ var_accessors[i] = function() { return y; }
+ }
+ for (var j = 0; j < 10; j++) {
+ y = j + 10;
+ assertEquals(j, let_accessors[j]());
+ assertEquals(y, var_accessors[j]());
+ }
+}
+f8();
diff --git a/deps/v8/test/mjsunit/harmony/debug-blockscopes.js b/deps/v8/test/mjsunit/harmony/debug-blockscopes.js
new file mode 100644
index 000000000..e0df71b2d
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/debug-blockscopes.js
@@ -0,0 +1,389 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug --harmony-block-scoping
+// The functions used for testing backtraces. They are at the top to make the
+// testing of source line/column easier.
+
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug;
+
+var test_name;
+var listener_delegate;
+var listener_called;
+var exception;
+var begin_test_count = 0;
+var end_test_count = 0;
+var break_count = 0;
+
+
+// Debug event listener which delegates.
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ break_count++;
+ listener_called = true;
+ listener_delegate(exec_state);
+ }
+ } catch (e) {
+ exception = e;
+ }
+}
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+
+// Initialize for a new test.
+function BeginTest(name) {
+ test_name = name;
+ listener_delegate = null;
+ listener_called = false;
+ exception = null;
+ begin_test_count++;
+}
+
+
+// Check result of a test.
+function EndTest() {
+ assertTrue(listener_called, "listerner not called for " + test_name);
+ assertNull(exception, test_name);
+ end_test_count++;
+}
+
+
+// Check that the scope chain contains the expected types of scopes.
+function CheckScopeChain(scopes, exec_state) {
+ assertEquals(scopes.length, exec_state.frame().scopeCount());
+ for (var i = 0; i < scopes.length; i++) {
+ var scope = exec_state.frame().scope(i);
+ assertTrue(scope.isScope());
+ assertEquals(scopes[i], scope.scopeType());
+
+ // Check the global object when hitting the global scope.
+ if (scopes[i] == debug.ScopeType.Global) {
+ // Objects don't have same class (one is "global", other is "Object",
+ // so just check the properties directly.
+ assertPropertiesEqual(this, scope.scopeObject().value());
+ }
+ }
+
+ // Get the debug command processor.
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
+
+ // Send a scopes request and check the result.
+ var json;
+ var request_json = '{"seq":0,"type":"request","command":"scopes"}';
+ var response_json = dcp.processDebugJSONRequest(request_json);
+ var response = JSON.parse(response_json);
+ assertEquals(scopes.length, response.body.scopes.length);
+ for (var i = 0; i < scopes.length; i++) {
+ assertEquals(i, response.body.scopes[i].index);
+ assertEquals(scopes[i], response.body.scopes[i].type);
+ if (scopes[i] == debug.ScopeType.Local ||
+ scopes[i] == debug.ScopeType.Closure) {
+ assertTrue(response.body.scopes[i].object.ref < 0);
+ } else {
+ assertTrue(response.body.scopes[i].object.ref >= 0);
+ }
+ var found = false;
+ for (var j = 0; j < response.refs.length && !found; j++) {
+ found = response.refs[j].handle == response.body.scopes[i].object.ref;
+ }
+ assertTrue(found, "Scope object " + response.body.scopes[i].object.ref + " not found");
+ }
+}
+
+// Check that the content of the scope is as expected. For functions just check
+// that there is a function.
+function CheckScopeContent(content, number, exec_state) {
+ var scope = exec_state.frame().scope(number);
+ var count = 0;
+ for (var p in content) {
+ var property_mirror = scope.scopeObject().property(p);
+ if (property_mirror.isUndefined()) {
+ print('property ' + p + ' not found in scope');
+ }
+ assertFalse(property_mirror.isUndefined(), 'property ' + p + ' not found in scope');
+ if (typeof(content[p]) === 'function') {
+ assertTrue(property_mirror.value().isFunction());
+ } else {
+ assertEquals(content[p], property_mirror.value().value(), 'property ' + p + ' has unexpected value');
+ }
+ count++;
+ }
+
+ // 'arguments' and might be exposed in the local and closure scope. Just
+ // ignore this.
+ var scope_size = scope.scopeObject().properties().length;
+ if (!scope.scopeObject().property('arguments').isUndefined()) {
+ scope_size--;
+ }
+ // Also ignore synthetic variable from catch block.
+ if (!scope.scopeObject().property('.catch-var').isUndefined()) {
+ scope_size--;
+ }
+ // Skip property with empty name.
+ if (!scope.scopeObject().property('').isUndefined()) {
+ scope_size--;
+ }
+ // Also ignore synthetic variable from block scopes.
+ if (!scope.scopeObject().property('.block').isUndefined()) {
+ scope_size--;
+ }
+
+ if (count != scope_size) {
+ print('Names found in scope:');
+ var names = scope.scopeObject().propertyNames();
+ for (var i = 0; i < names.length; i++) {
+ print(names[i]);
+ }
+ }
+ assertEquals(count, scope_size);
+
+ // Get the debug command processor.
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
+
+ // Send a scope request for information on a single scope and check the
+ // result.
+ var request_json = '{"seq":0,"type":"request","command":"scope","arguments":{"number":';
+ request_json += scope.scopeIndex();
+ request_json += '}}';
+ var response_json = dcp.processDebugJSONRequest(request_json);
+ var response = JSON.parse(response_json);
+ assertEquals(scope.scopeType(), response.body.type);
+ assertEquals(number, response.body.index);
+ if (scope.scopeType() == debug.ScopeType.Local ||
+ scope.scopeType() == debug.ScopeType.Closure) {
+ assertTrue(response.body.object.ref < 0);
+ } else {
+ assertTrue(response.body.object.ref >= 0);
+ }
+ var found = false;
+ for (var i = 0; i < response.refs.length && !found; i++) {
+ found = response.refs[i].handle == response.body.object.ref;
+ }
+ assertTrue(found, "Scope object " + response.body.object.ref + " not found");
+}
+
+
+// Simple empty block scope in local scope.
+BeginTest("Local block 1");
+
+function local_block_1() {
+ {
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({}, 0, exec_state);
+ CheckScopeContent({}, 1, exec_state);
+};
+local_block_1();
+EndTest();
+
+
+// Local scope with a parameter.
+BeginTest("Local 2");
+
+function local_2(a) {
+ {
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({a:1}, 1, exec_state);
+};
+local_2(1);
+EndTest();
+
+
+// Local scope with a parameter and a local variable.
+BeginTest("Local 3");
+
+function local_3(a) {
+ let x = 3;
+ debugger;
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({a:1,x:3}, 0, exec_state);
+};
+local_3(1);
+EndTest();
+
+
+// Local scope with parameters and local variables.
+BeginTest("Local 4");
+
+function local_4(a, b) {
+ let x = 3;
+ let y = 4;
+ debugger;
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state);
+};
+local_4(1, 2);
+EndTest();
+
+
+// Single empty with block.
+BeginTest("With block 1");
+
+function with_block_1() {
+ with({}) {
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.With,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({}, 0, exec_state);
+ CheckScopeContent({}, 1, exec_state);
+};
+with_block_1();
+EndTest();
+
+
+// Nested empty with blocks.
+BeginTest("With block 2");
+
+function with_block_2() {
+ with({}) {
+ with({}) {
+ debugger;
+ }
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.With,
+ debug.ScopeType.Block,
+ debug.ScopeType.With,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({}, 0, exec_state);
+ CheckScopeContent({}, 1, exec_state);
+ CheckScopeContent({}, 2, exec_state);
+ CheckScopeContent({}, 3, exec_state);
+};
+with_block_2();
+EndTest();
+
+
+// With block using an in-place object literal.
+BeginTest("With block 3");
+
+function with_block_3() {
+ with({a:1,b:2}) {
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.With,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({}, 0, exec_state);
+ CheckScopeContent({a:1,b:2}, 1, exec_state);
+};
+with_block_3();
+EndTest();
+
+
+// Nested with blocks using in-place object literals.
+BeginTest("With block 4");
+
+function with_block_4() {
+ with({a:1,b:2}) {
+ with({a:2,b:1}) {
+ debugger;
+ }
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.With,
+ debug.ScopeType.Block,
+ debug.ScopeType.With,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({a:2,b:1}, 1, exec_state);
+ CheckScopeContent({a:1,b:2}, 3, exec_state);
+};
+with_block_4();
+EndTest();
+
+
+// Simple closure formed by returning an inner function referering to an outer
+// block local variable and an outer function's parameter.
+BeginTest("Closure 1");
+
+function closure_1(a) {
+ var x = 2;
+ let y = 3;
+ if (true) {
+ let z = 4;
+ function f() {
+ debugger;
+ return a + x + y + z;
+ };
+ return f;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Local,
+ debug.ScopeType.Block,
+ debug.ScopeType.Closure,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({}, 0, exec_state);
+ CheckScopeContent({a:1,x:2,y:3}, 2, exec_state);
+};
+closure_1(1)();
+EndTest();
diff --git a/deps/v8/test/mjsunit/harmony/debug-evaluate-blockscopes.js b/deps/v8/test/mjsunit/harmony/debug-evaluate-blockscopes.js
new file mode 100644
index 000000000..549960a28
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/debug-evaluate-blockscopes.js
@@ -0,0 +1,64 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug --harmony-block-scoping
+
+// Test debug evaluation for functions without local context, but with
+// nested catch contexts.
+
+function f() {
+ { // Line 1.
+ let i = 1; // Line 2.
+ try { // Line 3.
+ throw 'stuff'; // Line 4.
+ } catch (e) { // Line 5.
+ x = 2; // Line 6.
+ }
+ }
+};
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+// Set breakpoint on line 6.
+var bp = Debug.setBreakPoint(f, 6);
+
+function listener(event, exec_state, event_data, data) {
+ if (event == Debug.DebugEvent.Break) {
+ result = exec_state.frame().evaluate("i").value();
+ }
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+result = -1;
+f();
+assertEquals(1, result);
+
+// Clear breakpoint.
+Debug.clearBreakPoint(bp);
+// Get rid of the debug event listener.
+Debug.setListener(null);
diff --git a/deps/v8/test/mjsunit/harmony/typeof.js b/deps/v8/test/mjsunit/harmony/typeof.js
new file mode 100644
index 000000000..acde97785
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/typeof.js
@@ -0,0 +1,35 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-typeof
+
+assertFalse(typeof null == 'object')
+assertFalse(typeof null === 'object')
+assertTrue(typeof null == 'null')
+assertTrue(typeof null === 'null')
+assertEquals("null", typeof null)
+assertSame("null", typeof null)
diff --git a/deps/v8/test/mjsunit/harmony/weakmaps.js b/deps/v8/test/mjsunit/harmony/weakmaps.js
index d98db10df..97f553cf2 100644
--- a/deps/v8/test/mjsunit/harmony/weakmaps.js
+++ b/deps/v8/test/mjsunit/harmony/weakmaps.js
@@ -139,6 +139,23 @@ assertTrue(WeakMap.prototype.has instanceof Function)
assertTrue(WeakMap.prototype.delete instanceof Function)
+// Regression test for issue 1617: The prototype of the WeakMap constructor
+// needs to be unique (i.e. different from the one of the Object constructor).
+assertFalse(WeakMap.prototype === Object.prototype);
+var o = Object.create({});
+assertFalse("get" in o);
+assertFalse("set" in o);
+assertEquals(undefined, o.get);
+assertEquals(undefined, o.set);
+var o = Object.create({}, { myValue: {
+ value: 10,
+ enumerable: false,
+ configurable: true,
+ writable: true
+}});
+assertEquals(10, o.myValue);
+
+
// Stress Test
// There is a proposed stress-test available at the es-discuss mailing list
// which cannot be reasonably automated. Check it out by hand if you like:
diff --git a/deps/v8/test/mjsunit/math-floor.js b/deps/v8/test/mjsunit/math-floor.js
index 11f4cd789..f211ce2e5 100644
--- a/deps/v8/test/mjsunit/math-floor.js
+++ b/deps/v8/test/mjsunit/math-floor.js
@@ -27,10 +27,11 @@
// Flags: --max-new-space-size=256 --allow-natives-syntax
+var test_id = 0;
+
function testFloor(expect, input) {
- function test(n) {
- return Math.floor(n);
- }
+ var test = new Function('n',
+ '"' + (test_id++) + '";return Math.floor(n)');
assertEquals(expect, test(input));
assertEquals(expect, test(input));
assertEquals(expect, test(input));
@@ -51,6 +52,17 @@ function test() {
testFloor(-Infinity, -Infinity);
testFloor(NaN, NaN);
+ // Ensure that a negative zero coming from Math.floor is properly handled
+ // by other operations.
+ function ifloor(x) {
+ return 1 / Math.floor(x);
+ }
+ assertEquals(-Infinity, ifloor(-0));
+ assertEquals(-Infinity, ifloor(-0));
+ assertEquals(-Infinity, ifloor(-0));
+ %OptimizeFunctionOnNextCall(ifloor);
+ assertEquals(-Infinity, ifloor(-0));
+
testFloor(0, 0.1);
testFloor(0, 0.49999999999999994);
testFloor(0, 0.5);
@@ -129,3 +141,19 @@ function test() {
for (var i = 0; i < 500; i++) {
test();
}
+
+
+// Regression test for a bug where a negative zero coming from Math.floor
+// was not properly handled by other operations.
+function floorsum(i, n) {
+ var ret = Math.floor(n);
+ while (--i > 0) {
+ ret += Math.floor(n);
+ }
+ return ret;
+}
+assertEquals(-0, floorsum(1, -0));
+%OptimizeFunctionOnNextCall(floorsum);
+// The optimized function will deopt. Run it with enough iterations to try
+// to optimize via OSR (triggering the bug).
+assertEquals(-0, floorsum(100000, -0));
diff --git a/deps/v8/test/mjsunit/math-round.js b/deps/v8/test/mjsunit/math-round.js
index 1366557f6..102c970f3 100644
--- a/deps/v8/test/mjsunit/math-round.js
+++ b/deps/v8/test/mjsunit/math-round.js
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -27,10 +27,12 @@
// Flags: --allow-natives-syntax
+var test_id = 0;
function testRound(expect, input) {
- function doRound(input) {
- return Math.round(input);
- }
+ // Make source code different on each invocation to make
+ // sure it gets optimized each time.
+ var doRound = new Function('input',
+ '"' + (test_id++) + '";return Math.round(input)');
assertEquals(expect, doRound(input));
assertEquals(expect, doRound(input));
assertEquals(expect, doRound(input));
@@ -44,6 +46,21 @@ testRound(Infinity, Infinity);
testRound(-Infinity, -Infinity);
testRound(NaN, NaN);
+// Regression test for a bug where a negative zero coming from Math.round
+// was not properly handled by other operations.
+function roundsum(i, n) {
+ var ret = Math.round(n);
+ while (--i > 0) {
+ ret += Math.round(n);
+ }
+ return ret;
+}
+assertEquals(-0, roundsum(1, -0));
+%OptimizeFunctionOnNextCall(roundsum);
+// The optimized function will deopt. Run it with enough iterations to try
+// to optimize via OSR (triggering the bug).
+assertEquals(-0, roundsum(100000, -0));
+
testRound(1, 0.5);
testRound(1, 0.7);
testRound(1, 1);
diff --git a/deps/v8/test/mjsunit/regress/regress-1592.js b/deps/v8/test/mjsunit/regress/regress-1592.js
new file mode 100644
index 000000000..8f6fba01a
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-1592.js
@@ -0,0 +1,45 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+var f = {
+ apply: function(a, b) {}
+};
+
+function test(a) {
+ f.apply(this, arguments);
+}
+
+// Initialize ICs.
+test(1);
+test(1);
+
+%OptimizeFunctionOnNextCall(test);
+
+// Kaboom!
+test(1);
diff --git a/deps/v8/test/mjsunit/with-leave.js b/deps/v8/test/mjsunit/with-leave.js
index ded62caf5..7369faa50 100644
--- a/deps/v8/test/mjsunit/with-leave.js
+++ b/deps/v8/test/mjsunit/with-leave.js
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -59,3 +59,162 @@ try {
}
assertTrue(caught);
+
+// We want to test the context chain shape. In each of the tests cases
+// below, the outer with is to force a runtime lookup of the identifier 'x'
+// to actually verify that the inner context has been discarded. A static
+// lookup of 'x' might accidentally succeed.
+with ({x: 'outer'}) {
+ label: {
+ with ({x: 'inner'}) {
+ break label;
+ }
+ }
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ label: {
+ with ({x: 'middle'}) {
+ with ({x: 'inner'}) {
+ break label;
+ }
+ }
+ }
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ for (var i = 0; i < 10; ++i) {
+ with ({x: 'inner' + i}) {
+ continue;
+ }
+ }
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ label: for (var i = 0; i < 10; ++i) {
+ with ({x: 'middle' + i}) {
+ for (var j = 0; j < 10; ++j) {
+ with ({x: 'inner' + j}) {
+ continue label;
+ }
+ }
+ }
+ }
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ try {
+ with ({x: 'inner'}) {
+ throw 0;
+ }
+ } catch (e) {
+ assertEquals('outer', x);
+ }
+}
+
+
+with ({x: 'outer'}) {
+ try {
+ with ({x: 'middle'}) {
+ with ({x: 'inner'}) {
+ throw 0;
+ }
+ }
+ } catch (e) {
+ assertEquals('outer', x);
+ }
+}
+
+
+try {
+ with ({x: 'outer'}) {
+ try {
+ with ({x: 'inner'}) {
+ throw 0;
+ }
+ } finally {
+ assertEquals('outer', x);
+ }
+ }
+} catch (e) {
+ if (e instanceof MjsUnitAssertionError) throw e;
+}
+
+
+try {
+ with ({x: 'outer'}) {
+ try {
+ with ({x: 'middle'}) {
+ with ({x: 'inner'}) {
+ throw 0;
+ }
+ }
+ } finally {
+ assertEquals('outer', x);
+ }
+ }
+} catch (e) {
+ if (e instanceof MjsUnitAssertionError) throw e;
+}
+
+
+// Verify that the context is correctly set in the stack frame after exiting
+// from with.
+function f() {}
+
+with ({x: 'outer'}) {
+ label: {
+ with ({x: 'inner'}) {
+ break label;
+ }
+ }
+ f(); // The context could be restored from the stack after the call.
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ for (var i = 0; i < 10; ++i) {
+ with ({x: 'inner' + i}) {
+ continue;
+ }
+ }
+ f();
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ try {
+ with ({x: 'inner'}) {
+ throw 0;
+ }
+ } catch (e) {
+ f();
+ assertEquals('outer', x);
+ }
+}
+
+
+try {
+ with ({x: 'outer'}) {
+ try {
+ with ({x: 'inner'}) {
+ throw 0;
+ }
+ } finally {
+ f();
+ assertEquals('outer', x);
+ }
+ }
+} catch (e) {
+ if (e instanceof MjsUnitAssertionError) throw e;
+}
diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp
index e755fcb92..03972463a 100644
--- a/deps/v8/tools/gyp/v8.gyp
+++ b/deps/v8/tools/gyp/v8.gyp
@@ -497,7 +497,6 @@
'../../src/code-stubs.cc',
'../../src/code-stubs.h',
'../../src/code.h',
- '../../src/codegen-inl.h',
'../../src/codegen.cc',
'../../src/codegen.h',
'../../src/compilation-cache.cc',