Browse Source

Upgrade V8 to 3.5.6

Ryan Dahl 14 years ago
parent
commit
05e6f318c6
  1. 1
      deps/v8/.gitignore
  2. 28
      deps/v8/ChangeLog
  3. 18
      deps/v8/include/v8.h
  4. 12
      deps/v8/src/api.cc
  5. 14
      deps/v8/src/apinatives.js
  6. 54
      deps/v8/src/arm/code-stubs-arm.cc
  7. 2
      deps/v8/src/arm/deoptimizer-arm.cc
  8. 7
      deps/v8/src/arm/frames-arm.h
  9. 12
      deps/v8/src/arm/full-codegen-arm.cc
  10. 20
      deps/v8/src/arm/lithium-arm.cc
  11. 23
      deps/v8/src/arm/lithium-arm.h
  12. 94
      deps/v8/src/arm/lithium-codegen-arm.cc
  13. 86
      deps/v8/src/arm/macro-assembler-arm.cc
  14. 46
      deps/v8/src/arm/stub-cache-arm.cc
  15. 3
      deps/v8/src/ast-inl.h
  16. 2
      deps/v8/src/ast.cc
  17. 22
      deps/v8/src/ast.h
  18. 5
      deps/v8/src/bootstrapper.cc
  19. 20
      deps/v8/src/code-stubs.cc
  20. 6
      deps/v8/src/code-stubs.h
  21. 10
      deps/v8/src/compiler.cc
  22. 21
      deps/v8/src/contexts.cc
  23. 4
      deps/v8/src/contexts.h
  24. 1
      deps/v8/src/d8.cc
  25. 4
      deps/v8/src/d8.h
  26. 3
      deps/v8/src/d8.js
  27. 36
      deps/v8/src/disassembler.cc
  28. 80
      deps/v8/src/elements.cc
  29. 4
      deps/v8/src/elements.h
  30. 2
      deps/v8/src/extensions/experimental/datetime-format.cc
  31. 22
      deps/v8/src/factory.cc
  32. 7
      deps/v8/src/factory.h
  33. 2
      deps/v8/src/flag-definitions.h
  34. 9
      deps/v8/src/frames-inl.h
  35. 3
      deps/v8/src/frames.h
  36. 94
      deps/v8/src/full-codegen.cc
  37. 53
      deps/v8/src/full-codegen.h
  38. 43
      deps/v8/src/heap.cc
  39. 14
      deps/v8/src/heap.h
  40. 33
      deps/v8/src/hydrogen-instructions.cc
  41. 36
      deps/v8/src/hydrogen-instructions.h
  42. 37
      deps/v8/src/hydrogen.cc
  43. 3
      deps/v8/src/hydrogen.h
  44. 12
      deps/v8/src/ia32/assembler-ia32.cc
  45. 10
      deps/v8/src/ia32/assembler-ia32.h
  46. 56
      deps/v8/src/ia32/code-stubs-ia32.cc
  47. 12
      deps/v8/src/ia32/disasm-ia32.cc
  48. 9
      deps/v8/src/ia32/frames-ia32.h
  49. 13
      deps/v8/src/ia32/full-codegen-ia32.cc
  50. 130
      deps/v8/src/ia32/lithium-codegen-ia32.cc
  51. 2
      deps/v8/src/ia32/lithium-codegen-ia32.h
  52. 24
      deps/v8/src/ia32/lithium-ia32.cc
  53. 33
      deps/v8/src/ia32/lithium-ia32.h
  54. 53
      deps/v8/src/ia32/macro-assembler-ia32.cc
  55. 97
      deps/v8/src/ia32/stub-cache-ia32.cc
  56. 6
      deps/v8/src/isolate.cc
  57. 194
      deps/v8/src/liveobjectlist.cc
  58. 4
      deps/v8/src/liveobjectlist.h
  59. 1
      deps/v8/src/messages.js
  60. 5
      deps/v8/src/mips/frames-mips.h
  61. 6
      deps/v8/src/mips/full-codegen-mips.cc
  62. 90
      deps/v8/src/mips/macro-assembler-mips.cc
  63. 8
      deps/v8/src/mips/stub-cache-mips.cc
  64. 3
      deps/v8/src/mirror-debugger.js
  65. 2
      deps/v8/src/mksnapshot.cc
  66. 22
      deps/v8/src/objects-inl.h
  67. 35
      deps/v8/src/objects.cc
  68. 49
      deps/v8/src/objects.h
  69. 266
      deps/v8/src/parser.cc
  70. 22
      deps/v8/src/parser.h
  71. 2
      deps/v8/src/platform-linux.cc
  72. 1
      deps/v8/src/preparser-api.cc
  73. 52
      deps/v8/src/preparser.cc
  74. 18
      deps/v8/src/preparser.h
  75. 19
      deps/v8/src/prettyprinter.cc
  76. 10
      deps/v8/src/rewriter.cc
  77. 6
      deps/v8/src/runtime-profiler.h
  78. 83
      deps/v8/src/runtime.cc
  79. 1
      deps/v8/src/runtime.h
  80. 104
      deps/v8/src/scanner-base.cc
  81. 11
      deps/v8/src/scanner-base.h
  82. 2
      deps/v8/src/scopeinfo.cc
  83. 2
      deps/v8/src/scopeinfo.h
  84. 66
      deps/v8/src/scopes.cc
  85. 12
      deps/v8/src/scopes.h
  86. 46
      deps/v8/src/serialize.cc
  87. 47
      deps/v8/src/serialize.h
  88. 1
      deps/v8/src/token.h
  89. 3
      deps/v8/src/variables.cc
  90. 13
      deps/v8/src/variables.h
  91. 4
      deps/v8/src/version.cc
  92. 11
      deps/v8/src/weakmap.js
  93. 54
      deps/v8/src/x64/code-stubs-x64.cc
  94. 11
      deps/v8/src/x64/frames-x64.h
  95. 12
      deps/v8/src/x64/full-codegen-x64.cc
  96. 113
      deps/v8/src/x64/lithium-codegen-x64.cc
  97. 2
      deps/v8/src/x64/lithium-codegen-x64.h
  98. 25
      deps/v8/src/x64/lithium-x64.cc
  99. 33
      deps/v8/src/x64/lithium-x64.h
  100. 69
      deps/v8/src/x64/macro-assembler-x64.cc

1
deps/v8/.gitignore

@ -21,6 +21,7 @@ shell
shell_g shell_g
/build/gyp /build/gyp
/obj/ /obj/
/out/
/test/es5conform/data/ /test/es5conform/data/
/test/mozilla/data/ /test/mozilla/data/
/test/sputnik/sputniktests/ /test/sputnik/sputniktests/

28
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 2011-08-10: Version 3.5.4
Added a preliminary implementation of ES Harmony weak maps. Weak Added a preliminary implementation of ES Harmony weak maps. Weak

18
deps/v8/include/v8.h

