Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Version 2.5.8

Removed dependency on Gay's dtoa.

Improved heap profiler precision and speed.

Reduced overhead of callback invocations on ARM.


git-svn-id: https://v8.googlecode.com/svn/trunk@5874 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
  • Loading branch information...
commit 8211e79dfca7f01d69d548a13579f2ace2772aea 1 parent 91ff7be
vegorov@chromium.org authored
Showing with 3,148 additions and 6,407 deletions.
  1. +9 −0 ChangeLog
  2. +0 −3  LICENSE
  3. +22 −7 include/v8-profiler.h
  4. +13 −1 samples/shell.cc
  5. +1 −7 src/SConscript
  6. +10 −8 src/api.cc
  7. +3 −0  src/apiutils.h
  8. +3 −2 src/arm/code-stubs-arm.cc
  9. +20 −5 src/arm/codegen-arm.cc
  10. +3 −1 src/arm/codegen-arm.h
  11. +16 −4 src/arm/full-codegen-arm.cc
  12. +199 −36 src/arm/stub-cache-arm.cc
  13. +4 −0 src/array.js
  14. +6 −1 src/ast.h
  15. +7 −14 src/builtins.cc
  16. +0 −10 src/conversions.cc
  17. +0 −5 src/conversions.h
  18. +0 −92 src/dtoa-config.c
  19. +3 −3 src/full-codegen.cc
  20. +1 −1  src/full-codegen.h
  21. +37 −29 src/handles.cc
  22. +11 −5 src/heap-profiler.cc
  23. +2 −1  src/ia32/code-stubs-ia32.cc
  24. +195 −5 src/ia32/codegen-ia32.cc
  25. +3 −1 src/ia32/codegen-ia32.h
  26. +193 −3 src/ia32/full-codegen-ia32.cc
  27. +51 −0 src/ia32/macro-assembler-ia32.cc
  28. +17 −0 src/ia32/macro-assembler-ia32.h
  29. +7 −8 src/ia32/stub-cache-ia32.cc
  30. +23 −46 src/parser.cc
  31. +9 −7 src/parser.h
  32. +2 −2 src/preparser.h
  33. +0 −1,098 src/prescanner.h
  34. +25 −18 src/profile-generator-inl.h
  35. +492 −254 src/profile-generator.cc
  36. +111 −74 src/profile-generator.h
  37. +10 −5 src/runtime.cc
  38. +3 −2 src/runtime.h
  39. +731 −3 src/scanner-base.cc
  40. +360 −13 src/scanner-base.h
  41. +82 −786 src/scanner.cc
  42. +44 −259 src/scanner.h
  43. +2 −5 src/stub-cache.cc
  44. +0 −15 src/third_party/dtoa/COPYING
  45. +0 −3,331 src/third_party/dtoa/dtoa.c
  46. +2 −0  src/utils.h
  47. +1 −1  src/version.cc
  48. +2 −1  src/x64/code-stubs-x64.cc
  49. +16 −5 src/x64/codegen-x64.cc
  50. +3 −1 src/x64/codegen-x64.h
  51. +12 −3 src/x64/full-codegen-x64.cc
  52. +1 −1  src/x64/stub-cache-x64.cc
  53. +5 −3 test/cctest/test-api.cc
  54. +5 −8 test/cctest/test-conversions.cc
  55. +56 −11 test/cctest/test-debug.cc
  56. +107 −79 test/cctest/test-heap-profiler.cc
  57. +4 −4 test/cctest/test-parsing.cc
  58. +38 −0 test/mjsunit/compiler/literals.js
  59. +1 −6 tools/gyp/v8.gyp
  60. +1 −2  tools/visual_studio/README.txt
  61. +28 −64 tools/visual_studio/v8_base.vcproj
  62. +68 −24 tools/visual_studio/v8_base_arm.vcproj
  63. +68 −24 tools/visual_studio/v8_base_x64.vcproj
