2011-05-03 08:23:58 +00:00
|
|
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
2008-07-03 15:10:15 +00:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
#include "v8.h"
|
|
|
|
|
|
|
|
#include "accessors.h"
|
2010-12-07 11:31:57 +00:00
|
|
|
#include "ast.h"
|
|
|
|
#include "deoptimizer.h"
|
2008-07-03 15:10:15 +00:00
|
|
|
#include "execution.h"
|
|
|
|
#include "factory.h"
|
2011-05-03 08:23:58 +00:00
|
|
|
#include "list-inl.h"
|
2010-12-07 11:31:57 +00:00
|
|
|
#include "safepoint-table.h"
|
2008-07-03 15:10:15 +00:00
|
|
|
#include "scopeinfo.h"
|
|
|
|
|
2009-05-25 10:05:56 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
template <class C>
|
|
|
|
static C* FindInPrototypeChain(Object* obj, bool* found_it) {
|
|
|
|
ASSERT(!*found_it);
|
2011-03-18 20:35:07 +00:00
|
|
|
Heap* heap = HEAP;
|
2008-07-03 15:10:15 +00:00
|
|
|
while (!Is<C>(obj)) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (obj == heap->null_value()) return NULL;
|
2008-07-03 15:10:15 +00:00
|
|
|
obj = obj->GetPrototype();
|
|
|
|
}
|
|
|
|
*found_it = true;
|
|
|
|
return C::cast(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Entry point that never should be called.
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Object* Accessors::IllegalGetAccessor(Object* object, void*) {
|
|
|
|
UNREACHABLE();
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
// According to ECMA-262, section 8.6.2.2, page 28, setting
|
|
|
|
// read-only properties must be silently ignored.
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::ArrayLength
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
// Traverse the prototype chain until we reach an array.
|
|
|
|
bool found_it = false;
|
|
|
|
JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
|
|
|
|
if (!found_it) return Smi::FromInt(0);
|
|
|
|
return holder->length();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The helper function will 'flatten' Number objects.
|
|
|
|
Object* Accessors::FlattenNumber(Object* value) {
|
|
|
|
if (value->IsNumber() || !value->IsJSValue()) return value;
|
|
|
|
JSValue* wrapper = JSValue::cast(value);
|
2011-03-18 20:35:07 +00:00
|
|
|
ASSERT(Isolate::Current()->context()->global_context()->number_function()->
|
|
|
|
has_initial_map());
|
|
|
|
Map* number_map = Isolate::Current()->context()->global_context()->
|
|
|
|
number_function()->initial_map();
|
2008-07-03 15:10:15 +00:00
|
|
|
if (wrapper->map() == number_map) return wrapper->value();
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
|
2011-03-29 07:34:23 +00:00
|
|
|
Isolate* isolate = object->GetIsolate();
|
2011-06-21 08:07:45 +00:00
|
|
|
|
|
|
|
// This means one of the object's prototypes is a JSArray and the
|
|
|
|
// object does not have a 'length' property. Calling SetProperty
|
|
|
|
// causes an infinite loop.
|
|
|
|
if (!object->IsJSArray()) {
|
|
|
|
return object->SetLocalPropertyIgnoreAttributes(
|
|
|
|
isolate->heap()->length_symbol(), value, NONE);
|
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
value = FlattenNumber(value);
|
|
|
|
|
|
|
|
// Need to call methods that may trigger GC.
|
2011-03-29 07:34:23 +00:00
|
|
|
HandleScope scope(isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// Protect raw pointers.
|
2011-03-29 07:34:23 +00:00
|
|
|
Handle<JSObject> object_handle(object, isolate);
|
|
|
|
Handle<Object> value_handle(value, isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
bool has_exception;
|
|
|
|
Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
|
|
|
|
if (has_exception) return Failure::Exception();
|
|
|
|
Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
|
|
|
|
if (has_exception) return Failure::Exception();
|
|
|
|
|
|
|
|
if (uint32_v->Number() == number_v->Number()) {
|
2011-06-21 08:07:45 +00:00
|
|
|
return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2011-03-29 07:34:23 +00:00
|
|
|
return isolate->Throw(
|
|
|
|
*isolate->factory()->NewRangeError("invalid_array_length",
|
|
|
|
HandleVector<Object>(NULL, 0)));
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ArrayLength = {
|
|
|
|
ArrayGetLength,
|
|
|
|
ArraySetLength,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::StringLength
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::StringGetLength(Object* object, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
Object* value = object;
|
|
|
|
if (object->IsJSValue()) value = JSValue::cast(object)->value();
|
|
|
|
if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
|
|
|
|
// If object is not a string we return 0 to be compatible with WebKit.
|
|
|
|
// Note: Firefox returns the length of ToString(object).
|
|
|
|
return Smi::FromInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::StringLength = {
|
|
|
|
StringGetLength,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::ScriptSource
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
return Script::cast(script)->source();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptSource = {
|
|
|
|
ScriptGetSource,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::ScriptName
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
return Script::cast(script)->name();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptName = {
|
|
|
|
ScriptGetName,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-03-10 08:10:50 +00:00
|
|
|
//
|
|
|
|
// Accessors::ScriptId
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
|
2009-03-10 08:10:50 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
return Script::cast(script)->id();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptId = {
|
|
|
|
ScriptGetId,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
//
|
|
|
|
// Accessors::ScriptLineOffset
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
return Script::cast(script)->line_offset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptLineOffset = {
|
|
|
|
ScriptGetLineOffset,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::ScriptColumnOffset
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
return Script::cast(script)->column_offset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptColumnOffset = {
|
|
|
|
ScriptGetColumnOffset,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-04-21 07:22:06 +00:00
|
|
|
//
|
|
|
|
// Accessors::ScriptData
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
|
2009-04-21 07:22:06 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
return Script::cast(script)->data();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptData = {
|
|
|
|
ScriptGetData,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
//
|
|
|
|
// Accessors::ScriptType
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
return Script::cast(script)->type();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptType = {
|
|
|
|
ScriptGetType,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-06-08 10:47:49 +00:00
|
|
|
//
|
|
|
|
// Accessors::ScriptCompilationType
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
|
2009-06-08 10:47:49 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
return Script::cast(script)->compilation_type();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptCompilationType = {
|
|
|
|
ScriptGetCompilationType,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-02-04 12:07:45 +00:00
|
|
|
//
|
|
|
|
// Accessors::ScriptGetLineEnds
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
|
2011-03-29 07:34:23 +00:00
|
|
|
JSValue* wrapper = JSValue::cast(object);
|
|
|
|
Isolate* isolate = wrapper->GetIsolate();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<Script> script(Script::cast(wrapper->value()), isolate);
|
2009-03-10 15:08:45 +00:00
|
|
|
InitScriptLineEnds(script);
|
2009-11-27 14:10:48 +00:00
|
|
|
ASSERT(script->line_ends()->IsFixedArray());
|
|
|
|
Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
|
2010-11-17 12:49:27 +00:00
|
|
|
// We do not want anyone to modify this array from JS.
|
2011-03-29 07:34:23 +00:00
|
|
|
ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
|
|
|
|
line_ends->map() == isolate->heap()->fixed_cow_array_map());
|
|
|
|
Handle<JSArray> js_array =
|
|
|
|
isolate->factory()->NewJSArrayWithElements(line_ends);
|
2009-11-27 14:10:48 +00:00
|
|
|
return *js_array;
|
2009-02-04 12:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptLineEnds = {
|
|
|
|
ScriptGetLineEnds,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-05-06 08:52:48 +00:00
|
|
|
//
|
|
|
|
// Accessors::ScriptGetContextData
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
|
2009-06-08 10:47:49 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
return Script::cast(script)->context_data();
|
2009-05-06 08:52:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptContextData = {
|
|
|
|
ScriptGetContextData,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-06-08 10:47:49 +00:00
|
|
|
//
|
2009-12-01 14:36:45 +00:00
|
|
|
// Accessors::ScriptGetEvalFromScript
|
2009-06-08 10:47:49 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
|
2009-06-08 10:47:49 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
2009-12-01 14:36:45 +00:00
|
|
|
if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
|
|
|
|
Handle<SharedFunctionInfo> eval_from_shared(
|
|
|
|
SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
|
|
|
|
|
|
|
|
if (eval_from_shared->script()->IsScript()) {
|
|
|
|
Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
|
|
|
|
return *GetScriptWrapper(eval_from_script);
|
|
|
|
}
|
|
|
|
}
|
2011-03-18 20:35:07 +00:00
|
|
|
return HEAP->undefined_value();
|
2009-06-08 10:47:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-01 14:36:45 +00:00
|
|
|
const AccessorDescriptor Accessors::ScriptEvalFromScript = {
|
|
|
|
ScriptGetEvalFromScript,
|
2009-06-08 10:47:49 +00:00
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
2009-12-01 14:36:45 +00:00
|
|
|
// Accessors::ScriptGetEvalFromScriptPosition
|
2009-06-08 10:47:49 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
|
2009-06-08 10:47:49 +00:00
|
|
|
HandleScope scope;
|
|
|
|
Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
|
|
|
|
|
|
|
|
// If this is not a script compiled through eval there is no eval position.
|
|
|
|
int compilation_type = Smi::cast(script->compilation_type())->value();
|
|
|
|
if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
|
2011-03-18 20:35:07 +00:00
|
|
|
return HEAP->undefined_value();
|
2009-06-08 10:47:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the function from where eval was called and find the source position
|
|
|
|
// from the instruction offset.
|
2009-12-01 14:36:45 +00:00
|
|
|
Handle<Code> code(SharedFunctionInfo::cast(
|
|
|
|
script->eval_from_shared())->code());
|
2009-06-08 10:47:49 +00:00
|
|
|
return Smi::FromInt(code->SourcePosition(code->instruction_start() +
|
|
|
|
script->eval_from_instructions_offset()->value()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-01 14:36:45 +00:00
|
|
|
const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
|
|
|
|
ScriptGetEvalFromScriptPosition,
|
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::ScriptGetEvalFromFunctionName
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
|
2009-12-01 14:36:45 +00:00
|
|
|
Object* script = JSValue::cast(object)->value();
|
|
|
|
Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
|
|
|
|
Script::cast(script)->eval_from_shared()));
|
|
|
|
|
|
|
|
|
|
|
|
// Find the name of the function calling eval.
|
|
|
|
if (!shared->name()->IsUndefined()) {
|
|
|
|
return shared->name();
|
|
|
|
} else {
|
|
|
|
return shared->inferred_name();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
|
|
|
|
ScriptGetEvalFromFunctionName,
|
2009-06-08 10:47:49 +00:00
|
|
|
IllegalSetter,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
//
|
|
|
|
// Accessors::FunctionPrototype
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
|
2011-03-29 07:34:23 +00:00
|
|
|
Heap* heap = Isolate::Current()->heap();
|
2008-07-03 15:10:15 +00:00
|
|
|
bool found_it = false;
|
|
|
|
JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
|
2011-03-29 07:34:23 +00:00
|
|
|
if (!found_it) return heap->undefined_value();
|
2011-02-22 12:27:36 +00:00
|
|
|
while (!function->should_have_prototype()) {
|
|
|
|
found_it = false;
|
|
|
|
function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
|
|
|
|
&found_it);
|
|
|
|
// There has to be one because we hit the getter.
|
|
|
|
ASSERT(found_it);
|
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
if (!function->has_prototype()) {
|
2010-10-25 15:22:03 +00:00
|
|
|
Object* prototype;
|
2011-03-29 07:34:23 +00:00
|
|
|
{ MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
|
2010-10-25 15:22:03 +00:00
|
|
|
if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
|
|
|
|
}
|
|
|
|
Object* result;
|
|
|
|
{ MaybeObject* maybe_result = function->SetPrototype(prototype);
|
|
|
|
if (!maybe_result->ToObject(&result)) return maybe_result;
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
return function->prototype();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
|
|
|
|
Object* value,
|
|
|
|
void*) {
|
2011-03-29 07:34:23 +00:00
|
|
|
Heap* heap = object->GetHeap();
|
2008-07-03 15:10:15 +00:00
|
|
|
bool found_it = false;
|
|
|
|
JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
|
2011-03-29 07:34:23 +00:00
|
|
|
if (!found_it) return heap->undefined_value();
|
2011-02-22 12:27:36 +00:00
|
|
|
if (!function->should_have_prototype()) {
|
|
|
|
// Since we hit this accessor, object will have no prototype property.
|
2011-03-29 07:34:23 +00:00
|
|
|
return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
|
2011-02-22 12:27:36 +00:00
|
|
|
value,
|
|
|
|
NONE);
|
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
if (function->has_initial_map()) {
|
|
|
|
// If the function has allocated the initial map
|
|
|
|
// replace it with a copy containing the new prototype.
|
2010-10-25 15:22:03 +00:00
|
|
|
Object* new_map;
|
|
|
|
{ MaybeObject* maybe_new_map =
|
|
|
|
function->initial_map()->CopyDropTransitions();
|
|
|
|
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
function->set_initial_map(Map::cast(new_map));
|
|
|
|
}
|
2010-10-25 15:22:03 +00:00
|
|
|
Object* prototype;
|
|
|
|
{ MaybeObject* maybe_prototype = function->SetPrototype(value);
|
|
|
|
if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
ASSERT(function->prototype() == value);
|
|
|
|
return function;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::FunctionPrototype = {
|
|
|
|
FunctionGetPrototype,
|
|
|
|
FunctionSetPrototype,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::FunctionLength
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
bool found_it = false;
|
|
|
|
JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
|
|
|
|
if (!found_it) return Smi::FromInt(0);
|
|
|
|
// Check if already compiled.
|
2010-08-11 08:12:53 +00:00
|
|
|
if (!function->shared()->is_compiled()) {
|
2008-07-03 15:10:15 +00:00
|
|
|
// If the function isn't compiled yet, the length is not computed
|
|
|
|
// correctly yet. Compile it now and return the right length.
|
|
|
|
HandleScope scope;
|
2010-12-07 11:31:57 +00:00
|
|
|
Handle<JSFunction> handle(function);
|
|
|
|
if (!CompileLazy(handle, KEEP_EXCEPTION)) return Failure::Exception();
|
|
|
|
return Smi::FromInt(handle->shared()->length());
|
2008-07-03 15:10:15 +00:00
|
|
|
} else {
|
|
|
|
return Smi::FromInt(function->shared()->length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::FunctionLength = {
|
|
|
|
FunctionGetLength,
|
|
|
|
ReadOnlySetAccessor,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::FunctionName
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
bool found_it = false;
|
|
|
|
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!found_it) return HEAP->undefined_value();
|
2008-07-03 15:10:15 +00:00
|
|
|
return holder->shared()->name();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::FunctionName = {
|
|
|
|
FunctionGetName,
|
|
|
|
ReadOnlySetAccessor,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::FunctionArguments
|
|
|
|
//
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
|
|
|
|
static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
|
|
|
|
JavaScriptFrame* frame,
|
|
|
|
Handle<JSFunction> inlined_function,
|
|
|
|
int inlined_frame_index) {
|
2011-03-18 20:35:07 +00:00
|
|
|
Factory* factory = Isolate::Current()->factory();
|
2010-12-07 11:31:57 +00:00
|
|
|
int args_count = inlined_function->shared()->formal_parameter_count();
|
|
|
|
ScopedVector<SlotRef> args_slots(args_count);
|
2011-04-01 11:41:36 +00:00
|
|
|
SlotRef::ComputeSlotMappingForArguments(frame,
|
|
|
|
inlined_frame_index,
|
|
|
|
&args_slots);
|
2010-12-07 11:31:57 +00:00
|
|
|
Handle<JSObject> arguments =
|
2011-03-18 20:35:07 +00:00
|
|
|
factory->NewArgumentsObject(inlined_function, args_count);
|
|
|
|
Handle<FixedArray> array = factory->NewFixedArray(args_count);
|
2010-12-07 11:31:57 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
|
2011-03-18 20:35:07 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
HandleScope scope(isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
bool found_it = false;
|
|
|
|
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!found_it) return isolate->heap()->undefined_value();
|
|
|
|
Handle<JSFunction> function(holder, isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// Find the top invocation of the function by traversing frames.
|
2010-12-07 11:31:57 +00:00
|
|
|
List<JSFunction*> functions(2);
|
Simplify isolates access during stack iteration (WAS: Move SafeStackFrameIterator::active_count_...)
While trying to fix Mac and Windows versions for this change:
http://codereview.chromium.org/6771047/, I figured out, that we
already store an isolate in StackFrameIterator, so we can use it in
frame objects, instead of requiring it from caller.
I've changed iterators usage to the following scheme: whenever a
caller maintains an isolate pointer, it just passes it to stack
iterator, and no more worries about passing it to frame content
accessors. If a caller uses current isolate, it can omit passing it
to iterator, in this case, an iterator will use the current isolate,
too.
There was a special case with LiveEdit, which creates
detached copies of frame objects.
R=vitalyr@chromium.org
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6794019
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7499 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2011-04-05 09:01:47 +00:00
|
|
|
for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
|
2008-07-03 15:10:15 +00:00
|
|
|
JavaScriptFrame* frame = it.frame();
|
2010-12-07 11:31:57 +00:00
|
|
|
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 (i > 0) {
|
2011-02-02 15:08:29 +00:00
|
|
|
// The function in question was inlined. Inlined functions have the
|
|
|
|
// correct number of arguments and no allocated arguments object, so
|
|
|
|
// we can construct a fresh one by interpreting the function's
|
|
|
|
// deoptimization input data.
|
2010-12-07 11:31:57 +00:00
|
|
|
return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
|
2011-02-02 15:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!frame->is_optimized()) {
|
2010-12-07 11:31:57 +00:00
|
|
|
// If there is an arguments variable in the stack, we return that.
|
2011-02-02 15:08:29 +00:00
|
|
|
Handle<SerializedScopeInfo> info(function->shared()->scope_info());
|
2011-03-18 20:35:07 +00:00
|
|
|
int index = info->StackSlotIndex(isolate->heap()->arguments_symbol());
|
2010-12-07 11:31:57 +00:00
|
|
|
if (index >= 0) {
|
2011-03-18 20:35:07 +00:00
|
|
|
Handle<Object> arguments(frame->GetExpression(index), isolate);
|
2011-01-06 15:53:56 +00:00
|
|
|
if (!arguments->IsArgumentsMarker()) return *arguments;
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
}
|
2011-02-02 15:08:29 +00:00
|
|
|
|
|
|
|
// If there is no arguments variable in the stack or we have an
|
|
|
|
// optimized frame, we find the frame that holds the actual arguments
|
|
|
|
// passed to the function.
|
|
|
|
it.AdvanceToArgumentsFrame();
|
|
|
|
frame = it.frame();
|
|
|
|
|
|
|
|
// Get the number of arguments and construct an arguments object
|
|
|
|
// mirror for the right frame.
|
2011-03-08 14:18:28 +00:00
|
|
|
const int length = frame->ComputeParametersCount();
|
2011-03-18 20:35:07 +00:00
|
|
|
Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
|
|
|
|
function, length);
|
|
|
|
Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
|
2011-02-02 15:08:29 +00:00
|
|
|
|
|
|
|
// 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;
|
2009-06-24 08:01:38 +00:00
|
|
|
}
|
2010-12-07 11:31:57 +00:00
|
|
|
functions.Rewind(0);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// No frame corresponding to the given function found. Return null.
|
2011-03-18 20:35:07 +00:00
|
|
|
return isolate->heap()->null_value();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::FunctionArguments = {
|
|
|
|
FunctionGetArguments,
|
|
|
|
ReadOnlySetAccessor,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::FunctionCaller
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2011-03-23 03:45:48 +00:00
|
|
|
static MaybeObject* CheckNonStrictCallerOrThrow(
|
|
|
|
Isolate* isolate,
|
|
|
|
JSFunction* caller) {
|
|
|
|
DisableAssertNoAllocation enable_allocation;
|
|
|
|
if (caller->shared()->strict_mode()) {
|
|
|
|
return isolate->Throw(
|
|
|
|
*isolate->factory()->NewTypeError("strict_caller",
|
|
|
|
HandleVector<Object>(NULL, 0)));
|
|
|
|
}
|
|
|
|
return caller;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
|
2011-03-18 20:35:07 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
HandleScope scope(isolate);
|
2010-10-25 15:22:03 +00:00
|
|
|
AssertNoAllocation no_alloc;
|
2008-07-03 15:10:15 +00:00
|
|
|
bool found_it = false;
|
|
|
|
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!found_it) return isolate->heap()->undefined_value();
|
|
|
|
Handle<JSFunction> function(holder, isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
List<JSFunction*> functions(2);
|
Simplify isolates access during stack iteration (WAS: Move SafeStackFrameIterator::active_count_...)
While trying to fix Mac and Windows versions for this change:
http://codereview.chromium.org/6771047/, I figured out, that we
already store an isolate in StackFrameIterator, so we can use it in
frame objects, instead of requiring it from caller.
I've changed iterators usage to the following scheme: whenever a
caller maintains an isolate pointer, it just passes it to stack
iterator, and no more worries about passing it to frame content
accessors. If a caller uses current isolate, it can omit passing it
to iterator, in this case, an iterator will use the current isolate,
too.
There was a special case with LiveEdit, which creates
detached copies of frame objects.
R=vitalyr@chromium.org
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6794019
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7499 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2011-04-05 09:01:47 +00:00
|
|
|
for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
|
2010-12-07 11:31:57 +00:00
|
|
|
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());
|
2011-03-23 03:45:48 +00:00
|
|
|
return CheckNonStrictCallerOrThrow(isolate, functions[i - 1]);
|
2010-12-07 11:31:57 +00:00
|
|
|
} else {
|
|
|
|
for (it.Advance(); !it.done(); it.Advance()) {
|
|
|
|
frame = it.frame();
|
|
|
|
functions.Rewind(0);
|
|
|
|
frame->GetFunctions(&functions);
|
|
|
|
if (!functions.last()->shared()->is_toplevel()) {
|
2011-03-23 03:45:48 +00:00
|
|
|
return CheckNonStrictCallerOrThrow(isolate, functions.last());
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
ASSERT(functions.length() == 1);
|
|
|
|
}
|
2011-03-18 20:35:07 +00:00
|
|
|
if (it.done()) return isolate->heap()->null_value();
|
2010-12-07 11:31:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2010-12-07 11:31:57 +00:00
|
|
|
functions.Rewind(0);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// No frame corresponding to the given function found. Return null.
|
2011-03-18 20:35:07 +00:00
|
|
|
return isolate->heap()->null_value();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::FunctionCaller = {
|
|
|
|
FunctionGetCaller,
|
|
|
|
ReadOnlySetAccessor,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accessors::ObjectPrototype
|
|
|
|
//
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
|
2008-07-03 15:10:15 +00:00
|
|
|
Object* current = receiver->GetPrototype();
|
|
|
|
while (current->IsJSObject() &&
|
|
|
|
JSObject::cast(current)->map()->is_hidden_prototype()) {
|
|
|
|
current = current->GetPrototype();
|
|
|
|
}
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
|
|
|
|
Object* value,
|
|
|
|
void*) {
|
2010-02-10 14:44:15 +00:00
|
|
|
const bool skip_hidden_prototypes = true;
|
2008-08-27 13:47:52 +00:00
|
|
|
// To be consistent with other Set functions, return the value.
|
2010-02-10 14:44:15 +00:00
|
|
|
return receiver->SetPrototype(value, skip_hidden_prototypes);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AccessorDescriptor Accessors::ObjectPrototype = {
|
|
|
|
ObjectGetPrototype,
|
|
|
|
ObjectSetPrototype,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
} } // namespace v8::internal
|