@ -171,12 +171,12 @@ template <class T> class Handle {
/** /**
* Creates an empty handle. * Creates an empty handle.
*/ */
inline Handle(); inline Handle() : val_(0) {}
/** /**
* Creates a new handle for the specified value. * 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 * 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 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. * 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. * Checks whether two handles are the same.
@ -3826,10 +3826,6 @@ class Internals {
} // namespace internal } // namespace internal
template <class T>
Handle<T>::Handle() : val_(0) { }
template <class T> template <class T>
Local<T>::Local() : Handle<T>() { } Local<T>::Local() : Handle<T>() { }

12
deps/v8/src/api.cc

@ -35,6 +35,7 @@
#include "debug.h" #include "debug.h"
#include "deoptimizer.h" #include "deoptimizer.h"
#include "execution.h" #include "execution.h"
#include "flags.h"
#include "global-handles.h" #include "global-handles.h"
#include "heap-profiler.h" #include "heap-profiler.h"
#include "messages.h" #include "messages.h"
@ -1405,7 +1406,7 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
ScriptData* ScriptData::PreCompile(const char* input, int length) { ScriptData* ScriptData::PreCompile(const char* input, int length) {
i::Utf8ToUC16CharacterStream stream( i::Utf8ToUC16CharacterStream stream(
reinterpret_cast<const unsigned char*>(input), length); 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()) { if (str->IsExternalTwoByteString()) {
i::ExternalTwoByteStringUC16CharacterStream stream( i::ExternalTwoByteStringUC16CharacterStream stream(
i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length()); 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 { } else {
i::GenericStringUC16CharacterStream stream(str, 0, str->length()); 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::Object* constructor = object->map()->constructor();
i::JSFunction* function; i::JSFunction* function;
if (!constructor->IsJSFunction()) { if (!constructor->IsJSFunction()) {
// API functions have null as a constructor, // Functions have null as a constructor,
// but any JSFunction knows its context immediately. // but any JSFunction knows its context immediately.
ASSERT(object->IsJSFunction() && ASSERT(object->IsJSFunction());
i::JSFunction::cast(object)->shared()->IsApiFunction());
function = i::JSFunction::cast(object); function = i::JSFunction::cast(object);
} else { } else {
function = i::JSFunction::cast(constructor); function = i::JSFunction::cast(constructor);

14
deps/v8/src/apinatives.js

@ -49,7 +49,10 @@ function Instantiate(data, name) {
return InstantiateFunction(data, name); return InstantiateFunction(data, name);
case kNewObjectTag: case kNewObjectTag:
var Constructor = %GetTemplateField(data, kApiConstructorOffset); 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); ConfigureTemplateInstance(result, data);
result = %ToFastProperties(result); result = %ToFastProperties(result);
return result; return result;
@ -74,13 +77,18 @@ function InstantiateFunction(data, name) {
cache[serialNumber] = fun; cache[serialNumber] = fun;
var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset); var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset);
var flags = %GetTemplateField(data, kApiFlagOffset); 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)) { if (flags & (1 << kReadOnlyPrototypeBit)) {
%FunctionSetReadOnlyPrototype(fun); %FunctionSetReadOnlyPrototype(fun);
} }
%SetProperty(fun.prototype, "constructor", fun, DONT_ENUM); %SetProperty(fun.prototype, "constructor", fun, DONT_ENUM);
var parent = %GetTemplateField(data, kApiParentTemplateOffset); 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); var parent_fun = Instantiate(parent);
fun.prototype.__proto__ = parent_fun.prototype; fun.prototype.__proto__ = parent_fun.prototype;
} }

54
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; const Register map = r9.is(tos_) ? r7 : r9;
// undefined -> false. // undefined -> false.
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch); CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value. // Boolean -> its value.
CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch); CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch); CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false. // 'null' -> false.
CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch); CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) { if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true // Smis: 0 -> false, all other -> true
@ -1635,23 +1635,20 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
if (types_.NeedsMap()) { if (types_.NeedsMap()) {
__ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset)); __ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
// Everything with a map could be undetectable, so check this now. if (types_.CanBeUndetectable()) {
__ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
__ tst(ip, Operand(1 << Map::kIsUndetectable)); __ tst(ip, Operand(1 << Map::kIsUndetectable));
// Undetectable -> false. // Undetectable -> false.
__ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne); __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
__ Ret(ne); __ Ret(ne);
} }
}
if (types_.Contains(SPEC_OBJECT)) { if (types_.Contains(SPEC_OBJECT)) {
// Spec object -> true. // Spec object -> true.
__ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE); __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
// tos_ contains the correct non-zero return value already. // tos_ contains the correct non-zero return value already.
__ Ret(ge); __ 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)) { if (types_.Contains(STRING)) {
@ -1659,10 +1656,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE); __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
__ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt); __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
__ Ret(lt); // the string length is OK as the return value __ 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)) { 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 __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN
__ Ret(); __ Ret();
__ bind(&not_heap_number); __ 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); __ bind(&patch);
GenerateTypeTransition(masm); GenerateTypeTransition(masm);
}
} }
void ToBooleanStub::CheckOddball(MacroAssembler* masm, void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type, Type type,
Heap::RootListIndex value, Heap::RootListIndex value,
bool result, bool result) {
Label* patch) {
if (types_.Contains(type)) { if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_. // If we see an expected oddball, return its ToBoolean value tos_.
__ LoadRoot(ip, value); __ LoadRoot(ip, value);
@ -1713,12 +1693,6 @@ void ToBooleanStub::CheckOddball(MacroAssembler* masm,
__ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq); __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq);
} }
__ Ret(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, void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
ExternalReference function) { ExternalReference function) {
__ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()),
RelocInfo::CODE_TARGET));
__ mov(r2, Operand(function)); __ mov(r2, Operand(function));
// Push return address (accessible to GC through exit frame pc). GenerateCall(masm, r2);
__ str(pc, MemOperand(sp, 0));
__ Jump(r2); // Call the api function.
} }
@ -6355,8 +6325,14 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
__ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()), __ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()),
RelocInfo::CODE_TARGET)); RelocInfo::CODE_TARGET));
// Push return address (accessible to GC through exit frame pc). // 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. __ Jump(target); // Call the C++ function.
ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta,
masm->SizeOfCodeGeneratedSince(&start));
} }

2
deps/v8/src/arm/deoptimizer-arm.cc

@ -593,6 +593,8 @@ void Deoptimizer::EntryGenerator::Generate() {
__ vstm(db_w, sp, first, last); __ vstm(db_w, sp, first, last);
// Push all 16 registers (needed to populate FrameDescription::registers_). // 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()); __ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit());
const int kSavedRegistersAreaSize = const int kSavedRegistersAreaSize =

7
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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -95,8 +95,9 @@ class StackHandlerConstants : public AllStatic {
public: public:
static const int kNextOffset = 0 * kPointerSize; static const int kNextOffset = 0 * kPointerSize;
static const int kStateOffset = 1 * kPointerSize; static const int kStateOffset = 1 * kPointerSize;
static const int kFPOffset = 2 * kPointerSize; static const int kContextOffset = 2 * kPointerSize;
static const int kPCOffset = 3 * kPointerSize; static const int kFPOffset = 3 * kPointerSize;
static const int kPCOffset = 4 * kPointerSize;
static const int kSize = kPCOffset + kPointerSize; static const int kSize = kPCOffset + kPointerSize;
}; };

12
deps/v8/src/arm/full-codegen-arm.cc

@ -742,9 +742,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ mov(r2, Operand(variable->name())); __ mov(r2, Operand(variable->name()));
// Declaration nodes are always introduced in one of two modes. // Declaration nodes are always introduced in one of two modes.
ASSERT(mode == Variable::VAR || ASSERT(mode == Variable::VAR ||
mode == Variable::CONST); mode == Variable::CONST ||
PropertyAttributes attr = mode == Variable::LET);
(mode == Variable::VAR) ? NONE : READ_ONLY; PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
__ mov(r1, Operand(Smi::FromInt(attr))); __ mov(r1, Operand(Smi::FromInt(attr)));
// Push initial value, if any. // Push initial value, if any.
// Note: For variables we must not push an initial value (such as // 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); __ b(eq, if_true);
__ CompareRoot(r0, Heap::kFalseValueRootIndex); __ CompareRoot(r0, Heap::kFalseValueRootIndex);
Split(eq, if_true, if_false, fall_through); 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())) { } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ CompareRoot(r0, Heap::kUndefinedValueRootIndex); __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
__ b(eq, if_true); __ b(eq, if_true);
@ -4047,8 +4051,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
} else if (check->Equals(isolate()->heap()->object_symbol())) { } else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(r0, if_false); __ JumpIfSmi(r0, if_false);
if (!FLAG_harmony_typeof) {
__ CompareRoot(r0, Heap::kNullValueRootIndex); __ CompareRoot(r0, Heap::kNullValueRootIndex);
__ b(eq, if_true); __ b(eq, if_true);
}
// Check for JS objects => true. // Check for JS objects => true.
__ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(lt, if_false); __ b(lt, if_false);

20
deps/v8/src/arm/lithium-arm.cc

@ -1039,13 +1039,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
: instr->SecondSuccessor(); : instr->SecondSuccessor();
return new LGoto(successor->block_id()); return new LGoto(successor->block_id());
} }
LInstruction* branch = new LBranch(UseRegister(v)); return AssignEnvironment(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);
} }
@ -1515,16 +1509,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
} }
LInstruction* LChunkBuilder::DoExternalArrayLength( LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HExternalArrayLength* instr) { HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value()); LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LExternalArrayLength(array)); return DefineAsRegister(new LFixedArrayBaseLength(array));
}
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array));
} }

23
deps/v8/src/arm/lithium-arm.h

@ -92,8 +92,7 @@ class LCodeGen;
V(DivI) \ V(DivI) \
V(DoubleToI) \ V(DoubleToI) \
V(ElementsKind) \ V(ElementsKind) \
V(ExternalArrayLength) \ V(FixedArrayBaseLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \ V(FunctionLiteral) \
V(GetCachedArrayIndex) \ V(GetCachedArrayIndex) \
V(GlobalObject) \ 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: public:
explicit LExternalArrayLength(LOperand* value) { explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value; inputs_[0] = value;
} }
DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length") DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength) "fixed-array-base-length")
}; DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
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)
}; };

94
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 result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0)); Register array = ToRegister(instr->InputAt(0));
__ ldr(result, FieldMemOperand(array, ExternalArray::kLengthOffset)); __ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset));
}
void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
__ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset));
} }
@ -1583,46 +1576,18 @@ void LCodeGen::DoBranch(LBranch* instr) {
// undefined -> false. // undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex); __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ b(eq, false_label); __ 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)) { if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// Boolean -> its value. // Boolean -> its value.
__ CompareRoot(reg, Heap::kTrueValueRootIndex); __ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ b(eq, true_label); __ b(eq, true_label);
__ CompareRoot(reg, Heap::kFalseValueRootIndex); __ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ b(eq, false_label); __ 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)) { if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false. // 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex); __ CompareRoot(reg, Heap::kNullValueRootIndex);
__ b(eq, false_label); __ 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)) { if (expected.Contains(ToBooleanStub::SMI)) {
@ -1639,20 +1604,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
const Register map = scratch0(); const Register map = scratch0();
if (expected.NeedsMap()) { if (expected.NeedsMap()) {
__ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset)); __ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset));
// Everything with a map could be undetectable, so check this now.
if (expected.CanBeUndetectable()) {
// Undetectable -> false.
__ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
__ tst(ip, Operand(1 << Map::kIsUndetectable)); __ tst(ip, Operand(1 << Map::kIsUndetectable));
__ b(ne, false_label); __ b(ne, false_label);
} }
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true. // spec object -> true.
__ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE); __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
__ b(ge, true_label); __ 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)) { if (expected.Contains(ToBooleanStub::STRING)) {
@ -1665,10 +1629,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ b(ne, true_label); __ b(ne, true_label);
__ b(false_label); __ b(false_label);
__ bind(&not_string); __ 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)) { if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@ -1683,21 +1643,12 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ b(eq, false_label); // +0, -0 -> false. __ b(eq, false_label); // +0, -0 -> false.
__ b(true_label); __ b(true_label);
__ bind(&not_heap_number); __ 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. // We've seen something for the first time -> deopt.
DeoptimizeIf(al, instr->environment()); DeoptimizeIf(al, instr->environment());
} }
} }
}
} }
@ -3014,19 +2965,18 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
Register scratch1 = result; Register scratch = scratch0();
Register scratch2 = scratch0();
Label done, check_sign_on_zero; Label done, check_sign_on_zero;
// Extract exponent bits. // Extract exponent bits.
__ vmov(scratch1, input.high()); __ vmov(result, input.high());
__ ubfx(scratch2, __ ubfx(scratch,
scratch1, result,
HeapNumber::kExponentShift, HeapNumber::kExponentShift,
HeapNumber::kExponentBits); HeapNumber::kExponentBits);
// If the number is in ]-0.5, +0.5[, the result is +/- 0. // 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); __ mov(result, Operand(0), LeaveCC, le);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ b(le, &check_sign_on_zero); __ b(le, &check_sign_on_zero);
@ -3036,19 +2986,19 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
// The following conversion will not work with numbers // The following conversion will not work with numbers
// outside of ]-2^32, 2^32[. // outside of ]-2^32, 2^32[.
__ cmp(scratch2, Operand(HeapNumber::kExponentBias + 32)); __ cmp(scratch, Operand(HeapNumber::kExponentBias + 32));
DeoptimizeIf(ge, instr->environment()); DeoptimizeIf(ge, instr->environment());
// Save the original sign for later comparison. // Save the original sign for later comparison.
__ and_(scratch2, scratch1, Operand(HeapNumber::kSignMask)); __ and_(scratch, result, Operand(HeapNumber::kSignMask));
__ Vmov(double_scratch0(), 0.5); __ Vmov(double_scratch0(), 0.5);
__ vadd(input, input, double_scratch0()); __ vadd(input, input, double_scratch0());
// Check sign of the result: if the sign changed, the input // Check sign of the result: if the sign changed, the input
// value was in ]0.5, 0[ and the result should be -0. // value was in ]0.5, 0[ and the result should be -0.
__ vmov(scratch1, input.high()); __ vmov(result, input.high());
__ eor(scratch1, scratch1, Operand(scratch2), SetCC); __ eor(result, result, Operand(scratch), SetCC);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(mi, instr->environment()); DeoptimizeIf(mi, instr->environment());
} else { } else {
@ -3059,8 +3009,8 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
__ EmitVFPTruncate(kRoundToMinusInf, __ EmitVFPTruncate(kRoundToMinusInf,
double_scratch0().low(), double_scratch0().low(),
input, input,
scratch1, result,
scratch2); scratch);
DeoptimizeIf(ne, instr->environment()); DeoptimizeIf(ne, instr->environment());
__ vmov(result, double_scratch0().low()); __ vmov(result, double_scratch0().low());
@ -3069,8 +3019,8 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
__ cmp(result, Operand(0)); __ cmp(result, Operand(0));
__ b(ne, &done); __ b(ne, &done);
__ bind(&check_sign_on_zero); __ bind(&check_sign_on_zero);
__ vmov(scratch1, input.high()); __ vmov(scratch, input.high());
__ tst(scratch1, Operand(HeapNumber::kSignMask)); __ tst(scratch, Operand(HeapNumber::kSignMask));
DeoptimizeIf(ne, instr->environment()); DeoptimizeIf(ne, instr->environment());
} }
__ bind(&done); __ bind(&done);
@ -4395,6 +4345,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
__ CompareRoot(input, Heap::kFalseValueRootIndex); __ CompareRoot(input, Heap::kFalseValueRootIndex);
final_branch_condition = eq; 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())) { } else if (type_name->Equals(heap()->undefined_symbol())) {
__ CompareRoot(input, Heap::kUndefinedValueRootIndex); __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
__ b(eq, true_label); __ b(eq, true_label);
@ -4413,8 +4367,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
} else if (type_name->Equals(heap()->object_symbol())) { } else if (type_name->Equals(heap()->object_symbol())) {
__ JumpIfSmi(input, false_label); __ JumpIfSmi(input, false_label);
if (!FLAG_harmony_typeof) {
__ CompareRoot(input, Heap::kNullValueRootIndex); __ CompareRoot(input, Heap::kNullValueRootIndex);
__ b(eq, true_label); __ b(eq, true_label);
}
__ CompareObjectType(input, input, scratch, __ CompareObjectType(input, input, scratch,
FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(lt, false_label); __ b(lt, false_label);

86
deps/v8/src/arm/macro-assembler-arm.cc

@ -1102,7 +1102,13 @@ void MacroAssembler::DebugBreak() {
void MacroAssembler::PushTryHandler(CodeLocation try_location, void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) { HandlerType type) {
// Adjust this code if not the case. // 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. // The pc (return address) is passed in register lr.
if (try_location == IN_JAVASCRIPT) { if (try_location == IN_JAVASCRIPT) {
if (type == TRY_CATCH_HANDLER) { if (type == TRY_CATCH_HANDLER) {
@ -1110,14 +1116,10 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
} else { } else {
mov(r3, Operand(StackHandler::TRY_FINALLY)); mov(r3, Operand(StackHandler::TRY_FINALLY));
} }
ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize stm(db_w, sp, r3.bit() | cp.bit() | fp.bit() | lr.bit());
&& StackHandlerConstants::kFPOffset == 2 * kPointerSize
&& StackHandlerConstants::kPCOffset == 3 * kPointerSize);
stm(db_w, sp, r3.bit() | fp.bit() | lr.bit());
// Save the current handler as the next handler. // Save the current handler as the next handler.
mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(r1, MemOperand(r3)); ldr(r1, MemOperand(r3));
ASSERT(StackHandlerConstants::kNextOffset == 0);
push(r1); push(r1);
// Link this handler as the new current one. // Link this handler as the new current one.
str(sp, MemOperand(r3)); 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 // 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 // for fp. We expect the code throwing an exception to check fp
// before dereferencing it to restore the context. // before dereferencing it to restore the context.
mov(ip, Operand(0, RelocInfo::NONE)); // To save a NULL frame pointer. mov(r5, Operand(StackHandler::ENTRY)); // State.
mov(r6, Operand(StackHandler::ENTRY)); mov(r6, Operand(Smi::FromInt(0))); // Indicates no context.
ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize mov(r7, Operand(0, RelocInfo::NONE)); // NULL frame pointer.
&& StackHandlerConstants::kFPOffset == 2 * kPointerSize stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | lr.bit());
&& StackHandlerConstants::kPCOffset == 3 * kPointerSize);
stm(db_w, sp, r6.bit() | ip.bit() | lr.bit());
// Save the current handler as the next handler. // Save the current handler as the next handler.
mov(r7, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); mov(r7, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(r6, MemOperand(r7)); ldr(r6, MemOperand(r7));
ASSERT(StackHandlerConstants::kNextOffset == 0);
push(r6); push(r6);
// Link this handler as the new current one. // Link this handler as the new current one.
str(sp, MemOperand(r7)); str(sp, MemOperand(r7));
@ -1145,7 +1144,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() { void MacroAssembler::PopTryHandler() {
ASSERT_EQ(0, StackHandlerConstants::kNextOffset); STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r1); pop(r1);
mov(ip, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); mov(ip, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
@ -1154,39 +1153,40 @@ void MacroAssembler::PopTryHandler() {
void MacroAssembler::Throw(Register value) { 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. // r0 is expected to hold the exception.
if (!value.is(r0)) { if (!value.is(r0)) {
mov(r0, value); 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. // Drop the sp to the top of the handler.
mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(sp, MemOperand(r3)); ldr(sp, MemOperand(r3));
// Restore the next handler and frame pointer, discard handler state. // Restore the next handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r2); pop(r2);
str(r2, MemOperand(r3)); str(r2, MemOperand(r3));
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
ldm(ia_w, sp, r3.bit() | fp.bit()); // r3: discarded state. // Restore context and frame pointer, discard state (r3).
ldm(ia_w, sp, r3.bit() | cp.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 // If the handler is a JS frame, restore the context to the frame.
// JS entry frame. // (r3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any
cmp(fp, Operand(0, RelocInfo::NONE)); // of them.
// Set cp to NULL if fp is NULL. cmp(r3, Operand(StackHandler::ENTRY));
mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
// Restore cp otherwise.
ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
#ifdef DEBUG #ifdef DEBUG
if (emit_debug_code()) { if (emit_debug_code()) {
mov(lr, Operand(pc)); mov(lr, Operand(pc));
} }
#endif #endif
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(pc); pop(pc);
} }
@ -1194,8 +1194,12 @@ void MacroAssembler::Throw(Register value) {
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) { Register value) {
// Adjust this code if not the case. // 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. // r0 is expected to hold the exception.
if (!value.is(r0)) { if (!value.is(r0)) {
mov(r0, value); mov(r0, value);
@ -1220,7 +1224,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
bind(&done); bind(&done);
// Set the top handler address to next handler past the current ENTRY handler. // Set the top handler address to next handler past the current ENTRY handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r2); pop(r2);
str(r2, MemOperand(r3)); str(r2, MemOperand(r3));
@ -1242,26 +1245,17 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
// Stack layout at this point. See also StackHandlerConstants. // Stack layout at this point. See also StackHandlerConstants.
// sp -> state (ENTRY) // sp -> state (ENTRY)
// cp
// fp // fp
// lr // lr
// Discard handler state (r2 is not used) and restore frame pointer. // Restore context and frame pointer, discard state (r2).
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); ldm(ia_w, sp, r2.bit() | cp.bit() | fp.bit());
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);
#ifdef DEBUG #ifdef DEBUG
if (emit_debug_code()) { if (emit_debug_code()) {
mov(lr, Operand(pc)); mov(lr, Operand(pc));
} }
#endif #endif
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(pc); pop(pc);
} }

46
deps/v8/src/arm/stub-cache-arm.cc

@ -3489,9 +3489,9 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// Check that the index is in range. // Check that the index is in range.
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
__ cmp(ip, Operand(key, ASR, kSmiTagSize)); __ cmp(key, ip);
// Unsigned comparison catches both negative and too-large values. // 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)); __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage // 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 // This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi. // have been verified by the caller to not be a smi.
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the key is a smi. // Check that the key is a smi.
__ JumpIfNotSmi(key, &miss_force_generic); __ JumpIfNotSmi(key, &miss_force_generic);
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the index is in range // Check that the index is in range
__ SmiUntag(r4, key);
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
__ cmp(r4, ip); __ cmp(key, ip);
// Unsigned comparison catches both negative and too-large values. // Unsigned comparison catches both negative and too-large values.
__ b(hs, &miss_force_generic); __ b(hs, &miss_force_generic);
// Handle both smis and HeapNumbers in the fast path. Go to the // Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values. // runtime for all other kinds of values.
// r3: external array. // r3: external array.
// r4: key (integer).
if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) { if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
// Double to pixel conversion is only implemented in the runtime for now. // Double to pixel conversion is only implemented in the runtime for now.
__ JumpIfNotSmi(value, &slow); __ JumpIfNotSmi(value, &slow);
@ -3837,32 +3835,32 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage. // r3: base pointer of external storage.
// r4: key (integer).
// r5: value (integer). // r5: value (integer).
switch (elements_kind) { switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS: case JSObject::EXTERNAL_PIXEL_ELEMENTS:
// Clamp the value to [0..255]. // Clamp the value to [0..255].
__ Usat(r5, 8, Operand(r5)); __ Usat(r5, 8, Operand(r5));
__ strb(r5, MemOperand(r3, r4, LSL, 0)); __ strb(r5, MemOperand(r3, key, LSR, 1));
break; break;
case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, r4, LSL, 0)); __ strb(r5, MemOperand(r3, key, LSR, 1));
break; break;
case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, r4, LSL, 1)); __ strh(r5, MemOperand(r3, key, LSL, 0));
break; break;
case JSObject::EXTERNAL_INT_ELEMENTS: case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, r4, LSL, 2)); __ str(r5, MemOperand(r3, key, LSL, 1));
break; break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS: case JSObject::EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory. // Perform int-to-float conversion and store to memory.
__ SmiUntag(r4, key);
StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9); StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
break; break;
case JSObject::EXTERNAL_DOUBLE_ELEMENTS: 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 // r3: effective address of the double element
FloatingPointHelper::Destination destination; FloatingPointHelper::Destination destination;
if (CpuFeatures::IsSupported(VFP3)) { if (CpuFeatures::IsSupported(VFP3)) {
@ -3895,7 +3893,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) { if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
// r3: external array. // r3: external array.
// r4: index (integer).
__ bind(&check_heap_number); __ bind(&check_heap_number);
__ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE); __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
__ b(ne, &slow); __ b(ne, &slow);
@ -3903,7 +3900,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage. // r3: base pointer of external storage.
// r4: key (integer).
// The WebGL specification leaves the behavior of storing NaN and // The WebGL specification leaves the behavior of storing NaN and
// +/-Infinity into integer arrays basically undefined. For more // +/-Infinity into integer arrays basically undefined. For more
@ -3916,13 +3912,13 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// include -kHeapObjectTag into it. // include -kHeapObjectTag into it.
__ sub(r5, r0, Operand(kHeapObjectTag)); __ sub(r5, r0, Operand(kHeapObjectTag));
__ vldr(d0, r5, HeapNumber::kValueOffset); __ vldr(d0, r5, HeapNumber::kValueOffset);
__ add(r5, r3, Operand(r4, LSL, 2)); __ add(r5, r3, Operand(key, LSL, 1));
__ vcvt_f32_f64(s0, d0); __ vcvt_f32_f64(s0, d0);
__ vstr(s0, r5, 0); __ vstr(s0, r5, 0);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
__ sub(r5, r0, Operand(kHeapObjectTag)); __ sub(r5, r0, Operand(kHeapObjectTag));
__ vldr(d0, r5, HeapNumber::kValueOffset); __ vldr(d0, r5, HeapNumber::kValueOffset);
__ add(r5, r3, Operand(r4, LSL, 3)); __ add(r5, r3, Operand(key, LSL, 2));
__ vstr(d0, r5, 0); __ vstr(d0, r5, 0);
} else { } else {
// Hoisted load. vldr requires offset to be a multiple of 4 so we can // Hoisted load. vldr requires offset to be a multiple of 4 so we can
@ -3934,15 +3930,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
switch (elements_kind) { switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, r4, LSL, 0)); __ strb(r5, MemOperand(r3, key, LSR, 1));
break; break;
case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, r4, LSL, 1)); __ strh(r5, MemOperand(r3, key, LSL, 0));
break; break;
case JSObject::EXTERNAL_INT_ELEMENTS: case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, r4, LSL, 2)); __ str(r5, MemOperand(r3, key, LSL, 1));
break; break;
case JSObject::EXTERNAL_PIXEL_ELEMENTS: case JSObject::EXTERNAL_PIXEL_ELEMENTS:
case JSObject::EXTERNAL_FLOAT_ELEMENTS: case JSObject::EXTERNAL_FLOAT_ELEMENTS:
@ -4004,7 +4000,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift)); __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
__ bind(&done); __ 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 // Entry registers are intact, r0 holds the value which is the return
// value. // value.
__ Ret(); __ Ret();
@ -4017,7 +4013,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift)); __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
__ b(&done); __ b(&done);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { } 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. // r7: effective address of destination element.
__ str(r6, MemOperand(r7, 0)); __ str(r6, MemOperand(r7, 0));
__ str(r5, MemOperand(r7, Register::kSizeInBytes)); __ str(r5, MemOperand(r7, Register::kSizeInBytes));
@ -4073,15 +4069,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
switch (elements_kind) { switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, r4, LSL, 0)); __ strb(r5, MemOperand(r3, key, LSR, 1));
break; break;
case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, r4, LSL, 1)); __ strh(r5, MemOperand(r3, key, LSL, 0));
break; break;
case JSObject::EXTERNAL_INT_ELEMENTS: case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, r4, LSL, 2)); __ str(r5, MemOperand(r3, key, LSL, 1));
break; break;
case JSObject::EXTERNAL_PIXEL_ELEMENTS: case JSObject::EXTERNAL_PIXEL_ELEMENTS:
case JSObject::EXTERNAL_FLOAT_ELEMENTS: case JSObject::EXTERNAL_FLOAT_ELEMENTS:

3
deps/v8/src/ast-inl.h

@ -50,7 +50,8 @@ Block::Block(Isolate* isolate,
bool is_initializer_block) bool is_initializer_block)
: BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY), : BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY),
statements_(capacity), statements_(capacity),
is_initializer_block_(is_initializer_block) { is_initializer_block_(is_initializer_block),
block_scope_(NULL) {
} }

2
deps/v8/src/ast.cc

@ -426,7 +426,7 @@ bool ForInStatement::IsInlineable() const {
} }
bool EnterWithContextStatement::IsInlineable() const { bool WithStatement::IsInlineable() const {
return false; return false;
} }

22
deps/v8/src/ast.h

@ -60,7 +60,7 @@ namespace internal {
V(ContinueStatement) \ V(ContinueStatement) \
V(BreakStatement) \ V(BreakStatement) \
V(ReturnStatement) \ V(ReturnStatement) \
V(EnterWithContextStatement) \ V(WithStatement) \
V(ExitContextStatement) \ V(ExitContextStatement) \
V(SwitchStatement) \ V(SwitchStatement) \
V(DoWhileStatement) \ V(DoWhileStatement) \
@ -359,9 +359,13 @@ class Block: public BreakableStatement {
ZoneList<Statement*>* statements() { return &statements_; } ZoneList<Statement*>* statements() { return &statements_; }
bool is_initializer_block() const { return is_initializer_block_; } 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: private:
ZoneList<Statement*> statements_; ZoneList<Statement*> statements_;
bool is_initializer_block_; bool is_initializer_block_;
Scope* block_scope_;
}; };
@ -371,9 +375,11 @@ class Declaration: public AstNode {
: proxy_(proxy), : proxy_(proxy),
mode_(mode), mode_(mode),
fun_(fun) { 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... // 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) DECLARE_NODE_TYPE(Declaration)
@ -627,19 +633,21 @@ class ReturnStatement: public Statement {
}; };
class EnterWithContextStatement: public Statement { class WithStatement: public Statement {
public: public:
explicit EnterWithContextStatement(Expression* expression) WithStatement(Expression* expression, Statement* statement)
: expression_(expression) { } : expression_(expression), statement_(statement) { }
DECLARE_NODE_TYPE(EnterWithContextStatement) DECLARE_NODE_TYPE(WithStatement)
Expression* expression() const { return expression_; } Expression* expression() const { return expression_; }
Statement* statement() const { return statement_; }
virtual bool IsInlineable() const; virtual bool IsInlineable() const;
private: private:
Expression* expression_; Expression* expression_;
Statement* statement_;
}; };

5
deps/v8/src/bootstrapper.cc

@ -1198,7 +1198,6 @@ void Genesis::InitializeExperimentalGlobal() {
// TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no // TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no
// longer need to live behind a flag, so WeakMap gets added to the snapshot. // 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 if (FLAG_harmony_weakmaps) { // -- W e a k M a p
Handle<JSFunction> weakmap_fun =
InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize, InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
isolate->initial_object_prototype(), isolate->initial_object_prototype(),
Builtins::kIllegal, true); Builtins::kIllegal, true);
@ -1587,8 +1586,6 @@ bool Genesis::InstallNatives() {
global_context()->set_string_function_prototype_map( global_context()->set_string_function_prototype_map(
HeapObject::cast(string_function->initial_map()->prototype())->map()); HeapObject::cast(string_function->initial_map()->prototype())->map());
InstallBuiltinFunctionIds();
// Install Function.prototype.call and apply. // Install Function.prototype.call and apply.
{ Handle<String> key = factory()->function_class_symbol(); { Handle<String> key = factory()->function_class_symbol();
Handle<JSFunction> function = Handle<JSFunction> function =
@ -1622,6 +1619,8 @@ bool Genesis::InstallNatives() {
apply->shared()->set_length(2); apply->shared()->set_length(2);
} }
InstallBuiltinFunctionIds();
// Create a constructor for RegExp results (a variant of Array that // Create a constructor for RegExp results (a variant of Array that
// predefines the two properties index and match). // predefines the two properties index and match).
{ {

20
deps/v8/src/code-stubs.cc

@ -340,12 +340,11 @@ void ToBooleanStub::Types::Print(StringStream* stream) const {
if (IsEmpty()) stream->Add("None"); if (IsEmpty()) stream->Add("None");
if (Contains(UNDEFINED)) stream->Add("Undefined"); if (Contains(UNDEFINED)) stream->Add("Undefined");
if (Contains(BOOLEAN)) stream->Add("Bool"); if (Contains(BOOLEAN)) stream->Add("Bool");
if (Contains(SMI)) stream->Add("Smi");
if (Contains(NULL_TYPE)) stream->Add("Null"); if (Contains(NULL_TYPE)) stream->Add("Null");
if (Contains(SMI)) stream->Add("Smi");
if (Contains(SPEC_OBJECT)) stream->Add("SpecObject"); if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
if (Contains(STRING)) stream->Add("String"); if (Contains(STRING)) stream->Add("String");
if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber"); 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() && return !object->IsUndetectableObject() &&
String::cast(*object)->length() != 0; String::cast(*object)->length() != 0;
} else if (object->IsHeapNumber()) { } else if (object->IsHeapNumber()) {
ASSERT(!object->IsUndetectableObject());
Add(HEAP_NUMBER); Add(HEAP_NUMBER);
double value = HeapNumber::cast(*object)->value(); double value = HeapNumber::cast(*object)->value();
return !object->IsUndetectableObject() && value != 0 && !isnan(value); return value != 0 && !isnan(value);
} else { } else {
Add(INTERNAL_OBJECT); // We should never see an internal object at runtime here!
return !object->IsUndetectableObject(); UNREACHABLE();
return true;
} }
} }
@ -398,8 +399,13 @@ bool ToBooleanStub::Types::Record(Handle<Object> object) {
bool ToBooleanStub::Types::NeedsMap() const { bool ToBooleanStub::Types::NeedsMap() const {
return Contains(ToBooleanStub::SPEC_OBJECT) return Contains(ToBooleanStub::SPEC_OBJECT)
|| Contains(ToBooleanStub::STRING) || Contains(ToBooleanStub::STRING)
|| Contains(ToBooleanStub::HEAP_NUMBER) || Contains(ToBooleanStub::HEAP_NUMBER);
|| Contains(ToBooleanStub::INTERNAL_OBJECT); }
bool ToBooleanStub::Types::CanBeUndetectable() const {
return Contains(ToBooleanStub::SPEC_OBJECT)
|| Contains(ToBooleanStub::STRING);
} }

6
deps/v8/src/code-stubs.h

@ -908,7 +908,6 @@ class ToBooleanStub: public CodeStub {
SPEC_OBJECT, SPEC_OBJECT,
STRING, STRING,
HEAP_NUMBER, HEAP_NUMBER,
INTERNAL_OBJECT,
NUMBER_OF_TYPES NUMBER_OF_TYPES
}; };
@ -922,7 +921,6 @@ class ToBooleanStub: public CodeStub {
explicit Types(byte bits) : set_(bits) {} explicit Types(byte bits) : set_(bits) {}
bool IsEmpty() const { return set_.IsEmpty(); } 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); } bool Contains(Type type) const { return set_.Contains(type); }
void Add(Type type) { set_.Add(type); } void Add(Type type) { set_.Add(type); }
byte ToByte() const { return set_.ToIntegral(); } byte ToByte() const { return set_.ToIntegral(); }
@ -930,6 +928,7 @@ class ToBooleanStub: public CodeStub {
void TraceTransition(Types to) const; void TraceTransition(Types to) const;
bool Record(Handle<Object> object); bool Record(Handle<Object> object);
bool NeedsMap() const; bool NeedsMap() const;
bool CanBeUndetectable() const;
private: private:
EnumSet<Type, byte> set_; EnumSet<Type, byte> set_;
@ -956,8 +955,7 @@ class ToBooleanStub: public CodeStub {
void CheckOddball(MacroAssembler* masm, void CheckOddball(MacroAssembler* masm,
Type type, Type type,
Heap::RootListIndex value, Heap::RootListIndex value,
bool result, bool result);
Label* patch);
void GenerateTypeTransition(MacroAssembler* masm); void GenerateTypeTransition(MacroAssembler* masm);
Register tos_; Register tos_;

10
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 // that would be compiled lazily anyway, so we skip the preparse step
// in that case too. // in that case too.
ScriptDataImpl* pre_data = input_pre_data; ScriptDataImpl* pre_data = input_pre_data;
bool harmony_block_scoping = natives != NATIVES_CODE &&
FLAG_harmony_block_scoping;
if (pre_data == NULL if (pre_data == NULL
&& source_length >= FLAG_min_preparse_length) { && source_length >= FLAG_min_preparse_length) {
if (source->IsExternalTwoByteString()) { if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUC16CharacterStream stream( ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length()); Handle<ExternalTwoByteString>::cast(source), 0, source->length());
pre_data = ParserApi::PartialPreParse(&stream, extension); pre_data = ParserApi::PartialPreParse(&stream,
extension,
harmony_block_scoping);
} else { } else {
GenericStringUC16CharacterStream stream(source, 0, source->length()); GenericStringUC16CharacterStream stream(source, 0, source->length());
pre_data = ParserApi::PartialPreParse(&stream, extension); pre_data = ParserApi::PartialPreParse(&stream,
extension,
harmony_block_scoping);
} }
} }

21
deps/v8/src/contexts.cc

@ -109,7 +109,7 @@ Handle<Object> Context::Lookup(Handle<String> name,
} }
// Check extension/with/global object. // Check extension/with/global object.
if (context->has_extension()) { if (!context->IsBlockContext() && context->has_extension()) {
if (context->IsCatchContext()) { if (context->IsCatchContext()) {
// Catch contexts have the variable name in the extension slot. // Catch contexts have the variable name in the extension slot.
if (name->Equals(String::cast(context->extension()))) { if (name->Equals(String::cast(context->extension()))) {
@ -121,6 +121,9 @@ Handle<Object> Context::Lookup(Handle<String> name,
return context; return context;
} }
} else { } else {
ASSERT(context->IsGlobalContext() ||
context->IsFunctionContext() ||
context->IsWithContext());
// Global, function, and with contexts may have an object in the // Global, function, and with contexts may have an object in the
// extension slot. // extension slot.
Handle<JSObject> extension(JSObject::cast(context->extension()), 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. // Check serialized scope information of functions and blocks. Only
if (context->IsFunctionContext()) { // functions can have parameters, and a function name.
if (context->IsFunctionContext() || context->IsBlockContext()) {
// We may have context-local slots. Check locals in the context. // We may have context-local slots. Check locals in the context.
Handle<SerializedScopeInfo> scope_info( Handle<SerializedScopeInfo> scope_info;
if (context->IsFunctionContext()) {
scope_info = Handle<SerializedScopeInfo>(
context->closure()->shared()->scope_info(), isolate); context->closure()->shared()->scope_info(), isolate);
} else {
ASSERT(context->IsBlockContext());
scope_info = Handle<SerializedScopeInfo>(
SerializedScopeInfo::cast(context->extension()), isolate);
}
Variable::Mode mode; Variable::Mode mode;
int index = scope_info->ContextSlotIndex(*name, &mode); int index = scope_info->ContextSlotIndex(*name, &mode);
ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS); ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
@ -168,6 +180,7 @@ Handle<Object> Context::Lookup(Handle<String> name,
switch (mode) { switch (mode) {
case Variable::INTERNAL: // Fall through. case Variable::INTERNAL: // Fall through.
case Variable::VAR: case Variable::VAR:
case Variable::LET:
*attributes = NONE; *attributes = NONE;
break; break;
case Variable::CONST: case Variable::CONST:

4
deps/v8/src/contexts.h

@ -295,6 +295,10 @@ class Context: public FixedArray {
Map* map = this->map(); Map* map = this->map();
return map == map->GetHeap()->with_context_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. // Tells whether the global context is marked with out of memory.
inline bool has_out_of_memory(); inline bool has_out_of_memory();

1
deps/v8/src/d8.cc

@ -740,6 +740,7 @@ Persistent<Context> Shell::CreateEvaluationContext() {
// Initialize the global objects // Initialize the global objects
Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
Persistent<Context> context = Context::New(NULL, global_template); Persistent<Context> context = Context::New(NULL, global_template);
ASSERT(!context.IsEmpty());
Context::Scope scope(context); Context::Scope scope(context);
#ifndef V8_SHARED #ifndef V8_SHARED

4
deps/v8/src/d8.h

@ -39,10 +39,6 @@
namespace v8 { namespace v8 {
#ifndef V8_SHARED
namespace i = v8::internal;
#endif // V8_SHARED
#ifndef V8_SHARED #ifndef V8_SHARED
// A single counter in a counter collection. // A single counter in a counter collection.

3
deps/v8/src/d8.js

@ -103,7 +103,8 @@ Debug.ScopeType = { Global: 0,
Local: 1, Local: 1,
With: 2, With: 2,
Closure: 3, Closure: 3,
Catch: 4 }; Catch: 4,
Block: 5 };
// Current debug state. // Current debug state.

36
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) { if (f == NULL) {
PrintF("%s", buff); PrintF("%s\n", out->Finalize());
} else { } else {
fprintf(f, "%s", buff); fprintf(f, "%s\n", out->Finalize());
} }
out->Reset();
} }
static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength; static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
static const int kRelocInfoPosition = 57; 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, 128> decode_buffer;
v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer; v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
StringBuilder out(out_buffer.start(), out_buffer.length());
byte* pc = begin; byte* pc = begin;
disasm::Disassembler d(converter); disasm::Disassembler d(converter);
RelocIterator* it = NULL; RelocIterator* it = NULL;
@ -181,17 +185,12 @@ static int DecodeIt(FILE* f,
} }
} }
StringBuilder out(out_buffer.start(), out_buffer.length());
// Comments. // Comments.
for (int i = 0; i < comments.length(); i++) { 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. // Instruction address and instruction offset.
out.AddFormatted("%p %4d ", prev_pc, prev_pc - begin); out.AddFormatted("%p %4d ", prev_pc, prev_pc - begin);
@ -209,7 +208,7 @@ static int DecodeIt(FILE* f,
out.AddPadding(' ', kRelocInfoPosition - out.position()); out.AddPadding(' ', kRelocInfoPosition - out.position());
} else { } else {
// Additional reloc infos are printed on separate lines. // Additional reloc infos are printed on separate lines.
out.AddFormatted("\n"); DumpBuffer(f, &out);
out.AddPadding(' ', kRelocInfoPosition); out.AddPadding(' ', kRelocInfoPosition);
} }
@ -299,9 +298,18 @@ static int DecodeIt(FILE* f,
out.AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode)); out.AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode));
} }
} }
out.AddString("\n"); DumpBuffer(f, &out);
DumpBuffer(f, out.Finalize()); }
out.Reset();
// 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; delete it;

80
deps/v8/src/elements.cc

@ -75,9 +75,8 @@ class ElementsAccessorBase : public ElementsAccessor {
virtual MaybeObject* GetWithReceiver(JSObject* obj, virtual MaybeObject* GetWithReceiver(JSObject* obj,
Object* receiver, Object* receiver,
uint32_t index) { uint32_t index) {
if (index < ElementsAccessorSubclass::GetLength(obj)) { BackingStoreClass* backing_store = BackingStoreClass::cast(obj->elements());
BackingStoreClass* backing_store = if (index < ElementsAccessorSubclass::GetLength(backing_store)) {
ElementsAccessorSubclass::GetBackingStore(obj);
return backing_store->get(index); return backing_store->get(index);
} }
return obj->GetHeap()->the_hole_value(); return obj->GetHeap()->the_hole_value();
@ -87,39 +86,39 @@ class ElementsAccessorBase : public ElementsAccessor {
uint32_t index, uint32_t index,
JSReceiver::DeleteMode mode) = 0; JSReceiver::DeleteMode mode) = 0;
virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other, virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from,
FixedArray* keys) { FixedArray* to) {
int len0 = keys->length(); int len0 = to->length();
#ifdef DEBUG #ifdef DEBUG
if (FLAG_enable_slow_asserts) { if (FLAG_enable_slow_asserts) {
for (int i = 0; i < len0; i++) { for (int i = 0; i < len0; i++) {
ASSERT(keys->get(i)->IsString() || keys->get(i)->IsNumber()); ASSERT(!to->get(i)->IsTheHole());
} }
} }
#endif #endif
int len1 = ElementsAccessorSubclass::GetCapacity(other); BackingStoreClass* backing_store = BackingStoreClass::cast(from);
int len1 = ElementsAccessorSubclass::GetCapacity(backing_store);
// Optimize if 'other' is empty. // Optimize if 'other' is empty.
// We cannot optimize if 'this' is empty, as other may have holes // We cannot optimize if 'this' is empty, as other may have holes.
// or non keys. if (len1 == 0) return to;
if (len1 == 0) return keys;
// Compute how many elements are not in other. // Compute how many elements are not in other.
int extra = 0; int extra = 0;
for (int y = 0; y < len1; y++) { for (int y = 0; y < len1; y++) {
Object* value; Object* value;
MaybeObject* maybe_value = MaybeObject* maybe_value =
ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y); ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y);
if (!maybe_value->ToObject(&value)) return maybe_value; 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 // Allocate the result
FixedArray* result; FixedArray* result;
MaybeObject* maybe_obj = MaybeObject* maybe_obj =
other->GetHeap()->AllocateFixedArray(len0 + extra); backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj; if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
// Fill in the content // Fill in the content
@ -127,20 +126,19 @@ class ElementsAccessorBase : public ElementsAccessor {
AssertNoAllocation no_gc; AssertNoAllocation no_gc;
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
for (int i = 0; i < len0; i++) { for (int i = 0; i < len0; i++) {
Object* e = keys->get(i); Object* e = to->get(i);
ASSERT(e->IsString() || e->IsNumber()); ASSERT(e->IsString() || e->IsNumber());
result->set(i, e, mode); result->set(i, e, mode);
} }
} }
// Fill in the extra keys. // Fill in the extra values.
int index = 0; int index = 0;
for (int y = 0; y < len1; y++) { for (int y = 0; y < len1; y++) {
MaybeObject* maybe_value = MaybeObject* maybe_value =
ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y); ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y);
Object* value; Object* value;
if (!maybe_value->ToObject(&value)) return maybe_value; if (!maybe_value->ToObject(&value)) return maybe_value;
if (!value->IsTheHole() && !HasKey(keys, value)) { if (!value->IsTheHole() && !HasKey(to, value)) {
ASSERT(value->IsString() || value->IsNumber());
result->set(len0 + index, value); result->set(len0 + index, value);
index++; index++;
} }
@ -149,23 +147,18 @@ class ElementsAccessorBase : public ElementsAccessor {
return result; return result;
} }
static uint32_t GetCapacity(JSObject* obj) { static uint32_t GetLength(BackingStoreClass* backing_store) {
return ElementsAccessorSubclass::GetBackingStore(obj)->length(); return backing_store->length();
} }
static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { static uint32_t GetCapacity(BackingStoreClass* backing_store) {
BackingStoreClass* backing_store = return GetLength(backing_store);
ElementsAccessorSubclass::GetBackingStore(obj);
return backing_store->get(index);
}
protected:
static BackingStoreClass* GetBackingStore(JSObject* obj) {
return BackingStoreClass::cast(obj->elements());
} }
static uint32_t GetLength(JSObject* obj) { static MaybeObject* GetElementAtCapacityIndex(
return ElementsAccessorSubclass::GetBackingStore(obj)->length(); BackingStoreClass* backing_store,
int index) {
return backing_store->get(index);
} }
private: private:
@ -255,9 +248,8 @@ class ExternalElementsAccessor
virtual MaybeObject* GetWithReceiver(JSObject* obj, virtual MaybeObject* GetWithReceiver(JSObject* obj,
Object* receiver, Object* receiver,
uint32_t index) { uint32_t index) {
if (index < ExternalElementsAccessorSubclass::GetLength(obj)) { ExternalArray* backing_store = ExternalArray::cast(obj->elements());
ExternalArray* backing_store = if (index < ExternalElementsAccessorSubclass::GetLength(backing_store)) {
ExternalElementsAccessorSubclass::GetBackingStore(obj);
return backing_store->get(index); return backing_store->get(index);
} else { } else {
return obj->GetHeap()->undefined_value(); return obj->GetHeap()->undefined_value();
@ -412,16 +404,16 @@ class DictionaryElementsAccessor
index); index);
} }
static uint32_t GetCapacity(JSObject* obj) { static uint32_t GetCapacity(NumberDictionary* dict) {
return obj->element_dictionary()->Capacity(); return dict->Capacity();
} }
static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { static MaybeObject* GetElementAtCapacityIndex(NumberDictionary* dict,
NumberDictionary* dict = obj->element_dictionary(); int index) {
if (dict->IsKey(dict->KeyAt(index))) { if (dict->IsKey(dict->KeyAt(index))) {
return dict->ValueAt(index); return dict->ValueAt(index);
} else { } else {
return obj->GetHeap()->the_hole_value(); return dict->GetHeap()->the_hole_value();
} }
} }
}; };
@ -434,7 +426,7 @@ class NonStrictArgumentsElementsAccessor
virtual MaybeObject* GetWithReceiver(JSObject* obj, virtual MaybeObject* GetWithReceiver(JSObject* obj,
Object* receiver, Object* receiver,
uint32_t index) { uint32_t index) {
FixedArray* parameter_map = GetBackingStore(obj); FixedArray* parameter_map = FixedArray::cast(obj->elements());
uint32_t length = parameter_map->length(); uint32_t length = parameter_map->length();
Object* probe = Object* probe =
(index < length - 2) ? parameter_map->get(index + 2) : NULL; (index < length - 2) ? parameter_map->get(index + 2) : NULL;
@ -482,13 +474,13 @@ class NonStrictArgumentsElementsAccessor
return obj->GetHeap()->true_value(); 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 // TODO(danno): Return max of parameter map length or backing store
// capacity. // capacity.
return 0; 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 // TODO(danno): Return either value from parameter map of backing
// store value at index. // store value at index.
return obj->GetHeap()->the_hole_value(); return obj->GetHeap()->the_hole_value();

4
deps/v8/src/elements.h

@ -47,8 +47,8 @@ class ElementsAccessor {
uint32_t index, uint32_t index,
JSReceiver::DeleteMode mode) = 0; JSReceiver::DeleteMode mode) = 0;
virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other, virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from,
FixedArray* keys) = 0; FixedArray* to) = 0;
// Returns a shared ElementsAccessor for the specified ElementsKind. // Returns a shared ElementsAccessor for the specified ElementsKind.
static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) { static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) {

2
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) { v8::Handle<v8::Value> DateTimeFormat::GetWeekdays(const v8::Arguments& args) {
icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder()); icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
if (!date_format) { if (!date_format) {
ThrowUnexpectedObjectError(); return ThrowUnexpectedObjectError();
} }
const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols(); const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();

22
deps/v8/src/factory.cc

@ -34,6 +34,7 @@
#include "macro-assembler.h" #include "macro-assembler.h"
#include "objects.h" #include "objects.h"
#include "objects-visiting.h" #include "objects-visiting.h"
#include "scopeinfo.h"
namespace v8 { namespace v8 {
namespace internal { 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) { Handle<Struct> Factory::NewStruct(InstanceType type) {
CALL_HEAP_FUNCTION( CALL_HEAP_FUNCTION(
isolate(), 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, Handle<Code> Factory::NewCode(const CodeDesc& desc,
Code::Flags flags, Code::Flags flags,
Handle<Object> self_ref, Handle<Object> self_ref,

7
deps/v8/src/factory.h

@ -167,6 +167,11 @@ class Factory {
Handle<Context> previous, Handle<Context> previous,
Handle<JSObject> extension); 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. // Return the Symbol matching the passed in string.
Handle<String> SymbolFromString(Handle<String> value); Handle<String> SymbolFromString(Handle<String> value);
@ -277,6 +282,8 @@ class Factory {
Handle<Context> context, Handle<Context> context,
PretenureFlag pretenure = TENURED); PretenureFlag pretenure = TENURED);
Handle<SerializedScopeInfo> NewSerializedScopeInfo(int length);
Handle<Code> NewCode(const CodeDesc& desc, Handle<Code> NewCode(const CodeDesc& desc,
Code::Flags flags, Code::Flags flags,
Handle<Object> self_reference, Handle<Object> self_reference,

2
deps/v8/src/flag-definitions.h

@ -97,8 +97,10 @@ private:
#define FLAG FLAG_FULL #define FLAG FLAG_FULL
// Flags for experimental language features. // 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_proxies, false, "enable harmony proxies")
DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps") DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps")
DEFINE_bool(harmony_block_scoping, false, "enable harmony block scoping")
// Flags for experimental implementation features. // Flags for experimental implementation features.
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles") DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")

9
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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -67,6 +67,7 @@ inline bool StackHandler::includes(Address address) const {
inline void StackHandler::Iterate(ObjectVisitor* v, Code* holder) const { inline void StackHandler::Iterate(ObjectVisitor* v, Code* holder) const {
v->VisitPointer(context_address());
StackFrame::IteratePc(v, pc_address(), holder); 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 { inline Address* StackHandler::pc_address() const {
const int offset = StackHandlerConstants::kPCOffset; const int offset = StackHandlerConstants::kPCOffset;
return reinterpret_cast<Address*>(address() + offset); return reinterpret_cast<Address*>(address() + offset);

3
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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -114,6 +114,7 @@ class StackHandler BASE_EMBEDDED {
// Accessors. // Accessors.
inline State state() const; inline State state() const;
inline Object** context_address() const;
inline Address* pc_address() const; inline Address* pc_address() const;
DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler); DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);

94
deps/v8/src/full-codegen.cc

@ -35,6 +35,7 @@
#include "macro-assembler.h" #include "macro-assembler.h"
#include "prettyprinter.h" #include "prettyprinter.h"
#include "scopes.h" #include "scopes.h"
#include "scopeinfo.h"
#include "stub-cache.h" #include "stub-cache.h"
namespace v8 { namespace v8 {
@ -90,8 +91,7 @@ void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
} }
void BreakableStatementChecker::VisitEnterWithContextStatement( void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) {
EnterWithContextStatement* stmt) {
Visit(stmt->expression()); 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 // field, and then a sequence of entries. Each entry is a pair of AST id
// and code-relative pc offset. // and code-relative pc offset.
masm()->Align(kIntSize); masm()->Align(kIntSize);
masm()->RecordComment("[ Stack check table");
unsigned offset = masm()->pc_offset(); unsigned offset = masm()->pc_offset();
unsigned length = stack_checks_.length(); unsigned length = stack_checks_.length();
__ dd(length); __ dd(length);
@ -325,7 +324,6 @@ unsigned FullCodeGenerator::EmitStackCheckTable() {
__ dd(stack_checks_[i].id); __ dd(stack_checks_[i].id);
__ dd(stack_checks_[i].pc_and_state); __ dd(stack_checks_[i].pc_and_state);
} }
masm()->RecordComment("]");
return offset; return offset;
} }
@ -847,8 +845,23 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
Breakable nested_statement(this, stmt); Breakable nested_statement(this, stmt);
SetStatementPosition(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); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
VisitStatements(stmt->statements()); VisitStatements(stmt->statements());
scope_ = saved_scope;
__ bind(nested_statement.break_target()); __ bind(nested_statement.break_target());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
} }
@ -900,16 +913,24 @@ void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
SetStatementPosition(stmt); SetStatementPosition(stmt);
NestedStatement* current = nesting_stack_; NestedStatement* current = nesting_stack_;
int stack_depth = 0; int stack_depth = 0;
int context_length = 0;
// When continuing, we clobber the unpredictable value in the accumulator // 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 // 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 // try...finally on our way out, we will unconditionally preserve the
// accumulator on the stack. // accumulator on the stack.
ClearAccumulator(); ClearAccumulator();
while (!current->IsContinueTarget(stmt->target())) { while (!current->IsContinueTarget(stmt->target())) {
stack_depth = current->Exit(stack_depth); current = current->Exit(&stack_depth, &context_length);
current = current->outer();
} }
__ Drop(stack_depth); __ 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(); Iteration* loop = current->AsIteration();
__ jmp(loop->continue_target()); __ jmp(loop->continue_target());
@ -921,16 +942,24 @@ void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
SetStatementPosition(stmt); SetStatementPosition(stmt);
NestedStatement* current = nesting_stack_; NestedStatement* current = nesting_stack_;
int stack_depth = 0; int stack_depth = 0;
int context_length = 0;
// When breaking, we clobber the unpredictable value in the accumulator // 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 // 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 // try...finally on our way out, we will unconditionally preserve the
// accumulator on the stack. // accumulator on the stack.
ClearAccumulator(); ClearAccumulator();
while (!current->IsBreakTarget(stmt->target())) { while (!current->IsBreakTarget(stmt->target())) {
stack_depth = current->Exit(stack_depth); current = current->Exit(&stack_depth, &context_length);
current = current->outer();
} }
__ Drop(stack_depth); __ 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(); Breakable* target = current->AsBreakable();
__ jmp(target->break_target()); __ jmp(target->break_target());
@ -946,9 +975,9 @@ void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
// Exit all nested statements. // Exit all nested statements.
NestedStatement* current = nesting_stack_; NestedStatement* current = nesting_stack_;
int stack_depth = 0; int stack_depth = 0;
int context_length = 0;
while (current != NULL) { while (current != NULL) {
stack_depth = current->Exit(stack_depth); current = current->Exit(&stack_depth, &context_length);
current = current->outer();
} }
__ Drop(stack_depth); __ Drop(stack_depth);
@ -956,9 +985,8 @@ void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
} }
void FullCodeGenerator::VisitEnterWithContextStatement( void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
EnterWithContextStatement* stmt) { Comment cmnt(masm_, "[ WithStatement");
Comment cmnt(masm_, "[ EnterWithContextStatement");
SetStatementPosition(stmt); SetStatementPosition(stmt);
VisitForStackValue(stmt->expression()); VisitForStackValue(stmt->expression());
@ -966,6 +994,15 @@ void FullCodeGenerator::VisitEnterWithContextStatement(
__ CallRuntime(Runtime::kPushWithContext, 2); __ CallRuntime(Runtime::kPushWithContext, 2);
decrement_stack_height(); decrement_stack_height();
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); 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* saved_scope = scope();
scope_ = stmt->scope(); scope_ = stmt->scope();
ASSERT(scope_->declarations()->is_empty()); ASSERT(scope_->declarations()->is_empty());
{ WithOrCatch body(this);
Visit(stmt->catch_block()); Visit(stmt->catch_block());
}
scope_ = saved_scope; scope_ = saved_scope;
__ jmp(&done); __ jmp(&done);
@ -1170,8 +1209,8 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
Label try_handler_setup; Label try_handler_setup;
const int original_stack_height = stack_height(); const int original_stack_height = stack_height();
const int finally_block_stack_height = original_stack_height + 2; const int finally_block_stack_height = original_stack_height + 2;
const int try_block_stack_height = original_stack_height + 4; const int try_block_stack_height = original_stack_height + 5;
STATIC_ASSERT(StackHandlerConstants::kSize / kPointerSize == 4); STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
// Setup the try-handler chain. Use a call to // Setup the try-handler chain. Use a call to
// Jump to try-handler setup and try-block code. Use call to put try-handler // 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. // The macros used here must preserve the result register.
__ Drop(stack_depth); __ Drop(*stack_depth);
__ PopTryHandler(); __ PopTryHandler();
*stack_depth = 0;
Register context = FullCodeGenerator::context_register();
while (*context_length > 0) {
codegen_->LoadContextField(context, Context::PREVIOUS_INDEX);
--(*context_length);
}
__ Call(finally_entry_); __ 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. // The macros used here must preserve the result register.
__ Drop(stack_depth); __ Drop(*stack_depth);
__ PopTryHandler(); __ PopTryHandler();
return 0; *stack_depth = 0;
return previous_;
} }

53
deps/v8/src/full-codegen.h

@ -140,25 +140,19 @@ class FullCodeGenerator: public AstVisitor {
virtual bool IsContinueTarget(Statement* target) { return false; } virtual bool IsContinueTarget(Statement* target) { return false; }
virtual bool IsBreakTarget(Statement* target) { return false; } virtual bool IsBreakTarget(Statement* target) { return false; }
// Generate code to leave the nested statement. This includes // Notify the statement that we are exiting it via break, continue, or
// cleaning up any stack elements in use and restoring the // return and give it a chance to generate cleanup code. Return the
// stack to the expectations of the surrounding statements. // next outer statement in the nesting stack. We accumulate in
// Takes a number of stack elements currently on top of the // *stack_depth the amount to drop the stack and in *context_length the
// nested statement's stack, and returns a number of stack // number of context chain links to unwind as we traverse the nesting
// elements left on top of the surrounding statement's stack. // stack from an exit to its target.
// The generated code must preserve the result register (which virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
// contains the value in case of a return). return previous_;
virtual int Exit(int stack_depth) {
// Default implementation for the case where there is
// nothing to clean up.
return stack_depth;
} }
NestedStatement* outer() { return previous_; }
protected: protected:
MacroAssembler* masm() { return codegen_->masm(); } MacroAssembler* masm() { return codegen_->masm(); }
private:
FullCodeGenerator* codegen_; FullCodeGenerator* codegen_;
NestedStatement* previous_; NestedStatement* previous_;
DISALLOW_COPY_AND_ASSIGN(NestedStatement); DISALLOW_COPY_AND_ASSIGN(NestedStatement);
@ -207,7 +201,7 @@ class FullCodeGenerator: public AstVisitor {
virtual ~TryCatch() {} virtual ~TryCatch() {}
virtual TryCatch* AsTryCatch() { return this; } virtual TryCatch* AsTryCatch() { return this; }
Label* catch_entry() { return catch_entry_; } Label* catch_entry() { return catch_entry_; }
virtual int Exit(int stack_depth); virtual NestedStatement* Exit(int* stack_depth, int* context_length);
private: private:
Label* catch_entry_; Label* catch_entry_;
DISALLOW_COPY_AND_ASSIGN(TryCatch); DISALLOW_COPY_AND_ASSIGN(TryCatch);
@ -221,7 +215,7 @@ class FullCodeGenerator: public AstVisitor {
virtual ~TryFinally() {} virtual ~TryFinally() {}
virtual TryFinally* AsTryFinally() { return this; } virtual TryFinally* AsTryFinally() { return this; }
Label* finally_entry() { return finally_entry_; } Label* finally_entry() { return finally_entry_; }
virtual int Exit(int stack_depth); virtual NestedStatement* Exit(int* stack_depth, int* context_length);
private: private:
Label* finally_entry_; Label* finally_entry_;
DISALLOW_COPY_AND_ASSIGN(TryFinally); DISALLOW_COPY_AND_ASSIGN(TryFinally);
@ -235,8 +229,9 @@ class FullCodeGenerator: public AstVisitor {
explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { } explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
virtual ~Finally() {} virtual ~Finally() {}
virtual Finally* AsFinally() { return this; } virtual Finally* AsFinally() { return this; }
virtual int Exit(int stack_depth) { virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
return stack_depth + kFinallyStackElementCount; *stack_depth += kFinallyStackElementCount;
return previous_;
} }
private: private:
// Number of extra stack slots occupied during a finally block. // Number of extra stack slots occupied during a finally block.
@ -254,14 +249,32 @@ class FullCodeGenerator: public AstVisitor {
: Iteration(codegen, statement) { } : Iteration(codegen, statement) { }
virtual ~ForIn() {} virtual ~ForIn() {}
virtual ForIn* AsForIn() { return this; } virtual ForIn* AsForIn() { return this; }
virtual int Exit(int stack_depth) { virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
return stack_depth + kForInStackElementCount; *stack_depth += kForInStackElementCount;
return previous_;
} }
private: private:
static const int kForInStackElementCount = 5; static const int kForInStackElementCount = 5;
DISALLOW_COPY_AND_ASSIGN(ForIn); 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 // The forward bailout stack keeps track of the expressions that can
// bail out to just before the control flow is split in a child // bail out to just before the control flow is split in a child
// node. The stack elements are linked together through the parent // node. The stack elements are linked together through the parent

43
deps/v8/src/heap.cc

@ -1745,6 +1745,12 @@ bool Heap::CreateInitialMaps() {
set_fixed_cow_array_map(Map::cast(obj)); set_fixed_cow_array_map(Map::cast(obj));
ASSERT(fixed_array_map() != fixed_cow_array_map()); 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); { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
if (!maybe_obj->ToObject(&obj)) return false; if (!maybe_obj->ToObject(&obj)) return false;
} }
@ -1906,6 +1912,12 @@ bool Heap::CreateInitialMaps() {
} }
set_with_context_map(Map::cast(obj)); set_with_context_map(Map::cast(obj));
{ MaybeObject* maybe_obj =
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_block_context_map(Map::cast(obj));
{ MaybeObject* maybe_obj = { MaybeObject* maybe_obj =
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false; if (!maybe_obj->ToObject(&obj)) return false;
@ -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) { MaybeObject* Heap::AllocateStruct(InstanceType type) {
Map* map; Map* map;
switch (type) { switch (type) {

14
deps/v8/src/heap.h

@ -65,6 +65,7 @@ inline Heap* _inline_get_heap_();
V(Map, heap_number_map, HeapNumberMap) \ V(Map, heap_number_map, HeapNumberMap) \
V(Map, global_context_map, GlobalContextMap) \ V(Map, global_context_map, GlobalContextMap) \
V(Map, fixed_array_map, FixedArrayMap) \ V(Map, fixed_array_map, FixedArrayMap) \
V(Map, serialized_scope_info_map, SerializedScopeInfoMap) \
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \ V(Map, fixed_cow_array_map, FixedCOWArrayMap) \
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \ V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \ V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \
@ -111,6 +112,7 @@ inline Heap* _inline_get_heap_();
V(Map, function_context_map, FunctionContextMap) \ V(Map, function_context_map, FunctionContextMap) \
V(Map, catch_context_map, CatchContextMap) \ V(Map, catch_context_map, CatchContextMap) \
V(Map, with_context_map, WithContextMap) \ V(Map, with_context_map, WithContextMap) \
V(Map, block_context_map, BlockContextMap) \
V(Map, code_map, CodeMap) \ V(Map, code_map, CodeMap) \
V(Map, oddball_map, OddballMap) \ V(Map, oddball_map, OddballMap) \
V(Map, global_property_cell_map, GlobalPropertyCellMap) \ V(Map, global_property_cell_map, GlobalPropertyCellMap) \
@ -160,6 +162,7 @@ inline Heap* _inline_get_heap_();
V(length_symbol, "length") \ V(length_symbol, "length") \
V(name_symbol, "name") \ V(name_symbol, "name") \
V(native_symbol, "native") \ V(native_symbol, "native") \
V(null_symbol, "null") \
V(number_symbol, "number") \ V(number_symbol, "number") \
V(Number_symbol, "Number") \ V(Number_symbol, "Number") \
V(nan_symbol, "NaN") \ V(nan_symbol, "NaN") \
@ -220,7 +223,8 @@ inline Heap* _inline_get_heap_();
V(closure_symbol, "(closure)") \ V(closure_symbol, "(closure)") \
V(use_strict, "use strict") \ V(use_strict, "use strict") \
V(dot_symbol, ".") \ V(dot_symbol, ".") \
V(anonymous_function_symbol, "(anonymous function)") V(anonymous_function_symbol, "(anonymous function)") \
V(block_scope_symbol, ".block")
// Forward declarations. // Forward declarations.
class GCTracer; class GCTracer;
@ -483,6 +487,9 @@ class Heap {
// Allocates an empty code cache. // Allocates an empty code cache.
MUST_USE_RESULT MaybeObject* AllocateCodeCache(); MUST_USE_RESULT MaybeObject* AllocateCodeCache();
// Allocates a serialized scope info.
MUST_USE_RESULT MaybeObject* AllocateSerializedScopeInfo(int length);
// Allocates an empty PolymorphicCodeCache. // Allocates an empty PolymorphicCodeCache.
MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache(); MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache();
@ -668,6 +675,11 @@ class Heap {
Context* previous, Context* previous,
JSObject* extension); 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. // Allocates a new utility object in the old generation.
MUST_USE_RESULT MaybeObject* AllocateStruct(InstanceType type); MUST_USE_RESULT MaybeObject* AllocateStruct(InstanceType type);

33
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) { void HCallConstantFunction::PrintDataTo(StringStream* stream) {
if (IsApplyFunction()) { if (IsApplyFunction()) {
stream->Add("optimized apply "); stream->Add("optimized apply ");
@ -862,19 +868,10 @@ void HInstanceOf::PrintDataTo(StringStream* stream) {
Range* HValue::InferRange() { Range* HValue::InferRange() {
if (representation().IsTagged()) { // Untagged integer32 cannot be -0, all other representations can.
// Tagged values are always in int32 range when converted to integer,
// but they can contain -0.
Range* result = new Range(); Range* result = new Range();
result->set_can_be_minus_zero(true); result->set_can_be_minus_zero(!representation().IsInteger32());
return result; 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();
}
} }
@ -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) { void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream); object()->PrintNameTo(stream);
stream->Add("["); stream->Add("[");

36
deps/v8/src/hydrogen-instructions.h

@ -104,8 +104,7 @@ class LChunkBuilder;
V(Div) \ V(Div) \
V(ElementsKind) \ V(ElementsKind) \
V(EnterInlined) \ V(EnterInlined) \
V(ExternalArrayLength) \ V(FixedArrayBaseLength) \
V(FixedArrayLength) \
V(ForceRepresentation) \ V(ForceRepresentation) \
V(FunctionLiteral) \ V(FunctionLiteral) \
V(GetCachedArrayIndex) \ V(GetCachedArrayIndex) \
@ -1702,9 +1701,9 @@ class HJSArrayLength: public HTemplateInstruction<2> {
}; };
class HFixedArrayLength: public HUnaryOperation { class HFixedArrayBaseLength: public HUnaryOperation {
public: public:
explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) { explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged()); set_representation(Representation::Tagged());
SetFlag(kUseGVN); SetFlag(kUseGVN);
SetFlag(kDependsOnArrayLengths); SetFlag(kDependsOnArrayLengths);
@ -1714,28 +1713,7 @@ class HFixedArrayLength: public HUnaryOperation {
return Representation::Tagged(); return Representation::Tagged();
} }
DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength) DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength)
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)
protected: protected:
virtual bool DataEquals(HValue* other) { return true; } virtual bool DataEquals(HValue* other) { return true; }
@ -2471,6 +2449,8 @@ class HBoundsCheck: public HTemplateInstruction<2> {
return Representation::Integer32(); return Representation::Integer32();
} }
virtual void PrintDataTo(StringStream* stream);
HValue* index() { return OperandAt(0); } HValue* index() { return OperandAt(0); }
HValue* length() { return OperandAt(1); } HValue* length() { return OperandAt(1); }
@ -3438,6 +3418,8 @@ class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> {
return Representation::Tagged(); return Representation::Tagged();
} }
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic) DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic)
static const int kMaxLoadPolymorphism = 4; static const int kMaxLoadPolymorphism = 4;
@ -3471,6 +3453,8 @@ class HLoadNamedGeneric: public HTemplateInstruction<2> {
return Representation::Tagged(); return Representation::Tagged();
} }
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric) DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
private: private:

37
deps/v8/src/hydrogen.cc

@ -2480,6 +2480,9 @@ void HGraphBuilder::VisitBlock(Block* stmt) {
ASSERT(!HasStackOverflow()); ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL); ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor()); ASSERT(current_block()->HasPredecessor());
if (stmt->block_scope() != NULL) {
return Bailout("ScopedBlock");
}
BreakAndContinueInfo break_info(stmt); BreakAndContinueInfo break_info(stmt);
{ BreakAndContinueScope push(&break_info, this); { BreakAndContinueScope push(&break_info, this);
CHECK_BAILOUT(VisitStatements(stmt->statements())); CHECK_BAILOUT(VisitStatements(stmt->statements()));
@ -2631,12 +2634,11 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
} }
void HGraphBuilder::VisitEnterWithContextStatement( void HGraphBuilder::VisitWithStatement(WithStatement* stmt) {
EnterWithContextStatement* stmt) {
ASSERT(!HasStackOverflow()); ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL); ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor()); ASSERT(current_block()->HasPredecessor());
return Bailout("EnterWithContextStatement"); return Bailout("WithStatement");
} }
@ -3940,7 +3942,7 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
HInstruction* length = NULL; HInstruction* length = NULL;
HInstruction* checked_key = NULL; HInstruction* checked_key = NULL;
if (map->has_external_array_elements()) { 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)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
HLoadExternalArrayPointer* external_elements = HLoadExternalArrayPointer* external_elements =
new(zone()) HLoadExternalArrayPointer(elements); new(zone()) HLoadExternalArrayPointer(elements);
@ -3952,7 +3954,7 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
if (map->instance_type() == JS_ARRAY_TYPE) { if (map->instance_type() == JS_ARRAY_TYPE) {
length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck)); length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck));
} else { } else {
length = AddInstruction(new(zone()) HFixedArrayLength(elements)); length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
} }
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
if (is_store) { if (is_store) {
@ -4024,7 +4026,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
&& todo_external_array) { && todo_external_array) {
HInstruction* length = HInstruction* length =
AddInstruction(new(zone()) HExternalArrayLength(elements)); AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
external_elements = new(zone()) HLoadExternalArrayPointer(elements); external_elements = new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements); AddInstruction(external_elements);
@ -4088,7 +4090,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
if_jsarray->Goto(join); if_jsarray->Goto(join);
set_current_block(if_fastobject); 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)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
if (is_store) { if (is_store) {
if (fast_double_elements) { if (fast_double_elements) {
@ -4762,10 +4764,17 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
Property* prop = callee->AsProperty(); Property* prop = callee->AsProperty();
ASSERT(prop != NULL); 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 (info()->scope()->arguments() == NULL) return false;
if (!name->IsEqualTo(CStrVector("apply"))) return false;
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
if (args->length() != 2) return false; if (args->length() != 2) return false;
@ -4775,9 +4784,6 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
HValue* arg_two_value = environment()->Lookup(arg_two->var()); HValue* arg_two_value = environment()->Lookup(arg_two->var());
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; 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 // Our implementation of arguments (based on this stack frame or an
// adapter below it) does not work for inlined functions. // adapter below it) does not work for inlined functions.
if (function_state()->outer() != NULL) { if (function_state()->outer() != NULL) {
@ -4794,10 +4800,7 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
HValue* receiver = Pop(); HValue* receiver = Pop();
HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
AddCheckConstantFunction(expr, AddCheckConstantFunction(expr, function, function_map, true);
function,
expr->GetReceiverTypes()->first(),
true);
HInstruction* result = HInstruction* result =
new(zone()) HApplyArguments(function, receiver, length, elements); new(zone()) HApplyArguments(function, receiver, length, elements);
result->set_position(expr->position()); result->set_position(expr->position());

3
deps/v8/src/hydrogen.h

@ -874,7 +874,10 @@ class HGraphBuilder: public AstVisitor {
bool is_store); bool is_store);
bool TryArgumentsAccess(Property* expr); bool TryArgumentsAccess(Property* expr);
// Try to optimize fun.apply(receiver, arguments) pattern.
bool TryCallApply(Call* expr); bool TryCallApply(Call* expr);
bool TryInline(Call* expr); bool TryInline(Call* expr);
bool TryInlineBuiltinFunction(Call* expr, bool TryInlineBuiltinFunction(Call* expr,
HValue* receiver, HValue* receiver,

12
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) { void Assembler::movmskpd(Register dst, XMMRegister src) {
ASSERT(CpuFeatures::IsEnabled(SSE2)); ASSERT(CpuFeatures::IsEnabled(SSE2));
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);

10
deps/v8/src/ia32/assembler-ia32.h

@ -941,6 +941,16 @@ class Assembler : public AssemblerBase {
void andpd(XMMRegister dst, XMMRegister src); void andpd(XMMRegister dst, XMMRegister src);
void ucomisd(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 movmskpd(Register dst, XMMRegister src);
void cmpltsd(XMMRegister dst, XMMRegister src); void cmpltsd(XMMRegister dst, XMMRegister src);

56
deps/v8/src/ia32/code-stubs-ia32.cc

@ -249,20 +249,20 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
} }
// undefined -> false // undefined -> false
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch); CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value // Boolean -> its value
CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch); CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch); CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false. // 'null' -> false.
CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch); CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) { if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true // Smis: 0 -> false, all other -> true
Label not_smi; Label not_smi;
__ JumpIfNotSmi(argument, &not_smi, Label::kNear); __ JumpIfNotSmi(argument, &not_smi, Label::kNear);
// argument contains the correct return value already // argument contains the correct return value already.
if (!tos_.is(argument)) { if (!tos_.is(argument)) {
__ mov(tos_, argument); __ mov(tos_, argument);
} }
@ -276,7 +276,7 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
if (types_.NeedsMap()) { if (types_.NeedsMap()) {
__ mov(map, FieldOperand(argument, HeapObject::kMapOffset)); __ mov(map, FieldOperand(argument, HeapObject::kMapOffset));
// Everything with a map could be undetectable, so check this now. if (types_.CanBeUndetectable()) {
__ test_b(FieldOperand(map, Map::kBitFieldOffset), __ test_b(FieldOperand(map, Map::kBitFieldOffset),
1 << Map::kIsUndetectable); 1 << Map::kIsUndetectable);
// Undetectable -> false. // Undetectable -> false.
@ -286,19 +286,19 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ ret(1 * kPointerSize); __ ret(1 * kPointerSize);
__ bind(&not_undetectable); __ bind(&not_undetectable);
} }
}
if (types_.Contains(SPEC_OBJECT)) { if (types_.Contains(SPEC_OBJECT)) {
// spec object -> true. // spec object -> true.
Label not_js_object; Label not_js_object;
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(below, &not_js_object, Label::kNear); __ j(below, &not_js_object, Label::kNear);
// argument contains the correct return value already.
if (!tos_.is(argument)) {
__ Set(tos_, Immediate(1)); __ Set(tos_, Immediate(1));
}
__ ret(1 * kPointerSize); __ ret(1 * kPointerSize);
__ bind(&not_js_object); __ 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)) { if (types_.Contains(STRING)) {
@ -309,10 +309,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ mov(tos_, FieldOperand(argument, String::kLengthOffset)); __ mov(tos_, FieldOperand(argument, String::kLengthOffset));
__ ret(1 * kPointerSize); // the string length is OK as the return value __ ret(1 * kPointerSize); // the string length is OK as the return value
__ bind(&not_string); __ 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)) { if (types_.Contains(HEAP_NUMBER)) {
@ -324,50 +320,42 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ fld_d(FieldOperand(argument, HeapNumber::kValueOffset)); __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset));
__ FCmp(); __ FCmp();
__ j(zero, &false_result, Label::kNear); __ j(zero, &false_result, Label::kNear);
// argument contains the correct return value already.
if (!tos_.is(argument)) {
__ Set(tos_, Immediate(1)); __ Set(tos_, Immediate(1));
}
__ ret(1 * kPointerSize); __ ret(1 * kPointerSize);
__ bind(&false_result); __ bind(&false_result);
__ Set(tos_, Immediate(0)); __ Set(tos_, Immediate(0));
__ ret(1 * kPointerSize); __ ret(1 * kPointerSize);
__ bind(&not_heap_number); __ 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); __ bind(&patch);
GenerateTypeTransition(masm); GenerateTypeTransition(masm);
}
} }
void ToBooleanStub::CheckOddball(MacroAssembler* masm, void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type, Type type,
Heap::RootListIndex value, Heap::RootListIndex value,
bool result, bool result) {
Label* patch) {
const Register argument = eax; const Register argument = eax;
if (types_.Contains(type)) { if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_. // If we see an expected oddball, return its ToBoolean value tos_.
Label different_value; Label different_value;
__ CompareRoot(argument, value); __ CompareRoot(argument, value);
__ j(not_equal, &different_value, Label::kNear); __ 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); __ ret(1 * kPointerSize);
__ bind(&different_value); __ 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);
} }
} }

12
deps/v8/src/ia32/disasm-ia32.cc

@ -1141,7 +1141,17 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
} }
} else if (*data == 0x3A) { } else if (*data == 0x3A) {
data++; 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++; data++;
int mod, regop, rm; int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm); get_modrm(*data, &mod, &regop, &rm);

9
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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -59,9 +59,10 @@ static const int kNumSafepointRegisters = 8;
class StackHandlerConstants : public AllStatic { class StackHandlerConstants : public AllStatic {
public: public:
static const int kNextOffset = 0 * kPointerSize; static const int kNextOffset = 0 * kPointerSize;
static const int kFPOffset = 1 * kPointerSize; static const int kContextOffset = 1 * kPointerSize;
static const int kStateOffset = 2 * kPointerSize; static const int kFPOffset = 2 * kPointerSize;
static const int kPCOffset = 3 * kPointerSize; static const int kStateOffset = 3 * kPointerSize;
static const int kPCOffset = 4 * kPointerSize;
static const int kSize = kPCOffset + kPointerSize; static const int kSize = kPCOffset + kPointerSize;
}; };

13
deps/v8/src/ia32/full-codegen-ia32.cc

@ -737,8 +737,10 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ push(esi); __ push(esi);
__ push(Immediate(variable->name())); __ push(Immediate(variable->name()));
// Declaration nodes are always introduced in one of two modes. // Declaration nodes are always introduced in one of two modes.
ASSERT(mode == Variable::VAR || mode == Variable::CONST); ASSERT(mode == Variable::VAR ||
PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; mode == Variable::CONST ||
mode == Variable::LET);
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
__ push(Immediate(Smi::FromInt(attr))); __ push(Immediate(Smi::FromInt(attr)));
// Push initial value, if any. // Push initial value, if any.
// Note: For variables we must not push an initial value (such as // 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, void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
const char* comment) { const char* comment) {
// TODO(svenpanne): Allowing format strings in Comment would be nice here...
Comment cmt(masm_, comment); Comment cmt(masm_, comment);
bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
UnaryOverwriteMode overwrite = UnaryOverwriteMode overwrite =
@ -4105,6 +4106,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
__ j(equal, if_true); __ j(equal, if_true);
__ cmp(eax, isolate()->factory()->false_value()); __ cmp(eax, isolate()->factory()->false_value());
Split(equal, if_true, if_false, fall_through); 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())) { } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ cmp(eax, isolate()->factory()->undefined_value()); __ cmp(eax, isolate()->factory()->undefined_value());
__ j(equal, if_true); __ j(equal, if_true);
@ -4120,8 +4125,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Split(above_equal, if_true, if_false, fall_through); Split(above_equal, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->object_symbol())) { } else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(eax, if_false); __ JumpIfSmi(eax, if_false);
if (!FLAG_harmony_typeof) {
__ cmp(eax, isolate()->factory()->null_value()); __ cmp(eax, isolate()->factory()->null_value());
__ j(equal, if_true); __ j(equal, if_true);
}
__ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx); __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
__ j(below, if_false); __ j(below, if_false);
__ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);

130
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 result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0)); Register array = ToRegister(instr->InputAt(0));
__ mov(result, FieldOperand(array, FixedArray::kLengthOffset)); __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
}
void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
__ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
} }
@ -1412,40 +1406,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
// undefined -> false. // undefined -> false.
__ cmp(reg, factory()->undefined_value()); __ cmp(reg, factory()->undefined_value());
__ j(equal, false_label); __ 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)) { if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// true -> true. // true -> true.
__ cmp(reg, factory()->true_value()); __ cmp(reg, factory()->true_value());
__ j(equal, true_label); __ 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. // false -> false.
__ cmp(reg, factory()->false_value()); __ cmp(reg, factory()->false_value());
__ j(equal, false_label); __ 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)) { if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false. // 'null' -> false.
__ cmp(reg, factory()->null_value()); __ cmp(reg, factory()->null_value());
__ j(equal, false_label); __ 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)) { if (expected.Contains(ToBooleanStub::SMI)) {
@ -1459,26 +1432,24 @@ void LCodeGen::DoBranch(LBranch* instr) {
DeoptimizeIf(zero, instr->environment()); DeoptimizeIf(zero, instr->environment());
} }
Register map = no_reg; Register map = no_reg; // Keep the compiler happy.
if (expected.NeedsMap()) { if (expected.NeedsMap()) {
map = ToRegister(instr->TempAt(0)); map = ToRegister(instr->TempAt(0));
ASSERT(!map.is(reg)); ASSERT(!map.is(reg));
__ mov(map, FieldOperand(reg, HeapObject::kMapOffset)); __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
// Everything with a map could be undetectable, so check this now.
if (expected.CanBeUndetectable()) {
// Undetectable -> false.
__ test_b(FieldOperand(map, Map::kBitFieldOffset), __ test_b(FieldOperand(map, Map::kBitFieldOffset),
1 << Map::kIsUndetectable); 1 << Map::kIsUndetectable);
// Undetectable -> false.
__ j(not_zero, false_label); __ j(not_zero, false_label);
} }
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true. // spec object -> true.
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(above_equal, true_label); __ 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)) { if (expected.Contains(ToBooleanStub::STRING)) {
@ -1490,10 +1461,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ j(not_zero, true_label); __ j(not_zero, true_label);
__ jmp(false_label); __ jmp(false_label);
__ bind(&not_string); __ 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)) { if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@ -1508,22 +1475,12 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ j(zero, false_label); __ j(zero, false_label);
__ jmp(true_label); __ jmp(true_label);
__ bind(&not_heap_number); __ 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. // We've seen something for the first time -> deopt.
DeoptimizeIf(no_condition, instr->environment()); DeoptimizeIf(no_condition, instr->environment());
} }
} }
}
} }
@ -2302,16 +2259,13 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
Register elements = ToRegister(instr->elements());
Register key = ToRegister(instr->key());
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
ASSERT(result.is(elements));
// Load the result. // Load the result.
__ mov(result, FieldOperand(elements, __ mov(result,
key, BuildFastArrayOperand(instr->elements(), instr->key(),
times_pointer_size, JSObject::FAST_ELEMENTS,
FixedArray::kHeaderSize)); FixedArray::kHeaderSize - kHeapObjectTag));
// Check for the hole value. // Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) { if (instr->hydrogen()->RequiresHoleCheck()) {
@ -2344,22 +2298,22 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Operand LCodeGen::BuildFastArrayOperand( Operand LCodeGen::BuildFastArrayOperand(
LOperand* external_pointer, LOperand* elements_pointer,
LOperand* key, LOperand* key,
JSObject::ElementsKind elements_kind, JSObject::ElementsKind elements_kind,
uint32_t offset) { uint32_t offset) {
Register external_pointer_reg = ToRegister(external_pointer); Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind); int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) { if (key->IsConstantOperand()) {
int constant_value = ToInteger32(LConstantOperand::cast(key)); int constant_value = ToInteger32(LConstantOperand::cast(key));
if (constant_value & 0xF0000000) { if (constant_value & 0xF0000000) {
Abort("array index constant value too big"); Abort("array index constant value too big");
} }
return Operand(external_pointer_reg, return Operand(elements_pointer_reg,
constant_value * (1 << shift_size) + offset); constant_value * (1 << shift_size) + offset);
} else { } else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); 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,13 +2710,42 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
XMMRegister xmm_scratch = xmm0; XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result()); Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value()); XMMRegister input_reg = ToDoubleRegister(instr->value());
__ xorps(xmm_scratch, xmm_scratch); // Zero the register.
__ ucomisd(input_reg, xmm_scratch);
if (CpuFeatures::IsSupported(SSE4_1)) {
CpuFeatures::Scope scope(SSE4_1);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(below_equal, instr->environment()); // 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 { } else {
Label done;
// Deoptimize on negative numbers.
__ xorps(xmm_scratch, xmm_scratch); // Zero the register.
__ ucomisd(input_reg, xmm_scratch);
DeoptimizeIf(below, instr->environment()); DeoptimizeIf(below, instr->environment());
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);
} }
// Use truncating instruction (OK because input is positive). // Use truncating instruction (OK because input is positive).
@ -2771,9 +2754,10 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
// Overflow is signalled with minint. // Overflow is signalled with minint.
__ cmp(output_reg, 0x80000000u); __ cmp(output_reg, 0x80000000u);
DeoptimizeIf(equal, instr->environment()); DeoptimizeIf(equal, instr->environment());
__ bind(&done);
}
} }
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
XMMRegister xmm_scratch = xmm0; XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result()); Register output_reg = ToRegister(instr->result());
@ -2783,13 +2767,11 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
// xmm_scratch = 0.5 // xmm_scratch = 0.5
ExternalReference one_half = ExternalReference::address_of_one_half(); ExternalReference one_half = ExternalReference::address_of_one_half();
__ movdbl(xmm_scratch, Operand::StaticVariable(one_half)); __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
__ ucomisd(xmm_scratch, input_reg); __ ucomisd(xmm_scratch, input_reg);
__ j(above, &below_half); __ j(above, &below_half);
// input = input + 0.5 // input = input + 0.5
__ addsd(input_reg, xmm_scratch); __ addsd(input_reg, xmm_scratch);
// Compute Math.floor(value + 0.5). // Compute Math.floor(value + 0.5).
// Use truncating instruction (OK because input is positive). // Use truncating instruction (OK because input is positive).
__ cvttsd2si(output_reg, Operand(input_reg)); __ cvttsd2si(output_reg, Operand(input_reg));
@ -3108,8 +3090,14 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
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())); __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
DeoptimizeIf(above_equal, instr->environment()); DeoptimizeIf(above_equal, instr->environment());
}
} }
@ -4200,6 +4188,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
__ cmp(input, factory()->false_value()); __ cmp(input, factory()->false_value());
final_branch_condition = equal; 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())) { } else if (type_name->Equals(heap()->undefined_symbol())) {
__ cmp(input, factory()->undefined_value()); __ cmp(input, factory()->undefined_value());
__ j(equal, true_label); __ j(equal, true_label);
@ -4218,8 +4210,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
} else if (type_name->Equals(heap()->object_symbol())) { } else if (type_name->Equals(heap()->object_symbol())) {
__ JumpIfSmi(input, false_label); __ JumpIfSmi(input, false_label);
if (!FLAG_harmony_typeof) {
__ cmp(input, factory()->null_value()); __ cmp(input, factory()->null_value());
__ j(equal, true_label); __ j(equal, true_label);
}
__ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
__ j(below, false_label); __ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);

2
deps/v8/src/ia32/lithium-codegen-ia32.h

@ -222,7 +222,7 @@ class LCodeGen BASE_EMBEDDED {
Register ToRegister(int index) const; Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const; XMMRegister ToDoubleRegister(int index) const;
int ToInteger32(LConstantOperand* op) const; int ToInteger32(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* external_pointer, Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key, LOperand* key,
JSObject::ElementsKind elements_kind, JSObject::ElementsKind elements_kind,
uint32_t offset); uint32_t offset);

24
deps/v8/src/ia32/lithium-ia32.cc

@ -1047,10 +1047,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
// involving maps). // involving maps).
bool needs_temp = expected.NeedsMap() || expected.IsEmpty(); bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
LOperand* temp = needs_temp ? TempRegister() : NULL; LOperand* temp = needs_temp ? TempRegister() : NULL;
LInstruction* branch = new LBranch(UseRegister(v), temp); return AssignEnvironment(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);
} }
@ -1541,16 +1538,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
} }
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value()); LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array)); return DefineAsRegister(new LFixedArrayBaseLength(array));
}
LInstruction* LChunkBuilder::DoExternalArrayLength(
HExternalArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LExternalArrayLength(array));
} }
@ -1568,7 +1559,8 @@ LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()), return AssignEnvironment(new LBoundsCheck(
UseRegisterOrConstantAtStart(instr->index()),
UseAtStart(instr->length()))); UseAtStart(instr->length())));
} }
@ -1890,9 +1882,9 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
ASSERT(instr->representation().IsTagged()); ASSERT(instr->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32()); ASSERT(instr->key()->representation().IsInteger32());
LOperand* obj = UseRegisterAtStart(instr->object()); LOperand* obj = UseRegisterAtStart(instr->object());
LOperand* key = UseRegisterAtStart(instr->key()); LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key); LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
return AssignEnvironment(DefineSameAsFirst(result)); return AssignEnvironment(DefineAsRegister(result));
} }

33
deps/v8/src/ia32/lithium-ia32.h

@ -86,8 +86,7 @@ class LCodeGen;
V(DivI) \ V(DivI) \
V(DoubleToI) \ V(DoubleToI) \
V(ElementsKind) \ V(ElementsKind) \
V(ExternalArrayLength) \ V(FixedArrayBaseLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \ V(FunctionLiteral) \
V(GetCachedArrayIndex) \ V(GetCachedArrayIndex) \
V(GlobalObject) \ 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: public:
explicit LExternalArrayLength(LOperand* value) { explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value; inputs_[0] = value;
} }
DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length") DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength) "fixed-array-base-length")
}; DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
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)
}; };
@ -2248,14 +2237,18 @@ class LChunkBuilder BASE_EMBEDDED {
template<int I, int T> template<int I, int T>
LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr, LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr,
XMMRegister reg); XMMRegister reg);
// Assigns an environment to an instruction. An instruction which can
// deoptimize must have an environment.
LInstruction* AssignEnvironment(LInstruction* instr); 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); LInstruction* AssignPointerMap(LInstruction* instr);
enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY }; enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
// By default we assume that instruction sequences generated for calls // Marks a call for the register allocator. Assigns a pointer map to
// cannot deoptimize eagerly and we do not attach environment to this // support GC and lazy deoptimization. Assigns an environment to support
// instruction. // eager deoptimization if CAN_DEOPTIMIZE_EAGERLY.
LInstruction* MarkAsCall( LInstruction* MarkAsCall(
LInstruction* instr, LInstruction* instr,
HInstruction* hinstr, HInstruction* hinstr,

53
deps/v8/src/ia32/macro-assembler-ia32.cc

@ -542,7 +542,12 @@ void MacroAssembler::LeaveApiExitFrame() {
void MacroAssembler::PushTryHandler(CodeLocation try_location, void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) { HandlerType type) {
// Adjust this code if not the case. // 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. // The pc (return address) is already on TOS.
if (try_location == IN_JAVASCRIPT) { if (try_location == IN_JAVASCRIPT) {
if (type == TRY_CATCH_HANDLER) { if (type == TRY_CATCH_HANDLER) {
@ -551,6 +556,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
push(Immediate(StackHandler::TRY_FINALLY)); push(Immediate(StackHandler::TRY_FINALLY));
} }
push(ebp); push(ebp);
push(esi);
} else { } else {
ASSERT(try_location == IN_JS_ENTRY); ASSERT(try_location == IN_JS_ENTRY);
// The frame pointer does not point to a JS frame so we save NULL // 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. // before dereferencing it to restore the context.
push(Immediate(StackHandler::ENTRY)); push(Immediate(StackHandler::ENTRY));
push(Immediate(0)); // NULL frame pointer. push(Immediate(0)); // NULL frame pointer.
push(Immediate(Smi::FromInt(0))); // No context.
} }
// Save the current handler as the next handler. // Save the current handler as the next handler.
push(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address, push(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
@ -570,7 +577,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() { void MacroAssembler::PopTryHandler() {
ASSERT_EQ(0, StackHandlerConstants::kNextOffset); STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address, pop(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
isolate()))); isolate())));
add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize)); add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
@ -579,8 +586,12 @@ void MacroAssembler::PopTryHandler() {
void MacroAssembler::Throw(Register value) { void MacroAssembler::Throw(Register value) {
// Adjust this code if not the case. // 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. // eax must hold the exception.
if (!value.is(eax)) { if (!value.is(eax)) {
mov(eax, value); mov(eax, value);
@ -591,24 +602,21 @@ void MacroAssembler::Throw(Register value) {
isolate()); isolate());
mov(esp, Operand::StaticVariable(handler_address)); mov(esp, Operand::StaticVariable(handler_address));
// Restore next handler and frame pointer, discard handler state. // Restore next handler, context, and frame pointer; discard handler state.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(Operand::StaticVariable(handler_address)); pop(Operand::StaticVariable(handler_address));
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize); pop(esi); // Context.
pop(ebp); pop(ebp); // Frame pointer.
pop(edx); // Remove state. pop(edx); // State.
// Before returning we restore the context from the frame pointer if // If the handler is a JS frame, restore the context to the frame.
// not NULL. The frame pointer is NULL in the exception handler of // (edx == ENTRY) == (ebp == 0) == (esi == 0), so we could test any
// a JS entry frame. // of them.
Set(esi, Immediate(0)); // Tentatively set context pointer to NULL.
Label skip; Label skip;
cmp(ebp, 0); cmp(Operand(edx), Immediate(StackHandler::ENTRY));
j(equal, &skip, Label::kNear); j(equal, &skip, Label::kNear);
mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
bind(&skip); bind(&skip);
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
ret(0); ret(0);
} }
@ -616,7 +624,12 @@ void MacroAssembler::Throw(Register value) {
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) { Register value) {
// Adjust this code if not the case. // 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. // eax must hold the exception.
if (!value.is(eax)) { if (!value.is(eax)) {
@ -642,7 +655,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
bind(&done); bind(&done);
// Set the top handler address to next handler past the current ENTRY handler. // Set the top handler address to next handler past the current ENTRY handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(Operand::StaticVariable(handler_address)); pop(Operand::StaticVariable(handler_address));
if (type == OUT_OF_MEMORY) { if (type == OUT_OF_MEMORY) {
@ -660,15 +672,14 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
mov(Operand::StaticVariable(pending_exception), eax); 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)); Set(esi, Immediate(0));
// Restore fp from handler and discard handler state. // Restore fp from handler and discard handler state.
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize);
pop(ebp); pop(ebp);
pop(edx); // State. pop(edx); // State.
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
ret(0); ret(0);
} }

97
deps/v8/src/ia32/stub-cache-ia32.cc

@ -3400,37 +3400,37 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ JumpIfNotSmi(eax, &miss_force_generic); __ JumpIfNotSmi(eax, &miss_force_generic);
// Check that the index is in range. // Check that the index is in range.
__ mov(ecx, eax);
__ SmiUntag(ecx); // Untag the index.
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); __ 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. // Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &miss_force_generic); __ j(above_equal, &miss_force_generic);
__ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
// ebx: base pointer of external storage // ebx: base pointer of external storage
switch (elements_kind) { switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS: 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; break;
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case JSObject::EXTERNAL_PIXEL_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; break;
case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_SHORT_ELEMENTS:
__ movsx_w(eax, Operand(ebx, ecx, times_2, 0)); __ movsx_w(eax, Operand(ebx, eax, times_1, 0));
break; break;
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 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; break;
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
case JSObject::EXTERNAL_INT_ELEMENTS: case JSObject::EXTERNAL_INT_ELEMENTS:
__ mov(ecx, Operand(ebx, ecx, times_4, 0)); __ mov(ecx, Operand(ebx, eax, times_2, 0));
break; break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS: case JSObject::EXTERNAL_FLOAT_ELEMENTS:
__ fld_s(Operand(ebx, ecx, times_4, 0)); __ fld_s(Operand(ebx, eax, times_2, 0));
break; break;
case JSObject::EXTERNAL_DOUBLE_ELEMENTS: case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
__ fld_d(Operand(ebx, ecx, times_8, 0)); __ fld_d(Operand(ebx, eax, times_4, 0));
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -3556,9 +3556,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Check that the index is in range. // Check that the index is in range.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
__ mov(ebx, ecx); __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
__ SmiUntag(ebx);
__ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values. // Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &slow); __ j(above_equal, &slow);
@ -3568,7 +3566,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// edx: receiver // edx: receiver
// ecx: key // ecx: key
// edi: elements array // edi: elements array
// ebx: untagged index
if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) { if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
__ JumpIfNotSmi(eax, &slow); __ JumpIfNotSmi(eax, &slow);
} else { } else {
@ -3576,44 +3573,39 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
} }
// smi case // smi case
__ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. __ mov(ebx, eax); // Preserve the value in eax as the return value.
__ SmiUntag(ecx); __ SmiUntag(ebx);
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
// ecx: base pointer of external storage // edi: base pointer of external storage
switch (elements_kind) { switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS: case JSObject::EXTERNAL_PIXEL_ELEMENTS:
{ // Clamp the value to [0..255]. __ ClampUint8(ebx);
Label done; __ SmiUntag(ecx);
__ test(ecx, Immediate(0xFFFFFF00)); __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
__ 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; break;
case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_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; break;
case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_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; break;
case JSObject::EXTERNAL_INT_ELEMENTS: case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_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; break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS: case JSObject::EXTERNAL_FLOAT_ELEMENTS:
case JSObject::EXTERNAL_DOUBLE_ELEMENTS: case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
// Need to perform int-to-float conversion. // Need to perform int-to-float conversion.
__ push(ecx); __ push(ebx);
__ fild_s(Operand(esp, 0)); __ fild_s(Operand(esp, 0));
__ pop(ecx); __ pop(ebx);
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { 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. } else { // elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS.
__ fstp_d(Operand(edi, ebx, times_8, 0)); __ fstp_d(Operand(edi, ecx, times_4, 0));
} }
break; break;
default: default:
@ -3629,7 +3621,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// edx: receiver // edx: receiver
// ecx: key // ecx: key
// edi: elements array // edi: elements array
// ebx: untagged index
__ cmp(FieldOperand(eax, HeapObject::kMapOffset), __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
Immediate(masm->isolate()->factory()->heap_number_map())); Immediate(masm->isolate()->factory()->heap_number_map()));
__ j(not_equal, &slow); __ j(not_equal, &slow);
@ -3638,15 +3629,14 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// +/-Infinity into integer arrays basically undefined. For more // +/-Infinity into integer arrays basically undefined. For more
// reproducible behavior, convert these to zero. // reproducible behavior, convert these to zero.
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
// ebx: untagged index
// edi: base pointer of external storage // edi: base pointer of external storage
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ fstp_s(Operand(edi, ebx, times_4, 0)); __ fstp_s(Operand(edi, ecx, times_2, 0));
__ ret(0); __ ret(0);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ fstp_d(Operand(edi, ebx, times_8, 0)); __ fstp_d(Operand(edi, ecx, times_4, 0));
__ ret(0); __ ret(0);
} else { } else {
// Perform float-to-int conversion with truncation (round-to-zero) // Perform float-to-int conversion with truncation (round-to-zero)
@ -3661,27 +3651,20 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
elements_kind != JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) { elements_kind != JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
ASSERT(CpuFeatures::IsSupported(SSE2)); ASSERT(CpuFeatures::IsSupported(SSE2));
CpuFeatures::Scope scope(SSE2); CpuFeatures::Scope scope(SSE2);
__ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
// ecx: untagged integer value // ecx: untagged integer value
switch (elements_kind) { switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS: case JSObject::EXTERNAL_PIXEL_ELEMENTS:
{ // Clamp the value to [0..255]. __ ClampUint8(ebx);
Label done; // Fall through.
__ 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;
case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_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; break;
case JSObject::EXTERNAL_SHORT_ELEMENTS: case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_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; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -3698,7 +3681,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ sub(Operand(esp), Immediate(2 * kPointerSize)); __ sub(Operand(esp), Immediate(2 * kPointerSize));
__ fisttp_d(Operand(esp, 0)); __ fisttp_d(Operand(esp, 0));
__ pop(ecx); __ pop(ebx);
__ add(Operand(esp), Immediate(kPointerSize)); __ add(Operand(esp), Immediate(kPointerSize));
} else { } else {
ASSERT(CpuFeatures::IsSupported(SSE2)); ASSERT(CpuFeatures::IsSupported(SSE2));
@ -3709,15 +3692,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Note: we could do better for signed int arrays. // Note: we could do better for signed int arrays.
__ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
// We will need the key if we have to make the slow runtime call. // We will need the key if we have to make the slow runtime call.
__ push(ecx); __ push(ebx);
__ LoadPowerOf2(xmm1, ecx, 31); __ LoadPowerOf2(xmm1, ebx, 31);
__ pop(ecx); __ pop(ebx);
__ ucomisd(xmm1, xmm0); __ ucomisd(xmm1, xmm0);
__ j(above_equal, &slow); __ j(above_equal, &slow);
__ cvttsd2si(ecx, Operand(xmm0)); __ cvttsd2si(ebx, Operand(xmm0));
} }
// ecx: untagged integer value // ebx: untagged integer value
__ mov(Operand(edi, ebx, times_4, 0), ecx); __ mov(Operand(edi, ecx, times_2, 0), ebx);
} }
__ ret(0); // Return original value. __ ret(0); // Return original value.
} }

6
deps/v8/src/isolate.cc

@ -1533,6 +1533,9 @@ void Isolate::SetIsolateThreadLocals(Isolate* isolate,
Isolate::~Isolate() { Isolate::~Isolate() {
TRACE_ISOLATE(destructor); TRACE_ISOLATE(destructor);
// Has to be called while counters_ are still alive.
zone_.DeleteKeptSegment();
delete unicode_cache_; delete unicode_cache_;
unicode_cache_ = NULL; unicode_cache_ = NULL;
@ -1591,6 +1594,9 @@ Isolate::~Isolate() {
delete global_handles_; delete global_handles_;
global_handles_ = NULL; global_handles_ = NULL;
delete external_reference_table_;
external_reference_table_ = NULL;
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
delete debugger_; delete debugger_;
debugger_ = NULL; debugger_ = NULL;

194
deps/v8/src/liveobjectlist.cc

@ -36,11 +36,12 @@
#include "global-handles.h" #include "global-handles.h"
#include "heap.h" #include "heap.h"
#include "inspector.h" #include "inspector.h"
#include "isolate.h"
#include "list-inl.h" #include "list-inl.h"
#include "liveobjectlist-inl.h" #include "liveobjectlist-inl.h"
#include "string-stream.h" #include "string-stream.h"
#include "top.h"
#include "v8utils.h" #include "v8utils.h"
#include "v8conversions.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
@ -109,7 +110,7 @@ typedef int (*RawComparer)(const void*, const void*);
\ \
v(Context, "meta: Context") \ v(Context, "meta: Context") \
v(ByteArray, "meta: ByteArray") \ v(ByteArray, "meta: ByteArray") \
v(PixelArray, "meta: PixelArray") \ v(ExternalPixelArray, "meta: PixelArray") \
v(ExternalArray, "meta: ExternalArray") \ v(ExternalArray, "meta: ExternalArray") \
v(FixedArray, "meta: FixedArray") \ v(FixedArray, "meta: FixedArray") \
v(String, "String") \ v(String, "String") \
@ -211,8 +212,9 @@ static AllocationSpace FindSpaceFor(String* space_str) {
static bool InSpace(AllocationSpace space, HeapObject *heap_obj) { static bool InSpace(AllocationSpace space, HeapObject *heap_obj) {
Heap* heap = ISOLATE->heap();
if (space != LO_SPACE) { 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 // 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 first_space = static_cast<int>(FIRST_SPACE);
int last_space = static_cast<int>(LO_SPACE); int last_space = static_cast<int>(LO_SPACE);
for (int sp = first_space; sp < last_space; sp++) { 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; return false;
} }
} }
SLOW_ASSERT(Heap::InSpace(heap_obj, LO_SPACE)); SLOW_ASSERT(heap->InSpace(heap_obj, LO_SPACE));
return true; return true;
} }
@ -285,7 +287,7 @@ LolFilter::LolFilter(Handle<JSObject> filter_obj)
void LolFilter::InitTypeFilter(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); MaybeObject* maybe_result = filter_obj->GetProperty(*type_sym);
Object* type_obj; Object* type_obj;
if (maybe_result->ToObject(&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) { 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); MaybeObject* maybe_result = filter_obj->GetProperty(*space_sym);
Object* space_obj; Object* space_obj;
if (maybe_result->ToObject(&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) { 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); MaybeObject* maybe_result = filter_obj->GetProperty(*prop_sym);
Object* prop_obj; Object* prop_obj;
if (maybe_result->ToObject(&prop_obj)) { if (maybe_result->ToObject(&prop_obj)) {
@ -571,7 +573,9 @@ static bool AddObjDetail(Handle<FixedArray> arr,
Handle<JSObject> detail, Handle<JSObject> detail,
Handle<String> desc, Handle<String> desc,
Handle<Object> error) { 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()) { if (detail->IsFailure()) {
error = detail; error = detail;
return false; return false;
@ -586,7 +590,7 @@ static bool AddObjDetail(Handle<FixedArray> arr,
desc_str = buffer; desc_str = buffer;
size = obj->Size(); size = obj->Size();
} }
desc = Factory::NewStringFromAscii(CStrVector(desc_str)); desc = factory->NewStringFromAscii(CStrVector(desc_str));
if (desc->IsFailure()) { if (desc->IsFailure()) {
error = desc; error = desc;
return false; return false;
@ -663,10 +667,13 @@ class LolDumpWriter: public DumpWriter {
int index = 0; int index = 0;
int count = 0; int count = 0;
Isolate* isolate = Isolate::Current();
Factory* factory = isolate->factory();
// Prefetch some needed symbols. // Prefetch some needed symbols.
Handle<String> id_sym = Factory::LookupAsciiSymbol("id"); Handle<String> id_sym = factory->LookupAsciiSymbol("id");
Handle<String> desc_sym = Factory::LookupAsciiSymbol("desc"); Handle<String> desc_sym = factory->LookupAsciiSymbol("desc");
Handle<String> size_sym = Factory::LookupAsciiSymbol("size"); Handle<String> size_sym = factory->LookupAsciiSymbol("size");
// Fill the array with the lol object details. // Fill the array with the lol object details.
Handle<JSObject> detail; Handle<JSObject> detail;
@ -1089,7 +1096,9 @@ static int CountHeapObjects() {
// Captures a current snapshot of all objects in the heap. // Captures a current snapshot of all objects in the heap.
MaybeObject* LiveObjectList::Capture() { MaybeObject* LiveObjectList::Capture() {
HandleScope scope; Isolate* isolate = Isolate::Current();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
// Count the number of objects in the heap. // Count the number of objects in the heap.
int total_count = CountHeapObjects(); int total_count = CountHeapObjects();
@ -1139,11 +1148,11 @@ MaybeObject* LiveObjectList::Capture() {
#endif #endif
} }
Handle<String> id_sym = Factory::LookupAsciiSymbol("id"); Handle<String> id_sym = factory->LookupAsciiSymbol("id");
Handle<String> count_sym = Factory::LookupAsciiSymbol("count"); Handle<String> count_sym = factory->LookupAsciiSymbol("count");
Handle<String> size_sym = Factory::LookupAsciiSymbol("size"); 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); if (result->IsFailure()) return Object::cast(*result);
{ MaybeObject* maybe_result = result->SetProperty(*id_sym, { MaybeObject* maybe_result = result->SetProperty(*id_sym,
@ -1259,7 +1268,10 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
int start, int start,
int dump_limit, int dump_limit,
LolFilter* filter) { LolFilter* filter) {
HandleScope scope; Isolate* isolate = Isolate::Current();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
// Calculate the number of entries of the dump. // Calculate the number of entries of the dump.
int count = -1; int count = -1;
@ -1277,7 +1289,7 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
} }
// Allocate an array to hold the result. // 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); if (elements_arr->IsFailure()) return Object::cast(*elements_arr);
// Fill in the dump. // Fill in the dump.
@ -1292,11 +1304,11 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
MaybeObject* maybe_result; MaybeObject* maybe_result;
// Allocate the result body. // 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); if (body->IsFailure()) return Object::cast(*body);
// Set the updated body.count. // 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, maybe_result = body->SetProperty(*count_sym,
Smi::FromInt(count), Smi::FromInt(count),
NONE, NONE,
@ -1305,7 +1317,7 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
// Set the updated body.size if appropriate. // Set the updated body.size if appropriate.
if (size >= 0) { if (size >= 0) {
Handle<String> size_sym = Factory::LookupAsciiSymbol("size"); Handle<String> size_sym = factory->LookupAsciiSymbol("size");
maybe_result = body->SetProperty(*size_sym, maybe_result = body->SetProperty(*size_sym,
Smi::FromInt(size), Smi::FromInt(size),
NONE, NONE,
@ -1314,7 +1326,7 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
} }
// Set body.first_index. // 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, maybe_result = body->SetProperty(*first_sym,
Smi::FromInt(start), Smi::FromInt(start),
NONE, NONE,
@ -1322,12 +1334,12 @@ MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
if (maybe_result->IsFailure()) return maybe_result; if (maybe_result->IsFailure()) return maybe_result;
// Allocate the JSArray of the elements. // 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); if (elements->IsFailure()) return Object::cast(*elements);
Handle<JSArray>::cast(elements)->SetContent(*elements_arr); Handle<JSArray>::cast(elements)->SetContent(*elements_arr);
// Set body.elements. // Set body.elements.
Handle<String> elements_sym = Factory::LookupAsciiSymbol("elements"); Handle<String> elements_sym = factory->LookupAsciiSymbol("elements");
maybe_result = body->SetProperty(*elements_sym, maybe_result = body->SetProperty(*elements_sym,
*elements, *elements,
NONE, NONE,
@ -1381,6 +1393,9 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
LiveObjectSummary summary(filter); LiveObjectSummary summary(filter);
writer->Write(&summary); writer->Write(&summary);
Isolate* isolate = Isolate::Current();
Factory* factory = isolate->factory();
// The result body will look like this: // The result body will look like this:
// body: { // body: {
// count: <total_count>, // count: <total_count>,
@ -1398,21 +1413,21 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
// } // }
// Prefetch some needed symbols. // Prefetch some needed symbols.
Handle<String> desc_sym = Factory::LookupAsciiSymbol("desc"); Handle<String> desc_sym = factory->LookupAsciiSymbol("desc");
Handle<String> count_sym = Factory::LookupAsciiSymbol("count"); Handle<String> count_sym = factory->LookupAsciiSymbol("count");
Handle<String> size_sym = Factory::LookupAsciiSymbol("size"); Handle<String> size_sym = factory->LookupAsciiSymbol("size");
Handle<String> summary_sym = Factory::LookupAsciiSymbol("summary"); Handle<String> summary_sym = factory->LookupAsciiSymbol("summary");
// Allocate the summary array. // Allocate the summary array.
int entries_count = summary.GetNumberOfEntries(); int entries_count = summary.GetNumberOfEntries();
Handle<FixedArray> summary_arr = Handle<FixedArray> summary_arr =
Factory::NewFixedArray(entries_count); factory->NewFixedArray(entries_count);
if (summary_arr->IsFailure()) return Object::cast(*summary_arr); if (summary_arr->IsFailure()) return Object::cast(*summary_arr);
int idx = 0; int idx = 0;
for (int i = 0; i < LiveObjectSummary::kNumberOfEntries; i++) { for (int i = 0; i < LiveObjectSummary::kNumberOfEntries; i++) {
// Allocate the summary record. // 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); if (detail->IsFailure()) return Object::cast(*detail);
// Fill in the summary record. // Fill in the summary record.
@ -1420,7 +1435,7 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
int count = summary.Count(type); int count = summary.Count(type);
if (count) { if (count) {
const char* desc_cstr = GetObjectTypeDesc(type); 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); int size = summary.Size(type);
maybe_result = detail->SetProperty(*desc_sym, maybe_result = detail->SetProperty(*desc_sym,
@ -1444,12 +1459,13 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
} }
// Wrap the summary fixed array in a JS array. // 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); if (summary_obj->IsFailure()) return Object::cast(*summary_obj);
Handle<JSArray>::cast(summary_obj)->SetContent(*summary_arr); Handle<JSArray>::cast(summary_obj)->SetContent(*summary_arr);
// Create the body object. // 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); if (body->IsFailure()) return Object::cast(*body);
// Fill out the body object. // Fill out the body object.
@ -1470,9 +1486,9 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
if (is_tracking_roots) { if (is_tracking_roots) {
int found_root = summary.found_root(); int found_root = summary.found_root();
int found_weak_root = summary.found_weak_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 = Handle<String> weak_root_sym =
Factory::LookupAsciiSymbol("found_weak_root"); factory->LookupAsciiSymbol("found_weak_root");
maybe_result = body->SetProperty(*root_sym, maybe_result = body->SetProperty(*root_sym,
Smi::FromInt(found_root), Smi::FromInt(found_root),
NONE, NONE,
@ -1499,7 +1515,10 @@ MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
// Note: only dumps the section starting at start_idx and only up to // Note: only dumps the section starting at start_idx and only up to
// dump_limit entries. // dump_limit entries.
MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) { 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; MaybeObject* maybe_result;
int total_count = LiveObjectList::list_count(); 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. // 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); if (list->IsFailure()) return Object::cast(*list);
// Prefetch some needed symbols. // Prefetch some needed symbols.
Handle<String> id_sym = Factory::LookupAsciiSymbol("id"); Handle<String> id_sym = factory->LookupAsciiSymbol("id");
Handle<String> count_sym = Factory::LookupAsciiSymbol("count"); Handle<String> count_sym = factory->LookupAsciiSymbol("count");
Handle<String> size_sym = Factory::LookupAsciiSymbol("size"); Handle<String> size_sym = factory->LookupAsciiSymbol("size");
// Fill the array with the lol details. // Fill the array with the lol details.
int idx = 0; int idx = 0;
@ -1543,7 +1562,8 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) {
int size; int size;
count = lol->GetTotalObjCountAndSize(&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); if (detail->IsFailure()) return Object::cast(*detail);
maybe_result = detail->SetProperty(*id_sym, 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. // 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<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); if (result->IsFailure()) return Object::cast(*result);
maybe_result = result->SetProperty(*count_sym, maybe_result = result->SetProperty(*count_sym,
@ -1580,14 +1600,14 @@ MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) {
kNonStrictMode); kNonStrictMode);
if (maybe_result->IsFailure()) return maybe_result; 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, maybe_result = result->SetProperty(*first_sym,
Smi::FromInt(start_idx), Smi::FromInt(start_idx),
NONE, NONE,
kNonStrictMode); kNonStrictMode);
if (maybe_result->IsFailure()) return maybe_result; 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, maybe_result = result->SetProperty(*lists_sym,
*lols, *lols,
NONE, NONE,
@ -1618,7 +1638,7 @@ Object* LiveObjectList::GetObj(int obj_id) {
if (element != NULL) { if (element != NULL) {
return Object::cast(element->obj_); 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 = SmartPointer<char> addr_str =
address->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); address->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Isolate* isolate = Isolate::Current();
// Extract the address value from the string. // 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); Object* obj = reinterpret_cast<Object*>(value);
return Smi::FromInt(GetObjId(obj)); return Smi::FromInt(GetObjId(obj));
} }
@ -1760,10 +1783,13 @@ int LiveObjectList::GetRetainers(Handle<HeapObject> target,
Handle<String> desc; Handle<String> desc;
Handle<HeapObject> retainer; Handle<HeapObject> retainer;
Isolate* isolate = Isolate::Current();
Factory* factory = isolate->factory();
// Prefetch some needed symbols. // Prefetch some needed symbols.
Handle<String> id_sym = Factory::LookupAsciiSymbol("id"); Handle<String> id_sym = factory->LookupAsciiSymbol("id");
Handle<String> desc_sym = Factory::LookupAsciiSymbol("desc"); Handle<String> desc_sym = factory->LookupAsciiSymbol("desc");
Handle<String> size_sym = Factory::LookupAsciiSymbol("size"); Handle<String> size_sym = factory->LookupAsciiSymbol("size");
NoHandleAllocation ha; NoHandleAllocation ha;
int count = 0; int count = 0;
@ -1774,7 +1800,7 @@ int LiveObjectList::GetRetainers(Handle<HeapObject> target,
// Iterate roots. // Iterate roots.
LolVisitor lol_visitor(*target, target); LolVisitor lol_visitor(*target, target);
Heap::IterateStrongRoots(&lol_visitor, VISIT_ALL); isolate->heap()->IterateStrongRoots(&lol_visitor, VISIT_ALL);
if (!AddRootRetainerIfFound(lol_visitor, if (!AddRootRetainerIfFound(lol_visitor,
filter, filter,
summary, summary,
@ -1794,7 +1820,7 @@ int LiveObjectList::GetRetainers(Handle<HeapObject> target,
} }
lol_visitor.reset(); lol_visitor.reset();
Heap::IterateWeakRoots(&lol_visitor, VISIT_ALL); isolate->heap()->IterateWeakRoots(&lol_visitor, VISIT_ALL);
if (!AddRootRetainerIfFound(lol_visitor, if (!AddRootRetainerIfFound(lol_visitor,
filter, filter,
summary, summary,
@ -1903,11 +1929,15 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id,
int start, int start,
int dump_limit, int dump_limit,
Handle<JSObject> filter_obj) { 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. // Get the target object.
HeapObject* heap_obj = HeapObject::cast(GetObj(obj_id)); HeapObject* heap_obj = HeapObject::cast(GetObj(obj_id));
if (heap_obj == Heap::undefined_value()) { if (heap_obj == heap->undefined_value()) {
return heap_obj; return heap_obj;
} }
@ -1915,7 +1945,7 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id,
// Get the constructor function for context extension and arguments array. // Get the constructor function for context extension and arguments array.
JSObject* arguments_boilerplate = JSObject* arguments_boilerplate =
Top::context()->global_context()->arguments_boilerplate(); isolate->context()->global_context()->arguments_boilerplate();
JSFunction* arguments_function = JSFunction* arguments_function =
JSFunction::cast(arguments_boilerplate->map()->constructor()); JSFunction::cast(arguments_boilerplate->map()->constructor());
@ -1937,7 +1967,7 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id,
// Set body.id. // Set body.id.
Handle<JSObject> body = Handle<JSObject>(JSObject::cast(body_obj)); 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, maybe_result = body->SetProperty(*id_sym,
Smi::FromInt(obj_id), Smi::FromInt(obj_id),
NONE, NONE,
@ -1952,13 +1982,17 @@ MaybeObject* LiveObjectList::GetObjRetainers(int obj_id,
Object* LiveObjectList::PrintObj(int obj_id) { Object* LiveObjectList::PrintObj(int obj_id) {
Object* obj = GetObj(obj_id); Object* obj = GetObj(obj_id);
if (!obj) { if (!obj) {
return Heap::undefined_value(); return HEAP->undefined_value();
} }
EmbeddedVector<char, 128> temp_filename; EmbeddedVector<char, 128> temp_filename;
static int temp_count = 0; static int temp_count = 0;
const char* path_prefix = "."; const char* path_prefix = ".";
Isolate* isolate = Isolate::Current();
Factory* factory = isolate->factory();
Heap* heap = isolate->heap();
if (FLAG_lol_workdir) { if (FLAG_lol_workdir) {
path_prefix = FLAG_lol_workdir; path_prefix = FLAG_lol_workdir;
} }
@ -1987,13 +2021,13 @@ Object* LiveObjectList::PrintObj(int obj_id) {
if (resource->exists() && !resource->is_empty()) { if (resource->exists() && !resource->is_empty()) {
ASSERT(resource->IsAscii()); ASSERT(resource->IsAscii());
Handle<String> dump_string = Handle<String> dump_string =
Factory::NewExternalStringFromAscii(resource); factory->NewExternalStringFromAscii(resource);
ExternalStringTable::AddString(*dump_string); heap->external_string_table()->AddString(*dump_string);
return *dump_string; return *dump_string;
} else { } else {
delete resource; 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+"); FILE* f = OS::FOpen(temp_filename.start(), "w+");
Isolate* isolate = Isolate::Current();
Factory* factory = isolate->factory();
Heap* heap = isolate->heap();
// Save the previous verbosity. // Save the previous verbosity.
bool prev_verbosity = FLAG_use_verbose_printer; bool prev_verbosity = FLAG_use_verbose_printer;
FLAG_use_verbose_printer = false; FLAG_use_verbose_printer = false;
@ -2096,15 +2134,14 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
// Check for ObjectGroups that references this object. // Check for ObjectGroups that references this object.
// TODO(mlam): refactor this to be more modular. // 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++) { for (int i = 0; i < groups->length(); i++) {
ObjectGroup* group = groups->at(i); ObjectGroup* group = groups->at(i);
if (group == NULL) continue; if (group == NULL) continue;
bool found_group = false; bool found_group = false;
List<Object**>& objects = group->objects_; for (size_t j = 0; j < group->length_; j++) {
for (int j = 0; j < objects.length(); j++) { Object* object = *(group->objects_[j]);
Object* object = *objects[j];
HeapObject* hobj = HeapObject::cast(object); HeapObject* hobj = HeapObject::cast(object);
if (obj2 == hobj) { if (obj2 == hobj) {
found_group = true; found_group = true;
@ -2117,8 +2154,8 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
"obj %p is a member of object group %p {\n", "obj %p is a member of object group %p {\n",
reinterpret_cast<void*>(obj2), reinterpret_cast<void*>(obj2),
reinterpret_cast<void*>(group)); reinterpret_cast<void*>(group));
for (int j = 0; j < objects.length(); j++) { for (size_t j = 0; j < group->length_; j++) {
Object* object = *objects[j]; Object* object = *(group->objects_[j]);
if (!object->IsHeapObject()) continue; if (!object->IsHeapObject()) continue;
HeapObject* hobj = HeapObject::cast(object); 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)); 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(); found = tracer.found();
if (!found) { if (!found) {
PrintF(f, " No paths found. Checking symbol tables ...\n"); 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), tracer.VisitPointers(reinterpret_cast<Object**>(&symbol_table),
reinterpret_cast<Object**>(&symbol_table)+1); reinterpret_cast<Object**>(&symbol_table)+1);
found = tracer.found(); found = tracer.found();
@ -2161,7 +2198,7 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
if (!found) { if (!found) {
PrintF(f, " No paths found. Checking weak roots ...\n"); PrintF(f, " No paths found. Checking weak roots ...\n");
// Check weak refs next. // Check weak refs next.
GlobalHandles::IterateWeakRoots(&tracer); isolate->global_handles()->IterateWeakRoots(&tracer);
found = tracer.found(); found = tracer.found();
} }
@ -2191,13 +2228,13 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
if (resource->exists() && !resource->is_empty()) { if (resource->exists() && !resource->is_empty()) {
ASSERT(resource->IsAscii()); ASSERT(resource->IsAscii());
Handle<String> path_string = Handle<String> path_string =
Factory::NewExternalStringFromAscii(resource); factory->NewExternalStringFromAscii(resource);
ExternalStringTable::AddString(*path_string); heap->external_string_table()->AddString(*path_string);
return *path_string; return *path_string;
} else { } else {
delete resource; delete resource;
} }
return Heap::undefined_value(); return heap->undefined_value();
} }
@ -2210,13 +2247,13 @@ Object* LiveObjectList::GetPath(int obj_id1,
HeapObject* obj1 = NULL; HeapObject* obj1 = NULL;
if (obj_id1 != 0) { if (obj_id1 != 0) {
obj1 = HeapObject::cast(GetObj(obj_id1)); obj1 = HeapObject::cast(GetObj(obj_id1));
if (obj1 == Heap::undefined_value()) { if (obj1 == HEAP->undefined_value()) {
return obj1; return obj1;
} }
} }
HeapObject* obj2 = HeapObject::cast(GetObj(obj_id2)); HeapObject* obj2 = HeapObject::cast(GetObj(obj_id2));
if (obj2 == Heap::undefined_value()) { if (obj2 == HEAP->undefined_value()) {
return obj2; return obj2;
} }
@ -2570,12 +2607,13 @@ void LiveObjectList::Verify(bool match_heap_exactly) {
void LiveObjectList::VerifyNotInFromSpace() { void LiveObjectList::VerifyNotInFromSpace() {
OS::Print("VerifyNotInFromSpace() ...\n"); OS::Print("VerifyNotInFromSpace() ...\n");
LolIterator it(NULL, last()); LolIterator it(NULL, last());
Heap* heap = ISOLATE->heap();
int i = 0; int i = 0;
for (it.Init(); !it.Done(); it.Next()) { for (it.Init(); !it.Done(); it.Next()) {
HeapObject* heap_obj = it.Obj(); 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", 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());
} }
} }
} }

4
deps/v8/src/liveobjectlist.h

@ -237,10 +237,10 @@ class UpdateLiveObjectListVisitor: public ObjectVisitor {
// to live new space objects, and not actually keep them alive. // to live new space objects, and not actually keep them alive.
void UpdatePointer(Object** p) { void UpdatePointer(Object** p) {
Object* object = *p; Object* object = *p;
if (!Heap::InNewSpace(object)) return; if (!HEAP->InNewSpace(object)) return;
HeapObject* heap_obj = HeapObject::cast(object); 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 // We use the first word (where the map pointer usually is) of a heap
// object to record the forwarding pointer. A forwarding pointer can // object to record the forwarding pointer. A forwarding pointer can

1
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_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_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."], strict_caller: ["Illegal access to a strict mode caller function."],
unprotected_let: ["Illegal let declaration in unprotected statement context."],
}; };
} }
var message_type = %MessageGetType(message); var message_type = %MessageGetType(message);

5
deps/v8/src/mips/frames-mips.h

@ -123,8 +123,9 @@ class StackHandlerConstants : public AllStatic {
public: public:
static const int kNextOffset = 0 * kPointerSize; static const int kNextOffset = 0 * kPointerSize;
static const int kStateOffset = 1 * kPointerSize; static const int kStateOffset = 1 * kPointerSize;
static const int kFPOffset = 2 * kPointerSize; static const int kContextOffset = 2 * kPointerSize;
static const int kPCOffset = 3 * kPointerSize; static const int kFPOffset = 3 * kPointerSize;
static const int kPCOffset = 4 * kPointerSize;
static const int kSize = kPCOffset + kPointerSize; static const int kSize = kPCOffset + kPointerSize;
}; };

6
deps/v8/src/mips/full-codegen-mips.cc

@ -4052,6 +4052,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
__ Branch(if_true, eq, v0, Operand(at)); __ Branch(if_true, eq, v0, Operand(at));
__ LoadRoot(at, Heap::kFalseValueRootIndex); __ LoadRoot(at, Heap::kFalseValueRootIndex);
Split(eq, v0, Operand(at), if_true, if_false, fall_through); 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())) { } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ LoadRoot(at, Heap::kUndefinedValueRootIndex); __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at)); __ Branch(if_true, eq, v0, Operand(at));
@ -4069,8 +4073,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
} else if (check->Equals(isolate()->heap()->object_symbol())) { } else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(v0, if_false); __ JumpIfSmi(v0, if_false);
if (!FLAG_harmony_typeof) {
__ LoadRoot(at, Heap::kNullValueRootIndex); __ LoadRoot(at, Heap::kNullValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at)); __ Branch(if_true, eq, v0, Operand(at));
}
// Check for JS objects => true. // Check for JS objects => true.
__ GetObjectType(v0, v0, a1); __ GetObjectType(v0, v0, a1);
__ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));

90
deps/v8/src/mips/macro-assembler-mips.cc

@ -2244,7 +2244,13 @@ void MacroAssembler::DebugBreak() {
void MacroAssembler::PushTryHandler(CodeLocation try_location, void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) { HandlerType type) {
// Adjust this code if not the case. // 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. // The return address is passed in register ra.
if (try_location == IN_JAVASCRIPT) { if (try_location == IN_JAVASCRIPT) {
if (type == TRY_CATCH_HANDLER) { if (type == TRY_CATCH_HANDLER) {
@ -2252,19 +2258,16 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
} else { } else {
li(t0, Operand(StackHandler::TRY_FINALLY)); 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. // Save the current handler as the next handler.
li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
lw(t1, MemOperand(t2)); lw(t1, MemOperand(t2));
addiu(sp, sp, -StackHandlerConstants::kSize); addiu(sp, sp, -StackHandlerConstants::kSize);
sw(ra, MemOperand(sp, 12)); sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset));
sw(fp, MemOperand(sp, 8)); sw(fp, MemOperand(sp, StackHandlerConstants::kFPOffset));
sw(t0, MemOperand(sp, 4)); sw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
sw(t1, MemOperand(sp, 0)); sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset));
sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset));
// Link this handler as the new current one. // Link this handler as the new current one.
sw(sp, MemOperand(t2)); sw(sp, MemOperand(t2));
@ -2272,11 +2275,6 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
} else { } else {
// Must preserve a0-a3, and s0 (argv). // Must preserve a0-a3, and s0 (argv).
ASSERT(try_location == IN_JS_ENTRY); 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 // 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 // for fp. We expect the code throwing an exception to check fp
// before dereferencing it to restore the context. // 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()))); li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
lw(t1, MemOperand(t2)); lw(t1, MemOperand(t2));
ASSERT(Smi::FromInt(0) == 0); // Used for no context.
addiu(sp, sp, -StackHandlerConstants::kSize); addiu(sp, sp, -StackHandlerConstants::kSize);
sw(ra, MemOperand(sp, 12)); sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset));
sw(zero_reg, MemOperand(sp, 8)); sw(zero_reg, MemOperand(sp, StackHandlerConstants::kFPOffset));
sw(t0, MemOperand(sp, 4)); sw(zero_reg, MemOperand(sp, StackHandlerConstants::kContextOffset));
sw(t1, MemOperand(sp, 0)); sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset));
sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset));
// Link this handler as the new current one. // Link this handler as the new current one.
sw(sp, MemOperand(t2)); sw(sp, MemOperand(t2));
@ -2299,7 +2300,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() { void MacroAssembler::PopTryHandler() {
ASSERT_EQ(0, StackHandlerConstants::kNextOffset); STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a1); pop(a1);
Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
@ -2312,28 +2313,31 @@ void MacroAssembler::Throw(Register value) {
Move(v0, value); Move(v0, value);
// Adjust this code if not the case. // 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. // Drop the sp to the top of the handler.
li(a3, Operand(ExternalReference(Isolate::k_handler_address, li(a3, Operand(ExternalReference(Isolate::k_handler_address,
isolate()))); isolate())));
lw(sp, MemOperand(a3)); lw(sp, MemOperand(a3));
// Restore the next handler and frame pointer, discard handler state. // Restore the next handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a2); pop(a2);
sw(a2, MemOperand(a3)); 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 // Restore context and frame pointer, discard state (a3).
// not NULL. The frame pointer is NULL in the exception handler of a MultiPop(a3.bit() | cp.bit() | fp.bit());
// JS entry frame.
// Set cp to NULL if fp is NULL. // 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; Label done;
Branch(USE_DELAY_SLOT, &done, eq, fp, Operand(zero_reg)); Branch(&done, eq, fp, Operand(zero_reg));
mov(cp, zero_reg); // In branch delay slot. sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
bind(&done); bind(&done);
#ifdef DEBUG #ifdef DEBUG
@ -2355,7 +2359,6 @@ void MacroAssembler::Throw(Register value) {
} }
#endif #endif
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(t9); // 2 instructions: lw, add sp. pop(t9); // 2 instructions: lw, add sp.
Jump(t9); // 2 instructions: jr, nop (in delay slot). Jump(t9); // 2 instructions: jr, nop (in delay slot).
@ -2370,7 +2373,12 @@ void MacroAssembler::Throw(Register value) {
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) { Register value) {
// Adjust this code if not the case. // 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. // v0 is expected to hold the exception.
Move(v0, value); Move(v0, value);
@ -2393,7 +2401,6 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
bind(&done); bind(&done);
// Set the top handler address to next handler past the current ENTRY handler. // Set the top handler address to next handler past the current ENTRY handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a2); pop(a2);
sw(a2, MemOperand(a3)); sw(a2, MemOperand(a3));
@ -2415,20 +2422,12 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
// Stack layout at this point. See also StackHandlerConstants. // Stack layout at this point. See also StackHandlerConstants.
// sp -> state (ENTRY) // sp -> state (ENTRY)
// cp
// fp // fp
// ra // ra
// Discard handler state (a2 is not used) and restore frame pointer. // Restore context and frame pointer, discard state (r2).
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); MultiPop(a2.bit() | cp.bit() | fp.bit());
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);
#ifdef DEBUG #ifdef DEBUG
// When emitting debug_code, set ra as return address for the jump. // 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); addiu(ra, ra, kOffsetRaBytes);
} }
#endif #endif
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(t9); // 2 instructions: lw, add sp. pop(t9); // 2 instructions: lw, add sp.
Jump(t9); // 2 instructions: jr, nop (in delay slot). Jump(t9); // 2 instructions: jr, nop (in delay slot).

8
deps/v8/src/mips/stub-cache-mips.cc

@ -3494,7 +3494,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset)); __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
__ sra(t2, key, kSmiTagSize); __ sra(t2, key, kSmiTagSize);
// Unsigned comparison catches both negative and too-large values. // 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)); __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
// a3: base pointer of external storage // 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 // This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi. // 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); __ JumpIfNotSmi(key, &miss_force_generic);
__ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the index is in range. // Check that the index is in range.
__ SmiUntag(t0, key); __ SmiUntag(t0, key);
__ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset)); __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values. // 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 // Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values. // runtime for all other kinds of values.

3
deps/v8/src/mirror-debugger.js

@ -195,7 +195,8 @@ ScopeType = { Global: 0,
Local: 1, Local: 1,
With: 2, With: 2,
Closure: 3, Closure: 3,
Catch: 4 }; Catch: 4,
Block: 5 };
// Mirror hierarchy: // Mirror hierarchy:

2
deps/v8/src/mksnapshot.cc

@ -40,8 +40,6 @@
#include "serialize.h" #include "serialize.h"
#include "list.h" #include "list.h"
// use explicit namespace to avoid clashing with types in namespace v8
namespace i = v8::internal;
using namespace v8; using namespace v8;
static const unsigned int kMaxCounters = 256; static const unsigned int kMaxCounters = 256;

22
deps/v8/src/objects-inl.h

@ -552,7 +552,8 @@ bool Object::IsContext() {
return (map == heap->function_context_map() || return (map == heap->function_context_map() ||
map == heap->catch_context_map() || map == heap->catch_context_map() ||
map == heap->with_context_map() || map == heap->with_context_map() ||
map == heap->global_context_map()); map == heap->global_context_map() ||
map == heap->block_context_map());
} }
return false; 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() { bool Object::IsJSFunction() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE; && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE;
@ -1335,14 +1343,14 @@ int HeapNumber::get_sign() {
ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset) ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
HeapObject* JSObject::elements() { FixedArrayBase* JSObject::elements() {
Object* array = READ_FIELD(this, kElementsOffset); Object* array = READ_FIELD(this, kElementsOffset);
ASSERT(array->HasValidElements()); 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() == ASSERT(map()->has_fast_elements() ==
(value->map() == GetHeap()->fixed_array_map() || (value->map() == GetHeap()->fixed_array_map() ||
value->map() == GetHeap()->fixed_cow_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(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) SMI_ACCESSORS(String, length, kLengthOffset)

35
deps/v8/src/objects.cc

@ -2318,7 +2318,8 @@ MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
if (has_exception) return Failure::Exception(); if (has_exception) return Failure::Exception();
Object* bool_result = result->ToBoolean(); 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> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError( Handle<Object> error = isolate->factory()->NewTypeError(
"handler_failed", HandleVector(args, ARRAY_SIZE(args))); "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
@ -3167,7 +3168,8 @@ MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
ASSERT(result->IsBoolean()); ASSERT(result->IsBoolean());
return *v8::Utils::OpenHandle(*result); return *v8::Utils::OpenHandle(*result);
} }
MaybeObject* raw_result = GetElementsAccessor()->Delete(*this_handle, MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
*this_handle,
index, index,
NORMAL_DELETION); NORMAL_DELETION);
RETURN_IF_SCHEDULED_EXCEPTION(isolate); RETURN_IF_SCHEDULED_EXCEPTION(isolate);
@ -4637,7 +4639,20 @@ MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { 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); PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
if (0 == deopt_count) return; 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++) { for (int i = 0; i < deopt_count; i++) {
PrintF(out, "%6d %6d %6d", PrintF(out, "%6d %6d %6d",
i, AstId(i)->value(), ArgumentsStackHeight(i)->value()); 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. // Print details of the frame translation.
int translation_index = TranslationIndex(i)->value(); int translation_index = TranslationIndex(i)->value();
TranslationIterator iterator(TranslationByteArray(), translation_index); TranslationIterator iterator(TranslationByteArray(), translation_index);
@ -8403,14 +8422,14 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
return isolate->Throw(*error); return isolate->Throw(*error);
} }
} }
Object* new_dictionary; FixedArrayBase* new_dictionary;
MaybeObject* maybe = dictionary->AtNumberPut(index, value); 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 (dictionary != NumberDictionary::cast(new_dictionary)) {
if (is_arguments) { if (is_arguments) {
elements->set(1, new_dictionary); elements->set(1, new_dictionary);
} else { } else {
set_elements(HeapObject::cast(new_dictionary)); set_elements(new_dictionary);
} }
dictionary = NumberDictionary::cast(new_dictionary); dictionary = NumberDictionary::cast(new_dictionary);
} }

49
deps/v8/src/objects.h

@ -62,17 +62,8 @@
// - JSMessageObject // - JSMessageObject
// - JSProxy // - JSProxy
// - JSFunctionProxy // - JSFunctionProxy
// - ByteArray
// - ExternalArray
// - ExternalPixelArray
// - ExternalByteArray
// - ExternalUnsignedByteArray
// - ExternalShortArray
// - ExternalUnsignedShortArray
// - ExternalIntArray
// - ExternalUnsignedIntArray
// - ExternalFloatArray
// - FixedArrayBase // - FixedArrayBase
// - ByteArray
// - FixedArray // - FixedArray
// - DescriptorArray // - DescriptorArray
// - HashTable // - HashTable
@ -85,6 +76,15 @@
// - JSFunctionResultCache // - JSFunctionResultCache
// - SerializedScopeInfo // - SerializedScopeInfo
// - FixedDoubleArray // - FixedDoubleArray
// - ExternalArray
// - ExternalPixelArray
// - ExternalByteArray
// - ExternalUnsignedByteArray
// - ExternalShortArray
// - ExternalUnsignedShortArray
// - ExternalIntArray
// - ExternalUnsignedIntArray
// - ExternalFloatArray
// - String // - String
// - SeqString // - SeqString
// - SeqAsciiString // - SeqAsciiString
@ -322,6 +322,7 @@ static const int kVariableSizeSentinel = 0;
V(POLYMORPHIC_CODE_CACHE_TYPE) \ V(POLYMORPHIC_CODE_CACHE_TYPE) \
\ \
V(FIXED_ARRAY_TYPE) \ V(FIXED_ARRAY_TYPE) \
V(FIXED_DOUBLE_ARRAY_TYPE) \
V(SHARED_FUNCTION_INFO_TYPE) \ V(SHARED_FUNCTION_INFO_TYPE) \
\ \
V(JS_MESSAGE_OBJECT_TYPE) \ V(JS_MESSAGE_OBJECT_TYPE) \
@ -635,10 +636,11 @@ enum CompareResult {
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \ WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
class DictionaryElementsAccessor;
class ElementsAccessor; class ElementsAccessor;
class StringStream; class FixedArrayBase;
class ObjectVisitor; class ObjectVisitor;
class DictionaryElementsAccessor; class StringStream;
struct ValueInfo : public Malloced { struct ValueInfo : public Malloced {
ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { } ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { }
@ -743,6 +745,7 @@ class MaybeObject BASE_EMBEDDED {
V(FixedDoubleArray) \ V(FixedDoubleArray) \
V(Context) \ V(Context) \
V(GlobalContext) \ V(GlobalContext) \
V(SerializedScopeInfo) \
V(JSFunction) \ V(JSFunction) \
V(Code) \ V(Code) \
V(Oddball) \ V(Oddball) \
@ -1492,7 +1495,7 @@ class JSObject: public JSReceiver {
// In the slow mode the elements is either a NumberDictionary, an // In the slow mode the elements is either a NumberDictionary, an
// ExternalArray, or a FixedArray parameter map for a (non-strict) // ExternalArray, or a FixedArray parameter map for a (non-strict)
// arguments object. // arguments object.
DECL_ACCESSORS(elements, HeapObject) DECL_ACCESSORS(elements, FixedArrayBase)
inline void initialize_elements(); inline void initialize_elements();
MUST_USE_RESULT inline MaybeObject* ResetElements(); MUST_USE_RESULT inline MaybeObject* ResetElements();
inline ElementsKind GetElementsKind(); inline ElementsKind GetElementsKind();
@ -2084,6 +2087,7 @@ class FixedArrayBase: public HeapObject {
static const int kHeaderSize = kLengthOffset + kPointerSize; static const int kHeaderSize = kLengthOffset + kPointerSize;
}; };
class FixedDoubleArray; class FixedDoubleArray;
// FixedArray describes fixed-sized arrays with element type Object*. // 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, // ByteArray represents fixed sized byte arrays. Used by the outside world,
// such as PCRE, and also by the memory allocator and garbage collector to // such as PCRE, and also by the memory allocator and garbage collector to
// fill in free blocks in the heap. // fill in free blocks in the heap.
class ByteArray: public HeapObject { class ByteArray: public FixedArrayBase {
public: public:
// [length]: length of the array.
inline int length();
inline void set_length(int value);
// Setter and getter. // Setter and getter.
inline byte get(int index); inline byte get(int index);
inline void set(int index, byte value); inline void set(int index, byte value);
@ -3103,10 +3103,6 @@ class ByteArray: public HeapObject {
#endif #endif
// Layout description. // 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); static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
// Maximal memory consumption for a single ByteArray. // 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 // Out-of-range values passed to the setter are converted via a C
// cast, not clamping. Out-of-range indices cause exceptions to be // cast, not clamping. Out-of-range indices cause exceptions to be
// raised rather than being silently ignored. // raised rather than being silently ignored.
class ExternalArray: public HeapObject { class ExternalArray: public FixedArrayBase {
public: public:
// [length]: length of the array.
inline int length();
inline void set_length(int value);
inline bool is_the_hole(int index) { return false; } inline bool is_the_hole(int index) { return false; }
@ -3149,9 +3142,8 @@ class ExternalArray: public HeapObject {
static const int kMaxLength = 0x3fffffff; static const int kMaxLength = 0x3fffffff;
// ExternalArray headers are not quadword aligned. // ExternalArray headers are not quadword aligned.
static const int kLengthOffset = HeapObject::kHeaderSize;
static const int kExternalPointerOffset = static const int kExternalPointerOffset =
POINTER_SIZE_ALIGN(kLengthOffset + kIntSize); POINTER_SIZE_ALIGN(FixedArrayBase::kLengthOffset + kPointerSize);
static const int kHeaderSize = kExternalPointerOffset + kPointerSize; static const int kHeaderSize = kExternalPointerOffset + kPointerSize;
static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize); static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
@ -4444,6 +4436,7 @@ class Script: public Struct {
#define FUNCTIONS_WITH_ID_LIST(V) \ #define FUNCTIONS_WITH_ID_LIST(V) \
V(Array.prototype, push, ArrayPush) \ V(Array.prototype, push, ArrayPush) \
V(Array.prototype, pop, ArrayPop) \ V(Array.prototype, pop, ArrayPop) \
V(Function.prototype, apply, FunctionApply) \
V(String.prototype, charCodeAt, StringCharCodeAt) \ V(String.prototype, charCodeAt, StringCharCodeAt) \
V(String.prototype, charAt, StringCharAt) \ V(String.prototype, charAt, StringCharAt) \
V(String, fromCharCode, StringFromCharCode) \ V(String, fromCharCode, StringFromCharCode) \

266
deps/v8/src/parser.cc

@ -584,7 +584,8 @@ Parser::Parser(Handle<Script> script,
pre_data_(pre_data), pre_data_(pre_data),
fni_(NULL), fni_(NULL),
stack_overflow_(false), stack_overflow_(false),
parenthesized_function_(false) { parenthesized_function_(false),
harmony_block_scoping_(false) {
AstNode::ResetIds(); AstNode::ResetIds();
} }
@ -809,6 +810,10 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
isolate()->Throw(*result, &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 // Base class containing common code for the different finder classes used by
// the parser. // 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, void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
int end_token, int end_token,
bool* ok) { bool* ok) {
@ -1112,21 +1136,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
} }
Scanner::Location token_loc = scanner().peek_location(); Scanner::Location token_loc = scanner().peek_location();
Statement* stat = ParseSourceElement(NULL, CHECK_OK);
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);
}
if (stat == NULL || stat->IsEmpty()) { if (stat == NULL || stat->IsEmpty()) {
directive_prologue = false; // End of directive prologue. directive_prologue = false; // End of directive prologue.
continue; continue;
@ -1214,7 +1224,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
case Token::CONST: // fall through case Token::CONST: // fall through
case Token::VAR: case Token::VAR:
stmt = ParseVariableStatement(ok); stmt = ParseVariableStatement(kStatement, ok);
break; break;
case Token::SEMICOLON: case Token::SEMICOLON:
@ -1309,9 +1319,9 @@ VariableProxy* Parser::Declare(Handle<String> name,
bool resolve, bool resolve,
bool* ok) { bool* ok) {
Variable* var = NULL; Variable* var = NULL;
// If we are inside a function, a declaration of a variable // If we are inside a function, a declaration of a var/const variable is a
// is a truly local variable, and the scope of the variable // truly local variable, and the scope of the variable is always the function
// is always the function scope. // scope.
// If a function scope exists, then we can statically declare this // If a function scope exists, then we can statically declare this
// variable and also set its mode. In any case, a Declaration node // 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. // to the calling function context.
// Similarly, strict mode eval scope does not leak variable declarations to // Similarly, strict mode eval scope does not leak variable declarations to
// the caller's scope so we declare all locals, too. // 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() || 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. // Declare the variable in the function scope.
var = declaration_scope->LocalLookup(name); var = declaration_scope->LocalLookup(name);
if (var == NULL) { if (var == NULL) {
// Declare the name. // Declare the name.
var = declaration_scope->DeclareLocal(name, mode); var = declaration_scope->DeclareLocal(name, mode);
} else { } else {
// The name was declared before; check for conflicting // The name was declared before; check for conflicting re-declarations.
// re-declarations. If the previous declaration was a const or the // We have a conflict if either of the declarations is not a var. There
// current declaration is a const then we have a conflict. There is // is similar code in runtime.cc in the Declare functions.
// similar code in runtime.cc in the Declare functions. if ((mode != Variable::VAR) || (var->mode() != Variable::VAR)) {
if ((mode == Variable::CONST) || (var->mode() == Variable::CONST)) { // We only have vars, consts and lets in declarations.
// We only have vars and consts in declarations.
ASSERT(var->mode() == Variable::VAR || ASSERT(var->mode() == Variable::VAR ||
var->mode() == Variable::CONST); var->mode() == Variable::CONST ||
const char* type = (var->mode() == Variable::VAR) ? "var" : "const"; var->mode() == Variable::LET);
const char* type = (var->mode() == Variable::VAR) ? "var" :
(var->mode() == Variable::CONST) ? "const" : "let";
Handle<String> type_string = Handle<String> type_string =
isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED); isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
Expression* expression = 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 // 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 // scope, we treat is as such and introduce the function with it's
// initial value upon entering the corresponding scope. // 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(); return EmptyStatement();
} }
Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
if (harmony_block_scoping_) return ParseScopedBlock(labels, ok);
// Block :: // Block ::
// '{' Statement* '}' // '{' 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 :: // VariableStatement ::
// VariableDeclarations ';' // VariableDeclarations ';'
Handle<String> ignore; Handle<String> ignore;
Block* result = ParseVariableDeclarations(true, &ignore, CHECK_OK); Block* result = ParseVariableDeclarations(var_context,
&ignore,
CHECK_OK);
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return result; return result;
} }
@ -1532,7 +1602,7 @@ bool Parser::IsEvalOrArguments(Handle<String> string) {
// *var is untouched; in particular, it is the caller's responsibility // *var is untouched; in particular, it is the caller's responsibility
// to initialize it properly. This mechanism is used for the parsing // to initialize it properly. This mechanism is used for the parsing
// of 'for-in' loops. // of 'for-in' loops.
Block* Parser::ParseVariableDeclarations(bool accept_IN, Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
Handle<String>* out, Handle<String>* out,
bool* ok) { bool* ok) {
// VariableDeclarations :: // VariableDeclarations ::
@ -1540,25 +1610,36 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
Variable::Mode mode = Variable::VAR; Variable::Mode mode = Variable::VAR;
bool is_const = false; bool is_const = false;
Scope* declaration_scope = top_scope_->DeclarationScope();
if (peek() == Token::VAR) { if (peek() == Token::VAR) {
Consume(Token::VAR); Consume(Token::VAR);
} else if (peek() == Token::CONST) { } else if (peek() == Token::CONST) {
Consume(Token::CONST); Consume(Token::CONST);
if (declaration_scope->is_strict_mode()) { if (top_scope_->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty()); ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false; *ok = false;
return NULL; return NULL;
} }
mode = Variable::CONST; mode = Variable::CONST;
is_const = true; 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 { } else {
UNREACHABLE(); // by current callers 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 // 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 // Scope declaration, and rewrite the source-level initialization into an
// assignment statement. We use a block to collect multiple assignments. // assignment statement. We use a block to collect multiple assignments.
// //
@ -1642,7 +1723,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
if (peek() == Token::ASSIGN) { if (peek() == Token::ASSIGN) {
Expect(Token::ASSIGN, CHECK_OK); Expect(Token::ASSIGN, CHECK_OK);
position = scanner().location().beg_pos; 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. // Don't infer if it is "a = function(){...}();"-like expression.
if (fni_ != NULL && if (fni_ != NULL &&
value->AsCall() == 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) { Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
// WithStatement :: // WithStatement ::
// 'with' '(' Expression ')' Statement // 'with' '(' Expression ')' Statement
@ -2007,7 +2053,11 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
Expression* expr = ParseExpression(true, CHECK_OK); Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, 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); Expect(Token::RPAREN, CHECK_OK);
if (peek() == Token::LBRACE) { if (peek() == Token::LBRACE) {
// Rewrite the catch body B to a single statement block // Rewrite the catch body { B } to a block:
// { try B finally { PopContext }}. // { { B } ExitContext; }.
Block* inner_body; Target target(&this->target_stack_, &catch_collector);
// 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()); catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
if (top_scope_->is_strict_mode()) { if (top_scope_->is_strict_mode()) {
catch_scope->EnableStrictMode(); catch_scope->EnableStrictMode();
} }
catch_variable = catch_scope->DeclareLocal(name, Variable::VAR); catch_variable = catch_scope->DeclareLocal(name, Variable::VAR);
catch_block = new(zone()) Block(isolate(), NULL, 2, false);
Scope* saved_scope = top_scope_; Scope* saved_scope = top_scope_;
top_scope_ = catch_scope; top_scope_ = catch_scope;
inner_body = ParseBlock(NULL, CHECK_OK); Block* catch_body = ParseBlock(NULL, CHECK_OK);
top_scope_ = saved_scope; top_scope_ = saved_scope;
} catch_block->AddStatement(catch_body);
} catch_block->AddStatement(new(zone()) ExitContextStatement());
// 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);
} else { } else {
Expect(Token::LBRACE, CHECK_OK); Expect(Token::LBRACE, CHECK_OK);
} }
@ -2290,7 +2323,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
if (peek() == Token::VAR || peek() == Token::CONST) { if (peek() == Token::VAR || peek() == Token::CONST) {
Handle<String> name; Handle<String> name;
Block* variable_statement = Block* variable_statement =
ParseVariableDeclarations(false, &name, CHECK_OK); ParseVariableDeclarations(kForStatement, &name, CHECK_OK);
if (peek() == Token::IN && !name.is_null()) { if (peek() == Token::IN && !name.is_null()) {
VariableProxy* each = top_scope_->NewUnresolved(name, inside_with()); VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
@ -3649,8 +3682,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
} }
int num_parameters = 0; int num_parameters = 0;
// Function declarations are hoisted. // Function declarations are function scoped in normal mode, so they are
Scope* scope = (type == FunctionLiteral::DECLARATION) // 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_->DeclarationScope(), Scope::FUNCTION_SCOPE, false)
: NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with()); : NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8); 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. // fails on strict mode future reserved keywords in a strict scope.
Handle<String> Parser::ParseIdentifier(bool* ok) { Handle<String> Parser::ParseIdentifier(bool* ok) {
if (top_scope_->is_strict_mode()) { 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. // Create a Scanner for the preparser to use as input, and preparse the source.
static ScriptDataImpl* DoPreParse(UC16CharacterStream* source, static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
bool allow_lazy, bool allow_lazy,
ParserRecorder* recorder) { ParserRecorder* recorder,
bool harmony_block_scoping) {
Isolate* isolate = Isolate::Current(); Isolate* isolate = Isolate::Current();
JavaScriptScanner scanner(isolate->unicode_cache()); JavaScriptScanner scanner(isolate->unicode_cache());
scanner.SetHarmonyBlockScoping(harmony_block_scoping);
scanner.Initialize(source); scanner.Initialize(source);
intptr_t stack_limit = isolate->stack_guard()->real_climit(); intptr_t stack_limit = isolate->stack_guard()->real_climit();
if (!preparser::PreParser::PreParseProgram(&scanner, if (!preparser::PreParser::PreParseProgram(&scanner,
@ -5056,7 +5094,8 @@ static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
// Preparse, but only collect data that is immediately useful, // Preparse, but only collect data that is immediately useful,
// even if the preparser data is only used once. // even if the preparser data is only used once.
ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source, ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
v8::Extension* extension) { v8::Extension* extension,
bool harmony_block_scoping) {
bool allow_lazy = FLAG_lazy && (extension == NULL); bool allow_lazy = FLAG_lazy && (extension == NULL);
if (!allow_lazy) { if (!allow_lazy) {
// Partial preparsing is only about lazily compiled functions. // Partial preparsing is only about lazily compiled functions.
@ -5064,16 +5103,17 @@ ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
return NULL; return NULL;
} }
PartialParserRecorder recorder; PartialParserRecorder recorder;
return DoPreParse(source, allow_lazy, &recorder); return DoPreParse(source, allow_lazy, &recorder, harmony_block_scoping);
} }
ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source, ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
v8::Extension* extension) { v8::Extension* extension,
bool harmony_block_scoping) {
Handle<Script> no_script; Handle<Script> no_script;
bool allow_lazy = FLAG_lazy && (extension == NULL); bool allow_lazy = FLAG_lazy && (extension == NULL);
CompleteParserRecorder recorder; 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); ASSERT(info->function() == NULL);
FunctionLiteral* result = NULL; FunctionLiteral* result = NULL;
Handle<Script> script = info->script(); Handle<Script> script = info->script();
bool harmony_block_scoping = !info->is_native() &&
FLAG_harmony_block_scoping;
if (info->is_lazy()) { if (info->is_lazy()) {
Parser parser(script, true, NULL, NULL); Parser parser(script, true, NULL, NULL);
parser.SetHarmonyBlockScoping(harmony_block_scoping);
result = parser.ParseLazy(info); result = parser.ParseLazy(info);
} else { } else {
// Whether we allow %identifier(..) syntax. // Whether we allow %identifier(..) syntax.
bool allow_natives_syntax = bool allow_natives_syntax =
info->allows_natives_syntax() || FLAG_allow_natives_syntax; info->allows_natives_syntax() || FLAG_allow_natives_syntax;
ScriptDataImpl* pre_data = info->pre_parse_data(); 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()) { if (pre_data != NULL && pre_data->has_error()) {
Scanner::Location loc = pre_data->MessageLocation(); Scanner::Location loc = pre_data->MessageLocation();
const char* message = pre_data->BuildMessage(); const char* message = pre_data->BuildMessage();
@ -5130,7 +5177,6 @@ bool ParserApi::Parse(CompilationInfo* info) {
info->StrictMode()); info->StrictMode());
} }
} }
info->SetFunction(result); info->SetFunction(result);
return (result != NULL); return (result != NULL);
} }

22
deps/v8/src/parser.h

@ -164,12 +164,14 @@ class ParserApi {
// Generic preparser generating full preparse data. // Generic preparser generating full preparse data.
static ScriptDataImpl* PreParse(UC16CharacterStream* source, 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 // Preparser that only does preprocessing that makes sense if only used
// immediately after. // immediately after.
static ScriptDataImpl* PartialPreParse(UC16CharacterStream* source, 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, void ReportMessageAt(Scanner::Location loc,
const char* message, const char* message,
Vector<Handle<String> > args); Vector<Handle<String> > args);
void SetHarmonyBlockScoping(bool block_scoping);
private: private:
// Limit on number of function parameters is chosen arbitrarily. // Limit on number of function parameters is chosen arbitrarily.
@ -451,6 +454,12 @@ class Parser {
PARSE_EAGERLY PARSE_EAGERLY
}; };
enum VariableDeclarationContext {
kSourceElement,
kStatement,
kForStatement
};
Isolate* isolate() { return isolate_; } Isolate* isolate() { return isolate_; }
Zone* zone() { return isolate_->zone(); } Zone* zone() { return isolate_->zone(); }
@ -479,12 +488,15 @@ class Parser {
// for failure at the call sites. // for failure at the call sites.
void* ParseSourceElements(ZoneList<Statement*>* processor, void* ParseSourceElements(ZoneList<Statement*>* processor,
int end_token, bool* ok); int end_token, bool* ok);
Statement* ParseSourceElement(ZoneStringList* labels, bool* ok);
Statement* ParseStatement(ZoneStringList* labels, bool* ok); Statement* ParseStatement(ZoneStringList* labels, bool* ok);
Statement* ParseFunctionDeclaration(bool* ok); Statement* ParseFunctionDeclaration(bool* ok);
Statement* ParseNativeDeclaration(bool* ok); Statement* ParseNativeDeclaration(bool* ok);
Block* ParseBlock(ZoneStringList* labels, bool* ok); Block* ParseBlock(ZoneStringList* labels, bool* ok);
Block* ParseVariableStatement(bool* ok); Block* ParseScopedBlock(ZoneStringList* labels, bool* ok);
Block* ParseVariableDeclarations(bool accept_IN, Block* ParseVariableStatement(VariableDeclarationContext var_context,
bool* ok);
Block* ParseVariableDeclarations(VariableDeclarationContext var_context,
Handle<String>* out, Handle<String>* out,
bool* ok); bool* ok);
Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels, Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels,
@ -493,7 +505,6 @@ class Parser {
Statement* ParseContinueStatement(bool* ok); Statement* ParseContinueStatement(bool* ok);
Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok); Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok);
Statement* ParseReturnStatement(bool* ok); Statement* ParseReturnStatement(bool* ok);
Block* WithHelper(Expression* obj, ZoneStringList* labels, bool* ok);
Statement* ParseWithStatement(ZoneStringList* labels, bool* ok); Statement* ParseWithStatement(ZoneStringList* labels, bool* ok);
CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok); CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok); SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok);
@ -715,6 +726,7 @@ class Parser {
// Heuristically that means that the function will be called immediately, // Heuristically that means that the function will be called immediately,
// so never lazily compile it. // so never lazily compile it.
bool parenthesized_function_; bool parenthesized_function_;
bool harmony_block_scoping_;
friend class LexicalScope; friend class LexicalScope;
}; };

2
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 // 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 // don't know which thread will run first (the original thread or the new
// one) so we initialize it here too. // one) so we initialize it here too.
#ifdef PR_SET_NAME
prctl(PR_SET_NAME, prctl(PR_SET_NAME,
reinterpret_cast<unsigned long>(thread->name()), // NOLINT reinterpret_cast<unsigned long>(thread->name()), // NOLINT
0, 0, 0); 0, 0, 0);
#endif
thread->data()->thread_ = pthread_self(); thread->data()->thread_ = pthread_self();
ASSERT(thread->data()->thread_ != kNoThread); ASSERT(thread->data()->thread_ != kNoThread);
thread->Run(); thread->Run();

1
deps/v8/src/preparser-api.cc

@ -28,6 +28,7 @@
#include "../include/v8-preparser.h" #include "../include/v8-preparser.h"
#include "globals.h" #include "globals.h"
#include "flags.h"
#include "checks.h" #include "checks.h"
#include "allocation.h" #include "allocation.h"
#include "utils.h" #include "utils.h"

52
deps/v8/src/preparser.cc

@ -56,8 +56,6 @@ namespace preparser {
// That means that contextual checks (like a label being declared where // That means that contextual checks (like a label being declared where
// it is used) are generally omitted. // it is used) are generally omitted.
namespace i = ::v8::internal;
void PreParser::ReportUnexpectedToken(i::Token::Value token) { void PreParser::ReportUnexpectedToken(i::Token::Value token) {
// We don't report stack overflows here, to avoid increasing the // We don't report stack overflows here, to avoid increasing the
// stack depth even further. Instead we report it after parsing is // 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 #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, PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
bool* ok) { bool* ok) {
// SourceElements :: // SourceElements ::
@ -121,7 +129,7 @@ PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
bool allow_directive_prologue = true; bool allow_directive_prologue = true;
while (peek() != end_token) { while (peek() != end_token) {
Statement statement = ParseStatement(CHECK_OK); Statement statement = ParseSourceElement(CHECK_OK);
if (allow_directive_prologue) { if (allow_directive_prologue) {
if (statement.IsUseStrictLiteral()) { if (statement.IsUseStrictLiteral()) {
set_strict_mode(); set_strict_mode();
@ -174,7 +182,7 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
case i::Token::CONST: case i::Token::CONST:
case i::Token::VAR: case i::Token::VAR:
return ParseVariableStatement(ok); return ParseVariableStatement(kStatement, ok);
case i::Token::SEMICOLON: case i::Token::SEMICOLON:
Next(); Next();
@ -260,7 +268,7 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) {
Expect(i::Token::LBRACE, CHECK_OK); Expect(i::Token::LBRACE, CHECK_OK);
while (peek() != i::Token::RBRACE) { while (peek() != i::Token::RBRACE) {
i::Scanner::Location start_location = scanner_->peek_location(); 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(); i::Scanner::Location end_location = scanner_->location();
if (strict_mode() && statement.IsFunctionDeclaration()) { if (strict_mode() && statement.IsFunctionDeclaration()) {
ReportMessageAt(start_location.beg_pos, end_location.end_pos, 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 :: // VariableStatement ::
// VariableDeclarations ';' // VariableDeclarations ';'
Statement result = ParseVariableDeclarations(true, NULL, CHECK_OK); Statement result = ParseVariableDeclarations(var_context,
NULL,
CHECK_OK);
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return result; return result;
} }
@ -289,7 +301,8 @@ PreParser::Statement PreParser::ParseVariableStatement(bool* ok) {
// *var is untouched; in particular, it is the caller's responsibility // *var is untouched; in particular, it is the caller's responsibility
// to initialize it properly. This mechanism is also used for the parsing // to initialize it properly. This mechanism is also used for the parsing
// of 'for-in' loops. // of 'for-in' loops.
PreParser::Statement PreParser::ParseVariableDeclarations(bool accept_IN, PreParser::Statement PreParser::ParseVariableDeclarations(
VariableDeclarationContext var_context,
int* num_decl, int* num_decl,
bool* ok) { bool* ok) {
// VariableDeclarations :: // VariableDeclarations ::
@ -306,13 +319,25 @@ PreParser::Statement PreParser::ParseVariableDeclarations(bool accept_IN,
return Statement::Default(); return Statement::Default();
} }
Consume(i::Token::CONST); 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 { } else {
*ok = false; *ok = false;
return Statement::Default(); return Statement::Default();
} }
// The scope of a variable/const declared anywhere inside a function // 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). . // 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 int nvars = 0; // the number of variables declared
do { do {
// Parse variable name. // Parse variable name.
@ -328,7 +353,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(bool accept_IN,
nvars++; nvars++;
if (peek() == i::Token::ASSIGN) { if (peek() == i::Token::ASSIGN) {
Expect(i::Token::ASSIGN, CHECK_OK); Expect(i::Token::ASSIGN, CHECK_OK);
ParseAssignmentExpression(accept_IN, CHECK_OK); ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
} }
} while (peek() == i::Token::COMMA); } while (peek() == i::Token::COMMA);
@ -537,9 +562,10 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
Expect(i::Token::FOR, CHECK_OK); Expect(i::Token::FOR, CHECK_OK);
Expect(i::Token::LPAREN, CHECK_OK); Expect(i::Token::LPAREN, CHECK_OK);
if (peek() != i::Token::SEMICOLON) { 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; int decl_count;
ParseVariableDeclarations(false, &decl_count, CHECK_OK); ParseVariableDeclarations(kForStatement, &decl_count, CHECK_OK);
if (peek() == i::Token::IN && decl_count == 1) { if (peek() == i::Token::IN && decl_count == 1) {
Expect(i::Token::IN, CHECK_OK); Expect(i::Token::IN, CHECK_OK);
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);

18
deps/v8/src/preparser.h

@ -77,6 +77,12 @@ class PreParser {
kFunctionScope kFunctionScope
}; };
enum VariableDeclarationContext {
kSourceElement,
kStatement,
kForStatement
};
class Expression; class Expression;
class Identifier { class Identifier {
@ -344,7 +350,8 @@ class PreParser {
strict_mode_violation_type_(NULL), strict_mode_violation_type_(NULL),
stack_overflow_(false), stack_overflow_(false),
allow_lazy_(true), allow_lazy_(true),
parenthesized_function_(false) { } parenthesized_function_(false),
harmony_block_scoping_(scanner->HarmonyBlockScoping()) { }
// Preparse the program. Only called in PreParseProgram after creating // Preparse the program. Only called in PreParseProgram after creating
// the instance. // the instance.
@ -377,12 +384,16 @@ class PreParser {
// which is set to false if parsing failed; it is unchanged otherwise. // which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check // By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites. // for failure at the call sites.
Statement ParseSourceElement(bool* ok);
SourceElements ParseSourceElements(int end_token, bool* ok); SourceElements ParseSourceElements(int end_token, bool* ok);
Statement ParseStatement(bool* ok); Statement ParseStatement(bool* ok);
Statement ParseFunctionDeclaration(bool* ok); Statement ParseFunctionDeclaration(bool* ok);
Statement ParseBlock(bool* ok); Statement ParseBlock(bool* ok);
Statement ParseVariableStatement(bool* ok); Statement ParseVariableStatement(VariableDeclarationContext var_context,
Statement ParseVariableDeclarations(bool accept_IN, int* num_decl, bool* ok); bool* ok);
Statement ParseVariableDeclarations(VariableDeclarationContext var_context,
int* num_decl,
bool* ok);
Statement ParseExpressionOrLabelledStatement(bool* ok); Statement ParseExpressionOrLabelledStatement(bool* ok);
Statement ParseIfStatement(bool* ok); Statement ParseIfStatement(bool* ok);
Statement ParseContinueStatement(bool* ok); Statement ParseContinueStatement(bool* ok);
@ -496,6 +507,7 @@ class PreParser {
bool stack_overflow_; bool stack_overflow_;
bool allow_lazy_; bool allow_lazy_;
bool parenthesized_function_; bool parenthesized_function_;
bool harmony_block_scoping_;
}; };
} } // v8::preparser } } // v8::preparser

19
deps/v8/src/prettyprinter.cc

@ -123,11 +123,11 @@ void PrettyPrinter::VisitReturnStatement(ReturnStatement* node) {
} }
void PrettyPrinter::VisitEnterWithContextStatement( void PrettyPrinter::VisitWithStatement(WithStatement* node) {
EnterWithContextStatement* node) { Print("with (");
Print("<enter with context> (");
Visit(node->expression()); Visit(node->expression());
Print(") "); Print(") ");
Visit(node->statement());
} }
@ -798,9 +798,10 @@ void AstPrinter::VisitReturnStatement(ReturnStatement* node) {
} }
void AstPrinter::VisitEnterWithContextStatement( void AstPrinter::VisitWithStatement(WithStatement* node) {
EnterWithContextStatement* node) { IndentedScope indent(this, "WITH");
PrintIndentedVisit("ENTER WITH CONTEXT", node->expression()); PrintIndentedVisit("OBJECT", node->expression());
PrintIndentedVisit("BODY", node->statement());
} }
@ -1194,10 +1195,10 @@ void JsonAstBuilder::VisitReturnStatement(ReturnStatement* stmt) {
} }
void JsonAstBuilder::VisitEnterWithContextStatement( void JsonAstBuilder::VisitWithStatement(WithStatement* stmt) {
EnterWithContextStatement* stmt) { TagScope tag(this, "WithStatement");
TagScope tag(this, "EnterWithContextStatement");
Visit(stmt->expression()); Visit(stmt->expression());
Visit(stmt->statement());
} }

10
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: // Do nothing:
void Processor::VisitDeclaration(Declaration* node) {} void Processor::VisitDeclaration(Declaration* node) {}
void Processor::VisitEmptyStatement(EmptyStatement* node) {} void Processor::VisitEmptyStatement(EmptyStatement* node) {}
void Processor::VisitReturnStatement(ReturnStatement* node) {} void Processor::VisitReturnStatement(ReturnStatement* node) {}
void Processor::VisitEnterWithContextStatement(
EnterWithContextStatement* node) {
}
void Processor::VisitExitContextStatement(ExitContextStatement* node) {} void Processor::VisitExitContextStatement(ExitContextStatement* node) {}
void Processor::VisitDebuggerStatement(DebuggerStatement* node) {} void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}

6
deps/v8/src/runtime-profiler.h

@ -94,12 +94,6 @@ class RuntimeProfiler {
private: private:
static const int kSamplerWindowSize = 16; 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); static void HandleWakeUp(Isolate* isolate);

83
deps/v8/src/runtime.cc

@ -4853,7 +4853,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
return isolate->heap()->boolean_symbol(); return isolate->heap()->boolean_symbol();
} }
if (heap_obj->IsNull()) { 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()); ASSERT(heap_obj->IsUndefined());
return isolate->heap()->undefined_symbol(); 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) { RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
@ -9654,7 +9680,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
CONVERT_CHECKED(JSArray, from, args[0]); CONVERT_CHECKED(JSArray, from, args[0]);
CONVERT_CHECKED(JSArray, to, args[1]); CONVERT_CHECKED(JSArray, to, args[1]);
HeapObject* new_elements = from->elements(); FixedArrayBase* new_elements = from->elements();
MaybeObject* maybe_new_map; MaybeObject* maybe_new_map;
if (new_elements->map() == isolate->heap()->fixed_array_map() || if (new_elements->map() == isolate->heap()->fixed_array_map() ||
new_elements->map() == isolate->heap()->fixed_cow_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 // 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 // backed by an actual context except the local scope, which is inserted
// "artifically" in the context chain. // "artifically" in the context chain.
@ -10649,7 +10703,8 @@ class ScopeIterator {
ScopeTypeLocal, ScopeTypeLocal,
ScopeTypeWith, ScopeTypeWith,
ScopeTypeClosure, ScopeTypeClosure,
ScopeTypeCatch ScopeTypeCatch,
ScopeTypeBlock
}; };
ScopeIterator(Isolate* isolate, ScopeIterator(Isolate* isolate,
@ -10675,8 +10730,10 @@ class ScopeIterator {
} else if (context_->IsFunctionContext()) { } else if (context_->IsFunctionContext()) {
at_local_ = true; at_local_ = true;
} else if (context_->closure() != *function_) { } else if (context_->closure() != *function_) {
// The context_ is a with or catch block from the outer function. // The context_ is a block or with or catch block from the outer function.
ASSERT(context_->IsWithContext() || context_->IsCatchContext()); ASSERT(context_->IsWithContext() ||
context_->IsCatchContext() ||
context_->IsBlockContext());
at_local_ = true; at_local_ = true;
} }
} }
@ -10731,6 +10788,9 @@ class ScopeIterator {
if (context_->IsCatchContext()) { if (context_->IsCatchContext()) {
return ScopeTypeCatch; return ScopeTypeCatch;
} }
if (context_->IsBlockContext()) {
return ScopeTypeBlock;
}
ASSERT(context_->IsWithContext()); ASSERT(context_->IsWithContext());
return ScopeTypeWith; return ScopeTypeWith;
} }
@ -10751,6 +10811,8 @@ class ScopeIterator {
case ScopeIterator::ScopeTypeClosure: case ScopeIterator::ScopeTypeClosure:
// Materialize the content of the closure scope into a JSObject. // Materialize the content of the closure scope into a JSObject.
return MaterializeClosure(isolate_, CurrentContext()); return MaterializeClosure(isolate_, CurrentContext());
case ScopeIterator::ScopeTypeBlock:
return MaterializeBlockScope(isolate_, CurrentContext());
} }
UNREACHABLE(); UNREACHABLE();
return Handle<JSObject>(); return Handle<JSObject>();
@ -11307,7 +11369,18 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate,
new_previous, new_previous,
name, name,
thrown_object); 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 { } else {
ASSERT(current->IsWithContext());
Handle<JSObject> extension(JSObject::cast(current->extension())); Handle<JSObject> extension(JSObject::cast(current->extension()));
new_current = new_current =
isolate->factory()->NewWithContext(function, new_previous, extension); isolate->factory()->NewWithContext(function, new_previous, extension);

1
deps/v8/src/runtime.h

@ -310,6 +310,7 @@ namespace internal {
F(NewFunctionContext, 1, 1) \ F(NewFunctionContext, 1, 1) \
F(PushWithContext, 2, 1) \ F(PushWithContext, 2, 1) \
F(PushCatchContext, 3, 1) \ F(PushCatchContext, 3, 1) \
F(PushBlockContext, 2, 1) \
F(DeleteContextSlot, 2, 1) \ F(DeleteContextSlot, 2, 1) \
F(LoadContextSlot, 2, 2) \ F(LoadContextSlot, 2, 2) \
F(LoadContextSlotNoReferenceError, 2, 2) \ F(LoadContextSlotNoReferenceError, 2, 2) \

104
deps/v8/src/scanner-base.cc

@ -74,7 +74,9 @@ uc32 Scanner::ScanHexEscape(uc32 c, int length) {
// JavaScriptScanner // JavaScriptScanner
JavaScriptScanner::JavaScriptScanner(UnicodeCache* scanner_contants) 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) { void JavaScriptScanner::Initialize(UC16CharacterStream* source) {
@ -815,69 +817,71 @@ uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() {
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \ #define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
KEYWORD_GROUP('b') \ KEYWORD_GROUP('b') \
KEYWORD("break", BREAK) \ KEYWORD("break", Token::BREAK) \
KEYWORD_GROUP('c') \ KEYWORD_GROUP('c') \
KEYWORD("case", CASE) \ KEYWORD("case", Token::CASE) \
KEYWORD("catch", CATCH) \ KEYWORD("catch", Token::CATCH) \
KEYWORD("class", FUTURE_RESERVED_WORD) \ KEYWORD("class", Token::FUTURE_RESERVED_WORD) \
KEYWORD("const", CONST) \ KEYWORD("const", Token::CONST) \
KEYWORD("continue", CONTINUE) \ KEYWORD("continue", Token::CONTINUE) \
KEYWORD_GROUP('d') \ KEYWORD_GROUP('d') \
KEYWORD("debugger", DEBUGGER) \ KEYWORD("debugger", Token::DEBUGGER) \
KEYWORD("default", DEFAULT) \ KEYWORD("default", Token::DEFAULT) \
KEYWORD("delete", DELETE) \ KEYWORD("delete", Token::DELETE) \
KEYWORD("do", DO) \ KEYWORD("do", Token::DO) \
KEYWORD_GROUP('e') \ KEYWORD_GROUP('e') \
KEYWORD("else", ELSE) \ KEYWORD("else", Token::ELSE) \
KEYWORD("enum", FUTURE_RESERVED_WORD) \ KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
KEYWORD("export", FUTURE_RESERVED_WORD) \ KEYWORD("export", Token::FUTURE_RESERVED_WORD) \
KEYWORD("extends", FUTURE_RESERVED_WORD) \ KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \
KEYWORD_GROUP('f') \ KEYWORD_GROUP('f') \
KEYWORD("false", FALSE_LITERAL) \ KEYWORD("false", Token::FALSE_LITERAL) \
KEYWORD("finally", FINALLY) \ KEYWORD("finally", Token::FINALLY) \
KEYWORD("for", FOR) \ KEYWORD("for", Token::FOR) \
KEYWORD("function", FUNCTION) \ KEYWORD("function", Token::FUNCTION) \
KEYWORD_GROUP('i') \ KEYWORD_GROUP('i') \
KEYWORD("if", IF) \ KEYWORD("if", Token::IF) \
KEYWORD("implements", FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("import", FUTURE_RESERVED_WORD) \ KEYWORD("import", Token::FUTURE_RESERVED_WORD) \
KEYWORD("in", IN) \ KEYWORD("in", Token::IN) \
KEYWORD("instanceof", INSTANCEOF) \ KEYWORD("instanceof", Token::INSTANCEOF) \
KEYWORD("interface", FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('l') \ KEYWORD_GROUP('l') \
KEYWORD("let", FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("let", harmony_block_scoping \
? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('n') \ KEYWORD_GROUP('n') \
KEYWORD("new", NEW) \ KEYWORD("new", Token::NEW) \
KEYWORD("null", NULL_LITERAL) \ KEYWORD("null", Token::NULL_LITERAL) \
KEYWORD_GROUP('p') \ KEYWORD_GROUP('p') \
KEYWORD("package", FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("private", FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("protected", FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("public", FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('r') \ KEYWORD_GROUP('r') \
KEYWORD("return", RETURN) \ KEYWORD("return", Token::RETURN) \
KEYWORD_GROUP('s') \ KEYWORD_GROUP('s') \
KEYWORD("static", FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("super", FUTURE_RESERVED_WORD) \ KEYWORD("super", Token::FUTURE_RESERVED_WORD) \
KEYWORD("switch", SWITCH) \ KEYWORD("switch", Token::SWITCH) \
KEYWORD_GROUP('t') \ KEYWORD_GROUP('t') \
KEYWORD("this", THIS) \ KEYWORD("this", Token::THIS) \
KEYWORD("throw", THROW) \ KEYWORD("throw", Token::THROW) \
KEYWORD("true", TRUE_LITERAL) \ KEYWORD("true", Token::TRUE_LITERAL) \
KEYWORD("try", TRY) \ KEYWORD("try", Token::TRY) \
KEYWORD("typeof", TYPEOF) \ KEYWORD("typeof", Token::TYPEOF) \
KEYWORD_GROUP('v') \ KEYWORD_GROUP('v') \
KEYWORD("var", VAR) \ KEYWORD("var", Token::VAR) \
KEYWORD("void", VOID) \ KEYWORD("void", Token::VOID) \
KEYWORD_GROUP('w') \ KEYWORD_GROUP('w') \
KEYWORD("while", WHILE) \ KEYWORD("while", Token::WHILE) \
KEYWORD("with", WITH) \ KEYWORD("with", Token::WITH) \
KEYWORD_GROUP('y') \ KEYWORD_GROUP('y') \
KEYWORD("yield", FUTURE_STRICT_RESERVED_WORD) KEYWORD("yield", Token::FUTURE_STRICT_RESERVED_WORD)
static Token::Value KeywordOrIdentifierToken(const char* input, static Token::Value KeywordOrIdentifierToken(const char* input,
int input_length) { int input_length,
bool harmony_block_scoping) {
ASSERT(input_length >= 1); ASSERT(input_length >= 1);
const int kMinLength = 2; const int kMinLength = 2;
const int kMaxLength = 10; const int kMaxLength = 10;
@ -906,7 +910,7 @@ static Token::Value KeywordOrIdentifierToken(const char* input,
(keyword_length <= 7 || input[7] == keyword[7]) && \ (keyword_length <= 7 || input[7] == keyword[7]) && \
(keyword_length <= 8 || input[8] == keyword[8]) && \ (keyword_length <= 8 || input[8] == keyword[8]) && \
(keyword_length <= 9 || input[9] == keyword[9])) { \ (keyword_length <= 9 || input[9] == keyword[9])) { \
return Token::token; \ return token; \
} \ } \
} }
KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
@ -947,7 +951,9 @@ Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
if (next_.literal_chars->is_ascii()) { if (next_.literal_chars->is_ascii()) {
Vector<const char> chars = next_.literal_chars->ascii_literal(); 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; return Token::IDENTIFIER;

11
deps/v8/src/scanner-base.h

@ -507,6 +507,14 @@ class JavaScriptScanner : public Scanner {
// tokens, which is what it is used for. // tokens, which is what it is used for.
void SeekForward(int pos); void SeekForward(int pos);
bool HarmonyBlockScoping() const {
return harmony_block_scoping_;
}
void SetHarmonyBlockScoping(bool block_scoping) {
harmony_block_scoping_ = block_scoping;
}
protected: protected:
bool SkipWhiteSpace(); bool SkipWhiteSpace();
Token::Value SkipSingleLineComment(); Token::Value SkipSingleLineComment();
@ -540,6 +548,9 @@ class JavaScriptScanner : public Scanner {
// Whether there is a multi-line comment that contains a // Whether there is a multi-line comment that contains a
// line-terminator after the current token, and before the next. // line-terminator after the current token, and before the next.
bool has_multiline_comment_before_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 } } // namespace v8::internal

2
deps/v8/src/scopeinfo.cc

@ -313,7 +313,7 @@ Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
stack_slots_.length(); stack_slots_.length();
Handle<SerializedScopeInfo> data( Handle<SerializedScopeInfo> data(
SerializedScopeInfo::cast(*FACTORY->NewFixedArray(length, TENURED))); SerializedScopeInfo::cast(*FACTORY->NewSerializedScopeInfo(length)));
AssertNoAllocation nogc; AssertNoAllocation nogc;
Object** p0 = data->data_start(); Object** p0 = data->data_start();

2
deps/v8/src/scopeinfo.h

@ -107,7 +107,7 @@ class SerializedScopeInfo : public FixedArray {
public : public :
static SerializedScopeInfo* cast(Object* object) { static SerializedScopeInfo* cast(Object* object) {
ASSERT(object->IsFixedArray()); ASSERT(object->IsSerializedScopeInfo());
return reinterpret_cast<SerializedScopeInfo*>(object); return reinterpret_cast<SerializedScopeInfo*>(object);
} }

66
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()), : isolate_(Isolate::Current()),
inner_scopes_(4), inner_scopes_(4),
variables_(), variables_(),
@ -156,7 +158,7 @@ Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info)
decls_(4), decls_(4),
already_resolved_(true) { already_resolved_(true) {
ASSERT(!scope_info.is_null()); ASSERT(!scope_info.is_null());
SetDefaults(FUNCTION_SCOPE, NULL, scope_info); SetDefaults(type, NULL, scope_info);
if (scope_info->HasHeapAllocatedLocals()) { if (scope_info->HasHeapAllocatedLocals()) {
num_heap_slots_ = scope_info_->NumberOfContextSlots(); num_heap_slots_ = scope_info_->NumberOfContextSlots();
} }
@ -232,8 +234,13 @@ Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
if (context->IsFunctionContext()) { if (context->IsFunctionContext()) {
SerializedScopeInfo* scope_info = SerializedScopeInfo* scope_info =
context->closure()->shared()->scope_info(); context->closure()->shared()->scope_info();
current_scope = current_scope = new Scope(current_scope, FUNCTION_SCOPE,
new Scope(current_scope, Handle<SerializedScopeInfo>(scope_info)); 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 { } else {
ASSERT(context->IsCatchContext()); ASSERT(context->IsCatchContext());
String* name = String::cast(context->extension()); 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 // instead load them directly from the stack. Currently, the only
// such parameter is 'this' which is passed on the stack when // such parameter is 'this' which is passed on the stack when
// invoking scripts // invoking scripts
if (is_catch_scope()) { if (is_catch_scope() || is_block_scope()) {
ASSERT(outer_scope() != NULL); ASSERT(outer_scope() != NULL);
receiver_ = outer_scope()->receiver(); receiver_ = outer_scope()->receiver();
} else { } else {
ASSERT(is_function_scope() ||
is_global_scope() ||
is_eval_scope());
Variable* var = Variable* var =
variables_.Declare(this, variables_.Declare(this,
isolate_->factory()->this_symbol(), 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 // This function handles VAR and CONST modes. DYNAMIC variables are
// introduces during variable allocation, INTERNAL variables are allocated // introduces during variable allocation, INTERNAL variables are allocated
// explicitly, and TEMPORARY variables are allocated via NewTemporary(). // 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_; ++num_var_or_const_;
return variables_.Declare(this, name, mode, true, Variable::NORMAL); return variables_.Declare(this, name, mode, true, Variable::NORMAL);
} }
@ -559,13 +571,22 @@ int Scope::ContextChainLength(Scope* scope) {
Scope* Scope::DeclarationScope() { Scope* Scope::DeclarationScope() {
Scope* scope = this; Scope* scope = this;
while (scope->is_catch_scope()) { while (scope->is_catch_scope() ||
scope->is_block_scope()) {
scope = scope->outer_scope(); scope = scope->outer_scope();
} }
return scope; return scope;
} }
Handle<SerializedScopeInfo> Scope::GetSerializedScopeInfo() {
if (scope_info_.is_null()) {
scope_info_ = SerializedScopeInfo::Create(this);
}
return scope_info_;
}
#ifdef DEBUG #ifdef DEBUG
static const char* Header(Scope::Type type) { static const char* Header(Scope::Type type) {
switch (type) { switch (type) {
@ -573,6 +594,7 @@ static const char* Header(Scope::Type type) {
case Scope::FUNCTION_SCOPE: return "function"; case Scope::FUNCTION_SCOPE: return "function";
case Scope::GLOBAL_SCOPE: return "global"; case Scope::GLOBAL_SCOPE: return "global";
case Scope::CATCH_SCOPE: return "catch"; case Scope::CATCH_SCOPE: return "catch";
case Scope::BLOCK_SCOPE: return "block";
} }
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
@ -598,9 +620,11 @@ static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
PrintF("; // "); PrintF("; // ");
if (var->rewrite() != NULL) { if (var->rewrite() != NULL) {
PrintF("%s, ", printer->Print(var->rewrite())); 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"); 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 // another variable that is introduced dynamically via an 'eval' call
// or a 'with' statement). // or a 'with' statement).
Variable* Scope::LookupRecursive(Handle<String> name, Variable* Scope::LookupRecursive(Handle<String> name,
bool inner_lookup, bool from_inner_function,
Variable** invalidated_local) { Variable** invalidated_local) {
// If we find a variable, but the current scope calls 'eval', the found // 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 // 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 // (Even if there is an 'eval' in this scope which introduces the
// same variable again, the resulting variable remains the same. // same variable again, the resulting variable remains the same.
// Note that enclosing 'with' statements are handled at the call site.) // Note that enclosing 'with' statements are handled at the call site.)
if (!inner_lookup) if (!from_inner_function)
return var; return var;
} else { } else {
@ -753,7 +777,10 @@ Variable* Scope::LookupRecursive(Handle<String> name,
var = function_; var = function_;
} else if (outer_scope_ != NULL) { } 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 // We may have found a variable in an outer scope. However, if
// the current scope is inside a 'with', the actual variable may // the current scope is inside a 'with', the actual variable may
// be a property introduced via the 'with' statement. Then, the // be a property introduced via the 'with' statement. Then, the
@ -770,8 +797,8 @@ Variable* Scope::LookupRecursive(Handle<String> name,
ASSERT(var != NULL); ASSERT(var != NULL);
// If this is a lookup from an inner scope, mark the variable. // If this is a lookup from an inner scope, mark the variable.
if (inner_lookup) { if (from_inner_function) {
var->MarkAsAccessedFromInnerScope(); var->MarkAsAccessedFromInnerFunctionScope();
} }
// If the variable we have found is just a guess, invalidate the // 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 // via an eval() call. This is only possible if the variable has a
// visible name. // visible name.
if ((var->is_this() || var->name()->length() > 0) && if ((var->is_this() || var->name()->length() > 0) &&
(var->is_accessed_from_inner_scope() || (var->is_accessed_from_inner_function_scope() ||
scope_calls_eval_ || scope_calls_eval_ ||
inner_scope_calls_eval_ || inner_scope_calls_eval_ ||
scope_contains_with_ || scope_contains_with_ ||
is_catch_scope())) { is_catch_scope() ||
is_block_scope())) {
var->set_is_used(true); var->set_is_used(true);
} }
// Global variables do not need to be allocated. // 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; // Exceptions: temporary variables are never allocated in a context;
// catch-bound variables are always allocated in a context. // catch-bound variables are always allocated in a context.
if (var->mode() == Variable::TEMPORARY) return false; if (var->mode() == Variable::TEMPORARY) return false;
if (is_catch_scope()) return true; if (is_catch_scope() || is_block_scope()) return true;
return var->is_accessed_from_inner_scope() || return var->is_accessed_from_inner_function_scope() ||
scope_calls_eval_ || scope_calls_eval_ ||
inner_scope_calls_eval_ || inner_scope_calls_eval_ ||
scope_contains_with_ || scope_contains_with_ ||
@ -1010,7 +1038,7 @@ void Scope::AllocateParameterLocals() {
if (uses_nonstrict_arguments) { if (uses_nonstrict_arguments) {
// Give the parameter a use from an inner scope, to force allocation // Give the parameter a use from an inner scope, to force allocation
// to the context. // to the context.
var->MarkAsAccessedFromInnerScope(); var->MarkAsAccessedFromInnerFunctionScope();
} }
if (MustAllocate(var)) { if (MustAllocate(var)) {

12
deps/v8/src/scopes.h

@ -93,7 +93,8 @@ class Scope: public ZoneObject {
EVAL_SCOPE, // The top-level scope for an eval source. EVAL_SCOPE, // The top-level scope for an eval source.
FUNCTION_SCOPE, // The top-level scope for a function. FUNCTION_SCOPE, // The top-level scope for a function.
GLOBAL_SCOPE, // The top-level scope for a program or a top-level eval. 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); 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_function_scope() const { return type_ == FUNCTION_SCOPE; }
bool is_global_scope() const { return type_ == GLOBAL_SCOPE; } bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
bool is_catch_scope() const { return type_ == CATCH_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() const { return strict_mode_; }
bool is_strict_mode_eval_scope() const { bool is_strict_mode_eval_scope() const {
return is_eval_scope() && is_strict_mode(); 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. // where var declarations will be hoisted to in the implementation.
Scope* DeclarationScope(); Scope* DeclarationScope();
Handle<SerializedScopeInfo> GetSerializedScopeInfo();
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Strict mode support. // Strict mode support.
bool IsDeclared(Handle<String> name) { bool IsDeclared(Handle<String> name) {
@ -397,7 +401,7 @@ class Scope: public ZoneObject {
// Variable resolution. // Variable resolution.
Variable* LookupRecursive(Handle<String> name, Variable* LookupRecursive(Handle<String> name,
bool inner_lookup, bool from_inner_function,
Variable** invalidated_local); Variable** invalidated_local);
void ResolveVariable(Scope* global_scope, void ResolveVariable(Scope* global_scope,
Handle<Context> context, Handle<Context> context,
@ -425,8 +429,8 @@ class Scope: public ZoneObject {
void AllocateVariablesRecursively(); void AllocateVariablesRecursively();
private: private:
// Construct a function scope based on the scope info. // Construct a function or block scope based on the scope info.
Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info); Scope(Scope* inner_scope, Type type, Handle<SerializedScopeInfo> scope_info);
// Construct a catch scope with a binding for the name. // Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name); Scope(Scope* inner_scope, Handle<String> catch_variable_name);

46
deps/v8/src/serialize.cc

@ -62,12 +62,7 @@ static int* GetInternalPointer(StatsCounter* counter) {
} }
// ExternalReferenceTable is a helper class that defines the relationship ExternalReferenceTable* ExternalReferenceTable::instance(Isolate* isolate) {
// 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 = ExternalReferenceTable* external_reference_table =
isolate->external_reference_table(); isolate->external_reference_table();
if (external_reference_table == NULL) { if (external_reference_table == NULL) {
@ -75,44 +70,7 @@ class ExternalReferenceTable {
isolate->set_external_reference_table(external_reference_table); isolate->set_external_reference_table(external_reference_table);
} }
return 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() { }
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];
};
void ExternalReferenceTable::AddFromId(TypeCode type, void ExternalReferenceTable::AddFromId(TypeCode type,

47
deps/v8/src/serialize.h

@ -60,6 +60,52 @@ const int kDebugRegisterBits = 4;
const int kDebugIdShift = kDebugRegisterBits; 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 { class ExternalReferenceEncoder {
public: public:
ExternalReferenceEncoder(); ExternalReferenceEncoder();
@ -544,6 +590,7 @@ class PartialSerializer : public Serializer {
ASSERT(!o->IsScript()); ASSERT(!o->IsScript());
return o->IsString() || o->IsSharedFunctionInfo() || return o->IsString() || o->IsSharedFunctionInfo() ||
o->IsHeapNumber() || o->IsCode() || o->IsHeapNumber() || o->IsCode() ||
o->IsSerializedScopeInfo() ||
o->map() == HEAP->fixed_cow_array_map(); o->map() == HEAP->fixed_cow_array_map();
} }

1
deps/v8/src/token.h

@ -168,6 +168,7 @@ namespace internal {
T(FUTURE_RESERVED_WORD, NULL, 0) \ T(FUTURE_RESERVED_WORD, NULL, 0) \
T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \ T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
K(CONST, "const", 0) \ K(CONST, "const", 0) \
K(LET, "let", 0) \
\ \
/* Illegal token - not able to scan. */ \ /* Illegal token - not able to scan. */ \
T(ILLEGAL, "ILLEGAL", 0) \ T(ILLEGAL, "ILLEGAL", 0) \

3
deps/v8/src/variables.cc

@ -41,6 +41,7 @@ const char* Variable::Mode2String(Mode mode) {
switch (mode) { switch (mode) {
case VAR: return "VAR"; case VAR: return "VAR";
case CONST: return "CONST"; case CONST: return "CONST";
case LET: return "LET";
case DYNAMIC: return "DYNAMIC"; case DYNAMIC: return "DYNAMIC";
case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL"; case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL";
case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL"; case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL";
@ -92,7 +93,7 @@ Variable::Variable(Scope* scope,
local_if_not_shadowed_(NULL), local_if_not_shadowed_(NULL),
rewrite_(NULL), rewrite_(NULL),
is_valid_LHS_(is_valid_LHS), is_valid_LHS_(is_valid_LHS),
is_accessed_from_inner_scope_(false), is_accessed_from_inner_function_scope_(false),
is_used_(false) { is_used_(false) {
// names must be canonicalized for fast equality checks // names must be canonicalized for fast equality checks
ASSERT(name->IsSymbol()); ASSERT(name->IsSymbol());

13
deps/v8/src/variables.h

@ -46,6 +46,8 @@ class Variable: public ZoneObject {
CONST, // declared via 'const' declarations CONST, // declared via 'const' declarations
LET, // declared via 'let' declarations
// Variables introduced by the compiler: // Variables introduced by the compiler:
DYNAMIC, // always require dynamic lookup (we don't know DYNAMIC, // always require dynamic lookup (we don't know
// the declaration) // the declaration)
@ -95,11 +97,12 @@ class Variable: public ZoneObject {
Handle<String> name() const { return name_; } Handle<String> name() const { return name_; }
Mode mode() const { return mode_; } Mode mode() const { return mode_; }
bool is_accessed_from_inner_scope() const { bool is_accessed_from_inner_function_scope() const {
return is_accessed_from_inner_scope_; return is_accessed_from_inner_function_scope_;
} }
void MarkAsAccessedFromInnerScope() { void MarkAsAccessedFromInnerFunctionScope() {
is_accessed_from_inner_scope_ = true; ASSERT(mode_ != TEMPORARY);
is_accessed_from_inner_function_scope_ = true;
} }
bool is_used() { return is_used_; } bool is_used() { return is_used_; }
void set_is_used(bool flag) { is_used_ = flag; } void set_is_used(bool flag) { is_used_ = flag; }
@ -156,7 +159,7 @@ class Variable: public ZoneObject {
bool is_valid_LHS_; bool is_valid_LHS_;
// Usage info. // 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_; bool is_used_;
}; };

4
deps/v8/src/version.cc

@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script. // cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3 #define MAJOR_VERSION 3
#define MINOR_VERSION 5 #define MINOR_VERSION 5
#define BUILD_NUMBER 4 #define BUILD_NUMBER 6
#define PATCH_LEVEL 3 #define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise. // Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.) // (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0 #define IS_CANDIDATE_VERSION 0

11
deps/v8/src/weakmap.js

@ -33,14 +33,13 @@ const $WeakMap = global.WeakMap;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Set the WeakMap function and constructor. function WeakMapConstructor() {
%SetCode($WeakMap, function(x) {
if (%_IsConstructCall()) { if (%_IsConstructCall()) {
%WeakMapInitialize(this); %WeakMapInitialize(this);
} else { } else {
return new $WeakMap(); return new $WeakMap();
} }
}); }
function WeakMapGet(key) { function WeakMapGet(key) {
@ -82,6 +81,12 @@ function WeakMapDelete(key) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupWeakMap() { 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. // Setup the non-enumerable functions on the WeakMap prototype object.
InstallFunctionsOnHiddenPrototype($WeakMap.prototype, DONT_ENUM, $Array( InstallFunctionsOnHiddenPrototype($WeakMap.prototype, DONT_ENUM, $Array(
"get", WeakMapGet, "get", WeakMapGet,

54
deps/v8/src/x64/code-stubs-x64.cc

@ -242,14 +242,14 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
} }
// undefined -> false // undefined -> false
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch); CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value // Boolean -> its value
CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch); CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch); CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false. // 'null' -> false.
CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch); CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) { if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true // Smis: 0 -> false, all other -> true
@ -269,7 +269,7 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
if (types_.NeedsMap()) { if (types_.NeedsMap()) {
__ movq(map, FieldOperand(argument, HeapObject::kMapOffset)); __ movq(map, FieldOperand(argument, HeapObject::kMapOffset));
// Everything with a map could be undetectable, so check this now. if (types_.CanBeUndetectable()) {
__ testb(FieldOperand(map, Map::kBitFieldOffset), __ testb(FieldOperand(map, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable)); Immediate(1 << Map::kIsUndetectable));
// Undetectable -> false. // Undetectable -> false.
@ -279,19 +279,19 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ ret(1 * kPointerSize); __ ret(1 * kPointerSize);
__ bind(&not_undetectable); __ bind(&not_undetectable);
} }
}
if (types_.Contains(SPEC_OBJECT)) { if (types_.Contains(SPEC_OBJECT)) {
// spec object -> true. // spec object -> true.
Label not_js_object; Label not_js_object;
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(below, &not_js_object, Label::kNear); __ j(below, &not_js_object, Label::kNear);
// argument contains the correct return value already.
if (!tos_.is(argument)) {
__ Set(tos_, 1); __ Set(tos_, 1);
}
__ ret(1 * kPointerSize); __ ret(1 * kPointerSize);
__ bind(&not_js_object); __ 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)) { if (types_.Contains(STRING)) {
@ -302,10 +302,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ movq(tos_, FieldOperand(argument, String::kLengthOffset)); __ movq(tos_, FieldOperand(argument, String::kLengthOffset));
__ ret(1 * kPointerSize); // the string length is OK as the return value __ ret(1 * kPointerSize); // the string length is OK as the return value
__ bind(&not_string); __ 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)) { if (types_.Contains(HEAP_NUMBER)) {
@ -316,50 +312,42 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ xorps(xmm0, xmm0); __ xorps(xmm0, xmm0);
__ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset)); __ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset));
__ j(zero, &false_result, Label::kNear); __ j(zero, &false_result, Label::kNear);
// argument contains the correct return value already.
if (!tos_.is(argument)) {
__ Set(tos_, 1); __ Set(tos_, 1);
}
__ ret(1 * kPointerSize); __ ret(1 * kPointerSize);
__ bind(&false_result); __ bind(&false_result);
__ Set(tos_, 0); __ Set(tos_, 0);
__ ret(1 * kPointerSize); __ ret(1 * kPointerSize);
__ bind(&not_heap_number); __ 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); __ bind(&patch);
GenerateTypeTransition(masm); GenerateTypeTransition(masm);
}
} }
void ToBooleanStub::CheckOddball(MacroAssembler* masm, void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type, Type type,
Heap::RootListIndex value, Heap::RootListIndex value,
bool result, bool result) {
Label* patch) {
const Register argument = rax; const Register argument = rax;
if (types_.Contains(type)) { if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_. // If we see an expected oddball, return its ToBoolean value tos_.
Label different_value; Label different_value;
__ CompareRoot(argument, value); __ CompareRoot(argument, value);
__ j(not_equal, &different_value, Label::kNear); __ 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); __ ret(1 * kPointerSize);
__ bind(&different_value); __ 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);
} }
} }