View
9 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).
View
3  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.
View
29 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;
};
View
14 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,7 +54,8 @@ 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));
- // Bind the global 'read' function to the C++ Read callback.
+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.
global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
@@ -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.
View
8 src/SConscript
@@ -297,14 +297,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
View
18 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 =
View
3  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);
}
View
5 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);
}
View
25 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();
View
4 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 {
View
20 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) == '_') {
View
235 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);
- __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
- argc + 1,
- 1);
+ 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);
View
4 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);
}
View
7 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
View
21 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;
View
10 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
View
5 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 {
View
92 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"
View
6 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);
}
View
2  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.
View
66 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;
View
16 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(),
View
3  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);
}
View
200 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));
View
4 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 {
View
196 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) == '_') {
View
51 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,
View
17 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.
View
15 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,9 +1141,8 @@ 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);
+ CheckPrototypes(object, receiver, holder,
+ scratch1, scratch2, scratch3, name, miss);
// Return the constant value.
__ mov(eax, Handle<Object>(value));
@@ -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.
View
69 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);
}
View
16 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
View
4 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) {
View
1,098 src/prescanner.h
@@ -1,1098 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef V8_PRESCANNER_H_
-#define V8_PRESCANNER_H_
-
-#include "token.h"
-#include "char-predicates-inl.h"
-#include "utils.h"
-#include "scanner-base.h"
-
-namespace v8 {
-namespace preparser {
-
-namespace i = v8::internal;
-
-typedef int uc32;
-
-int HexValue(uc32 c) {
- int res = c | 0x20; // Uppercase letters.
- int is_digit = (c & 0x10) >> 4; // 0 if non-digit, 1 if digit.
- // What to add to digits to make them consecutive with 'a'-'f' letters.
- int kDelta = 'a' - '9' - 1;
- // What to subtract to digits and letters to get them back to the range 0..15.
- int kStart = '0' + kDelta;
- res -= kStart;
- res += kDelta * is_digit;
- return res;
-}
-
-
-class PreScannerStackGuard {
- public:
- explicit PreScannerStackGuard(int max_size)
- : limit_(StackPoint().at() - max_size) { }
- bool has_overflowed() {
- return StackPoint().at() < limit_;
- }
- private:
- class StackPoint {
- public:
- char* at() { return reinterpret_cast<char*>(this); }
- };
- char* limit_;
-};
-
-
-// Scanner for preparsing.
-// InputStream is a source of UC16 characters with limited push-back.
-// LiteralsBuffer is a collector of (UTF-8) characters used to capture literals.
-template <typename InputStream, typename LiteralsBuffer>
-class Scanner {
- public:
- enum LiteralType {
- kLiteralNumber,
- kLiteralIdentifier,
- kLiteralString,
- kLiteralRegExp,
- kLiteralRegExpFlags
- };
-
- class LiteralScope {
- public:
- explicit LiteralScope(Scanner* self, LiteralType type);
- ~LiteralScope();
- void Complete();
-
- private:
- Scanner* scanner_;
- bool complete_;
- };
-
- Scanner();
-
- void Initialize(InputStream* stream);
-
- // Returns the next token.
- i::Token::Value Next();
-
- // Returns the current token again.
- i::Token::Value current_token() { return current_.token; }
-
- // One token look-ahead (past the token returned by Next()).
- i::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;
- };
-
- // Returns the location information for the current token
- // (the token returned by Next()).
- Location location() const { return current_.location; }
- // Returns the location information for the look-ahead token
- // (the token returned by peek()).
- 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;
- }
-
- int literal_length() const {
- // Excluding terminal '\x00' added by TerminateLiteral().
- return current_.literal_length - 1;
- }
-
- i::Vector<const char> literal() const {
- return i::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;
- }
-
-
- // 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_length - 1;
- }
-
- i::Vector<const char> next_literal() const {
- return i::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_; }
-
- static const int kCharacterLookaheadBufferSize = 1;
- static const int kNoEndPosition = 1;
-
- private:
- // The current and look-ahead token.
- struct TokenDesc {
- i::Token::Value token;
- Location location;
- const char* literal_chars;
- int literal_length;
- };
-
- // Default stack limit is 128K pointers.
- static const int kMaxStackSize = 128 * 1024 * sizeof(void*); // NOLINT.
-
- void Init(unibrow::CharacterStream* stream);
-
- // Literal buffer support
- inline void StartLiteral(LiteralType type);
- 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;
- }
-
- bool SkipWhiteSpace();
-
- i::Token::Value SkipSingleLineComment();
- i::Token::Value SkipMultiLineComment();
-
- inline i::Token::Value Select(i::Token::Value tok);
- inline i::Token::Value Select(uc32 next,
- i::Token::Value then,
- i::Token::Value else_);
-
- // Scans a single JavaScript token.
- void Scan();
-
- void ScanDecimalDigits();
- i::Token::Value ScanNumber(bool seen_period);
- i::Token::Value ScanIdentifier();
- uc32 ScanHexEscape(uc32 c, int length);
- uc32 ScanOctalEscape(uc32 c, int length);
- void ScanEscape();
- i::Token::Value ScanString();
-
- // Scans a possible HTML comment -- begins with '<!'.
- i::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();
-
- PreScannerStackGuard stack_guard_;
-
- 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_;
-
- // Source.
- InputStream* source_;
-
- // Buffer to hold literal values (identifiers, strings, numerals, regexps and
- // regexp flags) using '\x00'-terminated UTF-8 encoding.
- // Handles allocation internally.
- // Notice that the '\x00' termination is meaningless for strings and regexps
- // which may contain the zero-character, but can be used as terminator for
- // identifiers, numerals and regexp flags.
- LiteralsBuffer literal_buffer_;
-
- bool stack_overflow_;
-
- // One Unicode character look-ahead; c0_ < 0 at the end of the input.
- uc32 c0_;
-};
-
-
-// ----------------------------------------------------------------------------
-// Scanner::LiteralScope
-
-template <typename InputStream, typename LiteralsBuffer>
-Scanner<InputStream, LiteralsBuffer>::LiteralScope::LiteralScope(
- Scanner* self, LiteralType type)
- : scanner_(self), complete_(false) {
- self->StartLiteral(type);
-}
-
-
-template <typename InputStream, typename LiteralsBuffer>
-Scanner<InputStream, LiteralsBuffer>::LiteralScope::~LiteralScope() {
- if (!complete_) scanner_->DropLiteral();
-}
-
-template <typename InputStream, typename LiteralsBuffer>
-void Scanner<InputStream, LiteralsBuffer>::LiteralScope::Complete() {
- scanner_->TerminateLiteral();
- complete_ = true;
-}
-
-
-// ----------------------------------------------------------------------------
-// Scanner.
-template <typename InputStream, typename LiteralsBuffer>
-Scanner<InputStream, LiteralsBuffer>::Scanner()
- : stack_guard_(kMaxStackSize),
- has_line_terminator_before_next_(false),
- source_(NULL),
- stack_overflow_(false) {}
-
-
-template <typename InputStream, typename LiteralsBuffer>
-void Scanner<InputStream, LiteralsBuffer>::Initialize(InputStream* stream) {
- source_ = stream;
-
- // Initialize current_ to not refer to a literal.
- current_.literal_length = 0;
- // Reset literal buffer.
- literal_buffer_.Reset();
-
- // Set c0_ (one character ahead)
- ASSERT(kCharacterLookaheadBufferSize == 1);
- Advance();
-
- // Skip initial whitespace allowing HTML comment ends just like
- // after a newline and scan first token.
- has_line_terminator_before_next_ = true;
- SkipWhiteSpace();
- Scan();
-}
-
-
-template <typename InputStream, typename LiteralsBuffer>
-i::Token::Value Scanner<InputStream, LiteralsBuffer>::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.
- current_ = next_;
- // Check for stack-overflow before returning any tokens.
- if (stack_guard_.has_overflowed()) {
- stack_overflow_ = true;
- next_.token = i::Token::ILLEGAL;
- } else {
- has_line_terminator_before_next_ = false;
- Scan();
- }
- return current_.token;
-}
-
-
-template <typename In