// 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 Isolate::Current()->factory()->NewNumberFromInt(value);
- }
- }
-
- case DOUBLE: {
- double value = Memory::double_at(addr_);
- return Isolate::Current()->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 the frame corresponding to the inlined function
- // in question. Process the translation commands for the
- // arguments.
- //
- // Skip the translation command for the 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,
Factory* factory = Isolate::Current()->factory();
int args_count = inlined_function->shared()->formal_parameter_count();
ScopedVector<SlotRef> args_slots(args_count);
- ComputeSlotMappingForArguments(frame, inlined_frame_index, &args_slots);
+ SlotRef::ComputeSlotMappingForArguments(frame,
+ inlined_frame_index,
+ &args_slots);
Handle<JSObject> arguments =
factory->NewArgumentsObject(inlined_function, args_count);
Handle<FixedArray> array = factory->NewFixedArray(args_count);
public:
// FP-relative.
static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
- static const int kSavedRegistersOffset = +2 * kPointerSize;
+ static const int kLastParameterOffset = +2 * kPointerSize;
static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
// Caller SP-relative.
}
+// We can't intermix stack decoding and allocations because
+// deoptimization infrastracture is not GC safe.
+// Thus we build a temporary structure in malloced space.
+SlotRef 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();
+}
+
+
+void SlotRef::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 the frame corresponding to the inlined function
+ // in question. Process the translation commands for the
+ // arguments.
+ //
+ // Skip the translation command for the 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();
+}
+
+
} } // namespace v8::internal
};
+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 Isolate::Current()->factory()->NewNumberFromInt(value);
+ }
+ }
+
+ case DOUBLE: {
+ double value = Memory::double_at(addr_);
+ return Isolate::Current()->factory()->NewNumber(value);
+ }
+
+ case LITERAL:
+ return literal_;
+
+ default:
+ UNREACHABLE();
+ return Handle<Object>::null();
+ }
+ }
+
+ static void ComputeSlotMappingForArguments(JavaScriptFrame* frame,
+ int inlined_frame_index,
+ Vector<SlotRef>* args_slots);
+
+ private:
+ Address addr_;
+ Handle<Object> literal_;
+ SlotRepresentation representation_;
+
+ 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::kLastParameterOffset;
+ return frame->fp() + offset - ((slot_index + 1) * kPointerSize);
+ }
+ }
+
+ static SlotRef ComputeSlotForNextArgument(TranslationIterator* iterator,
+ DeoptimizationInputData* data,
+ JavaScriptFrame* frame);
+};
+
+
} } // namespace v8::internal
#endif // V8_DEOPTIMIZER_H_
int JavaScriptFrame::ComputeParametersCount() const {
Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset;
- Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
+ Address limit = fp() + JavaScriptFrameConstants::kLastParameterOffset;
return static_cast<int>((base - limit) / kPointerSize);
}
void JavaScriptFrame::IterateArguments(ObjectVisitor* v) const {
// Traverse callee-saved registers, receiver, and parameters.
- const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
+ const int kBaseOffset = JavaScriptFrameConstants::kLastParameterOffset;
const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
Object** base = &Memory::Object_at(fp() + kBaseOffset);
Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1;
void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) {
if (FLAG_trace_inlining) {
- SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
- SmartPointer<char> caller =
- info()->function()->debug_name()->ToCString();
if (reason == NULL) {
+ // We are currently in the context of inlined function thus we have
+ // to go to an outer FunctionState to get caller.
+ SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
+ SmartPointer<char> caller =
+ function_state()->outer()->compilation_info()->function()->
+ debug_name()->ToCString();
PrintF("Inlined %s called from %s.\n", *callee, *caller);
} else {
+ SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
+ SmartPointer<char> caller =
+ info()->function()->debug_name()->ToCString();
PrintF("Did not inline %s called from %s (%s).\n",
*callee, *caller, reason);
}
// Support for construct call checks.
void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
ASSERT(call->arguments()->length() == 0);
- ast_context()->ReturnInstruction(new HIsConstructCall, call->id());
+ if (function_state()->outer() != NULL) {
+ // We are generating graph for inlined function. Currently
+ // constructor inlining is not supported and we can just return
+ // false from %_IsConstructCall().
+ ast_context()->ReturnValue(graph()->GetConstantFalse());
+ } else {
+ ast_context()->ReturnInstruction(new HIsConstructCall, call->id());
+ }
}
test_context_ = NULL;
}
+ FunctionState* outer() { return outer_; }
+
private:
HGraphBuilder* owner_;
public:
// FP-relative.
static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
- static const int kSavedRegistersOffset = +2 * kPointerSize;
+ static const int kLastParameterOffset = +2 * kPointerSize;
static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
// Caller SP-relative.
public:
// FP-relative.
static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
- static const int kSavedRegistersOffset = +2 * kPointerSize;
+ static const int kLastParameterOffset = +2 * kPointerSize;
static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
// Caller SP-relative.
return *result;
}
+
+static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
+ int* total_argc) {
+ // Find frame containing arguments passed to the caller.
+ JavaScriptFrameIterator it;
+ JavaScriptFrame* frame = it.frame();
+ List<JSFunction*> functions(2);
+ frame->GetFunctions(&functions);
+ if (functions.length() > 1) {
+ int inlined_frame_index = functions.length() - 1;
+ JSFunction* inlined_function = functions[inlined_frame_index];
+ int args_count = inlined_function->shared()->formal_parameter_count();
+ ScopedVector<SlotRef> args_slots(args_count);
+ SlotRef::ComputeSlotMappingForArguments(frame,
+ inlined_frame_index,
+ &args_slots);
+
+ *total_argc = bound_argc + args_count;
+ SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
+ for (int i = 0; i < args_count; i++) {
+ Handle<Object> val = args_slots[i].GetValue();
+ param_data[bound_argc + i] = val.location();
+ }
+ return param_data;
+ } else {
+ it.AdvanceToArgumentsFrame();
+ frame = it.frame();
+ int args_count = frame->ComputeParametersCount();
+
+ *total_argc = bound_argc + args_count;
+ SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
+ for (int i = 0; i < args_count; i++) {
+ Handle<Object> val = Handle<Object>(frame->GetParameter(i));
+ param_data[bound_argc + i] = val.location();
+ }
+ return param_data;
+ }
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
// Second argument is either null or an array of bound arguments.
- FixedArray* bound_args = NULL;
+ Handle<FixedArray> bound_args;
int bound_argc = 0;
if (!args[1]->IsNull()) {
CONVERT_ARG_CHECKED(JSArray, params, 1);
RUNTIME_ASSERT(params->HasFastElements());
- bound_args = FixedArray::cast(params->elements());
+ bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
bound_argc = Smi::cast(params->length())->value();
}
- // Find frame containing arguments passed to the caller.
- JavaScriptFrameIterator it;
- JavaScriptFrame* frame = it.frame();
- ASSERT(!frame->is_optimized());
- it.AdvanceToArgumentsFrame();
- frame = it.frame();
- int argc = frame->ComputeParametersCount();
-
- // Prepend bound arguments to caller's arguments.
- int total_argc = bound_argc + argc;
- SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
+ int total_argc = 0;
+ SmartPointer<Object**> param_data =
+ GetNonBoundArguments(bound_argc, &total_argc);
for (int i = 0; i < bound_argc; i++) {
Handle<Object> val = Handle<Object>(bound_args->get(i));
param_data[i] = val.location();
}
- for (int i = 0; i < argc; i++) {
- Handle<Object> val = Handle<Object>(frame->GetParameter(i));
- param_data[bound_argc + i] = val.location();
- }
bool exception = false;
Handle<Object> result =
public:
// FP-relative.
static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
- static const int kSavedRegistersOffset = +2 * kPointerSize;
+ static const int kLastParameterOffset = +2 * kPointerSize;
static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
// Caller SP-relative.
--- /dev/null
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * 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.
+
+// Flags: --allow-natives-syntax
+
+// Check that %NewObjectFromBound works correctly when called from optimized
+// frame.
+function foo(x, y, z) {
+ assertEquals(1, x);
+ assertEquals(2, y);
+ assertEquals(3, z);
+}
+
+var bound_arg = [1];
+
+function f(y, z) {
+ return %NewObjectFromBound(foo, bound_arg);
+}
+
+// Check that %NewObjectFromBound looks at correct frame for inlined function.
+function g(z, y) {
+ return f(y, z); /* f should be inlined into g, note rotated arguments */
+}
+
+// Check that %NewObjectFromBound looks at correct frame for inlined function.
+function ff(x) { }
+function h(z2, y2) {
+ var local_z = z2 >> 1;
+ ff(local_z);
+ var local_y = y2 >> 1;
+ ff(local_y);
+ return f(local_y, local_z); /* f should be inlined into h */
+}
+
+for (var i = 0; i < 100000; i++) f(2, 3);
+
+for (var i = 0; i < 100000; i++) g(3, 2);
+
+for (var i = 0; i < 100000; i++) h(6, 4);
+
+// Check that %_IsConstructCall returns correct value when inlined
+var NON_CONSTRUCT_MARKER = {};
+var CONSTRUCT_MARKER = {};
+function baz() {
+ return (!%_IsConstructCall()) ? NON_CONSTRUCT_MARKER : CONSTRUCT_MARKER;
+}
+
+function bar(x, y, z) {
+ var non_construct = baz(); /* baz should be inlined */
+ assertEquals(non_construct, NON_CONSTRUCT_MARKER);
+ var construct = new baz();
+ assertEquals(construct, CONSTRUCT_MARKER);
+}
+
+for (var i = 0; i < 100000; i++) new bar(1, 2, 3);