11
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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -51,11 +51,12 @@ static const int kNumSafepointRegisters = 16;
class StackHandlerConstants : public AllStatic { class StackHandlerConstants : public AllStatic {
public: public:
static const int kNextOffset = 0 * kPointerSize; static const int kNextOffset = 0 * kPointerSize;
static const int kFPOffset = 1 * kPointerSize; static const int kContextOffset = 1 * kPointerSize;
static const int kStateOffset = 2 * kPointerSize; static const int kFPOffset = 2 * kPointerSize;
static const int kPCOffset = 3 * 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;
}; };

12
deps/v8/src/x64/full-codegen-x64.cc

@ -712,8 +712,10 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ push(rsi); __ push(rsi);
__ Push(variable->name()); __ Push(variable->name());
// Declaration nodes are always introduced in one of two modes. // Declaration nodes are always introduced in one of two modes.
ASSERT(mode == Variable::VAR || mode == Variable::CONST); ASSERT(mode == Variable::VAR ||
PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; mode == Variable::CONST ||
mode == Variable::LET);
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
__ Push(Smi::FromInt(attr)); __ Push(Smi::FromInt(attr));
// Push initial value, if any. // Push initial value, if any.
// Note: For variables we must not push an initial value (such as // 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); __ j(equal, if_true);
__ CompareRoot(rax, Heap::kFalseValueRootIndex); __ CompareRoot(rax, Heap::kFalseValueRootIndex);
Split(equal, if_true, if_false, fall_through); 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())) { } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex); __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(equal, if_true); __ j(equal, if_true);
@ -3987,8 +3993,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Split(above_equal, if_true, if_false, fall_through); Split(above_equal, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->object_symbol())) { } else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(rax, if_false); __ JumpIfSmi(rax, if_false);
if (!FLAG_harmony_typeof) {
__ CompareRoot(rax, Heap::kNullValueRootIndex); __ CompareRoot(rax, Heap::kNullValueRootIndex);
__ j(equal, if_true); __ j(equal, if_true);
}
__ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx); __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
__ j(below, if_false); __ j(below, if_false);
__ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);

