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. 16
      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. 44
      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
/build/gyp
/obj/
/out/
/test/es5conform/data/
/test/mozilla/data/
/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
Added a preliminary implementation of ES Harmony weak maps. Weak

16
deps/v8/include/v8.h

@ -171,7 +171,7 @@ template <class T> class Handle {
/**
* Creates an empty handle.
*/
inline Handle();
inline Handle() : val_(0) {}
/**
* Creates a new handle for the specified value.
@ -203,14 +203,14 @@ template <class T> class Handle {
*/
inline bool IsEmpty() const { return val_ == 0; }
inline T* operator->() const { return val_; }
inline T* operator*() const { return val_; }
/**
* Sets the handle to be empty. IsEmpty() will then return true.
*/
inline void Clear() { this->val_ = 0; }
inline void Clear() { val_ = 0; }
inline T* operator->() const { return val_; }
inline T* operator*() const { return val_; }
/**
* Checks whether two handles are the same.
@ -3826,10 +3826,6 @@ class Internals {
} // namespace internal
template <class T>
Handle<T>::Handle() : val_(0) { }
template <class T>
Local<T>::Local() : Handle<T>() { }

12
deps/v8/src/api.cc

@ -35,6 +35,7 @@
#include "debug.h"
#include "deoptimizer.h"
#include "execution.h"
#include "flags.h"
#include "global-handles.h"
#include "heap-profiler.h"
#include "messages.h"
@ -1405,7 +1406,7 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
ScriptData* ScriptData::PreCompile(const char* input, int length) {
i::Utf8ToUC16CharacterStream stream(
reinterpret_cast<const unsigned char*>(input), length);
return i::ParserApi::PreParse(&stream, NULL);
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping);
}
@ -1414,10 +1415,10 @@ ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
if (str->IsExternalTwoByteString()) {
i::ExternalTwoByteStringUC16CharacterStream stream(
i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length());
return i::ParserApi::PreParse(&stream, NULL);
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping);
} else {
i::GenericStringUC16CharacterStream stream(str, 0, str->length());
return i::ParserApi::PreParse(&stream, NULL);
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping);
}
}
@ -3163,10 +3164,9 @@ static i::Context* GetCreationContext(i::JSObject* object) {
i::Object* constructor = object->map()->constructor();
i::JSFunction* function;
if (!constructor->IsJSFunction()) {
// API functions have null as a constructor,
// Functions have null as a constructor,
// but any JSFunction knows its context immediately.
ASSERT(object->IsJSFunction() &&
i::JSFunction::cast(object)->shared()->IsApiFunction());
ASSERT(object->IsJSFunction());
function = i::JSFunction::cast(object);
} else {
function = i::JSFunction::cast(constructor);

14
deps/v8/src/apinatives.js

@ -49,7 +49,10 @@ function Instantiate(data, name) {
return InstantiateFunction(data, name);
case kNewObjectTag:
var Constructor = %GetTemplateField(data, kApiConstructorOffset);
var result = Constructor ? new (Instantiate(Constructor))() : {};
// Note: Do not directly use a function template as a condition, our
// internal ToBoolean doesn't handle that!
var result = typeof Constructor === 'undefined' ?
{} : new (Instantiate(Constructor))();
ConfigureTemplateInstance(result, data);
result = %ToFastProperties(result);
return result;
@ -74,13 +77,18 @@ function InstantiateFunction(data, name) {
cache[serialNumber] = fun;
var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset);
var flags = %GetTemplateField(data, kApiFlagOffset);
fun.prototype = prototype ? Instantiate(prototype) : {};
// Note: Do not directly use an object template as a condition, our
// internal ToBoolean doesn't handle that!
fun.prototype = typeof prototype === 'undefined' ?
{} : Instantiate(prototype);
if (flags & (1 << kReadOnlyPrototypeBit)) {
%FunctionSetReadOnlyPrototype(fun);
}
%SetProperty(fun.prototype, "constructor", fun, DONT_ENUM);
var parent = %GetTemplateField(data, kApiParentTemplateOffset);
if (parent) {
// Note: Do not directly use a function template as a condition, our
// internal ToBoolean doesn't handle that!
if (!(typeof parent === 'undefined')) {
var parent_fun = Instantiate(parent);
fun.prototype.__proto__ = parent_fun.prototype;
}

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;
// undefined -> false.
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value.
CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false.
CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true
@ -1635,23 +1635,20 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
if (types_.NeedsMap()) {
__ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
// Everything with a map could be undetectable, so check this now.
if (types_.CanBeUndetectable()) {
__ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
__ tst(ip, Operand(1 << Map::kIsUndetectable));
// Undetectable -> false.
__ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
__ Ret(ne);
}
}
if (types_.Contains(SPEC_OBJECT)) {
// Spec object -> true.
__ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
// tos_ contains the correct non-zero return value already.
__ Ret(ge);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// We've seen a spec object for the first time -> patch.
__ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
__ b(ge, &patch);
}
if (types_.Contains(STRING)) {
@ -1659,10 +1656,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
__ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
__ Ret(lt); // the string length is OK as the return value
} else if (types_.Contains(INTERNAL_OBJECT)) {
// We've seen a string for the first time -> patch
__ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
__ b(lt, &patch);
}
if (types_.Contains(HEAP_NUMBER)) {
@ -1679,30 +1672,17 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN
__ Ret();
__ bind(&not_heap_number);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// We've seen a heap number for the first time -> patch
__ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
__ b(eq, &patch);
}
if (types_.Contains(INTERNAL_OBJECT)) {
// Internal objects -> true.
__ mov(tos_, Operand(1, RelocInfo::NONE));
__ Ret();
}
if (!types_.IsAll()) {
__ bind(&patch);
GenerateTypeTransition(masm);
}
}
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
bool result,
Label* patch) {
bool result) {
if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_.
__ LoadRoot(ip, value);
@ -1713,12 +1693,6 @@ void ToBooleanStub::CheckOddball(MacroAssembler* masm,
__ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq);
}
__ Ret(eq);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// If we see an unexpected oddball and handle internal objects, we must
// patch because the code for internal objects doesn't handle it explictly.
__ LoadRoot(ip, value);
__ cmp(tos_, ip);
__ b(eq, patch);
}
}
@ -6341,12 +6315,8 @@ void DirectCEntryStub::Generate(MacroAssembler* masm) {
void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
ExternalReference function) {
__ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()),
RelocInfo::CODE_TARGET));
__ mov(r2, Operand(function));
// Push return address (accessible to GC through exit frame pc).
__ str(pc, MemOperand(sp, 0));
__ Jump(r2); // Call the api function.
GenerateCall(masm, r2);
}
@ -6355,8 +6325,14 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
__ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()),
RelocInfo::CODE_TARGET));
// Push return address (accessible to GC through exit frame pc).
__ str(pc, MemOperand(sp, 0));
// Note that using pc with str is deprecated.
Label start;
__ bind(&start);
__ add(ip, pc, Operand(Assembler::kInstrSize));
__ str(ip, MemOperand(sp, 0));
__ Jump(target); // Call the C++ function.
ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta,
masm->SizeOfCodeGeneratedSince(&start));
}

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

@ -593,6 +593,8 @@ void Deoptimizer::EntryGenerator::Generate() {
__ vstm(db_w, sp, first, last);
// Push all 16 registers (needed to populate FrameDescription::registers_).
// TODO(1588) Note that using pc with stm is deprecated, so we should perhaps
// handle this a bit differently.
__ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit());
const int kSavedRegistersAreaSize =

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
// modification, are permitted provided that the following conditions are
// met:
@ -95,8 +95,9 @@ class StackHandlerConstants : public AllStatic {
public:
static const int kNextOffset = 0 * kPointerSize;
static const int kStateOffset = 1 * kPointerSize;
static const int kFPOffset = 2 * kPointerSize;
static const int kPCOffset = 3 * kPointerSize;
static const int kContextOffset = 2 * kPointerSize;
static const int kFPOffset = 3 * kPointerSize;
static const int kPCOffset = 4 * 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()));
// Declaration nodes are always introduced in one of two modes.
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST);
PropertyAttributes attr =
(mode == Variable::VAR) ? NONE : READ_ONLY;
mode == Variable::CONST ||
mode == Variable::LET);
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
__ mov(r1, Operand(Smi::FromInt(attr)));
// Push initial value, if any.
// Note: For variables we must not push an initial value (such as
@ -4030,6 +4030,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
__ b(eq, if_true);
__ CompareRoot(r0, Heap::kFalseValueRootIndex);
Split(eq, if_true, if_false, fall_through);
} else if (FLAG_harmony_typeof &&
check->Equals(isolate()->heap()->null_symbol())) {
__ CompareRoot(r0, Heap::kNullValueRootIndex);
Split(eq, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
__ b(eq, if_true);
@ -4047,8 +4051,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
} else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(r0, if_false);
if (!FLAG_harmony_typeof) {
__ CompareRoot(r0, Heap::kNullValueRootIndex);
__ b(eq, if_true);
}
// Check for JS objects => true.
__ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(lt, if_false);

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

@ -1039,13 +1039,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
: instr->SecondSuccessor();
return new LGoto(successor->block_id());
}
LInstruction* branch = new LBranch(UseRegister(v));
// When we handle all cases, we never deopt, so we don't need to assign the
// environment then. Note that we map the "empty" case to the "all" case in
// the code generator.
ToBooleanStub::Types types = instr->expected_input_types();
bool all_cases_handled = types.IsAll() || types.IsEmpty();
return all_cases_handled ? branch : AssignEnvironment(branch);
return AssignEnvironment(new LBranch(UseRegister(v)));
}
@ -1515,16 +1509,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
LInstruction* LChunkBuilder::DoExternalArrayLength(
HExternalArrayLength* instr) {
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LExternalArrayLength(array));
}
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array));
return DefineAsRegister(new LFixedArrayBaseLength(array));
}

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

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

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

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

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

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

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

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

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

2
deps/v8/src/ast.cc

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

22
deps/v8/src/ast.h

@ -60,7 +60,7 @@ namespace internal {
V(ContinueStatement) \
V(BreakStatement) \
V(ReturnStatement) \
V(EnterWithContextStatement) \
V(WithStatement) \
V(ExitContextStatement) \
V(SwitchStatement) \
V(DoWhileStatement) \
@ -359,9 +359,13 @@ class Block: public BreakableStatement {
ZoneList<Statement*>* statements() { return &statements_; }
bool is_initializer_block() const { return is_initializer_block_; }
Scope* block_scope() const { return block_scope_; }
void set_block_scope(Scope* block_scope) { block_scope_ = block_scope; }
private:
ZoneList<Statement*> statements_;
bool is_initializer_block_;
Scope* block_scope_;
};
@ -371,9 +375,11 @@ class Declaration: public AstNode {
: proxy_(proxy),
mode_(mode),
fun_(fun) {
ASSERT(mode == Variable::VAR || mode == Variable::CONST);
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
// At the moment there are no "const functions"'s in JavaScript...
ASSERT(fun == NULL || mode == Variable::VAR);
ASSERT(fun == NULL || mode == Variable::VAR || mode == Variable::LET);
}
DECLARE_NODE_TYPE(Declaration)
@ -627,19 +633,21 @@ class ReturnStatement: public Statement {
};
class EnterWithContextStatement: public Statement {
class WithStatement: public Statement {
public:
explicit EnterWithContextStatement(Expression* expression)
: expression_(expression) { }
WithStatement(Expression* expression, Statement* statement)
: expression_(expression), statement_(statement) { }
DECLARE_NODE_TYPE(EnterWithContextStatement)
DECLARE_NODE_TYPE(WithStatement)
Expression* expression() const { return expression_; }
Statement* statement() const { return statement_; }
virtual bool IsInlineable() const;
private:
Expression* expression_;
Statement* statement_;
};

5
deps/v8/src/bootstrapper.cc

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

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

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

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

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

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

21
deps/v8/src/contexts.cc

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

4
deps/v8/src/contexts.h

@ -295,6 +295,10 @@ class Context: public FixedArray {
Map* map = this->map();
return map == map->GetHeap()->with_context_map();
}
bool IsBlockContext() {
Map* map = this->map();
return map == map->GetHeap()->block_context_map();
}
// Tells whether the global context is marked with out of memory.
inline bool has_out_of_memory();

1
deps/v8/src/d8.cc

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

4
deps/v8/src/d8.h

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

3
deps/v8/src/d8.js

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

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

80
deps/v8/src/elements.cc

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

4
deps/v8/src/elements.h

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

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) {
icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
if (!date_format) {
ThrowUnexpectedObjectError();
return ThrowUnexpectedObjectError();
}
const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();

22
deps/v8/src/factory.cc

@ -34,6 +34,7 @@
#include "macro-assembler.h"
#include "objects.h"
#include "objects-visiting.h"
#include "scopeinfo.h"
namespace v8 {
namespace internal {
@ -291,6 +292,19 @@ Handle<Context> Factory::NewWithContext(Handle<JSFunction> function,
}
Handle<Context> Factory::NewBlockContext(
Handle<JSFunction> function,
Handle<Context> previous,
Handle<SerializedScopeInfo> scope_info) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateBlockContext(*function,
*previous,
*scope_info),
Context);
}
Handle<Struct> Factory::NewStruct(InstanceType type) {
CALL_HEAP_FUNCTION(
isolate(),
@ -734,6 +748,14 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
}
Handle<SerializedScopeInfo> Factory::NewSerializedScopeInfo(int length) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateSerializedScopeInfo(length),
SerializedScopeInfo);
}
Handle<Code> Factory::NewCode(const CodeDesc& desc,
Code::Flags flags,
Handle<Object> self_ref,

7
deps/v8/src/factory.h

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

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

@ -97,8 +97,10 @@ private:
#define FLAG FLAG_FULL
// Flags for experimental language features.
DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof")
DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps")
DEFINE_bool(harmony_block_scoping, false, "enable harmony block scoping")
// Flags for experimental implementation features.
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")

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
// modification, are permitted provided that the following conditions are
// met:
@ -67,6 +67,7 @@ inline bool StackHandler::includes(Address address) const {
inline void StackHandler::Iterate(ObjectVisitor* v, Code* holder) const {
v->VisitPointer(context_address());
StackFrame::IteratePc(v, pc_address(), holder);
}
@ -82,6 +83,12 @@ inline StackHandler::State StackHandler::state() const {
}
inline Object** StackHandler::context_address() const {
const int offset = StackHandlerConstants::kContextOffset;
return reinterpret_cast<Object**>(address() + offset);
}
inline Address* StackHandler::pc_address() const {
const int offset = StackHandlerConstants::kPCOffset;
return reinterpret_cast<Address*>(address() + offset);

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
// modification, are permitted provided that the following conditions are
// met:
@ -114,6 +114,7 @@ class StackHandler BASE_EMBEDDED {
// Accessors.
inline State state() const;
inline Object** context_address() const;
inline Address* pc_address() const;
DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);

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

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

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

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

43
deps/v8/src/heap.cc

@ -1745,6 +1745,12 @@ bool Heap::CreateInitialMaps() {
set_fixed_cow_array_map(Map::cast(obj));
ASSERT(fixed_array_map() != fixed_cow_array_map());
{ MaybeObject* maybe_obj =
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_serialized_scope_info_map(Map::cast(obj));
{ MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
if (!maybe_obj->ToObject(&obj)) return false;
}
@ -1906,6 +1912,12 @@ bool Heap::CreateInitialMaps() {
}
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 =
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
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) {
Map* map;
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, global_context_map, GlobalContextMap) \
V(Map, fixed_array_map, FixedArrayMap) \
V(Map, serialized_scope_info_map, SerializedScopeInfoMap) \
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \
@ -111,6 +112,7 @@ inline Heap* _inline_get_heap_();
V(Map, function_context_map, FunctionContextMap) \
V(Map, catch_context_map, CatchContextMap) \
V(Map, with_context_map, WithContextMap) \
V(Map, block_context_map, BlockContextMap) \
V(Map, code_map, CodeMap) \
V(Map, oddball_map, OddballMap) \
V(Map, global_property_cell_map, GlobalPropertyCellMap) \
@ -160,6 +162,7 @@ inline Heap* _inline_get_heap_();
V(length_symbol, "length") \
V(name_symbol, "name") \
V(native_symbol, "native") \
V(null_symbol, "null") \
V(number_symbol, "number") \
V(Number_symbol, "Number") \
V(nan_symbol, "NaN") \
@ -220,7 +223,8 @@ inline Heap* _inline_get_heap_();
V(closure_symbol, "(closure)") \
V(use_strict, "use strict") \
V(dot_symbol, ".") \
V(anonymous_function_symbol, "(anonymous function)")
V(anonymous_function_symbol, "(anonymous function)") \
V(block_scope_symbol, ".block")
// Forward declarations.
class GCTracer;
@ -483,6 +487,9 @@ class Heap {
// Allocates an empty code cache.
MUST_USE_RESULT MaybeObject* AllocateCodeCache();
// Allocates a serialized scope info.
MUST_USE_RESULT MaybeObject* AllocateSerializedScopeInfo(int length);
// Allocates an empty PolymorphicCodeCache.
MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache();
@ -668,6 +675,11 @@ class Heap {
Context* previous,
JSObject* extension);
// Allocate a block context.
MUST_USE_RESULT MaybeObject* AllocateBlockContext(JSFunction* function,
Context* previous,
SerializedScopeInfo* info);
// Allocates a new utility object in the old generation.
MUST_USE_RESULT MaybeObject* AllocateStruct(InstanceType type);

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

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

@ -104,8 +104,7 @@ class LChunkBuilder;
V(Div) \
V(ElementsKind) \
V(EnterInlined) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FixedArrayBaseLength) \
V(ForceRepresentation) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
@ -1702,9 +1701,9 @@ class HJSArrayLength: public HTemplateInstruction<2> {
};
class HFixedArrayLength: public HUnaryOperation {
class HFixedArrayBaseLength: public HUnaryOperation {
public:
explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) {
explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kDependsOnArrayLengths);
@ -1714,28 +1713,7 @@ class HFixedArrayLength: public HUnaryOperation {
return Representation::Tagged();
}
DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength)
protected:
virtual bool DataEquals(HValue* other) { return true; }
};
class HExternalArrayLength: public HUnaryOperation {
public:
explicit HExternalArrayLength(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Integer32());
// The result of this instruction is idempotent as long as its inputs don't
// change. The length of a pixel array cannot change once set, so it's not
// necessary to introduce a kDependsOnArrayLengths or any other dependency.
SetFlag(kUseGVN);
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength)
DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength)
protected:
virtual bool DataEquals(HValue* other) { return true; }
@ -2471,6 +2449,8 @@ class HBoundsCheck: public HTemplateInstruction<2> {
return Representation::Integer32();
}
virtual void PrintDataTo(StringStream* stream);
HValue* index() { return OperandAt(0); }
HValue* length() { return OperandAt(1); }
@ -3438,6 +3418,8 @@ class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> {
return Representation::Tagged();
}
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic)
static const int kMaxLoadPolymorphism = 4;
@ -3471,6 +3453,8 @@ class HLoadNamedGeneric: public HTemplateInstruction<2> {
return Representation::Tagged();
}
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
private:

37
deps/v8/src/hydrogen.cc

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

3
deps/v8/src/hydrogen.h

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

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) {
ASSERT(CpuFeatures::IsEnabled(SSE2));
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 ucomisd(XMMRegister dst, XMMRegister src);
enum RoundingMode {
kRoundToNearest = 0x0,
kRoundDown = 0x1,
kRoundUp = 0x2,
kRoundToZero = 0x3
};
void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
void movmskpd(Register dst, XMMRegister src);
void cmpltsd(XMMRegister dst, XMMRegister src);

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

@ -249,20 +249,20 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
}
// undefined -> false
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value
CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false.
CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true
Label not_smi;
__ JumpIfNotSmi(argument, &not_smi, Label::kNear);
// argument contains the correct return value already
// argument contains the correct return value already.
if (!tos_.is(argument)) {
__ mov(tos_, argument);
}
@ -276,7 +276,7 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
if (types_.NeedsMap()) {
__ mov(map, FieldOperand(argument, HeapObject::kMapOffset));
// Everything with a map could be undetectable, so check this now.
if (types_.CanBeUndetectable()) {
__ test_b(FieldOperand(map, Map::kBitFieldOffset),
1 << Map::kIsUndetectable);
// Undetectable -> false.
@ -286,19 +286,19 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ ret(1 * kPointerSize);
__ bind(&not_undetectable);
}
}
if (types_.Contains(SPEC_OBJECT)) {
// spec object -> true.
Label not_js_object;
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(below, &not_js_object, Label::kNear);
// argument contains the correct return value already.
if (!tos_.is(argument)) {
__ Set(tos_, Immediate(1));
}
__ ret(1 * kPointerSize);
__ bind(&not_js_object);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// We've seen a spec object for the first time -> patch.
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(above_equal, &patch, Label::kNear);
}
if (types_.Contains(STRING)) {
@ -309,10 +309,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ mov(tos_, FieldOperand(argument, String::kLengthOffset));
__ ret(1 * kPointerSize); // the string length is OK as the return value
__ bind(&not_string);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// We've seen a string for the first time -> patch
__ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
__ j(below, &patch, Label::kNear);
}
if (types_.Contains(HEAP_NUMBER)) {
@ -324,50 +320,42 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ fld_d(FieldOperand(argument, HeapNumber::kValueOffset));
__ FCmp();
__ j(zero, &false_result, Label::kNear);
// argument contains the correct return value already.
if (!tos_.is(argument)) {
__ Set(tos_, Immediate(1));
}
__ ret(1 * kPointerSize);
__ bind(&false_result);
__ Set(tos_, Immediate(0));
__ ret(1 * kPointerSize);
__ bind(&not_heap_number);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// We've seen a heap number for the first time -> patch
__ cmp(map, factory->heap_number_map());
__ j(equal, &patch, Label::kNear);
}
if (types_.Contains(INTERNAL_OBJECT)) {
// internal objects -> true
__ Set(tos_, Immediate(1));
__ ret(1 * kPointerSize);
}
if (!types_.IsAll()) {
__ bind(&patch);
GenerateTypeTransition(masm);
}
}
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
bool result,
Label* patch) {
bool result) {
const Register argument = eax;
if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_.
Label different_value;
__ CompareRoot(argument, value);
__ j(not_equal, &different_value, Label::kNear);
__ Set(tos_, Immediate(result ? 1 : 0));
if (!result) {
// If we have to return zero, there is no way around clearing tos_.
__ Set(tos_, Immediate(0));
} else if (!tos_.is(argument)) {
// If we have to return non-zero, we can re-use the argument if it is the
// same register as the result, because we never see Smi-zero here.
__ Set(tos_, Immediate(1));
}
__ ret(1 * kPointerSize);
__ bind(&different_value);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// If we see an unexpected oddball and handle internal objects, we must
// patch because the code for internal objects doesn't handle it explictly.
__ CompareRoot(argument, value);
__ j(equal, patch);
}
}

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) {
data++;
if (*data == 0x16) {
if (*data == 0x0B) {
data++;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
int8_t imm8 = static_cast<int8_t>(data[1]);
AppendToBuffer("roundsd %s,%s,%d",
NameOfXMMRegister(regop),
NameOfXMMRegister(rm),
static_cast<int>(imm8));
data += 2;
} else if (*data == 0x16) {
data++;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);

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

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

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

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

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

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

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

@ -1047,10 +1047,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
// involving maps).
bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
LOperand* temp = needs_temp ? TempRegister() : NULL;
LInstruction* branch = new LBranch(UseRegister(v), temp);
// When we handle all cases, we never deopt, so we don't need to assign the
// environment then.
return expected.IsAll() ? branch : AssignEnvironment(branch);
return AssignEnvironment(new LBranch(UseRegister(v), temp));
}
@ -1541,16 +1538,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array));
}
LInstruction* LChunkBuilder::DoExternalArrayLength(
HExternalArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LExternalArrayLength(array));
return DefineAsRegister(new LFixedArrayBaseLength(array));
}
@ -1568,7 +1559,8 @@ LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
return AssignEnvironment(new LBoundsCheck(
UseRegisterOrConstantAtStart(instr->index()),
UseAtStart(instr->length())));
}
@ -1890,9 +1882,9 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
ASSERT(instr->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* obj = UseRegisterAtStart(instr->object());
LOperand* key = UseRegisterAtStart(instr->key());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
return AssignEnvironment(DefineSameAsFirst(result));
return AssignEnvironment(DefineAsRegister(result));
}

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

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

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

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

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

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

6
deps/v8/src/isolate.cc

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

194
deps/v8/src/liveobjectlist.cc

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

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.
void UpdatePointer(Object** p) {
Object* object = *p;
if (!Heap::InNewSpace(object)) return;
if (!HEAP->InNewSpace(object)) return;
HeapObject* heap_obj = HeapObject::cast(object);
ASSERT(Heap::InFromSpace(heap_obj));
ASSERT(HEAP->InFromSpace(heap_obj));
// We use the first word (where the map pointer usually is) of a heap
// object to record the forwarding pointer. A forwarding pointer can

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_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
strict_caller: ["Illegal access to a strict mode caller function."],
unprotected_let: ["Illegal let declaration in unprotected statement context."],
};
}
var message_type = %MessageGetType(message);

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

@ -123,8 +123,9 @@ class StackHandlerConstants : public AllStatic {
public:
static const int kNextOffset = 0 * kPointerSize;
static const int kStateOffset = 1 * kPointerSize;
static const int kFPOffset = 2 * kPointerSize;
static const int kPCOffset = 3 * kPointerSize;
static const int kContextOffset = 2 * kPointerSize;
static const int kFPOffset = 3 * kPointerSize;
static const int kPCOffset = 4 * 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));
__ LoadRoot(at, Heap::kFalseValueRootIndex);
Split(eq, v0, Operand(at), if_true, if_false, fall_through);
} else if (FLAG_harmony_typeof &&
check->Equals(isolate()->heap()->null_symbol())) {
__ LoadRoot(at, Heap::kNullValueRootIndex);
Split(eq, v0, Operand(at), if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at));
@ -4069,8 +4073,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
} else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(v0, if_false);
if (!FLAG_harmony_typeof) {
__ LoadRoot(at, Heap::kNullValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at));
}
// Check for JS objects => true.
__ GetObjectType(v0, v0, a1);
__ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));

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

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

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

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

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

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

2
deps/v8/src/mksnapshot.cc

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

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

@ -552,7 +552,8 @@ bool Object::IsContext() {
return (map == heap->function_context_map() ||
map == heap->catch_context_map() ||
map == heap->with_context_map() ||
map == heap->global_context_map());
map == heap->global_context_map() ||
map == heap->block_context_map());
}
return false;
}
@ -565,6 +566,13 @@ bool Object::IsGlobalContext() {
}
bool Object::IsSerializedScopeInfo() {
return Object::IsHeapObject() &&
HeapObject::cast(this)->map() ==
HeapObject::cast(this)->GetHeap()->serialized_scope_info_map();
}
bool Object::IsJSFunction() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE;
@ -1335,14 +1343,14 @@ int HeapNumber::get_sign() {
ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
HeapObject* JSObject::elements() {
FixedArrayBase* JSObject::elements() {
Object* array = READ_FIELD(this, kElementsOffset);
ASSERT(array->HasValidElements());
return reinterpret_cast<HeapObject*>(array);
return static_cast<FixedArrayBase*>(array);
}
void JSObject::set_elements(HeapObject* value, WriteBarrierMode mode) {
void JSObject::set_elements(FixedArrayBase* value, WriteBarrierMode mode) {
ASSERT(map()->has_fast_elements() ==
(value->map() == GetHeap()->fixed_array_map() ||
value->map() == GetHeap()->fixed_cow_array_map()));
@ -2114,12 +2122,6 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
SMI_ACCESSORS(ByteArray, length, kLengthOffset)
// TODO(1493): Investigate if it's possible to s/INT/SMI/ here (and
// subsequently unify H{Fixed,External}ArrayLength).
INT_ACCESSORS(ExternalArray, length, kLengthOffset)
SMI_ACCESSORS(String, length, kLengthOffset)

35
deps/v8/src/objects.cc

@ -2318,7 +2318,8 @@ MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
if (has_exception) return Failure::Exception();
Object* bool_result = result->ToBoolean();
if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
if (mode == STRICT_DELETION &&
bool_result == isolate->heap()->false_value()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
"handler_failed", HandleVector(args, ARRAY_SIZE(args)));
@ -3167,7 +3168,8 @@ MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
ASSERT(result->IsBoolean());
return *v8::Utils::OpenHandle(*result);
}
MaybeObject* raw_result = GetElementsAccessor()->Delete(*this_handle,
MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
*this_handle,
index,
NORMAL_DELETION);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
@ -4637,7 +4639,20 @@ MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
return array->GetElementsAccessor()->AddJSArrayKeysToFixedArray(array, this);
ElementsAccessor* accessor = array->GetElementsAccessor();
MaybeObject* maybe_result =
accessor->AddElementsToFixedArray(array->elements(), this);
FixedArray* result;
if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
#ifdef DEBUG
if (FLAG_enable_slow_asserts) {
for (int i = 0; i < result->length(); i++) {
Object* current = result->get(i);
ASSERT(current->IsNumber() || current->IsString());
}
}
#endif
return result;
}
@ -6961,12 +6976,16 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
if (0 == deopt_count) return;
PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc",
FLAG_print_code_verbose ? "commands" : "");
for (int i = 0; i < deopt_count; i++) {
PrintF(out, "%6d %6d %6d",
i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
if (!FLAG_print_code_verbose) continue;
if (!FLAG_print_code_verbose) {
PrintF(out, "\n");
continue;
}
// Print details of the frame translation.
int translation_index = TranslationIndex(i)->value();
TranslationIterator iterator(TranslationByteArray(), translation_index);
@ -8403,14 +8422,14 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
return isolate->Throw(*error);
}
}
Object* new_dictionary;
FixedArrayBase* new_dictionary;
MaybeObject* maybe = dictionary->AtNumberPut(index, value);
if (!maybe->ToObject(&new_dictionary)) return maybe;
if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
if (dictionary != NumberDictionary::cast(new_dictionary)) {
if (is_arguments) {
elements->set(1, new_dictionary);
} else {
set_elements(HeapObject::cast(new_dictionary));
set_elements(new_dictionary);
}
dictionary = NumberDictionary::cast(new_dictionary);
}

49
deps/v8/src/objects.h

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

266
deps/v8/src/parser.cc

@ -584,7 +584,8 @@ Parser::Parser(Handle<Script> script,
pre_data_(pre_data),
fni_(NULL),
stack_overflow_(false),
parenthesized_function_(false) {
parenthesized_function_(false),
harmony_block_scoping_(false) {
AstNode::ResetIds();
}
@ -809,6 +810,10 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
isolate()->Throw(*result, &location);
}
void Parser::SetHarmonyBlockScoping(bool block_scoping) {
scanner().SetHarmonyBlockScoping(block_scoping);
harmony_block_scoping_ = block_scoping;
}
// Base class containing common code for the different finder classes used by
// the parser.
@ -1089,6 +1094,25 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder {
};
Statement* Parser::ParseSourceElement(ZoneStringList* labels,
bool* ok) {
if (peek() == Token::FUNCTION) {
// FunctionDeclaration is only allowed in the context of SourceElements
// (Ecma 262 5th Edition, clause 14):
// SourceElement:
// Statement
// FunctionDeclaration
// Common language extension is to allow function declaration in place
// of any statement. This language extension is disabled in strict mode.
return ParseFunctionDeclaration(ok);
} else if (peek() == Token::LET) {
return ParseVariableStatement(kSourceElement, ok);
} else {
return ParseStatement(labels, ok);
}
}
void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
int end_token,
bool* ok) {
@ -1112,21 +1136,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
}
Scanner::Location token_loc = scanner().peek_location();
Statement* stat;
if (peek() == Token::FUNCTION) {
// FunctionDeclaration is only allowed in the context of SourceElements
// (Ecma 262 5th Edition, clause 14):
// SourceElement:
// Statement
// FunctionDeclaration
// Common language extension is to allow function declaration in place
// of any statement. This language extension is disabled in strict mode.
stat = ParseFunctionDeclaration(CHECK_OK);
} else {
stat = ParseStatement(NULL, CHECK_OK);
}
Statement* stat = ParseSourceElement(NULL, CHECK_OK);
if (stat == NULL || stat->IsEmpty()) {
directive_prologue = false; // End of directive prologue.
continue;
@ -1214,7 +1224,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
case Token::CONST: // fall through
case Token::VAR:
stmt = ParseVariableStatement(ok);
stmt = ParseVariableStatement(kStatement, ok);
break;
case Token::SEMICOLON:
@ -1309,9 +1319,9 @@ VariableProxy* Parser::Declare(Handle<String> name,
bool resolve,
bool* ok) {
Variable* var = NULL;
// If we are inside a function, a declaration of a variable
// is a truly local variable, and the scope of the variable
// is always the function scope.
// If we are inside a function, a declaration of a var/const variable is a
// truly local variable, and the scope of the variable is always the function
// scope.
// If a function scope exists, then we can statically declare this
// variable and also set its mode. In any case, a Declaration node
@ -1321,24 +1331,28 @@ VariableProxy* Parser::Declare(Handle<String> name,
// to the calling function context.
// Similarly, strict mode eval scope does not leak variable declarations to
// the caller's scope so we declare all locals, too.
Scope* declaration_scope = top_scope_->DeclarationScope();
Scope* declaration_scope = mode == Variable::LET ? top_scope_
: top_scope_->DeclarationScope();
if (declaration_scope->is_function_scope() ||
declaration_scope->is_strict_mode_eval_scope()) {
declaration_scope->is_strict_mode_eval_scope() ||
declaration_scope->is_block_scope()) {
// Declare the variable in the function scope.
var = declaration_scope->LocalLookup(name);
if (var == NULL) {
// Declare the name.
var = declaration_scope->DeclareLocal(name, mode);
} else {
// The name was declared before; check for conflicting
// re-declarations. If the previous declaration was a const or the
// current declaration is a const then we have a conflict. There is
// similar code in runtime.cc in the Declare functions.
if ((mode == Variable::CONST) || (var->mode() == Variable::CONST)) {
// We only have vars and consts in declarations.
// The name was declared before; check for conflicting re-declarations.
// We have a conflict if either of the declarations is not a var. There
// is similar code in runtime.cc in the Declare functions.
if ((mode != Variable::VAR) || (var->mode() != Variable::VAR)) {
// We only have vars, consts and lets in declarations.
ASSERT(var->mode() == Variable::VAR ||
var->mode() == Variable::CONST);
const char* type = (var->mode() == Variable::VAR) ? "var" : "const";
var->mode() == Variable::CONST ||
var->mode() == Variable::LET);
const char* type = (var->mode() == Variable::VAR) ? "var" :
(var->mode() == Variable::CONST) ? "const" : "let";
Handle<String> type_string =
isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
Expression* expression =
@ -1481,12 +1495,15 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) {
// Even if we're not at the top-level of the global or a function
// scope, we treat is as such and introduce the function with it's
// initial value upon entering the corresponding scope.
Declare(name, Variable::VAR, fun, true, CHECK_OK);
Variable::Mode mode = harmony_block_scoping_ ? Variable::LET : Variable::VAR;
Declare(name, mode, fun, true, CHECK_OK);
return EmptyStatement();
}
Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
if (harmony_block_scoping_) return ParseScopedBlock(labels, ok);
// Block ::
// '{' Statement* '}'
@ -1510,12 +1527,65 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
}
Block* Parser::ParseVariableStatement(bool* ok) {
Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
// Construct block expecting 16 statements.
Block* body = new(zone()) Block(isolate(), labels, 16, false);
Scope* saved_scope = top_scope_;
Scope* block_scope = NewScope(top_scope_,
Scope::BLOCK_SCOPE,
inside_with());
body->set_block_scope(block_scope);
block_scope->DeclareLocal(isolate()->factory()->block_scope_symbol(),
Variable::VAR);
if (top_scope_->is_strict_mode()) {
block_scope->EnableStrictMode();
}
top_scope_ = block_scope;
// Parse the statements and collect escaping labels.
TargetCollector collector;
Target target(&this->target_stack_, &collector);
Expect(Token::LBRACE, CHECK_OK);
{
Target target_body(&this->target_stack_, body);
InitializationBlockFinder block_finder(top_scope_, target_stack_);
while (peek() != Token::RBRACE) {
Statement* stat = ParseSourceElement(NULL, CHECK_OK);
if (stat && !stat->IsEmpty()) {
body->AddStatement(stat);
block_finder.Update(stat);
}
}
}
Expect(Token::RBRACE, CHECK_OK);
// Create exit block.
Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
exit->AddStatement(new(zone()) ExitContextStatement());
// Create a try-finally statement.
TryFinallyStatement* try_finally =
new(zone()) TryFinallyStatement(body, exit);
try_finally->set_escaping_targets(collector.targets());
top_scope_ = saved_scope;
// Create a result block.
Block* result = new(zone()) Block(isolate(), NULL, 1, false);
result->AddStatement(try_finally);
return result;
}
Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
bool* ok) {
// VariableStatement ::
// VariableDeclarations ';'
Handle<String> ignore;
Block* result = ParseVariableDeclarations(true, &ignore, CHECK_OK);
Block* result = ParseVariableDeclarations(var_context,
&ignore,
CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
@ -1532,7 +1602,7 @@ bool Parser::IsEvalOrArguments(Handle<String> string) {
// *var is untouched; in particular, it is the caller's responsibility
// to initialize it properly. This mechanism is used for the parsing
// of 'for-in' loops.
Block* Parser::ParseVariableDeclarations(bool accept_IN,
Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
Handle<String>* out,
bool* ok) {
// VariableDeclarations ::
@ -1540,25 +1610,36 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
Variable::Mode mode = Variable::VAR;
bool is_const = false;
Scope* declaration_scope = top_scope_->DeclarationScope();
if (peek() == Token::VAR) {
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
Consume(Token::CONST);
if (declaration_scope->is_strict_mode()) {
if (top_scope_->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false;
return NULL;
}
mode = Variable::CONST;
is_const = true;
} else if (peek() == Token::LET) {
Consume(Token::LET);
if (var_context != kSourceElement &&
var_context != kForStatement) {
ASSERT(var_context == kStatement);
ReportMessage("unprotected_let", Vector<const char*>::empty());
*ok = false;
return NULL;
}
mode = Variable::LET;
} else {
UNREACHABLE(); // by current callers
}
// The scope of a variable/const declared anywhere inside a function
Scope* declaration_scope = mode == Variable::LET
? top_scope_ : top_scope_->DeclarationScope();
// The scope of a var/const declared variable anywhere inside a function
// is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
// transform a source-level variable/const declaration into a (Function)
// transform a source-level var/const declaration into a (Function)
// Scope declaration, and rewrite the source-level initialization into an
// assignment statement. We use a block to collect multiple assignments.
//
@ -1642,7 +1723,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
if (peek() == Token::ASSIGN) {
Expect(Token::ASSIGN, CHECK_OK);
position = scanner().location().beg_pos;
value = ParseAssignmentExpression(accept_IN, CHECK_OK);
value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
// Don't infer if it is "a = function(){...}();"-like expression.
if (fni_ != NULL &&
value->AsCall() == NULL &&
@ -1956,41 +2037,6 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
}
Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
// Parse the statement and collect escaping labels.
TargetCollector collector;
Statement* stat;
{ Target target(&this->target_stack_, &collector);
with_nesting_level_++;
top_scope_->DeclarationScope()->RecordWithStatement();
stat = ParseStatement(labels, CHECK_OK);
with_nesting_level_--;
}
// Create resulting block with two statements.
// 1: Evaluate the with expression.
// 2: The try-finally block evaluating the body.
Block* result = new(zone()) Block(isolate(), NULL, 2, false);
if (result != NULL) {
result->AddStatement(new(zone()) EnterWithContextStatement(obj));
// Create body block.
Block* body = new(zone()) Block(isolate(), NULL, 1, false);
body->AddStatement(stat);
// Create exit block.
Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
exit->AddStatement(new(zone()) ExitContextStatement());
// Return a try-finally statement.
TryFinallyStatement* wrapper = new(zone()) TryFinallyStatement(body, exit);
wrapper->set_escaping_targets(collector.targets());
result->AddStatement(wrapper);
}
return result;
}
Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
// WithStatement ::
// 'with' '(' Expression ')' Statement
@ -2007,7 +2053,11 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
return WithHelper(expr, labels, CHECK_OK);
++with_nesting_level_;
top_scope_->DeclarationScope()->RecordWithStatement();
Statement* stmt = ParseStatement(labels, CHECK_OK);
--with_nesting_level_;
return new(zone()) WithStatement(expr, stmt);
}
@ -2142,39 +2192,22 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::RPAREN, CHECK_OK);
if (peek() == Token::LBRACE) {
// Rewrite the catch body B to a single statement block
// { try B finally { PopContext }}.
Block* inner_body;
// We need to collect escapes from the body for both the inner
// try/finally used to pop the catch context and any possible outer
// try/finally.
TargetCollector inner_collector;
{ Target target(&this->target_stack_, &catch_collector);
{ Target target(&this->target_stack_, &inner_collector);
// Rewrite the catch body { B } to a block:
// { { B } ExitContext; }.
Target target(&this->target_stack_, &catch_collector);
catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
if (top_scope_->is_strict_mode()) {
catch_scope->EnableStrictMode();
}
catch_variable = catch_scope->DeclareLocal(name, Variable::VAR);
catch_block = new(zone()) Block(isolate(), NULL, 2, false);
Scope* saved_scope = top_scope_;
top_scope_ = catch_scope;
inner_body = ParseBlock(NULL, CHECK_OK);
Block* catch_body = ParseBlock(NULL, CHECK_OK);
top_scope_ = saved_scope;
}
}
// Create exit block.
Block* inner_finally = new(zone()) Block(isolate(), NULL, 1, false);
inner_finally->AddStatement(new(zone()) ExitContextStatement());
// Create a try/finally statement.
TryFinallyStatement* inner_try_finally =
new(zone()) TryFinallyStatement(inner_body, inner_finally);
inner_try_finally->set_escaping_targets(inner_collector.targets());
catch_block = new(zone()) Block(isolate(), NULL, 1, false);
catch_block->AddStatement(inner_try_finally);
catch_block->AddStatement(catch_body);
catch_block->AddStatement(new(zone()) ExitContextStatement());
} else {
Expect(Token::LBRACE, CHECK_OK);
}
@ -2290,7 +2323,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
if (peek() == Token::VAR || peek() == Token::CONST) {
Handle<String> name;
Block* variable_statement =
ParseVariableDeclarations(false, &name, CHECK_OK);
ParseVariableDeclarations(kForStatement, &name, CHECK_OK);
if (peek() == Token::IN && !name.is_null()) {
VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
@ -3649,8 +3682,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
}
int num_parameters = 0;
// Function declarations are hoisted.
Scope* scope = (type == FunctionLiteral::DECLARATION)
// Function declarations are function scoped in normal mode, so they are
// hoisted. In harmony block scoping mode they are block scoped, so they
// are not hoisted.
Scope* scope = (type == FunctionLiteral::DECLARATION &&
!harmony_block_scoping_)
? NewScope(top_scope_->DeclarationScope(), Scope::FUNCTION_SCOPE, false)
: NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8);
@ -3952,7 +3988,7 @@ Literal* Parser::GetLiteralNumber(double value) {
}
// Parses and identifier that is valid for the current scope, in particular it
// Parses an identifier that is valid for the current scope, in particular it
// fails on strict mode future reserved keywords in a strict scope.
Handle<String> Parser::ParseIdentifier(bool* ok) {
if (top_scope_->is_strict_mode()) {
@ -5033,9 +5069,11 @@ int ScriptDataImpl::ReadNumber(byte** source) {
// Create a Scanner for the preparser to use as input, and preparse the source.
static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
bool allow_lazy,
ParserRecorder* recorder) {
ParserRecorder* recorder,
bool harmony_block_scoping) {
Isolate* isolate = Isolate::Current();
JavaScriptScanner scanner(isolate->unicode_cache());
scanner.SetHarmonyBlockScoping(harmony_block_scoping);
scanner.Initialize(source);
intptr_t stack_limit = isolate->stack_guard()->real_climit();
if (!preparser::PreParser::PreParseProgram(&scanner,
@ -5056,7 +5094,8 @@ static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
// Preparse, but only collect data that is immediately useful,
// even if the preparser data is only used once.
ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
v8::Extension* extension) {
v8::Extension* extension,
bool harmony_block_scoping) {
bool allow_lazy = FLAG_lazy && (extension == NULL);
if (!allow_lazy) {
// Partial preparsing is only about lazily compiled functions.
@ -5064,16 +5103,17 @@ ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
return NULL;
}
PartialParserRecorder recorder;
return DoPreParse(source, allow_lazy, &recorder);
return DoPreParse(source, allow_lazy, &recorder, harmony_block_scoping);
}
ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
v8::Extension* extension) {
v8::Extension* extension,
bool harmony_block_scoping) {
Handle<Script> no_script;
bool allow_lazy = FLAG_lazy && (extension == NULL);
CompleteParserRecorder recorder;
return DoPreParse(source, allow_lazy, &recorder);
return DoPreParse(source, allow_lazy, &recorder, harmony_block_scoping);
}
@ -5103,15 +5143,22 @@ bool ParserApi::Parse(CompilationInfo* info) {
ASSERT(info->function() == NULL);
FunctionLiteral* result = NULL;
Handle<Script> script = info->script();
bool harmony_block_scoping = !info->is_native() &&
FLAG_harmony_block_scoping;
if (info->is_lazy()) {
Parser parser(script, true, NULL, NULL);
parser.SetHarmonyBlockScoping(harmony_block_scoping);
result = parser.ParseLazy(info);
} else {
// Whether we allow %identifier(..) syntax.
bool allow_natives_syntax =
info->allows_natives_syntax() || FLAG_allow_natives_syntax;
ScriptDataImpl* pre_data = info->pre_parse_data();
Parser parser(script, allow_natives_syntax, info->extension(), pre_data);
Parser parser(script,
allow_natives_syntax,
info->extension(),
pre_data);
parser.SetHarmonyBlockScoping(harmony_block_scoping);
if (pre_data != NULL && pre_data->has_error()) {
Scanner::Location loc = pre_data->MessageLocation();
const char* message = pre_data->BuildMessage();
@ -5130,7 +5177,6 @@ bool ParserApi::Parse(CompilationInfo* info) {
info->StrictMode());
}
}
info->SetFunction(result);
return (result != NULL);
}

22
deps/v8/src/parser.h

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

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

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

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

52
deps/v8/src/preparser.cc

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

18
deps/v8/src/preparser.h

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

19
deps/v8/src/prettyprinter.cc

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

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

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

@ -94,12 +94,6 @@ class RuntimeProfiler {
private:
static const int kSamplerWindowSize = 16;
static const int kStateWindowSize = 128;
enum SamplerState {
IN_NON_JS_STATE = 0,
IN_JS_STATE = 1
};
static void HandleWakeUp(Isolate* isolate);

83
deps/v8/src/runtime.cc

@ -4853,7 +4853,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
return isolate->heap()->boolean_symbol();
}
if (heap_obj->IsNull()) {
return isolate->heap()->object_symbol();
return FLAG_harmony_typeof
? isolate->heap()->null_symbol()
: isolate->heap()->object_symbol();
}
ASSERT(heap_obj->IsUndefined());
return isolate->heap()->undefined_symbol();
@ -8314,6 +8316,30 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
JSFunction* function;
if (args[1]->IsSmi()) {
// A smi sentinel indicates a context nested inside global code rather
// than some function. There is a canonical empty function that can be
// gotten from the global context.
function = isolate->context()->global_context()->closure();
} else {
function = JSFunction::cast(args[1]);
}
Context* context;
MaybeObject* maybe_context =
isolate->heap()->AllocateBlockContext(function,
isolate->context(),
scope_info);
if (!maybe_context->To(&context)) return maybe_context;
isolate->set_context(context);
return context;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
@ -9654,7 +9680,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSArray, from, args[0]);
CONVERT_CHECKED(JSArray, to, args[1]);
HeapObject* new_elements = from->elements();
FixedArrayBase* new_elements = from->elements();
MaybeObject* maybe_new_map;
if (new_elements->map() == isolate->heap()->fixed_array_map() ||
new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
@ -10639,6 +10665,34 @@ static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
}
// Create a plain JSObject which materializes the block scope for the specified
// block context.
static Handle<JSObject> MaterializeBlockScope(
Isolate* isolate,
Handle<Context> context) {
ASSERT(context->IsBlockContext());
Handle<SerializedScopeInfo> serialized_scope_info(
SerializedScopeInfo::cast(context->extension()));
ScopeInfo<> scope_info(*serialized_scope_info);
// Allocate and initialize a JSObject with all the arguments, stack locals
// heap locals and extension properties of the debugged function.
Handle<JSObject> block_scope =
isolate->factory()->NewJSObject(isolate->object_function());
// Fill all context locals.
if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
if (!CopyContextLocalsToScopeObject(isolate,
serialized_scope_info, scope_info,
context, block_scope)) {
return Handle<JSObject>();
}
}
return block_scope;
}
// Iterate over the actual scopes visible from a stack frame. All scopes are
// backed by an actual context except the local scope, which is inserted
// "artifically" in the context chain.
@ -10649,7 +10703,8 @@ class ScopeIterator {
ScopeTypeLocal,
ScopeTypeWith,
ScopeTypeClosure,
ScopeTypeCatch
ScopeTypeCatch,
ScopeTypeBlock
};
ScopeIterator(Isolate* isolate,
@ -10675,8 +10730,10 @@ class ScopeIterator {
} else if (context_->IsFunctionContext()) {
at_local_ = true;
} else if (context_->closure() != *function_) {
// The context_ is a with or catch block from the outer function.
ASSERT(context_->IsWithContext() || context_->IsCatchContext());
// The context_ is a block or with or catch block from the outer function.
ASSERT(context_->IsWithContext() ||
context_->IsCatchContext() ||
context_->IsBlockContext());
at_local_ = true;
}
}
@ -10731,6 +10788,9 @@ class ScopeIterator {
if (context_->IsCatchContext()) {
return ScopeTypeCatch;
}
if (context_->IsBlockContext()) {
return ScopeTypeBlock;
}
ASSERT(context_->IsWithContext());
return ScopeTypeWith;
}
@ -10751,6 +10811,8 @@ class ScopeIterator {
case ScopeIterator::ScopeTypeClosure:
// Materialize the content of the closure scope into a JSObject.
return MaterializeClosure(isolate_, CurrentContext());
case ScopeIterator::ScopeTypeBlock:
return MaterializeBlockScope(isolate_, CurrentContext());
}
UNREACHABLE();
return Handle<JSObject>();
@ -11307,7 +11369,18 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate,
new_previous,
name,
thrown_object);
} else if (current->IsBlockContext()) {
Handle<SerializedScopeInfo> scope_info(
SerializedScopeInfo::cast(current->extension()));
new_current =
isolate->factory()->NewBlockContext(function, new_previous, scope_info);
// Copy context slots.
int num_context_slots = scope_info->NumberOfContextSlots();
for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
new_current->set(i, current->get(i));
}
} else {
ASSERT(current->IsWithContext());
Handle<JSObject> extension(JSObject::cast(current->extension()));
new_current =
isolate->factory()->NewWithContext(function, new_previous, extension);

1
deps/v8/src/runtime.h

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

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

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

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

@ -507,6 +507,14 @@ class JavaScriptScanner : public Scanner {
// tokens, which is what it is used for.
void SeekForward(int pos);
bool HarmonyBlockScoping() const {
return harmony_block_scoping_;
}
void SetHarmonyBlockScoping(bool block_scoping) {
harmony_block_scoping_ = block_scoping;
}
protected:
bool SkipWhiteSpace();
Token::Value SkipSingleLineComment();
@ -540,6 +548,9 @@ class JavaScriptScanner : public Scanner {
// Whether there is a multi-line comment that contains a
// line-terminator after the current token, and before the next.
bool has_multiline_comment_before_next_;
// Whether we scan 'let' as a keyword for harmony block scoped
// let bindings.
bool harmony_block_scoping_;
};
} } // namespace v8::internal

2
deps/v8/src/scopeinfo.cc

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

2
deps/v8/src/scopeinfo.h

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

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

12
deps/v8/src/scopes.h

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

44
deps/v8/src/serialize.cc

@ -62,12 +62,7 @@ static int* GetInternalPointer(StatsCounter* counter) {
}
// ExternalReferenceTable is a helper class that defines the relationship
// between external references and their encodings. It is used to build
// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
class ExternalReferenceTable {
public:
static ExternalReferenceTable* instance(Isolate* isolate) {
ExternalReferenceTable* ExternalReferenceTable::instance(Isolate* isolate) {
ExternalReferenceTable* external_reference_table =
isolate->external_reference_table();
if (external_reference_table == NULL) {
@ -77,43 +72,6 @@ class ExternalReferenceTable {
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,
uint16_t id,

47
deps/v8/src/serialize.h

@ -60,6 +60,52 @@ const int kDebugRegisterBits = 4;
const int kDebugIdShift = kDebugRegisterBits;
// ExternalReferenceTable is a helper class that defines the relationship
// between external references and their encodings. It is used to build
// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
class ExternalReferenceTable {
public:
static ExternalReferenceTable* instance(Isolate* isolate);
~ExternalReferenceTable() { }
int size() const { return refs_.length(); }
Address address(int i) { return refs_[i].address; }
uint32_t code(int i) { return refs_[i].code; }
const char* name(int i) { return refs_[i].name; }
int max_id(int code) { return max_id_[code]; }
private:
explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) {
PopulateTable(isolate);
}
struct ExternalReferenceEntry {
Address address;
uint32_t code;
const char* name;
};
void PopulateTable(Isolate* isolate);
// For a few types of references, we can get their address from their id.
void AddFromId(TypeCode type,
uint16_t id,
const char* name,
Isolate* isolate);
// For other types of references, the caller will figure out the address.
void Add(Address address, TypeCode type, uint16_t id, const char* name);
List<ExternalReferenceEntry> refs_;
int max_id_[kTypeCodeCount];
};
class ExternalReferenceEncoder {
public:
ExternalReferenceEncoder();
@ -544,6 +590,7 @@ class PartialSerializer : public Serializer {
ASSERT(!o->IsScript());
return o->IsString() || o->IsSharedFunctionInfo() ||
o->IsHeapNumber() || o->IsCode() ||
o->IsSerializedScopeInfo() ||
o->map() == HEAP->fixed_cow_array_map();
}

1
deps/v8/src/token.h

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

3
deps/v8/src/variables.cc

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

13
deps/v8/src/variables.h

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

4
deps/v8/src/version.cc

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

11
deps/v8/src/weakmap.js

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

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

@ -242,14 +242,14 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
}
// undefined -> false
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value
CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false.
CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true
@ -269,7 +269,7 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
if (types_.NeedsMap()) {
__ movq(map, FieldOperand(argument, HeapObject::kMapOffset));
// Everything with a map could be undetectable, so check this now.
if (types_.CanBeUndetectable()) {
__ testb(FieldOperand(map, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
// Undetectable -> false.
@ -279,19 +279,19 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ ret(1 * kPointerSize);
__ bind(&not_undetectable);
}
}
if (types_.Contains(SPEC_OBJECT)) {
// spec object -> true.
Label not_js_object;
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(below, &not_js_object, Label::kNear);
// argument contains the correct return value already.
if (!tos_.is(argument)) {
__ Set(tos_, 1);
}
__ ret(1 * kPointerSize);
__ bind(&not_js_object);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// We've seen a spec object for the first time -> patch.
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(above_equal, &patch, Label::kNear);
}
if (types_.Contains(STRING)) {
@ -302,10 +302,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ movq(tos_, FieldOperand(argument, String::kLengthOffset));
__ ret(1 * kPointerSize); // the string length is OK as the return value
__ bind(&not_string);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// We've seen a string for the first time -> patch
__ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
__ j(below, &patch, Label::kNear);
}
if (types_.Contains(HEAP_NUMBER)) {
@ -316,50 +312,42 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ xorps(xmm0, xmm0);
__ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset));
__ j(zero, &false_result, Label::kNear);
// argument contains the correct return value already.
if (!tos_.is(argument)) {
__ Set(tos_, 1);
}
__ ret(1 * kPointerSize);
__ bind(&false_result);
__ Set(tos_, 0);
__ ret(1 * kPointerSize);
__ bind(&not_heap_number);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// We've seen a heap number for the first time -> patch
__ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
__ j(equal, &patch, Label::kNear);
}
if (types_.Contains(INTERNAL_OBJECT)) {
// internal objects -> true
__ Set(tos_, 1);
__ ret(1 * kPointerSize);
}
if (!types_.IsAll()) {
__ bind(&patch);
GenerateTypeTransition(masm);
}
}
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
bool result,
Label* patch) {
bool result) {
const Register argument = rax;
if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_.
Label different_value;
__ CompareRoot(argument, value);
__ j(not_equal, &different_value, Label::kNear);
__ Set(tos_, result ? 1 : 0);
if (!result) {
// If we have to return zero, there is no way around clearing tos_.
__ Set(tos_, 0);
} else if (!tos_.is(argument)) {
// If we have to return non-zero, we can re-use the argument if it is the
// same register as the result, because we never see Smi-zero here.
__ Set(tos_, 1);
}
__ ret(1 * kPointerSize);
__ bind(&different_value);
} else if (types_.Contains(INTERNAL_OBJECT)) {
// If we see an unexpected oddball and handle internal objects, we must
// patch because the code for internal objects doesn't handle it explictly.
__ CompareRoot(argument, value);
__ j(equal, patch);
}
}

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

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

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

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

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

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

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

@ -1036,11 +1036,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
: instr->SecondSuccessor();
return new LGoto(successor->block_id());
}
LInstruction* branch = new LBranch(UseRegister(v));
// When we handle all cases, we never deopt, so we don't need to assign the
// environment then.
bool all_cases_handled = instr->expected_input_types().IsAll();
return all_cases_handled ? branch : AssignEnvironment(branch);
return AssignEnvironment(new LBranch(UseRegister(v)));
}
@ -1502,16 +1498,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array));
}
LInstruction* LChunkBuilder::DoExternalArrayLength(
HExternalArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LExternalArrayLength(array));
return DefineAsRegister(new LFixedArrayBaseLength(array));
}
@ -1529,7 +1519,8 @@ LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
return AssignEnvironment(new LBoundsCheck(
UseRegisterOrConstantAtStart(instr->index()),
Use(instr->length())));
}
@ -1829,9 +1820,9 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
ASSERT(instr->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* obj = UseRegisterAtStart(instr->object());
LOperand* key = UseRegisterAtStart(instr->key());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
return AssignEnvironment(DefineSameAsFirst(result));
return AssignEnvironment(DefineAsRegister(result));
}

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

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

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

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

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

Loading…
Cancel
Save