Browse Source

Upgrade V8 to 2.5.8

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
73318fa09d
  1. 9
      deps/v8/ChangeLog
  2. 3
      deps/v8/LICENSE
  3. 29
      deps/v8/include/v8-profiler.h
  4. 12
      deps/v8/samples/shell.cc
  5. 8
      deps/v8/src/SConscript
  6. 18
      deps/v8/src/api.cc
  7. 3
      deps/v8/src/apiutils.h
  8. 5
      deps/v8/src/arm/code-stubs-arm.cc
  9. 25
      deps/v8/src/arm/codegen-arm.cc
  10. 4
      deps/v8/src/arm/codegen-arm.h
  11. 20
      deps/v8/src/arm/full-codegen-arm.cc
  12. 229
      deps/v8/src/arm/stub-cache-arm.cc
  13. 4
      deps/v8/src/array.js
  14. 7
      deps/v8/src/ast.h
  15. 21
      deps/v8/src/builtins.cc
  16. 10
      deps/v8/src/conversions.cc
  17. 5
      deps/v8/src/conversions.h
  18. 92
      deps/v8/src/dtoa-config.c
  19. 6
      deps/v8/src/full-codegen.cc
  20. 2
      deps/v8/src/full-codegen.h
  21. 66
      deps/v8/src/handles.cc
  22. 16
      deps/v8/src/heap-profiler.cc
  23. 3
      deps/v8/src/ia32/code-stubs-ia32.cc
  24. 200
      deps/v8/src/ia32/codegen-ia32.cc
  25. 4
      deps/v8/src/ia32/codegen-ia32.h
  26. 196
      deps/v8/src/ia32/full-codegen-ia32.cc
  27. 51
      deps/v8/src/ia32/macro-assembler-ia32.cc
  28. 17
      deps/v8/src/ia32/macro-assembler-ia32.h
  29. 11
      deps/v8/src/ia32/stub-cache-ia32.cc
  30. 69
      deps/v8/src/parser.cc
  31. 16
      deps/v8/src/parser.h
  32. 4
      deps/v8/src/preparser.h
  33. 1098
      deps/v8/src/prescanner.h
  34. 43
      deps/v8/src/profile-generator-inl.h
  35. 742
      deps/v8/src/profile-generator.cc
  36. 181
      deps/v8/src/profile-generator.h
  37. 15
      deps/v8/src/runtime.cc
  38. 5
      deps/v8/src/runtime.h
  39. 734
      deps/v8/src/scanner-base.cc
  40. 363
      deps/v8/src/scanner-base.h
  41. 860
      deps/v8/src/scanner.cc
  42. 299
      deps/v8/src/scanner.h
  43. 7
      deps/v8/src/stub-cache.cc
  44. 15
      deps/v8/src/third_party/dtoa/COPYING
  45. 3331
      deps/v8/src/third_party/dtoa/dtoa.c
  46. 2
      deps/v8/src/utils.h
  47. 2
      deps/v8/src/version.cc
  48. 3
      deps/v8/src/x64/code-stubs-x64.cc
  49. 21
      deps/v8/src/x64/codegen-x64.cc
  50. 4
      deps/v8/src/x64/codegen-x64.h
  51. 15
      deps/v8/src/x64/full-codegen-x64.cc
  52. 2
      deps/v8/src/x64/stub-cache-x64.cc
  53. 8
      deps/v8/test/cctest/test-api.cc
  54. 13
      deps/v8/test/cctest/test-conversions.cc
  55. 63
      deps/v8/test/cctest/test-debug.cc
  56. 186
      deps/v8/test/cctest/test-heap-profiler.cc
  57. 8
      deps/v8/test/cctest/test-parsing.cc
  58. 38
      deps/v8/test/mjsunit/compiler/literals.js
  59. 7
      deps/v8/tools/gyp/v8.gyp
  60. 3
      deps/v8/tools/visual_studio/README.txt
  61. 92
      deps/v8/tools/visual_studio/v8_base.vcproj
  62. 92
      deps/v8/tools/visual_studio/v8_base_arm.vcproj
  63. 92
      deps/v8/tools/visual_studio/v8_base_x64.vcproj

9
deps/v8/ChangeLog

@ -1,3 +1,12 @@
2010-11-23: Version 2.5.8
Removed dependency on Gay's dtoa.
Improved heap profiler precision and speed.
Reduced overhead of callback invocations on ARM.
2010-11-18: Version 2.5.7
Fixed obscure evaluation order bug (issue 931).

3
deps/v8/LICENSE

@ -12,9 +12,6 @@ are:
based on layout tests from webkit.org which are copyrighted by
Apple Computer, Inc. and released under a 3-clause BSD license.
- Dtoa, located under third_party/dtoa. This code is copyrighted by
David M. Gay and released under an MIT license.
- Strongtalk assembler, the basis of the files assembler-arm-inl.h,
assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h,
assembler-ia32.cc, assembler-ia32.h, assembler.cc and assembler.h.

29
deps/v8/include/v8-profiler.h