113
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 result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0)); Register array = ToRegister(instr->InputAt(0));
__ movq(result, FieldOperand(array, FixedArray::kLengthOffset)); __ movq(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
}
void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
__ movl(result, FieldOperand(array, ExternalPixelArray::kLengthOffset));
} }
@ -1410,40 +1403,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
// undefined -> false. // undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex); __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ j(equal, false_label); __ 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)) { if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// true -> true. // true -> true.
__ CompareRoot(reg, Heap::kTrueValueRootIndex); __ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ j(equal, true_label); __ 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. // false -> false.
__ CompareRoot(reg, Heap::kFalseValueRootIndex); __ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ j(equal, false_label); __ 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)) { if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false. // 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex); __ CompareRoot(reg, Heap::kNullValueRootIndex);
__ j(equal, false_label); __ 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)) { if (expected.Contains(ToBooleanStub::SMI)) {
@ -1460,21 +1432,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
const Register map = kScratchRegister; const Register map = kScratchRegister;
if (expected.NeedsMap()) { if (expected.NeedsMap()) {
__ movq(map, FieldOperand(reg, HeapObject::kMapOffset)); __ movq(map, FieldOperand(reg, HeapObject::kMapOffset));
// Everything with a map could be undetectable, so check this now.
if (expected.CanBeUndetectable()) {
// Undetectable -> false.
__ testb(FieldOperand(map, Map::kBitFieldOffset), __ testb(FieldOperand(map, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable)); Immediate(1 << Map::kIsUndetectable));
// Undetectable -> false.
__ j(not_zero, false_label); __ j(not_zero, false_label);
} }
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true. // spec object -> true.
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(above_equal, true_label); __ 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)) { if (expected.Contains(ToBooleanStub::STRING)) {
@ -1486,10 +1456,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ j(not_zero, true_label); __ j(not_zero, true_label);
__ jmp(false_label); __ jmp(false_label);
__ bind(&not_string); __ 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)) { if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@ -1502,21 +1468,12 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ j(zero, false_label); __ j(zero, false_label);
__ jmp(true_label); __ jmp(true_label);
__ bind(&not_heap_number); __ 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. // We've seen something for the first time -> deopt.
DeoptimizeIf(no_condition, instr->environment()); DeoptimizeIf(no_condition, instr->environment());
} }
} }
}
} }
@ -2305,16 +2262,13 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
Register elements = ToRegister(instr->elements());
Register key = ToRegister(instr->key());
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
ASSERT(result.is(elements));
// Load the result. // Load the result.
__ movq(result, FieldOperand(elements, __ movq(result,
key, BuildFastArrayOperand(instr->elements(), instr->key(),
times_pointer_size, JSObject::FAST_ELEMENTS,
FixedArray::kHeaderSize)); FixedArray::kHeaderSize - kHeapObjectTag));
// Check for the hole value. // Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) { if (instr->hydrogen()->RequiresHoleCheck()) {
@ -2348,22 +2302,22 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Operand LCodeGen::BuildFastArrayOperand( Operand LCodeGen::BuildFastArrayOperand(
LOperand* external_pointer, LOperand* elements_pointer,
LOperand* key, LOperand* key,
JSObject::ElementsKind elements_kind, JSObject::ElementsKind elements_kind,
uint32_t offset) { uint32_t offset) {
Register external_pointer_reg = ToRegister(external_pointer); Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind); int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) { if (key->IsConstantOperand()) {
int constant_value = ToInteger32(LConstantOperand::cast(key)); int constant_value = ToInteger32(LConstantOperand::cast(key));
if (constant_value & 0xF0000000) { if (constant_value & 0xF0000000) {
Abort("array index constant value too big"); Abort("array index constant value too big");
} }
return Operand(external_pointer_reg, return Operand(elements_pointer_reg,
constant_value * (1 << shift_size) + offset); constant_value * (1 << shift_size) + offset);
} else { } else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); 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); scale_factor, offset);
} }
} }
@ -2759,6 +2713,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
XMMRegister xmm_scratch = xmm0; XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result()); Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
Label done;
if (CpuFeatures::IsSupported(SSE4_1)) { if (CpuFeatures::IsSupported(SSE4_1)) {
CpuFeatures::Scope scope(SSE4_1); CpuFeatures::Scope scope(SSE4_1);
@ -2773,13 +2728,20 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
__ cmpl(output_reg, Immediate(0x80000000)); __ cmpl(output_reg, Immediate(0x80000000));
DeoptimizeIf(equal, instr->environment()); DeoptimizeIf(equal, instr->environment());
} else { } else {
// Deoptimize on negative inputs.
__ xorps(xmm_scratch, xmm_scratch); // Zero the register. __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
__ ucomisd(input_reg, xmm_scratch); __ ucomisd(input_reg, xmm_scratch);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(below_equal, instr->environment());
} else {
DeoptimizeIf(below, instr->environment()); DeoptimizeIf(below, instr->environment());
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// 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). // Use truncating instruction (OK because input is positive).
@ -2789,6 +2751,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
__ cmpl(output_reg, Immediate(0x80000000)); __ cmpl(output_reg, Immediate(0x80000000));
DeoptimizeIf(equal, instr->environment()); DeoptimizeIf(equal, instr->environment());
} }
__ bind(&done);
} }
@ -3137,12 +3100,22 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
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 {
if (instr->length()->IsRegister()) { if (instr->length()->IsRegister()) {
__ cmpq(ToRegister(instr->index()), ToRegister(instr->length())); __ cmpq(ToRegister(instr->length()), ToRegister(instr->index()));
} else { } else {
__ cmpq(ToRegister(instr->index()), ToOperand(instr->length())); __ 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); __ CompareRoot(input, Heap::kFalseValueRootIndex);
final_branch_condition = equal; 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())) { } else if (type_name->Equals(heap()->undefined_symbol())) {
__ CompareRoot(input, Heap::kUndefinedValueRootIndex); __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
__ j(equal, true_label); __ j(equal, true_label);
@ -4025,8 +4002,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
} else if (type_name->Equals(heap()->object_symbol())) { } else if (type_name->Equals(heap()->object_symbol())) {
__ JumpIfSmi(input, false_label); __ JumpIfSmi(input, false_label);
if (!FLAG_harmony_typeof) {
__ CompareRoot(input, Heap::kNullValueRootIndex); __ CompareRoot(input, Heap::kNullValueRootIndex);
__ j(equal, true_label); __ j(equal, true_label);
}
__ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
__ j(below, false_label); __ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);

