blob: 5f9bf744af80c13e0b9580da190845019cd8017a [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "accessors.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010031#include "ast.h"
32#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033#include "execution.h"
34#include "factory.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "safepoint-table.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "scopeinfo.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000037
38namespace v8 {
39namespace internal {
40
41
42template <class C>
43static C* FindInPrototypeChain(Object* obj, bool* found_it) {
44 ASSERT(!*found_it);
Steve Block44f0eee2011-05-26 01:26:41 +010045 Heap* heap = HEAP;
Steve Blocka7e24c12009-10-30 11:49:00 +000046 while (!Is<C>(obj)) {
Steve Block44f0eee2011-05-26 01:26:41 +010047 if (obj == heap->null_value()) return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000048 obj = obj->GetPrototype();
49 }
50 *found_it = true;
51 return C::cast(obj);
52}
53
54
55// Entry point that never should be called.
John Reck59135872010-11-02 12:39:01 -070056MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000057 UNREACHABLE();
58 return NULL;
59}
60
61
62Object* Accessors::IllegalGetAccessor(Object* object, void*) {
63 UNREACHABLE();
64 return object;
65}
66
67
John Reck59135872010-11-02 12:39:01 -070068MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000069 // According to ECMA-262, section 8.6.2.2, page 28, setting
70 // read-only properties must be silently ignored.
71 return value;
72}
73
74
75//
76// Accessors::ArrayLength
77//
78
79
John Reck59135872010-11-02 12:39:01 -070080MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000081 // Traverse the prototype chain until we reach an array.
82 bool found_it = false;
83 JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
84 if (!found_it) return Smi::FromInt(0);
85 return holder->length();
86}
87
88
89// The helper function will 'flatten' Number objects.
90Object* Accessors::FlattenNumber(Object* value) {
91 if (value->IsNumber() || !value->IsJSValue()) return value;
92 JSValue* wrapper = JSValue::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +010093 ASSERT(Isolate::Current()->context()->global_context()->number_function()->
94 has_initial_map());
95 Map* number_map = Isolate::Current()->context()->global_context()->
96 number_function()->initial_map();
Steve Blocka7e24c12009-10-30 11:49:00 +000097 if (wrapper->map() == number_map) return wrapper->value();
98 return value;
99}
100
101
John Reck59135872010-11-02 12:39:01 -0700102MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100103 Isolate* isolate = object->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000104 value = FlattenNumber(value);
105
106 // Need to call methods that may trigger GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100107 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000108
109 // Protect raw pointers.
Steve Block44f0eee2011-05-26 01:26:41 +0100110 Handle<JSObject> object_handle(object, isolate);
111 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000112
113 bool has_exception;
114 Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
115 if (has_exception) return Failure::Exception();
116 Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
117 if (has_exception) return Failure::Exception();
118
119 // Restore raw pointers,
120 object = *object_handle;
121 value = *value_handle;
122
123 if (uint32_v->Number() == number_v->Number()) {
124 if (object->IsJSArray()) {
125 return JSArray::cast(object)->SetElementsLength(*uint32_v);
126 } else {
127 // This means one of the object's prototypes is a JSArray and
128 // the object does not have a 'length' property.
129 // Calling SetProperty causes an infinite loop.
Steve Block44f0eee2011-05-26 01:26:41 +0100130 return object->SetLocalPropertyIgnoreAttributes(
131 isolate->heap()->length_symbol(), value, NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000132 }
133 }
Steve Block44f0eee2011-05-26 01:26:41 +0100134 return isolate->Throw(
135 *isolate->factory()->NewRangeError("invalid_array_length",
136 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000137}
138
139
140const AccessorDescriptor Accessors::ArrayLength = {
141 ArrayGetLength,
142 ArraySetLength,
143 0
144};
145
146
147//
148// Accessors::StringLength
149//
150
151
John Reck59135872010-11-02 12:39:01 -0700152MaybeObject* Accessors::StringGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000153 Object* value = object;
154 if (object->IsJSValue()) value = JSValue::cast(object)->value();
155 if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
156 // If object is not a string we return 0 to be compatible with WebKit.
157 // Note: Firefox returns the length of ToString(object).
158 return Smi::FromInt(0);
159}
160
161
162const AccessorDescriptor Accessors::StringLength = {
163 StringGetLength,
164 IllegalSetter,
165 0
166};
167
168
169//
170// Accessors::ScriptSource
171//
172
173
John Reck59135872010-11-02 12:39:01 -0700174MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000175 Object* script = JSValue::cast(object)->value();
176 return Script::cast(script)->source();
177}
178
179
180const AccessorDescriptor Accessors::ScriptSource = {
181 ScriptGetSource,
182 IllegalSetter,
183 0
184};
185
186
187//
188// Accessors::ScriptName
189//
190
191
John Reck59135872010-11-02 12:39:01 -0700192MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 Object* script = JSValue::cast(object)->value();
194 return Script::cast(script)->name();
195}
196
197
198const AccessorDescriptor Accessors::ScriptName = {
199 ScriptGetName,
200 IllegalSetter,
201 0
202};
203
204
205//
206// Accessors::ScriptId
207//
208
209
John Reck59135872010-11-02 12:39:01 -0700210MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000211 Object* script = JSValue::cast(object)->value();
212 return Script::cast(script)->id();
213}
214
215
216const AccessorDescriptor Accessors::ScriptId = {
217 ScriptGetId,
218 IllegalSetter,
219 0
220};
221
222
223//
224// Accessors::ScriptLineOffset
225//
226
227
John Reck59135872010-11-02 12:39:01 -0700228MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000229 Object* script = JSValue::cast(object)->value();
230 return Script::cast(script)->line_offset();
231}
232
233
234const AccessorDescriptor Accessors::ScriptLineOffset = {
235 ScriptGetLineOffset,
236 IllegalSetter,
237 0
238};
239
240
241//
242// Accessors::ScriptColumnOffset
243//
244
245
John Reck59135872010-11-02 12:39:01 -0700246MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000247 Object* script = JSValue::cast(object)->value();
248 return Script::cast(script)->column_offset();
249}
250
251
252const AccessorDescriptor Accessors::ScriptColumnOffset = {
253 ScriptGetColumnOffset,
254 IllegalSetter,
255 0
256};
257
258
259//
260// Accessors::ScriptData
261//
262
263
John Reck59135872010-11-02 12:39:01 -0700264MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000265 Object* script = JSValue::cast(object)->value();
266 return Script::cast(script)->data();
267}
268
269
270const AccessorDescriptor Accessors::ScriptData = {
271 ScriptGetData,
272 IllegalSetter,
273 0
274};
275
276
277//
278// Accessors::ScriptType
279//
280
281
John Reck59135872010-11-02 12:39:01 -0700282MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000283 Object* script = JSValue::cast(object)->value();
284 return Script::cast(script)->type();
285}
286
287
288const AccessorDescriptor Accessors::ScriptType = {
289 ScriptGetType,
290 IllegalSetter,
291 0
292};
293
294
295//
296// Accessors::ScriptCompilationType
297//
298
299
John Reck59135872010-11-02 12:39:01 -0700300MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000301 Object* script = JSValue::cast(object)->value();
302 return Script::cast(script)->compilation_type();
303}
304
305
306const AccessorDescriptor Accessors::ScriptCompilationType = {
307 ScriptGetCompilationType,
308 IllegalSetter,
309 0
310};
311
312
313//
314// Accessors::ScriptGetLineEnds
315//
316
317
John Reck59135872010-11-02 12:39:01 -0700318MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100319 JSValue* wrapper = JSValue::cast(object);
320 Isolate* isolate = wrapper->GetIsolate();
321 HandleScope scope(isolate);
322 Handle<Script> script(Script::cast(wrapper->value()), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000323 InitScriptLineEnds(script);
Steve Blockd0582a62009-12-15 09:54:21 +0000324 ASSERT(script->line_ends()->IsFixedArray());
325 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800326 // We do not want anyone to modify this array from JS.
Steve Block44f0eee2011-05-26 01:26:41 +0100327 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
328 line_ends->map() == isolate->heap()->fixed_cow_array_map());
329 Handle<JSArray> js_array =
330 isolate->factory()->NewJSArrayWithElements(line_ends);
Steve Blockd0582a62009-12-15 09:54:21 +0000331 return *js_array;
Steve Blocka7e24c12009-10-30 11:49:00 +0000332}
333
334
335const AccessorDescriptor Accessors::ScriptLineEnds = {
336 ScriptGetLineEnds,
337 IllegalSetter,
338 0
339};
340
341
342//
343// Accessors::ScriptGetContextData
344//
345
346
John Reck59135872010-11-02 12:39:01 -0700347MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000348 Object* script = JSValue::cast(object)->value();
349 return Script::cast(script)->context_data();
350}
351
352
353const AccessorDescriptor Accessors::ScriptContextData = {
354 ScriptGetContextData,
355 IllegalSetter,
356 0
357};
358
359
360//
Steve Blockd0582a62009-12-15 09:54:21 +0000361// Accessors::ScriptGetEvalFromScript
Steve Blocka7e24c12009-10-30 11:49:00 +0000362//
363
364
John Reck59135872010-11-02 12:39:01 -0700365MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000366 Object* script = JSValue::cast(object)->value();
Steve Blockd0582a62009-12-15 09:54:21 +0000367 if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
368 Handle<SharedFunctionInfo> eval_from_shared(
369 SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
370
371 if (eval_from_shared->script()->IsScript()) {
372 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
373 return *GetScriptWrapper(eval_from_script);
374 }
375 }
Steve Block44f0eee2011-05-26 01:26:41 +0100376 return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000377}
378
379
Steve Blockd0582a62009-12-15 09:54:21 +0000380const AccessorDescriptor Accessors::ScriptEvalFromScript = {
381 ScriptGetEvalFromScript,
Steve Blocka7e24c12009-10-30 11:49:00 +0000382 IllegalSetter,
383 0
384};
385
386
387//
Steve Blockd0582a62009-12-15 09:54:21 +0000388// Accessors::ScriptGetEvalFromScriptPosition
Steve Blocka7e24c12009-10-30 11:49:00 +0000389//
390
391
John Reck59135872010-11-02 12:39:01 -0700392MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000393 HandleScope scope;
394 Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
395
396 // If this is not a script compiled through eval there is no eval position.
397 int compilation_type = Smi::cast(script->compilation_type())->value();
398 if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100399 return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 }
401
402 // Get the function from where eval was called and find the source position
403 // from the instruction offset.
Steve Blockd0582a62009-12-15 09:54:21 +0000404 Handle<Code> code(SharedFunctionInfo::cast(
405 script->eval_from_shared())->code());
Steve Blocka7e24c12009-10-30 11:49:00 +0000406 return Smi::FromInt(code->SourcePosition(code->instruction_start() +
407 script->eval_from_instructions_offset()->value()));
408}
409
410
Steve Blockd0582a62009-12-15 09:54:21 +0000411const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
412 ScriptGetEvalFromScriptPosition,
413 IllegalSetter,
414 0
415};
416
417
418//
419// Accessors::ScriptGetEvalFromFunctionName
420//
421
422
John Reck59135872010-11-02 12:39:01 -0700423MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
Steve Blockd0582a62009-12-15 09:54:21 +0000424 Object* script = JSValue::cast(object)->value();
425 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
426 Script::cast(script)->eval_from_shared()));
427
428
429 // Find the name of the function calling eval.
430 if (!shared->name()->IsUndefined()) {
431 return shared->name();
432 } else {
433 return shared->inferred_name();
434 }
435}
436
437
438const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
439 ScriptGetEvalFromFunctionName,
Steve Blocka7e24c12009-10-30 11:49:00 +0000440 IllegalSetter,
441 0
442};
443
444
445//
446// Accessors::FunctionPrototype
447//
448
449
John Reck59135872010-11-02 12:39:01 -0700450MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100451 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000452 bool found_it = false;
453 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100454 if (!found_it) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100455 while (!function->should_have_prototype()) {
456 found_it = false;
457 function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
458 &found_it);
459 // There has to be one because we hit the getter.
460 ASSERT(found_it);
461 }
462
Steve Blocka7e24c12009-10-30 11:49:00 +0000463 if (!function->has_prototype()) {
John Reck59135872010-11-02 12:39:01 -0700464 Object* prototype;
Steve Block44f0eee2011-05-26 01:26:41 +0100465 { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
John Reck59135872010-11-02 12:39:01 -0700466 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
467 }
468 Object* result;
469 { MaybeObject* maybe_result = function->SetPrototype(prototype);
470 if (!maybe_result->ToObject(&result)) return maybe_result;
471 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000472 }
473 return function->prototype();
474}
475
476
John Reck59135872010-11-02 12:39:01 -0700477MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
478 Object* value,
479 void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100480 Heap* heap = object->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000481 bool found_it = false;
482 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100483 if (!found_it) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100484 if (!function->should_have_prototype()) {
485 // Since we hit this accessor, object will have no prototype property.
Steve Block44f0eee2011-05-26 01:26:41 +0100486 return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100487 value,
488 NONE);
489 }
490
Steve Blocka7e24c12009-10-30 11:49:00 +0000491 if (function->has_initial_map()) {
492 // If the function has allocated the initial map
493 // replace it with a copy containing the new prototype.
John Reck59135872010-11-02 12:39:01 -0700494 Object* new_map;
495 { MaybeObject* maybe_new_map =
496 function->initial_map()->CopyDropTransitions();
497 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
498 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000499 function->set_initial_map(Map::cast(new_map));
500 }
John Reck59135872010-11-02 12:39:01 -0700501 Object* prototype;
502 { MaybeObject* maybe_prototype = function->SetPrototype(value);
503 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
504 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000505 ASSERT(function->prototype() == value);
506 return function;
507}
508
509
510const AccessorDescriptor Accessors::FunctionPrototype = {
511 FunctionGetPrototype,
512 FunctionSetPrototype,
513 0
514};
515
516
517//
518// Accessors::FunctionLength
519//
520
521
John Reck59135872010-11-02 12:39:01 -0700522MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000523 bool found_it = false;
524 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
525 if (!found_it) return Smi::FromInt(0);
526 // Check if already compiled.
Iain Merrick75681382010-08-19 15:07:18 +0100527 if (!function->shared()->is_compiled()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000528 // If the function isn't compiled yet, the length is not computed
529 // correctly yet. Compile it now and return the right length.
530 HandleScope scope;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100531 Handle<JSFunction> handle(function);
532 if (!CompileLazy(handle, KEEP_EXCEPTION)) return Failure::Exception();
533 return Smi::FromInt(handle->shared()->length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000534 } else {
535 return Smi::FromInt(function->shared()->length());
536 }
537}
538
539
540const AccessorDescriptor Accessors::FunctionLength = {
541 FunctionGetLength,
542 ReadOnlySetAccessor,
543 0
544};
545
546
547//
548// Accessors::FunctionName
549//
550
551
John Reck59135872010-11-02 12:39:01 -0700552MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000553 bool found_it = false;
554 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100555 if (!found_it) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000556 return holder->shared()->name();
557}
558
559
560const AccessorDescriptor Accessors::FunctionName = {
561 FunctionGetName,
562 ReadOnlySetAccessor,
563 0
564};
565
566
567//
568// Accessors::FunctionArguments
569//
570
Ben Murdochb0fe1622011-05-05 13:52:32 +0100571
572static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
573 JavaScriptFrame* frame,
574 Handle<JSFunction> inlined_function,
575 int inlined_frame_index) {
Steve Block44f0eee2011-05-26 01:26:41 +0100576 Factory* factory = Isolate::Current()->factory();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100577 int args_count = inlined_function->shared()->formal_parameter_count();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100578 ScopedVector<SlotRef> args_slots(args_count);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100579 SlotRef::ComputeSlotMappingForArguments(frame,
580 inlined_frame_index,
581 &args_slots);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100582 Handle<JSObject> arguments =
Steve Block44f0eee2011-05-26 01:26:41 +0100583 factory->NewArgumentsObject(inlined_function, args_count);
584 Handle<FixedArray> array = factory->NewFixedArray(args_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100585 for (int i = 0; i < args_count; ++i) {
586 Handle<Object> value = args_slots[i].GetValue();
587 array->set(i, *value);
588 }
589 arguments->set_elements(*array);
590
591 // Return the freshly allocated arguments object.
592 return *arguments;
593}
594
Steve Blocka7e24c12009-10-30 11:49:00 +0000595
John Reck59135872010-11-02 12:39:01 -0700596MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100597 Isolate* isolate = Isolate::Current();
598 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000599 bool found_it = false;
600 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100601 if (!found_it) return isolate->heap()->undefined_value();
602 Handle<JSFunction> function(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000603
604 // Find the top invocation of the function by traversing frames.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100605 List<JSFunction*> functions(2);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100606 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000607 JavaScriptFrame* frame = it.frame();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100608 frame->GetFunctions(&functions);
609 for (int i = functions.length() - 1; i >= 0; i--) {
610 // Skip all frames that aren't invocations of the given function.
611 if (functions[i] != *function) continue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000612
Ben Murdochb0fe1622011-05-05 13:52:32 +0100613 if (i > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +0100614 // The function in question was inlined. Inlined functions have the
615 // correct number of arguments and no allocated arguments object, so
616 // we can construct a fresh one by interpreting the function's
617 // deoptimization input data.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100618 return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
Steve Block1e0659c2011-05-24 12:43:12 +0100619 }
620
621 if (!frame->is_optimized()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100622 // If there is an arguments variable in the stack, we return that.
Steve Block1e0659c2011-05-24 12:43:12 +0100623 Handle<SerializedScopeInfo> info(function->shared()->scope_info());
Steve Block44f0eee2011-05-26 01:26:41 +0100624 int index = info->StackSlotIndex(isolate->heap()->arguments_symbol());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100625 if (index >= 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100626 Handle<Object> arguments(frame->GetExpression(index), isolate);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100627 if (!arguments->IsArgumentsMarker()) return *arguments;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100628 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100629 }
Steve Block1e0659c2011-05-24 12:43:12 +0100630
631 // If there is no arguments variable in the stack or we have an
632 // optimized frame, we find the frame that holds the actual arguments
633 // passed to the function.
634 it.AdvanceToArgumentsFrame();
635 frame = it.frame();
636
637 // Get the number of arguments and construct an arguments object
638 // mirror for the right frame.
Steve Block44f0eee2011-05-26 01:26:41 +0100639 const int length = frame->ComputeParametersCount();
640 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
641 function, length);
642 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
Steve Block1e0659c2011-05-24 12:43:12 +0100643
644 // Copy the parameters to the arguments object.
645 ASSERT(array->length() == length);
646 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
647 arguments->set_elements(*array);
648
649 // Return the freshly allocated arguments object.
650 return *arguments;
Steve Blocka7e24c12009-10-30 11:49:00 +0000651 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100652 functions.Rewind(0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000653 }
654
655 // No frame corresponding to the given function found. Return null.
Steve Block44f0eee2011-05-26 01:26:41 +0100656 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000657}
658
659
660const AccessorDescriptor Accessors::FunctionArguments = {
661 FunctionGetArguments,
662 ReadOnlySetAccessor,
663 0
664};
665
666
667//
668// Accessors::FunctionCaller
669//
670
671
Steve Block44f0eee2011-05-26 01:26:41 +0100672static MaybeObject* CheckNonStrictCallerOrThrow(
673 Isolate* isolate,
674 JSFunction* caller) {
675 DisableAssertNoAllocation enable_allocation;
676 if (caller->shared()->strict_mode()) {
677 return isolate->Throw(
678 *isolate->factory()->NewTypeError("strict_caller",
679 HandleVector<Object>(NULL, 0)));
680 }
681 return caller;
682}
683
684
John Reck59135872010-11-02 12:39:01 -0700685MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100686 Isolate* isolate = Isolate::Current();
687 HandleScope scope(isolate);
John Reck59135872010-11-02 12:39:01 -0700688 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000689 bool found_it = false;
690 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100691 if (!found_it) return isolate->heap()->undefined_value();
692 Handle<JSFunction> function(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000693
Ben Murdochb0fe1622011-05-05 13:52:32 +0100694 List<JSFunction*> functions(2);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100695 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100696 JavaScriptFrame* frame = it.frame();
697 frame->GetFunctions(&functions);
698 for (int i = functions.length() - 1; i >= 0; i--) {
699 if (functions[i] == *function) {
700 // Once we have found the frame, we need to go to the caller
701 // frame. This may require skipping through a number of top-level
702 // frames, e.g. frames for scripts not functions.
703 if (i > 0) {
704 ASSERT(!functions[i - 1]->shared()->is_toplevel());
Steve Block44f0eee2011-05-26 01:26:41 +0100705 return CheckNonStrictCallerOrThrow(isolate, functions[i - 1]);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100706 } else {
707 for (it.Advance(); !it.done(); it.Advance()) {
708 frame = it.frame();
709 functions.Rewind(0);
710 frame->GetFunctions(&functions);
711 if (!functions.last()->shared()->is_toplevel()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100712 return CheckNonStrictCallerOrThrow(isolate, functions.last());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100713 }
714 ASSERT(functions.length() == 1);
715 }
Steve Block44f0eee2011-05-26 01:26:41 +0100716 if (it.done()) return isolate->heap()->null_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100717 break;
718 }
719 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000720 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100721 functions.Rewind(0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000722 }
723
724 // No frame corresponding to the given function found. Return null.
Steve Block44f0eee2011-05-26 01:26:41 +0100725 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000726}
727
728
729const AccessorDescriptor Accessors::FunctionCaller = {
730 FunctionGetCaller,
731 ReadOnlySetAccessor,
732 0
733};
734
735
736//
737// Accessors::ObjectPrototype
738//
739
740
John Reck59135872010-11-02 12:39:01 -0700741MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000742 Object* current = receiver->GetPrototype();
743 while (current->IsJSObject() &&
744 JSObject::cast(current)->map()->is_hidden_prototype()) {
745 current = current->GetPrototype();
746 }
747 return current;
748}
749
750
John Reck59135872010-11-02 12:39:01 -0700751MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
752 Object* value,
753 void*) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000754 const bool skip_hidden_prototypes = true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000755 // To be consistent with other Set functions, return the value.
Andrei Popescu402d9372010-02-26 13:31:12 +0000756 return receiver->SetPrototype(value, skip_hidden_prototypes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000757}
758
759
760const AccessorDescriptor Accessors::ObjectPrototype = {
761 ObjectGetPrototype,
762 ObjectSetPrototype,
763 0
764};
765
766} } // namespace v8::internal