@ -197,8 +197,13 @@ class V8EXPORT HeapGraphEdge {
kContextVariable = 0, // A variable from a function context.
kElement = 1, // An element of an array.
kProperty = 2, // A named object property.
kInternal = 3 // A link that can't be accessed from JS,
// thus, its name isn't a real property name.
kInternal = 3, // A link that can't be accessed from JS,
// thus, its name isn't a real property name
// (e.g. parts of a ConsString).
kHidden = 4, // A link that is needed for proper sizes
// calculation, but may be hidden from user.
kShortcut = 5 // A link that must not be followed during
// sizes calculation.
};
/** Returns edge type (see HeapGraphEdge::Type). */
@ -240,7 +245,8 @@ class V8EXPORT HeapGraphPath {
class V8EXPORT HeapGraphNode {
public:
enum Type {
kInternal = 0, // Internal node, a virtual one, for housekeeping.
kInternal = 0, // For compatibility, will be removed.
kHidden = 0, // Hidden node, may be filtered when shown to user.
kArray = 1, // An array of elements.
kString = 2, // A string.
kObject = 3, // A JS object (except for arrays and strings).
@ -276,16 +282,19 @@ class V8EXPORT HeapGraphNode {
/** Returns node's own size, in bytes. */
int GetSelfSize() const;
/** Returns node's network (self + reachable nodes) size, in bytes. */
int GetReachableSize() const;
/**
* Returns node's retained size, in bytes. That is, self + sizes of
* the objects that are reachable only from this object. In other
* words, the size of memory that will be reclaimed having this node
* collected.
*
* Exact retained size calculation has O(N) (number of nodes)
* computational complexity, while approximate has O(1). It is
* assumed that initially heap profiling tools provide approximate
* sizes for all nodes, and then exact sizes are calculated for the
* most 'interesting' nodes.
*/
int GetRetainedSize() const;
int GetRetainedSize(bool exact) const;
/** Returns child nodes count of the node. */
int GetChildrenCount() const;
@ -304,6 +313,12 @@ class V8EXPORT HeapGraphNode {
/** Returns a retaining path by index. */
const HeapGraphPath* GetRetainingPath(int index) const;
/**
* Returns a dominator node. This is the node that participates in every
* path from the snapshot root to the current node.
*/
const HeapGraphNode* GetDominatorNode() const;
};

12
deps/v8/samples/shell.cc

@ -37,6 +37,7 @@ bool ExecuteString(v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
bool print_result,
bool report_exceptions);
v8::Handle<v8::Value> PrintToInteger(const v8::Arguments& args);
v8::Handle<v8::Value> Print(const v8::Arguments& args);
v8::Handle<v8::Value> Read(const v8::Arguments& args);
v8::Handle<v8::Value> Load(const v8::Arguments& args);
@ -53,6 +54,7 @@ int RunMain(int argc, char* argv[]) {
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
// Bind the global 'print' function to the C++ Print callback.
global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
global->Set(v8::String::New("print2int"), v8::FunctionTemplate::New(PrintToInteger));
// Bind the global 'read' function to the C++ Read callback.
global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
// Bind the global 'load' function to the C++ Load callback.
@ -138,6 +140,16 @@ v8::Handle<v8::Value> Print(const v8::Arguments& args) {
}
v8::Handle<v8::Value> PrintToInteger(const v8::Arguments& args) {
v8::HandleScope handle_scope;
v8::String::Utf8Value str(args[0]);
const char* cstr = ToCString(str);
printf("%s -> %d\n", cstr, args[0]->ToInt32()->Value());
fflush(stdout);
return v8::Undefined();
}
// The callback that is invoked by v8 whenever the JavaScript 'read'
// function is called. This function loads the content of the file named in
// the argument into a JavaScript string.

8
deps/v8/src/SConscript

@ -298,14 +298,8 @@ def ConfigureObjectFiles():
libraries_src, libraries_empty_src = env.JS2C(['libraries.cc', 'libraries-empty.cc'], library_files, TYPE='CORE')
libraries_obj = context.ConfigureObject(env, libraries_src, CPPPATH=['.'])
# Build dtoa.
dtoa_env = env.Copy()
dtoa_env.Replace(**context.flags['dtoa'])
dtoa_files = ['dtoa-config.c']
dtoa_obj = context.ConfigureObject(dtoa_env, dtoa_files)
source_objs = context.ConfigureObject(env, source_files)
non_snapshot_files = [dtoa_obj, source_objs]
non_snapshot_files = [source_objs]
# Create snapshot if necessary. For cross compilation you should either
# do without snapshots and take the performance hit or you should build a

18
deps/v8/src/api.cc

@ -4669,9 +4669,11 @@ Handle<Value> HeapGraphEdge::GetName() const {
case i::HeapGraphEdge::kContextVariable:
case i::HeapGraphEdge::kInternal:
case i::HeapGraphEdge::kProperty:
case i::HeapGraphEdge::kShortcut:
return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
edge->name())));
case i::HeapGraphEdge::kElement:
case i::HeapGraphEdge::kHidden:
return Handle<Number>(ToApi<Number>(i::Factory::NewNumberFromInt(
edge->index())));
default: UNREACHABLE();
@ -4761,15 +4763,9 @@ int HeapGraphNode::GetSelfSize() const {
}
int HeapGraphNode::GetReachableSize() const {
IsDeadCheck("v8::HeapSnapshot::GetReachableSize");
return ToInternal(this)->ReachableSize();
}
int HeapGraphNode::GetRetainedSize() const {
int HeapGraphNode::GetRetainedSize(bool exact) const {
IsDeadCheck("v8::HeapSnapshot::GetRetainedSize");
return ToInternal(this)->RetainedSize();
return ToInternal(this)->RetainedSize(exact);
}
@ -4812,6 +4808,12 @@ const HeapGraphPath* HeapGraphNode::GetRetainingPath(int index) const {
}
const HeapGraphNode* HeapGraphNode::GetDominatorNode() const {
IsDeadCheck("v8::HeapSnapshot::GetDominatorNode");
return reinterpret_cast<const HeapGraphNode*>(ToInternal(this)->dominator());
}
const HeapGraphNode* HeapSnapshotsDiff::GetAdditionsRoot() const {
IsDeadCheck("v8::HeapSnapshotsDiff::GetAdditionsRoot");
i::HeapSnapshotsDiff* diff =

3
deps/v8/src/apiutils.h

@ -58,6 +58,9 @@ class ImplementationUtilities {
static v8::Arguments NewArguments(internal::Object** implicit_args,
internal::Object** argv, int argc,
bool is_construct_call) {
ASSERT(implicit_args[v8::Arguments::kCalleeIndex]->IsJSFunction());
ASSERT(implicit_args[v8::Arguments::kHolderIndex]->IsHeapObject());
return v8::Arguments(implicit_args, argv, argc, is_construct_call);
}

5
deps/v8/src/arm/code-stubs-arm.cc

@ -100,8 +100,9 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
// Create a new closure through the slower runtime call.
__ bind(&gc);
__ Push(cp, r3);
__ TailCallRuntime(Runtime::kNewClosure, 2, 1);
__ LoadRoot(r4, Heap::kFalseValueRootIndex);
__ Push(cp, r3, r4);
__ TailCallRuntime(Runtime::kNewClosure, 3, 1);
}

25
deps/v8/src/arm/codegen-arm.cc

@ -3103,10 +3103,13 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
void CodeGenerator::InstantiateFunction(
Handle<SharedFunctionInfo> function_info) {
Handle<SharedFunctionInfo> function_info,
bool pretenure) {
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
if (scope()->is_function_scope() && function_info->num_literals() == 0) {
if (scope()->is_function_scope() &&
function_info->num_literals() == 0 &&
!pretenure) {
FastNewClosureStub stub;
frame_->EmitPush(Operand(function_info));
frame_->SpillAll();
@ -3116,7 +3119,10 @@ void CodeGenerator::InstantiateFunction(
// Create a new closure.
frame_->EmitPush(cp);
frame_->EmitPush(Operand(function_info));
frame_->CallRuntime(Runtime::kNewClosure, 2);
frame_->EmitPush(Operand(pretenure
? Factory::true_value()
: Factory::false_value()));
frame_->CallRuntime(Runtime::kNewClosure, 3);
frame_->EmitPush(r0);
}
}
@ -3136,7 +3142,7 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
ASSERT(frame_->height() == original_height);
return;
}
InstantiateFunction(function_info);
InstantiateFunction(function_info, node->pretenure());
ASSERT_EQ(original_height + 1, frame_->height());
}
@ -3147,7 +3153,7 @@ void CodeGenerator::VisitSharedFunctionInfoLiteral(
int original_height = frame_->height();
#endif
Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
InstantiateFunction(node->shared_function_info());
InstantiateFunction(node->shared_function_info(), false);
ASSERT_EQ(original_height + 1, frame_->height());
}
@ -5816,6 +5822,15 @@ void CodeGenerator::GenerateGetCachedArrayIndex(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
Load(args->at(0));
Register value = frame_->PopToRegister();
__ LoadRoot(value, Heap::kUndefinedValueRootIndex);
frame_->EmitPush(value);
}
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
#ifdef DEBUG
int original_height = frame_->height();

4
deps/v8/src/arm/codegen-arm.h

@ -449,7 +449,8 @@ class CodeGenerator: public AstVisitor {
void DeclareGlobals(Handle<FixedArray> pairs);
// Instantiate the function based on the shared function info.
void InstantiateFunction(Handle<SharedFunctionInfo> function_info);
void InstantiateFunction(Handle<SharedFunctionInfo> function_info,
bool pretenure);
// Support for type checks.
void GenerateIsSmi(ZoneList<Expression*>* args);
@ -528,6 +529,7 @@ class CodeGenerator: public AstVisitor {
void GenerateHasCachedArrayIndex(ZoneList<Expression*>* args);
void GenerateGetCachedArrayIndex(ZoneList<Expression*>* args);
void GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {

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

@ -860,18 +860,23 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
}
void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
bool pretenure) {
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
if (scope()->is_function_scope() && info->num_literals() == 0) {
if (scope()->is_function_scope() &&
info->num_literals() == 0 &&
!pretenure) {
FastNewClosureStub stub;
__ mov(r0, Operand(info));
__ push(r0);
__ CallStub(&stub);
} else {
__ mov(r0, Operand(info));
__ Push(cp, r0);
__ CallRuntime(Runtime::kNewClosure, 2);
__ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex
: Heap::kFalseValueRootIndex);
__ Push(cp, r0, r1);
__ CallRuntime(Runtime::kNewClosure, 3);
}
context()->Plug(r0);
}
@ -2772,6 +2777,13 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
}
void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
context()->Plug(r0);
return;
}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') {

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

@ -598,8 +598,8 @@ static void GenerateFastApiCall(MacroAssembler* masm,
int argc) {
// Get the function and setup the context.
JSFunction* function = optimization.constant_function();
__ mov(r7, Operand(Handle<JSFunction>(function)));
__ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
__ mov(r5, Operand(Handle<JSFunction>(function)));
__ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset));
// Pass the additional arguments FastHandleApiCall expects.
bool info_loaded = false;
@ -607,18 +607,18 @@ static void GenerateFastApiCall(MacroAssembler* masm,
if (Heap::InNewSpace(callback)) {
info_loaded = true;
__ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
__ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
__ ldr(r7, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
} else {
__ Move(r6, Handle<Object>(callback));
__ Move(r7, Handle<Object>(callback));
}
Object* call_data = optimization.api_call_info()->data();
if (Heap::InNewSpace(call_data)) {
if (!info_loaded) {
__ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
}
__ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
__ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
} else {
__ Move(r5, Handle<Object>(call_data));
__ Move(r6, Handle<Object>(call_data));
}
__ add(sp, sp, Operand(1 * kPointerSize));
@ -1082,10 +1082,9 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
// Push the arguments on the JS stack of the caller.
__ push(receiver); // Receiver.
__ push(reg); // Holder.
__ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
__ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
__ Push(ip, reg, name_reg);
__ mov(scratch3, Operand(Handle<AccessorInfo>(callback))); // callback data
__ ldr(ip, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
__ Push(reg, ip, scratch3, name_reg);
// Do tail-call to the runtime system.
ExternalReference load_callback_property =
@ -1208,15 +1207,15 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
// holder_reg is either receiver or scratch1.
if (!receiver.is(holder_reg)) {
ASSERT(scratch1.is(holder_reg));
__ Push(receiver, holder_reg, scratch2);
__ ldr(scratch1,
FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
__ Push(scratch1, name_reg);
__ Push(receiver, holder_reg);
__ ldr(scratch3,
FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
__ Push(scratch3, scratch2, name_reg);
} else {
__ push(receiver);
__ ldr(scratch1,
FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
__ Push(holder_reg, scratch2, scratch1, name_reg);
__ ldr(scratch3,
FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
__ Push(holder_reg, scratch3, scratch2, name_reg);
}
ExternalReference ref =
@ -1360,10 +1359,11 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
// -- ...
// -- sp[argc * 4] : receiver
// -----------------------------------
// TODO(639): faster implementation.
// If object is not an array, bail out to regular call.
if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
@ -1371,20 +1371,133 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
GenerateNameCheck(name, &miss);
Register receiver = r1;
// Get the receiver from the stack
const int argc = arguments().immediate();
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
__ ldr(receiver, MemOperand(sp, argc * kPointerSize));
// Check that the receiver isn't a smi.
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &miss);
__ BranchOnSmi(receiver, &miss);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
CheckPrototypes(JSObject::cast(object), receiver,
holder, r3, r0, r4, name, &miss);
if (argc == 0) {
// Nothing to do, just return the length.
__ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ Drop(argc + 1);
__ Ret();
} else {
Label call_builtin;
Register elements = r3;
Register end_elements = r5;
// Get the elements array of the object.
__ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
// Check that the elements are in fast mode and writable.
__ CheckMap(elements, r0,
Heap::kFixedArrayMapRootIndex, &call_builtin, true);
if (argc == 1) { // Otherwise fall through to call the builtin.
Label exit, with_write_barrier, attempt_to_grow_elements;
// Get the array's length into r0 and calculate new length.
__ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
STATIC_ASSERT(kSmiTagSize == 1);
STATIC_ASSERT(kSmiTag == 0);
__ add(r0, r0, Operand(Smi::FromInt(argc)));
// Get the element's length.
__ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
// Check if we could survive without allocation.
__ cmp(r0, r4);
__ b(gt, &attempt_to_grow_elements);
// Save new length.
__ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
// Push the element.
__ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
// We may need a register containing the address end_elements below,
// so write back the value in end_elements.
__ add(end_elements, elements,
Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
const int kEndElementsOffset =
FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
__ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex));
// Check for a smi.
__ BranchOnNotSmi(r4, &with_write_barrier);
__ bind(&exit);
__ Drop(argc + 1);
__ Ret();
__ bind(&with_write_barrier);
__ InNewSpace(elements, r4, eq, &exit);
__ RecordWriteHelper(elements, end_elements, r4);
__ Drop(argc + 1);
__ Ret();
__ bind(&attempt_to_grow_elements);
// r0: array's length + 1.
// r4: elements' length.
if (!FLAG_inline_new) {
__ b(&call_builtin);
}
ExternalReference new_space_allocation_top =
ExternalReference::new_space_allocation_top_address();
ExternalReference new_space_allocation_limit =
ExternalReference::new_space_allocation_limit_address();
const int kAllocationDelta = 4;
// Load top and check if it is the end of elements.
__ add(end_elements, elements,
Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
__ add(end_elements, end_elements, Operand(kEndElementsOffset));
__ mov(r7, Operand(new_space_allocation_top));
__ ldr(r6, MemOperand(r7));
__ cmp(end_elements, r6);
__ b(ne, &call_builtin);
__ mov(r9, Operand(new_space_allocation_limit));
__ ldr(r9, MemOperand(r9));
__ add(r6, r6, Operand(kAllocationDelta * kPointerSize));
__ cmp(r6, r9);
__ b(hi, &call_builtin);
// We fit and could grow elements.
// Update new_space_allocation_top.
__ str(r6, MemOperand(r7));
// Push the argument.
__ ldr(r6, MemOperand(sp, (argc - 1) * kPointerSize));
__ str(r6, MemOperand(end_elements));
// Fill the rest with holes.
__ LoadRoot(r6, Heap::kTheHoleValueRootIndex);
for (int i = 1; i < kAllocationDelta; i++) {
__ str(r6, MemOperand(end_elements, i * kPointerSize));
}
// Update elements' and array's sizes.
__ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ add(r4, r4, Operand(Smi::FromInt(kAllocationDelta)));
__ str(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
// Elements are in new space, so write barrier is not required.
__ Drop(argc + 1);
__ Ret();
}
__ bind(&call_builtin);
__ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
argc + 1,
1);
}
// Handle call cache miss.
__ bind(&miss);
@ -1406,28 +1519,68 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
// -- ...
// -- sp[argc * 4] : receiver
// -----------------------------------
// TODO(642): faster implementation.
// If object is not an array, bail out to regular call.
if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
Label miss;
Label miss, return_undefined, call_builtin;
Register receiver = r1;
Register elements = r3;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack
const int argc = arguments().immediate();
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
__ ldr(receiver, MemOperand(sp, argc * kPointerSize));
// Check that the receiver isn't a smi.
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &miss);
__ BranchOnSmi(receiver, &miss);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
CheckPrototypes(JSObject::cast(object),
receiver, holder, elements, r4, r0, name, &miss);
// Get the elements array of the object.
__ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
// Check that the elements are in fast mode and writable.
__ CheckMap(elements, r0, Heap::kFixedArrayMapRootIndex, &call_builtin, true);
// Get the array's length into r4 and calculate new length.
__ ldr(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ sub(r4, r4, Operand(Smi::FromInt(1)), SetCC);
__ b(lt, &return_undefined);
// Get the last element.
__ LoadRoot(r6, Heap::kTheHoleValueRootIndex);
STATIC_ASSERT(kSmiTagSize == 1);
STATIC_ASSERT(kSmiTag == 0);
// We can't address the last element in one operation. Compute the more
// expensive shift first, and use an offset later on.
__ add(elements, elements, Operand(r4, LSL, kPointerSizeLog2 - kSmiTagSize));
__ ldr(r0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
__ cmp(r0, r6);
__ b(eq, &call_builtin);
// Set the array's length.
__ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
// Fill with the hole.
__ str(r6, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
__ Drop(argc + 1);
__ Ret();
__ bind(&return_undefined);
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
__ Drop(argc + 1);
__ Ret();
__ bind(&call_builtin);
__ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
argc + 1,
1);
@ -2672,7 +2825,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
// -- r1 : receiver
// -----------------------------------
Label miss;
__ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
__ IncrementCounter(&Counters::keyed_load_string_length, 1, r2, r3);
// Check the key is the cached one.
__ cmp(r0, Operand(Handle<String>(name)));
@ -2680,7 +2833,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
__ DecrementCounter(&Counters::keyed_load_string_length, 1, r2, r3);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@ -2688,13 +2841,23 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
}
// TODO(1224671): implement the fast case.
MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
Label miss;
__ IncrementCounter(&Counters::keyed_load_function_prototype, 1, r2, r3);
// Check the name hasn't changed.
__ cmp(r0, Operand(Handle<String>(name)));
__ b(ne, &miss);
GenerateLoadFunctionPrototype(masm(), r1, r2, r3, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_function_prototype, 1, r2, r3);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
return GetCode(CALLBACKS, name);

4
deps/v8/src/array.js

@ -364,6 +364,10 @@ function ArrayJoin(separator) {
} else if (!IS_STRING(separator)) {
separator = ToString(separator);
}
var result = %_FastAsciiArrayJoin(this, separator);
if (typeof result != "undefined") return result;
var length = TO_UINT32(this.length);
return Join(this, length, separator, ConvertToString);
}

7
deps/v8/src/ast.h

@ -1416,7 +1416,8 @@ class FunctionLiteral: public Expression {
contains_loops_(contains_loops),
function_token_position_(RelocInfo::kNoPosition),
inferred_name_(Heap::empty_string()),
try_full_codegen_(false) {
try_full_codegen_(false),
pretenure_(false) {
#ifdef DEBUG
already_compiled_ = false;
#endif
@ -1459,6 +1460,9 @@ class FunctionLiteral: public Expression {
bool try_full_codegen() { return try_full_codegen_; }
void set_try_full_codegen(bool flag) { try_full_codegen_ = flag; }
bool pretenure() { return pretenure_; }
void set_pretenure(bool value) { pretenure_ = value; }
#ifdef DEBUG
void mark_as_compiled() {
ASSERT(!already_compiled_);
@ -1482,6 +1486,7 @@ class FunctionLiteral: public Expression {
int function_token_position_;
Handle<String> inferred_name_;
bool try_full_codegen_;
bool pretenure_;
#ifdef DEBUG
bool already_compiled_;
#endif

21
deps/v8/src/builtins.cc

@ -1081,29 +1081,22 @@ BUILTIN(FastHandleApiCall) {
ASSERT(!CalledAsConstructor());
const bool is_construct = false;
// We expect four more arguments: function, callback, call data, and holder.
// We expect four more arguments: callback, function, call data, and holder.
const int args_length = args.length() - 4;
ASSERT(args_length >= 0);
Handle<JSFunction> function = args.at<JSFunction>(args_length);
Object* callback_obj = args[args_length + 1];
Handle<Object> data = args.at<Object>(args_length + 2);
Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3);
#ifdef DEBUG
VerifyTypeCheck(checked_holder, function);
#endif
CustomArguments custom;
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
*data, *function, *checked_holder);
Object* callback_obj = args[args_length];
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
custom.end(),
&args[args_length + 1],
&args[0] - 1,
args_length - 1,
is_construct);
#ifdef DEBUG
VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()),
Utils::OpenHandle(*new_args.Callee()));
#endif
HandleScope scope;
Object* result;
v8::Handle<v8::Value> value;

10
deps/v8/src/conversions.cc

@ -39,16 +39,6 @@
namespace v8 {
namespace internal {
int HexValue(uc32 c) {
if ('0' <= c && c <= '9')
return c - '0';
if ('a' <= c && c <= 'f')
return c - 'a' + 10;
if ('A' <= c && c <= 'F')
return c - 'A' + 10;
return -1;
}
namespace {
// C++-style iterator adaptor for StringInputBuffer

5
deps/v8/src/conversions.h

@ -75,11 +75,6 @@ static inline uint32_t DoubleToUint32(double x) {
}
// Returns the value (0 .. 15) of a hexadecimal character c.
// If c is not a legal hexadecimal character, returns a value < 0.
int HexValue(uc32 c);
// Enumeration for allowing octals and ignoring junk when converting
// strings to numbers.
enum ConversionFlags {

92
deps/v8/src/dtoa-config.c

@ -1,92 +0,0 @@
/*
* Copyright 2007-2008 the V8 project authors. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Dtoa needs to have a particular environment set up for it so
* instead of using it directly you should use this file.
*
* The way it works is that when you link with it, its definitions
* of dtoa, strtod etc. override the default ones. So if you fail
* to link with this library everything will still work, it's just
* subtly wrong.
*/
#if !(defined(__APPLE__) && defined(__MACH__)) && \
!defined(WIN32) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && \
!defined(__sun)
#include <endian.h>
#endif
#include <math.h>
#include <float.h>
/* The floating point word order on ARM is big endian when floating point
* emulation is used, even if the byte order is little endian */
#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32) && \
!defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sun) && \
__FLOAT_WORD_ORDER == __BIG_ENDIAN
#define IEEE_MC68k
#else
#define IEEE_8087
#endif
#define __MATH_H__
#if defined(__APPLE__) && defined(__MACH__) || defined(__FreeBSD__) || \
defined(__OpenBSD__) || defined(__sun)
/* stdlib.h on FreeBSD and Apple's 10.5 and later SDKs will mangle the
* name of strtod. If it's included after strtod is redefined as
* gay_strtod, it will mangle the name of gay_strtod, which is
* unwanted. */
#include <stdlib.h>
#endif
/* stdlib.h on Windows adds __declspec(dllimport) to all functions when using
* the DLL version of the CRT (compiling with /MD or /MDd). If stdlib.h is
* included after strtod is redefined as gay_strtod, it will add
* __declspec(dllimport) to gay_strtod, which causes the compilation of
* gay_strtod in dtoa.c to fail.
*/
#if defined(WIN32) && defined(_DLL)
#include "stdlib.h"
#endif
/* For MinGW, turn on __NO_ISOCEXT so that its strtod doesn't get added */
#ifdef __MINGW32__
#define __NO_ISOCEXT
#endif /* __MINGW32__ */
/* On 64-bit systems, we need to make sure that a Long is only 32 bits. */
#ifdef V8_TARGET_ARCH_X64
#define Long int
#endif /* V8_TARGET_ARCH_X64 */
/* Make sure we use the David M. Gay version of strtod(). On Linux, we
* cannot use the same name (maybe the function does not have weak
* linkage?). */
#define strtod gay_strtod
#include "third_party/dtoa/dtoa.c"

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

@ -882,12 +882,12 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
Visit(stmt->body());
// Check stack before looping.
__ bind(loop_statement.continue_target());
__ StackLimitCheck(&stack_limit_hit);
__ bind(&stack_check_success);
// Record the position of the do while condition and make sure it is
// possible to break on the condition.
__ bind(loop_statement.continue_target());
SetExpressionPosition(stmt->cond(), stmt->condition_position());
VisitForControl(stmt->cond(),
&body,
@ -1168,14 +1168,14 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
SetStackOverflow();
return;
}
EmitNewClosure(function_info);
EmitNewClosure(function_info, expr->pretenure());
}
void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
SharedFunctionInfoLiteral* expr) {
Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
EmitNewClosure(expr->shared_function_info());
EmitNewClosure(expr->shared_function_info(), false);
}

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

@ -348,7 +348,7 @@ class FullCodeGenerator: public AstVisitor {
// Platform-specific support for allocating a new closure based on
// the given function info.
void EmitNewClosure(Handle<SharedFunctionInfo> info);
void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure);
// Platform-specific support for compiling assignments.

66
deps/v8/src/handles.cc

@ -37,6 +37,7 @@
#include "global-handles.h"
#include "natives.h"
#include "runtime.h"
#include "string-search.h"
#include "stub-cache.h"
namespace v8 {
@ -508,43 +509,50 @@ void InitScriptLineEnds(Handle<Script> script) {
}
Handle<FixedArray> CalculateLineEnds(Handle<String> src,
bool with_imaginary_last_new_line) {
const int src_len = src->length();
Handle<String> new_line = Factory::NewStringFromAscii(CStrVector("\n"));
template <typename SourceChar>
static void CalculateLineEnds(List<int>* line_ends,
Vector<const SourceChar> src,
bool with_last_line) {
const int src_len = src.length();
StringSearch<char, SourceChar> search(CStrVector("\n"));
// Pass 1: Identify line count.
int line_count = 0;
// Find and record line ends.
int position = 0;
while (position != -1 && position < src_len) {
position = Runtime::StringMatch(src, new_line, position);
position = search.Search(src, position);
if (position != -1) {
line_ends->Add(position);
position++;
}
if (position != -1) {
line_count++;
} else if (with_imaginary_last_new_line) {
} else if (with_last_line) {
// Even if the last line misses a line end, it is counted.
line_count++;
line_ends->Add(src_len);
return;
}
}
}
// Pass 2: Fill in line ends positions
Handle<FixedArray> array = Factory::NewFixedArray(line_count);
int array_index = 0;
position = 0;
while (position != -1 && position < src_len) {
position = Runtime::StringMatch(src, new_line, position);
if (position != -1) {
array->set(array_index++, Smi::FromInt(position++));
} else if (with_imaginary_last_new_line) {
// If the script does not end with a line ending add the final end
// position as just past the last line ending.
array->set(array_index++, Smi::FromInt(src_len));
Handle<FixedArray> CalculateLineEnds(Handle<String> src,
bool with_last_line) {
src = FlattenGetString(src);
// Rough estimate of line count based on a roughly estimated average
// length of (unpacked) code.
int line_count_estimate = src->length() >> 4;
List<int> line_ends(line_count_estimate);
{
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid.
// Dispatch on type of strings.
if (src->IsAsciiRepresentation()) {
CalculateLineEnds(&line_ends, src->ToAsciiVector(), with_last_line);
} else {
CalculateLineEnds(&line_ends, src->ToUC16Vector(), with_last_line);
}
}
ASSERT(array_index == line_count);
int line_count = line_ends.length();
Handle<FixedArray> array = Factory::NewFixedArray(line_count);
for (int i = 0; i < line_count; i++) {
array->set(i, Smi::FromInt(line_ends[i]));
}
return array;
}
@ -556,11 +564,11 @@ int GetScriptLineNumber(Handle<Script> script, int code_pos) {
FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
const int line_ends_len = line_ends_array->length();
if (!line_ends_len)
return -1;
if (!line_ends_len) return -1;
if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos)
if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
return script->line_offset()->value();
}
int left = 0;
int right = line_ends_len;

16
deps/v8/src/heap-profiler.cc

@ -927,10 +927,16 @@ class AllocatingRetainersIterator {
void Call(const JSObjectsCluster& cluster,
const NumberAndSizeInfo& number_and_size) {
int child_index, retainer_index;
map_->CountReference(ClusterAsHeapObject(cluster), child_,
&child_index, &retainer_index);
map_->Map(ClusterAsHeapObject(cluster))->SetElementReference(
child_index, number_and_size.number(), child_entry_, retainer_index);
map_->CountReference(ClusterAsHeapObject(cluster),
child_,
&child_index,
&retainer_index);
map_->Map(ClusterAsHeapObject(cluster))->SetIndexedReference(
HeapGraphEdge::kElement,
child_index,
number_and_size.number(),
child_entry_,
retainer_index);
}
private:
@ -1042,7 +1048,7 @@ void AggregatedHeapSnapshotGenerator::FillHeapSnapshot(HeapSnapshot* snapshot) {
if (agg_snapshot_->info()[i].bytes() > 0) {
AddEntryFromAggregatedSnapshot(snapshot,
&root_child_index,
HeapEntry::kInternal,
HeapEntry::kHidden,
agg_snapshot_->info()[i].name(),
agg_snapshot_->info()[i].number(),
agg_snapshot_->info()[i].bytes(),

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

@ -80,8 +80,9 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
__ pop(edx);
__ push(esi);
__ push(edx);
__ push(Immediate(Factory::false_value()));
__ push(ecx); // Restore return address.
__ TailCallRuntime(Runtime::kNewClosure, 2, 1);
__ TailCallRuntime(Runtime::kNewClosure, 3, 1);
}

200
deps/v8/src/ia32/codegen-ia32.cc

@ -4897,7 +4897,8 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
Result CodeGenerator::InstantiateFunction(
Handle<SharedFunctionInfo> function_info) {
Handle<SharedFunctionInfo> function_info,
bool pretenure) {
// The inevitable call will sync frame elements to memory anyway, so
// we do it eagerly to allow us to push the arguments directly into
// place.
@ -4905,7 +4906,9 @@ Result CodeGenerator::InstantiateFunction(
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
if (scope()->is_function_scope() && function_info->num_literals() == 0) {
if (scope()->is_function_scope() &&
function_info->num_literals() == 0 &&
!pretenure) {
FastNewClosureStub stub;
frame()->EmitPush(Immediate(function_info));
return frame()->CallStub(&stub, 1);
@ -4914,7 +4917,10 @@ Result CodeGenerator::InstantiateFunction(
// shared function info.
frame()->EmitPush(esi);
frame()->EmitPush(Immediate(function_info));
return frame()->CallRuntime(Runtime::kNewClosure, 2);
frame()->EmitPush(Immediate(pretenure
? Factory::true_value()
: Factory::false_value()));
return frame()->CallRuntime(Runtime::kNewClosure, 3);
}
}
@ -4930,7 +4936,7 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
SetStackOverflow();
return;
}
Result result = InstantiateFunction(function_info);
Result result = InstantiateFunction(function_info, node->pretenure());
frame()->Push(&result);
}
@ -4939,7 +4945,7 @@ void CodeGenerator::VisitSharedFunctionInfoLiteral(
SharedFunctionInfoLiteral* node) {
ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
Result result = InstantiateFunction(node->shared_function_info());
Result result = InstantiateFunction(node->shared_function_info(), false);
frame()->Push(&result);
}
@ -6642,6 +6648,190 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
Load(args->at(1));
Load(args->at(0));
Result array_result = frame_->Pop();
array_result.ToRegister(eax);
frame_->SpillAll();
Label bailout;
Label done;
// All aliases of the same register have disjoint lifetimes.
Register array = eax;
Register result_pos = no_reg;
Register index = edi;
Register current_string_length = ecx; // Will be ecx when live.
Register current_string = edx;
Register scratch = ebx;
Register scratch_2 = esi;
Register new_padding_chars = scratch_2;
Operand separator = Operand(esp, 4 * kPointerSize); // Already pushed.
Operand elements = Operand(esp, 3 * kPointerSize);
Operand result = Operand(esp, 2 * kPointerSize);
Operand padding_chars = Operand(esp, 1 * kPointerSize);
Operand array_length = Operand(esp, 0);
__ sub(Operand(esp), Immediate(4 * kPointerSize));
// Check that eax is a JSArray
__ test(array, Immediate(kSmiTagMask));
__ j(zero, &bailout);
__ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
__ j(not_equal, &bailout);
// Check that the array has fast elements.
__ test_b(FieldOperand(scratch, Map::kBitField2Offset),
1 << Map::kHasFastElements);
__ j(zero, &bailout);
// If the array is empty, return the empty string.
__ mov(scratch, FieldOperand(array, JSArray::kLengthOffset));
__ sar(scratch, 1);
Label non_trivial;
__ j(not_zero, &non_trivial);
__ mov(result, Factory::empty_string());
__ jmp(&done);
__ bind(&non_trivial);
__ mov(array_length, scratch);
__ mov(scratch, FieldOperand(array, JSArray::kElementsOffset));
__ mov(elements, scratch);
// End of array's live range.
result_pos = array;
array = no_reg;
// Check that the separator is a flat ascii string.
__ mov(current_string, separator);
__ test(current_string, Immediate(kSmiTagMask));
__ j(zero, &bailout);
__ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset));
__ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
__ and_(scratch, Immediate(
kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
__ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
__ j(not_equal, &bailout);
// If the separator is the empty string, replace it with NULL.
// The test for NULL is quicker than the empty string test, in a loop.
__ cmp(FieldOperand(current_string, SeqAsciiString::kLengthOffset),
Immediate(0));
Label separator_checked;
__ j(not_zero, &separator_checked);
__ mov(separator, Immediate(0));
__ bind(&separator_checked);
// Check that elements[0] is a flat ascii string, and copy it in new space.
__ mov(scratch, elements);
__ mov(current_string, FieldOperand(scratch, FixedArray::kHeaderSize));
__ test(current_string, Immediate(kSmiTagMask));
__ j(zero, &bailout);
__ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset));
__ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
__ and_(scratch, Immediate(
kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
__ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
__ j(not_equal, &bailout);
// Allocate space to copy it. Round up the size to the alignment granularity.
__ mov(current_string_length,
FieldOperand(current_string, String::kLengthOffset));
__ shr(current_string_length, 1);
// Live registers and stack values:
// current_string_length: length of elements[0].
// New string result in new space = elements[0]
__ AllocateAsciiString(result_pos, current_string_length, scratch_2,
index, no_reg, &bailout);
__ mov(result, result_pos);
// Adjust current_string_length to include padding bytes at end of string.
// Keep track of the number of padding bytes.
__ mov(new_padding_chars, current_string_length);
__ add(Operand(current_string_length), Immediate(kObjectAlignmentMask));
__ and_(Operand(current_string_length), Immediate(~kObjectAlignmentMask));
__ sub(new_padding_chars, Operand(current_string_length));
__ neg(new_padding_chars);
__ mov(padding_chars, new_padding_chars);
Label copy_loop_1_done;
Label copy_loop_1;
__ test(current_string_length, Operand(current_string_length));
__ j(zero, &copy_loop_1_done);
__ bind(&copy_loop_1);
__ sub(Operand(current_string_length), Immediate(kPointerSize));
__ mov(scratch, FieldOperand(current_string, current_string_length,
times_1, SeqAsciiString::kHeaderSize));
__ mov(FieldOperand(result_pos, current_string_length,
times_1, SeqAsciiString::kHeaderSize),
scratch);
__ j(not_zero, &copy_loop_1);
__ bind(&copy_loop_1_done);
__ mov(index, Immediate(1));
// Loop condition: while (index < length).
Label loop;
__ bind(&loop);
__ cmp(index, array_length);
__ j(greater_equal, &done);
// If the separator is the empty string, signalled by NULL, skip it.
Label separator_done;
__ mov(current_string, separator);
__ test(current_string, Operand(current_string));
__ j(zero, &separator_done);
// Append separator to result. It is known to be a flat ascii string.
__ AppendStringToTopOfNewSpace(current_string, current_string_length,
result_pos, scratch, scratch_2, result,
padding_chars, &bailout);
__ bind(&separator_done);
// Add next element of array to the end of the result.
// Get current_string = array[index].
__ mov(scratch, elements);
__ mov(current_string, FieldOperand(scratch, index,
times_pointer_size,
FixedArray::kHeaderSize));
// If current != flat ascii string drop result, return undefined.
__ test(current_string, Immediate(kSmiTagMask));
__ j(zero, &bailout);
__ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset));
__ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
__ and_(scratch, Immediate(
kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
__ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
__ j(not_equal, &bailout);
// Append current to the result.
__ AppendStringToTopOfNewSpace(current_string, current_string_length,
result_pos, scratch, scratch_2, result,
padding_chars, &bailout);
__ add(Operand(index), Immediate(1));
__ jmp(&loop); // End while (index < length).
__ bind(&bailout);
__ mov(result, Factory::undefined_value());
__ bind(&done);
__ mov(eax, result);
// Drop temp values from the stack, and restore context register.
__ add(Operand(esp), Immediate(4 * kPointerSize));
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
frame_->Drop(1);
frame_->Push(&array_result);
}
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));

4
deps/v8/src/ia32/codegen-ia32.h

@ -625,7 +625,8 @@ class CodeGenerator: public AstVisitor {
void DeclareGlobals(Handle<FixedArray> pairs);
// Instantiate the function based on the shared function info.
Result InstantiateFunction(Handle<SharedFunctionInfo> function_info);
Result InstantiateFunction(Handle<SharedFunctionInfo> function_info,
bool pretenure);
// Support for types.
void GenerateIsSmi(ZoneList<Expression*>* args);
@ -710,6 +711,7 @@ class CodeGenerator: public AstVisitor {
void GenerateHasCachedArrayIndex(ZoneList<Expression*>* args);
void GenerateGetCachedArrayIndex(ZoneList<Expression*>* args);
void GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {

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

@ -880,17 +880,23 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
}
void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
bool pretenure) {
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
if (scope()->is_function_scope() && info->num_literals() == 0) {
if (scope()->is_function_scope() &&
info->num_literals() == 0 &&
!pretenure) {
FastNewClosureStub stub;
__ push(Immediate(info));
__ CallStub(&stub);
} else {
__ push(esi);
__ push(Immediate(info));
__ CallRuntime(Runtime::kNewClosure, 2);
__ push(Immediate(pretenure
? Factory::true_value()
: Factory::false_value()));
__ CallRuntime(Runtime::kNewClosure, 3);
}
context()->Plug(eax);
}
@ -3084,6 +3090,190 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
}
void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
Label bailout;
Label done;
ASSERT(args->length() == 2);
// We will leave the separator on the stack until the end of the function.
VisitForStackValue(args->at(1));
// Load this to eax (= array)
VisitForAccumulatorValue(args->at(0));
// All aliases of the same register have disjoint lifetimes.
Register array = eax;
Register result_pos = no_reg;
Register index = edi;
Register current_string_length = ecx; // Will be ecx when live.
Register current_string = edx;
Register scratch = ebx;
Register scratch_2 = esi;
Register new_padding_chars = scratch_2;
Operand separator = Operand(esp, 4 * kPointerSize); // Already pushed.
Operand elements = Operand(esp, 3 * kPointerSize);
Operand result = Operand(esp, 2 * kPointerSize);
Operand padding_chars = Operand(esp, 1 * kPointerSize);
Operand array_length = Operand(esp, 0);
__ sub(Operand(esp), Immediate(4 * kPointerSize));
// Check that eax is a JSArray
__ test(array, Immediate(kSmiTagMask));
__ j(zero, &bailout);
__ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
__ j(not_equal, &bailout);
// Check that the array has fast elements.
__ test_b(FieldOperand(scratch, Map::kBitField2Offset),
1 << Map::kHasFastElements);
__ j(zero, &bailout);
// If the array is empty, return the empty string.
__ mov(scratch, FieldOperand(array, JSArray::kLengthOffset));
__ sar(scratch, 1);
Label non_trivial;
__ j(not_zero, &non_trivial);
__ mov(result, Factory::empty_string());
__ jmp(&done);
__ bind(&non_trivial);
__ mov(array_length, scratch);
__ mov(scratch, FieldOperand(array, JSArray::kElementsOffset));
__ mov(elements, scratch);
// End of array's live range.
result_pos = array;
array = no_reg;
// Check that the separator is a flat ascii string.
__ mov(current_string, separator);
__ test(current_string, Immediate(kSmiTagMask));
__ j(zero, &bailout);
__ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset));
__ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
__ and_(scratch, Immediate(
kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
__ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
__ j(not_equal, &bailout);
// If the separator is the empty string, replace it with NULL.
// The test for NULL is quicker than the empty string test, in a loop.
__ cmp(FieldOperand(current_string, SeqAsciiString::kLengthOffset),
Immediate(0));
Label separator_checked;
__ j(not_zero, &separator_checked);
__ mov(separator, Immediate(0));
__ bind(&separator_checked);
// Check that elements[0] is a flat ascii string, and copy it in new space.
__ mov(scratch, elements);
__ mov(current_string, FieldOperand(scratch, FixedArray::kHeaderSize));
__ test(current_string, Immediate(kSmiTagMask));
__ j(zero, &bailout);
__ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset));
__ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
__ and_(scratch, Immediate(
kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
__ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
__ j(not_equal, &bailout);
// Allocate space to copy it. Round up the size to the alignment granularity.
__ mov(current_string_length,
FieldOperand(current_string, String::kLengthOffset));
__ shr(current_string_length, 1);
// Live registers and stack values:
// current_string_length: length of elements[0].
// New string result in new space = elements[0]
__ AllocateAsciiString(result_pos, current_string_length, scratch_2,
index, no_reg, &bailout);
__ mov(result, result_pos);
// Adjust current_string_length to include padding bytes at end of string.
// Keep track of the number of padding bytes.
__ mov(new_padding_chars, current_string_length);
__ add(Operand(current_string_length), Immediate(kObjectAlignmentMask));
__ and_(Operand(current_string_length), Immediate(~kObjectAlignmentMask));
__ sub(new_padding_chars, Operand(current_string_length));
__ neg(new_padding_chars);
__ mov(padding_chars, new_padding_chars);
Label copy_loop_1_done;
Label copy_loop_1;
__ test(current_string_length, Operand(current_string_length));
__ j(zero, &copy_loop_1_done);
__ bind(&copy_loop_1);
__ sub(Operand(current_string_length), Immediate(kPointerSize));
__ mov(scratch, FieldOperand(current_string, current_string_length,
times_1, SeqAsciiString::kHeaderSize));
__ mov(FieldOperand(result_pos, current_string_length,
times_1, SeqAsciiString::kHeaderSize),
scratch);
__ j(not_zero, &copy_loop_1);
__ bind(&copy_loop_1_done);
__ mov(index, Immediate(1));
// Loop condition: while (index < length).
Label loop;
__ bind(&loop);
__ cmp(index, array_length);
__ j(greater_equal, &done);
// If the separator is the empty string, signalled by NULL, skip it.
Label separator_done;
__ mov(current_string, separator);
__ test(current_string, Operand(current_string));
__ j(zero, &separator_done);
// Append separator to result. It is known to be a flat ascii string.
__ AppendStringToTopOfNewSpace(current_string, current_string_length,
result_pos, scratch, scratch_2, result,
padding_chars, &bailout);
__ bind(&separator_done);
// Add next element of array to the end of the result.
// Get current_string = array[index].
__ mov(scratch, elements);
__ mov(current_string, FieldOperand(scratch, index,
times_pointer_size,
FixedArray::kHeaderSize));
// If current != flat ascii string drop result, return undefined.
__ test(current_string, Immediate(kSmiTagMask));
__ j(zero, &bailout);
__ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset));
__ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
__ and_(scratch, Immediate(
kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
__ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
__ j(not_equal, &bailout);
// Append current to the result.
__ AppendStringToTopOfNewSpace(current_string, current_string_length,
result_pos, scratch, scratch_2, result,
padding_chars, &bailout);
__ add(Operand(index), Immediate(1));
__ jmp(&loop); // End while (index < length).
__ bind(&bailout);
__ mov(result, Factory::undefined_value());
__ bind(&done);
__ mov(eax, result);
// Drop temp values from the stack, and restore context register.
__ add(Operand(esp), Immediate(5 * kPointerSize));
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
context()->Plug(eax);
}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') {

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

@ -889,6 +889,57 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
Immediate(Factory::cons_ascii_string_map()));
}
// All registers must be distinct. Only current_string needs valid contents
// on entry. All registers may be invalid on exit. result_operand is
// unchanged, padding_chars is updated correctly.
void MacroAssembler::AppendStringToTopOfNewSpace(
Register current_string, // Tagged pointer to string to copy.
Register current_string_length,
Register result_pos,
Register scratch,
Register new_padding_chars,
Operand operand_result,
Operand operand_padding_chars,
Label* bailout) {
mov(current_string_length,
FieldOperand(current_string, String::kLengthOffset));
shr(current_string_length, 1);
sub(current_string_length, operand_padding_chars);
mov(new_padding_chars, current_string_length);
add(Operand(current_string_length), Immediate(kObjectAlignmentMask));
and_(Operand(current_string_length), Immediate(~kObjectAlignmentMask));
sub(new_padding_chars, Operand(current_string_length));
neg(new_padding_chars);
// We need an allocation even if current_string_length is 0, to fetch
// result_pos. Consider using a faster fetch of result_pos in that case.
AllocateInNewSpace(current_string_length, result_pos, scratch, no_reg,
bailout, NO_ALLOCATION_FLAGS);
sub(result_pos, operand_padding_chars);
mov(operand_padding_chars, new_padding_chars);
Register scratch_2 = new_padding_chars; // Used to compute total length.
// Copy string to the end of result.
mov(current_string_length,
FieldOperand(current_string, String::kLengthOffset));
mov(scratch, operand_result);
mov(scratch_2, current_string_length);
add(scratch_2, FieldOperand(scratch, String::kLengthOffset));
mov(FieldOperand(scratch, String::kLengthOffset), scratch_2);
shr(current_string_length, 1);
lea(current_string,
FieldOperand(current_string, SeqAsciiString::kHeaderSize));
// Loop condition: while (--current_string_length >= 0).
Label copy_loop;
Label copy_loop_entry;
jmp(&copy_loop_entry);
bind(&copy_loop);
mov_b(scratch, Operand(current_string, current_string_length, times_1, 0));
mov_b(Operand(result_pos, current_string_length, times_1, 0), scratch);
bind(&copy_loop_entry);
sub(Operand(current_string_length), Immediate(1));
j(greater_equal, &copy_loop);
}
void MacroAssembler::NegativeZeroTest(CodeGenerator* cgen,
Register result,

17
deps/v8/src/ia32/macro-assembler-ia32.h

@ -379,6 +379,23 @@ class MacroAssembler: public Assembler {
Register scratch2,
Label* gc_required);
// All registers must be distinct. Only current_string needs valid contents
// on entry. All registers may be invalid on exit. result_operand is
// unchanged, padding_chars is updated correctly.
// The top of new space must contain a sequential ascii string with
// padding_chars bytes free in its top word. The sequential ascii string
// current_string is concatenated to it, allocating the necessary amount
// of new memory.
void AppendStringToTopOfNewSpace(
Register current_string, // Tagged pointer to string to copy.
Register current_string_length,
Register result_pos,
Register scratch,
Register new_padding_chars,
Operand operand_result,
Operand operand_padding_chars,
Label* bailout);
// ---------------------------------------------------------------------------
// Support functions.

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

@ -417,7 +417,7 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
static const int kFastApiCallArguments = 3;
// Reserves space for the extra arguments to FastHandleApiCall in the
// Reserves space for the extra arguments to API function in the
// caller's frame.
//
// These arguments are set by CheckPrototypes and GenerateFastApiCall.
@ -450,7 +450,7 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
}
// Generates call to FastHandleApiCall builtin.
// Generates call to API function.
static bool GenerateFastApiCall(MacroAssembler* masm,
const CallOptimization& optimization,
int argc,
@ -473,7 +473,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm,
__ mov(edi, Immediate(Handle<JSFunction>(function)));
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Pass the additional arguments FastHandleApiCall expects.
// Pass the additional arguments.
__ mov(Operand(esp, 2 * kPointerSize), edi);
Object* call_data = optimization.api_call_info()->data();
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
@ -1141,7 +1141,6 @@ void StubCompiler::GenerateLoadConstant(JSObject* object,
__ j(zero, miss, not_taken);
// Check that the maps haven't changed.
Register reg =
CheckPrototypes(object, receiver, holder,
scratch1, scratch2, scratch3, name, miss);
@ -1263,8 +1262,8 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
__ push(receiver);
__ push(holder_reg);
__ mov(holder_reg, Immediate(Handle<AccessorInfo>(callback)));
__ push(holder_reg);
__ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
__ push(holder_reg);
__ push(name_reg);
__ push(scratch2); // restore return address
@ -2318,7 +2317,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
&miss,
&failure);
if (!success) {
return false;
return failure;
}
// Restore receiver.

69
deps/v8/src/parser.cc

@ -37,7 +37,6 @@
#include "parser.h"
#include "platform.h"
#include "preparser.h"
#include "prescanner.h"
#include "runtime.h"
#include "scopeinfo.h"
#include "string-stream.h"
@ -728,7 +727,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
// Initialize parser state.
source->TryFlatten();
scanner_.Initialize(source, JAVASCRIPT);
scanner_.Initialize(source);
ASSERT(target_stack_ == NULL);
if (pre_data_ != NULL) pre_data_->Initialize();
@ -791,8 +790,7 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
// Initialize parser state.
source->TryFlatten();
scanner_.Initialize(source, info->start_position(), info->end_position(),
JAVASCRIPT);
scanner_.Initialize(source, info->start_position(), info->end_position());
ASSERT(target_stack_ == NULL);
mode_ = PARSE_EAGERLY;
@ -2278,6 +2276,12 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
temp_scope_->AddProperty();
}
// If we assign a function literal to a property we pretenure the
// literal so it can be added as a constant function property.
if (property != NULL && right->AsFunctionLiteral() != NULL) {
right->AsFunctionLiteral()->set_pretenure(true);
}
if (fni_ != NULL) {
// Check if the right hand side is a call to avoid inferring a
// name if we're dealing with "a = function(){...}();"-like
@ -3613,7 +3617,7 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
Handle<Object> JsonParser::ParseJson(Handle<String> source) {
source->TryFlatten();
scanner_.Initialize(source, JSON);
scanner_.Initialize(source);
Handle<Object> result = ParseJsonValue();
if (result.is_null() || scanner_.Next() != Token::EOS) {
if (scanner_.stack_overflow()) {
@ -4638,13 +4642,15 @@ int ScriptDataImpl::ReadNumber(byte** source) {
}
static ScriptDataImpl* DoPreParse(UTF16Buffer* stream,
// Create a Scanner for the preparser to use as input, and preparse the source.
static ScriptDataImpl* DoPreParse(Handle<String> source,
unibrow::CharacterStream* stream,
bool allow_lazy,
PartialParserRecorder* recorder) {
typedef preparser::Scanner<UTF16Buffer, UTF8Buffer> PreScanner;
PreScanner scanner;
scanner.Initialize(stream);
preparser::PreParser<PreScanner, PartialParserRecorder> preparser;
PartialParserRecorder* recorder,
int literal_flags) {
V8JavaScriptScanner scanner;
scanner.Initialize(source, stream, literal_flags);
preparser::PreParser<JavaScriptScanner, PartialParserRecorder> preparser;
if (!preparser.PreParseProgram(&scanner, recorder, allow_lazy)) {
Top::StackOverflow();
return NULL;
@ -4657,44 +4663,11 @@ static ScriptDataImpl* DoPreParse(UTF16Buffer* stream,
}
// Create an UTF16Buffer for the preparser to use as input,
// and preparse the source.
static ScriptDataImpl* DoPreParse(Handle<String> source,
unibrow::CharacterStream* stream,
bool allow_lazy,
PartialParserRecorder* recorder) {
if (source.is_null()) {
CharacterStreamUTF16Buffer buffer;
int length = stream->Length();
buffer.Initialize(source, stream, 0, length);
return DoPreParse(&buffer, allow_lazy, recorder);
} else if (source->IsExternalAsciiString()) {
ExternalStringUTF16Buffer<ExternalAsciiString, char> buffer;
int length = source->length();
buffer.Initialize(Handle<ExternalAsciiString>::cast(source), 0, length);
return DoPreParse(&buffer, allow_lazy, recorder);
} else if (source->IsExternalTwoByteString()) {
ExternalStringUTF16Buffer<ExternalTwoByteString, uint16_t> buffer;
int length = source->length();
buffer.Initialize(Handle<ExternalTwoByteString>::cast(source), 0, length);
return DoPreParse(&buffer, allow_lazy, recorder);
} else {
CharacterStreamUTF16Buffer buffer;
SafeStringInputBuffer input;
input.Reset(0, source.location());
int length = source->length();
buffer.Initialize(source, &input, 0, length);
return DoPreParse(&buffer, allow_lazy, recorder);
}
}
// Preparse, but only collect data that is immediately useful,
// even if the preparser data is only used once.
ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source,
unibrow::CharacterStream* stream,
v8::Extension* extension) {
Handle<Script> no_script;
bool allow_lazy = FLAG_lazy && (extension == NULL);
if (!allow_lazy) {
// Partial preparsing is only about lazily compiled functions.
@ -4703,7 +4676,8 @@ ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source,
}
PartialParserRecorder recorder;
return DoPreParse(source, stream, allow_lazy, &recorder);
return DoPreParse(source, stream, allow_lazy, &recorder,
JavaScriptScanner::kNoLiterals);
}
@ -4713,7 +4687,10 @@ ScriptDataImpl* ParserApi::PreParse(Handle<String> source,
Handle<Script> no_script;
bool allow_lazy = FLAG_lazy && (extension == NULL);
CompleteParserRecorder recorder;
return DoPreParse(source, stream, allow_lazy, &recorder);
int kPreParseLiteralsFlags =
JavaScriptScanner::kLiteralString | JavaScriptScanner::kLiteralIdentifier;
return DoPreParse(source, stream, allow_lazy,
&recorder, kPreParseLiteralsFlags);
}

16
deps/v8/src/parser.h

@ -181,6 +181,7 @@ class ScriptDataImpl : public ScriptData {
class PartialParserRecorder {
public:
PartialParserRecorder();
virtual ~PartialParserRecorder() {}
void LogFunction(int start, int end, int literals, int properties) {
function_store_.Add(start);
@ -189,7 +190,7 @@ class PartialParserRecorder {
function_store_.Add(properties);
}
void LogSymbol(int start, const char* symbol, int length) { }
virtual void LogSymbol(int start, const char* symbol, int length) { }
// Logs an error message and marks the log as containing an error.
// Further logging will be ignored, and ExtractData will return a vector
@ -212,7 +213,7 @@ class PartialParserRecorder {
const char* message,
Vector<const char*> args);
Vector<unsigned> ExtractData();
virtual Vector<unsigned> ExtractData();
void PauseRecording() {
pause_count_++;
@ -253,14 +254,15 @@ class PartialParserRecorder {
class CompleteParserRecorder: public PartialParserRecorder {
public:
CompleteParserRecorder();
virtual ~CompleteParserRecorder() { }
void LogSymbol(int start, Vector<const char> literal);
void LogSymbol(int start, const char* symbol, int length) {
virtual void LogSymbol(int start, const char* symbol, int length) {
LogSymbol(start, Vector<const char>(symbol, length));
}
Vector<unsigned> ExtractData();
virtual Vector<unsigned> ExtractData();
int symbol_position() { return symbol_store_.size(); }
int symbol_ids() { return symbol_id_; }
@ -682,7 +684,7 @@ class Parser {
Expression* ParseV8Intrinsic(bool* ok);
INLINE(Token::Value peek()) { return scanner_.peek(); }
INLINE(Token::Value Next()) { return scanner_.Next(); }
INLINE(Token::Value Next()) { return scanner_.NextCheckStack(); }
INLINE(void Consume(Token::Value token));
void Expect(Token::Value token, bool* ok);
bool Check(Token::Value token);
@ -760,7 +762,7 @@ class Parser {
ZoneList<Handle<String> > symbol_cache_;
Handle<Script> script_;
Scanner scanner_;
V8JavaScriptScanner scanner_;
Scope* top_scope_;
int with_nesting_level_;
@ -852,7 +854,7 @@ class JsonParser BASE_EMBEDDED {
// Converts the currently parsed literal to a JavaScript String.
Handle<String> GetString();
Scanner scanner_;
JsonScanner scanner_;
};
} } // namespace v8::internal

4
deps/v8/src/preparser.h

@ -720,7 +720,7 @@ Statement PreParser<Scanner, Log>::ParseThrowStatement(bool* ok) {
ReportMessageAt(pos.beg_pos, pos.end_pos,
"newline_after_throw", NULL);
*ok = false;
return NULL;
return kUnknownStatement;
}
ParseExpression(true, CHECK_OK);
ExpectSemicolon(CHECK_OK);
@ -1006,7 +1006,7 @@ Expression PreParser<Scanner, Log>::ParseMemberWithNewPrefixesExpression(
// ('[' Expression ']' | '.' Identifier | Arguments)*
// Parse the initial primary or function expression.
Expression result = NULL;
Expression result = kUnknownExpression;
if (peek() == i::Token::FUNCTION) {
Consume(i::Token::FUNCTION);
if (peek() == i::Token::IDENTIFIER) {

1098
deps/v8/src/prescanner.h

File diff suppressed because it is too large

43
deps/v8/src/profile-generator-inl.h

@ -105,24 +105,6 @@ void CodeMap::DeleteCode(Address addr) {
}
template<class Visitor>
void HeapEntriesMap::UpdateEntries(Visitor* visitor) {
for (HashMap::Entry* p = entries_.Start();
p != NULL;
p = entries_.Next(p)) {
if (!IsAlias(p->value)) {
EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value);
entry_info->entry = visitor->GetEntry(
reinterpret_cast<HeapObject*>(p->key),
entry_info->children_count,
entry_info->retainers_count);
entry_info->children_count = 0;
entry_info->retainers_count = 0;
}
}
}
CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
switch (tag) {
case GC:
@ -139,6 +121,31 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
}
}
inline uint64_t HeapEntry::id() {
union {
Id stored_id;
uint64_t returned_id;
} id_adaptor = {id_};
return id_adaptor.returned_id;
}
template<class Visitor>
void HeapEntriesMap::UpdateEntries(Visitor* visitor) {
for (HashMap::Entry* p = entries_.Start();
p != NULL;
p = entries_.Next(p)) {
EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value);
entry_info->entry = visitor->GetEntry(
reinterpret_cast<HeapObject*>(p->key),
entry_info->children_count,
entry_info->retainers_count);
entry_info->children_count = 0;
entry_info->retainers_count = 0;
}
}
} } // namespace v8::internal
#endif // ENABLE_LOGGING_AND_PROFILING

742
deps/v8/src/profile-generator.cc

File diff suppressed because it is too large

181
deps/v8/src/profile-generator.h

@ -439,22 +439,26 @@ class HeapGraphEdge BASE_EMBEDDED {
kContextVariable = v8::HeapGraphEdge::kContextVariable,
kElement = v8::HeapGraphEdge::kElement,
kProperty = v8::HeapGraphEdge::kProperty,
kInternal = v8::HeapGraphEdge::kInternal
kInternal = v8::HeapGraphEdge::kInternal,
kHidden = v8::HeapGraphEdge::kHidden,
kShortcut = v8::HeapGraphEdge::kShortcut
};
HeapGraphEdge() { }
void Init(int child_index, Type type, const char* name, HeapEntry* to);
void Init(int child_index, Type type, int index, HeapEntry* to);
void Init(int child_index, int index, HeapEntry* to);
Type type() { return static_cast<Type>(type_); }
int index() {
ASSERT(type_ == kElement);
ASSERT(type_ == kElement || type_ == kHidden);
return index_;
}
const char* name() {
ASSERT(type_ == kContextVariable
|| type_ == kProperty
|| type_ == kInternal);
|| type_ == kInternal
|| type_ == kShortcut);
return name_;
}
HeapEntry* to() { return to_; }
@ -462,8 +466,8 @@ class HeapGraphEdge BASE_EMBEDDED {
HeapEntry* From();
private:
int child_index_ : 30;
unsigned type_ : 2;
int child_index_ : 29;
unsigned type_ : 3;
union {
int index_;
const char* name_;
@ -500,7 +504,7 @@ class HeapSnapshot;
class HeapEntry BASE_EMBEDDED {
public:
enum Type {
kInternal = v8::HeapGraphNode::kInternal,
kHidden = v8::HeapGraphNode::kHidden,
kArray = v8::HeapGraphNode::kArray,
kString = v8::HeapGraphNode::kString,
kObject = v8::HeapGraphNode::kObject,
@ -522,14 +526,21 @@ class HeapEntry BASE_EMBEDDED {
HeapSnapshot* snapshot() { return snapshot_; }
Type type() { return static_cast<Type>(type_); }
const char* name() { return name_; }
uint64_t id() { return id_; }
uint64_t id();
int self_size() { return self_size_; }
int retained_size() { return retained_size_; }
void add_retained_size(int size) { retained_size_ += size; }
void set_retained_size(int value) { retained_size_ = value; }
int ordered_index() { return ordered_index_; }
void set_ordered_index(int value) { ordered_index_ = value; }
Vector<HeapGraphEdge> children() {
return Vector<HeapGraphEdge>(children_arr(), children_count_); }
Vector<HeapGraphEdge*> retainers() {
return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); }
List<HeapGraphPath*>* GetRetainingPaths();
HeapEntry* dominator() { return dominator_; }
void set_dominator(HeapEntry* entry) { dominator_ = entry; }
void clear_paint() { painted_ = kUnpainted; }
bool painted_reachable() { return painted_ == kPainted; }
@ -547,8 +558,18 @@ class HeapEntry BASE_EMBEDDED {
void ApplyAndPaintAllReachable(Visitor* visitor);
void PaintAllReachable();
void SetElementReference(
int child_index, int index, HeapEntry* entry, int retainer_index);
bool is_leaf() { return painted_ == kLeaf; }
void set_leaf() { painted_ = kLeaf; }
bool is_non_leaf() { return painted_ == kNonLeaf; }
void set_non_leaf() { painted_ = kNonLeaf; }
bool is_processed() { return painted_ == kProcessed; }
void set_processed() { painted_ = kProcessed; }
void SetIndexedReference(HeapGraphEdge::Type type,
int child_index,
int index,
HeapEntry* entry,
int retainer_index);
void SetNamedReference(HeapGraphEdge::Type type,
int child_index,
const char* name,
@ -557,14 +578,19 @@ class HeapEntry BASE_EMBEDDED {
void SetUnidirElementReference(int child_index, int index, HeapEntry* entry);
int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); }
int ReachableSize();
int RetainedSize();
int RetainedSize(bool exact);
List<HeapGraphPath*>* CalculateRetainingPaths();
void Print(int max_depth, int indent);
static int EntriesSize(int entries_count,
int children_count,
int retainers_count);
static uint32_t Hash(HeapEntry* entry) {
return ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(entry)));
}
static bool Match(void* entry1, void* entry2) { return entry1 == entry2; }
private:
HeapGraphEdge* children_arr() {
@ -573,53 +599,40 @@ class HeapEntry BASE_EMBEDDED {
HeapGraphEdge** retainers_arr() {
return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
}
void CalculateExactRetainedSize();
void FindRetainingPaths(CachedHeapGraphPath* prev_path,
List<HeapGraphPath*>* retaining_paths);
const char* TypeAsString();
unsigned painted_: 2;
unsigned type_: 3;
// The calculated data is stored in HeapSnapshot in HeapEntryCalculatedData
// entries. See AddCalculatedData and GetCalculatedData.
int calculated_data_index_: 27;
int self_size_;
int children_count_;
int children_count_: 27;
int retainers_count_;
int self_size_;
union {
int ordered_index_; // Used during dominator tree building.
int retained_size_; // At that moment, there is no retained size yet.
};
HeapEntry* dominator_;
HeapSnapshot* snapshot_;
struct Id {
uint32_t id1_;
uint32_t id2_;
} id_; // This is to avoid extra padding of 64-bit value.
const char* name_;
uint64_t id_;
// Paints used for exact retained sizes calculation.
static const unsigned kUnpainted = 0;
static const unsigned kPainted = 1;
static const unsigned kPaintedReachableFromOthers = 2;
static const int kNoCalculatedData = -1;
DISALLOW_COPY_AND_ASSIGN(HeapEntry);
};
class HeapEntryCalculatedData {
public:
HeapEntryCalculatedData()
: retaining_paths_(NULL),
reachable_size_(kUnknownSize),
retained_size_(kUnknownSize) {
}
void Dispose();
List<HeapGraphPath*>* GetRetainingPaths(HeapEntry* entry);
int ReachableSize(HeapEntry* entry);
int RetainedSize(HeapEntry* entry);
private:
void CalculateSizes(HeapEntry* entry);
void FindRetainingPaths(HeapEntry* entry, CachedHeapGraphPath* prev_path);
List<HeapGraphPath*>* retaining_paths_;
int reachable_size_;
int retained_size_;
// Paints used for approximate retained sizes calculation.
static const unsigned kLeaf = 0;
static const unsigned kNonLeaf = 1;
static const unsigned kProcessed = 2;
static const int kUnknownSize = -1;
static const int kExactRetainedSizeTag = 1;
// Allow generated copy constructor and assignment operator.
DISALLOW_COPY_AND_ASSIGN(HeapEntry);
};
@ -668,24 +681,22 @@ class HeapSnapshot {
const char* title() { return title_; }
unsigned uid() { return uid_; }
HeapEntry* root() { return root_entry_; }
HeapEntry* gc_roots() { return gc_roots_entry_; }
void AllocateEntries(
int entries_count, int children_count, int retainers_count);
HeapEntry* AddEntry(
HeapObject* object, int children_count, int retainers_count);
bool WillAddEntry(HeapObject* object);
HeapEntry* AddEntry(HeapEntry::Type type,
const char* name,
uint64_t id,
int size,
int children_count,
int retainers_count);
int AddCalculatedData();
HeapEntryCalculatedData& GetCalculatedData(int index) {
return calculated_data_[index];
}
void ApproximateRetainedSizes();
void ClearPaint();
HeapSnapshotsDiff* CompareWith(HeapSnapshot* snapshot);
List<HeapGraphPath*>* GetRetainingPaths(HeapEntry* entry);
List<HeapEntry*>* GetSortedEntriesList();
template<class Visitor>
void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); }
@ -694,6 +705,7 @@ class HeapSnapshot {
void PrintEntriesSize();
static HeapObject* const kInternalRootObject;
static HeapObject* const kGcRootsObject;
private:
HeapEntry* AddEntry(HeapObject* object,
@ -702,18 +714,21 @@ class HeapSnapshot {
int children_count,
int retainers_count);
HeapEntry* GetNextEntryToInit();
static int GetObjectSize(HeapObject* obj);
static int CalculateNetworkSize(JSObject* obj);
void BuildDominatorTree(const Vector<HeapEntry*>& entries,
Vector<HeapEntry*>* dominators);
void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
void SetEntriesDominators();
HeapSnapshotsCollection* collection_;
Type type_;
const char* title_;
unsigned uid_;
HeapEntry* root_entry_;
HeapEntry* gc_roots_entry_;
char* raw_entries_;
List<HeapEntry*> entries_;
bool entries_sorted_;
List<HeapEntryCalculatedData> calculated_data_;
HashMap retaining_paths_;
#ifdef DEBUG
int raw_entries_size_;
#endif
@ -733,6 +748,10 @@ class HeapObjectsMap {
uint64_t FindObject(Address addr);
void MoveObject(Address from, Address to);
static const uint64_t kInternalRootObjectId;
static const uint64_t kGcRootsObjectId;
static const uint64_t kFirstAvailableObjectId;
private:
struct EntryInfo {
explicit EntryInfo(uint64_t id) : id(id), accessed(true) { }
@ -868,9 +887,6 @@ class HeapEntriesMap {
HeapEntriesMap();
~HeapEntriesMap();
// Aliasing is used for skipping intermediate proxy objects, like
// JSGlobalPropertyCell.
void Alias(HeapObject* from, HeapObject* to);
HeapEntry* Map(HeapObject* object);
void Pair(HeapObject* object, HeapEntry* entry);
void CountReference(HeapObject* from, HeapObject* to,
@ -894,41 +910,45 @@ class HeapEntriesMap {
int retainers_count;
};
uint32_t Hash(HeapObject* object) {
static uint32_t Hash(HeapObject* object) {
return ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object)));
}
static bool HeapObjectsMatch(void* key1, void* key2) { return key1 == key2; }
bool IsAlias(void* ptr) {
return reinterpret_cast<intptr_t>(ptr) & kAliasTag;
}
void* MakeAlias(void* ptr) {
return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(ptr) | kAliasTag);
}
void* Unalias(void* ptr) {
return reinterpret_cast<void*>(
reinterpret_cast<intptr_t>(ptr) & (~kAliasTag));
}
HashMap entries_;
int entries_count_;
int total_children_count_;
int total_retainers_count_;
static const intptr_t kAliasTag = 1;
friend class HeapObjectsSet;
DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
};
class HeapObjectsSet {
public:
HeapObjectsSet();
void Clear();
bool Contains(Object* object);
void Insert(Object* obj);
private:
HashMap entries_;
DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
};
class HeapSnapshotGenerator {
public:
class SnapshotFillerInterface {
public:
virtual ~SnapshotFillerInterface() { }
virtual HeapEntry* AddEntry(HeapObject* obj) = 0;
virtual void SetElementReference(HeapObject* parent_obj,
virtual void SetIndexedReference(HeapGraphEdge::Type type,
HeapObject* parent_obj,
HeapEntry* parent_entry,
int index,
Object* child_obj,
@ -939,7 +959,10 @@ class HeapSnapshotGenerator {
const char* reference_name,
Object* child_obj,
HeapEntry* child_entry) = 0;
virtual void SetRootReference(Object* child_obj,
virtual void SetRootGcRootsReference() = 0;
virtual void SetRootShortcutReference(Object* child_obj,
HeapEntry* child_entry) = 0;
virtual void SetStrongRootReference(Object* child_obj,
HeapEntry* child_entry) = 0;
};
@ -969,19 +992,33 @@ class HeapSnapshotGenerator {
HeapEntry* parent,
int index,
Object* child);
void SetHiddenReference(HeapObject* parent_obj,
HeapEntry* parent,
int index,
Object* child);
void SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent,
String* reference_name,
Object* child);
void SetRootReference(Object* child);
void SetPropertyShortcutReference(HeapObject* parent_obj,
HeapEntry* parent,
String* reference_name,
Object* child);
void SetRootShortcutReference(Object* child);
void SetRootGcRootsReference();
void SetGcRootsReference(Object* child);
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
// Mapping from HeapObject* pointers to HeapEntry* pointers.
HeapEntriesMap entries_;
SnapshotFillerInterface* filler_;
// Used during references extraction to mark heap objects that
// are references via non-hidden properties.
HeapObjectsSet known_references_;
friend class IndexedReferencesExtractor;
friend class RootsReferencesExtractor;
DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
};

15
deps/v8/src/runtime.cc

@ -6340,15 +6340,20 @@ static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
static MaybeObject* Runtime_NewClosure(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 2);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(Context, context, 0);
CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
PretenureFlag pretenure = (context->global_context() == *context)
? TENURED // Allocate global closures in old space.
: NOT_TENURED; // Allocate local closures in new space.
// Allocate global closures in old space and allocate local closures
// in new space. Additionally pretenure closures that are assigned
// directly to properties.
pretenure = pretenure || (context->global_context() == *context);
PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
Handle<JSFunction> result =
Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure);
Factory::NewFunctionFromSharedFunctionInfo(shared,
context,
pretenure_flag);
return *result;
}

5
deps/v8/src/runtime.h

@ -262,7 +262,7 @@ namespace internal {
F(CreateCatchExtensionObject, 2, 1) \
\
/* Statements */ \
F(NewClosure, 2, 1) \
F(NewClosure, 3, 1) \
F(NewObject, 1, 1) \
F(NewObjectFromBound, 2, 1) \
F(FinalizeInstanceSize, 1, 1) \
@ -418,7 +418,8 @@ namespace internal {
F(MathSqrt, 1, 1) \
F(IsRegExpEquivalent, 2, 1) \
F(HasCachedArrayIndex, 1, 1) \
F(GetCachedArrayIndex, 1, 1)
F(GetCachedArrayIndex, 1, 1) \
F(FastAsciiArrayJoin, 2, 1)
// ----------------------------------------------------------------------------

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

@ -29,10 +29,39 @@
#include "../include/v8stdint.h"
#include "scanner-base.h"
#include "char-predicates-inl.h"
namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
// UTF16Buffer
UTF16Buffer::UTF16Buffer()
: pos_(0), end_(kNoEndPosition) { }
// ----------------------------------------------------------------------------
// LiteralCollector
LiteralCollector::LiteralCollector()
: buffer_(kInitialCapacity), recording_(false) { }
LiteralCollector::~LiteralCollector() {}
void LiteralCollector::AddCharSlow(uc32 c) {
ASSERT(static_cast<unsigned>(c) > unibrow::Utf8::kMaxOneByteChar);
int length = unibrow::Utf8::Length(c);
Vector<char> block = buffer_.AddBlock(length, '\0');
#ifdef DEBUG
int written_length = unibrow::Utf8::Encode(block.start(), c);
CHECK_EQ(length, written_length);
#else
unibrow::Utf8::Encode(block.start(), c);
#endif
}
// ----------------------------------------------------------------------------
// Character predicates
@ -60,6 +89,707 @@ bool ScannerConstants::IsIdentifier(unibrow::CharacterStream* buffer) {
return true;
}
// ----------------------------------------------------------------------------
// Scanner
Scanner::Scanner() : source_(NULL), stack_overflow_(false) {}
uc32 Scanner::ScanHexEscape(uc32 c, int length) {
ASSERT(length <= 4); // prevent overflow
uc32 digits[4];
uc32 x = 0;
for (int i = 0; i < length; i++) {
digits[i] = c0_;
int d = HexValue(c0_);
if (d < 0) {
// According to ECMA-262, 3rd, 7.8.4, page 18, these hex escapes
// should be illegal, but other JS VMs just return the
// non-escaped version of the original character.
// Push back digits read, except the last one (in c0_).
for (int j = i-1; j >= 0; j--) {
PushBack(digits[j]);
}
// Notice: No handling of error - treat it as "\u"->"u".
return c;
}
x = x * 16 + d;
Advance();
}
return x;
}
// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
// ECMA-262. Other JS VMs support them.
uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
uc32 x = c - '0';
for (int i = 0; i < length; i++) {
int d = c0_ - '0';
if (d < 0 || d > 7) break;
int nx = x * 8 + d;
if (nx >= 256) break;
x = nx;
Advance();
}
return x;
}
// ----------------------------------------------------------------------------
// JavaScriptScanner
JavaScriptScanner::JavaScriptScanner()
: has_line_terminator_before_next_(false) {}
Token::Value JavaScriptScanner::Next() {
current_ = next_;
has_line_terminator_before_next_ = false;
Scan();
return current_.token;
}
static inline bool IsByteOrderMark(uc32 c) {
// The Unicode value U+FFFE is guaranteed never to be assigned as a
// Unicode character; this implies that in a Unicode context the
// 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF
// character expressed in little-endian byte order (since it could
// not be a U+FFFE character expressed in big-endian byte
// order). Nevertheless, we check for it to be compatible with
// Spidermonkey.
return c == 0xFEFF || c == 0xFFFE;
}
bool JavaScriptScanner::SkipWhiteSpace() {
int start_position = source_pos();
while (true) {
// We treat byte-order marks (BOMs) as whitespace for better
// compatibility with Spidermonkey and other JavaScript engines.
while (ScannerConstants::kIsWhiteSpace.get(c0_) || IsByteOrderMark(c0_)) {
// IsWhiteSpace() includes line terminators!
if (ScannerConstants::kIsLineTerminator.get(c0_)) {
// Ignore line terminators, but remember them. This is necessary
// for automatic semicolon insertion.
has_line_terminator_before_next_ = true;
}
Advance();
}
// If there is an HTML comment end '-->' at the beginning of a
// line (with only whitespace in front of it), we treat the rest
// of the line as a comment. This is in line with the way
// SpiderMonkey handles it.
if (c0_ == '-' && has_line_terminator_before_next_) {
Advance();
if (c0_ == '-') {
Advance();
if (c0_ == '>') {
// Treat the rest of the line as a comment.
SkipSingleLineComment();
// Continue skipping white space after the comment.
continue;
}
PushBack('-'); // undo Advance()
}
PushBack('-'); // undo Advance()
}
// Return whether or not we skipped any characters.
return source_pos() != start_position;
}
}
Token::Value JavaScriptScanner::SkipSingleLineComment() {
Advance();
// The line terminator at the end of the line is not considered
// to be part of the single-line comment; it is recognized
// separately by the lexical grammar and becomes part of the
// stream of input elements for the syntactic grammar (see
// ECMA-262, section 7.4, page 12).
while (c0_ >= 0 && !ScannerConstants::kIsLineTerminator.get(c0_)) {
Advance();
}
return Token::WHITESPACE;
}
Token::Value JavaScriptScanner::SkipMultiLineComment() {
ASSERT(c0_ == '*');
Advance();
while (c0_ >= 0) {
char ch = c0_;
Advance();
// If we have reached the end of the multi-line comment, we
// consume the '/' and insert a whitespace. This way all
// multi-line comments are treated as whitespace - even the ones
// containing line terminators. This contradicts ECMA-262, section
// 7.4, page 12, that says that multi-line comments containing
// line terminators should be treated as a line terminator, but it
// matches the behaviour of SpiderMonkey and KJS.
if (ch == '*' && c0_ == '/') {
c0_ = ' ';
return Token::WHITESPACE;
}
}
// Unterminated multi-line comment.
return Token::ILLEGAL;
}
Token::Value JavaScriptScanner::ScanHtmlComment() {
// Check for <!-- comments.
ASSERT(c0_ == '!');
Advance();
if (c0_ == '-') {
Advance();
if (c0_ == '-') return SkipSingleLineComment();
PushBack('-'); // undo Advance()
}
PushBack('!'); // undo Advance()
ASSERT(c0_ == '!');
return Token::LT;
}
void JavaScriptScanner::Scan() {
next_.literal_chars = Vector<const char>();
Token::Value token;
do {
// Remember the position of the next token
next_.location.beg_pos = source_pos();
switch (c0_) {
case ' ':
case '\t':
Advance();
token = Token::WHITESPACE;
break;
case '\n':
Advance();
has_line_terminator_before_next_ = true;
token = Token::WHITESPACE;
break;
case '"': case '\'':
token = ScanString();
break;
case '<':
// < <= << <<= <!--
Advance();
if (c0_ == '=') {
token = Select(Token::LTE);
} else if (c0_ == '<') {
token = Select('=', Token::ASSIGN_SHL, Token::SHL);
} else if (c0_ == '!') {
token = ScanHtmlComment();
} else {
token = Token::LT;
}
break;
case '>':
// > >= >> >>= >>> >>>=
Advance();
if (c0_ == '=') {
token = Select(Token::GTE);
} else if (c0_ == '>') {
// >> >>= >>> >>>=
Advance();
if (c0_ == '=') {
token = Select(Token::ASSIGN_SAR);
} else if (c0_ == '>') {
token = Select('=', Token::ASSIGN_SHR, Token::SHR);
} else {
token = Token::SAR;
}
} else {
token = Token::GT;
}
break;
case '=':
// = == ===
Advance();
if (c0_ == '=') {
token = Select('=', Token::EQ_STRICT, Token::EQ);
} else {
token = Token::ASSIGN;
}
break;
case '!':
// ! != !==
Advance();
if (c0_ == '=') {
token = Select('=', Token::NE_STRICT, Token::NE);
} else {
token = Token::NOT;
}
break;
case '+':
// + ++ +=
Advance();
if (c0_ == '+') {
token = Select(Token::INC);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_ADD);
} else {
token = Token::ADD;
}
break;
case '-':
// - -- --> -=
Advance();
if (c0_ == '-') {
Advance();
if (c0_ == '>' && has_line_terminator_before_next_) {
// For compatibility with SpiderMonkey, we skip lines that
// start with an HTML comment end '-->'.
token = SkipSingleLineComment();
} else {
token = Token::DEC;
}
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_SUB);
} else {
token = Token::SUB;
}
break;
case '*':
// * *=
token = Select('=', Token::ASSIGN_MUL, Token::MUL);
break;
case '%':
// % %=
token = Select('=', Token::ASSIGN_MOD, Token::MOD);
break;
case '/':
// / // /* /=
Advance();
if (c0_ == '/') {
token = SkipSingleLineComment();
} else if (c0_ == '*') {
token = SkipMultiLineComment();
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_DIV);
} else {
token = Token::DIV;
}
break;
case '&':
// & && &=
Advance();
if (c0_ == '&') {
token = Select(Token::AND);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_BIT_AND);
} else {
token = Token::BIT_AND;
}
break;
case '|':
// | || |=
Advance();
if (c0_ == '|') {
token = Select(Token::OR);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_BIT_OR);
} else {
token = Token::BIT_OR;
}
break;
case '^':
// ^ ^=
token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
break;
case '.':
// . Number
Advance();
if (IsDecimalDigit(c0_)) {
token = ScanNumber(true);
} else {
token = Token::PERIOD;
}
break;
case ':':
token = Select(Token::COLON);
break;
case ';':
token = Select(Token::SEMICOLON);
break;
case ',':
token = Select(Token::COMMA);
break;
case '(':
token = Select(Token::LPAREN);
break;
case ')':
token = Select(Token::RPAREN);
break;
case '[':
token = Select(Token::LBRACK);
break;
case ']':
token = Select(Token::RBRACK);
break;
case '{':
token = Select(Token::LBRACE);
break;
case '}':
token = Select(Token::RBRACE);
break;
case '?':
token = Select(Token::CONDITIONAL);
break;
case '~':
token = Select(Token::BIT_NOT);
break;
default:
if (ScannerConstants::kIsIdentifierStart.get(c0_)) {
token = ScanIdentifierOrKeyword();
} else if (IsDecimalDigit(c0_)) {
token = ScanNumber(false);
} else if (SkipWhiteSpace()) {
token = Token::WHITESPACE;
} else if (c0_ < 0) {
token = Token::EOS;
} else {
token = Select(Token::ILLEGAL);
}
break;
}
// Continue scanning for tokens as long as we're just skipping
// whitespace.
} while (token == Token::WHITESPACE);
next_.location.end_pos = source_pos();
next_.token = token;
}
void JavaScriptScanner::SeekForward(int pos) {
source_->SeekForward(pos - 1);
Advance();
// This function is only called to seek to the location
// of the end of a function (at the "}" token). It doesn't matter
// whether there was a line terminator in the part we skip.
has_line_terminator_before_next_ = false;
Scan();
}
void JavaScriptScanner::ScanEscape() {
uc32 c = c0_;
Advance();
// Skip escaped newlines.
if (ScannerConstants::kIsLineTerminator.get(c)) {
// Allow CR+LF newlines in multiline string literals.
if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
// Allow LF+CR newlines in multiline string literals.
if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance();
return;
}
switch (c) {
case '\'': // fall through
case '"' : // fall through
case '\\': break;
case 'b' : c = '\b'; break;
case 'f' : c = '\f'; break;
case 'n' : c = '\n'; break;
case 'r' : c = '\r'; break;
case 't' : c = '\t'; break;
case 'u' : c = ScanHexEscape(c, 4); break;
case 'v' : c = '\v'; break;
case 'x' : c = ScanHexEscape(c, 2); break;
case '0' : // fall through
case '1' : // fall through
case '2' : // fall through
case '3' : // fall through
case '4' : // fall through
case '5' : // fall through
case '6' : // fall through
case '7' : c = ScanOctalEscape(c, 2); break;
}
// According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
// should be illegal, but they are commonly handled
// as non-escaped characters by JS VMs.
AddLiteralChar(c);
}
Token::Value JavaScriptScanner::ScanString() {
uc32 quote = c0_;
Advance(); // consume quote
LiteralScope literal(this, kLiteralString);
while (c0_ != quote && c0_ >= 0
&& !ScannerConstants::kIsLineTerminator.get(c0_)) {
uc32 c = c0_;
Advance();
if (c == '\\') {
if (c0_ < 0) return Token::ILLEGAL;
ScanEscape();
} else {
AddLiteralChar(c);
}
}
if (c0_ != quote) return Token::ILLEGAL;
literal.Complete();
Advance(); // consume quote
return Token::STRING;
}
void JavaScriptScanner::ScanDecimalDigits() {
while (IsDecimalDigit(c0_))
AddLiteralCharAdvance();
}
Token::Value JavaScriptScanner::ScanNumber(bool seen_period) {
ASSERT(IsDecimalDigit(c0_)); // the first digit of the number or the fraction
enum { DECIMAL, HEX, OCTAL } kind = DECIMAL;
LiteralScope literal(this, kLiteralNumber);
if (seen_period) {
// we have already seen a decimal point of the float
AddLiteralChar('.');
ScanDecimalDigits(); // we know we have at least one digit
} else {
// if the first character is '0' we must check for octals and hex
if (c0_ == '0') {
AddLiteralCharAdvance();
// either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
if (c0_ == 'x' || c0_ == 'X') {
// hex number
kind = HEX;
AddLiteralCharAdvance();
if (!IsHexDigit(c0_)) {
// we must have at least one hex digit after 'x'/'X'
return Token::ILLEGAL;
}
while (IsHexDigit(c0_)) {
AddLiteralCharAdvance();
}
} else if ('0' <= c0_ && c0_ <= '7') {
// (possible) octal number
kind = OCTAL;
while (true) {
if (c0_ == '8' || c0_ == '9') {
kind = DECIMAL;
break;
}
if (c0_ < '0' || '7' < c0_) break;
AddLiteralCharAdvance();
}
}
}
// Parse decimal digits and allow trailing fractional part.
if (kind == DECIMAL) {
ScanDecimalDigits(); // optional
if (c0_ == '.') {
AddLiteralCharAdvance();
ScanDecimalDigits(); // optional
}
}
}
// scan exponent, if any
if (c0_ == 'e' || c0_ == 'E') {
ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
if (kind == OCTAL) return Token::ILLEGAL; // no exponent for octals allowed
// scan exponent
AddLiteralCharAdvance();
if (c0_ == '+' || c0_ == '-')
AddLiteralCharAdvance();
if (!IsDecimalDigit(c0_)) {
// we must have at least one decimal digit after 'e'/'E'
return Token::ILLEGAL;
}
ScanDecimalDigits();
}
// The source character immediately following a numeric literal must
// not be an identifier start or a decimal digit; see ECMA-262
// section 7.8.3, page 17 (note that we read only one decimal digit
// if the value is 0).
if (IsDecimalDigit(c0_) || ScannerConstants::kIsIdentifierStart.get(c0_))
return Token::ILLEGAL;
literal.Complete();
return Token::NUMBER;
}
uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() {
Advance();
if (c0_ != 'u') return unibrow::Utf8::kBadChar;
Advance();
uc32 c = ScanHexEscape('u', 4);
// We do not allow a unicode escape sequence to start another
// unicode escape sequence.
if (c == '\\') return unibrow::Utf8::kBadChar;
return c;
}
Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
ASSERT(ScannerConstants::kIsIdentifierStart.get(c0_));
LiteralScope literal(this, kLiteralIdentifier);
KeywordMatcher keyword_match;
// Scan identifier start character.
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier start characters.
if (!ScannerConstants::kIsIdentifierStart.get(c)) return Token::ILLEGAL;
AddLiteralChar(c);
return ScanIdentifierSuffix(&literal);
}
uc32 first_char = c0_;
Advance();
AddLiteralChar(first_char);
if (!keyword_match.AddChar(first_char)) {
return ScanIdentifierSuffix(&literal);
}
// Scan the rest of the identifier characters.
while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
if (c0_ != '\\') {
uc32 next_char = c0_;
Advance();
AddLiteralChar(next_char);
if (keyword_match.AddChar(next_char)) continue;
}
// Fallthrough if no loner able to complete keyword.
return ScanIdentifierSuffix(&literal);
}
literal.Complete();
return keyword_match.token();
}
Token::Value JavaScriptScanner::ScanIdentifierSuffix(LiteralScope* literal) {
// Scan the rest of the identifier characters.
while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier part characters.
if (!ScannerConstants::kIsIdentifierPart.get(c)) return Token::ILLEGAL;
AddLiteralChar(c);
} else {
AddLiteralChar(c0_);
Advance();
}
}
literal->Complete();
return Token::IDENTIFIER;
}
bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
// Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
bool in_character_class = false;
// Previous token is either '/' or '/=', in the second case, the
// pattern starts at =.
next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1);
next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0);
// Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
// the scanner should pass uninterpreted bodies to the RegExp
// constructor.
LiteralScope literal(this, kLiteralRegExp);
if (seen_equal)
AddLiteralChar('=');
while (c0_ != '/' || in_character_class) {
if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
if (c0_ == '\\') { // escaped character
AddLiteralCharAdvance();
if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
AddLiteralCharAdvance();
} else { // unescaped character
if (c0_ == '[') in_character_class = true;
if (c0_ == ']') in_character_class = false;
AddLiteralCharAdvance();
}
}
Advance(); // consume '/'
literal.Complete();
return true;
}
bool JavaScriptScanner::ScanRegExpFlags() {
// Scan regular expression flags.
LiteralScope literal(this, kLiteralRegExpFlags);
while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
if (c != static_cast<uc32>(unibrow::Utf8::kBadChar)) {
// We allow any escaped character, unlike the restriction on
// IdentifierPart when it is used to build an IdentifierName.
AddLiteralChar(c);
continue;
}
}
AddLiteralCharAdvance();
}
literal.Complete();
next_.location.end_pos = source_pos() - 1;
return true;
}
// ----------------------------------------------------------------------------
// Keyword Matcher
@ -155,9 +885,7 @@ void KeywordMatcher::Step(unibrow::uchar input) {
break;
case IN:
token_ = Token::IDENTIFIER;
if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) {
return;
}
if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) return;
break;
case N:
if (MatchKeywordStart(input, "native", 1, Token::NATIVE)) return;

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

@ -37,11 +37,24 @@
#include "unicode-inl.h"
#include "char-predicates.h"
#include "utils.h"
#include "list-inl.h"
namespace v8 {
namespace internal {
// Interface through which the scanner reads characters from the input source.
// Returns the value (0 .. 15) of a hexadecimal character c.
// If c is not a legal hexadecimal character, returns a value < 0.
inline int HexValue(uc32 c) {
c -= '0';
if (static_cast<unsigned>(c) <= 9) return c;
c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36.
if (static_cast<unsigned>(c) <= 5) return c + 10;
return -1;
}
// ----------------------------------------------------------------------------
// UTF16Buffer - scanner input source with pushback.
class UTF16Buffer {
public:
UTF16Buffer();
@ -54,7 +67,11 @@ class UTF16Buffer {
int pos() const { return pos_; }
static const int kNoEndPosition = 1;
protected:
// Initial value of end_ before the input stream is initialized.
int pos_; // Current position in the buffer.
int end_; // Position where scanning should stop (EOF).
};
@ -79,6 +96,335 @@ class ScannerConstants : AllStatic {
static StaticResource<Utf8Decoder> utf8_decoder_;
};
// ----------------------------------------------------------------------------
// LiteralCollector - Collector of chars of literals.
class LiteralCollector {
public:
LiteralCollector();
~LiteralCollector();
inline void AddChar(uc32 c) {
if (recording_) {
if (static_cast<unsigned>(c) <= unibrow::Utf8::kMaxOneByteChar) {
buffer_.Add(static_cast<char>(c));
} else {
AddCharSlow(c);
}
}
}
void StartLiteral() {
buffer_.StartSequence();
recording_ = true;
}
Vector<const char> EndLiteral() {
if (recording_) {
recording_ = false;
buffer_.Add(kEndMarker);
Vector<char> sequence = buffer_.EndSequence();
return Vector<const char>(sequence.start(), sequence.length());
}
return Vector<const char>();
}
void DropLiteral() {
if (recording_) {
recording_ = false;
buffer_.DropSequence();
}
}
void Reset() {
buffer_.Reset();
}
// The end marker added after a parsed literal.
// Using zero allows the usage of strlen and similar functions on
// identifiers and numbers (but not strings, since they may contain zero
// bytes).
static const char kEndMarker = '\x00';
private:
static const int kInitialCapacity = 256;
SequenceCollector<char, 4> buffer_;
bool recording_;
void AddCharSlow(uc32 c);
};
// ----------------------------------------------------------------------------
// Scanner base-class.
// Generic functionality used by both JSON and JavaScript scanners.
class Scanner {
public:
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
class LiteralScope {
public:
explicit LiteralScope(Scanner* self);
~LiteralScope();
void Complete();
private:
Scanner* scanner_;
bool complete_;
};
Scanner();
// Returns the current token again.
Token::Value current_token() { return current_.token; }
// One token look-ahead (past the token returned by Next()).
Token::Value peek() const { return next_.token; }
struct Location {
Location(int b, int e) : beg_pos(b), end_pos(e) { }
Location() : beg_pos(0), end_pos(0) { }
int beg_pos;
int end_pos;
};
// Returns the location information for the current token
// (the token returned by Next()).
Location location() const { return current_.location; }
Location peek_location() const { return next_.location; }
// Returns the literal string, if any, for the current token (the
// token returned by Next()). The string is 0-terminated and in
// UTF-8 format; they may contain 0-characters. Literal strings are
// collected for identifiers, strings, and numbers.
// These functions only give the correct result if the literal
// was scanned between calls to StartLiteral() and TerminateLiteral().
const char* literal_string() const {
return current_.literal_chars.start();
}
int literal_length() const {
// Excluding terminal '\x00' added by TerminateLiteral().
return current_.literal_chars.length() - 1;
}
Vector<const char> literal() const {
return Vector<const char>(literal_string(), literal_length());
}
// Returns the literal string for the next token (the token that
// would be returned if Next() were called).
const char* next_literal_string() const {
return next_.literal_chars.start();
}
// Returns the length of the next token (that would be returned if
// Next() were called).
int next_literal_length() const {
// Excluding terminal '\x00' added by TerminateLiteral().
return next_.literal_chars.length() - 1;
}
Vector<const char> next_literal() const {
return Vector<const char>(next_literal_string(), next_literal_length());
}
bool stack_overflow() { return stack_overflow_; }
static const int kCharacterLookaheadBufferSize = 1;
protected:
// The current and look-ahead token.
struct TokenDesc {
Token::Value token;
Location location;
Vector<const char> literal_chars;
};
// Call this after setting source_ to the input.
void Init() {
// Set c0_ (one character ahead)
ASSERT(kCharacterLookaheadBufferSize == 1);
Advance();
// Initialize current_ to not refer to a literal.
current_.literal_chars = Vector<const char>();
// Reset literal buffer.
literal_buffer_.Reset();
}
// Literal buffer support
inline void StartLiteral() {
literal_buffer_.StartLiteral();
}
inline void AddLiteralChar(uc32 c) {
literal_buffer_.AddChar(c);
}
// Complete scanning of a literal.
inline void TerminateLiteral() {
next_.literal_chars = literal_buffer_.EndLiteral();
}
// Stops scanning of a literal and drop the collected characters,
// e.g., due to an encountered error.
inline void DropLiteral() {
literal_buffer_.DropLiteral();
}
inline void AddLiteralCharAdvance() {
AddLiteralChar(c0_);
Advance();
}
// Low-level scanning support.
void Advance() { c0_ = source_->Advance(); }
void PushBack(uc32 ch) {
source_->PushBack(ch);
c0_ = ch;
}
inline Token::Value Select(Token::Value tok) {
Advance();
return tok;
}
inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) {
Advance();
if (c0_ == next) {
Advance();
return then;
} else {
return else_;
}
}
uc32 ScanHexEscape(uc32 c, int length);
uc32 ScanOctalEscape(uc32 c, int length);
// Return the current source position.
int source_pos() {
return source_->pos() - kCharacterLookaheadBufferSize;
}
TokenDesc current_; // desc for current token (as returned by Next())
TokenDesc next_; // desc for next token (one token look-ahead)
// Input stream. Must be initialized to an UTF16Buffer.
UTF16Buffer* source_;
// Buffer to hold literal values (identifiers, strings, numbers)
// using '\x00'-terminated UTF-8 encoding. Handles allocation internally.
LiteralCollector literal_buffer_;
bool stack_overflow_;
// One Unicode character look-ahead; c0_ < 0 at the end of the input.
uc32 c0_;
};
// ----------------------------------------------------------------------------
// JavaScriptScanner - base logic for JavaScript scanning.
class JavaScriptScanner : public Scanner {
public:
// Bit vector representing set of types of literals.
enum LiteralType {
kNoLiterals = 0,
kLiteralNumber = 1,
kLiteralIdentifier = 2,
kLiteralString = 4,
kLiteralRegExp = 8,
kLiteralRegExpFlags = 16,
kAllLiterals = 31
};
// A LiteralScope that disables recording of some types of JavaScript
// literals. If the scanner is configured to not record the specific
// type of literal, the scope will not call StartLiteral.
class LiteralScope {
public:
LiteralScope(JavaScriptScanner* self, LiteralType type)
: scanner_(self), complete_(false) {
if (scanner_->RecordsLiteral(type)) {
scanner_->StartLiteral();
}
}
~LiteralScope() {
if (!complete_) scanner_->DropLiteral();
}
void Complete() {
scanner_->TerminateLiteral();
complete_ = true;
}
private:
JavaScriptScanner* scanner_;
bool complete_;
};
JavaScriptScanner();
// Returns the next token.
Token::Value Next();
// Returns true if there was a line terminator before the peek'ed token.
bool has_line_terminator_before_next() const {
return has_line_terminator_before_next_;
}
// Scans the input as a regular expression pattern, previous
// character(s) must be /(=). Returns true if a pattern is scanned.
bool ScanRegExpPattern(bool seen_equal);
// Returns true if regexp flags are scanned (always since flags can
// be empty).
bool ScanRegExpFlags();
// Tells whether the buffer contains an identifier (no escapes).
// Used for checking if a property name is an identifier.
static bool IsIdentifier(unibrow::CharacterStream* buffer);
// Seek forward to the given position. This operation does not
// work in general, for instance when there are pushed back
// characters, but works for seeking forward until simple delimiter
// tokens, which is what it is used for.
void SeekForward(int pos);
// Whether this scanner records the given literal type or not.
bool RecordsLiteral(LiteralType type) {
return (literal_flags_ & type) != 0;
}
protected:
bool SkipWhiteSpace();
Token::Value SkipSingleLineComment();
Token::Value SkipMultiLineComment();
// Scans a single JavaScript token.
void Scan();
void ScanDecimalDigits();
Token::Value ScanNumber(bool seen_period);
Token::Value ScanIdentifierOrKeyword();
Token::Value ScanIdentifierSuffix(LiteralScope* literal);
void ScanEscape();
Token::Value ScanString();
// Scans a possible HTML comment -- begins with '<!'.
Token::Value ScanHtmlComment();
// Decodes a unicode escape-sequence which is part of an identifier.
// If the escape sequence cannot be decoded the result is kBadChar.
uc32 ScanIdentifierUnicodeEscape();
int literal_flags_;
bool has_line_terminator_before_next_;
};
// ----------------------------------------------------------------------------
// Keyword matching state machine.
class KeywordMatcher {
// Incrementally recognize keywords.
@ -101,10 +447,11 @@ class KeywordMatcher {
Token::Value token() { return token_; }
inline void AddChar(unibrow::uchar input) {
inline bool AddChar(unibrow::uchar input) {
if (state_ != UNMATCHABLE) {
Step(input);
}
return state_ != UNMATCHABLE;
}
void Fail() {
@ -155,24 +502,24 @@ class KeywordMatcher {
const char* keyword,
int position,
Token::Value token_if_match) {
if (input == static_cast<unibrow::uchar>(keyword[position])) {
if (input != static_cast<unibrow::uchar>(keyword[position])) {
return false;
}
state_ = KEYWORD_PREFIX;
this->keyword_ = keyword;
this->counter_ = position + 1;
this->keyword_token_ = token_if_match;
return true;
}
return false;
}
// If input equals match character, transition to new state and return true.
inline bool MatchState(unibrow::uchar input, char match, State new_state) {
if (input == static_cast<unibrow::uchar>(match)) {
if (input != static_cast<unibrow::uchar>(match)) {
return false;
}
state_ = new_state;
return true;
}
return false;
}
inline bool MatchKeyword(unibrow::uchar input,
char match,

860
deps/v8/src/scanner.cc

@ -35,36 +35,9 @@
namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
// UTF8Buffer
UTF8Buffer::UTF8Buffer() : buffer_(kInitialCapacity), recording_(false) { }
UTF8Buffer::~UTF8Buffer() {}
void UTF8Buffer::AddCharSlow(uc32 c) {
ASSERT(static_cast<unsigned>(c) > unibrow::Utf8::kMaxOneByteChar);
int length = unibrow::Utf8::Length(c);
Vector<char> block = buffer_.AddBlock(length, '\0');
#ifdef DEBUG
int written_length = unibrow::Utf8::Encode(block.start(), c);
CHECK_EQ(length, written_length);
#else
unibrow::Utf8::Encode(block.start(), c);
#endif
}
// ----------------------------------------------------------------------------
// UTF16Buffer
UTF16Buffer::UTF16Buffer()
: pos_(0), end_(Scanner::kNoEndPosition) { }
// CharacterStreamUTF16Buffer
CharacterStreamUTF16Buffer::CharacterStreamUTF16Buffer()
: pushback_buffer_(0), last_(0), stream_(NULL) { }
@ -78,7 +51,7 @@ void CharacterStreamUTF16Buffer::Initialize(Handle<String> data,
if (start_position > 0) {
SeekForward(start_position);
}
end_ = end_position != Scanner::kNoEndPosition ? end_position : kMaxInt;
end_ = end_position != kNoEndPosition ? end_position : kMaxInt;
}
@ -90,7 +63,7 @@ void CharacterStreamUTF16Buffer::PushBack(uc32 ch) {
uc32 CharacterStreamUTF16Buffer::Advance() {
ASSERT(end_ != Scanner::kNoEndPosition);
ASSERT(end_ != kNoEndPosition);
ASSERT(end_ >= 0);
// NOTE: It is of importance to Persian / Farsi resources that we do
// *not* strip format control characters in the scanner; see
@ -143,41 +116,74 @@ void Scanner::LiteralScope::Complete() {
}
// ----------------------------------------------------------------------------
// Scanner
Scanner::Scanner()
: has_line_terminator_before_next_(false),
is_parsing_json_(false),
source_(NULL),
stack_overflow_(false) {}
void Scanner::Initialize(Handle<String> source,
ParserLanguage language) {
Init(source, NULL, 0, source->length(), language);
// V8JavaScriptScanner
void V8JavaScriptScanner::Initialize(Handle<String> source,
int literal_flags) {
source_ = stream_initializer_.Init(source, NULL, 0, source->length());
// Need to capture identifiers in order to recognize "get" and "set"
// in object literals.
literal_flags_ = literal_flags | kLiteralIdentifier;
Init();
// Skip initial whitespace allowing HTML comment ends just like
// after a newline and scan first token.
has_line_terminator_before_next_ = true;
SkipWhiteSpace();
Scan();
}
void Scanner::Initialize(Handle<String> source,
void V8JavaScriptScanner::Initialize(Handle<String> source,
unibrow::CharacterStream* stream,
ParserLanguage language) {
Init(source, stream, 0, kNoEndPosition, language);
int literal_flags) {
source_ = stream_initializer_.Init(source, stream,
0, UTF16Buffer::kNoEndPosition);
literal_flags_ = literal_flags | kLiteralIdentifier;
Init();
// Skip initial whitespace allowing HTML comment ends just like
// after a newline and scan first token.
has_line_terminator_before_next_ = true;
SkipWhiteSpace();
Scan();
}
void Scanner::Initialize(Handle<String> source,
void V8JavaScriptScanner::Initialize(Handle<String> source,
int start_position,
int end_position,
ParserLanguage language) {
Init(source, NULL, start_position, end_position, language);
int literal_flags) {
source_ = stream_initializer_.Init(source, NULL,
start_position, end_position);
literal_flags_ = literal_flags | kLiteralIdentifier;
Init();
// Skip initial whitespace allowing HTML comment ends just like
// after a newline and scan first token.
has_line_terminator_before_next_ = true;
SkipWhiteSpace();
Scan();
}
Token::Value V8JavaScriptScanner::NextCheckStack() {
// BUG 1215673: Find a thread safe way to set a stack limit in
// pre-parse mode. Otherwise, we cannot safely pre-parse from other
// threads.
StackLimitCheck check;
if (check.HasOverflowed()) {
stack_overflow_ = true;
current_ = next_;
next_.token = Token::ILLEGAL;
return current_.token;
} else {
return Next();
}
}
void Scanner::Init(Handle<String> source,
UTF16Buffer* StreamInitializer::Init(Handle<String> source,
unibrow::CharacterStream* stream,
int start_position,
int end_position,
ParserLanguage language) {
int end_position) {
// Either initialize the scanner from a character stream or from a
// string.
ASSERT(source.is_null() || stream == NULL);
@ -188,13 +194,13 @@ void Scanner::Init(Handle<String> source,
Handle<ExternalTwoByteString>::cast(source),
start_position,
end_position);
source_ = &two_byte_string_buffer_;
return &two_byte_string_buffer_;
} else if (!source.is_null() && StringShape(*source).IsExternalAscii()) {
ascii_string_buffer_.Initialize(
Handle<ExternalAsciiString>::cast(source),
start_position,
end_position);
source_ = &ascii_string_buffer_;
return &ascii_string_buffer_;
} else {
if (!source.is_null()) {
safe_string_input_buffer_.Reset(source.location());
@ -204,28 +210,27 @@ void Scanner::Init(Handle<String> source,
stream,
start_position,
end_position);
source_ = &char_stream_buffer_;
return &char_stream_buffer_;
}
}
is_parsing_json_ = (language == JSON);
// ----------------------------------------------------------------------------
// JsonScanner
// Set c0_ (one character ahead)
ASSERT(kCharacterLookaheadBufferSize == 1);
Advance();
// Initialize current_ to not refer to a literal.
current_.literal_chars = Vector<const char>();
// Reset literal buffer.
literal_buffer_.Reset();
JsonScanner::JsonScanner() {}
// Skip initial whitespace allowing HTML comment ends just like
// after a newline and scan first token.
has_line_terminator_before_next_ = true;
SkipWhiteSpace();
Scan();
void JsonScanner::Initialize(Handle<String> source) {
source_ = stream_initializer_.Init(source, NULL, 0, source->length());
Init();
// Skip initial whitespace.
SkipJsonWhiteSpace();
// Preload first token as look-ahead.
ScanJson();
}
Token::Value Scanner::Next() {
Token::Value JsonScanner::Next() {
// BUG 1215673: Find a thread safe way to set a stack limit in
// pre-parse mode. Otherwise, we cannot safely pre-parse from other
// threads.
@ -236,52 +241,13 @@ Token::Value Scanner::Next() {
stack_overflow_ = true;
next_.token = Token::ILLEGAL;
} else {
has_line_terminator_before_next_ = false;
Scan();
ScanJson();
}
return current_.token;
}
void Scanner::StartLiteral() {
literal_buffer_.StartLiteral();
}
void Scanner::AddLiteralChar(uc32 c) {
literal_buffer_.AddChar(c);
}
void Scanner::TerminateLiteral() {
next_.literal_chars = literal_buffer_.EndLiteral();
}
void Scanner::DropLiteral() {
literal_buffer_.DropLiteral();
}
void Scanner::AddLiteralCharAdvance() {
AddLiteralChar(c0_);
Advance();
}
static inline bool IsByteOrderMark(uc32 c) {
// The Unicode value U+FFFE is guaranteed never to be assigned as a
// Unicode character; this implies that in a Unicode context the
// 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF
// character expressed in little-endian byte order (since it could
// not be a U+FFFE character expressed in big-endian byte
// order). Nevertheless, we check for it to be compatible with
// Spidermonkey.
return c == 0xFEFF || c == 0xFFFE;
}
bool Scanner::SkipJsonWhiteSpace() {
bool JsonScanner::SkipJsonWhiteSpace() {
int start_position = source_pos();
// JSON WhiteSpace is tab, carrige-return, newline and space.
while (c0_ == ' ' || c0_ == '\n' || c0_ == '\r' || c0_ == '\t') {
@ -291,107 +257,9 @@ bool Scanner::SkipJsonWhiteSpace() {
}
bool Scanner::SkipJavaScriptWhiteSpace() {
int start_position = source_pos();
while (true) {
// We treat byte-order marks (BOMs) as whitespace for better
// compatibility with Spidermonkey and other JavaScript engines.
while (ScannerConstants::kIsWhiteSpace.get(c0_) || IsByteOrderMark(c0_)) {
// IsWhiteSpace() includes line terminators!
if (ScannerConstants::kIsLineTerminator.get(c0_)) {
// Ignore line terminators, but remember them. This is necessary
// for automatic semicolon insertion.
has_line_terminator_before_next_ = true;
}
Advance();
}
// If there is an HTML comment end '-->' at the beginning of a
// line (with only whitespace in front of it), we treat the rest
// of the line as a comment. This is in line with the way
// SpiderMonkey handles it.
if (c0_ == '-' && has_line_terminator_before_next_) {
Advance();
if (c0_ == '-') {
Advance();
if (c0_ == '>') {
// Treat the rest of the line as a comment.
SkipSingleLineComment();
// Continue skipping white space after the comment.
continue;
}
PushBack('-'); // undo Advance()
}
PushBack('-'); // undo Advance()
}
// Return whether or not we skipped any characters.
return source_pos() != start_position;
}
}
Token::Value Scanner::SkipSingleLineComment() {
Advance();
// The line terminator at the end of the line is not considered
// to be part of the single-line comment; it is recognized
// separately by the lexical grammar and becomes part of the
// stream of input elements for the syntactic grammar (see
// ECMA-262, section 7.4, page 12).
while (c0_ >= 0 && !ScannerConstants::kIsLineTerminator.get(c0_)) {
Advance();
}
return Token::WHITESPACE;
}
Token::Value Scanner::SkipMultiLineComment() {
ASSERT(c0_ == '*');
Advance();
while (c0_ >= 0) {
char ch = c0_;
Advance();
// If we have reached the end of the multi-line comment, we
// consume the '/' and insert a whitespace. This way all
// multi-line comments are treated as whitespace - even the ones
// containing line terminators. This contradicts ECMA-262, section
// 7.4, page 12, that says that multi-line comments containing
// line terminators should be treated as a line terminator, but it
// matches the behaviour of SpiderMonkey and KJS.
if (ch == '*' && c0_ == '/') {
c0_ = ' ';
return Token::WHITESPACE;
}
}
// Unterminated multi-line comment.
return Token::ILLEGAL;
}
Token::Value Scanner::ScanHtmlComment() {
// Check for <!-- comments.
ASSERT(c0_ == '!');
Advance();
if (c0_ == '-') {
Advance();
if (c0_ == '-') return SkipSingleLineComment();
PushBack('-'); // undo Advance()
}
PushBack('!'); // undo Advance()
ASSERT(c0_ == '!');
return Token::LT;
}
void Scanner::ScanJson() {
void JsonScanner::ScanJson() {
next_.literal_chars = Vector<const char>();
Token::Value token;
has_line_terminator_before_next_ = false;
do {
// Remember the position of the next token
next_.location.beg_pos = source_pos();
@ -468,7 +336,7 @@ void Scanner::ScanJson() {
}
Token::Value Scanner::ScanJsonString() {
Token::Value JsonScanner::ScanJsonString() {
ASSERT_EQ('"', c0_);
Advance();
LiteralScope literal(this);
@ -528,7 +396,7 @@ Token::Value Scanner::ScanJsonString() {
}
Token::Value Scanner::ScanJsonNumber() {
Token::Value JsonScanner::ScanJsonNumber() {
LiteralScope literal(this);
if (c0_ == '-') AddLiteralCharAdvance();
if (c0_ == '0') {
@ -562,7 +430,7 @@ Token::Value Scanner::ScanJsonNumber() {
}
Token::Value Scanner::ScanJsonIdentifier(const char* text,
Token::Value JsonScanner::ScanJsonIdentifier(const char* text,
Token::Value token) {
LiteralScope literal(this);
while (*text != '\0') {
@ -576,577 +444,5 @@ Token::Value Scanner::ScanJsonIdentifier(const char* text,
}
void Scanner::ScanJavaScript() {
next_.literal_chars = Vector<const char>();
Token::Value token;
do {
// Remember the position of the next token
next_.location.beg_pos = source_pos();
switch (c0_) {
case ' ':
case '\t':
Advance();
token = Token::WHITESPACE;
break;
case '\n':
Advance();
has_line_terminator_before_next_ = true;
token = Token::WHITESPACE;
break;
case '"': case '\'':
token = ScanString();
break;
case '<':
// < <= << <<= <!--
Advance();
if (c0_ == '=') {
token = Select(Token::LTE);
} else if (c0_ == '<') {
token = Select('=', Token::ASSIGN_SHL, Token::SHL);
} else if (c0_ == '!') {
token = ScanHtmlComment();
} else {
token = Token::LT;
}
break;
case '>':
// > >= >> >>= >>> >>>=
Advance();
if (c0_ == '=') {
token = Select(Token::GTE);
} else if (c0_ == '>') {
// >> >>= >>> >>>=
Advance();
if (c0_ == '=') {
token = Select(Token::ASSIGN_SAR);
} else if (c0_ == '>') {
token = Select('=', Token::ASSIGN_SHR, Token::SHR);
} else {
token = Token::SAR;
}
} else {
token = Token::GT;
}
break;
case '=':
// = == ===
Advance();
if (c0_ == '=') {
token = Select('=', Token::EQ_STRICT, Token::EQ);
} else {
token = Token::ASSIGN;
}
break;
case '!':
// ! != !==
Advance();
if (c0_ == '=') {
token = Select('=', Token::NE_STRICT, Token::NE);
} else {
token = Token::NOT;
}
break;
case '+':
// + ++ +=
Advance();
if (c0_ == '+') {
token = Select(Token::INC);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_ADD);
} else {
token = Token::ADD;
}
break;
case '-':
// - -- --> -=
Advance();
if (c0_ == '-') {
Advance();
if (c0_ == '>' && has_line_terminator_before_next_) {
// For compatibility with SpiderMonkey, we skip lines that
// start with an HTML comment end '-->'.
token = SkipSingleLineComment();
} else {
token = Token::DEC;
}
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_SUB);
} else {
token = Token::SUB;
}
break;
case '*':
// * *=
token = Select('=', Token::ASSIGN_MUL, Token::MUL);
break;
case '%':
// % %=
token = Select('=', Token::ASSIGN_MOD, Token::MOD);
break;
case '/':
// / // /* /=
Advance();
if (c0_ == '/') {
token = SkipSingleLineComment();
} else if (c0_ == '*') {
token = SkipMultiLineComment();
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_DIV);
} else {
token = Token::DIV;
}
break;
case '&':
// & && &=
Advance();
if (c0_ == '&') {
token = Select(Token::AND);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_BIT_AND);
} else {
token = Token::BIT_AND;
}
break;
case '|':
// | || |=
Advance();
if (c0_ == '|') {
token = Select(Token::OR);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_BIT_OR);
} else {
token = Token::BIT_OR;
}
break;
case '^':
// ^ ^=
token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
break;
case '.':
// . Number
Advance();
if (IsDecimalDigit(c0_)) {
token = ScanNumber(true);
} else {
token = Token::PERIOD;
}
break;
case ':':
token = Select(Token::COLON);
break;
case ';':
token = Select(Token::SEMICOLON);
break;
case ',':
token = Select(Token::COMMA);
break;
case '(':
token = Select(Token::LPAREN);
break;
case ')':
token = Select(Token::RPAREN);
break;
case '[':
token = Select(Token::LBRACK);
break;
case ']':
token = Select(Token::RBRACK);
break;
case '{':
token = Select(Token::LBRACE);
break;
case '}':
token = Select(Token::RBRACE);
break;
case '?':
token = Select(Token::CONDITIONAL);
break;
case '~':
token = Select(Token::BIT_NOT);
break;
default:
if (ScannerConstants::kIsIdentifierStart.get(c0_)) {
token = ScanIdentifier();
} else if (IsDecimalDigit(c0_)) {
token = ScanNumber(false);
} else if (SkipWhiteSpace()) {
token = Token::WHITESPACE;
} else if (c0_ < 0) {
token = Token::EOS;
} else {
token = Select(Token::ILLEGAL);
}
break;
}
// Continue scanning for tokens as long as we're just skipping
// whitespace.
} while (token == Token::WHITESPACE);
next_.location.end_pos = source_pos();
next_.token = token;
}
void Scanner::SeekForward(int pos) {
source_->SeekForward(pos - 1);
Advance();
// This function is only called to seek to the location
// of the end of a function (at the "}" token). It doesn't matter
// whether there was a line terminator in the part we skip.
has_line_terminator_before_next_ = false;
Scan();
}
uc32 Scanner::ScanHexEscape(uc32 c, int length) {
ASSERT(length <= 4); // prevent overflow
uc32 digits[4];
uc32 x = 0;
for (int i = 0; i < length; i++) {
digits[i] = c0_;
int d = HexValue(c0_);
if (d < 0) {
// According to ECMA-262, 3rd, 7.8.4, page 18, these hex escapes
// should be illegal, but other JS VMs just return the
// non-escaped version of the original character.
// Push back digits read, except the last one (in c0_).
for (int j = i-1; j >= 0; j--) {
PushBack(digits[j]);
}
// Notice: No handling of error - treat it as "\u"->"u".
return c;
}
x = x * 16 + d;
Advance();
}
return x;
}
// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
// ECMA-262. Other JS VMs support them.
uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
uc32 x = c - '0';
for (int i = 0; i < length; i++) {
int d = c0_ - '0';
if (d < 0 || d > 7) break;
int nx = x * 8 + d;
if (nx >= 256) break;
x = nx;
Advance();
}
return x;
}
void Scanner::ScanEscape() {
uc32 c = c0_;
Advance();
// Skip escaped newlines.
if (ScannerConstants::kIsLineTerminator.get(c)) {
// Allow CR+LF newlines in multiline string literals.
if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
// Allow LF+CR newlines in multiline string literals.
if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance();
return;
}
switch (c) {
case '\'': // fall through
case '"' : // fall through
case '\\': break;
case 'b' : c = '\b'; break;
case 'f' : c = '\f'; break;
case 'n' : c = '\n'; break;
case 'r' : c = '\r'; break;
case 't' : c = '\t'; break;
case 'u' : c = ScanHexEscape(c, 4); break;
case 'v' : c = '\v'; break;
case 'x' : c = ScanHexEscape(c, 2); break;
case '0' : // fall through
case '1' : // fall through
case '2' : // fall through
case '3' : // fall through
case '4' : // fall through
case '5' : // fall through
case '6' : // fall through
case '7' : c = ScanOctalEscape(c, 2); break;
}
// According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
// should be illegal, but they are commonly handled
// as non-escaped characters by JS VMs.
AddLiteralChar(c);
}
Token::Value Scanner::ScanString() {
uc32 quote = c0_;
Advance(); // consume quote
LiteralScope literal(this);
while (c0_ != quote && c0_ >= 0
&& !ScannerConstants::kIsLineTerminator.get(c0_)) {
uc32 c = c0_;
Advance();
if (c == '\\') {
if (c0_ < 0) return Token::ILLEGAL;
ScanEscape();
} else {
AddLiteralChar(c);
}
}
if (c0_ != quote) return Token::ILLEGAL;
literal.Complete();
Advance(); // consume quote
return Token::STRING;
}
Token::Value Scanner::Select(Token::Value tok) {
Advance();
return tok;
}
Token::Value Scanner::Select(uc32 next, Token::Value then, Token::Value else_) {
Advance();
if (c0_ == next) {
Advance();
return then;
} else {
return else_;
}
}
// Returns true if any decimal digits were scanned, returns false otherwise.
void Scanner::ScanDecimalDigits() {
while (IsDecimalDigit(c0_))
AddLiteralCharAdvance();
}
Token::Value Scanner::ScanNumber(bool seen_period) {
ASSERT(IsDecimalDigit(c0_)); // the first digit of the number or the fraction
enum { DECIMAL, HEX, OCTAL } kind = DECIMAL;
LiteralScope literal(this);
if (seen_period) {
// we have already seen a decimal point of the float
AddLiteralChar('.');
ScanDecimalDigits(); // we know we have at least one digit
} else {
// if the first character is '0' we must check for octals and hex
if (c0_ == '0') {
AddLiteralCharAdvance();
// either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
if (c0_ == 'x' || c0_ == 'X') {
// hex number
kind = HEX;
AddLiteralCharAdvance();
if (!IsHexDigit(c0_)) {
// we must have at least one hex digit after 'x'/'X'
return Token::ILLEGAL;
}
while (IsHexDigit(c0_)) {
AddLiteralCharAdvance();
}
} else if ('0' <= c0_ && c0_ <= '7') {
// (possible) octal number
kind = OCTAL;
while (true) {
if (c0_ == '8' || c0_ == '9') {
kind = DECIMAL;
break;
}
if (c0_ < '0' || '7' < c0_) break;
AddLiteralCharAdvance();
}
}
}
// Parse decimal digits and allow trailing fractional part.
if (kind == DECIMAL) {
ScanDecimalDigits(); // optional
if (c0_ == '.') {
AddLiteralCharAdvance();
ScanDecimalDigits(); // optional
}
}
}
// scan exponent, if any
if (c0_ == 'e' || c0_ == 'E') {
ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
if (kind == OCTAL) return Token::ILLEGAL; // no exponent for octals allowed
// scan exponent
AddLiteralCharAdvance();
if (c0_ == '+' || c0_ == '-')
AddLiteralCharAdvance();
if (!IsDecimalDigit(c0_)) {
// we must have at least one decimal digit after 'e'/'E'
return Token::ILLEGAL;
}
ScanDecimalDigits();
}
// The source character immediately following a numeric literal must
// not be an identifier start or a decimal digit; see ECMA-262
// section 7.8.3, page 17 (note that we read only one decimal digit
// if the value is 0).
if (IsDecimalDigit(c0_) || ScannerConstants::kIsIdentifierStart.get(c0_))
return Token::ILLEGAL;
literal.Complete();
return Token::NUMBER;
}
uc32 Scanner::ScanIdentifierUnicodeEscape() {
Advance();
if (c0_ != 'u') return unibrow::Utf8::kBadChar;
Advance();
uc32 c = ScanHexEscape('u', 4);
// We do not allow a unicode escape sequence to start another
// unicode escape sequence.
if (c == '\\') return unibrow::Utf8::kBadChar;
return c;
}
Token::Value Scanner::ScanIdentifier() {
ASSERT(ScannerConstants::kIsIdentifierStart.get(c0_));
LiteralScope literal(this);
KeywordMatcher keyword_match;
// Scan identifier start character.
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier start characters.
if (!ScannerConstants::kIsIdentifierStart.get(c)) return Token::ILLEGAL;
AddLiteralChar(c);
keyword_match.Fail();
} else {
AddLiteralChar(c0_);
keyword_match.AddChar(c0_);
Advance();
}
// Scan the rest of the identifier characters.
while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier part characters.
if (!ScannerConstants::kIsIdentifierPart.get(c)) return Token::ILLEGAL;
AddLiteralChar(c);
keyword_match.Fail();
} else {
AddLiteralChar(c0_);
keyword_match.AddChar(c0_);
Advance();
}
}
literal.Complete();
return keyword_match.token();
}
bool Scanner::ScanRegExpPattern(bool seen_equal) {
// Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
bool in_character_class = false;
// Previous token is either '/' or '/=', in the second case, the
// pattern starts at =.
next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1);
next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0);
// Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
// the scanner should pass uninterpreted bodies to the RegExp
// constructor.
LiteralScope literal(this);
if (seen_equal)
AddLiteralChar('=');
while (c0_ != '/' || in_character_class) {
if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
if (c0_ == '\\') { // escaped character
AddLiteralCharAdvance();
if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
AddLiteralCharAdvance();
} else { // unescaped character
if (c0_ == '[') in_character_class = true;
if (c0_ == ']') in_character_class = false;
AddLiteralCharAdvance();
}
}
Advance(); // consume '/'
literal.Complete();
return true;
}
bool Scanner::ScanRegExpFlags() {
// Scan regular expression flags.
LiteralScope literal(this);
while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
if (c != static_cast<uc32>(unibrow::Utf8::kBadChar)) {
// We allow any escaped character, unlike the restriction on
// IdentifierPart when it is used to build an IdentifierName.
AddLiteralChar(c);
continue;
}
}
AddLiteralCharAdvance();
}
literal.Complete();
next_.location.end_pos = source_pos() - 1;
return true;
}
} } // namespace v8::internal

299
deps/v8/src/scanner.h

@ -35,65 +35,6 @@
namespace v8 {
namespace internal {
class UTF8Buffer {
public:
UTF8Buffer();
~UTF8Buffer();
inline void AddChar(uc32 c) {
if (recording_) {
if (static_cast<unsigned>(c) <= unibrow::Utf8::kMaxOneByteChar) {
buffer_.Add(static_cast<char>(c));
} else {
AddCharSlow(c);
}
}
}
void StartLiteral() {
buffer_.StartSequence();
recording_ = true;
}
Vector<const char> EndLiteral() {
if (recording_) {
recording_ = false;
buffer_.Add(kEndMarker);
Vector<char> sequence = buffer_.EndSequence();
return Vector<const char>(sequence.start(), sequence.length());
}
return Vector<const char>();
}
void DropLiteral() {
if (recording_) {
recording_ = false;
buffer_.DropSequence();
}
}
void Reset() {
buffer_.Reset();
}
// The end marker added after a parsed literal.
// Using zero allows the usage of strlen and similar functions on
// identifiers and numbers (but not strings, since they may contain zero
// bytes).
// TODO(lrn): Use '\xff' as end marker, since it cannot occur inside
// an utf-8 string. This requires changes in all places that uses
// str-functions on the literals, but allows a single pointer to represent
// the literal, even if it contains embedded zeros.
static const char kEndMarker = '\x00';
private:
static const int kInitialCapacity = 256;
SequenceCollector<char, 4> buffer_;
bool recording_;
void AddCharSlow(uc32 c);
};
// UTF16 buffer to read characters from a character stream.
class CharacterStreamUTF16Buffer: public UTF16Buffer {
public:
@ -134,175 +75,65 @@ class ExternalStringUTF16Buffer: public UTF16Buffer {
};
enum ParserLanguage { JAVASCRIPT, JSON };
// Initializes a UTF16Buffer as input stream, using one of a number
// of strategies depending on the available character sources.
class StreamInitializer {
public:
UTF16Buffer* Init(Handle<String> source,
unibrow::CharacterStream* stream,
int start_position,
int end_position);
private:
// Different UTF16 buffers used to pull characters from. Based on input one of
// these will be initialized as the actual data source.
CharacterStreamUTF16Buffer char_stream_buffer_;
ExternalStringUTF16Buffer<ExternalTwoByteString, uint16_t>
two_byte_string_buffer_;
ExternalStringUTF16Buffer<ExternalAsciiString, char> ascii_string_buffer_;
// Used to convert the source string into a character stream when a stream
// is not passed to the scanner.
SafeStringInputBuffer safe_string_input_buffer_;
};
class Scanner {
public:
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
// ----------------------------------------------------------------------------
// V8JavaScriptScanner
// JavaScript scanner getting its input from either a V8 String or a unicode
// CharacterStream.
class LiteralScope {
class V8JavaScriptScanner : public JavaScriptScanner {
public:
explicit LiteralScope(Scanner* self);
~LiteralScope();
void Complete();
private:
Scanner* scanner_;
bool complete_;
};
V8JavaScriptScanner() {}
Scanner();
Token::Value NextCheckStack();
// Initialize the Scanner to scan source.
void Initialize(Handle<String> source,
ParserLanguage language);
void Initialize(Handle<String> source, int literal_flags = kAllLiterals);
void Initialize(Handle<String> source,
unibrow::CharacterStream* stream,
ParserLanguage language);
int literal_flags = kAllLiterals);
void Initialize(Handle<String> source,
int start_position, int end_position,
ParserLanguage language);
// Returns the next token.
Token::Value Next();
// Returns the current token again.
Token::Value current_token() { return current_.token; }
int literal_flags = kAllLiterals);
// One token look-ahead (past the token returned by Next()).
Token::Value peek() const { return next_.token; }
// Returns true if there was a line terminator before the peek'ed token.
bool has_line_terminator_before_next() const {
return has_line_terminator_before_next_;
}
struct Location {
Location(int b, int e) : beg_pos(b), end_pos(e) { }
Location() : beg_pos(0), end_pos(0) { }
int beg_pos;
int end_pos;
protected:
StreamInitializer stream_initializer_;
};
// Returns the location information for the current token
// (the token returned by Next()).
Location location() const { return current_.location; }
Location peek_location() const { return next_.location; }
// Returns the literal string, if any, for the current token (the
// token returned by Next()). The string is 0-terminated and in
// UTF-8 format; they may contain 0-characters. Literal strings are
// collected for identifiers, strings, and numbers.
// These functions only give the correct result if the literal
// was scanned between calls to StartLiteral() and TerminateLiteral().
const char* literal_string() const {
return current_.literal_chars.start();
}
int literal_length() const {
// Excluding terminal '\x00' added by TerminateLiteral().
return current_.literal_chars.length() - 1;
}
Vector<const char> literal() const {
return Vector<const char>(literal_string(), literal_length());
}
// Returns the literal string for the next token (the token that
// would be returned if Next() were called).
const char* next_literal_string() const {
return next_.literal_chars.start();
}
// Returns the length of the next token (that would be returned if
// Next() were called).
int next_literal_length() const {
// Excluding terminal '\x00' added by TerminateLiteral().
return next_.literal_chars.length() - 1;
}
Vector<const char> next_literal() const {
return Vector<const char>(next_literal_string(), next_literal_length());
}
// Scans the input as a regular expression pattern, previous
// character(s) must be /(=). Returns true if a pattern is scanned.
bool ScanRegExpPattern(bool seen_equal);
// Returns true if regexp flags are scanned (always since flags can
// be empty).
bool ScanRegExpFlags();
// Seek forward to the given position. This operation does not
// work in general, for instance when there are pushed back
// characters, but works for seeking forward until simple delimiter
// tokens, which is what it is used for.
void SeekForward(int pos);
bool stack_overflow() { return stack_overflow_; }
// Tells whether the buffer contains an identifier (no escapes).
// Used for checking if a property name is an identifier.
static bool IsIdentifier(unibrow::CharacterStream* buffer);
static const int kCharacterLookaheadBufferSize = 1;
static const int kNoEndPosition = 1;
private:
// The current and look-ahead token.
struct TokenDesc {
Token::Value token;
Location location;
Vector<const char> literal_chars;
};
class JsonScanner : public Scanner {
public:
JsonScanner();
void Init(Handle<String> source,
unibrow::CharacterStream* stream,
int start_position, int end_position,
ParserLanguage language);
// Literal buffer support
inline void StartLiteral();
inline void AddLiteralChar(uc32 ch);
inline void AddLiteralCharAdvance();
inline void TerminateLiteral();
// Stops scanning of a literal, e.g., due to an encountered error.
inline void DropLiteral();
// Low-level scanning support.
void Advance() { c0_ = source_->Advance(); }
void PushBack(uc32 ch) {
source_->PushBack(ch);
c0_ = ch;
}
// Initialize the Scanner to scan source.
void Initialize(Handle<String> source);
bool SkipWhiteSpace() {
if (is_parsing_json_) {
return SkipJsonWhiteSpace();
} else {
return SkipJavaScriptWhiteSpace();
}
}
// Returns the next token.
Token::Value Next();
bool SkipJavaScriptWhiteSpace();
protected:
// Skip past JSON whitespace (only space, tab, newline and carrige-return).
bool SkipJsonWhiteSpace();
Token::Value SkipSingleLineComment();
Token::Value SkipMultiLineComment();
inline Token::Value Select(Token::Value tok);
inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_);
inline void Scan() {
if (is_parsing_json_) {
ScanJson();
} else {
ScanJavaScript();
}
}
// Scans a single JavaScript token.
void ScanJavaScript();
// Scan a single JSON token. The JSON lexical grammar is specified in the
// ECMAScript 5 standard, section 15.12.1.1.
@ -331,53 +162,7 @@ class Scanner {
// JSONNullLiteral).
Token::Value ScanJsonIdentifier(const char* text, Token::Value token);
void ScanDecimalDigits();
Token::Value ScanNumber(bool seen_period);
Token::Value ScanIdentifier();
uc32 ScanHexEscape(uc32 c, int length);
uc32 ScanOctalEscape(uc32 c, int length);
void ScanEscape();
Token::Value ScanString();
// Scans a possible HTML comment -- begins with '<!'.
Token::Value ScanHtmlComment();
// Return the current source position.
int source_pos() {
return source_->pos() - kCharacterLookaheadBufferSize;
}
// Decodes a unicode escape-sequence which is part of an identifier.
// If the escape sequence cannot be decoded the result is kBadRune.
uc32 ScanIdentifierUnicodeEscape();
TokenDesc current_; // desc for current token (as returned by Next())
TokenDesc next_; // desc for next token (one token look-ahead)
bool has_line_terminator_before_next_;
bool is_parsing_json_;
// Different UTF16 buffers used to pull characters from. Based on input one of
// these will be initialized as the actual data source.
CharacterStreamUTF16Buffer char_stream_buffer_;
ExternalStringUTF16Buffer<ExternalTwoByteString, uint16_t>
two_byte_string_buffer_;
ExternalStringUTF16Buffer<ExternalAsciiString, char> ascii_string_buffer_;
// Source. Will point to one of the buffers declared above.
UTF16Buffer* source_;
// Used to convert the source string into a character stream when a stream
// is not passed to the scanner.
SafeStringInputBuffer safe_string_input_buffer_;
// Buffer to hold literal values (identifiers, strings, numbers)
// using '\x00'-terminated UTF-8 encoding. Handles allocation internally.
UTF8Buffer literal_buffer_;
bool stack_overflow_;
// One Unicode character look-ahead; c0_ < 0 at the end of the input.
uc32 c0_;
StreamInitializer stream_initializer_;
};
@ -400,7 +185,7 @@ void ExternalStringUTF16Buffer<StringType, CharType>::Initialize(
SeekForward(start_position);
}
end_ =
end_position != Scanner::kNoEndPosition ? end_position : data->length();
end_position != kNoEndPosition ? end_position : data->length();
}

7
deps/v8/src/stub-cache.cc

@ -960,14 +960,11 @@ void StubCache::Clear() {
MaybeObject* LoadCallbackProperty(Arguments args) {
ASSERT(args[0]->IsJSObject());
ASSERT(args[1]->IsJSObject());
AccessorInfo* callback = AccessorInfo::cast(args[2]);
AccessorInfo* callback = AccessorInfo::cast(args[3]);
Address getter_address = v8::ToCData<Address>(callback->getter());
v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
ASSERT(fun != NULL);
CustomArguments custom_args(callback->data(),
JSObject::cast(args[0]),
JSObject::cast(args[1]));
v8::AccessorInfo info(custom_args.end());
v8::AccessorInfo info(&args[0]);
HandleScope scope;
v8::Handle<v8::Value> result;
{

15
deps/v8/src/third_party/dtoa/COPYING

@ -1,15 +0,0 @@
The author of this software is David M. Gay.
Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
Permission to use, copy, modify, and distribute this software for any
purpose without fee is hereby granted, provided that this entire
notice is included in all copies of any software which is or includes
a copy or modification of this software and in all copies of the
supporting documentation for such software.
THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES
ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
PURPOSE.

3331
deps/v8/src/third_party/dtoa/dtoa.c

File diff suppressed because it is too large

2
deps/v8/src/utils.h

@ -326,6 +326,8 @@ class Vector {
return start_[index];
}
T& at(int i) const { return operator[](i); }
T& first() { return start_[0]; }
T& last() { return start_[length_ - 1]; }

2
deps/v8/src/version.cc

@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 5
#define BUILD_NUMBER 7
#define BUILD_NUMBER 8
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false

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

@ -80,8 +80,9 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
__ pop(rdx);
__ push(rsi);
__ push(rdx);
__ Push(Factory::false_value());
__ push(rcx); // Restore return address.
__ TailCallRuntime(Runtime::kNewClosure, 2, 1);
__ TailCallRuntime(Runtime::kNewClosure, 3, 1);
}

21
deps/v8/src/x64/codegen-x64.cc

@ -4244,7 +4244,8 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
void CodeGenerator::InstantiateFunction(
Handle<SharedFunctionInfo> function_info) {
Handle<SharedFunctionInfo> function_info,
bool pretenure) {
// The inevitable call will sync frame elements to memory anyway, so
// we do it eagerly to allow us to push the arguments directly into
// place.
@ -4252,7 +4253,9 @@ void CodeGenerator::InstantiateFunction(
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
if (scope()->is_function_scope() && function_info->num_literals() == 0) {
if (scope()->is_function_scope() &&
function_info->num_literals() == 0 &&
!pretenure) {
FastNewClosureStub stub;
frame_->Push(function_info);
Result answer = frame_->CallStub(&stub, 1);
@ -4262,7 +4265,10 @@ void CodeGenerator::InstantiateFunction(
// shared function info.
frame_->EmitPush(rsi);
frame_->EmitPush(function_info);
Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
frame_->EmitPush(pretenure
? Factory::true_value()
: Factory::false_value());
Result result = frame_->CallRuntime(Runtime::kNewClosure, 3);
frame_->Push(&result);
}
}
@ -4279,14 +4285,14 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
SetStackOverflow();
return;
}
InstantiateFunction(function_info);
InstantiateFunction(function_info, node->pretenure());
}
void CodeGenerator::VisitSharedFunctionInfoLiteral(
SharedFunctionInfoLiteral* node) {
Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
InstantiateFunction(node->shared_function_info());
InstantiateFunction(node->shared_function_info(), false);
}
@ -7217,6 +7223,11 @@ void CodeGenerator::GenerateGetCachedArrayIndex(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) {
frame_->Push(Factory::undefined_value());
}
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
if (CheckForInlineRuntimeCall(node)) {
return;

4
deps/v8/src/x64/codegen-x64.h

@ -585,7 +585,8 @@ class CodeGenerator: public AstVisitor {
void DeclareGlobals(Handle<FixedArray> pairs);
// Instantiate the function based on the shared function info.
void InstantiateFunction(Handle<SharedFunctionInfo> function_info);
void InstantiateFunction(Handle<SharedFunctionInfo> function_info,
bool pretenure);
// Support for type checks.
void GenerateIsSmi(ZoneList<Expression*>* args);
@ -668,6 +669,7 @@ class CodeGenerator: public AstVisitor {
void GenerateHasCachedArrayIndex(ZoneList<Expression*>* args);
void GenerateGetCachedArrayIndex(ZoneList<Expression*>* args);
void GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {

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

@ -837,17 +837,21 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
}
void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
bool pretenure) {
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
if (scope()->is_function_scope() && info->num_literals() == 0) {
if (scope()->is_function_scope() &&
info->num_literals() == 0 &&
!pretenure) {
FastNewClosureStub stub;
__ Push(info);
__ CallStub(&stub);
} else {
__ push(rsi);
__ Push(info);
__ CallRuntime(Runtime::kNewClosure, 2);
__ Push(pretenure ? Factory::true_value() : Factory::false_value());
__ CallRuntime(Runtime::kNewClosure, 3);
}
context()->Plug(rax);
}
@ -2795,6 +2799,11 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
}
void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
context()->Plug(Heap::kUndefinedValueRootIndex);
}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') {

2
deps/v8/src/x64/stub-cache-x64.cc

@ -2588,8 +2588,8 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
__ push(receiver);
__ push(holder_reg);
__ Move(holder_reg, Handle<AccessorInfo>(callback));
__ push(holder_reg);
__ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
__ push(holder_reg);
__ push(name_reg);
__ push(scratch2); // restore return address

8
deps/v8/test/cctest/test-api.cc

@ -6324,7 +6324,7 @@ static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
int expected) {
v8::HandleScope scope;
v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
templ->SetNamedPropertyHandler(getter);
templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
LocalContext context;
context->Global()->Set(v8_str("o"), templ->NewInstance());
v8::Handle<Value> value = CompileRun(source);
@ -6335,7 +6335,8 @@ static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
CHECK(v8_str("x")->Equals(name));
CHECK_EQ(v8_str("data"), info.Data());
CHECK_EQ(v8_str("x"), name);
return v8::Integer::New(42);
}
@ -6733,7 +6734,8 @@ THREADED_TEST(InterceptorStoreIC) {
v8::HandleScope scope;
v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
InterceptorStoreICSetter);
InterceptorStoreICSetter,
0, 0, 0, v8_str("data"));
LocalContext context;
context->Global()->Set(v8_str("o"), templ->NewInstance());
v8::Handle<Value> value = CompileRun(

13
deps/v8/test/cctest/test-conversions.cc

@ -141,9 +141,6 @@ TEST(LongNumberStr) {
}
extern "C" double gay_strtod(const char* s00, const char** se);
TEST(MaximumSignificantDigits) {
char num[] =
"4.4501477170144020250819966727949918635852426585926051135169509"
@ -160,12 +157,12 @@ TEST(MaximumSignificantDigits) {
"847003580761626016356864581135848683152156368691976240370422601"
"6998291015625000000000000000000000000000000000e-308";
CHECK_EQ(gay_strtod(num, NULL), StringToDouble(num, NO_FLAGS));
CHECK_EQ(4.4501477170144017780491e-308, StringToDouble(num, NO_FLAGS));
// Changes the result of strtod (at least in glibc implementation).
num[sizeof(num) - 8] = '1';
CHECK_EQ(gay_strtod(num, NULL), StringToDouble(num, NO_FLAGS));
CHECK_EQ(4.4501477170144022721148e-308, StringToDouble(num, NO_FLAGS));
}
TEST(MinimumExponent) {
@ -185,19 +182,19 @@ TEST(MinimumExponent) {
"470035807616260163568645811358486831521563686919762403704226016"
"998291015625000000000000000000000000000000000e-1108";
CHECK_EQ(gay_strtod(num, NULL), StringToDouble(num, NO_FLAGS));
CHECK_EQ(4.4501477170144017780491e-308, StringToDouble(num, NO_FLAGS));
// Changes the result of strtod (at least in glibc implementation).
num[sizeof(num) - 8] = '1';
CHECK_EQ(gay_strtod(num, NULL), StringToDouble(num, NO_FLAGS));
CHECK_EQ(4.4501477170144022721148e-308, StringToDouble(num, NO_FLAGS));
}
TEST(MaximumExponent) {
char num[] = "0.16e309";
CHECK_EQ(gay_strtod(num, NULL), StringToDouble(num, NO_FLAGS));
CHECK_EQ(1.59999999999999997765e+308, StringToDouble(num, NO_FLAGS));
}

63
deps/v8/test/cctest/test-debug.cc

@ -6900,26 +6900,71 @@ TEST(DebugEventBreakData) {
// Test that setting the terminate execution flag during debug break processing.
TEST(DebugBreakLoop) {
v8::HandleScope scope;
DebugLocalContext env;
static void TestDebugBreakInLoop(const char* loop_head,
const char** loop_bodies,
const char* loop_tail) {
// Receive 100 breaks for each test and then terminate JavaScript execution.
static int count = 0;
// Receive 100 breaks and terminate.
max_break_point_hit_count = 100;
for (int i = 0; loop_bodies[i] != NULL; i++) {
count++;
max_break_point_hit_count = count * 100;
terminate_after_max_break_point_hit = true;
// Register a debug event listener which sets the break flag and counts.
v8::Debug::SetDebugEventListener(DebugEventBreakMax);
EmbeddedVector<char, 1024> buffer;
OS::SNPrintF(buffer,
"function f() {%s%s%s}",
loop_head, loop_bodies[i], loop_tail);
// Function with infinite loop.
CompileRun("function f() { while (true) { } }");
CompileRun(buffer.start());
// Set the debug break to enter the debugger as soon as possible.
v8::Debug::DebugBreak();
// Call function with infinite loop.
CompileRun("f();");
CHECK_EQ(100, break_point_hit_count);
CHECK_EQ(count * 100, break_point_hit_count);
CHECK(!v8::V8::IsExecutionTerminating());
}
}
TEST(DebugBreakLoop) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which sets the break flag and counts.
v8::Debug::SetDebugEventListener(DebugEventBreakMax);
CompileRun("var a = 1;");
CompileRun("function g() { }");
CompileRun("function h() { }");
const char* loop_bodies[] = {
"",
"g()",
"if (a == 0) { g() }",
"if (a == 1) { g() }",
"if (a == 0) { g() } else { h() }",
"if (a == 0) { continue }",
"if (a == 1) { continue }",
"switch (a) { case 1: g(); }",
"switch (a) { case 1: continue; }",
"switch (a) { case 1: g(); break; default: h() }",
"switch (a) { case 1: continue; break; default: h() }",
NULL
};
TestDebugBreakInLoop("while (true) {", loop_bodies, "}");
TestDebugBreakInLoop("while (a == 1) {", loop_bodies, "}");
TestDebugBreakInLoop("do {", loop_bodies, "} while (true)");
TestDebugBreakInLoop("do {", loop_bodies, "} while (a == 1)");
TestDebugBreakInLoop("for (;;) {", loop_bodies, "}");
TestDebugBreakInLoop("for (;a == 1;) {", loop_bodies, "}");
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);

186
deps/v8/test/cctest/test-heap-profiler.cc

@ -411,8 +411,12 @@ class NamedEntriesDetector {
static const v8::HeapGraphNode* GetGlobalObject(
const v8::HeapSnapshot* snapshot) {
CHECK_EQ(1, snapshot->GetRoot()->GetChildrenCount());
return snapshot->GetRoot()->GetChild(0)->GetToNode();
CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
const v8::HeapGraphNode* global_obj =
snapshot->GetRoot()->GetChild(0)->GetToNode();
CHECK_EQ("Object", const_cast<i::HeapEntry*>(
reinterpret_cast<const i::HeapEntry*>(global_obj))->name());
return global_obj;
}
@ -479,21 +483,24 @@ TEST(HeapSnapshot) {
// Verify, that JS global object of env2 has '..2' properties.
const v8::HeapGraphNode* a2_node =
GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2");
GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2");
CHECK_NE(NULL, a2_node);
CHECK_NE(
NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_1"));
NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1"));
CHECK_NE(
NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2"));
CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2"));
NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
// Verify that anything related to '[ABC]1' is not reachable.
NamedEntriesDetector det;
i_snapshot_env2->IterateEntries(&det);
CHECK(det.has_A2);
CHECK(det.has_B2);
CHECK(det.has_C2);
/*
// Currently disabled. Too many retaining paths emerge, need to
// reduce the amount.
// Verify 'a2' object retainers. They are:
// - (global object).a2
// - c2.x1, c2.x2, c2[1]
@ -538,6 +545,7 @@ TEST(HeapSnapshot) {
CHECK(has_c2_1_ref);
CHECK(has_b2_1_x_ref);
CHECK(has_b2_2_x_ref);
*/
}
@ -550,37 +558,28 @@ TEST(HeapSnapshotObjectSizes) {
CompileRun(
"function X(a, b) { this.a = a; this.b = b; }\n"
"x = new X(new X(), new X());\n"
"x.a.a = x.b;");
"(function() { x.a.a = x.b; })();");
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8::String::New("sizes"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphNode* x =
GetProperty(global, v8::HeapGraphEdge::kProperty, "x");
GetProperty(global, v8::HeapGraphEdge::kShortcut, "x");
CHECK_NE(NULL, x);
const v8::HeapGraphNode* x_prototype =
GetProperty(x, v8::HeapGraphEdge::kProperty, "__proto__");
CHECK_NE(NULL, x_prototype);
const v8::HeapGraphNode* x1 =
GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
CHECK_NE(NULL, x1);
const v8::HeapGraphNode* x2 =
GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
CHECK_NE(NULL, x2);
CHECK_EQ(
x->GetSelfSize() * 3,
x->GetReachableSize() - x_prototype->GetReachableSize());
CHECK_EQ(
x->GetSelfSize() * 3, x->GetRetainedSize());
CHECK_EQ(
x1->GetSelfSize() * 2,
x1->GetReachableSize() - x_prototype->GetReachableSize());
CHECK_EQ(
x1->GetSelfSize(), x1->GetRetainedSize());
CHECK_EQ(
x2->GetSelfSize(),
x2->GetReachableSize() - x_prototype->GetReachableSize());
CHECK_EQ(
x2->GetSelfSize(), x2->GetRetainedSize());
// Test approximate sizes.
CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(false));
CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(false));
CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(false));
// Test exact sizes.
CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(true));
CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(true));
CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(true));
}
@ -622,15 +621,15 @@ TEST(HeapSnapshotCodeObjects) {
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphNode* compiled =
GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled");
GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled");
CHECK_NE(NULL, compiled);
CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
const v8::HeapGraphNode* lazy =
GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy");
GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy");
CHECK_NE(NULL, lazy);
CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
const v8::HeapGraphNode* anonymous =
GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous");
GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous");
CHECK_NE(NULL, anonymous);
CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
v8::String::AsciiValue anonymous_name(anonymous->GetName());
@ -682,9 +681,9 @@ TEST(HeapSnapshotHeapNumbers) {
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8::String::New("numbers"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a"));
CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a"));
const v8::HeapGraphNode* b =
GetProperty(global, v8::HeapGraphEdge::kProperty, "b");
GetProperty(global, v8::HeapGraphEdge::kShortcut, "b");
CHECK_NE(NULL, b);
CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
}
@ -808,12 +807,12 @@ TEST(HeapSnapshotsDiff) {
if (node->GetType() == v8::HeapGraphNode::kObject) {
v8::String::AsciiValue node_name(node->GetName());
if (strcmp(*node_name, "A2") == 0) {
CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kProperty, "a"));
CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a"));
CHECK(!found_A);
found_A = true;
s1_A_id = node->GetId();
} else if (strcmp(*node_name, "B") == 0) {
CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kProperty, "b2"));
CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "b2"));
CHECK(!found_B);
found_B = true;
}
@ -832,7 +831,7 @@ TEST(HeapSnapshotsDiff) {
if (node->GetType() == v8::HeapGraphNode::kObject) {
v8::String::AsciiValue node_name(node->GetName());
if (strcmp(*node_name, "A") == 0) {
CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kProperty, "a"));
CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a"));
CHECK(!found_A_del);
found_A_del = true;
s2_A_id = node->GetId();
@ -858,37 +857,6 @@ TEST(HeapSnapshotRootPreservedAfterSorting) {
}
namespace v8 {
namespace internal {
class HeapSnapshotTester {
public:
static int CalculateNetworkSize(JSObject* obj) {
return HeapSnapshot::CalculateNetworkSize(obj);
}
};
} } // namespace v8::internal
// http://code.google.com/p/v8/issues/detail?id=822
// Trying to call CalculateNetworkSize on an object with elements set
// to non-FixedArray may cause an assertion error in debug builds.
TEST(Issue822) {
v8::HandleScope scope;
LocalContext context;
const int kElementCount = 260;
uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
pixel_data);
v8::Handle<v8::Object> obj = v8::Object::New();
// Set the elements to be the pixels.
obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
// This call must not cause an assertion error in debug builds.
i::HeapSnapshotTester::CalculateNetworkSize(*jsobj);
}
static const v8::HeapGraphNode* GetChild(
const v8::HeapGraphNode* node,
v8::HeapGraphNode::Type type,
@ -932,13 +900,13 @@ TEST(AggregatedHeapSnapshot) {
v8::HeapProfiler::TakeSnapshot(
v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
const v8::HeapGraphNode* strings = GetChild(snapshot->GetRoot(),
v8::HeapGraphNode::kInternal,
v8::HeapGraphNode::kHidden,
"STRING_TYPE");
CHECK_NE(NULL, strings);
CHECK_NE(0, strings->GetSelfSize());
CHECK_NE(0, strings->GetInstancesCount());
const v8::HeapGraphNode* maps = GetChild(snapshot->GetRoot(),
v8::HeapGraphNode::kInternal,
v8::HeapGraphNode::kHidden,
"MAP_TYPE");
CHECK_NE(NULL, maps);
CHECK_NE(0, maps->GetSelfSize());
@ -998,6 +966,67 @@ TEST(AggregatedHeapSnapshot) {
CHECK(IsNodeRetainedAs(a_from_b, 1)); // B has 1 ref to A.
}
TEST(HeapEntryDominator) {
// The graph looks like this:
//
// -> node1
// a |^
// -> node5 ba
// a v|
// node6 -> node2
// b a |^
// -> node4 ba
// b v|
// -> node3
//
// The dominator for all nodes is node6.
v8::HandleScope scope;
LocalContext env;
CompileRun(
"function X(a, b) { this.a = a; this.b = b; }\n"
"node6 = new X(new X(new X()), new X(new X(),new X()));\n"
"(function(){\n"
"node6.a.a.b = node6.b.a; // node1 -> node2\n"
"node6.b.a.a = node6.a.a; // node2 -> node1\n"
"node6.b.a.b = node6.b.b; // node2 -> node3\n"
"node6.b.b.a = node6.b.a; // node3 -> node2\n"
"})();");
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8::String::New("dominators"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
CHECK_NE(NULL, global);
const v8::HeapGraphNode* node6 =
GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6");
CHECK_NE(NULL, node6);
const v8::HeapGraphNode* node5 =
GetProperty(node6, v8::HeapGraphEdge::kProperty, "a");
CHECK_NE(NULL, node5);
const v8::HeapGraphNode* node4 =
GetProperty(node6, v8::HeapGraphEdge::kProperty, "b");
CHECK_NE(NULL, node4);
const v8::HeapGraphNode* node3 =
GetProperty(node4, v8::HeapGraphEdge::kProperty, "b");
CHECK_NE(NULL, node3);
const v8::HeapGraphNode* node2 =
GetProperty(node4, v8::HeapGraphEdge::kProperty, "a");
CHECK_NE(NULL, node2);
const v8::HeapGraphNode* node1 =
GetProperty(node5, v8::HeapGraphEdge::kProperty, "a");
CHECK_NE(NULL, node1);
CHECK_EQ(node6, node1->GetDominatorNode());
CHECK_EQ(node6, node2->GetDominatorNode());
CHECK_EQ(node6, node3->GetDominatorNode());
CHECK_EQ(node6, node4->GetDominatorNode());
CHECK_EQ(node6, node5->GetDominatorNode());
}
namespace {
class TestJSONStream : public v8::OutputStream {
@ -1073,13 +1102,9 @@ TEST(HeapSnapshotJSONSerialization) {
CHECK(parsed_snapshot->Has(v8::String::New("nodes")));
CHECK(parsed_snapshot->Has(v8::String::New("strings")));
// Verify that nodes meta-info is valid JSON.
v8::Local<v8::Value> nodes_meta_parse_result = CompileRun(
"var parsed_meta = JSON.parse(parsed.nodes[0]); true;");
CHECK(!nodes_meta_parse_result.IsEmpty());
// Get node and edge "member" offsets.
v8::Local<v8::Value> meta_analysis_result = CompileRun(
"var parsed_meta = parsed.nodes[0];\n"
"var children_count_offset ="
" parsed_meta.fields.indexOf('children_count');\n"
"var children_offset ="
@ -1094,19 +1119,21 @@ TEST(HeapSnapshotJSONSerialization) {
"var child_to_node_offset ="
" children_meta.fields.indexOf('to_node');\n"
"var property_type ="
" children_meta.types[child_type_offset].indexOf('property');");
" children_meta.types[child_type_offset].indexOf('property');\n"
"var shortcut_type ="
" children_meta.types[child_type_offset].indexOf('shortcut');");
CHECK(!meta_analysis_result.IsEmpty());
// A helper function for processing encoded nodes.
CompileRun(
"function GetChildPosByProperty(pos, prop_name) {\n"
"function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
" var nodes = parsed.nodes;\n"
" var strings = parsed.strings;\n"
" for (var i = 0,\n"
" count = nodes[pos + children_count_offset] * child_fields_count;\n"
" i < count; i += child_fields_count) {\n"
" var child_pos = pos + children_offset + i;\n"
" if (nodes[child_pos + child_type_offset] === property_type\n"
" if (nodes[child_pos + child_type_offset] === prop_type\n"
" && strings[nodes[child_pos + child_name_offset]] === prop_name)\n"
" return nodes[child_pos + child_to_node_offset];\n"
" }\n"
@ -1117,9 +1144,10 @@ TEST(HeapSnapshotJSONSerialization) {
"GetChildPosByProperty(\n"
" GetChildPosByProperty(\n"
" GetChildPosByProperty("
" parsed.nodes[1 + children_offset + child_to_node_offset],\"b\"),\n"
" \"x\"),"
" \"s\")");
" parsed.nodes[1 + children_offset + child_to_node_offset],"
" \"b\",shortcut_type),\n"
" \"x\", property_type),"
" \"s\", property_type)");
CHECK(!string_obj_pos_val.IsEmpty());
int string_obj_pos =
static_cast<int>(string_obj_pos_val->ToNumber()->Value());

8
deps/v8/test/cctest/test-parsing.cc

@ -36,7 +36,6 @@
#include "parser.h"
#include "utils.h"
#include "execution.h"
#include "scanner.h"
#include "preparser.h"
#include "cctest.h"
@ -262,9 +261,10 @@ TEST(StandAlonePreParser) {
const char* program = programs[i];
unibrow::Utf8InputBuffer<256> stream(program, strlen(program));
i::CompleteParserRecorder log;
i::Scanner scanner;
scanner.Initialize(i::Handle<i::String>::null(), &stream, i::JAVASCRIPT);
v8::preparser::PreParser<i::Scanner, i::CompleteParserRecorder> preparser;
i::V8JavaScriptScanner scanner;
scanner.Initialize(i::Handle<i::String>::null(), &stream);
v8::preparser::PreParser<i::V8JavaScriptScanner,
i::CompleteParserRecorder> preparser;
bool result = preparser.PreParseProgram(&scanner, &log, true);
CHECK(result);
i::ScriptDataImpl data(log.ExtractData());

38
deps/v8/test/mjsunit/compiler/literals.js

@ -34,6 +34,43 @@ assertEquals("abc", eval("'abc'"));
assertEquals(8, eval("6;'abc';8"));
// Characters just outside the ranges of hex-escapes.
// "/" comes just before "0".
assertEquals("x1/", "\x1/");
assertEquals("u111/", "\u111/");
assertEquals("\\x1/", RegExp("\\x1/").source);
assertEquals("\\u111/", RegExp("\\u111/").source);
// ":" comes just after "9".
assertEquals("x1:", "\x1:");
assertEquals("u111:", "\u111:");
assertEquals("\\x1:", /\x1:/.source);
assertEquals("\\u111:", /\u111:/.source);
// "`" comes just before "a".
assertEquals("x1`", "\x1`");
assertEquals("u111`", "\u111`");
assertEquals("\\x1`", /\x1`/.source);
assertEquals("\\u111`", /\u111`/.source);
// "g" comes just before "f".
assertEquals("x1g", "\x1g");
assertEquals("u111g", "\u111g");
assertEquals("\\x1g", /\x1g/.source);
assertEquals("\\u111g", /\u111g/.source);
// "@" comes just before "A".
assertEquals("x1@", "\x1@");
assertEquals("u111@", "\u111@");
assertEquals("\\x1@", /\x1@/.source);
assertEquals("\\u111@", /\u111@/.source);
// "G" comes just after "F".
assertEquals("x1G", "\x1G");
assertEquals("u111G", "\u111G");
assertEquals("\\x1G", /\x1G/.source);
assertEquals("\\u111G", /\u111G/.source);
// Test some materialized array literals.
assertEquals([1,2,3,4], eval('[1,2,3,4]'));
assertEquals([[1,2],3,4], eval('[[1,2],3,4]'));
@ -50,3 +87,4 @@ assertEquals([2,4,6,8], eval(s));
assertEquals(17, eval('[1,2,3,4]; 17'));
assertEquals(19, eval('var a=1, b=2; [a,b,3,4]; 19'));
assertEquals(23, eval('var a=1, b=2; c=23; [a,b,3,4]; c'));

7
deps/v8/tools/gyp/v8.gyp

@ -333,7 +333,6 @@
'../../src/disassembler.h',
'../../src/dtoa.cc',
'../../src/dtoa.h',
'../../src/dtoa-config.c',
'../../src/diy-fp.cc',
'../../src/diy-fp.h',
'../../src/double.h',
@ -657,11 +656,7 @@
'../../src/platform-win32.cc',
],
# 4355, 4800 came from common.vsprops
# 4018, 4244 were a per file config on dtoa-config.c
# TODO: It's probably possible and desirable to stop disabling the
# dtoa-specific warnings by modifying dtoa as was done in Chromium
# r9255. Refer to that revision for details.
'msvs_disabled_warnings': [4355, 4800, 4018, 4244],
'msvs_disabled_warnings': [4355, 4800],
'link_settings': {
'libraries': [ '-lwinmm.lib' ],
},

3
deps/v8/tools/visual_studio/README.txt

@ -7,8 +7,7 @@ be performed by Visual Studio.
v8_base.vcproj
--------------
Base V8 library containing all the V8 code but no JavaScript library code. This
includes third party code for string/number convertions (dtoa).
Base V8 library containing all the V8 code but no JavaScript library code.
v8.vcproj
---------

92
deps/v8/tools/visual_studio/v8_base.vcproj

@ -121,70 +121,6 @@
<References>
</References>
<Files>
<Filter
Name="dtoa"
>
<File
RelativePath="..\..\src\dtoa-config.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
DisableSpecificWarnings="4018;4244"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
DisableSpecificWarnings="4018;4244"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\bignum.cc"
>
</File>
<File
RelativePath="..\..\src\bignum.h"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\dtoa.h"
>
</File>
<File
RelativePath="..\..\src\fast-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\fast-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\fixed-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\fixed-dtoa.h"
>
</File>
</Filter>
<Filter
Name="src"
>
@ -296,6 +232,10 @@
RelativePath="..\..\src\bytecodes-irregexp.h"
>
</File>
<File
RelativePath="..\..\src\cached-powers.cc"
>
</File>
<File
RelativePath="..\..\src\cached-powers.h"
>
@ -488,6 +428,14 @@
RelativePath="..\..\src\double.h"
>
</File>
<File
RelativePath="..\..\src\dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\dtoa.h"
>
</File>
<File
RelativePath="..\..\src\execution.cc"
>
@ -512,6 +460,14 @@
RelativePath="..\..\src\fast-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\fixed-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\fixed-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\flags.cc"
>
@ -993,6 +949,14 @@
RelativePath="..\..\src\string-stream.h"
>
</File>
<File
RelativePath="..\..\src\strtod.cc"
>
</File>
<File
RelativePath="..\..\src\strtod.h"
>
</File>
<File
RelativePath="..\..\src\ia32\stub-cache-ia32.cc"
>

92
deps/v8/tools/visual_studio/v8_base_arm.vcproj

@ -121,30 +121,6 @@
<References>
</References>
<Files>
<Filter
Name="dtoa"
>
<File
RelativePath="..\..\src\dtoa-config.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
DisableSpecificWarnings="4018;4244"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
DisableSpecificWarnings="4018;4244"
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="src"
>
@ -228,6 +204,22 @@
RelativePath="..\..\src\arm\builtins-arm.cc"
>
</File>
<File
RelativePath="..\..\src\bignum.cc"
>
</File>
<File
RelativePath="..\..\src\bignum.h"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\builtins.cc"
>
@ -240,6 +232,14 @@
RelativePath="..\..\src\bytecodes-irregexp.h"
>
</File>
<File
RelativePath="..\..\src\cached-powers.cc"
>
</File>
<File
RelativePath="..\..\src\cached-powers.h"
>
</File>
<File
RelativePath="..\..\src\char-predicates-inl.h"
>
@ -424,6 +424,26 @@
RelativePath="..\..\src\disassembler.h"
>
</File>
<File
RelativePath="..\..\src\diy-fp.cc"
>
</File>
<File
RelativePath="..\..\src\diy-fp.h"
>
</File>
<File
RelativePath="..\..\src\double.h"
>
</File>
<File
RelativePath="..\..\src\dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\dtoa.h"
>
</File>
<File
RelativePath="..\..\src\execution.cc"
>
@ -440,6 +460,22 @@
RelativePath="..\..\src\factory.h"
>
</File>
<File
RelativePath="..\..\src\fast-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\fast-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\fixed-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\fixed-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\flags.cc"
>
@ -927,6 +963,14 @@
RelativePath="..\..\src\string-stream.h"
>
</File>
<File
RelativePath="..\..\src\strtod.cc"
>
</File>
<File
RelativePath="..\..\src\strtod.h"
>
</File>
<File
RelativePath="..\..\src\arm\stub-cache-arm.cc"
>

92
deps/v8/tools/visual_studio/v8_base_x64.vcproj

@ -121,30 +121,6 @@
<References>
</References>
<Files>
<Filter
Name="dtoa"
>
<File
RelativePath="..\..\src\dtoa-config.c"
>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
DisableSpecificWarnings="4018;4244"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
DisableSpecificWarnings="4018;4244"
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="src"
>
@ -216,6 +192,22 @@
RelativePath="..\..\src\ast.h"
>
</File>
<File
RelativePath="..\..\src\bignum.cc"
>
</File>
<File
RelativePath="..\..\src\bignum.h"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\bootstrapper.cc"
>
@ -240,6 +232,14 @@
RelativePath="..\..\src\bytecodes-irregexp.h"
>
</File>
<File
RelativePath="..\..\src\cached-powers.cc"
>
</File>
<File
RelativePath="..\..\src\cached-powers.h"
>
</File>
<File
RelativePath="..\..\src\char-predicates-inl.h"
>
@ -416,6 +416,26 @@
RelativePath="..\..\src\disassembler.h"
>
</File>
<File
RelativePath="..\..\src\diy-fp.cc"
>
</File>
<File
RelativePath="..\..\src\diy-fp.h"
>
</File>
<File
RelativePath="..\..\src\double.h"
>
</File>
<File
RelativePath="..\..\src\dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\dtoa.h"
>
</File>
<File
RelativePath="..\..\src\execution.cc"
>
@ -432,6 +452,22 @@
RelativePath="..\..\src\factory.h"
>
</File>
<File
RelativePath="..\..\src\fast-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\fast-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\fixed-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\fixed-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\flags.cc"
>
@ -913,6 +949,14 @@
RelativePath="..\..\src\string-stream.h"
>
</File>
<File
RelativePath="..\..\src\strtod.cc"
>
</File>
<File
RelativePath="..\..\src\strtod.h"
>
</File>
<File
RelativePath="..\..\src\x64\stub-cache-x64.cc"
>

Loading…
Cancel
Save