2
deps/v8/src/x64/lithium-codegen-x64.h

@ -216,7 +216,7 @@ class LCodeGen BASE_EMBEDDED {
Register ToRegister(int index) const; Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const; XMMRegister ToDoubleRegister(int index) const;
Operand BuildFastArrayOperand( Operand BuildFastArrayOperand(
LOperand* external_pointer, LOperand* elements_pointer,
LOperand* key, LOperand* key,
JSObject::ElementsKind elements_kind, JSObject::ElementsKind elements_kind,
uint32_t offset); uint32_t offset);

25
deps/v8/src/x64/lithium-x64.cc

@ -1036,11 +1036,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
: instr->SecondSuccessor(); : instr->SecondSuccessor();
return new LGoto(successor->block_id()); return new LGoto(successor->block_id());
} }
LInstruction* branch = new LBranch(UseRegister(v)); return AssignEnvironment(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);
} }
@ -1502,16 +1498,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
} }
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value()); LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array)); return DefineAsRegister(new LFixedArrayBaseLength(array));
}
LInstruction* LChunkBuilder::DoExternalArrayLength(
HExternalArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LExternalArrayLength(array));
} }
@ -1529,7 +1519,8 @@ LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()), return AssignEnvironment(new LBoundsCheck(
UseRegisterOrConstantAtStart(instr->index()),
Use(instr->length()))); Use(instr->length())));
} }
@ -1829,9 +1820,9 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
ASSERT(instr->representation().IsTagged()); ASSERT(instr->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32()); ASSERT(instr->key()->representation().IsInteger32());
LOperand* obj = UseRegisterAtStart(instr->object()); LOperand* obj = UseRegisterAtStart(instr->object());
LOperand* key = UseRegisterAtStart(instr->key()); LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key); LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
return AssignEnvironment(DefineSameAsFirst(result)); return AssignEnvironment(DefineAsRegister(result));
} }

