blob: 806c679f4bc82ef016777fb8c329ca2637489a49 [file] [log] [blame]
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000031#include "ast.h"
32#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "execution.h"
34#include "factory.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000035#include "list-inl.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "safepoint-table.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "scopeinfo.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
kasperl@chromium.org71affb52009-05-26 05:44:31 +000039namespace v8 {
40namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
42
43template <class C>
44static C* FindInPrototypeChain(Object* obj, bool* found_it) {
45 ASSERT(!*found_it);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000046 Heap* heap = HEAP;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047 while (!Is<C>(obj)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000048 if (obj == heap->null_value()) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049 obj = obj->GetPrototype();
50 }
51 *found_it = true;
52 return C::cast(obj);
53}
54
55
56// Entry point that never should be called.
lrn@chromium.org303ada72010-10-27 09:33:13 +000057MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058 UNREACHABLE();
59 return NULL;
60}
61
62
63Object* Accessors::IllegalGetAccessor(Object* object, void*) {
64 UNREACHABLE();
65 return object;
66}
67
68
lrn@chromium.org303ada72010-10-27 09:33:13 +000069MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000070 // According to ECMA-262, section 8.6.2.2, page 28, setting
71 // read-only properties must be silently ignored.
72 return value;
73}
74
75
76//
77// Accessors::ArrayLength
78//
79
80
lrn@chromium.org303ada72010-10-27 09:33:13 +000081MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082 // Traverse the prototype chain until we reach an array.
83 bool found_it = false;
84 JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
85 if (!found_it) return Smi::FromInt(0);
86 return holder->length();
87}
88
89
90// The helper function will 'flatten' Number objects.
91Object* Accessors::FlattenNumber(Object* value) {
92 if (value->IsNumber() || !value->IsJSValue()) return value;
93 JSValue* wrapper = JSValue::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000094 ASSERT(Isolate::Current()->context()->global_context()->number_function()->
95 has_initial_map());
96 Map* number_map = Isolate::Current()->context()->global_context()->
97 number_function()->initial_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098 if (wrapper->map() == number_map) return wrapper->value();
99 return value;
100}
101
102
lrn@chromium.org303ada72010-10-27 09:33:13 +0000103MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000104 Isolate* isolate = object->GetIsolate();
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000105
106 // This means one of the object's prototypes is a JSArray and the
107 // object does not have a 'length' property. Calling SetProperty
108 // causes an infinite loop.
109 if (!object->IsJSArray()) {
110 return object->SetLocalPropertyIgnoreAttributes(
111 isolate->heap()->length_symbol(), value, NONE);
112 }
113
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114 value = FlattenNumber(value);
115
116 // Need to call methods that may trigger GC.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000117 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118
119 // Protect raw pointers.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000120 Handle<JSObject> object_handle(object, isolate);
121 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122
123 bool has_exception;
124 Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
125 if (has_exception) return Failure::Exception();
126 Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
127 if (has_exception) return Failure::Exception();
128
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000129 if (uint32_v->Number() == number_v->Number()) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000130 return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000132 return isolate->Throw(
133 *isolate->factory()->NewRangeError("invalid_array_length",
134 HandleVector<Object>(NULL, 0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000135}
136
137
138const AccessorDescriptor Accessors::ArrayLength = {
139 ArrayGetLength,
140 ArraySetLength,
141 0
142};
143
144
145//
146// Accessors::StringLength
147//
148
149
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150MaybeObject* Accessors::StringGetLength(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151 Object* value = object;
152 if (object->IsJSValue()) value = JSValue::cast(object)->value();
153 if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
154 // If object is not a string we return 0 to be compatible with WebKit.
155 // Note: Firefox returns the length of ToString(object).
156 return Smi::FromInt(0);
157}
158
159
160const AccessorDescriptor Accessors::StringLength = {
161 StringGetLength,
162 IllegalSetter,
163 0
164};
165
166
167//
168// Accessors::ScriptSource
169//
170
171
lrn@chromium.org303ada72010-10-27 09:33:13 +0000172MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173 Object* script = JSValue::cast(object)->value();
174 return Script::cast(script)->source();
175}
176
177
178const AccessorDescriptor Accessors::ScriptSource = {
179 ScriptGetSource,
180 IllegalSetter,
181 0
182};
183
184
185//
186// Accessors::ScriptName
187//
188
189
lrn@chromium.org303ada72010-10-27 09:33:13 +0000190MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191 Object* script = JSValue::cast(object)->value();
192 return Script::cast(script)->name();
193}
194
195
196const AccessorDescriptor Accessors::ScriptName = {
197 ScriptGetName,
198 IllegalSetter,
199 0
200};
201
202
203//
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000204// Accessors::ScriptId
205//
206
207
lrn@chromium.org303ada72010-10-27 09:33:13 +0000208MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000209 Object* script = JSValue::cast(object)->value();
210 return Script::cast(script)->id();
211}
212
213
214const AccessorDescriptor Accessors::ScriptId = {
215 ScriptGetId,
216 IllegalSetter,
217 0
218};
219
220
221//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222// Accessors::ScriptLineOffset
223//
224
225
lrn@chromium.org303ada72010-10-27 09:33:13 +0000226MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227 Object* script = JSValue::cast(object)->value();
228 return Script::cast(script)->line_offset();
229}
230
231
232const AccessorDescriptor Accessors::ScriptLineOffset = {
233 ScriptGetLineOffset,
234 IllegalSetter,
235 0
236};
237
238
239//
240// Accessors::ScriptColumnOffset
241//
242
243
lrn@chromium.org303ada72010-10-27 09:33:13 +0000244MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245 Object* script = JSValue::cast(object)->value();
246 return Script::cast(script)->column_offset();
247}
248
249
250const AccessorDescriptor Accessors::ScriptColumnOffset = {
251 ScriptGetColumnOffset,
252 IllegalSetter,
253 0
254};
255
256
257//
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000258// Accessors::ScriptData
259//
260
261
lrn@chromium.org303ada72010-10-27 09:33:13 +0000262MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000263 Object* script = JSValue::cast(object)->value();
264 return Script::cast(script)->data();
265}
266
267
268const AccessorDescriptor Accessors::ScriptData = {
269 ScriptGetData,
270 IllegalSetter,
271 0
272};
273
274
275//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276// Accessors::ScriptType
277//
278
279
lrn@chromium.org303ada72010-10-27 09:33:13 +0000280MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000281 Object* script = JSValue::cast(object)->value();
282 return Script::cast(script)->type();
283}
284
285
286const AccessorDescriptor Accessors::ScriptType = {
287 ScriptGetType,
288 IllegalSetter,
289 0
290};
291
292
293//
ager@chromium.orge2902be2009-06-08 12:21:35 +0000294// Accessors::ScriptCompilationType
295//
296
297
lrn@chromium.org303ada72010-10-27 09:33:13 +0000298MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000299 Object* script = JSValue::cast(object)->value();
300 return Script::cast(script)->compilation_type();
301}
302
303
304const AccessorDescriptor Accessors::ScriptCompilationType = {
305 ScriptGetCompilationType,
306 IllegalSetter,
307 0
308};
309
310
311//
iposva@chromium.org245aa852009-02-10 00:49:54 +0000312// Accessors::ScriptGetLineEnds
313//
314
315
lrn@chromium.org303ada72010-10-27 09:33:13 +0000316MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000317 JSValue* wrapper = JSValue::cast(object);
318 Isolate* isolate = wrapper->GetIsolate();
319 HandleScope scope(isolate);
320 Handle<Script> script(Script::cast(wrapper->value()), isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000321 InitScriptLineEnds(script);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000322 ASSERT(script->line_ends()->IsFixedArray());
323 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000324 // We do not want anyone to modify this array from JS.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000325 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
326 line_ends->map() == isolate->heap()->fixed_cow_array_map());
327 Handle<JSArray> js_array =
328 isolate->factory()->NewJSArrayWithElements(line_ends);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000329 return *js_array;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000330}
331
332
333const AccessorDescriptor Accessors::ScriptLineEnds = {
334 ScriptGetLineEnds,
335 IllegalSetter,
336 0
337};
338
339
340//
ager@chromium.org9085a012009-05-11 19:22:57 +0000341// Accessors::ScriptGetContextData
342//
343
344
lrn@chromium.org303ada72010-10-27 09:33:13 +0000345MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000346 Object* script = JSValue::cast(object)->value();
347 return Script::cast(script)->context_data();
ager@chromium.org9085a012009-05-11 19:22:57 +0000348}
349
350
351const AccessorDescriptor Accessors::ScriptContextData = {
352 ScriptGetContextData,
353 IllegalSetter,
354 0
355};
356
357
358//
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000359// Accessors::ScriptGetEvalFromScript
ager@chromium.orge2902be2009-06-08 12:21:35 +0000360//
361
362
lrn@chromium.org303ada72010-10-27 09:33:13 +0000363MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000364 Object* script = JSValue::cast(object)->value();
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000365 if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
366 Handle<SharedFunctionInfo> eval_from_shared(
367 SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
368
369 if (eval_from_shared->script()->IsScript()) {
370 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
371 return *GetScriptWrapper(eval_from_script);
372 }
373 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000374 return HEAP->undefined_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +0000375}
376
377
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000378const AccessorDescriptor Accessors::ScriptEvalFromScript = {
379 ScriptGetEvalFromScript,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000380 IllegalSetter,
381 0
382};
383
384
385//
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000386// Accessors::ScriptGetEvalFromScriptPosition
ager@chromium.orge2902be2009-06-08 12:21:35 +0000387//
388
389
lrn@chromium.org303ada72010-10-27 09:33:13 +0000390MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000391 HandleScope scope;
392 Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
393
394 // If this is not a script compiled through eval there is no eval position.
395 int compilation_type = Smi::cast(script->compilation_type())->value();
396 if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 return HEAP->undefined_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +0000398 }
399
400 // Get the function from where eval was called and find the source position
401 // from the instruction offset.
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000402 Handle<Code> code(SharedFunctionInfo::cast(
403 script->eval_from_shared())->code());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000404 return Smi::FromInt(code->SourcePosition(code->instruction_start() +
405 script->eval_from_instructions_offset()->value()));
406}
407
408
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000409const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
410 ScriptGetEvalFromScriptPosition,
411 IllegalSetter,
412 0
413};
414
415
416//
417// Accessors::ScriptGetEvalFromFunctionName
418//
419
420
lrn@chromium.org303ada72010-10-27 09:33:13 +0000421MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000422 Object* script = JSValue::cast(object)->value();
423 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
424 Script::cast(script)->eval_from_shared()));
425
426
427 // Find the name of the function calling eval.
428 if (!shared->name()->IsUndefined()) {
429 return shared->name();
430 } else {
431 return shared->inferred_name();
432 }
433}
434
435
436const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
437 ScriptGetEvalFromFunctionName,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000438 IllegalSetter,
439 0
440};
441
442
443//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444// Accessors::FunctionPrototype
445//
446
447
lrn@chromium.org303ada72010-10-27 09:33:13 +0000448MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000449 Heap* heap = Isolate::Current()->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000450 bool found_it = false;
451 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000452 if (!found_it) return heap->undefined_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000453 while (!function->should_have_prototype()) {
454 found_it = false;
455 function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
456 &found_it);
457 // There has to be one because we hit the getter.
458 ASSERT(found_it);
459 }
460
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461 if (!function->has_prototype()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000462 Object* prototype;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000463 { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000464 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
465 }
466 Object* result;
467 { MaybeObject* maybe_result = function->SetPrototype(prototype);
468 if (!maybe_result->ToObject(&result)) return maybe_result;
469 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470 }
471 return function->prototype();
472}
473
474
lrn@chromium.org303ada72010-10-27 09:33:13 +0000475MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
476 Object* value,
477 void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000478 Heap* heap = object->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000479 bool found_it = false;
480 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000481 if (!found_it) return heap->undefined_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000482 if (!function->should_have_prototype()) {
483 // Since we hit this accessor, object will have no prototype property.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000484 return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000485 value,
486 NONE);
487 }
488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489 if (function->has_initial_map()) {
490 // If the function has allocated the initial map
491 // replace it with a copy containing the new prototype.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000492 Object* new_map;
493 { MaybeObject* maybe_new_map =
494 function->initial_map()->CopyDropTransitions();
495 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
496 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497 function->set_initial_map(Map::cast(new_map));
498 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000499 Object* prototype;
500 { MaybeObject* maybe_prototype = function->SetPrototype(value);
501 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
502 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000503 ASSERT(function->prototype() == value);
504 return function;
505}
506
507
508const AccessorDescriptor Accessors::FunctionPrototype = {
509 FunctionGetPrototype,
510 FunctionSetPrototype,
511 0
512};
513
514
515//
516// Accessors::FunctionLength
517//
518
519
lrn@chromium.org303ada72010-10-27 09:33:13 +0000520MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000521 bool found_it = false;
522 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
523 if (!found_it) return Smi::FromInt(0);
524 // Check if already compiled.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000525 if (!function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526 // If the function isn't compiled yet, the length is not computed
527 // correctly yet. Compile it now and return the right length.
528 HandleScope scope;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000529 Handle<JSFunction> handle(function);
530 if (!CompileLazy(handle, KEEP_EXCEPTION)) return Failure::Exception();
531 return Smi::FromInt(handle->shared()->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532 } else {
533 return Smi::FromInt(function->shared()->length());
534 }
535}
536
537
538const AccessorDescriptor Accessors::FunctionLength = {
539 FunctionGetLength,
540 ReadOnlySetAccessor,
541 0
542};
543
544
545//
546// Accessors::FunctionName
547//
548
549
lrn@chromium.org303ada72010-10-27 09:33:13 +0000550MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 bool found_it = false;
552 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 if (!found_it) return HEAP->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000554 return holder->shared()->name();
555}
556
557
558const AccessorDescriptor Accessors::FunctionName = {
559 FunctionGetName,
560 ReadOnlySetAccessor,
561 0
562};
563
564
565//
566// Accessors::FunctionArguments
567//
568
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000569
570static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
571 JavaScriptFrame* frame,
572 Handle<JSFunction> inlined_function,
573 int inlined_frame_index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 Factory* factory = Isolate::Current()->factory();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000575 int args_count = inlined_function->shared()->formal_parameter_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000576 ScopedVector<SlotRef> args_slots(args_count);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000577 SlotRef::ComputeSlotMappingForArguments(frame,
578 inlined_frame_index,
579 &args_slots);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000580 Handle<JSObject> arguments =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000581 factory->NewArgumentsObject(inlined_function, args_count);
582 Handle<FixedArray> array = factory->NewFixedArray(args_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000583 for (int i = 0; i < args_count; ++i) {
584 Handle<Object> value = args_slots[i].GetValue();
585 array->set(i, *value);
586 }
587 arguments->set_elements(*array);
588
589 // Return the freshly allocated arguments object.
590 return *arguments;
591}
592
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000593
lrn@chromium.org303ada72010-10-27 09:33:13 +0000594MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 Isolate* isolate = Isolate::Current();
596 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597 bool found_it = false;
598 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 if (!found_it) return isolate->heap()->undefined_value();
600 Handle<JSFunction> function(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601
602 // Find the top invocation of the function by traversing frames.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000603 List<JSFunction*> functions(2);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000604 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605 JavaScriptFrame* frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000606 frame->GetFunctions(&functions);
607 for (int i = functions.length() - 1; i >= 0; i--) {
608 // Skip all frames that aren't invocations of the given function.
609 if (functions[i] != *function) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000610
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000611 if (i > 0) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000612 // The function in question was inlined. Inlined functions have the
613 // correct number of arguments and no allocated arguments object, so
614 // we can construct a fresh one by interpreting the function's
615 // deoptimization input data.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000616 return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000617 }
618
619 if (!frame->is_optimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000620 // If there is an arguments variable in the stack, we return that.
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000621 Handle<SerializedScopeInfo> info(function->shared()->scope_info());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 int index = info->StackSlotIndex(isolate->heap()->arguments_symbol());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000623 if (index >= 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000624 Handle<Object> arguments(frame->GetExpression(index), isolate);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000625 if (!arguments->IsArgumentsMarker()) return *arguments;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000626 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000627 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000628
629 // If there is no arguments variable in the stack or we have an
630 // optimized frame, we find the frame that holds the actual arguments
631 // passed to the function.
632 it.AdvanceToArgumentsFrame();
633 frame = it.frame();
634
635 // Get the number of arguments and construct an arguments object
636 // mirror for the right frame.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000637 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
639 function, length);
640 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000641
642 // Copy the parameters to the arguments object.
643 ASSERT(array->length() == length);
644 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
645 arguments->set_elements(*array);
646
647 // Return the freshly allocated arguments object.
648 return *arguments;
ager@chromium.org3e875802009-06-29 08:26:34 +0000649 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000650 functions.Rewind(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651 }
652
653 // No frame corresponding to the given function found. Return null.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000654 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655}
656
657
658const AccessorDescriptor Accessors::FunctionArguments = {
659 FunctionGetArguments,
660 ReadOnlySetAccessor,
661 0
662};
663
664
665//
666// Accessors::FunctionCaller
667//
668
669
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000670static MaybeObject* CheckNonStrictCallerOrThrow(
671 Isolate* isolate,
672 JSFunction* caller) {
673 DisableAssertNoAllocation enable_allocation;
674 if (caller->shared()->strict_mode()) {
675 return isolate->Throw(
676 *isolate->factory()->NewTypeError("strict_caller",
677 HandleVector<Object>(NULL, 0)));
678 }
679 return caller;
680}
681
682
lrn@chromium.org303ada72010-10-27 09:33:13 +0000683MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000684 Isolate* isolate = Isolate::Current();
685 HandleScope scope(isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000686 AssertNoAllocation no_alloc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687 bool found_it = false;
688 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000689 if (!found_it) return isolate->heap()->undefined_value();
690 Handle<JSFunction> function(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000692 List<JSFunction*> functions(2);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000693 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000694 JavaScriptFrame* frame = it.frame();
695 frame->GetFunctions(&functions);
696 for (int i = functions.length() - 1; i >= 0; i--) {
697 if (functions[i] == *function) {
698 // Once we have found the frame, we need to go to the caller
699 // frame. This may require skipping through a number of top-level
700 // frames, e.g. frames for scripts not functions.
701 if (i > 0) {
702 ASSERT(!functions[i - 1]->shared()->is_toplevel());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000703 return CheckNonStrictCallerOrThrow(isolate, functions[i - 1]);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000704 } else {
705 for (it.Advance(); !it.done(); it.Advance()) {
706 frame = it.frame();
707 functions.Rewind(0);
708 frame->GetFunctions(&functions);
709 if (!functions.last()->shared()->is_toplevel()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000710 return CheckNonStrictCallerOrThrow(isolate, functions.last());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000711 }
712 ASSERT(functions.length() == 1);
713 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000714 if (it.done()) return isolate->heap()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000715 break;
716 }
717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000719 functions.Rewind(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000720 }
721
722 // No frame corresponding to the given function found. Return null.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000723 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000724}
725
726
727const AccessorDescriptor Accessors::FunctionCaller = {
728 FunctionGetCaller,
729 ReadOnlySetAccessor,
730 0
731};
732
733
734//
735// Accessors::ObjectPrototype
736//
737
738
lrn@chromium.org303ada72010-10-27 09:33:13 +0000739MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000740 Object* current = receiver->GetPrototype();
741 while (current->IsJSObject() &&
742 JSObject::cast(current)->map()->is_hidden_prototype()) {
743 current = current->GetPrototype();
744 }
745 return current;
746}
747
748
lrn@chromium.org303ada72010-10-27 09:33:13 +0000749MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
750 Object* value,
751 void*) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000752 const bool skip_hidden_prototypes = true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000753 // To be consistent with other Set functions, return the value.
ager@chromium.org5c838252010-02-19 08:53:10 +0000754 return receiver->SetPrototype(value, skip_hidden_prototypes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000755}
756
757
758const AccessorDescriptor Accessors::ObjectPrototype = {
759 ObjectGetPrototype,
760 ObjectSetPrototype,
761 0
762};
763
764} } // namespace v8::internal