Update V8 to r6101 as required by WebKit r74534
Change-Id: I7f84af8dd732f11898fd644b2c2b1538914cb78d
diff --git a/src/accessors.cc b/src/accessors.cc
index 08ef41b..43d54fe 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -28,8 +28,11 @@
#include "v8.h"
#include "accessors.h"
+#include "ast.h"
+#include "deoptimizer.h"
#include "execution.h"
#include "factory.h"
+#include "safepoint-table.h"
#include "scopeinfo.h"
#include "top.h"
@@ -503,11 +506,9 @@
// If the function isn't compiled yet, the length is not computed
// correctly yet. Compile it now and return the right length.
HandleScope scope;
- Handle<SharedFunctionInfo> shared(function->shared());
- if (!CompileLazyShared(shared, KEEP_EXCEPTION)) {
- return Failure::Exception();
- }
- return Smi::FromInt(shared->length());
+ Handle<JSFunction> handle(function);
+ if (!CompileLazy(handle, KEEP_EXCEPTION)) return Failure::Exception();
+ return Smi::FromInt(handle->shared()->length());
} else {
return Smi::FromInt(function->shared()->length());
}
@@ -545,6 +546,208 @@
// Accessors::FunctionArguments
//
+static Address SlotAddress(JavaScriptFrame* frame, int slot_index) {
+ if (slot_index >= 0) {
+ const int offset = JavaScriptFrameConstants::kLocal0Offset;
+ return frame->fp() + offset - (slot_index * kPointerSize);
+ } else {
+ const int offset = JavaScriptFrameConstants::kReceiverOffset;
+ return frame->caller_sp() + offset + (slot_index * kPointerSize);
+ }
+}
+
+
+// We can't intermix stack decoding and allocations because
+// deoptimization infrastracture is not GC safe.
+// Thus we build a temporary structure in malloced space.
+class SlotRef BASE_EMBEDDED {
+ public:
+ enum SlotRepresentation {
+ UNKNOWN,
+ TAGGED,
+ INT32,
+ DOUBLE,
+ LITERAL
+ };
+
+ SlotRef()
+ : addr_(NULL), representation_(UNKNOWN) { }
+
+ SlotRef(Address addr, SlotRepresentation representation)
+ : addr_(addr), representation_(representation) { }
+
+ explicit SlotRef(Object* literal)
+ : literal_(literal), representation_(LITERAL) { }
+
+ Handle<Object> GetValue() {
+ switch (representation_) {
+ case TAGGED:
+ return Handle<Object>(Memory::Object_at(addr_));
+
+ case INT32: {
+ int value = Memory::int32_at(addr_);
+ if (Smi::IsValid(value)) {
+ return Handle<Object>(Smi::FromInt(value));
+ } else {
+ return Factory::NewNumberFromInt(value);
+ }
+ }
+
+ case DOUBLE: {
+ double value = Memory::double_at(addr_);
+ return Factory::NewNumber(value);
+ }
+
+ case LITERAL:
+ return literal_;
+
+ default:
+ UNREACHABLE();
+ return Handle<Object>::null();
+ }
+ }
+
+ private:
+ Address addr_;
+ Handle<Object> literal_;
+ SlotRepresentation representation_;
+};
+
+
+static SlotRef ComputeSlotForNextArgument(TranslationIterator* iterator,
+ DeoptimizationInputData* data,
+ JavaScriptFrame* frame) {
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+
+ switch (opcode) {
+ case Translation::BEGIN:
+ case Translation::FRAME:
+ // Peeled off before getting here.
+ break;
+
+ case Translation::ARGUMENTS_OBJECT:
+ // This can be only emitted for local slots not for argument slots.
+ break;
+
+ case Translation::REGISTER:
+ case Translation::INT32_REGISTER:
+ case Translation::DOUBLE_REGISTER:
+ case Translation::DUPLICATE:
+ // We are at safepoint which corresponds to call. All registers are
+ // saved by caller so there would be no live registers at this
+ // point. Thus these translation commands should not be used.
+ break;
+
+ case Translation::STACK_SLOT: {
+ int slot_index = iterator->Next();
+ Address slot_addr = SlotAddress(frame, slot_index);
+ return SlotRef(slot_addr, SlotRef::TAGGED);
+ }
+
+ case Translation::INT32_STACK_SLOT: {
+ int slot_index = iterator->Next();
+ Address slot_addr = SlotAddress(frame, slot_index);
+ return SlotRef(slot_addr, SlotRef::INT32);
+ }
+
+ case Translation::DOUBLE_STACK_SLOT: {
+ int slot_index = iterator->Next();
+ Address slot_addr = SlotAddress(frame, slot_index);
+ return SlotRef(slot_addr, SlotRef::DOUBLE);
+ }
+
+ case Translation::LITERAL: {
+ int literal_index = iterator->Next();
+ return SlotRef(data->LiteralArray()->get(literal_index));
+ }
+ }
+
+ UNREACHABLE();
+ return SlotRef();
+}
+
+
+
+
+
+static void ComputeSlotMappingForArguments(JavaScriptFrame* frame,
+ int inlined_frame_index,
+ Vector<SlotRef>* args_slots) {
+ AssertNoAllocation no_gc;
+
+ int deopt_index = AstNode::kNoNumber;
+
+ DeoptimizationInputData* data =
+ static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
+
+ TranslationIterator it(data->TranslationByteArray(),
+ data->TranslationIndex(deopt_index)->value());
+
+ Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
+ ASSERT(opcode == Translation::BEGIN);
+ int frame_count = it.Next();
+
+ USE(frame_count);
+ ASSERT(frame_count > inlined_frame_index);
+
+ int frames_to_skip = inlined_frame_index;
+ while (true) {
+ opcode = static_cast<Translation::Opcode>(it.Next());
+
+ // Skip over operands to advance to the next opcode.
+ it.Skip(Translation::NumberOfOperandsFor(opcode));
+
+ if (opcode == Translation::FRAME) {
+ if (frames_to_skip == 0) {
+ // We reached frame corresponding to inlined function in question.
+ // Process translation commands for arguments.
+
+ // Skip translation command for receiver.
+ it.Skip(Translation::NumberOfOperandsFor(
+ static_cast<Translation::Opcode>(it.Next())));
+
+ // Compute slots for arguments.
+ for (int i = 0; i < args_slots->length(); ++i) {
+ (*args_slots)[i] = ComputeSlotForNextArgument(&it, data, frame);
+ }
+
+ return;
+ }
+
+ frames_to_skip--;
+ }
+ }
+
+ UNREACHABLE();
+}
+
+
+static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
+ JavaScriptFrame* frame,
+ Handle<JSFunction> inlined_function,
+ int inlined_frame_index) {
+
+ int args_count = inlined_function->shared()->formal_parameter_count();
+
+ ScopedVector<SlotRef> args_slots(args_count);
+
+ ComputeSlotMappingForArguments(frame, inlined_frame_index, &args_slots);
+
+ Handle<JSObject> arguments =
+ Factory::NewArgumentsObject(inlined_function, args_count);
+
+ Handle<FixedArray> array = Factory::NewFixedArray(args_count);
+ for (int i = 0; i < args_count; ++i) {
+ Handle<Object> value = args_slots[i].GetValue();
+ array->set(i, *value);
+ }
+ arguments->set_elements(*array);
+
+ // Return the freshly allocated arguments object.
+ return *arguments;
+}
+
MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
HandleScope scope;
@@ -554,38 +757,50 @@
Handle<JSFunction> function(holder);
// Find the top invocation of the function by traversing frames.
+ List<JSFunction*> functions(2);
for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
- // Skip all frames that aren't invocations of the given function.
JavaScriptFrame* frame = it.frame();
- if (frame->function() != *function) continue;
+ frame->GetFunctions(&functions);
+ for (int i = functions.length() - 1; i >= 0; i--) {
+ // Skip all frames that aren't invocations of the given function.
+ if (functions[i] != *function) continue;
- // If there is an arguments variable in the stack, we return that.
- int index = function->shared()->scope_info()->
- StackSlotIndex(Heap::arguments_symbol());
- if (index >= 0) {
- Handle<Object> arguments = Handle<Object>(frame->GetExpression(index));
- if (!arguments->IsTheHole()) return *arguments;
+ if (i > 0) {
+ // Function in question was inlined.
+ return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
+ } else {
+ // If there is an arguments variable in the stack, we return that.
+ int index = function->shared()->scope_info()->
+ StackSlotIndex(Heap::arguments_symbol());
+ if (index >= 0) {
+ Handle<Object> arguments =
+ Handle<Object>(frame->GetExpression(index));
+ if (!arguments->IsTheHole()) return *arguments;
+ }
+
+ // If there isn't an arguments variable in the stack, we need to
+ // find the frame that holds the actual arguments passed to the
+ // function on the stack.
+ it.AdvanceToArgumentsFrame();
+ frame = it.frame();
+
+ // Get the number of arguments and construct an arguments object
+ // mirror for the right frame.
+ const int length = frame->GetProvidedParametersCount();
+ Handle<JSObject> arguments = Factory::NewArgumentsObject(function,
+ length);
+ Handle<FixedArray> array = Factory::NewFixedArray(length);
+
+ // Copy the parameters to the arguments object.
+ ASSERT(array->length() == length);
+ for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
+ arguments->set_elements(*array);
+
+ // Return the freshly allocated arguments object.
+ return *arguments;
+ }
}
-
- // If there isn't an arguments variable in the stack, we need to
- // find the frame that holds the actual arguments passed to the
- // function on the stack.
- it.AdvanceToArgumentsFrame();
- frame = it.frame();
-
- // Get the number of arguments and construct an arguments object
- // mirror for the right frame.
- const int length = frame->GetProvidedParametersCount();
- Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
- Handle<FixedArray> array = Factory::NewFixedArray(length);
-
- // Copy the parameters to the arguments object.
- ASSERT(array->length() == length);
- for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
- arguments->set_elements(*array);
-
- // Return the freshly allocated arguments object.
- return *arguments;
+ functions.Rewind(0);
}
// No frame corresponding to the given function found. Return null.
@@ -613,19 +828,34 @@
if (!found_it) return Heap::undefined_value();
Handle<JSFunction> function(holder);
- // Find the top invocation of the function by traversing frames.
+ List<JSFunction*> functions(2);
for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
- // Skip all frames that aren't invocations of the given function.
- if (it.frame()->function() != *function) continue;
- // Once we have found the frame, we need to go to the caller
- // frame. This may require skipping through a number of top-level
- // frames, e.g. frames for scripts not functions.
- while (true) {
- it.Advance();
- if (it.done()) return Heap::null_value();
- JSFunction* caller = JSFunction::cast(it.frame()->function());
- if (!caller->shared()->is_toplevel()) return caller;
+ JavaScriptFrame* frame = it.frame();
+ frame->GetFunctions(&functions);
+ for (int i = functions.length() - 1; i >= 0; i--) {
+ if (functions[i] == *function) {
+ // Once we have found the frame, we need to go to the caller
+ // frame. This may require skipping through a number of top-level
+ // frames, e.g. frames for scripts not functions.
+ if (i > 0) {
+ ASSERT(!functions[i - 1]->shared()->is_toplevel());
+ return functions[i - 1];
+ } else {
+ for (it.Advance(); !it.done(); it.Advance()) {
+ frame = it.frame();
+ functions.Rewind(0);
+ frame->GetFunctions(&functions);
+ if (!functions.last()->shared()->is_toplevel()) {
+ return functions.last();
+ }
+ ASSERT(functions.length() == 1);
+ }
+ if (it.done()) return Heap::null_value();
+ break;
+ }
+ }
}
+ functions.Rewind(0);
}
// No frame corresponding to the given function found. Return null.