33
deps/v8/src/x64/lithium-x64.h

@ -92,8 +92,7 @@ class LCodeGen;
V(DivI) \ V(DivI) \
V(DoubleToI) \ V(DoubleToI) \
V(ElementsKind) \ V(ElementsKind) \
V(ExternalArrayLength) \ V(FixedArrayBaseLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \ V(FunctionLiteral) \
V(GetCachedArrayIndex) \ V(GetCachedArrayIndex) \
V(GlobalObject) \ 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: public:
explicit LExternalArrayLength(LOperand* value) { explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value; inputs_[0] = value;
} }
DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length") DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength) "fixed-array-base-length")
}; DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
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)
}; };
@ -2135,14 +2124,18 @@ class LChunkBuilder BASE_EMBEDDED {
template<int I, int T> template<int I, int T>
LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr, LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr,
XMMRegister reg); XMMRegister reg);
// Assigns an environment to an instruction. An instruction which can
// deoptimize must have an environment.
LInstruction* AssignEnvironment(LInstruction* instr); 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); LInstruction* AssignPointerMap(LInstruction* instr);
enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY }; enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
// By default we assume that instruction sequences generated for calls // Marks a call for the register allocator. Assigns a pointer map to
// cannot deoptimize eagerly and we do not attach environment to this // support GC and lazy deoptimization. Assigns an environment to support
// instruction. // eager deoptimization if CAN_DEOPTIMIZE_EAGERLY.
LInstruction* MarkAsCall( LInstruction* MarkAsCall(
LInstruction* instr, LInstruction* instr,
HInstruction* hinstr, HInstruction* hinstr,

69
deps/v8/src/x64/macro-assembler-x64.cc

@ -2387,18 +2387,15 @@ Operand MacroAssembler::SafepointRegisterSlot(Register reg) {
void MacroAssembler::PushTryHandler(CodeLocation try_location, void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) { HandlerType type) {
// Adjust this code if not the case. // 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, // The pc (return address) is already on TOS. This code pushes state,
// frame pointer and current handler. Check that they are expected // frame pointer, context, and current handler.
// 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);
if (try_location == IN_JAVASCRIPT) { if (try_location == IN_JAVASCRIPT) {
if (type == TRY_CATCH_HANDLER) { if (type == TRY_CATCH_HANDLER) {
push(Immediate(StackHandler::TRY_CATCH)); push(Immediate(StackHandler::TRY_CATCH));
@ -2406,6 +2403,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
push(Immediate(StackHandler::TRY_FINALLY)); push(Immediate(StackHandler::TRY_FINALLY));
} }
push(rbp); push(rbp);
push(rsi);
} else { } else {
ASSERT(try_location == IN_JS_ENTRY); ASSERT(try_location == IN_JS_ENTRY);
// The frame pointer does not point to a JS frame so we save NULL // 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. // before dereferencing it to restore the context.
push(Immediate(StackHandler::ENTRY)); push(Immediate(StackHandler::ENTRY));
push(Immediate(0)); // NULL frame pointer. push(Immediate(0)); // NULL frame pointer.
Push(Smi::FromInt(0)); // No context.
} }
// Save the current handler. // Save the current handler.
Operand handler_operand = Operand handler_operand =
@ -2435,12 +2434,13 @@ void MacroAssembler::PopTryHandler() {
void MacroAssembler::Throw(Register value) { void MacroAssembler::Throw(Register value) {
// Check that stack should contain next handler, frame pointer, state and // Adjust this code if not the case.
// return address in that order. STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize == STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
StackHandlerConstants::kStateOffset); STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize == STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
StackHandlerConstants::kPCOffset); STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// Keep thrown value in rax. // Keep thrown value in rax.
if (!value.is(rax)) { if (!value.is(rax)) {
movq(rax, value); movq(rax, value);
@ -2451,23 +2451,32 @@ void MacroAssembler::Throw(Register value) {
movq(rsp, handler_operand); movq(rsp, handler_operand);
// get next in chain // get next in chain
pop(handler_operand); pop(handler_operand);
pop(rbp); // pop frame pointer pop(rsi); // Context.
pop(rdx); // remove state pop(rbp); // Frame pointer.
pop(rdx); // State.
// Before returning we restore the context from the frame pointer if not NULL. // If the handler is a JS frame, restore the context to the frame.
// The frame pointer is NULL in the exception handler of a JS entry frame. // (rdx == ENTRY) == (rbp == 0) == (rsi == 0), so we could test any
Set(rsi, 0); // Tentatively set context pointer to NULL // of them.
Label skip; Label skip;
cmpq(rbp, Immediate(0)); cmpq(rdx, Immediate(StackHandler::ENTRY));
j(equal, &skip, Label::kNear); j(equal, &skip, Label::kNear);
movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
bind(&skip); bind(&skip);
ret(0); ret(0);
} }
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) { 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. // Keep thrown value in rax.
if (!value.is(rax)) { if (!value.is(rax)) {
movq(rax, value); movq(rax, value);
@ -2507,19 +2516,13 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Store(pending_exception, rax); 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); Set(rsi, 0);
// Restore registers from handler. pop(rbp); // Restore frame pointer.
STATIC_ASSERT(StackHandlerConstants::kNextOffset + kPointerSize == pop(rdx); // Discard state.
StackHandlerConstants::kFPOffset);
pop(rbp); // FP
STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize ==
StackHandlerConstants::kStateOffset);
pop(rdx); // State
STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize ==
StackHandlerConstants::kPCOffset);
ret(0); ret(0);
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save