blob: ff1ad67313ad909f351b7210ebbe1966beb9706a [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +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 <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000048#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000051#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000053#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000055#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000056#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
kasperl@chromium.org71affb52009-05-26 05:44:31 +000059namespace v8 {
60namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62
ager@chromium.org3e875802009-06-29 08:26:34 +000063#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000064 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66// Cast the given object to a value of the specified type and store
67// it in a variable with the given name. If the object is not of the
68// expected type call IllegalOperation and return.
69#define CONVERT_CHECKED(Type, name, obj) \
70 RUNTIME_ASSERT(obj->Is##Type()); \
71 Type* name = Type::cast(obj);
72
73#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
75 Handle<Type> name = args.at<Type>(index);
76
kasper.lundbd3ec4e2008-07-09 11:06:54 +000077// Cast the given object to a boolean and store it in a variable with
78// the given name. If the object is not a boolean call IllegalOperation
79// and return.
80#define CONVERT_BOOLEAN_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsBoolean()); \
82 bool name = (obj)->IsTrue();
83
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000084// Cast the given object to a Smi and store its value in an int variable
85// with the given name. If the object is not a Smi call IllegalOperation
86// and return.
87#define CONVERT_SMI_CHECKED(name, obj) \
88 RUNTIME_ASSERT(obj->IsSmi()); \
89 int name = Smi::cast(obj)->value();
90
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091// Cast the given object to a double and store it in a variable with
92// the given name. If the object is not a number (as opposed to
93// the number not-a-number) call IllegalOperation and return.
94#define CONVERT_DOUBLE_CHECKED(name, obj) \
95 RUNTIME_ASSERT(obj->IsNumber()); \
96 double name = (obj)->Number();
97
98// Call the specified converter on the object *comand store the result in
99// a variable of the specified type with the given name. If the
100// object is not a Number call IllegalOperation and return.
101#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
102 RUNTIME_ASSERT(obj->IsNumber()); \
103 type name = NumberTo##Type(obj);
104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
107 JSObject* boilerplate) {
108 StackLimitCheck check(isolate);
109 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 if (!maybe_result->ToObject(&result)) return maybe_result;
115 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000116 JSObject* copy = JSObject::cast(result);
117
118 // Deep copy local properties.
119 if (copy->HasFastProperties()) {
120 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000121 for (int i = 0; i < properties->length(); i++) {
122 Object* value = properties->get(i);
123 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000124 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000125 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000126 if (!maybe_result->ToObject(&result)) return maybe_result;
127 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 }
130 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000131 int nof = copy->map()->inobject_properties();
132 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 Object* value = copy->InObjectPropertyAt(i);
134 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000135 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000137 if (!maybe_result->ToObject(&result)) return maybe_result;
138 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 }
141 }
142 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 if (!maybe_result->ToObject(&result)) return maybe_result;
146 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000147 FixedArray* names = FixedArray::cast(result);
148 copy->GetLocalPropertyNames(names, 0);
149 for (int i = 0; i < names->length(); i++) {
150 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 // Only deep copy fields from the object literal expression.
155 // In particular, don't try to copy the length attribute of
156 // an array.
157 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 Object* value =
159 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000162 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000163 if (!maybe_result->ToObject(&result)) return maybe_result;
164 }
165 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000166 // Creating object copy for literals. No strict mode needed.
167 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000168 if (!maybe_result->ToObject(&result)) return maybe_result;
169 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 }
171 }
172 }
173
174 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000176 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 switch (copy->GetElementsKind()) {
178 case JSObject::FAST_ELEMENTS: {
179 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 if (elements->map() == heap->fixed_cow_array_map()) {
181 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000182#ifdef DEBUG
183 for (int i = 0; i < elements->length(); i++) {
184 ASSERT(!elements->get(i)->IsJSObject());
185 }
186#endif
187 } else {
188 for (int i = 0; i < elements->length(); i++) {
189 Object* value = elements->get(i);
190 if (value->IsJSObject()) {
191 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000192 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
193 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000194 if (!maybe_result->ToObject(&result)) return maybe_result;
195 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196 elements->set(i, result);
197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000198 }
199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 case JSObject::DICTIONARY_ELEMENTS: {
203 NumberDictionary* element_dictionary = copy->element_dictionary();
204 int capacity = element_dictionary->Capacity();
205 for (int i = 0; i < capacity; i++) {
206 Object* k = element_dictionary->KeyAt(i);
207 if (element_dictionary->IsKey(k)) {
208 Object* value = element_dictionary->ValueAt(i);
209 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000210 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
212 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000213 if (!maybe_result->ToObject(&result)) return maybe_result;
214 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000215 element_dictionary->ValueAtPut(i, result);
216 }
217 }
218 }
219 break;
220 }
221 default:
222 UNREACHABLE();
223 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 }
225 return copy;
226}
227
228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000229RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232}
233
234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000235RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238}
239
240
ager@chromium.org236ad962008-09-25 09:45:57 +0000241static Handle<Map> ComputeObjectLiteralMap(
242 Handle<Context> context,
243 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000244 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000246 int properties_length = constant_properties->length();
247 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000251 for (int p = 0; p != properties_length; p += 2) {
252 Object* key = constant_properties->get(p);
253 uint32_t element_index = 0;
254 if (key->IsSymbol()) {
255 number_of_symbol_keys++;
256 } else if (key->ToArrayIndex(&element_index)) {
257 // An index key does not require space in the property backing store.
258 number_of_properties--;
259 } else {
260 // Bail out as a non-symbol non-index key makes caching impossible.
261 // ASSERT to make sure that the if condition after the loop is false.
262 ASSERT(number_of_symbol_keys != number_of_properties);
263 break;
264 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000265 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 // If we only have symbols and array indices among keys then we can
267 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000268 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000269 if ((number_of_symbol_keys == number_of_properties) &&
270 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000271 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000272 Handle<FixedArray> keys =
273 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 if (number_of_symbol_keys > 0) {
275 int index = 0;
276 for (int p = 0; p < properties_length; p += 2) {
277 Object* key = constant_properties->get(p);
278 if (key->IsSymbol()) {
279 keys->set(index++, key);
280 }
281 }
282 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000283 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000284 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000286 }
287 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000290 Handle<Map>(context->object_function()->initial_map()),
291 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000292}
293
294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000296 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000297 Handle<FixedArray> literals,
298 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000300
301static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000303 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000304 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 bool should_have_fast_elements,
306 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307 // Get the global context from the literals array. This is the
308 // context in which the function was created and we use the object
309 // function from this context to create the object literal. We do
310 // not use the object function from the current global context
311 // because this might be the object function from another context
312 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<Context> context =
314 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 // In case we have function literals, we want the object to be in
317 // slow properties mode for now. We don't go in the map cache because
318 // maps with constant functions can't be shared if the functions are
319 // not the same (which is the common case).
320 bool is_result_from_cache = false;
321 Handle<Map> map = has_function_literal
322 ? Handle<Map>(context->object_function()->initial_map())
323 : ComputeObjectLiteralMap(context,
324 constant_properties,
325 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000328
329 // Normalize the elements of the boilerplate to save space if needed.
330 if (!should_have_fast_elements) NormalizeElements(boilerplate);
331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 // Add the constant properties to the boilerplate.
333 int length = constant_properties->length();
334 bool should_transform =
335 !is_result_from_cache && boilerplate->HasFastProperties();
336 if (should_transform || has_function_literal) {
337 // Normalize the properties of object to avoid n^2 behavior
338 // when extending the object multiple properties. Indicate the number of
339 // properties to be added.
340 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
341 }
342
343 for (int index = 0; index < length; index +=2) {
344 Handle<Object> key(constant_properties->get(index+0), isolate);
345 Handle<Object> value(constant_properties->get(index+1), isolate);
346 if (value->IsFixedArray()) {
347 // The value contains the constant_properties of a
348 // simple object or array literal.
349 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
350 value = CreateLiteralBoilerplate(isolate, literals, array);
351 if (value.is_null()) return value;
352 }
353 Handle<Object> result;
354 uint32_t element_index = 0;
355 if (key->IsSymbol()) {
356 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
357 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000358 result = SetOwnElement(boilerplate,
359 element_index,
360 value,
361 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 Handle<String> name(String::cast(*key));
364 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000365 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
366 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 } else if (key->ToArrayIndex(&element_index)) {
369 // Array index (uint32).
370 result = SetOwnElement(boilerplate,
371 element_index,
372 value,
373 kNonStrictMode);
374 } else {
375 // Non-uint32 number.
376 ASSERT(key->IsNumber());
377 double num = key->Number();
378 char arr[100];
379 Vector<char> buffer(arr, ARRAY_SIZE(arr));
380 const char* str = DoubleToCString(num, buffer);
381 Handle<String> name =
382 isolate->factory()->NewStringFromAscii(CStrVector(str));
383 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
384 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 // If setting the property on the boilerplate throws an
387 // exception, the exception is converted to an empty handle in
388 // the handle based operations. In that case, we need to
389 // convert back to an exception.
390 if (result.is_null()) return result;
391 }
392
393 // Transform to fast properties if necessary. For object literals with
394 // containing function literals we defer this operation until after all
395 // computed properties have been assigned so that we can generate
396 // constant function properties.
397 if (should_transform && !has_function_literal) {
398 TransformToFastProperties(boilerplate,
399 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
401
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000402 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 Handle<FixedArray> literals,
409 Handle<FixedArray> elements) {
410 // Create the JSArray.
411 Handle<JSFunction> constructor(
412 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 const bool is_cow =
416 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000417 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419
420 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000421 if (is_cow) {
422#ifdef DEBUG
423 // Copy-on-write arrays must be shallow (and simple).
424 for (int i = 0; i < content->length(); i++) {
425 ASSERT(!content->get(i)->IsFixedArray());
426 }
427#endif
428 } else {
429 for (int i = 0; i < content->length(); i++) {
430 if (content->get(i)->IsFixedArray()) {
431 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000433 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
434 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000436 if (result.is_null()) return result;
437 content->set(i, *result);
438 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000439 }
440 }
441
442 // Set the elements.
443 Handle<JSArray>::cast(object)->SetContent(*content);
444 return object;
445}
446
447
448static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000450 Handle<FixedArray> literals,
451 Handle<FixedArray> array) {
452 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000454 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000455 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 return CreateObjectLiteralBoilerplate(isolate,
457 literals,
458 elements,
459 true,
460 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000461 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 return CreateObjectLiteralBoilerplate(isolate,
463 literals,
464 elements,
465 false,
466 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 default:
470 UNREACHABLE();
471 return Handle<Object>::null();
472 }
473}
474
475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000476RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000477 // Takes a FixedArray of elements containing the literal elements of
478 // the array literal and produces JSArray with those elements.
479 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000480 // which contains the context from which to get the Array function
481 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 ASSERT(args.length() == 3);
484 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
485 CONVERT_SMI_CHECKED(literals_index, args[1]);
486 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000488 Handle<Object> object =
489 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000492 // Update the functions literal and return the boilerplate.
493 literals->set(literals_index, *object);
494 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495}
496
497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000498RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000500 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000501 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
502 CONVERT_SMI_CHECKED(literals_index, args[1]);
503 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000504 CONVERT_SMI_CHECKED(flags, args[3]);
505 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
506 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000507
508 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 Handle<Object> boilerplate(literals->get(literals_index), isolate);
510 if (*boilerplate == isolate->heap()->undefined_value()) {
511 boilerplate = CreateObjectLiteralBoilerplate(isolate,
512 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 should_have_fast_elements,
515 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 if (boilerplate.is_null()) return Failure::Exception();
517 // Update the functions literal and return the boilerplate.
518 literals->set(literals_index, *boilerplate);
519 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521}
522
523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000524RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000527 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
528 CONVERT_SMI_CHECKED(literals_index, args[1]);
529 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 CONVERT_SMI_CHECKED(flags, args[3]);
531 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
532 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000533
534 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 Handle<Object> boilerplate(literals->get(literals_index), isolate);
536 if (*boilerplate == isolate->heap()->undefined_value()) {
537 boilerplate = CreateObjectLiteralBoilerplate(isolate,
538 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 should_have_fast_elements,
541 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 if (boilerplate.is_null()) return Failure::Exception();
543 // Update the functions literal and return the boilerplate.
544 literals->set(literals_index, *boilerplate);
545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547}
548
549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000550RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 ASSERT(args.length() == 3);
553 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
554 CONVERT_SMI_CHECKED(literals_index, args[1]);
555 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561 if (boilerplate.is_null()) return Failure::Exception();
562 // Update the functions literal and return the boilerplate.
563 literals->set(literals_index, *boilerplate);
564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566}
567
568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000569RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000571 ASSERT(args.length() == 3);
572 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
573 CONVERT_SMI_CHECKED(literals_index, args[1]);
574 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 if (boilerplate.is_null()) return Failure::Exception();
581 // Update the functions literal and return the boilerplate.
582 literals->set(literals_index, *boilerplate);
583 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000584 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000586 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
593 ASSERT(args.length() == 2);
594 Object* handler = args[0];
595 Object* prototype = args[1];
596 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000597 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000598 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
599}
600
601
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000602RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
603 ASSERT(args.length() == 1);
604 Object* obj = args[0];
605 return obj->IsJSProxy()
606 ? isolate->heap()->true_value() : isolate->heap()->false_value();
607}
608
609
610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
611 ASSERT(args.length() == 1);
612 CONVERT_CHECKED(JSProxy, proxy, args[0]);
613 return proxy->handler();
614}
615
616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000617RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000618 ASSERT(args.length() == 2);
619 CONVERT_CHECKED(String, key, args[0]);
620 Object* value = args[1];
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000621 ASSERT(!value->IsFailure());
ager@chromium.org32912102009-01-16 10:38:43 +0000622 // Create a catch context extension object.
623 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000624 isolate->context()->global_context()->
625 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000626 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000628 if (!maybe_object->ToObject(&object)) return maybe_object;
629 }
ager@chromium.org32912102009-01-16 10:38:43 +0000630 // Assign the exception value to the catch variable and make sure
631 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000632 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000633 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
634 JSObject::cast(object)->SetProperty(
635 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000636 if (!maybe_value->ToObject(&value)) return maybe_value;
637 }
ager@chromium.org32912102009-01-16 10:38:43 +0000638 return object;
639}
640
641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000642RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643 NoHandleAllocation ha;
644 ASSERT(args.length() == 1);
645 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000646 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 return JSObject::cast(obj)->class_name();
648}
649
ager@chromium.org7c537e22008-10-16 08:43:32 +0000650
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000651RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
652 NoHandleAllocation ha;
653 ASSERT(args.length() == 1);
654 Object* obj = args[0];
655 obj = obj->GetPrototype();
656 while (obj->IsJSObject() &&
657 JSObject::cast(obj)->map()->is_hidden_prototype()) {
658 obj = obj->GetPrototype();
659 }
660 return obj;
661}
662
663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665 NoHandleAllocation ha;
666 ASSERT(args.length() == 2);
667 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
668 Object* O = args[0];
669 Object* V = args[1];
670 while (true) {
671 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000672 if (prototype->IsNull()) return isolate->heap()->false_value();
673 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674 V = prototype;
675 }
676}
677
678
ager@chromium.org9085a012009-05-11 19:22:57 +0000679// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000680RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000681 NoHandleAllocation ha;
682 ASSERT(args.length() == 2);
683 CONVERT_CHECKED(JSObject, jsobject, args[0]);
684 CONVERT_CHECKED(JSObject, proto, args[1]);
685
686 // Sanity checks. The old prototype (that we are replacing) could
687 // theoretically be null, but if it is not null then check that we
688 // didn't already install a hidden prototype here.
689 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
690 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
691 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
692
693 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000694 Object* map_or_failure;
695 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
696 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
697 return maybe_map_or_failure;
698 }
699 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000700 Map* new_proto_map = Map::cast(map_or_failure);
701
lrn@chromium.org303ada72010-10-27 09:33:13 +0000702 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
703 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
704 return maybe_map_or_failure;
705 }
706 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000707 Map* new_map = Map::cast(map_or_failure);
708
709 // Set proto's prototype to be the old prototype of the object.
710 new_proto_map->set_prototype(jsobject->GetPrototype());
711 proto->set_map(new_proto_map);
712 new_proto_map->set_is_hidden_prototype();
713
714 // Set the object's prototype to proto.
715 new_map->set_prototype(proto);
716 jsobject->set_map(new_map);
717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000718 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000719}
720
721
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000723 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000724 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000725 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000726 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000727}
728
729
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000730// Recursively traverses hidden prototypes if property is not found
731static void GetOwnPropertyImplementation(JSObject* obj,
732 String* name,
733 LookupResult* result) {
734 obj->LocalLookupRealNamedProperty(name, result);
735
736 if (!result->IsProperty()) {
737 Object* proto = obj->GetPrototype();
738 if (proto->IsJSObject() &&
739 JSObject::cast(proto)->map()->is_hidden_prototype())
740 GetOwnPropertyImplementation(JSObject::cast(proto),
741 name, result);
742 }
743}
744
745
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000746static bool CheckAccessException(LookupResult* result,
747 v8::AccessType access_type) {
748 if (result->type() == CALLBACKS) {
749 Object* callback = result->GetCallbackObject();
750 if (callback->IsAccessorInfo()) {
751 AccessorInfo* info = AccessorInfo::cast(callback);
752 bool can_access =
753 (access_type == v8::ACCESS_HAS &&
754 (info->all_can_read() || info->all_can_write())) ||
755 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
756 (access_type == v8::ACCESS_SET && info->all_can_write());
757 return can_access;
758 }
759 }
760
761 return false;
762}
763
764
765static bool CheckAccess(JSObject* obj,
766 String* name,
767 LookupResult* result,
768 v8::AccessType access_type) {
769 ASSERT(result->IsProperty());
770
771 JSObject* holder = result->holder();
772 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000773 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000774 while (true) {
775 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000776 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000777 // Access check callback denied the access, but some properties
778 // can have a special permissions which override callbacks descision
779 // (currently see v8::AccessControl).
780 break;
781 }
782
783 if (current == holder) {
784 return true;
785 }
786
787 current = JSObject::cast(current->GetPrototype());
788 }
789
790 // API callbacks can have per callback access exceptions.
791 switch (result->type()) {
792 case CALLBACKS: {
793 if (CheckAccessException(result, access_type)) {
794 return true;
795 }
796 break;
797 }
798 case INTERCEPTOR: {
799 // If the object has an interceptor, try real named properties.
800 // Overwrite the result to fetch the correct property later.
801 holder->LookupRealNamedProperty(name, result);
802 if (result->IsProperty()) {
803 if (CheckAccessException(result, access_type)) {
804 return true;
805 }
806 }
807 break;
808 }
809 default:
810 break;
811 }
812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000813 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000814 return false;
815}
816
817
818// TODO(1095): we should traverse hidden prototype hierachy as well.
819static bool CheckElementAccess(JSObject* obj,
820 uint32_t index,
821 v8::AccessType access_type) {
822 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000823 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000824 return false;
825 }
826
827 return true;
828}
829
830
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000831// Enumerator used as indices into the array returned from GetOwnProperty
832enum PropertyDescriptorIndices {
833 IS_ACCESSOR_INDEX,
834 VALUE_INDEX,
835 GETTER_INDEX,
836 SETTER_INDEX,
837 WRITABLE_INDEX,
838 ENUMERABLE_INDEX,
839 CONFIGURABLE_INDEX,
840 DESCRIPTOR_SIZE
841};
842
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000843// Returns an array with the property description:
844// if args[1] is not a property on args[0]
845// returns undefined
846// if args[1] is a data property on args[0]
847// [false, value, Writeable, Enumerable, Configurable]
848// if args[1] is an accessor on args[0]
849// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000850RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000851 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000852 Heap* heap = isolate->heap();
853 HandleScope scope(isolate);
854 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
855 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000856 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000857 CONVERT_ARG_CHECKED(JSObject, obj, 0);
858 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000859
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000860 // This could be an element.
861 uint32_t index;
862 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000863 switch (obj->HasLocalElement(index)) {
864 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000866
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000867 case JSObject::STRING_CHARACTER_ELEMENT: {
868 // Special handling of string objects according to ECMAScript 5
869 // 15.5.5.2. Note that this might be a string object with elements
870 // other than the actual string value. This is covered by the
871 // subsequent cases.
872 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
873 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000874 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000875
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000877 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 elms->set(WRITABLE_INDEX, heap->false_value());
879 elms->set(ENUMERABLE_INDEX, heap->false_value());
880 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000881 return *desc;
882 }
883
884 case JSObject::INTERCEPTED_ELEMENT:
885 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000886 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000887 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000889 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000890 elms->set(WRITABLE_INDEX, heap->true_value());
891 elms->set(ENUMERABLE_INDEX, heap->true_value());
892 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000893 return *desc;
894 }
895
896 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000897 Handle<JSObject> holder = obj;
898 if (obj->IsJSGlobalProxy()) {
899 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000900 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000901 ASSERT(proto->IsJSGlobalObject());
902 holder = Handle<JSObject>(JSObject::cast(proto));
903 }
904 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000905 int entry = dictionary->FindEntry(index);
906 ASSERT(entry != NumberDictionary::kNotFound);
907 PropertyDetails details = dictionary->DetailsAt(entry);
908 switch (details.type()) {
909 case CALLBACKS: {
910 // This is an accessor property with getter and/or setter.
911 FixedArray* callbacks =
912 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000914 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
915 elms->set(GETTER_INDEX, callbacks->get(0));
916 }
917 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
918 elms->set(SETTER_INDEX, callbacks->get(1));
919 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000920 break;
921 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000922 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000923 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000924 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000925 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000926 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000927 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000929 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000930 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000931 default:
932 UNREACHABLE();
933 break;
934 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000935 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
936 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000937 return *desc;
938 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000939 }
940 }
941
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000942 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000943 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000944
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000945 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000946 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000947 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000948
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000949 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000950 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000951 }
952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000953 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
954 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000955
956 bool is_js_accessor = (result.type() == CALLBACKS) &&
957 (result.GetCallbackObject()->IsFixedArray());
958
959 if (is_js_accessor) {
960 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000962
963 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
964 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
965 elms->set(GETTER_INDEX, structure->get(0));
966 }
967 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
968 elms->set(SETTER_INDEX, structure->get(1));
969 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000970 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000971 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
972 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000973
974 PropertyAttributes attrs;
975 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000976 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000977 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
978 if (!maybe_value->ToObject(&value)) return maybe_value;
979 }
980 elms->set(VALUE_INDEX, value);
981 }
982
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000983 return *desc;
984}
985
986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000987RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000988 ASSERT(args.length() == 1);
989 CONVERT_CHECKED(JSObject, obj, args[0]);
990 return obj->PreventExtensions();
991}
992
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000993
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000994RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000995 ASSERT(args.length() == 1);
996 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000997 if (obj->IsJSGlobalProxy()) {
998 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000999 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001000 ASSERT(proto->IsJSGlobalObject());
1001 obj = JSObject::cast(proto);
1002 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 return obj->map()->is_extensible() ? isolate->heap()->true_value()
1004 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001005}
1006
1007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001008RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001011 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1012 CONVERT_ARG_CHECKED(String, pattern, 1);
1013 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001014 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1015 if (result.is_null()) return Failure::Exception();
1016 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017}
1018
1019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001020RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001021 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001023 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001024 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025}
1026
1027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001028RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 ASSERT(args.length() == 1);
1030 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001031 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033}
1034
1035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001036RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001037 ASSERT(args.length() == 2);
1038 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001040 int index = field->value();
1041 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1042 InstanceType type = templ->map()->instance_type();
1043 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1044 type == OBJECT_TEMPLATE_INFO_TYPE);
1045 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001046 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001047 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1048 } else {
1049 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1050 }
1051 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052}
1053
1054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001055RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001056 ASSERT(args.length() == 1);
1057 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001058 Map* old_map = object->map();
1059 bool needs_access_checks = old_map->is_access_check_needed();
1060 if (needs_access_checks) {
1061 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001062 Object* new_map;
1063 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1064 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1065 }
ager@chromium.org32912102009-01-16 10:38:43 +00001066
1067 Map::cast(new_map)->set_is_access_check_needed(false);
1068 object->set_map(Map::cast(new_map));
1069 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 return needs_access_checks ? isolate->heap()->true_value()
1071 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001072}
1073
1074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001075RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001076 ASSERT(args.length() == 1);
1077 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001078 Map* old_map = object->map();
1079 if (!old_map->is_access_check_needed()) {
1080 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001081 Object* new_map;
1082 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1083 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1084 }
ager@chromium.org32912102009-01-16 10:38:43 +00001085
1086 Map::cast(new_map)->set_is_access_check_needed(true);
1087 object->set_map(Map::cast(new_map));
1088 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001090}
1091
1092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093static Failure* ThrowRedeclarationError(Isolate* isolate,
1094 const char* type,
1095 Handle<String> name) {
1096 HandleScope scope(isolate);
1097 Handle<Object> type_handle =
1098 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099 Handle<Object> args[2] = { type_handle, name };
1100 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1102 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103}
1104
1105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001106RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001107 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001108 HandleScope scope(isolate);
1109 Handle<GlobalObject> global = Handle<GlobalObject>(
1110 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
ager@chromium.org3811b432009-10-28 14:53:37 +00001112 Handle<Context> context = args.at<Context>(0);
1113 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001115 StrictModeFlag strict_mode =
1116 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1117 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118
1119 // Compute the property attributes. According to ECMA-262, section
1120 // 13, page 71, the property must be read-only and
1121 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1122 // property as read-only, so we don't either.
1123 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1124
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125 // Traverse the name/value pairs and set the properties.
1126 int length = pairs->length();
1127 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001128 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001130 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131
1132 // We have to declare a global const property. To capture we only
1133 // assign to it when evaluating the assignment for "const x =
1134 // <expr>" the initial value is the hole.
1135 bool is_const_property = value->IsTheHole();
1136
1137 if (value->IsUndefined() || is_const_property) {
1138 // Lookup the property in the global object, and don't set the
1139 // value of the variable if the property is already there.
1140 LookupResult lookup;
1141 global->Lookup(*name, &lookup);
1142 if (lookup.IsProperty()) {
1143 // Determine if the property is local by comparing the holder
1144 // against the global object. The information will be used to
1145 // avoid throwing re-declaration errors when declaring
1146 // variables or constants that exist in the prototype chain.
1147 bool is_local = (*global == lookup.holder());
1148 // Get the property attributes and determine if the property is
1149 // read-only.
1150 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1151 bool is_read_only = (attributes & READ_ONLY) != 0;
1152 if (lookup.type() == INTERCEPTOR) {
1153 // If the interceptor says the property is there, we
1154 // just return undefined without overwriting the property.
1155 // Otherwise, we continue to setting the property.
1156 if (attributes != ABSENT) {
1157 // Check if the existing property conflicts with regards to const.
1158 if (is_local && (is_read_only || is_const_property)) {
1159 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 };
1162 // The property already exists without conflicting: Go to
1163 // the next declaration.
1164 continue;
1165 }
1166 // Fall-through and introduce the absent property by using
1167 // SetProperty.
1168 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001169 // For const properties, we treat a callback with this name
1170 // even in the prototype as a conflicting declaration.
1171 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
1174 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 if (is_local && (is_read_only || is_const_property)) {
1176 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 }
1179 // The property already exists without conflicting: Go to
1180 // the next declaration.
1181 continue;
1182 }
1183 }
1184 } else {
1185 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001186 Handle<SharedFunctionInfo> shared =
1187 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1190 context,
1191 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 value = function;
1193 }
1194
1195 LookupResult lookup;
1196 global->LocalLookup(*name, &lookup);
1197
1198 PropertyAttributes attributes = is_const_property
1199 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1200 : base;
1201
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001202 // There's a local property that we need to overwrite because
1203 // we're either declaring a function or there's an interceptor
1204 // that claims the property is absent.
1205 //
1206 // Check for conflicting re-declarations. We cannot have
1207 // conflicting types in case of intercepted properties because
1208 // they are absent.
1209 if (lookup.IsProperty() &&
1210 (lookup.type() != INTERCEPTOR) &&
1211 (lookup.IsReadOnly() || is_const_property)) {
1212 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001213 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001216 // Safari does not allow the invocation of callback setters for
1217 // function declarations. To mimic this behavior, we do not allow
1218 // the invocation of setters for function values. This makes a
1219 // difference for global functions with the same names as event
1220 // handlers such as "function onload() {}". Firefox does call the
1221 // onload setter in those case and Safari does not. We follow
1222 // Safari for compatibility.
1223 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001224 // Do not change DONT_DELETE to false from true.
1225 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1226 attributes = static_cast<PropertyAttributes>(
1227 attributes | (lookup.GetAttributes() & DONT_DELETE));
1228 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001229 RETURN_IF_EMPTY_HANDLE(isolate,
1230 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001231 name,
1232 value,
1233 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 RETURN_IF_EMPTY_HANDLE(isolate,
1236 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001237 name,
1238 value,
1239 attributes,
1240 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 }
1242 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001244 ASSERT(!isolate->has_pending_exception());
1245 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246}
1247
1248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001249RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001250 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001251 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252
ager@chromium.org7c537e22008-10-16 08:43:32 +00001253 CONVERT_ARG_CHECKED(Context, context, 0);
1254 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001256 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001257 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001258 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259
1260 // Declarations are always done in the function context.
1261 context = Handle<Context>(context->fcontext());
1262
1263 int index;
1264 PropertyAttributes attributes;
1265 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001266 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 context->Lookup(name, flags, &index, &attributes);
1268
1269 if (attributes != ABSENT) {
1270 // The name was declared before; check for conflicting
1271 // re-declarations: This is similar to the code in parser.cc in
1272 // the AstBuildingParser::Declare function.
1273 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1274 // Functions are not read-only.
1275 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1276 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 }
1279
1280 // Initialize it if necessary.
1281 if (*initial_value != NULL) {
1282 if (index >= 0) {
1283 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001284 // the function context or the arguments object.
1285 if (holder->IsContext()) {
1286 ASSERT(holder.is_identical_to(context));
1287 if (((attributes & READ_ONLY) == 0) ||
1288 context->get(index)->IsTheHole()) {
1289 context->set(index, *initial_value);
1290 }
1291 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001292 // The holder is an arguments object.
1293 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001294 Handle<Object> result = SetElement(arguments, index, initial_value,
1295 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001296 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297 }
1298 } else {
1299 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001300 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001301 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001303 SetProperty(context_ext, name, initial_value,
1304 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 }
1306 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001309 // The property is not in the function context. It needs to be
1310 // "declared" in the function context's extension context, or in the
1311 // global context.
1312 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001313 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001314 // The function context's extension context exists - use it.
1315 context_ext = Handle<JSObject>(context->extension());
1316 } else {
1317 // The function context's extension context does not exists - allocate
1318 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 context_ext = isolate->factory()->NewJSObject(
1320 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001321 // And store it in the extension slot.
1322 context->set_extension(*context_ext);
1323 }
1324 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325
ager@chromium.org7c537e22008-10-16 08:43:32 +00001326 // Declare the property by setting it to the initial value if provided,
1327 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1328 // constant declarations).
1329 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001330 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001331 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001332 // Declaring a const context slot is a conflicting declaration if
1333 // there is a callback with that name in a prototype. It is
1334 // allowed to introduce const variables in
1335 // JSContextExtensionObjects. They are treated specially in
1336 // SetProperty and no setters are invoked for those since they are
1337 // not real JSObjects.
1338 if (initial_value->IsTheHole() &&
1339 !context_ext->IsJSContextExtensionObject()) {
1340 LookupResult lookup;
1341 context_ext->Lookup(*name, &lookup);
1342 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001343 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001344 }
1345 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001346 RETURN_IF_EMPTY_HANDLE(isolate,
1347 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349 }
1350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352}
1353
1354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001355RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001357 // args[0] == name
1358 // args[1] == strict_mode
1359 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360
1361 // Determine if we need to assign to the variable if it already
1362 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001363 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1364 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365
1366 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001367 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001368 RUNTIME_ASSERT(args[1]->IsSmi());
1369 StrictModeFlag strict_mode =
1370 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1371 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372
1373 // According to ECMA-262, section 12.2, page 62, the property must
1374 // not be deletable.
1375 PropertyAttributes attributes = DONT_DELETE;
1376
1377 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001378 // there, there is a property with this name in the prototype chain.
1379 // We follow Safari and Firefox behavior and only set the property
1380 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001381 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001382 // Note that objects can have hidden prototypes, so we need to traverse
1383 // the whole chain of hidden prototypes to do a 'local' lookup.
1384 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001386 while (true) {
1387 real_holder->LocalLookup(*name, &lookup);
1388 if (lookup.IsProperty()) {
1389 // Determine if this is a redeclaration of something read-only.
1390 if (lookup.IsReadOnly()) {
1391 // If we found readonly property on one of hidden prototypes,
1392 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001393 if (real_holder != isolate->context()->global()) break;
1394 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001395 }
1396
1397 // Determine if this is a redeclaration of an intercepted read-only
1398 // property and figure out if the property exists at all.
1399 bool found = true;
1400 PropertyType type = lookup.type();
1401 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001403 Handle<JSObject> holder(real_holder);
1404 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1405 real_holder = *holder;
1406 if (intercepted == ABSENT) {
1407 // The interceptor claims the property isn't there. We need to
1408 // make sure to introduce it.
1409 found = false;
1410 } else if ((intercepted & READ_ONLY) != 0) {
1411 // The property is present, but read-only. Since we're trying to
1412 // overwrite it with a variable declaration we must throw a
1413 // re-declaration error. However if we found readonly property
1414 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 if (real_holder != isolate->context()->global()) break;
1416 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001417 }
1418 }
1419
1420 if (found && !assign) {
1421 // The global property is there and we're not assigning any value
1422 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001423 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001424 }
1425
1426 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001427 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001428 return real_holder->SetProperty(
1429 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001430 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001431
1432 Object* proto = real_holder->GetPrototype();
1433 if (!proto->IsJSObject())
1434 break;
1435
1436 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1437 break;
1438
1439 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440 }
1441
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001442 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001443 if (assign) {
1444 return global->SetProperty(*name, args[2], attributes, strict_mode);
1445 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447}
1448
1449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001450RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 // All constants are declared with an initial value. The name
1452 // of the constant is the first argument and the initial value
1453 // is the second.
1454 RUNTIME_ASSERT(args.length() == 2);
1455 CONVERT_ARG_CHECKED(String, name, 0);
1456 Handle<Object> value = args.at<Object>(1);
1457
1458 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001459 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 // According to ECMA-262, section 12.2, page 62, the property must
1462 // not be deletable. Since it's a const, it must be READ_ONLY too.
1463 PropertyAttributes attributes =
1464 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1465
1466 // Lookup the property locally in the global object. If it isn't
1467 // there, we add the property and take special precautions to always
1468 // add it as a local property even in case of callbacks in the
1469 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001470 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 LookupResult lookup;
1472 global->LocalLookup(*name, &lookup);
1473 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001474 return global->SetLocalPropertyIgnoreAttributes(*name,
1475 *value,
1476 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 }
1478
1479 // Determine if this is a redeclaration of something not
1480 // read-only. In case the result is hidden behind an interceptor we
1481 // need to ask it for the property attributes.
1482 if (!lookup.IsReadOnly()) {
1483 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485 }
1486
1487 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1488
1489 // Throw re-declaration error if the intercepted property is present
1490 // but not read-only.
1491 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001492 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493 }
1494
1495 // Restore global object from context (in case of GC) and continue
1496 // with setting the value because the property is either absent or
1497 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001498 HandleScope handle_scope(isolate);
1499 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001501 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 // property through an interceptor and only do it if it's
1503 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001504 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 RETURN_IF_EMPTY_HANDLE(isolate,
1506 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001507 name,
1508 value,
1509 attributes,
1510 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001511 return *value;
1512 }
1513
1514 // Set the value, but only we're assigning the initial value to a
1515 // constant. For now, we determine this by checking if the
1516 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001517 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001518 PropertyType type = lookup.type();
1519 if (type == FIELD) {
1520 FixedArray* properties = global->properties();
1521 int index = lookup.GetFieldIndex();
1522 if (properties->get(index)->IsTheHole()) {
1523 properties->set(index, *value);
1524 }
1525 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001526 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1527 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 }
1529 } else {
1530 // Ignore re-initialization of constants that have already been
1531 // assigned a function value.
1532 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1533 }
1534
1535 // Use the set value as the result of the operation.
1536 return *value;
1537}
1538
1539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001540RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001541 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 ASSERT(args.length() == 3);
1543
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001544 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545 ASSERT(!value->IsTheHole());
1546 CONVERT_ARG_CHECKED(Context, context, 1);
1547 Handle<String> name(String::cast(args[2]));
1548
1549 // Initializations are always done in the function context.
1550 context = Handle<Context>(context->fcontext());
1551
1552 int index;
1553 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001554 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001555 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 context->Lookup(name, flags, &index, &attributes);
1557
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001558 // In most situations, the property introduced by the const
1559 // declaration should be present in the context extension object.
1560 // However, because declaration and initialization are separate, the
1561 // property might have been deleted (if it was introduced by eval)
1562 // before we reach the initialization point.
1563 //
1564 // Example:
1565 //
1566 // function f() { eval("delete x; const x;"); }
1567 //
1568 // In that case, the initialization behaves like a normal assignment
1569 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001571 // Property was found in a context.
1572 if (holder->IsContext()) {
1573 // The holder cannot be the function context. If it is, there
1574 // should have been a const redeclaration error when declaring
1575 // the const property.
1576 ASSERT(!holder.is_identical_to(context));
1577 if ((attributes & READ_ONLY) == 0) {
1578 Handle<Context>::cast(holder)->set(index, *value);
1579 }
1580 } else {
1581 // The holder is an arguments object.
1582 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001583 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001584 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001585 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001586 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001587 }
1588 return *value;
1589 }
1590
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001591 // The property could not be found, we introduce it in the global
1592 // context.
1593 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 Handle<JSObject> global = Handle<JSObject>(
1595 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001596 // Strict mode not needed (const disallowed in strict mode).
1597 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001599 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001600 return *value;
1601 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001603 // The property was present in a context extension object.
1604 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001606 if (*context_ext == context->extension()) {
1607 // This is the property that was introduced by the const
1608 // declaration. Set it if it hasn't been set before. NOTE: We
1609 // cannot use GetProperty() to get the current value as it
1610 // 'unholes' the value.
1611 LookupResult lookup;
1612 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1613 ASSERT(lookup.IsProperty()); // the property was declared
1614 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1615
1616 PropertyType type = lookup.type();
1617 if (type == FIELD) {
1618 FixedArray* properties = context_ext->properties();
1619 int index = lookup.GetFieldIndex();
1620 if (properties->get(index)->IsTheHole()) {
1621 properties->set(index, *value);
1622 }
1623 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001624 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1625 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 }
1627 } else {
1628 // We should not reach here. Any real, named property should be
1629 // either a field or a dictionary slot.
1630 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 }
1632 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001633 // The property was found in a different context extension object.
1634 // Set it if it is not a read-only property.
1635 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001636 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001637 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001638 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001639 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643 return *value;
1644}
1645
1646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001647RUNTIME_FUNCTION(MaybeObject*,
1648 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001650 ASSERT(args.length() == 2);
1651 CONVERT_ARG_CHECKED(JSObject, object, 0);
1652 CONVERT_SMI_CHECKED(properties, args[1]);
1653 if (object->HasFastProperties()) {
1654 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1655 }
1656 return *object;
1657}
1658
1659
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001660RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001661 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001662 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001663 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1664 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001665 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001666 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001667 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001668 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001669 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001670 RUNTIME_ASSERT(index >= 0);
1671 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001672 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001673 Handle<Object> result = RegExpImpl::Exec(regexp,
1674 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001675 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001676 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001677 if (result.is_null()) return Failure::Exception();
1678 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679}
1680
1681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001682RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001683 ASSERT(args.length() == 3);
1684 CONVERT_SMI_CHECKED(elements_count, args[0]);
1685 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001686 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001687 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001688 Object* new_object;
1689 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001690 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001691 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1692 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001693 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001694 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1695 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001696 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1697 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001698 {
1699 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001701 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001702 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001703 }
1704 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001706 array->set_elements(elements);
1707 array->set_length(Smi::FromInt(elements_count));
1708 // Write in-object properties after the length of the array.
1709 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1710 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1711 return array;
1712}
1713
1714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001715RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001716 AssertNoAllocation no_alloc;
1717 ASSERT(args.length() == 5);
1718 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1719 CONVERT_CHECKED(String, source, args[1]);
1720
1721 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001723
1724 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001726
1727 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001728 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001729
1730 Map* map = regexp->map();
1731 Object* constructor = map->constructor();
1732 if (constructor->IsJSFunction() &&
1733 JSFunction::cast(constructor)->initial_map() == map) {
1734 // If we still have the original map, set in-object properties directly.
1735 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1736 // TODO(lrn): Consider skipping write barrier on booleans as well.
1737 // Both true and false should be in oldspace at all times.
1738 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1739 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1740 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1741 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1742 Smi::FromInt(0),
1743 SKIP_WRITE_BARRIER);
1744 return regexp;
1745 }
1746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001748 PropertyAttributes final =
1749 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1750 PropertyAttributes writable =
1751 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001753 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001755 source,
1756 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001758 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001759 global,
1760 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001761 ASSERT(!result->IsFailure());
1762 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001764 ignoreCase,
1765 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001767 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001768 multiline,
1769 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001770 ASSERT(!result->IsFailure());
1771 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001773 Smi::FromInt(0),
1774 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001775 ASSERT(!result->IsFailure());
1776 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777 return regexp;
1778}
1779
1780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001781RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001782 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001783 ASSERT(args.length() == 1);
1784 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1785 // This is necessary to enable fast checks for absence of elements
1786 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001787 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001788 return Smi::FromInt(0);
1789}
1790
1791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001792static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1793 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001794 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001795 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1797 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1798 Handle<JSFunction> optimized =
1799 isolate->factory()->NewFunction(key,
1800 JS_OBJECT_TYPE,
1801 JSObject::kHeaderSize,
1802 code,
1803 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001804 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001805 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001806 return optimized;
1807}
1808
1809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001810RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001812 ASSERT(args.length() == 1);
1813 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1814
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001815 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1816 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1817 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1818 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1819 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1820 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1821 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001822
1823 return *holder;
1824}
1825
1826
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001827RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001828 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 Context* global_context =
1830 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001831 return global_context->global()->global_receiver();
1832}
1833
1834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001835RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 ASSERT(args.length() == 4);
1838 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1839 int index = Smi::cast(args[1])->value();
1840 Handle<String> pattern = args.at<String>(2);
1841 Handle<String> flags = args.at<String>(3);
1842
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001843 // Get the RegExp function from the context in the literals array.
1844 // This is the RegExp function from the context in which the
1845 // function was created. We do not use the RegExp function from the
1846 // current global context because this might be the RegExp function
1847 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001848 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001849 Handle<JSFunction>(
1850 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001851 // Compute the regular expression literal.
1852 bool has_pending_exception;
1853 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001854 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1855 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 return Failure::Exception();
1859 }
1860 literals->set(index, *regexp);
1861 return *regexp;
1862}
1863
1864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001865RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001866 NoHandleAllocation ha;
1867 ASSERT(args.length() == 1);
1868
1869 CONVERT_CHECKED(JSFunction, f, args[0]);
1870 return f->shared()->name();
1871}
1872
1873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001874RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001875 NoHandleAllocation ha;
1876 ASSERT(args.length() == 2);
1877
1878 CONVERT_CHECKED(JSFunction, f, args[0]);
1879 CONVERT_CHECKED(String, name, args[1]);
1880 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001881 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001882}
1883
1884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001885RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001886 NoHandleAllocation ha;
1887 ASSERT(args.length() == 1);
1888
1889 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001890 Object* obj = f->RemovePrototype();
1891 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001893 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001894}
1895
1896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001897RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001898 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899 ASSERT(args.length() == 1);
1900
1901 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001902 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1903 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904
1905 return *GetScriptWrapper(Handle<Script>::cast(script));
1906}
1907
1908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001909RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 NoHandleAllocation ha;
1911 ASSERT(args.length() == 1);
1912
1913 CONVERT_CHECKED(JSFunction, f, args[0]);
1914 return f->shared()->GetSourceCode();
1915}
1916
1917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 NoHandleAllocation ha;
1920 ASSERT(args.length() == 1);
1921
1922 CONVERT_CHECKED(JSFunction, fun, args[0]);
1923 int pos = fun->shared()->start_position();
1924 return Smi::FromInt(pos);
1925}
1926
1927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001928RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001929 ASSERT(args.length() == 2);
1930
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001931 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001932 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1933
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001934 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1935
1936 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001937 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001938}
1939
1940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001941RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942 NoHandleAllocation ha;
1943 ASSERT(args.length() == 2);
1944
1945 CONVERT_CHECKED(JSFunction, fun, args[0]);
1946 CONVERT_CHECKED(String, name, args[1]);
1947 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001948 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949}
1950
1951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001952RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 NoHandleAllocation ha;
1954 ASSERT(args.length() == 2);
1955
1956 CONVERT_CHECKED(JSFunction, fun, args[0]);
1957 CONVERT_CHECKED(Smi, length, args[1]);
1958 fun->shared()->set_length(length->value());
1959 return length;
1960}
1961
1962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001964 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001965 ASSERT(args.length() == 2);
1966
1967 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001968 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001969 Object* obj;
1970 { MaybeObject* maybe_obj =
1971 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1972 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001974 return args[0]; // return TOS
1975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001979 NoHandleAllocation ha;
1980 ASSERT(args.length() == 1);
1981
1982 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001983 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1984 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001985}
1986
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001988RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001989 NoHandleAllocation ha;
1990 ASSERT(args.length() == 1);
1991
1992 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001993 return f->IsBuiltin() ? isolate->heap()->true_value() :
1994 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001995}
1996
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001999 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002000 ASSERT(args.length() == 2);
2001
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002002 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003 Handle<Object> code = args.at<Object>(1);
2004
2005 Handle<Context> context(target->context());
2006
2007 if (!code->IsNull()) {
2008 RUNTIME_ASSERT(code->IsJSFunction());
2009 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002010 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002011
2012 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 return Failure::Exception();
2014 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002015 // Since we don't store the source for this we should never
2016 // optimize this.
2017 shared->code()->set_optimizable(false);
2018
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002019 // Set the code, scope info, formal parameter count,
2020 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002021 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002022 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002023 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002024 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002026 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002027 // Set the source code of the target function to undefined.
2028 // SetCode is only used for built-in constructors like String,
2029 // Array, and Object, and some web code
2030 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002032 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002033 // Clear the optimization hints related to the compiled code as these are no
2034 // longer valid when the code is overwritten.
2035 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036 context = Handle<Context>(fun->context());
2037
2038 // Make sure we get a fresh copy of the literal vector to avoid
2039 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002040 int number_of_literals = fun->NumberOfLiterals();
2041 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002042 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002043 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002044 // Insert the object, regexp and array functions in the literals
2045 // array prefix. These are the functions that will be used when
2046 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002047 literals->set(JSFunction::kLiteralGlobalContextIndex,
2048 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002050 // It's okay to skip the write barrier here because the literals
2051 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002052 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002053 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002054 }
2055
2056 target->set_context(*context);
2057 return *target;
2058}
2059
2060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002061RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002062 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002063 ASSERT(args.length() == 2);
2064 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2065 CONVERT_SMI_CHECKED(num, args[1]);
2066 RUNTIME_ASSERT(num >= 0);
2067 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002069}
2070
2071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2073 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002074 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002075 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002076 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002077 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002078 }
2079 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002080 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002081}
2082
2083
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002084RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002085 NoHandleAllocation ha;
2086 ASSERT(args.length() == 2);
2087
2088 CONVERT_CHECKED(String, subject, args[0]);
2089 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002090 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002091
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002092 uint32_t i = 0;
2093 if (index->IsSmi()) {
2094 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002095 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002096 i = value;
2097 } else {
2098 ASSERT(index->IsHeapNumber());
2099 double value = HeapNumber::cast(index)->value();
2100 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002101 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002102
2103 // Flatten the string. If someone wants to get a char at an index
2104 // in a cons string, it is likely that more indices will be
2105 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002106 Object* flat;
2107 { MaybeObject* maybe_flat = subject->TryFlatten();
2108 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2109 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002110 subject = String::cast(flat);
2111
2112 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002113 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002114 }
2115
2116 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002117}
2118
2119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002120RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002121 NoHandleAllocation ha;
2122 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002123 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002124}
2125
lrn@chromium.org25156de2010-04-06 13:10:27 +00002126
2127class FixedArrayBuilder {
2128 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002129 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2130 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002131 length_(0) {
2132 // Require a non-zero initial size. Ensures that doubling the size to
2133 // extend the array will work.
2134 ASSERT(initial_capacity > 0);
2135 }
2136
2137 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2138 : array_(backing_store),
2139 length_(0) {
2140 // Require a non-zero initial size. Ensures that doubling the size to
2141 // extend the array will work.
2142 ASSERT(backing_store->length() > 0);
2143 }
2144
2145 bool HasCapacity(int elements) {
2146 int length = array_->length();
2147 int required_length = length_ + elements;
2148 return (length >= required_length);
2149 }
2150
2151 void EnsureCapacity(int elements) {
2152 int length = array_->length();
2153 int required_length = length_ + elements;
2154 if (length < required_length) {
2155 int new_length = length;
2156 do {
2157 new_length *= 2;
2158 } while (new_length < required_length);
2159 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002160 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002161 array_->CopyTo(0, *extended_array, 0, length_);
2162 array_ = extended_array;
2163 }
2164 }
2165
2166 void Add(Object* value) {
2167 ASSERT(length_ < capacity());
2168 array_->set(length_, value);
2169 length_++;
2170 }
2171
2172 void Add(Smi* value) {
2173 ASSERT(length_ < capacity());
2174 array_->set(length_, value);
2175 length_++;
2176 }
2177
2178 Handle<FixedArray> array() {
2179 return array_;
2180 }
2181
2182 int length() {
2183 return length_;
2184 }
2185
2186 int capacity() {
2187 return array_->length();
2188 }
2189
2190 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002191 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002192 result_array->set_length(Smi::FromInt(length_));
2193 return result_array;
2194 }
2195
2196 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2197 target_array->set_elements(*array_);
2198 target_array->set_length(Smi::FromInt(length_));
2199 return target_array;
2200 }
2201
2202 private:
2203 Handle<FixedArray> array_;
2204 int length_;
2205};
2206
2207
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002208// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002209const int kStringBuilderConcatHelperLengthBits = 11;
2210const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211
2212template <typename schar>
2213static inline void StringBuilderConcatHelper(String*,
2214 schar*,
2215 FixedArray*,
2216 int);
2217
lrn@chromium.org25156de2010-04-06 13:10:27 +00002218typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2219 StringBuilderSubstringLength;
2220typedef BitField<int,
2221 kStringBuilderConcatHelperLengthBits,
2222 kStringBuilderConcatHelperPositionBits>
2223 StringBuilderSubstringPosition;
2224
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002225
2226class ReplacementStringBuilder {
2227 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002228 ReplacementStringBuilder(Heap* heap,
2229 Handle<String> subject,
2230 int estimated_part_count)
2231 : heap_(heap),
2232 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002233 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002234 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002235 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002236 // Require a non-zero initial size. Ensures that doubling the size to
2237 // extend the array will work.
2238 ASSERT(estimated_part_count > 0);
2239 }
2240
lrn@chromium.org25156de2010-04-06 13:10:27 +00002241 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2242 int from,
2243 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 ASSERT(from >= 0);
2245 int length = to - from;
2246 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002247 if (StringBuilderSubstringLength::is_valid(length) &&
2248 StringBuilderSubstringPosition::is_valid(from)) {
2249 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2250 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002251 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002252 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002253 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 builder->Add(Smi::FromInt(-length));
2255 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002257 }
2258
2259
2260 void EnsureCapacity(int elements) {
2261 array_builder_.EnsureCapacity(elements);
2262 }
2263
2264
2265 void AddSubjectSlice(int from, int to) {
2266 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002267 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002268 }
2269
2270
2271 void AddString(Handle<String> string) {
2272 int length = string->length();
2273 ASSERT(length > 0);
2274 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002275 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002276 is_ascii_ = false;
2277 }
2278 IncrementCharacterCount(length);
2279 }
2280
2281
2282 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002285 }
2286
2287 Handle<String> joined_string;
2288 if (is_ascii_) {
2289 joined_string = NewRawAsciiString(character_count_);
2290 AssertNoAllocation no_alloc;
2291 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2292 char* char_buffer = seq->GetChars();
2293 StringBuilderConcatHelper(*subject_,
2294 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002295 *array_builder_.array(),
2296 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002297 } else {
2298 // Non-ASCII.
2299 joined_string = NewRawTwoByteString(character_count_);
2300 AssertNoAllocation no_alloc;
2301 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2302 uc16* char_buffer = seq->GetChars();
2303 StringBuilderConcatHelper(*subject_,
2304 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002305 *array_builder_.array(),
2306 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002307 }
2308 return joined_string;
2309 }
2310
2311
2312 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002313 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002314 V8::FatalProcessOutOfMemory("String.replace result too large.");
2315 }
2316 character_count_ += by;
2317 }
2318
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002320 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002321 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002322
lrn@chromium.org25156de2010-04-06 13:10:27 +00002323 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002324 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002325 CALL_HEAP_FUNCTION(heap_->isolate(),
2326 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002327 }
2328
2329
2330 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002331 CALL_HEAP_FUNCTION(heap_->isolate(),
2332 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002333 }
2334
2335
2336 void AddElement(Object* element) {
2337 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002338 ASSERT(array_builder_.capacity() > array_builder_.length());
2339 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002340 }
2341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002342 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002343 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002344 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002345 int character_count_;
2346 bool is_ascii_;
2347};
2348
2349
2350class CompiledReplacement {
2351 public:
2352 CompiledReplacement()
2353 : parts_(1), replacement_substrings_(0) {}
2354
2355 void Compile(Handle<String> replacement,
2356 int capture_count,
2357 int subject_length);
2358
2359 void Apply(ReplacementStringBuilder* builder,
2360 int match_from,
2361 int match_to,
2362 Handle<JSArray> last_match_info);
2363
2364 // Number of distinct parts of the replacement pattern.
2365 int parts() {
2366 return parts_.length();
2367 }
2368 private:
2369 enum PartType {
2370 SUBJECT_PREFIX = 1,
2371 SUBJECT_SUFFIX,
2372 SUBJECT_CAPTURE,
2373 REPLACEMENT_SUBSTRING,
2374 REPLACEMENT_STRING,
2375
2376 NUMBER_OF_PART_TYPES
2377 };
2378
2379 struct ReplacementPart {
2380 static inline ReplacementPart SubjectMatch() {
2381 return ReplacementPart(SUBJECT_CAPTURE, 0);
2382 }
2383 static inline ReplacementPart SubjectCapture(int capture_index) {
2384 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2385 }
2386 static inline ReplacementPart SubjectPrefix() {
2387 return ReplacementPart(SUBJECT_PREFIX, 0);
2388 }
2389 static inline ReplacementPart SubjectSuffix(int subject_length) {
2390 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2391 }
2392 static inline ReplacementPart ReplacementString() {
2393 return ReplacementPart(REPLACEMENT_STRING, 0);
2394 }
2395 static inline ReplacementPart ReplacementSubString(int from, int to) {
2396 ASSERT(from >= 0);
2397 ASSERT(to > from);
2398 return ReplacementPart(-from, to);
2399 }
2400
2401 // If tag <= 0 then it is the negation of a start index of a substring of
2402 // the replacement pattern, otherwise it's a value from PartType.
2403 ReplacementPart(int tag, int data)
2404 : tag(tag), data(data) {
2405 // Must be non-positive or a PartType value.
2406 ASSERT(tag < NUMBER_OF_PART_TYPES);
2407 }
2408 // Either a value of PartType or a non-positive number that is
2409 // the negation of an index into the replacement string.
2410 int tag;
2411 // The data value's interpretation depends on the value of tag:
2412 // tag == SUBJECT_PREFIX ||
2413 // tag == SUBJECT_SUFFIX: data is unused.
2414 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2415 // tag == REPLACEMENT_SUBSTRING ||
2416 // tag == REPLACEMENT_STRING: data is index into array of substrings
2417 // of the replacement string.
2418 // tag <= 0: Temporary representation of the substring of the replacement
2419 // string ranging over -tag .. data.
2420 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2421 // substring objects.
2422 int data;
2423 };
2424
2425 template<typename Char>
2426 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2427 Vector<Char> characters,
2428 int capture_count,
2429 int subject_length) {
2430 int length = characters.length();
2431 int last = 0;
2432 for (int i = 0; i < length; i++) {
2433 Char c = characters[i];
2434 if (c == '$') {
2435 int next_index = i + 1;
2436 if (next_index == length) { // No next character!
2437 break;
2438 }
2439 Char c2 = characters[next_index];
2440 switch (c2) {
2441 case '$':
2442 if (i > last) {
2443 // There is a substring before. Include the first "$".
2444 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2445 last = next_index + 1; // Continue after the second "$".
2446 } else {
2447 // Let the next substring start with the second "$".
2448 last = next_index;
2449 }
2450 i = next_index;
2451 break;
2452 case '`':
2453 if (i > last) {
2454 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2455 }
2456 parts->Add(ReplacementPart::SubjectPrefix());
2457 i = next_index;
2458 last = i + 1;
2459 break;
2460 case '\'':
2461 if (i > last) {
2462 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2463 }
2464 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2465 i = next_index;
2466 last = i + 1;
2467 break;
2468 case '&':
2469 if (i > last) {
2470 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2471 }
2472 parts->Add(ReplacementPart::SubjectMatch());
2473 i = next_index;
2474 last = i + 1;
2475 break;
2476 case '0':
2477 case '1':
2478 case '2':
2479 case '3':
2480 case '4':
2481 case '5':
2482 case '6':
2483 case '7':
2484 case '8':
2485 case '9': {
2486 int capture_ref = c2 - '0';
2487 if (capture_ref > capture_count) {
2488 i = next_index;
2489 continue;
2490 }
2491 int second_digit_index = next_index + 1;
2492 if (second_digit_index < length) {
2493 // Peek ahead to see if we have two digits.
2494 Char c3 = characters[second_digit_index];
2495 if ('0' <= c3 && c3 <= '9') { // Double digits.
2496 int double_digit_ref = capture_ref * 10 + c3 - '0';
2497 if (double_digit_ref <= capture_count) {
2498 next_index = second_digit_index;
2499 capture_ref = double_digit_ref;
2500 }
2501 }
2502 }
2503 if (capture_ref > 0) {
2504 if (i > last) {
2505 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2506 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002507 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002508 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2509 last = next_index + 1;
2510 }
2511 i = next_index;
2512 break;
2513 }
2514 default:
2515 i = next_index;
2516 break;
2517 }
2518 }
2519 }
2520 if (length > last) {
2521 if (last == 0) {
2522 parts->Add(ReplacementPart::ReplacementString());
2523 } else {
2524 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2525 }
2526 }
2527 }
2528
2529 ZoneList<ReplacementPart> parts_;
2530 ZoneList<Handle<String> > replacement_substrings_;
2531};
2532
2533
2534void CompiledReplacement::Compile(Handle<String> replacement,
2535 int capture_count,
2536 int subject_length) {
2537 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002538 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002539 AssertNoAllocation no_alloc;
2540 ParseReplacementPattern(&parts_,
2541 replacement->ToAsciiVector(),
2542 capture_count,
2543 subject_length);
2544 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002545 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002546 AssertNoAllocation no_alloc;
2547
2548 ParseReplacementPattern(&parts_,
2549 replacement->ToUC16Vector(),
2550 capture_count,
2551 subject_length);
2552 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002553 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002554 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002555 int substring_index = 0;
2556 for (int i = 0, n = parts_.length(); i < n; i++) {
2557 int tag = parts_[i].tag;
2558 if (tag <= 0) { // A replacement string slice.
2559 int from = -tag;
2560 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002561 replacement_substrings_.Add(
2562 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002563 parts_[i].tag = REPLACEMENT_SUBSTRING;
2564 parts_[i].data = substring_index;
2565 substring_index++;
2566 } else if (tag == REPLACEMENT_STRING) {
2567 replacement_substrings_.Add(replacement);
2568 parts_[i].data = substring_index;
2569 substring_index++;
2570 }
2571 }
2572}
2573
2574
2575void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2576 int match_from,
2577 int match_to,
2578 Handle<JSArray> last_match_info) {
2579 for (int i = 0, n = parts_.length(); i < n; i++) {
2580 ReplacementPart part = parts_[i];
2581 switch (part.tag) {
2582 case SUBJECT_PREFIX:
2583 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2584 break;
2585 case SUBJECT_SUFFIX: {
2586 int subject_length = part.data;
2587 if (match_to < subject_length) {
2588 builder->AddSubjectSlice(match_to, subject_length);
2589 }
2590 break;
2591 }
2592 case SUBJECT_CAPTURE: {
2593 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002594 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002595 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2596 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2597 if (from >= 0 && to > from) {
2598 builder->AddSubjectSlice(from, to);
2599 }
2600 break;
2601 }
2602 case REPLACEMENT_SUBSTRING:
2603 case REPLACEMENT_STRING:
2604 builder->AddString(replacement_substrings_[part.data]);
2605 break;
2606 default:
2607 UNREACHABLE();
2608 }
2609 }
2610}
2611
2612
2613
lrn@chromium.org303ada72010-10-27 09:33:13 +00002614MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002615 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002616 String* subject,
2617 JSRegExp* regexp,
2618 String* replacement,
2619 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002620 ASSERT(subject->IsFlat());
2621 ASSERT(replacement->IsFlat());
2622
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002623 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002624
2625 int length = subject->length();
2626 Handle<String> subject_handle(subject);
2627 Handle<JSRegExp> regexp_handle(regexp);
2628 Handle<String> replacement_handle(replacement);
2629 Handle<JSArray> last_match_info_handle(last_match_info);
2630 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2631 subject_handle,
2632 0,
2633 last_match_info_handle);
2634 if (match.is_null()) {
2635 return Failure::Exception();
2636 }
2637 if (match->IsNull()) {
2638 return *subject_handle;
2639 }
2640
2641 int capture_count = regexp_handle->CaptureCount();
2642
2643 // CompiledReplacement uses zone allocation.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002644 CompilationZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002645 CompiledReplacement compiled_replacement;
2646 compiled_replacement.Compile(replacement_handle,
2647 capture_count,
2648 length);
2649
2650 bool is_global = regexp_handle->GetFlags().is_global();
2651
2652 // Guessing the number of parts that the final result string is built
2653 // from. Global regexps can match any number of times, so we guess
2654 // conservatively.
2655 int expected_parts =
2656 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002657 ReplacementStringBuilder builder(isolate->heap(),
2658 subject_handle,
2659 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002660
2661 // Index of end of last match.
2662 int prev = 0;
2663
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002664 // Number of parts added by compiled replacement plus preceeding
2665 // string and possibly suffix after last match. It is possible for
2666 // all components to use two elements when encoded as two smis.
2667 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002668 bool matched = true;
2669 do {
2670 ASSERT(last_match_info_handle->HasFastElements());
2671 // Increase the capacity of the builder before entering local handle-scope,
2672 // so its internal buffer can safely allocate a new handle if it grows.
2673 builder.EnsureCapacity(parts_added_per_loop);
2674
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002675 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002676 int start, end;
2677 {
2678 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002679 FixedArray* match_info_array =
2680 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002681
2682 ASSERT_EQ(capture_count * 2 + 2,
2683 RegExpImpl::GetLastCaptureCount(match_info_array));
2684 start = RegExpImpl::GetCapture(match_info_array, 0);
2685 end = RegExpImpl::GetCapture(match_info_array, 1);
2686 }
2687
2688 if (prev < start) {
2689 builder.AddSubjectSlice(prev, start);
2690 }
2691 compiled_replacement.Apply(&builder,
2692 start,
2693 end,
2694 last_match_info_handle);
2695 prev = end;
2696
2697 // Only continue checking for global regexps.
2698 if (!is_global) break;
2699
2700 // Continue from where the match ended, unless it was an empty match.
2701 int next = end;
2702 if (start == end) {
2703 next = end + 1;
2704 if (next > length) break;
2705 }
2706
2707 match = RegExpImpl::Exec(regexp_handle,
2708 subject_handle,
2709 next,
2710 last_match_info_handle);
2711 if (match.is_null()) {
2712 return Failure::Exception();
2713 }
2714 matched = !match->IsNull();
2715 } while (matched);
2716
2717 if (prev < length) {
2718 builder.AddSubjectSlice(prev, length);
2719 }
2720
2721 return *(builder.ToString());
2722}
2723
2724
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002725template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002726MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002727 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002728 String* subject,
2729 JSRegExp* regexp,
2730 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002731 ASSERT(subject->IsFlat());
2732
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002733 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002734
2735 Handle<String> subject_handle(subject);
2736 Handle<JSRegExp> regexp_handle(regexp);
2737 Handle<JSArray> last_match_info_handle(last_match_info);
2738 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2739 subject_handle,
2740 0,
2741 last_match_info_handle);
2742 if (match.is_null()) return Failure::Exception();
2743 if (match->IsNull()) return *subject_handle;
2744
2745 ASSERT(last_match_info_handle->HasFastElements());
2746
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002747 int start, end;
2748 {
2749 AssertNoAllocation match_info_array_is_not_in_a_handle;
2750 FixedArray* match_info_array =
2751 FixedArray::cast(last_match_info_handle->elements());
2752
2753 start = RegExpImpl::GetCapture(match_info_array, 0);
2754 end = RegExpImpl::GetCapture(match_info_array, 1);
2755 }
2756
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002757 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002758 int new_length = length - (end - start);
2759 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002760 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002761 }
2762 Handle<ResultSeqString> answer;
2763 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002764 answer = Handle<ResultSeqString>::cast(
2765 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002766 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002767 answer = Handle<ResultSeqString>::cast(
2768 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002769 }
2770
2771 // If the regexp isn't global, only match once.
2772 if (!regexp_handle->GetFlags().is_global()) {
2773 if (start > 0) {
2774 String::WriteToFlat(*subject_handle,
2775 answer->GetChars(),
2776 0,
2777 start);
2778 }
2779 if (end < length) {
2780 String::WriteToFlat(*subject_handle,
2781 answer->GetChars() + start,
2782 end,
2783 length);
2784 }
2785 return *answer;
2786 }
2787
2788 int prev = 0; // Index of end of last match.
2789 int next = 0; // Start of next search (prev unless last match was empty).
2790 int position = 0;
2791
2792 do {
2793 if (prev < start) {
2794 // Add substring subject[prev;start] to answer string.
2795 String::WriteToFlat(*subject_handle,
2796 answer->GetChars() + position,
2797 prev,
2798 start);
2799 position += start - prev;
2800 }
2801 prev = end;
2802 next = end;
2803 // Continue from where the match ended, unless it was an empty match.
2804 if (start == end) {
2805 next++;
2806 if (next > length) break;
2807 }
2808 match = RegExpImpl::Exec(regexp_handle,
2809 subject_handle,
2810 next,
2811 last_match_info_handle);
2812 if (match.is_null()) return Failure::Exception();
2813 if (match->IsNull()) break;
2814
2815 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002816 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002817 {
2818 AssertNoAllocation match_info_array_is_not_in_a_handle;
2819 FixedArray* match_info_array =
2820 FixedArray::cast(last_match_info_handle->elements());
2821 start = RegExpImpl::GetCapture(match_info_array, 0);
2822 end = RegExpImpl::GetCapture(match_info_array, 1);
2823 }
2824 } while (true);
2825
2826 if (prev < length) {
2827 // Add substring subject[prev;length] to answer string.
2828 String::WriteToFlat(*subject_handle,
2829 answer->GetChars() + position,
2830 prev,
2831 length);
2832 position += length - prev;
2833 }
2834
2835 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002836 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002837 }
2838
2839 // Shorten string and fill
2840 int string_size = ResultSeqString::SizeFor(position);
2841 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2842 int delta = allocated_string_size - string_size;
2843
2844 answer->set_length(position);
2845 if (delta == 0) return *answer;
2846
2847 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002848 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002849
2850 return *answer;
2851}
2852
2853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002854RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002855 ASSERT(args.length() == 4);
2856
2857 CONVERT_CHECKED(String, subject, args[0]);
2858 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002859 Object* flat_subject;
2860 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2861 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2862 return maybe_flat_subject;
2863 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002864 }
2865 subject = String::cast(flat_subject);
2866 }
2867
2868 CONVERT_CHECKED(String, replacement, args[2]);
2869 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002870 Object* flat_replacement;
2871 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2872 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2873 return maybe_flat_replacement;
2874 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002875 }
2876 replacement = String::cast(flat_replacement);
2877 }
2878
2879 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2880 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2881
2882 ASSERT(last_match_info->HasFastElements());
2883
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002884 if (replacement->length() == 0) {
2885 if (subject->HasOnlyAsciiChars()) {
2886 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002887 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002888 } else {
2889 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002890 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002891 }
2892 }
2893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002894 return StringReplaceRegExpWithString(isolate,
2895 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002896 regexp,
2897 replacement,
2898 last_match_info);
2899}
2900
2901
ager@chromium.org7c537e22008-10-16 08:43:32 +00002902// Perform string match of pattern on subject, starting at start index.
2903// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002904// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002905int Runtime::StringMatch(Isolate* isolate,
2906 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002907 Handle<String> pat,
2908 int start_index) {
2909 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002910 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002911
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002912 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002913 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002914
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002915 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002916 if (start_index + pattern_length > subject_length) return -1;
2917
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002918 if (!sub->IsFlat()) FlattenString(sub);
2919 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002920
ager@chromium.org7c537e22008-10-16 08:43:32 +00002921 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002922 // Extract flattened substrings of cons strings before determining asciiness.
2923 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002924 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002925 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002926 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002927
ager@chromium.org7c537e22008-10-16 08:43:32 +00002928 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002929 if (seq_pat->IsAsciiRepresentation()) {
2930 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2931 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002932 return SearchString(isolate,
2933 seq_sub->ToAsciiVector(),
2934 pat_vector,
2935 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002936 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002937 return SearchString(isolate,
2938 seq_sub->ToUC16Vector(),
2939 pat_vector,
2940 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002941 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002942 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2943 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002944 return SearchString(isolate,
2945 seq_sub->ToAsciiVector(),
2946 pat_vector,
2947 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002948 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 return SearchString(isolate,
2950 seq_sub->ToUC16Vector(),
2951 pat_vector,
2952 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002953}
2954
2955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002956RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002957 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002958 ASSERT(args.length() == 3);
2959
ager@chromium.org7c537e22008-10-16 08:43:32 +00002960 CONVERT_ARG_CHECKED(String, sub, 0);
2961 CONVERT_ARG_CHECKED(String, pat, 1);
2962
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002963 Object* index = args[2];
2964 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002965 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002966
ager@chromium.org870a0b62008-11-04 11:43:05 +00002967 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002968 int position =
2969 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002970 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002971}
2972
2973
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002974template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002975static int StringMatchBackwards(Vector<const schar> subject,
2976 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002977 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002978 int pattern_length = pattern.length();
2979 ASSERT(pattern_length >= 1);
2980 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981
2982 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002983 for (int i = 0; i < pattern_length; i++) {
2984 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 if (c > String::kMaxAsciiCharCode) {
2986 return -1;
2987 }
2988 }
2989 }
2990
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002991 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002992 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002993 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002994 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002995 while (j < pattern_length) {
2996 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002997 break;
2998 }
2999 j++;
3000 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003001 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003002 return i;
3003 }
3004 }
3005 return -1;
3006}
3007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003008RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003009 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003010 ASSERT(args.length() == 3);
3011
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003012 CONVERT_ARG_CHECKED(String, sub, 0);
3013 CONVERT_ARG_CHECKED(String, pat, 1);
3014
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003015 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003016 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003017 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003018
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003019 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003020 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003021
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003022 if (start_index + pat_length > sub_length) {
3023 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003024 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003026 if (pat_length == 0) {
3027 return Smi::FromInt(start_index);
3028 }
3029
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003030 if (!sub->IsFlat()) FlattenString(sub);
3031 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003032
3033 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3034
3035 int position = -1;
3036
3037 if (pat->IsAsciiRepresentation()) {
3038 Vector<const char> pat_vector = pat->ToAsciiVector();
3039 if (sub->IsAsciiRepresentation()) {
3040 position = StringMatchBackwards(sub->ToAsciiVector(),
3041 pat_vector,
3042 start_index);
3043 } else {
3044 position = StringMatchBackwards(sub->ToUC16Vector(),
3045 pat_vector,
3046 start_index);
3047 }
3048 } else {
3049 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3050 if (sub->IsAsciiRepresentation()) {
3051 position = StringMatchBackwards(sub->ToAsciiVector(),
3052 pat_vector,
3053 start_index);
3054 } else {
3055 position = StringMatchBackwards(sub->ToUC16Vector(),
3056 pat_vector,
3057 start_index);
3058 }
3059 }
3060
3061 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003062}
3063
3064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003065RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003066 NoHandleAllocation ha;
3067 ASSERT(args.length() == 2);
3068
3069 CONVERT_CHECKED(String, str1, args[0]);
3070 CONVERT_CHECKED(String, str2, args[1]);
3071
3072 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003073 int str1_length = str1->length();
3074 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003075
3076 // Decide trivial cases without flattening.
3077 if (str1_length == 0) {
3078 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3079 return Smi::FromInt(-str2_length);
3080 } else {
3081 if (str2_length == 0) return Smi::FromInt(str1_length);
3082 }
3083
3084 int end = str1_length < str2_length ? str1_length : str2_length;
3085
3086 // No need to flatten if we are going to find the answer on the first
3087 // character. At this point we know there is at least one character
3088 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003089 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003090 if (d != 0) return Smi::FromInt(d);
3091
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003092 str1->TryFlatten();
3093 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003094
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 StringInputBuffer& buf1 =
3096 *isolate->runtime_state()->string_locale_compare_buf1();
3097 StringInputBuffer& buf2 =
3098 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003099
3100 buf1.Reset(str1);
3101 buf2.Reset(str2);
3102
3103 for (int i = 0; i < end; i++) {
3104 uint16_t char1 = buf1.GetNext();
3105 uint16_t char2 = buf2.GetNext();
3106 if (char1 != char2) return Smi::FromInt(char1 - char2);
3107 }
3108
3109 return Smi::FromInt(str1_length - str2_length);
3110}
3111
3112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003113RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114 NoHandleAllocation ha;
3115 ASSERT(args.length() == 3);
3116
3117 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003118 Object* from = args[1];
3119 Object* to = args[2];
3120 int start, end;
3121 // We have a fast integer-only case here to avoid a conversion to double in
3122 // the common case where from and to are Smis.
3123 if (from->IsSmi() && to->IsSmi()) {
3124 start = Smi::cast(from)->value();
3125 end = Smi::cast(to)->value();
3126 } else {
3127 CONVERT_DOUBLE_CHECKED(from_number, from);
3128 CONVERT_DOUBLE_CHECKED(to_number, to);
3129 start = FastD2I(from_number);
3130 end = FastD2I(to_number);
3131 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003132 RUNTIME_ASSERT(end >= start);
3133 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003134 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003135 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003136 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003137}
3138
3139
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003140RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003141 ASSERT_EQ(3, args.length());
3142
3143 CONVERT_ARG_CHECKED(String, subject, 0);
3144 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3145 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3146 HandleScope handles;
3147
3148 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3149
3150 if (match.is_null()) {
3151 return Failure::Exception();
3152 }
3153 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003154 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003155 }
3156 int length = subject->length();
3157
danno@chromium.org40cb8782011-05-25 07:58:50 +00003158 CompilationZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003159 ZoneList<int> offsets(8);
3160 do {
3161 int start;
3162 int end;
3163 {
3164 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003165 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003166 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3167 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3168 }
3169 offsets.Add(start);
3170 offsets.Add(end);
3171 int index = start < end ? end : end + 1;
3172 if (index > length) break;
3173 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3174 if (match.is_null()) {
3175 return Failure::Exception();
3176 }
3177 } while (!match->IsNull());
3178 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003179 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003180 for (int i = 0; i < matches ; i++) {
3181 int from = offsets.at(i * 2);
3182 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003183 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003184 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003185 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003186 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003187 result->set_length(Smi::FromInt(matches));
3188 return *result;
3189}
3190
3191
lrn@chromium.org25156de2010-04-06 13:10:27 +00003192// Two smis before and after the match, for very long strings.
3193const int kMaxBuilderEntriesPerRegExpMatch = 5;
3194
3195
3196static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3197 Handle<JSArray> last_match_info,
3198 int match_start,
3199 int match_end) {
3200 // Fill last_match_info with a single capture.
3201 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3202 AssertNoAllocation no_gc;
3203 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3204 RegExpImpl::SetLastCaptureCount(elements, 2);
3205 RegExpImpl::SetLastInput(elements, *subject);
3206 RegExpImpl::SetLastSubject(elements, *subject);
3207 RegExpImpl::SetCapture(elements, 0, match_start);
3208 RegExpImpl::SetCapture(elements, 1, match_end);
3209}
3210
3211
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003212template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003213static bool SearchStringMultiple(Isolate* isolate,
3214 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003215 Vector<const PatternChar> pattern,
3216 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 FixedArrayBuilder* builder,
3218 int* match_pos) {
3219 int pos = *match_pos;
3220 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003221 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003223 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003224 while (pos <= max_search_start) {
3225 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3226 *match_pos = pos;
3227 return false;
3228 }
3229 // Position of end of previous match.
3230 int match_end = pos + pattern_length;
3231 int new_pos = search.Search(subject, match_end);
3232 if (new_pos >= 0) {
3233 // A match.
3234 if (new_pos > match_end) {
3235 ReplacementStringBuilder::AddSubjectSlice(builder,
3236 match_end,
3237 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003238 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003239 pos = new_pos;
3240 builder->Add(pattern_string);
3241 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003242 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003243 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003244 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003245
lrn@chromium.org25156de2010-04-06 13:10:27 +00003246 if (pos < max_search_start) {
3247 ReplacementStringBuilder::AddSubjectSlice(builder,
3248 pos + pattern_length,
3249 subject_length);
3250 }
3251 *match_pos = pos;
3252 return true;
3253}
3254
3255
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003256static bool SearchStringMultiple(Isolate* isolate,
3257 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003258 Handle<String> pattern,
3259 Handle<JSArray> last_match_info,
3260 FixedArrayBuilder* builder) {
3261 ASSERT(subject->IsFlat());
3262 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003263
3264 // Treating as if a previous match was before first character.
3265 int match_pos = -pattern->length();
3266
3267 for (;;) { // Break when search complete.
3268 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3269 AssertNoAllocation no_gc;
3270 if (subject->IsAsciiRepresentation()) {
3271 Vector<const char> subject_vector = subject->ToAsciiVector();
3272 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003273 if (SearchStringMultiple(isolate,
3274 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003275 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003276 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003277 builder,
3278 &match_pos)) break;
3279 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003280 if (SearchStringMultiple(isolate,
3281 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003282 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003283 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003284 builder,
3285 &match_pos)) break;
3286 }
3287 } else {
3288 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3289 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290 if (SearchStringMultiple(isolate,
3291 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003293 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003294 builder,
3295 &match_pos)) break;
3296 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003297 if (SearchStringMultiple(isolate,
3298 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003299 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003300 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003301 builder,
3302 &match_pos)) break;
3303 }
3304 }
3305 }
3306
3307 if (match_pos >= 0) {
3308 SetLastMatchInfoNoCaptures(subject,
3309 last_match_info,
3310 match_pos,
3311 match_pos + pattern->length());
3312 return true;
3313 }
3314 return false; // No matches at all.
3315}
3316
3317
3318static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003319 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003320 Handle<String> subject,
3321 Handle<JSRegExp> regexp,
3322 Handle<JSArray> last_match_array,
3323 FixedArrayBuilder* builder) {
3324 ASSERT(subject->IsFlat());
3325 int match_start = -1;
3326 int match_end = 0;
3327 int pos = 0;
3328 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3329 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3330
3331 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003332 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003333 int subject_length = subject->length();
3334
3335 for (;;) { // Break on failure, return on exception.
3336 RegExpImpl::IrregexpResult result =
3337 RegExpImpl::IrregexpExecOnce(regexp,
3338 subject,
3339 pos,
3340 register_vector);
3341 if (result == RegExpImpl::RE_SUCCESS) {
3342 match_start = register_vector[0];
3343 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3344 if (match_end < match_start) {
3345 ReplacementStringBuilder::AddSubjectSlice(builder,
3346 match_end,
3347 match_start);
3348 }
3349 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003350 HandleScope loop_scope(isolate);
3351 builder->Add(*isolate->factory()->NewSubString(subject,
3352 match_start,
3353 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003354 if (match_start != match_end) {
3355 pos = match_end;
3356 } else {
3357 pos = match_end + 1;
3358 if (pos > subject_length) break;
3359 }
3360 } else if (result == RegExpImpl::RE_FAILURE) {
3361 break;
3362 } else {
3363 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3364 return result;
3365 }
3366 }
3367
3368 if (match_start >= 0) {
3369 if (match_end < subject_length) {
3370 ReplacementStringBuilder::AddSubjectSlice(builder,
3371 match_end,
3372 subject_length);
3373 }
3374 SetLastMatchInfoNoCaptures(subject,
3375 last_match_array,
3376 match_start,
3377 match_end);
3378 return RegExpImpl::RE_SUCCESS;
3379 } else {
3380 return RegExpImpl::RE_FAILURE; // No matches at all.
3381 }
3382}
3383
3384
3385static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003386 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003387 Handle<String> subject,
3388 Handle<JSRegExp> regexp,
3389 Handle<JSArray> last_match_array,
3390 FixedArrayBuilder* builder) {
3391
3392 ASSERT(subject->IsFlat());
3393 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3394 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3395
3396 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003397 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003398
3399 RegExpImpl::IrregexpResult result =
3400 RegExpImpl::IrregexpExecOnce(regexp,
3401 subject,
3402 0,
3403 register_vector);
3404
3405 int capture_count = regexp->CaptureCount();
3406 int subject_length = subject->length();
3407
3408 // Position to search from.
3409 int pos = 0;
3410 // End of previous match. Differs from pos if match was empty.
3411 int match_end = 0;
3412 if (result == RegExpImpl::RE_SUCCESS) {
3413 // Need to keep a copy of the previous match for creating last_match_info
3414 // at the end, so we have two vectors that we swap between.
3415 OffsetsVector registers2(required_registers);
3416 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3417
3418 do {
3419 int match_start = register_vector[0];
3420 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3421 if (match_end < match_start) {
3422 ReplacementStringBuilder::AddSubjectSlice(builder,
3423 match_end,
3424 match_start);
3425 }
3426 match_end = register_vector[1];
3427
3428 {
3429 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003430 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003431 // Arguments array to replace function is match, captures, index and
3432 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003433 Handle<FixedArray> elements =
3434 isolate->factory()->NewFixedArray(3 + capture_count);
3435 Handle<String> match = isolate->factory()->NewSubString(subject,
3436 match_start,
3437 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003438 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003439 for (int i = 1; i <= capture_count; i++) {
3440 int start = register_vector[i * 2];
3441 if (start >= 0) {
3442 int end = register_vector[i * 2 + 1];
3443 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003444 Handle<String> substring = isolate->factory()->NewSubString(subject,
3445 start,
3446 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003447 elements->set(i, *substring);
3448 } else {
3449 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003450 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003451 }
3452 }
3453 elements->set(capture_count + 1, Smi::FromInt(match_start));
3454 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003455 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003456 }
3457 // Swap register vectors, so the last successful match is in
3458 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003459 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003460 prev_register_vector = register_vector;
3461 register_vector = tmp;
3462
3463 if (match_end > match_start) {
3464 pos = match_end;
3465 } else {
3466 pos = match_end + 1;
3467 if (pos > subject_length) {
3468 break;
3469 }
3470 }
3471
3472 result = RegExpImpl::IrregexpExecOnce(regexp,
3473 subject,
3474 pos,
3475 register_vector);
3476 } while (result == RegExpImpl::RE_SUCCESS);
3477
3478 if (result != RegExpImpl::RE_EXCEPTION) {
3479 // Finished matching, with at least one match.
3480 if (match_end < subject_length) {
3481 ReplacementStringBuilder::AddSubjectSlice(builder,
3482 match_end,
3483 subject_length);
3484 }
3485
3486 int last_match_capture_count = (capture_count + 1) * 2;
3487 int last_match_array_size =
3488 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3489 last_match_array->EnsureSize(last_match_array_size);
3490 AssertNoAllocation no_gc;
3491 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3492 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3493 RegExpImpl::SetLastSubject(elements, *subject);
3494 RegExpImpl::SetLastInput(elements, *subject);
3495 for (int i = 0; i < last_match_capture_count; i++) {
3496 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3497 }
3498 return RegExpImpl::RE_SUCCESS;
3499 }
3500 }
3501 // No matches at all, return failure or exception result directly.
3502 return result;
3503}
3504
3505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003506RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003507 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003508 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003509
3510 CONVERT_ARG_CHECKED(String, subject, 1);
3511 if (!subject->IsFlat()) { FlattenString(subject); }
3512 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3513 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3514 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3515
3516 ASSERT(last_match_info->HasFastElements());
3517 ASSERT(regexp->GetFlags().is_global());
3518 Handle<FixedArray> result_elements;
3519 if (result_array->HasFastElements()) {
3520 result_elements =
3521 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3522 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003523 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003524 }
3525 FixedArrayBuilder builder(result_elements);
3526
3527 if (regexp->TypeTag() == JSRegExp::ATOM) {
3528 Handle<String> pattern(
3529 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003530 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003531 if (SearchStringMultiple(isolate, subject, pattern,
3532 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003533 return *builder.ToJSArray(result_array);
3534 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003535 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003536 }
3537
3538 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3539
3540 RegExpImpl::IrregexpResult result;
3541 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003542 result = SearchRegExpNoCaptureMultiple(isolate,
3543 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003544 regexp,
3545 last_match_info,
3546 &builder);
3547 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003548 result = SearchRegExpMultiple(isolate,
3549 subject,
3550 regexp,
3551 last_match_info,
3552 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003553 }
3554 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003555 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003556 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3557 return Failure::Exception();
3558}
3559
3560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003561RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562 NoHandleAllocation ha;
3563 ASSERT(args.length() == 2);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003564 CONVERT_SMI_CHECKED(radix, args[1]);
3565 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003567 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003568 if (args[0]->IsSmi()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003569 int value = Smi::cast(args[0])->value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003570 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003571 // Character array used for conversion.
3572 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 return isolate->heap()->
3574 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003575 }
3576 }
3577
3578 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 CONVERT_DOUBLE_CHECKED(value, args[0]);
3580 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003581 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582 }
3583 if (isinf(value)) {
3584 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003585 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003587 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003589 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 MaybeObject* result =
3591 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 DeleteArray(str);
3593 return result;
3594}
3595
3596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003597RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 NoHandleAllocation ha;
3599 ASSERT(args.length() == 2);
3600
3601 CONVERT_DOUBLE_CHECKED(value, args[0]);
3602 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003603 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 }
3605 if (isinf(value)) {
3606 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003607 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003609 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 }
3611 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3612 int f = FastD2I(f_number);
3613 RUNTIME_ASSERT(f >= 0);
3614 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 MaybeObject* res =
3616 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619}
3620
3621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003622RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 NoHandleAllocation ha;
3624 ASSERT(args.length() == 2);
3625
3626 CONVERT_DOUBLE_CHECKED(value, args[0]);
3627 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 }
3630 if (isinf(value)) {
3631 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003634 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003635 }
3636 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3637 int f = FastD2I(f_number);
3638 RUNTIME_ASSERT(f >= -1 && f <= 20);
3639 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003640 MaybeObject* res =
3641 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644}
3645
3646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003647RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003648 NoHandleAllocation ha;
3649 ASSERT(args.length() == 2);
3650
3651 CONVERT_DOUBLE_CHECKED(value, args[0]);
3652 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654 }
3655 if (isinf(value)) {
3656 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003657 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003658 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003659 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003660 }
3661 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3662 int f = FastD2I(f_number);
3663 RUNTIME_ASSERT(f >= 1 && f <= 21);
3664 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003665 MaybeObject* res =
3666 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003667 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003668 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669}
3670
3671
3672// Returns a single character string where first character equals
3673// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003674static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003675 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003676 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003677 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003678 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003680 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003681}
3682
3683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003684MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3685 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003686 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003687 // Handle [] indexing on Strings
3688 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003689 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3690 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003691 }
3692
3693 // Handle [] indexing on String objects
3694 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003695 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3696 Handle<Object> result =
3697 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3698 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003699 }
3700
3701 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003702 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003703 return prototype->GetElement(index);
3704 }
3705
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003706 return GetElement(object, index);
3707}
3708
3709
lrn@chromium.org303ada72010-10-27 09:33:13 +00003710MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003711 return object->GetElement(index);
3712}
3713
3714
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003715MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3716 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003717 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003718 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003719
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003721 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003722 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003723 isolate->factory()->NewTypeError("non_object_property_load",
3724 HandleVector(args, 2));
3725 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726 }
3727
3728 // Check if the given key is an array index.
3729 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003730 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003731 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003732 }
3733
3734 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003735 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003737 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739 bool has_pending_exception = false;
3740 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003741 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003743 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744 }
3745
ager@chromium.org32912102009-01-16 10:38:43 +00003746 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003747 // the element if so.
3748 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003749 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003750 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003751 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752 }
3753}
3754
3755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003756RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003757 NoHandleAllocation ha;
3758 ASSERT(args.length() == 2);
3759
3760 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003761 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003763 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764}
3765
3766
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003767// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003768RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003769 NoHandleAllocation ha;
3770 ASSERT(args.length() == 2);
3771
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003772 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003773 // itself.
3774 //
3775 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003776 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003777 // global proxy object never has properties. This is the case
3778 // because the global proxy object forwards everything to its hidden
3779 // prototype including local lookups.
3780 //
3781 // Additionally, we need to make sure that we do not cache results
3782 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003783 if (args[0]->IsJSObject() &&
3784 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003785 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003786 args[1]->IsString()) {
3787 JSObject* receiver = JSObject::cast(args[0]);
3788 String* key = String::cast(args[1]);
3789 if (receiver->HasFastProperties()) {
3790 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003791 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003792 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3793 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003794 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003795 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003796 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003797 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003798 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003799 LookupResult result;
3800 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003801 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003802 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003803 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003804 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003805 }
3806 } else {
3807 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003808 StringDictionary* dictionary = receiver->property_dictionary();
3809 int entry = dictionary->FindEntry(key);
3810 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003811 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003812 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003813 if (!receiver->IsGlobalObject()) return value;
3814 value = JSGlobalPropertyCell::cast(value)->value();
3815 if (!value->IsTheHole()) return value;
3816 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003817 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003818 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003819 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3820 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003821 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003822 Handle<String> str = args.at<String>(0);
3823 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003824 if (index >= 0 && index < str->length()) {
3825 Handle<Object> result = GetCharAt(str, index);
3826 return *result;
3827 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003828 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003829
3830 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003831 return Runtime::GetObjectProperty(isolate,
3832 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003833 args.at<Object>(1));
3834}
3835
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003836// Implements part of 8.12.9 DefineOwnProperty.
3837// There are 3 cases that lead here:
3838// Step 4b - define a new accessor property.
3839// Steps 9c & 12 - replace an existing data property with an accessor property.
3840// Step 12 - update an existing accessor property with an accessor or generic
3841// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003842RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003843 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003845 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3846 CONVERT_CHECKED(String, name, args[1]);
3847 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003848 Object* fun = args[3];
3849 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003850 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3851 int unchecked = flag_attr->value();
3852 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3853 RUNTIME_ASSERT(!obj->IsNull());
3854 LookupResult result;
3855 obj->LocalLookupRealNamedProperty(name, &result);
3856
3857 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3858 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3859 // delete it to avoid running into trouble in DefineAccessor, which
3860 // handles this incorrectly if the property is readonly (does nothing)
3861 if (result.IsProperty() &&
3862 (result.type() == FIELD || result.type() == NORMAL
3863 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003864 Object* ok;
3865 { MaybeObject* maybe_ok =
3866 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3867 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3868 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003869 }
3870 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3871}
3872
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003873// Implements part of 8.12.9 DefineOwnProperty.
3874// There are 3 cases that lead here:
3875// Step 4a - define a new data property.
3876// Steps 9b & 12 - replace an existing accessor property with a data property.
3877// Step 12 - update an existing data property with a data or generic
3878// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003879RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003880 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003881 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003882 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3883 CONVERT_ARG_CHECKED(String, name, 1);
3884 Handle<Object> obj_value = args.at<Object>(2);
3885
3886 CONVERT_CHECKED(Smi, flag, args[3]);
3887 int unchecked = flag->value();
3888 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3889
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003890 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3891
3892 // Check if this is an element.
3893 uint32_t index;
3894 bool is_element = name->AsArrayIndex(&index);
3895
3896 // Special case for elements if any of the flags are true.
3897 // If elements are in fast case we always implicitly assume that:
3898 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3899 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3900 is_element) {
3901 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003902 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003903 // We do not need to do access checks here since these has already
3904 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003905 Handle<Object> proto(js_object->GetPrototype());
3906 // If proxy is detached, ignore the assignment. Alternatively,
3907 // we could throw an exception.
3908 if (proto->IsNull()) return *obj_value;
3909 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003910 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003911 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003912 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003913 // Make sure that we never go back to fast case.
3914 dictionary->set_requires_slow_elements();
3915 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003916 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003917 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003918 }
3919
ager@chromium.org5c838252010-02-19 08:53:10 +00003920 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003921 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003922
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003923 // To be compatible with safari we do not change the value on API objects
3924 // in defineProperty. Firefox disagrees here, and actually changes the value.
3925 if (result.IsProperty() &&
3926 (result.type() == CALLBACKS) &&
3927 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003928 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003929 }
3930
ager@chromium.org5c838252010-02-19 08:53:10 +00003931 // Take special care when attributes are different and there is already
3932 // a property. For simplicity we normalize the property which enables us
3933 // to not worry about changing the instance_descriptor and creating a new
3934 // map. The current version of SetObjectProperty does not handle attributes
3935 // correctly in the case where a property is a field and is reset with
3936 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003937 if (result.IsProperty() &&
3938 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003939 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003940 if (js_object->IsJSGlobalProxy()) {
3941 // Since the result is a property, the prototype will exist so
3942 // we don't have to check for null.
3943 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003944 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003945 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003946 // Use IgnoreAttributes version since a readonly property may be
3947 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003948 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3949 *obj_value,
3950 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003951 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003953 return Runtime::ForceSetObjectProperty(isolate,
3954 js_object,
3955 name,
3956 obj_value,
3957 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003958}
3959
3960
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003961MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3962 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003963 Handle<Object> key,
3964 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003965 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003966 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003967 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003968
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003970 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003972 isolate->factory()->NewTypeError("non_object_property_store",
3973 HandleVector(args, 2));
3974 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 }
3976
3977 // If the object isn't a JavaScript object, we ignore the store.
3978 if (!object->IsJSObject()) return *value;
3979
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003980 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3981
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003982 // Check if the given key is an array index.
3983 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003984 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3986 // of a string using [] notation. We need to support this too in
3987 // JavaScript.
3988 // In the case of a String object we just need to redirect the assignment to
3989 // the underlying string if the index is in range. Since the underlying
3990 // string does nothing with the assignment then we can ignore such
3991 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003992 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003993 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003996 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003997 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 return *value;
3999 }
4000
4001 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004002 Handle<Object> result;
4003 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004004 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004005 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004006 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004007 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004008 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004010 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011 return *value;
4012 }
4013
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 bool has_pending_exception = false;
4016 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4017 if (has_pending_exception) return Failure::Exception();
4018 Handle<String> name = Handle<String>::cast(converted);
4019
4020 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004021 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004023 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 }
4025}
4026
4027
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004028MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4029 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004030 Handle<Object> key,
4031 Handle<Object> value,
4032 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004033 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004034
4035 // Check if the given key is an array index.
4036 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004037 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004038 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4039 // of a string using [] notation. We need to support this too in
4040 // JavaScript.
4041 // In the case of a String object we just need to redirect the assignment to
4042 // the underlying string if the index is in range. Since the underlying
4043 // string does nothing with the assignment then we can ignore such
4044 // assignments.
4045 if (js_object->IsStringObjectWithCharacterAt(index)) {
4046 return *value;
4047 }
4048
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004049 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004050 }
4051
4052 if (key->IsString()) {
4053 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004054 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004055 } else {
4056 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004057 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004058 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4059 *value,
4060 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004061 }
4062 }
4063
4064 // Call-back into JavaScript to convert the key to a string.
4065 bool has_pending_exception = false;
4066 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4067 if (has_pending_exception) return Failure::Exception();
4068 Handle<String> name = Handle<String>::cast(converted);
4069
4070 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004071 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004072 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004073 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004074 }
4075}
4076
4077
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004078MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4079 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004080 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004081 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004082
4083 // Check if the given key is an array index.
4084 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004085 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004086 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4087 // characters of a string using [] notation. In the case of a
4088 // String object we just need to redirect the deletion to the
4089 // underlying string if the index is in range. Since the
4090 // underlying string does nothing with the deletion, we can ignore
4091 // such deletions.
4092 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004093 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004094 }
4095
4096 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4097 }
4098
4099 Handle<String> key_string;
4100 if (key->IsString()) {
4101 key_string = Handle<String>::cast(key);
4102 } else {
4103 // Call-back into JavaScript to convert the key to a string.
4104 bool has_pending_exception = false;
4105 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4106 if (has_pending_exception) return Failure::Exception();
4107 key_string = Handle<String>::cast(converted);
4108 }
4109
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004110 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004111 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4112}
4113
4114
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004115RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004117 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118
4119 Handle<Object> object = args.at<Object>(0);
4120 Handle<Object> key = args.at<Object>(1);
4121 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004122 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4123 RUNTIME_ASSERT(
4124 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004126 PropertyAttributes attributes =
4127 static_cast<PropertyAttributes>(unchecked_attributes);
4128
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004129 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004130 if (args.length() == 5) {
4131 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4132 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4133 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004134 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004136
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004137 return Runtime::SetObjectProperty(isolate,
4138 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004139 key,
4140 value,
4141 attributes,
4142 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143}
4144
4145
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004146// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004147// This is used to decide if we should transform null and undefined
4148// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004149RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004150 NoHandleAllocation ha;
4151 RUNTIME_ASSERT(args.length() == 1);
4152
4153 Handle<Object> object = args.at<Object>(0);
4154
4155 if (object->IsJSFunction()) {
4156 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004157 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004158 }
4159 return isolate->heap()->undefined_value();
4160}
4161
4162
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004163// Set a local property, even if it is READ_ONLY. If the property does not
4164// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004165RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004167 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168 CONVERT_CHECKED(JSObject, object, args[0]);
4169 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004170 // Compute attributes.
4171 PropertyAttributes attributes = NONE;
4172 if (args.length() == 4) {
4173 CONVERT_CHECKED(Smi, value_obj, args[3]);
4174 int unchecked_value = value_obj->value();
4175 // Only attribute bits should be set.
4176 RUNTIME_ASSERT(
4177 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4178 attributes = static_cast<PropertyAttributes>(unchecked_value);
4179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004181 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004182 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183}
4184
4185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004186RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004188 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189
4190 CONVERT_CHECKED(JSObject, object, args[0]);
4191 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004192 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004193 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004194 ? JSObject::STRICT_DELETION
4195 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004196}
4197
4198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004199static Object* HasLocalPropertyImplementation(Isolate* isolate,
4200 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004201 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004202 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004203 // Handle hidden prototypes. If there's a hidden prototype above this thing
4204 // then we have to check it for properties, because they are supposed to
4205 // look like they are on this object.
4206 Handle<Object> proto(object->GetPrototype());
4207 if (proto->IsJSObject() &&
4208 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004209 return HasLocalPropertyImplementation(isolate,
4210 Handle<JSObject>::cast(proto),
4211 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004212 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004213 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004214}
4215
4216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004217RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 NoHandleAllocation ha;
4219 ASSERT(args.length() == 2);
4220 CONVERT_CHECKED(String, key, args[1]);
4221
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004222 uint32_t index;
4223 const bool key_is_array_index = key->AsArrayIndex(&index);
4224
ager@chromium.org9085a012009-05-11 19:22:57 +00004225 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004226 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004227 if (obj->IsJSObject()) {
4228 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004229 // Fast case: either the key is a real named property or it is not
4230 // an array index and there are no interceptors or hidden
4231 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004232 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004233 Map* map = object->map();
4234 if (!key_is_array_index &&
4235 !map->has_named_interceptor() &&
4236 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4237 return isolate->heap()->false_value();
4238 }
4239 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 HandleScope scope(isolate);
4241 return HasLocalPropertyImplementation(isolate,
4242 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004243 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004244 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004245 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004246 String* string = String::cast(obj);
4247 if (index < static_cast<uint32_t>(string->length())) {
4248 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004249 }
4250 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004251 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004252}
4253
4254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004255RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004256 NoHandleAllocation na;
4257 ASSERT(args.length() == 2);
4258
4259 // Only JS objects can have properties.
4260 if (args[0]->IsJSObject()) {
4261 JSObject* object = JSObject::cast(args[0]);
4262 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004263 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004264 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004265 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004266}
4267
4268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004269RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004270 NoHandleAllocation na;
4271 ASSERT(args.length() == 2);
4272
4273 // Only JS objects can have elements.
4274 if (args[0]->IsJSObject()) {
4275 JSObject* object = JSObject::cast(args[0]);
4276 CONVERT_CHECKED(Smi, index_obj, args[1]);
4277 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004278 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004279 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004280 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004281}
4282
4283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004284RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004285 NoHandleAllocation ha;
4286 ASSERT(args.length() == 2);
4287
4288 CONVERT_CHECKED(JSObject, object, args[0]);
4289 CONVERT_CHECKED(String, key, args[1]);
4290
4291 uint32_t index;
4292 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004293 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004294 }
4295
ager@chromium.org870a0b62008-11-04 11:43:05 +00004296 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004297 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004298}
4299
4300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004301RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004302 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004303 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004304 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004305 return *GetKeysFor(object);
4306}
4307
4308
4309// Returns either a FixedArray as Runtime_GetPropertyNames,
4310// or, if the given object has an enum cache that contains
4311// all enumerable properties of the object and its prototypes
4312// have none, the map of the object. This is used to speed up
4313// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004314RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 ASSERT(args.length() == 1);
4316
4317 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4318
4319 if (raw_object->IsSimpleEnum()) return raw_object->map();
4320
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004321 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004322 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004323 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4324 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004325
4326 // Test again, since cache may have been built by preceding call.
4327 if (object->IsSimpleEnum()) return object->map();
4328
4329 return *content;
4330}
4331
4332
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004333// Find the length of the prototype chain that is to to handled as one. If a
4334// prototype object is hidden it is to be viewed as part of the the object it
4335// is prototype for.
4336static int LocalPrototypeChainLength(JSObject* obj) {
4337 int count = 1;
4338 Object* proto = obj->GetPrototype();
4339 while (proto->IsJSObject() &&
4340 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4341 count++;
4342 proto = JSObject::cast(proto)->GetPrototype();
4343 }
4344 return count;
4345}
4346
4347
4348// Return the names of the local named properties.
4349// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004350RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004351 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004352 ASSERT(args.length() == 1);
4353 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004354 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004355 }
4356 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4357
4358 // Skip the global proxy as it has no properties and always delegates to the
4359 // real global object.
4360 if (obj->IsJSGlobalProxy()) {
4361 // Only collect names if access is permitted.
4362 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004363 !isolate->MayNamedAccess(*obj,
4364 isolate->heap()->undefined_value(),
4365 v8::ACCESS_KEYS)) {
4366 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4367 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004368 }
4369 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4370 }
4371
4372 // Find the number of objects making up this.
4373 int length = LocalPrototypeChainLength(*obj);
4374
4375 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004376 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004377 int total_property_count = 0;
4378 Handle<JSObject> jsproto = obj;
4379 for (int i = 0; i < length; i++) {
4380 // Only collect names if access is permitted.
4381 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004382 !isolate->MayNamedAccess(*jsproto,
4383 isolate->heap()->undefined_value(),
4384 v8::ACCESS_KEYS)) {
4385 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4386 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004387 }
4388 int n;
4389 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4390 local_property_count[i] = n;
4391 total_property_count += n;
4392 if (i < length - 1) {
4393 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4394 }
4395 }
4396
4397 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004398 Handle<FixedArray> names =
4399 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004400
4401 // Get the property names.
4402 jsproto = obj;
4403 int proto_with_hidden_properties = 0;
4404 for (int i = 0; i < length; i++) {
4405 jsproto->GetLocalPropertyNames(*names,
4406 i == 0 ? 0 : local_property_count[i - 1]);
4407 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4408 proto_with_hidden_properties++;
4409 }
4410 if (i < length - 1) {
4411 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4412 }
4413 }
4414
4415 // Filter out name of hidden propeties object.
4416 if (proto_with_hidden_properties > 0) {
4417 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419 names->length() - proto_with_hidden_properties);
4420 int dest_pos = 0;
4421 for (int i = 0; i < total_property_count; i++) {
4422 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004423 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004424 continue;
4425 }
4426 names->set(dest_pos++, name);
4427 }
4428 }
4429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004431}
4432
4433
4434// Return the names of the local indexed properties.
4435// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004436RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004437 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004438 ASSERT(args.length() == 1);
4439 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004441 }
4442 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4443
4444 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004445 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004446 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004447 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004448}
4449
4450
4451// Return information on whether an object has a named or indexed interceptor.
4452// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004453RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004455 ASSERT(args.length() == 1);
4456 if (!args[0]->IsJSObject()) {
4457 return Smi::FromInt(0);
4458 }
4459 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4460
4461 int result = 0;
4462 if (obj->HasNamedInterceptor()) result |= 2;
4463 if (obj->HasIndexedInterceptor()) result |= 1;
4464
4465 return Smi::FromInt(result);
4466}
4467
4468
4469// Return property names from named interceptor.
4470// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004471RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004472 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004473 ASSERT(args.length() == 1);
4474 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4475
4476 if (obj->HasNamedInterceptor()) {
4477 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4478 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4479 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004480 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004481}
4482
4483
4484// Return element names from indexed interceptor.
4485// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004486RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004487 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004488 ASSERT(args.length() == 1);
4489 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4490
4491 if (obj->HasIndexedInterceptor()) {
4492 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4493 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4494 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004495 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004496}
4497
4498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004499RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004500 ASSERT_EQ(args.length(), 1);
4501 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004503 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004504
4505 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004506 // Do access checks before going to the global object.
4507 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004508 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004509 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004510 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4511 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004512 }
4513
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004514 Handle<Object> proto(object->GetPrototype());
4515 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004516 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004517 object = Handle<JSObject>::cast(proto);
4518 }
4519
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004520 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4521 LOCAL_ONLY);
4522 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4523 // property array and since the result is mutable we have to create
4524 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004525 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004526 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004527 for (int i = 0; i < length; i++) {
4528 Object* entry = contents->get(i);
4529 if (entry->IsString()) {
4530 copy->set(i, entry);
4531 } else {
4532 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004533 HandleScope scope(isolate);
4534 Handle<Object> entry_handle(entry, isolate);
4535 Handle<Object> entry_str =
4536 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004537 copy->set(i, *entry_str);
4538 }
4539 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004540 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004541}
4542
4543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004544RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004545 NoHandleAllocation ha;
4546 ASSERT(args.length() == 1);
4547
4548 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004549 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 it.AdvanceToArgumentsFrame();
4551 JavaScriptFrame* frame = it.frame();
4552
4553 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004554 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555
4556 // Try to convert the key to an index. If successful and within
4557 // index return the the argument from the frame.
4558 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004559 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004560 return frame->GetParameter(index);
4561 }
4562
4563 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004564 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 bool exception = false;
4566 Handle<Object> converted =
4567 Execution::ToString(args.at<Object>(0), &exception);
4568 if (exception) return Failure::Exception();
4569 Handle<String> key = Handle<String>::cast(converted);
4570
4571 // Try to convert the string key into an array index.
4572 if (key->AsArrayIndex(&index)) {
4573 if (index < n) {
4574 return frame->GetParameter(index);
4575 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004576 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577 }
4578 }
4579
4580 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004581 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4582 if (key->Equals(isolate->heap()->callee_symbol())) {
4583 Object* function = frame->function();
4584 if (function->IsJSFunction() &&
4585 JSFunction::cast(function)->shared()->strict_mode()) {
4586 return isolate->Throw(*isolate->factory()->NewTypeError(
4587 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4588 }
4589 return function;
4590 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004591
4592 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004593 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594}
4595
4596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004597RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004598 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004599
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004600 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004601 Handle<Object> object = args.at<Object>(0);
4602 if (object->IsJSObject()) {
4603 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004604 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004605 MaybeObject* ok = js_object->TransformToFastProperties(0);
4606 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004607 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004608 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004609 return *object;
4610}
4611
4612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004613RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004614 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004615
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004616 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004617 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004618 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004619 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004620 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004621 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004622 return *object;
4623}
4624
4625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004626RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004627 NoHandleAllocation ha;
4628 ASSERT(args.length() == 1);
4629
4630 return args[0]->ToBoolean();
4631}
4632
4633
4634// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4635// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004636RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004637 NoHandleAllocation ha;
4638
4639 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004640 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004641 HeapObject* heap_obj = HeapObject::cast(obj);
4642
4643 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004644 if (heap_obj->map()->is_undetectable()) {
4645 return isolate->heap()->undefined_symbol();
4646 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004647
4648 InstanceType instance_type = heap_obj->map()->instance_type();
4649 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004650 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004651 }
4652
4653 switch (instance_type) {
4654 case ODDBALL_TYPE:
4655 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004656 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004657 }
4658 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004659 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004660 }
4661 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004662 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004663 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004664 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004665 default:
4666 // For any kind of object not handled above, the spec rule for
4667 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004668 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 }
4670}
4671
4672
lrn@chromium.org25156de2010-04-06 13:10:27 +00004673static bool AreDigits(const char*s, int from, int to) {
4674 for (int i = from; i < to; i++) {
4675 if (s[i] < '0' || s[i] > '9') return false;
4676 }
4677
4678 return true;
4679}
4680
4681
4682static int ParseDecimalInteger(const char*s, int from, int to) {
4683 ASSERT(to - from < 10); // Overflow is not possible.
4684 ASSERT(from < to);
4685 int d = s[from] - '0';
4686
4687 for (int i = from + 1; i < to; i++) {
4688 d = 10 * d + (s[i] - '0');
4689 }
4690
4691 return d;
4692}
4693
4694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004695RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696 NoHandleAllocation ha;
4697 ASSERT(args.length() == 1);
4698 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004699 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004700
4701 // Fast case: short integer or some sorts of junk values.
4702 int len = subject->length();
4703 if (subject->IsSeqAsciiString()) {
4704 if (len == 0) return Smi::FromInt(0);
4705
4706 char const* data = SeqAsciiString::cast(subject)->GetChars();
4707 bool minus = (data[0] == '-');
4708 int start_pos = (minus ? 1 : 0);
4709
4710 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004711 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004712 } else if (data[start_pos] > '9') {
4713 // Fast check for a junk value. A valid string may start from a
4714 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4715 // the 'I' character ('Infinity'). All of that have codes not greater than
4716 // '9' except 'I'.
4717 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004718 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004719 }
4720 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4721 // The maximal/minimal smi has 10 digits. If the string has less digits we
4722 // know it will fit into the smi-data type.
4723 int d = ParseDecimalInteger(data, start_pos, len);
4724 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004725 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004726 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004727 } else if (!subject->HasHashCode() &&
4728 len <= String::kMaxArrayIndexSize &&
4729 (len == 1 || data[0] != '0')) {
4730 // String hash is not calculated yet but all the data are present.
4731 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004732 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004733#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004734 subject->Hash(); // Force hash calculation.
4735 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4736 static_cast<int>(hash));
4737#endif
4738 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004739 }
4740 return Smi::FromInt(d);
4741 }
4742 }
4743
4744 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004745 return isolate->heap()->NumberFromDouble(
4746 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747}
4748
4749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004750RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751 NoHandleAllocation ha;
4752 ASSERT(args.length() == 1);
4753
4754 CONVERT_CHECKED(JSArray, codes, args[0]);
4755 int length = Smi::cast(codes->length())->value();
4756
4757 // Check if the string can be ASCII.
4758 int i;
4759 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004760 Object* element;
4761 { MaybeObject* maybe_element = codes->GetElement(i);
4762 // We probably can't get an exception here, but just in order to enforce
4763 // the checking of inputs in the runtime calls we check here.
4764 if (!maybe_element->ToObject(&element)) return maybe_element;
4765 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004766 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4767 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4768 break;
4769 }
4770
lrn@chromium.org303ada72010-10-27 09:33:13 +00004771 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004773 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004775 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776 }
4777
lrn@chromium.org303ada72010-10-27 09:33:13 +00004778 Object* object = NULL;
4779 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780 String* result = String::cast(object);
4781 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004782 Object* element;
4783 { MaybeObject* maybe_element = codes->GetElement(i);
4784 if (!maybe_element->ToObject(&element)) return maybe_element;
4785 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004786 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004787 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788 }
4789 return result;
4790}
4791
4792
4793// kNotEscaped is generated by the following:
4794//
4795// #!/bin/perl
4796// for (my $i = 0; $i < 256; $i++) {
4797// print "\n" if $i % 16 == 0;
4798// my $c = chr($i);
4799// my $escaped = 1;
4800// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4801// print $escaped ? "0, " : "1, ";
4802// }
4803
4804
4805static bool IsNotEscaped(uint16_t character) {
4806 // Only for 8 bit characters, the rest are always escaped (in a different way)
4807 ASSERT(character < 256);
4808 static const char kNotEscaped[256] = {
4809 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4810 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4811 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4812 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4813 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4814 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4815 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4816 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4817 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4818 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4819 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4820 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4821 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4822 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4823 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4824 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4825 };
4826 return kNotEscaped[character] != 0;
4827}
4828
4829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004830RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 const char hex_chars[] = "0123456789ABCDEF";
4832 NoHandleAllocation ha;
4833 ASSERT(args.length() == 1);
4834 CONVERT_CHECKED(String, source, args[0]);
4835
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004836 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004837
4838 int escaped_length = 0;
4839 int length = source->length();
4840 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004841 Access<StringInputBuffer> buffer(
4842 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 buffer->Reset(source);
4844 while (buffer->has_more()) {
4845 uint16_t character = buffer->GetNext();
4846 if (character >= 256) {
4847 escaped_length += 6;
4848 } else if (IsNotEscaped(character)) {
4849 escaped_length++;
4850 } else {
4851 escaped_length += 3;
4852 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004853 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004854 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004855 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004856 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857 return Failure::OutOfMemoryException();
4858 }
4859 }
4860 }
4861 // No length change implies no change. Return original string if no change.
4862 if (escaped_length == length) {
4863 return source;
4864 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004865 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004866 { MaybeObject* maybe_o =
4867 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004868 if (!maybe_o->ToObject(&o)) return maybe_o;
4869 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 String* destination = String::cast(o);
4871 int dest_position = 0;
4872
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004873 Access<StringInputBuffer> buffer(
4874 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004875 buffer->Rewind();
4876 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004877 uint16_t chr = buffer->GetNext();
4878 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004879 destination->Set(dest_position, '%');
4880 destination->Set(dest_position+1, 'u');
4881 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4882 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4883 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4884 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004885 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004886 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004887 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 dest_position++;
4889 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004890 destination->Set(dest_position, '%');
4891 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4892 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893 dest_position += 3;
4894 }
4895 }
4896 return destination;
4897}
4898
4899
4900static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4901 static const signed char kHexValue['g'] = {
4902 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4903 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4904 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4905 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4906 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4907 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4908 -1, 10, 11, 12, 13, 14, 15 };
4909
4910 if (character1 > 'f') return -1;
4911 int hi = kHexValue[character1];
4912 if (hi == -1) return -1;
4913 if (character2 > 'f') return -1;
4914 int lo = kHexValue[character2];
4915 if (lo == -1) return -1;
4916 return (hi << 4) + lo;
4917}
4918
4919
ager@chromium.org870a0b62008-11-04 11:43:05 +00004920static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004921 int i,
4922 int length,
4923 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004924 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004925 int32_t hi = 0;
4926 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004927 if (character == '%' &&
4928 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004929 source->Get(i + 1) == 'u' &&
4930 (hi = TwoDigitHex(source->Get(i + 2),
4931 source->Get(i + 3))) != -1 &&
4932 (lo = TwoDigitHex(source->Get(i + 4),
4933 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004934 *step = 6;
4935 return (hi << 8) + lo;
4936 } else if (character == '%' &&
4937 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004938 (lo = TwoDigitHex(source->Get(i + 1),
4939 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004940 *step = 3;
4941 return lo;
4942 } else {
4943 *step = 1;
4944 return character;
4945 }
4946}
4947
4948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004949RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004950 NoHandleAllocation ha;
4951 ASSERT(args.length() == 1);
4952 CONVERT_CHECKED(String, source, args[0]);
4953
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004954 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004955
4956 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004957 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004958
4959 int unescaped_length = 0;
4960 for (int i = 0; i < length; unescaped_length++) {
4961 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004962 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004963 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004964 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004965 i += step;
4966 }
4967
4968 // No length change implies no change. Return original string if no change.
4969 if (unescaped_length == length)
4970 return source;
4971
lrn@chromium.org303ada72010-10-27 09:33:13 +00004972 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004973 { MaybeObject* maybe_o =
4974 ascii ?
4975 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4976 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004977 if (!maybe_o->ToObject(&o)) return maybe_o;
4978 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004979 String* destination = String::cast(o);
4980
4981 int dest_position = 0;
4982 for (int i = 0; i < length; dest_position++) {
4983 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004984 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 i += step;
4986 }
4987 return destination;
4988}
4989
4990
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004991static const unsigned int kQuoteTableLength = 128u;
4992
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004993static const int kJsonQuotesCharactersPerEntry = 8;
4994static const char* const JsonQuotes =
4995 "\\u0000 \\u0001 \\u0002 \\u0003 "
4996 "\\u0004 \\u0005 \\u0006 \\u0007 "
4997 "\\b \\t \\n \\u000b "
4998 "\\f \\r \\u000e \\u000f "
4999 "\\u0010 \\u0011 \\u0012 \\u0013 "
5000 "\\u0014 \\u0015 \\u0016 \\u0017 "
5001 "\\u0018 \\u0019 \\u001a \\u001b "
5002 "\\u001c \\u001d \\u001e \\u001f "
5003 " ! \\\" # "
5004 "$ % & ' "
5005 "( ) * + "
5006 ", - . / "
5007 "0 1 2 3 "
5008 "4 5 6 7 "
5009 "8 9 : ; "
5010 "< = > ? "
5011 "@ A B C "
5012 "D E F G "
5013 "H I J K "
5014 "L M N O "
5015 "P Q R S "
5016 "T U V W "
5017 "X Y Z [ "
5018 "\\\\ ] ^ _ "
5019 "` a b c "
5020 "d e f g "
5021 "h i j k "
5022 "l m n o "
5023 "p q r s "
5024 "t u v w "
5025 "x y z { "
5026 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005027
5028
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005029// For a string that is less than 32k characters it should always be
5030// possible to allocate it in new space.
5031static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5032
5033
5034// Doing JSON quoting cannot make the string more than this many times larger.
5035static const int kJsonQuoteWorstCaseBlowup = 6;
5036
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005037static const int kSpaceForQuotesAndComma = 3;
5038static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005039
5040// Covers the entire ASCII range (all other characters are unchanged by JSON
5041// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005042static const byte JsonQuoteLengths[kQuoteTableLength] = {
5043 6, 6, 6, 6, 6, 6, 6, 6,
5044 2, 2, 2, 6, 2, 2, 6, 6,
5045 6, 6, 6, 6, 6, 6, 6, 6,
5046 6, 6, 6, 6, 6, 6, 6, 6,
5047 1, 1, 2, 1, 1, 1, 1, 1,
5048 1, 1, 1, 1, 1, 1, 1, 1,
5049 1, 1, 1, 1, 1, 1, 1, 1,
5050 1, 1, 1, 1, 1, 1, 1, 1,
5051 1, 1, 1, 1, 1, 1, 1, 1,
5052 1, 1, 1, 1, 1, 1, 1, 1,
5053 1, 1, 1, 1, 1, 1, 1, 1,
5054 1, 1, 1, 1, 2, 1, 1, 1,
5055 1, 1, 1, 1, 1, 1, 1, 1,
5056 1, 1, 1, 1, 1, 1, 1, 1,
5057 1, 1, 1, 1, 1, 1, 1, 1,
5058 1, 1, 1, 1, 1, 1, 1, 1,
5059};
5060
5061
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005062template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005064
5065
5066template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005067MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5068 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005069}
5070
5071
5072template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5074 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005075}
5076
5077
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005078template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5080 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005081 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005082 const Char* read_cursor = characters.start();
5083 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005084 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005085 int quoted_length = kSpaceForQuotes;
5086 while (read_cursor < end) {
5087 Char c = *(read_cursor++);
5088 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5089 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005090 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005091 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005092 }
5093 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005094 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5095 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005096 Object* new_object;
5097 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005098 return new_alloc;
5099 }
5100 StringType* new_string = StringType::cast(new_object);
5101
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005102 Char* write_cursor = reinterpret_cast<Char*>(
5103 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005104 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005105 *(write_cursor++) = '"';
5106
5107 read_cursor = characters.start();
5108 while (read_cursor < end) {
5109 Char c = *(read_cursor++);
5110 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5111 *(write_cursor++) = c;
5112 } else {
5113 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5114 const char* replacement = JsonQuotes +
5115 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5116 for (int i = 0; i < len; i++) {
5117 *write_cursor++ = *replacement++;
5118 }
5119 }
5120 }
5121 *(write_cursor++) = '"';
5122 return new_string;
5123}
5124
5125
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005126template <typename SinkChar, typename SourceChar>
5127static inline SinkChar* WriteQuoteJsonString(
5128 Isolate* isolate,
5129 SinkChar* write_cursor,
5130 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005131 // SinkChar is only char if SourceChar is guaranteed to be char.
5132 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005133 const SourceChar* read_cursor = characters.start();
5134 const SourceChar* end = read_cursor + characters.length();
5135 *(write_cursor++) = '"';
5136 while (read_cursor < end) {
5137 SourceChar c = *(read_cursor++);
5138 if (sizeof(SourceChar) > 1u &&
5139 static_cast<unsigned>(c) >= kQuoteTableLength) {
5140 *(write_cursor++) = static_cast<SinkChar>(c);
5141 } else {
5142 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5143 const char* replacement = JsonQuotes +
5144 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5145 write_cursor[0] = replacement[0];
5146 if (len > 1) {
5147 write_cursor[1] = replacement[1];
5148 if (len > 2) {
5149 ASSERT(len == 6);
5150 write_cursor[2] = replacement[2];
5151 write_cursor[3] = replacement[3];
5152 write_cursor[4] = replacement[4];
5153 write_cursor[5] = replacement[5];
5154 }
5155 }
5156 write_cursor += len;
5157 }
5158 }
5159 *(write_cursor++) = '"';
5160 return write_cursor;
5161}
5162
5163
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005164template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165static MaybeObject* QuoteJsonString(Isolate* isolate,
5166 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005167 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005168 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005169 int worst_case_length =
5170 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005171 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005172 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005173 }
5174
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005175 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5176 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005177 Object* new_object;
5178 if (!new_alloc->ToObject(&new_object)) {
5179 return new_alloc;
5180 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005181 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005182 // Even if our string is small enough to fit in new space we still have to
5183 // handle it being allocated in old space as may happen in the third
5184 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5185 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005186 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005187 }
5188 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005189 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005190
5191 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5192 Char* write_cursor = reinterpret_cast<Char*>(
5193 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005194 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005195 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5196 write_cursor,
5197 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005198 int final_length = static_cast<int>(
5199 write_cursor - reinterpret_cast<Char*>(
5200 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005201 isolate->heap()->new_space()->
5202 template ShrinkStringAtAllocationBoundary<StringType>(
5203 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005204 return new_string;
5205}
5206
5207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005208RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005209 NoHandleAllocation ha;
5210 CONVERT_CHECKED(String, str, args[0]);
5211 if (!str->IsFlat()) {
5212 MaybeObject* try_flatten = str->TryFlatten();
5213 Object* flat;
5214 if (!try_flatten->ToObject(&flat)) {
5215 return try_flatten;
5216 }
5217 str = String::cast(flat);
5218 ASSERT(str->IsFlat());
5219 }
5220 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5222 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005223 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005224 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5225 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226 }
5227}
5228
5229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005230RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005231 NoHandleAllocation ha;
5232 CONVERT_CHECKED(String, str, args[0]);
5233 if (!str->IsFlat()) {
5234 MaybeObject* try_flatten = str->TryFlatten();
5235 Object* flat;
5236 if (!try_flatten->ToObject(&flat)) {
5237 return try_flatten;
5238 }
5239 str = String::cast(flat);
5240 ASSERT(str->IsFlat());
5241 }
5242 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005243 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5244 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005245 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005246 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5247 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005248 }
5249}
5250
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005251
5252template <typename Char, typename StringType>
5253static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5254 FixedArray* array,
5255 int worst_case_length) {
5256 int length = array->length();
5257
5258 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5259 worst_case_length);
5260 Object* new_object;
5261 if (!new_alloc->ToObject(&new_object)) {
5262 return new_alloc;
5263 }
5264 if (!isolate->heap()->new_space()->Contains(new_object)) {
5265 // Even if our string is small enough to fit in new space we still have to
5266 // handle it being allocated in old space as may happen in the third
5267 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5268 // CEntryStub::GenerateCore.
5269 return isolate->heap()->undefined_value();
5270 }
5271 AssertNoAllocation no_gc;
5272 StringType* new_string = StringType::cast(new_object);
5273 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5274
5275 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5276 Char* write_cursor = reinterpret_cast<Char*>(
5277 new_string->address() + SeqAsciiString::kHeaderSize);
5278 *(write_cursor++) = '[';
5279 for (int i = 0; i < length; i++) {
5280 if (i != 0) *(write_cursor++) = ',';
5281 String* str = String::cast(array->get(i));
5282 if (str->IsTwoByteRepresentation()) {
5283 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5284 write_cursor,
5285 str->ToUC16Vector());
5286 } else {
5287 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5288 write_cursor,
5289 str->ToAsciiVector());
5290 }
5291 }
5292 *(write_cursor++) = ']';
5293
5294 int final_length = static_cast<int>(
5295 write_cursor - reinterpret_cast<Char*>(
5296 new_string->address() + SeqAsciiString::kHeaderSize));
5297 isolate->heap()->new_space()->
5298 template ShrinkStringAtAllocationBoundary<StringType>(
5299 new_string, final_length);
5300 return new_string;
5301}
5302
5303
5304RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5305 NoHandleAllocation ha;
5306 ASSERT(args.length() == 1);
5307 CONVERT_CHECKED(JSArray, array, args[0]);
5308
5309 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5310 FixedArray* elements = FixedArray::cast(array->elements());
5311 int n = elements->length();
5312 bool ascii = true;
5313 int total_length = 0;
5314
5315 for (int i = 0; i < n; i++) {
5316 Object* elt = elements->get(i);
5317 if (!elt->IsString()) return isolate->heap()->undefined_value();
5318 String* element = String::cast(elt);
5319 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5320 total_length += element->length();
5321 if (ascii && element->IsTwoByteRepresentation()) {
5322 ascii = false;
5323 }
5324 }
5325
5326 int worst_case_length =
5327 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5328 + total_length * kJsonQuoteWorstCaseBlowup;
5329
5330 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5331 return isolate->heap()->undefined_value();
5332 }
5333
5334 if (ascii) {
5335 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5336 elements,
5337 worst_case_length);
5338 } else {
5339 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5340 elements,
5341 worst_case_length);
5342 }
5343}
5344
5345
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005346RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005347 NoHandleAllocation ha;
5348
5349 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005350 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005351
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005352 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005353
lrn@chromium.org25156de2010-04-06 13:10:27 +00005354 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005355 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005356 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005357}
5358
5359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005360RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005361 NoHandleAllocation ha;
5362 CONVERT_CHECKED(String, str, args[0]);
5363
5364 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005365 double value = StringToDouble(isolate->unicode_cache(),
5366 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005367
5368 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005369 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370}
5371
5372
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005373template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005374MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005375 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005376 String* s,
5377 int length,
5378 int input_string_length,
5379 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005380 // We try this twice, once with the assumption that the result is no longer
5381 // than the input and, if that assumption breaks, again with the exact
5382 // length. This may not be pretty, but it is nicer than what was here before
5383 // and I hereby claim my vaffel-is.
5384 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005385 // Allocate the resulting string.
5386 //
5387 // NOTE: This assumes that the upper/lower case of an ascii
5388 // character is also ascii. This is currently the case, but it
5389 // might break in the future if we implement more context and locale
5390 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005391 Object* o;
5392 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005393 ? isolate->heap()->AllocateRawAsciiString(length)
5394 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005395 if (!maybe_o->ToObject(&o)) return maybe_o;
5396 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 String* result = String::cast(o);
5398 bool has_changed_character = false;
5399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005400 // Convert all characters to upper case, assuming that they will fit
5401 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005402 Access<StringInputBuffer> buffer(
5403 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005404 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005405 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406 // We can assume that the string is not empty
5407 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005408 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005409 bool has_next = buffer->has_more();
5410 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 int char_length = mapping->get(current, next, chars);
5412 if (char_length == 0) {
5413 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005414 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005415 i++;
5416 } else if (char_length == 1) {
5417 // Common case: converting the letter resulted in one character.
5418 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005419 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420 has_changed_character = true;
5421 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005422 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005423 // We've assumed that the result would be as long as the
5424 // input but here is a character that converts to several
5425 // characters. No matter, we calculate the exact length
5426 // of the result and try the whole thing again.
5427 //
5428 // Note that this leaves room for optimization. We could just
5429 // memcpy what we already have to the result string. Also,
5430 // the result string is the last object allocated we could
5431 // "realloc" it and probably, in the vast majority of cases,
5432 // extend the existing string to be able to hold the full
5433 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005434 int next_length = 0;
5435 if (has_next) {
5436 next_length = mapping->get(next, 0, chars);
5437 if (next_length == 0) next_length = 1;
5438 }
5439 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005440 while (buffer->has_more()) {
5441 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005442 // NOTE: we use 0 as the next character here because, while
5443 // the next character may affect what a character converts to,
5444 // it does not in any case affect the length of what it convert
5445 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005446 int char_length = mapping->get(current, 0, chars);
5447 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005448 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005449 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005450 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005451 return Failure::OutOfMemoryException();
5452 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005453 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005454 // Try again with the real length.
5455 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 } else {
5457 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005458 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005459 i++;
5460 }
5461 has_changed_character = true;
5462 }
5463 current = next;
5464 }
5465 if (has_changed_character) {
5466 return result;
5467 } else {
5468 // If we didn't actually change anything in doing the conversion
5469 // we simple return the result and let the converted string
5470 // become garbage; there is no reason to keep two identical strings
5471 // alive.
5472 return s;
5473 }
5474}
5475
5476
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005477namespace {
5478
lrn@chromium.org303ada72010-10-27 09:33:13 +00005479static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5480
5481
5482// Given a word and two range boundaries returns a word with high bit
5483// set in every byte iff the corresponding input byte was strictly in
5484// the range (m, n). All the other bits in the result are cleared.
5485// This function is only useful when it can be inlined and the
5486// boundaries are statically known.
5487// Requires: all bytes in the input word and the boundaries must be
5488// ascii (less than 0x7F).
5489static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5490 // Every byte in an ascii string is less than or equal to 0x7F.
5491 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5492 // Use strict inequalities since in edge cases the function could be
5493 // further simplified.
5494 ASSERT(0 < m && m < n && n < 0x7F);
5495 // Has high bit set in every w byte less than n.
5496 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5497 // Has high bit set in every w byte greater than m.
5498 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5499 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5500}
5501
5502
5503enum AsciiCaseConversion {
5504 ASCII_TO_LOWER,
5505 ASCII_TO_UPPER
5506};
5507
5508
5509template <AsciiCaseConversion dir>
5510struct FastAsciiConverter {
5511 static bool Convert(char* dst, char* src, int length) {
5512#ifdef DEBUG
5513 char* saved_dst = dst;
5514 char* saved_src = src;
5515#endif
5516 // We rely on the distance between upper and lower case letters
5517 // being a known power of 2.
5518 ASSERT('a' - 'A' == (1 << 5));
5519 // Boundaries for the range of input characters than require conversion.
5520 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5521 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5522 bool changed = false;
5523 char* const limit = src + length;
5524#ifdef V8_HOST_CAN_READ_UNALIGNED
5525 // Process the prefix of the input that requires no conversion one
5526 // (machine) word at a time.
5527 while (src <= limit - sizeof(uintptr_t)) {
5528 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5529 if (AsciiRangeMask(w, lo, hi) != 0) {
5530 changed = true;
5531 break;
5532 }
5533 *reinterpret_cast<uintptr_t*>(dst) = w;
5534 src += sizeof(uintptr_t);
5535 dst += sizeof(uintptr_t);
5536 }
5537 // Process the remainder of the input performing conversion when
5538 // required one word at a time.
5539 while (src <= limit - sizeof(uintptr_t)) {
5540 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5541 uintptr_t m = AsciiRangeMask(w, lo, hi);
5542 // The mask has high (7th) bit set in every byte that needs
5543 // conversion and we know that the distance between cases is
5544 // 1 << 5.
5545 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5546 src += sizeof(uintptr_t);
5547 dst += sizeof(uintptr_t);
5548 }
5549#endif
5550 // Process the last few bytes of the input (or the whole input if
5551 // unaligned access is not supported).
5552 while (src < limit) {
5553 char c = *src;
5554 if (lo < c && c < hi) {
5555 c ^= (1 << 5);
5556 changed = true;
5557 }
5558 *dst = c;
5559 ++src;
5560 ++dst;
5561 }
5562#ifdef DEBUG
5563 CheckConvert(saved_dst, saved_src, length, changed);
5564#endif
5565 return changed;
5566 }
5567
5568#ifdef DEBUG
5569 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5570 bool expected_changed = false;
5571 for (int i = 0; i < length; i++) {
5572 if (dst[i] == src[i]) continue;
5573 expected_changed = true;
5574 if (dir == ASCII_TO_LOWER) {
5575 ASSERT('A' <= src[i] && src[i] <= 'Z');
5576 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5577 } else {
5578 ASSERT(dir == ASCII_TO_UPPER);
5579 ASSERT('a' <= src[i] && src[i] <= 'z');
5580 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5581 }
5582 }
5583 ASSERT(expected_changed == changed);
5584 }
5585#endif
5586};
5587
5588
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005589struct ToLowerTraits {
5590 typedef unibrow::ToLowercase UnibrowConverter;
5591
lrn@chromium.org303ada72010-10-27 09:33:13 +00005592 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005593};
5594
5595
5596struct ToUpperTraits {
5597 typedef unibrow::ToUppercase UnibrowConverter;
5598
lrn@chromium.org303ada72010-10-27 09:33:13 +00005599 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005600};
5601
5602} // namespace
5603
5604
5605template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005606MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005607 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005608 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005609 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005610 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005611 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005612 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005613
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005614 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005615 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005616 if (length == 0) return s;
5617
5618 // Simpler handling of ascii strings.
5619 //
5620 // NOTE: This assumes that the upper/lower case of an ascii
5621 // character is also ascii. This is currently the case, but it
5622 // might break in the future if we implement more context and locale
5623 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005624 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005625 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005626 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005627 if (!maybe_o->ToObject(&o)) return maybe_o;
5628 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005629 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005630 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005631 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005632 return has_changed_character ? result : s;
5633 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005634
lrn@chromium.org303ada72010-10-27 09:33:13 +00005635 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005636 { MaybeObject* maybe_answer =
5637 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005638 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5639 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005640 if (answer->IsSmi()) {
5641 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005642 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005643 ConvertCaseHelper(isolate,
5644 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005645 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5646 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005647 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005648 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005649}
5650
5651
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005652RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005653 return ConvertCase<ToLowerTraits>(
5654 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005655}
5656
5657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005658RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005659 return ConvertCase<ToUpperTraits>(
5660 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005661}
5662
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005663
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005664static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5665 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5666}
5667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005668
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005669RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005670 NoHandleAllocation ha;
5671 ASSERT(args.length() == 3);
5672
5673 CONVERT_CHECKED(String, s, args[0]);
5674 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5675 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5676
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005677 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005678 int length = s->length();
5679
5680 int left = 0;
5681 if (trimLeft) {
5682 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5683 left++;
5684 }
5685 }
5686
5687 int right = length;
5688 if (trimRight) {
5689 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5690 right--;
5691 }
5692 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005693 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005694}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005695
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005696
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005697template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005698void FindStringIndices(Isolate* isolate,
5699 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005700 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005701 ZoneList<int>* indices,
5702 unsigned int limit) {
5703 ASSERT(limit > 0);
5704 // Collect indices of pattern in subject, and the end-of-string index.
5705 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005706 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005707 int pattern_length = pattern.length();
5708 int index = 0;
5709 while (limit > 0) {
5710 index = search.Search(subject, index);
5711 if (index < 0) return;
5712 indices->Add(index);
5713 index += pattern_length;
5714 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005715 }
5716}
5717
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005719RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005720 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005721 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005722 CONVERT_ARG_CHECKED(String, subject, 0);
5723 CONVERT_ARG_CHECKED(String, pattern, 1);
5724 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5725
5726 int subject_length = subject->length();
5727 int pattern_length = pattern->length();
5728 RUNTIME_ASSERT(pattern_length > 0);
5729
5730 // The limit can be very large (0xffffffffu), but since the pattern
5731 // isn't empty, we can never create more parts than ~half the length
5732 // of the subject.
5733
5734 if (!subject->IsFlat()) FlattenString(subject);
5735
5736 static const int kMaxInitialListCapacity = 16;
5737
danno@chromium.org40cb8782011-05-25 07:58:50 +00005738 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005739
5740 // Find (up to limit) indices of separator and end-of-string in subject
5741 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5742 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005743 if (!pattern->IsFlat()) FlattenString(pattern);
5744
5745 // No allocation block.
5746 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005747 AssertNoAllocation nogc;
5748 if (subject->IsAsciiRepresentation()) {
5749 Vector<const char> subject_vector = subject->ToAsciiVector();
5750 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005751 FindStringIndices(isolate,
5752 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005753 pattern->ToAsciiVector(),
5754 &indices,
5755 limit);
5756 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005757 FindStringIndices(isolate,
5758 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005759 pattern->ToUC16Vector(),
5760 &indices,
5761 limit);
5762 }
5763 } else {
5764 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5765 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005766 FindStringIndices(isolate,
5767 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005768 pattern->ToAsciiVector(),
5769 &indices,
5770 limit);
5771 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005772 FindStringIndices(isolate,
5773 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005774 pattern->ToUC16Vector(),
5775 &indices,
5776 limit);
5777 }
5778 }
5779 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005780
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005781 if (static_cast<uint32_t>(indices.length()) < limit) {
5782 indices.Add(subject_length);
5783 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005784
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005785 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005786
5787 // Create JSArray of substrings separated by separator.
5788 int part_count = indices.length();
5789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005791 result->set_length(Smi::FromInt(part_count));
5792
5793 ASSERT(result->HasFastElements());
5794
5795 if (part_count == 1 && indices.at(0) == subject_length) {
5796 FixedArray::cast(result->elements())->set(0, *subject);
5797 return *result;
5798 }
5799
5800 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5801 int part_start = 0;
5802 for (int i = 0; i < part_count; i++) {
5803 HandleScope local_loop_handle;
5804 int part_end = indices.at(i);
5805 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005806 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005807 elements->set(i, *substring);
5808 part_start = part_end + pattern_length;
5809 }
5810
5811 return *result;
5812}
5813
5814
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005815// Copies ascii characters to the given fixed array looking up
5816// one-char strings in the cache. Gives up on the first char that is
5817// not in the cache and fills the remainder with smi zeros. Returns
5818// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005819static int CopyCachedAsciiCharsToArray(Heap* heap,
5820 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005821 FixedArray* elements,
5822 int length) {
5823 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005824 FixedArray* ascii_cache = heap->single_character_string_cache();
5825 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005826 int i;
5827 for (i = 0; i < length; ++i) {
5828 Object* value = ascii_cache->get(chars[i]);
5829 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005830 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005831 elements->set(i, value, SKIP_WRITE_BARRIER);
5832 }
5833 if (i < length) {
5834 ASSERT(Smi::FromInt(0) == 0);
5835 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5836 }
5837#ifdef DEBUG
5838 for (int j = 0; j < length; ++j) {
5839 Object* element = elements->get(j);
5840 ASSERT(element == Smi::FromInt(0) ||
5841 (element->IsString() && String::cast(element)->LooksValid()));
5842 }
5843#endif
5844 return i;
5845}
5846
5847
5848// Converts a String to JSArray.
5849// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005850RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005851 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005852 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005853 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005854 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005855
5856 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005857 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005858
5859 Handle<FixedArray> elements;
5860 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005861 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005862 { MaybeObject* maybe_obj =
5863 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005864 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5865 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005866 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005867
5868 Vector<const char> chars = s->ToAsciiVector();
5869 // Note, this will initialize all elements (not only the prefix)
5870 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5872 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005873 *elements,
5874 length);
5875
5876 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005877 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5878 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005879 }
5880 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005881 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005882 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005883 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5884 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005885 }
5886 }
5887
5888#ifdef DEBUG
5889 for (int i = 0; i < length; ++i) {
5890 ASSERT(String::cast(elements->get(i))->length() == 1);
5891 }
5892#endif
5893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005894 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005895}
5896
5897
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005898RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005899 NoHandleAllocation ha;
5900 ASSERT(args.length() == 1);
5901 CONVERT_CHECKED(String, value, args[0]);
5902 return value->ToObject();
5903}
5904
5905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005906bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005907 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005908 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005909 return char_length == 0;
5910}
5911
5912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005913RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914 NoHandleAllocation ha;
5915 ASSERT(args.length() == 1);
5916
5917 Object* number = args[0];
5918 RUNTIME_ASSERT(number->IsNumber());
5919
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005920 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921}
5922
5923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005924RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005925 NoHandleAllocation ha;
5926 ASSERT(args.length() == 1);
5927
5928 Object* number = args[0];
5929 RUNTIME_ASSERT(number->IsNumber());
5930
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005931 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005932}
5933
5934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005935RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005936 NoHandleAllocation ha;
5937 ASSERT(args.length() == 1);
5938
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005939 CONVERT_DOUBLE_CHECKED(number, args[0]);
5940
5941 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5942 if (number > 0 && number <= Smi::kMaxValue) {
5943 return Smi::FromInt(static_cast<int>(number));
5944 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005945 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005946}
5947
5948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005949RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005950 NoHandleAllocation ha;
5951 ASSERT(args.length() == 1);
5952
5953 CONVERT_DOUBLE_CHECKED(number, args[0]);
5954
5955 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5956 if (number > 0 && number <= Smi::kMaxValue) {
5957 return Smi::FromInt(static_cast<int>(number));
5958 }
5959
5960 double double_value = DoubleToInteger(number);
5961 // Map both -0 and +0 to +0.
5962 if (double_value == 0) double_value = 0;
5963
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005964 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005965}
5966
5967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005968RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 NoHandleAllocation ha;
5970 ASSERT(args.length() == 1);
5971
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005972 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005973 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974}
5975
5976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005977RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978 NoHandleAllocation ha;
5979 ASSERT(args.length() == 1);
5980
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005981 CONVERT_DOUBLE_CHECKED(number, args[0]);
5982
5983 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5984 if (number > 0 && number <= Smi::kMaxValue) {
5985 return Smi::FromInt(static_cast<int>(number));
5986 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005987 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988}
5989
5990
ager@chromium.org870a0b62008-11-04 11:43:05 +00005991// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5992// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005993RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005994 NoHandleAllocation ha;
5995 ASSERT(args.length() == 1);
5996
5997 Object* obj = args[0];
5998 if (obj->IsSmi()) {
5999 return obj;
6000 }
6001 if (obj->IsHeapNumber()) {
6002 double value = HeapNumber::cast(obj)->value();
6003 int int_value = FastD2I(value);
6004 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6005 return Smi::FromInt(int_value);
6006 }
6007 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006008 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006009}
6010
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006012RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006013 NoHandleAllocation ha;
6014 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006015 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006016}
6017
6018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006019RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 NoHandleAllocation ha;
6021 ASSERT(args.length() == 2);
6022
6023 CONVERT_DOUBLE_CHECKED(x, args[0]);
6024 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006025 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026}
6027
6028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006029RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 NoHandleAllocation ha;
6031 ASSERT(args.length() == 2);
6032
6033 CONVERT_DOUBLE_CHECKED(x, args[0]);
6034 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006035 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006036}
6037
6038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006039RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 NoHandleAllocation ha;
6041 ASSERT(args.length() == 2);
6042
6043 CONVERT_DOUBLE_CHECKED(x, args[0]);
6044 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006045 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046}
6047
6048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006049RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006050 NoHandleAllocation ha;
6051 ASSERT(args.length() == 1);
6052
6053 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006054 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006055}
6056
6057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006058RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006059 NoHandleAllocation ha;
6060 ASSERT(args.length() == 0);
6061
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006062 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006063}
6064
6065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006066RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006067 NoHandleAllocation ha;
6068 ASSERT(args.length() == 2);
6069
6070 CONVERT_DOUBLE_CHECKED(x, args[0]);
6071 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006072 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006073}
6074
6075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006076RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077 NoHandleAllocation ha;
6078 ASSERT(args.length() == 2);
6079
6080 CONVERT_DOUBLE_CHECKED(x, args[0]);
6081 CONVERT_DOUBLE_CHECKED(y, args[1]);
6082
ager@chromium.org3811b432009-10-28 14:53:37 +00006083 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006084 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006085 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086}
6087
6088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006089RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006090 NoHandleAllocation ha;
6091 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006092 CONVERT_CHECKED(String, str1, args[0]);
6093 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006094 isolate->counters()->string_add_runtime()->Increment();
6095 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006096}
6097
6098
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006099template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006100static inline void StringBuilderConcatHelper(String* special,
6101 sinkchar* sink,
6102 FixedArray* fixed_array,
6103 int array_length) {
6104 int position = 0;
6105 for (int i = 0; i < array_length; i++) {
6106 Object* element = fixed_array->get(i);
6107 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006108 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006109 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006110 int pos;
6111 int len;
6112 if (encoded_slice > 0) {
6113 // Position and length encoded in one smi.
6114 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6115 len = StringBuilderSubstringLength::decode(encoded_slice);
6116 } else {
6117 // Position and length encoded in two smis.
6118 Object* obj = fixed_array->get(++i);
6119 ASSERT(obj->IsSmi());
6120 pos = Smi::cast(obj)->value();
6121 len = -encoded_slice;
6122 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006123 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006124 sink + position,
6125 pos,
6126 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006127 position += len;
6128 } else {
6129 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006130 int element_length = string->length();
6131 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006132 position += element_length;
6133 }
6134 }
6135}
6136
6137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006138RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006139 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006140 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006141 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006142 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006143 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006144 return Failure::OutOfMemoryException();
6145 }
6146 int array_length = Smi::cast(args[1])->value();
6147 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006148
6149 // This assumption is used by the slice encoding in one or two smis.
6150 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6151
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006152 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006153 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006154 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006155 }
6156 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006157 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006158 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006159 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006160
6161 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006162 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006163 } else if (array_length == 1) {
6164 Object* first = fixed_array->get(0);
6165 if (first->IsString()) return first;
6166 }
6167
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006168 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006169 int position = 0;
6170 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006171 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006172 Object* elt = fixed_array->get(i);
6173 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006174 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006175 int smi_value = Smi::cast(elt)->value();
6176 int pos;
6177 int len;
6178 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006179 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006180 pos = StringBuilderSubstringPosition::decode(smi_value);
6181 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006182 } else {
6183 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006184 len = -smi_value;
6185 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006186 i++;
6187 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006188 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006189 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006190 Object* next_smi = fixed_array->get(i);
6191 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006193 }
6194 pos = Smi::cast(next_smi)->value();
6195 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006196 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006199 ASSERT(pos >= 0);
6200 ASSERT(len >= 0);
6201 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006202 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006203 }
6204 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006205 } else if (elt->IsString()) {
6206 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006207 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006208 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006209 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006212 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006213 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006214 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006215 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006216 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006217 return Failure::OutOfMemoryException();
6218 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006219 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 }
6221
6222 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006223 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006225 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006226 { MaybeObject* maybe_object =
6227 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006228 if (!maybe_object->ToObject(&object)) return maybe_object;
6229 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006230 SeqAsciiString* answer = SeqAsciiString::cast(object);
6231 StringBuilderConcatHelper(special,
6232 answer->GetChars(),
6233 fixed_array,
6234 array_length);
6235 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006236 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006237 { MaybeObject* maybe_object =
6238 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006239 if (!maybe_object->ToObject(&object)) return maybe_object;
6240 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006241 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6242 StringBuilderConcatHelper(special,
6243 answer->GetChars(),
6244 fixed_array,
6245 array_length);
6246 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248}
6249
6250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006251RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006252 NoHandleAllocation ha;
6253 ASSERT(args.length() == 3);
6254 CONVERT_CHECKED(JSArray, array, args[0]);
6255 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006256 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006257 return Failure::OutOfMemoryException();
6258 }
6259 int array_length = Smi::cast(args[1])->value();
6260 CONVERT_CHECKED(String, separator, args[2]);
6261
6262 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006263 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006264 }
6265 FixedArray* fixed_array = FixedArray::cast(array->elements());
6266 if (fixed_array->length() < array_length) {
6267 array_length = fixed_array->length();
6268 }
6269
6270 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006271 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006272 } else if (array_length == 1) {
6273 Object* first = fixed_array->get(0);
6274 if (first->IsString()) return first;
6275 }
6276
6277 int separator_length = separator->length();
6278 int max_nof_separators =
6279 (String::kMaxLength + separator_length - 1) / separator_length;
6280 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006281 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006282 return Failure::OutOfMemoryException();
6283 }
6284 int length = (array_length - 1) * separator_length;
6285 for (int i = 0; i < array_length; i++) {
6286 Object* element_obj = fixed_array->get(i);
6287 if (!element_obj->IsString()) {
6288 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006289 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006290 }
6291 String* element = String::cast(element_obj);
6292 int increment = element->length();
6293 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006294 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006295 return Failure::OutOfMemoryException();
6296 }
6297 length += increment;
6298 }
6299
6300 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006301 { MaybeObject* maybe_object =
6302 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006303 if (!maybe_object->ToObject(&object)) return maybe_object;
6304 }
6305 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6306
6307 uc16* sink = answer->GetChars();
6308#ifdef DEBUG
6309 uc16* end = sink + length;
6310#endif
6311
6312 String* first = String::cast(fixed_array->get(0));
6313 int first_length = first->length();
6314 String::WriteToFlat(first, sink, 0, first_length);
6315 sink += first_length;
6316
6317 for (int i = 1; i < array_length; i++) {
6318 ASSERT(sink + separator_length <= end);
6319 String::WriteToFlat(separator, sink, 0, separator_length);
6320 sink += separator_length;
6321
6322 String* element = String::cast(fixed_array->get(i));
6323 int element_length = element->length();
6324 ASSERT(sink + element_length <= end);
6325 String::WriteToFlat(element, sink, 0, element_length);
6326 sink += element_length;
6327 }
6328 ASSERT(sink == end);
6329
6330 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6331 return answer;
6332}
6333
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006334template <typename Char>
6335static void JoinSparseArrayWithSeparator(FixedArray* elements,
6336 int elements_length,
6337 uint32_t array_length,
6338 String* separator,
6339 Vector<Char> buffer) {
6340 int previous_separator_position = 0;
6341 int separator_length = separator->length();
6342 int cursor = 0;
6343 for (int i = 0; i < elements_length; i += 2) {
6344 int position = NumberToInt32(elements->get(i));
6345 String* string = String::cast(elements->get(i + 1));
6346 int string_length = string->length();
6347 if (string->length() > 0) {
6348 while (previous_separator_position < position) {
6349 String::WriteToFlat<Char>(separator, &buffer[cursor],
6350 0, separator_length);
6351 cursor += separator_length;
6352 previous_separator_position++;
6353 }
6354 String::WriteToFlat<Char>(string, &buffer[cursor],
6355 0, string_length);
6356 cursor += string->length();
6357 }
6358 }
6359 if (separator_length > 0) {
6360 // Array length must be representable as a signed 32-bit number,
6361 // otherwise the total string length would have been too large.
6362 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6363 int last_array_index = static_cast<int>(array_length - 1);
6364 while (previous_separator_position < last_array_index) {
6365 String::WriteToFlat<Char>(separator, &buffer[cursor],
6366 0, separator_length);
6367 cursor += separator_length;
6368 previous_separator_position++;
6369 }
6370 }
6371 ASSERT(cursor <= buffer.length());
6372}
6373
6374
6375RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6376 NoHandleAllocation ha;
6377 ASSERT(args.length() == 3);
6378 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6379 RUNTIME_ASSERT(elements_array->HasFastElements());
6380 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6381 CONVERT_CHECKED(String, separator, args[2]);
6382 // elements_array is fast-mode JSarray of alternating positions
6383 // (increasing order) and strings.
6384 // array_length is length of original array (used to add separators);
6385 // separator is string to put between elements. Assumed to be non-empty.
6386
6387 // Find total length of join result.
6388 int string_length = 0;
6389 bool is_ascii = true;
6390 int max_string_length = SeqAsciiString::kMaxLength;
6391 bool overflow = false;
6392 CONVERT_NUMBER_CHECKED(int, elements_length,
6393 Int32, elements_array->length());
6394 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6395 FixedArray* elements = FixedArray::cast(elements_array->elements());
6396 for (int i = 0; i < elements_length; i += 2) {
6397 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6398 CONVERT_CHECKED(String, string, elements->get(i + 1));
6399 int length = string->length();
6400 if (is_ascii && !string->IsAsciiRepresentation()) {
6401 is_ascii = false;
6402 max_string_length = SeqTwoByteString::kMaxLength;
6403 }
6404 if (length > max_string_length ||
6405 max_string_length - length < string_length) {
6406 overflow = true;
6407 break;
6408 }
6409 string_length += length;
6410 }
6411 int separator_length = separator->length();
6412 if (!overflow && separator_length > 0) {
6413 if (array_length <= 0x7fffffffu) {
6414 int separator_count = static_cast<int>(array_length) - 1;
6415 int remaining_length = max_string_length - string_length;
6416 if ((remaining_length / separator_length) >= separator_count) {
6417 string_length += separator_length * (array_length - 1);
6418 } else {
6419 // Not room for the separators within the maximal string length.
6420 overflow = true;
6421 }
6422 } else {
6423 // Nonempty separator and at least 2^31-1 separators necessary
6424 // means that the string is too large to create.
6425 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6426 overflow = true;
6427 }
6428 }
6429 if (overflow) {
6430 // Throw OutOfMemory exception for creating too large a string.
6431 V8::FatalProcessOutOfMemory("Array join result too large.");
6432 }
6433
6434 if (is_ascii) {
6435 MaybeObject* result_allocation =
6436 isolate->heap()->AllocateRawAsciiString(string_length);
6437 if (result_allocation->IsFailure()) return result_allocation;
6438 SeqAsciiString* result_string =
6439 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6440 JoinSparseArrayWithSeparator<char>(elements,
6441 elements_length,
6442 array_length,
6443 separator,
6444 Vector<char>(result_string->GetChars(),
6445 string_length));
6446 return result_string;
6447 } else {
6448 MaybeObject* result_allocation =
6449 isolate->heap()->AllocateRawTwoByteString(string_length);
6450 if (result_allocation->IsFailure()) return result_allocation;
6451 SeqTwoByteString* result_string =
6452 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6453 JoinSparseArrayWithSeparator<uc16>(elements,
6454 elements_length,
6455 array_length,
6456 separator,
6457 Vector<uc16>(result_string->GetChars(),
6458 string_length));
6459 return result_string;
6460 }
6461}
6462
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006463
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006464RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006465 NoHandleAllocation ha;
6466 ASSERT(args.length() == 2);
6467
6468 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6469 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006470 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006471}
6472
6473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006474RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006475 NoHandleAllocation ha;
6476 ASSERT(args.length() == 2);
6477
6478 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6479 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006480 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006481}
6482
6483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006484RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006485 NoHandleAllocation ha;
6486 ASSERT(args.length() == 2);
6487
6488 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6489 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006490 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006491}
6492
6493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006494RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006495 NoHandleAllocation ha;
6496 ASSERT(args.length() == 1);
6497
6498 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500}
6501
6502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006503RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006504 NoHandleAllocation ha;
6505 ASSERT(args.length() == 2);
6506
6507 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6508 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006510}
6511
6512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006513RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006514 NoHandleAllocation ha;
6515 ASSERT(args.length() == 2);
6516
6517 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6518 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006519 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006520}
6521
6522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006523RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006524 NoHandleAllocation ha;
6525 ASSERT(args.length() == 2);
6526
6527 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6528 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006529 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006530}
6531
6532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006533RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006534 NoHandleAllocation ha;
6535 ASSERT(args.length() == 2);
6536
6537 CONVERT_DOUBLE_CHECKED(x, args[0]);
6538 CONVERT_DOUBLE_CHECKED(y, args[1]);
6539 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6540 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6541 if (x == y) return Smi::FromInt(EQUAL);
6542 Object* result;
6543 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6544 result = Smi::FromInt(EQUAL);
6545 } else {
6546 result = Smi::FromInt(NOT_EQUAL);
6547 }
6548 return result;
6549}
6550
6551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006552RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553 NoHandleAllocation ha;
6554 ASSERT(args.length() == 2);
6555
6556 CONVERT_CHECKED(String, x, args[0]);
6557 CONVERT_CHECKED(String, y, args[1]);
6558
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006559 bool not_equal = !x->Equals(y);
6560 // This is slightly convoluted because the value that signifies
6561 // equality is 0 and inequality is 1 so we have to negate the result
6562 // from String::Equals.
6563 ASSERT(not_equal == 0 || not_equal == 1);
6564 STATIC_CHECK(EQUAL == 0);
6565 STATIC_CHECK(NOT_EQUAL == 1);
6566 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567}
6568
6569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006570RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006571 NoHandleAllocation ha;
6572 ASSERT(args.length() == 3);
6573
6574 CONVERT_DOUBLE_CHECKED(x, args[0]);
6575 CONVERT_DOUBLE_CHECKED(y, args[1]);
6576 if (isnan(x) || isnan(y)) return args[2];
6577 if (x == y) return Smi::FromInt(EQUAL);
6578 if (isless(x, y)) return Smi::FromInt(LESS);
6579 return Smi::FromInt(GREATER);
6580}
6581
6582
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006583// Compare two Smis as if they were converted to strings and then
6584// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006585RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006586 NoHandleAllocation ha;
6587 ASSERT(args.length() == 2);
6588
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006589 // Extract the integer values from the Smis.
6590 CONVERT_CHECKED(Smi, x, args[0]);
6591 CONVERT_CHECKED(Smi, y, args[1]);
6592 int x_value = x->value();
6593 int y_value = y->value();
6594
6595 // If the integers are equal so are the string representations.
6596 if (x_value == y_value) return Smi::FromInt(EQUAL);
6597
6598 // If one of the integers are zero the normal integer order is the
6599 // same as the lexicographic order of the string representations.
6600 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6601
ager@chromium.org32912102009-01-16 10:38:43 +00006602 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006603 // smallest because the char code of '-' is less than the char code
6604 // of any digit. Otherwise, we make both values positive.
6605 if (x_value < 0 || y_value < 0) {
6606 if (y_value >= 0) return Smi::FromInt(LESS);
6607 if (x_value >= 0) return Smi::FromInt(GREATER);
6608 x_value = -x_value;
6609 y_value = -y_value;
6610 }
6611
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006612 // Arrays for the individual characters of the two Smis. Smis are
6613 // 31 bit integers and 10 decimal digits are therefore enough.
6614 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6615 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6616 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6617
6618
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006619 // Convert the integers to arrays of their decimal digits.
6620 int x_index = 0;
6621 int y_index = 0;
6622 while (x_value > 0) {
6623 x_elms[x_index++] = x_value % 10;
6624 x_value /= 10;
6625 }
6626 while (y_value > 0) {
6627 y_elms[y_index++] = y_value % 10;
6628 y_value /= 10;
6629 }
6630
6631 // Loop through the arrays of decimal digits finding the first place
6632 // where they differ.
6633 while (--x_index >= 0 && --y_index >= 0) {
6634 int diff = x_elms[x_index] - y_elms[y_index];
6635 if (diff != 0) return Smi::FromInt(diff);
6636 }
6637
6638 // If one array is a suffix of the other array, the longest array is
6639 // the representation of the largest of the Smis in the
6640 // lexicographic ordering.
6641 return Smi::FromInt(x_index - y_index);
6642}
6643
6644
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006645static Object* StringInputBufferCompare(RuntimeState* state,
6646 String* x,
6647 String* y) {
6648 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6649 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006650 bufx.Reset(x);
6651 bufy.Reset(y);
6652 while (bufx.has_more() && bufy.has_more()) {
6653 int d = bufx.GetNext() - bufy.GetNext();
6654 if (d < 0) return Smi::FromInt(LESS);
6655 else if (d > 0) return Smi::FromInt(GREATER);
6656 }
6657
6658 // x is (non-trivial) prefix of y:
6659 if (bufy.has_more()) return Smi::FromInt(LESS);
6660 // y is prefix of x:
6661 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6662}
6663
6664
6665static Object* FlatStringCompare(String* x, String* y) {
6666 ASSERT(x->IsFlat());
6667 ASSERT(y->IsFlat());
6668 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6669 int prefix_length = x->length();
6670 if (y->length() < prefix_length) {
6671 prefix_length = y->length();
6672 equal_prefix_result = Smi::FromInt(GREATER);
6673 } else if (y->length() > prefix_length) {
6674 equal_prefix_result = Smi::FromInt(LESS);
6675 }
6676 int r;
6677 if (x->IsAsciiRepresentation()) {
6678 Vector<const char> x_chars = x->ToAsciiVector();
6679 if (y->IsAsciiRepresentation()) {
6680 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006681 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006682 } else {
6683 Vector<const uc16> y_chars = y->ToUC16Vector();
6684 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6685 }
6686 } else {
6687 Vector<const uc16> x_chars = x->ToUC16Vector();
6688 if (y->IsAsciiRepresentation()) {
6689 Vector<const char> y_chars = y->ToAsciiVector();
6690 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6691 } else {
6692 Vector<const uc16> y_chars = y->ToUC16Vector();
6693 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6694 }
6695 }
6696 Object* result;
6697 if (r == 0) {
6698 result = equal_prefix_result;
6699 } else {
6700 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6701 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006702 ASSERT(result ==
6703 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006704 return result;
6705}
6706
6707
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006708RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 NoHandleAllocation ha;
6710 ASSERT(args.length() == 2);
6711
6712 CONVERT_CHECKED(String, x, args[0]);
6713 CONVERT_CHECKED(String, y, args[1]);
6714
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006715 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717 // A few fast case tests before we flatten.
6718 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006719 if (y->length() == 0) {
6720 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006722 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006723 return Smi::FromInt(LESS);
6724 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006725
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006726 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006727 if (d < 0) return Smi::FromInt(LESS);
6728 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006729
lrn@chromium.org303ada72010-10-27 09:33:13 +00006730 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006731 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006732 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6733 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006734 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006735 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6736 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006738 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006739 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740}
6741
6742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006743RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744 NoHandleAllocation ha;
6745 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006746 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006747
6748 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006749 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750}
6751
6752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006753RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 NoHandleAllocation ha;
6755 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006756 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757
6758 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006759 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760}
6761
6762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006763RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764 NoHandleAllocation ha;
6765 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006766 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767
6768 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006769 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770}
6771
6772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006773static const double kPiDividedBy4 = 0.78539816339744830962;
6774
6775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006776RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777 NoHandleAllocation ha;
6778 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006779 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780
6781 CONVERT_DOUBLE_CHECKED(x, args[0]);
6782 CONVERT_DOUBLE_CHECKED(y, args[1]);
6783 double result;
6784 if (isinf(x) && isinf(y)) {
6785 // Make sure that the result in case of two infinite arguments
6786 // is a multiple of Pi / 4. The sign of the result is determined
6787 // by the first argument (x) and the sign of the second argument
6788 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006789 int multiplier = (x < 0) ? -1 : 1;
6790 if (y < 0) multiplier *= 3;
6791 result = multiplier * kPiDividedBy4;
6792 } else {
6793 result = atan2(x, y);
6794 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006795 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796}
6797
6798
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006799RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800 NoHandleAllocation ha;
6801 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006802 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006803
6804 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006805 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006806}
6807
6808
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006809RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810 NoHandleAllocation ha;
6811 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006812 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006813
6814 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006815 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816}
6817
6818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006819RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820 NoHandleAllocation ha;
6821 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006822 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823
6824 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006825 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006826}
6827
6828
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006829RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830 NoHandleAllocation ha;
6831 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006832 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006833
6834 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006835 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836}
6837
6838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006839RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006840 NoHandleAllocation ha;
6841 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006842 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006843
6844 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006845 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006846}
6847
6848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006849RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850 NoHandleAllocation ha;
6851 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006852 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006853
6854 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006855
6856 // If the second argument is a smi, it is much faster to call the
6857 // custom powi() function than the generic pow().
6858 if (args[1]->IsSmi()) {
6859 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006860 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006861 }
6862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006864 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006865}
6866
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006867// Fast version of Math.pow if we know that y is not an integer and
6868// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006869RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006870 NoHandleAllocation ha;
6871 ASSERT(args.length() == 2);
6872 CONVERT_DOUBLE_CHECKED(x, args[0]);
6873 CONVERT_DOUBLE_CHECKED(y, args[1]);
6874 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006875 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006876 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006877 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006878 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006879 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006880 }
6881}
6882
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006884RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006885 NoHandleAllocation ha;
6886 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006887 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006888
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006889 if (!args[0]->IsHeapNumber()) {
6890 // Must be smi. Return the argument unchanged for all the other types
6891 // to make fuzz-natives test happy.
6892 return args[0];
6893 }
6894
6895 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6896
6897 double value = number->value();
6898 int exponent = number->get_exponent();
6899 int sign = number->get_sign();
6900
danno@chromium.org160a7b02011-04-18 15:51:38 +00006901 if (exponent < -1) {
6902 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6903 if (sign) return isolate->heap()->minus_zero_value();
6904 return Smi::FromInt(0);
6905 }
6906
6907 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6908 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6909 // agument holds for 32-bit smis).
6910 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006911 return Smi::FromInt(static_cast<int>(value + 0.5));
6912 }
6913
6914 // If the magnitude is big enough, there's no place for fraction part. If we
6915 // try to add 0.5 to this number, 1.0 will be added instead.
6916 if (exponent >= 52) {
6917 return number;
6918 }
6919
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006920 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006921
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006922 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006923 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006924}
6925
6926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006927RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006928 NoHandleAllocation ha;
6929 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006930 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006931
6932 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006933 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006934}
6935
6936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006937RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006938 NoHandleAllocation ha;
6939 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006940 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006941
6942 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006943 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006944}
6945
6946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006947RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006948 NoHandleAllocation ha;
6949 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006950 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006951
6952 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006953 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006954}
6955
6956
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006957static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006958 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6959 181, 212, 243, 273, 304, 334};
6960 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6961 182, 213, 244, 274, 305, 335};
6962
6963 year += month / 12;
6964 month %= 12;
6965 if (month < 0) {
6966 year--;
6967 month += 12;
6968 }
6969
6970 ASSERT(month >= 0);
6971 ASSERT(month < 12);
6972
6973 // year_delta is an arbitrary number such that:
6974 // a) year_delta = -1 (mod 400)
6975 // b) year + year_delta > 0 for years in the range defined by
6976 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6977 // Jan 1 1970. This is required so that we don't run into integer
6978 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006979 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006980 // operations.
6981 static const int year_delta = 399999;
6982 static const int base_day = 365 * (1970 + year_delta) +
6983 (1970 + year_delta) / 4 -
6984 (1970 + year_delta) / 100 +
6985 (1970 + year_delta) / 400;
6986
6987 int year1 = year + year_delta;
6988 int day_from_year = 365 * year1 +
6989 year1 / 4 -
6990 year1 / 100 +
6991 year1 / 400 -
6992 base_day;
6993
6994 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006995 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006996 }
6997
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006998 return day_from_year + day_from_month_leap[month] + day - 1;
6999}
7000
7001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007002RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007003 NoHandleAllocation ha;
7004 ASSERT(args.length() == 3);
7005
7006 CONVERT_SMI_CHECKED(year, args[0]);
7007 CONVERT_SMI_CHECKED(month, args[1]);
7008 CONVERT_SMI_CHECKED(date, args[2]);
7009
7010 return Smi::FromInt(MakeDay(year, month, date));
7011}
7012
7013
7014static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7015static const int kDaysIn4Years = 4 * 365 + 1;
7016static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7017static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7018static const int kDays1970to2000 = 30 * 365 + 7;
7019static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7020 kDays1970to2000;
7021static const int kYearsOffset = 400000;
7022
7023static const char kDayInYear[] = {
7024 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7025 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7026 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7027 22, 23, 24, 25, 26, 27, 28,
7028 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7029 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7030 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7031 22, 23, 24, 25, 26, 27, 28, 29, 30,
7032 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7033 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7034 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7035 22, 23, 24, 25, 26, 27, 28, 29, 30,
7036 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7037 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7038 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7039 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7040 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7041 22, 23, 24, 25, 26, 27, 28, 29, 30,
7042 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7043 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7044 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7045 22, 23, 24, 25, 26, 27, 28, 29, 30,
7046 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7047 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7048
7049 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7050 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7051 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7052 22, 23, 24, 25, 26, 27, 28,
7053 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7054 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7055 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7056 22, 23, 24, 25, 26, 27, 28, 29, 30,
7057 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7058 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7059 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7060 22, 23, 24, 25, 26, 27, 28, 29, 30,
7061 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7062 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7063 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7064 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7065 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7066 22, 23, 24, 25, 26, 27, 28, 29, 30,
7067 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7068 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7069 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7070 22, 23, 24, 25, 26, 27, 28, 29, 30,
7071 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7072 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7073
7074 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7075 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7076 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7077 22, 23, 24, 25, 26, 27, 28, 29,
7078 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7079 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7080 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7081 22, 23, 24, 25, 26, 27, 28, 29, 30,
7082 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7083 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7084 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7085 22, 23, 24, 25, 26, 27, 28, 29, 30,
7086 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7087 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7088 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7089 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7090 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7091 22, 23, 24, 25, 26, 27, 28, 29, 30,
7092 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7093 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7094 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7095 22, 23, 24, 25, 26, 27, 28, 29, 30,
7096 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7097 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7098
7099 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7100 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7101 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7102 22, 23, 24, 25, 26, 27, 28,
7103 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7104 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7105 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7106 22, 23, 24, 25, 26, 27, 28, 29, 30,
7107 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7108 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7109 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7110 22, 23, 24, 25, 26, 27, 28, 29, 30,
7111 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7112 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7113 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7114 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7115 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7116 22, 23, 24, 25, 26, 27, 28, 29, 30,
7117 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7118 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7119 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7120 22, 23, 24, 25, 26, 27, 28, 29, 30,
7121 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7122 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7123
7124static const char kMonthInYear[] = {
7125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7126 0, 0, 0, 0, 0, 0,
7127 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7128 1, 1, 1,
7129 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7130 2, 2, 2, 2, 2, 2,
7131 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7132 3, 3, 3, 3, 3,
7133 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7134 4, 4, 4, 4, 4, 4,
7135 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7136 5, 5, 5, 5, 5,
7137 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7138 6, 6, 6, 6, 6, 6,
7139 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7140 7, 7, 7, 7, 7, 7,
7141 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7142 8, 8, 8, 8, 8,
7143 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7144 9, 9, 9, 9, 9, 9,
7145 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7146 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7147 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7148 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7149
7150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7151 0, 0, 0, 0, 0, 0,
7152 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7153 1, 1, 1,
7154 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7155 2, 2, 2, 2, 2, 2,
7156 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7157 3, 3, 3, 3, 3,
7158 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7159 4, 4, 4, 4, 4, 4,
7160 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7161 5, 5, 5, 5, 5,
7162 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7163 6, 6, 6, 6, 6, 6,
7164 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7165 7, 7, 7, 7, 7, 7,
7166 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7167 8, 8, 8, 8, 8,
7168 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7169 9, 9, 9, 9, 9, 9,
7170 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7171 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7172 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7173 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7174
7175 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7176 0, 0, 0, 0, 0, 0,
7177 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7178 1, 1, 1, 1,
7179 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7180 2, 2, 2, 2, 2, 2,
7181 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7182 3, 3, 3, 3, 3,
7183 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7184 4, 4, 4, 4, 4, 4,
7185 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7186 5, 5, 5, 5, 5,
7187 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7188 6, 6, 6, 6, 6, 6,
7189 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7190 7, 7, 7, 7, 7, 7,
7191 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7192 8, 8, 8, 8, 8,
7193 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7194 9, 9, 9, 9, 9, 9,
7195 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7196 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7197 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7198 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7199
7200 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7201 0, 0, 0, 0, 0, 0,
7202 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7203 1, 1, 1,
7204 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7205 2, 2, 2, 2, 2, 2,
7206 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7207 3, 3, 3, 3, 3,
7208 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7209 4, 4, 4, 4, 4, 4,
7210 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7211 5, 5, 5, 5, 5,
7212 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7213 6, 6, 6, 6, 6, 6,
7214 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7215 7, 7, 7, 7, 7, 7,
7216 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7217 8, 8, 8, 8, 8,
7218 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7219 9, 9, 9, 9, 9, 9,
7220 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7221 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7222 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7223 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7224
7225
7226// This function works for dates from 1970 to 2099.
7227static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007228 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007229#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007230 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007231#endif
7232
7233 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7234 date %= kDaysIn4Years;
7235
7236 month = kMonthInYear[date];
7237 day = kDayInYear[date];
7238
7239 ASSERT(MakeDay(year, month, day) == save_date);
7240}
7241
7242
7243static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007244 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007245#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007246 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007247#endif
7248
7249 date += kDaysOffset;
7250 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7251 date %= kDaysIn400Years;
7252
7253 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7254
7255 date--;
7256 int yd1 = date / kDaysIn100Years;
7257 date %= kDaysIn100Years;
7258 year += 100 * yd1;
7259
7260 date++;
7261 int yd2 = date / kDaysIn4Years;
7262 date %= kDaysIn4Years;
7263 year += 4 * yd2;
7264
7265 date--;
7266 int yd3 = date / 365;
7267 date %= 365;
7268 year += yd3;
7269
7270 bool is_leap = (!yd1 || yd2) && !yd3;
7271
7272 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007273 ASSERT(is_leap || (date >= 0));
7274 ASSERT((date < 365) || (is_leap && (date < 366)));
7275 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7276 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7277 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007278
7279 if (is_leap) {
7280 day = kDayInYear[2*365 + 1 + date];
7281 month = kMonthInYear[2*365 + 1 + date];
7282 } else {
7283 day = kDayInYear[date];
7284 month = kMonthInYear[date];
7285 }
7286
7287 ASSERT(MakeDay(year, month, day) == save_date);
7288}
7289
7290
7291static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007292 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007293 if (date >= 0 && date < 32 * kDaysIn4Years) {
7294 DateYMDFromTimeAfter1970(date, year, month, day);
7295 } else {
7296 DateYMDFromTimeSlow(date, year, month, day);
7297 }
7298}
7299
7300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007301RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007302 NoHandleAllocation ha;
7303 ASSERT(args.length() == 2);
7304
7305 CONVERT_DOUBLE_CHECKED(t, args[0]);
7306 CONVERT_CHECKED(JSArray, res_array, args[1]);
7307
7308 int year, month, day;
7309 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007311 RUNTIME_ASSERT(res_array->elements()->map() ==
7312 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007313 FixedArray* elms = FixedArray::cast(res_array->elements());
7314 RUNTIME_ASSERT(elms->length() == 3);
7315
7316 elms->set(0, Smi::FromInt(year));
7317 elms->set(1, Smi::FromInt(month));
7318 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007319
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007321}
7322
7323
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007324RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007325 NoHandleAllocation ha;
7326 ASSERT(args.length() == 3);
7327
7328 JSFunction* callee = JSFunction::cast(args[0]);
7329 Object** parameters = reinterpret_cast<Object**>(args[1]);
7330 const int length = Smi::cast(args[2])->value();
7331
lrn@chromium.org303ada72010-10-27 09:33:13 +00007332 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 { MaybeObject* maybe_result =
7334 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007335 if (!maybe_result->ToObject(&result)) return maybe_result;
7336 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007337 // Allocate the elements if needed.
7338 if (length > 0) {
7339 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007340 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007341 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007342 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7343 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007344
7345 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007346 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007348 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007349
7350 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007351 for (int i = 0; i < length; i++) {
7352 array->set(i, *--parameters, mode);
7353 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007354 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007355 }
7356 return result;
7357}
7358
7359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007360RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007362 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007363 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007364 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007365 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007367 // Allocate global closures in old space and allocate local closures
7368 // in new space. Additionally pretenure closures that are assigned
7369 // directly to properties.
7370 pretenure = pretenure || (context->global_context() == *context);
7371 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7374 context,
7375 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376 return *result;
7377}
7378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007379
7380static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7381 int* total_argc) {
7382 // Find frame containing arguments passed to the caller.
7383 JavaScriptFrameIterator it;
7384 JavaScriptFrame* frame = it.frame();
7385 List<JSFunction*> functions(2);
7386 frame->GetFunctions(&functions);
7387 if (functions.length() > 1) {
7388 int inlined_frame_index = functions.length() - 1;
7389 JSFunction* inlined_function = functions[inlined_frame_index];
7390 int args_count = inlined_function->shared()->formal_parameter_count();
7391 ScopedVector<SlotRef> args_slots(args_count);
7392 SlotRef::ComputeSlotMappingForArguments(frame,
7393 inlined_frame_index,
7394 &args_slots);
7395
7396 *total_argc = bound_argc + args_count;
7397 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7398 for (int i = 0; i < args_count; i++) {
7399 Handle<Object> val = args_slots[i].GetValue();
7400 param_data[bound_argc + i] = val.location();
7401 }
7402 return param_data;
7403 } else {
7404 it.AdvanceToArgumentsFrame();
7405 frame = it.frame();
7406 int args_count = frame->ComputeParametersCount();
7407
7408 *total_argc = bound_argc + args_count;
7409 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7410 for (int i = 0; i < args_count; i++) {
7411 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7412 param_data[bound_argc + i] = val.location();
7413 }
7414 return param_data;
7415 }
7416}
7417
7418
7419RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007420 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007421 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007422 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007423 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007424
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007425 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007426 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007427 int bound_argc = 0;
7428 if (!args[1]->IsNull()) {
7429 CONVERT_ARG_CHECKED(JSArray, params, 1);
7430 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007431 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007432 bound_argc = Smi::cast(params->length())->value();
7433 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007435 int total_argc = 0;
7436 SmartPointer<Object**> param_data =
7437 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007438 for (int i = 0; i < bound_argc; i++) {
7439 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007440 param_data[i] = val.location();
7441 }
7442
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007443 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007444 Handle<Object> result =
7445 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007446 if (exception) {
7447 return Failure::Exception();
7448 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007449
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007450 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007451 return *result;
7452}
7453
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007455static void TrySettingInlineConstructStub(Isolate* isolate,
7456 Handle<JSFunction> function) {
7457 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007458 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007459 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007460 }
7461 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007462 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007463 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007464 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007465 function->shared()->set_construct_stub(
7466 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007467 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007468 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007469}
7470
7471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007472RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007473 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474 ASSERT(args.length() == 1);
7475
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007476 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007477
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007478 // If the constructor isn't a proper function we throw a type error.
7479 if (!constructor->IsJSFunction()) {
7480 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7481 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007482 isolate->factory()->NewTypeError("not_constructor", arguments);
7483 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007484 }
7485
7486 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007487
7488 // If function should not have prototype, construction is not allowed. In this
7489 // case generated code bailouts here, since function has no initial_map.
7490 if (!function->should_have_prototype()) {
7491 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7492 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007493 isolate->factory()->NewTypeError("not_constructor", arguments);
7494 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007495 }
7496
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007497#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007498 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007499 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007500 if (debug->StepInActive()) {
7501 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007502 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007503#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007504
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007505 if (function->has_initial_map()) {
7506 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007507 // The 'Function' function ignores the receiver object when
7508 // called using 'new' and creates a new JSFunction object that
7509 // is returned. The receiver object is only used for error
7510 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007512 // allocate JSFunctions since it does not properly initialize
7513 // the shared part of the function. Since the receiver is
7514 // ignored anyway, we use the global object as the receiver
7515 // instead of a new JSFunction object. This way, errors are
7516 // reported the same way whether or not 'Function' is called
7517 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007518 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007519 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520 }
7521
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007522 // The function should be compiled for the optimization hints to be
7523 // available. We cannot use EnsureCompiled because that forces a
7524 // compilation through the shared function info which makes it
7525 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007526 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007527 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007528
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007529 if (!function->has_initial_map() &&
7530 shared->IsInobjectSlackTrackingInProgress()) {
7531 // The tracking is already in progress for another function. We can only
7532 // track one initial_map at a time, so we force the completion before the
7533 // function is called as a constructor for the first time.
7534 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007535 }
7536
7537 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7539 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007540 // Delay setting the stub if inobject slack tracking is in progress.
7541 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007542 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007543 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007544
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007545 isolate->counters()->constructed_objects()->Increment();
7546 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007547
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007548 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007549}
7550
7551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007552RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007553 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007554 ASSERT(args.length() == 1);
7555
7556 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7557 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007558 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007560 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007561}
7562
7563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007564RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007566 ASSERT(args.length() == 1);
7567
7568 Handle<JSFunction> function = args.at<JSFunction>(0);
7569#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007570 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007571 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007572 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007573 PrintF("]\n");
7574 }
7575#endif
7576
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007577 // Compile the target function. Here we compile using CompileLazyInLoop in
7578 // order to get the optimized version. This helps code like delta-blue
7579 // that calls performance-critical routines through constructors. A
7580 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7581 // direct call. Since the in-loop tracking takes place through CallICs
7582 // this means that things called through constructors are never known to
7583 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007584 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007585 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007586 return Failure::Exception();
7587 }
7588
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007589 // All done. Return the compiled code.
7590 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007591 return function->code();
7592}
7593
7594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007595RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007596 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007597 ASSERT(args.length() == 1);
7598 Handle<JSFunction> function = args.at<JSFunction>(0);
7599 // If the function is not optimizable or debugger is active continue using the
7600 // code from the full compiler.
7601 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007602 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007603 if (FLAG_trace_opt) {
7604 PrintF("[failed to optimize ");
7605 function->PrintName();
7606 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7607 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007608 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007609 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007610 function->ReplaceCode(function->shared()->code());
7611 return function->code();
7612 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007613 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007614 return function->code();
7615 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007616 if (FLAG_trace_opt) {
7617 PrintF("[failed to optimize ");
7618 function->PrintName();
7619 PrintF(": optimized compilation failed]\n");
7620 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007621 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007622 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007623}
7624
7625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007626RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007627 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007628 ASSERT(args.length() == 1);
7629 RUNTIME_ASSERT(args[0]->IsSmi());
7630 Deoptimizer::BailoutType type =
7631 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007632 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7633 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007634 int frames = deoptimizer->output_count();
7635
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007636 deoptimizer->MaterializeHeapNumbers();
7637 delete deoptimizer;
7638
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007639 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007640 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007641 for (int i = 0; i < frames - 1; i++) it.Advance();
7642 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007643
7644 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007645 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007646 Handle<Object> arguments;
7647 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007648 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007649 if (arguments.is_null()) {
7650 // FunctionGetArguments can't throw an exception, so cast away the
7651 // doubt with an assert.
7652 arguments = Handle<Object>(
7653 Accessors::FunctionGetArguments(*function,
7654 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007655 ASSERT(*arguments != isolate->heap()->null_value());
7656 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007657 }
7658 frame->SetExpression(i, *arguments);
7659 }
7660 }
7661
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007662 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007663 if (type == Deoptimizer::EAGER) {
7664 RUNTIME_ASSERT(function->IsOptimized());
7665 } else {
7666 RUNTIME_ASSERT(!function->IsOptimized());
7667 }
7668
7669 // Avoid doing too much work when running with --always-opt and keep
7670 // the optimized code around.
7671 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007672 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007673 }
7674
7675 // Count the number of optimized activations of the function.
7676 int activations = 0;
7677 while (!it.done()) {
7678 JavaScriptFrame* frame = it.frame();
7679 if (frame->is_optimized() && frame->function() == *function) {
7680 activations++;
7681 }
7682 it.Advance();
7683 }
7684
7685 // TODO(kasperl): For now, we cannot support removing the optimized
7686 // code when we have recursive invocations of the same function.
7687 if (activations == 0) {
7688 if (FLAG_trace_deopt) {
7689 PrintF("[removing optimized code for: ");
7690 function->PrintName();
7691 PrintF("]\n");
7692 }
7693 function->ReplaceCode(function->shared()->code());
7694 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007695 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007696}
7697
7698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007699RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007700 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007701 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007702 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007703}
7704
7705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007706RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007707 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007708 ASSERT(args.length() == 1);
7709 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007710 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007711
7712 Deoptimizer::DeoptimizeFunction(*function);
7713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007714 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007715}
7716
7717
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007718RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7719 HandleScope scope(isolate);
7720 ASSERT(args.length() == 1);
7721 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7722 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7723 function->MarkForLazyRecompilation();
7724 return isolate->heap()->undefined_value();
7725}
7726
7727
lrn@chromium.org1c092762011-05-09 09:42:16 +00007728RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7729 HandleScope scope(isolate);
7730 ASSERT(args.length() == 1);
7731 if (!V8::UseCrankshaft()) {
7732 return Smi::FromInt(4); // 4 == "never".
7733 }
7734 if (FLAG_always_opt) {
7735 return Smi::FromInt(3); // 3 == "always".
7736 }
7737 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7738 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7739 : Smi::FromInt(2); // 2 == "no".
7740}
7741
7742
7743RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7744 HandleScope scope(isolate);
7745 ASSERT(args.length() == 1);
7746 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7747 return Smi::FromInt(function->shared()->opt_count());
7748}
7749
7750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007751RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007752 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007753 ASSERT(args.length() == 1);
7754 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7755
7756 // We're not prepared to handle a function with arguments object.
7757 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7758
7759 // We have hit a back edge in an unoptimized frame for a function that was
7760 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007761 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007762 // Keep track of whether we've succeeded in optimizing.
7763 bool succeeded = unoptimized->optimizable();
7764 if (succeeded) {
7765 // If we are trying to do OSR when there are already optimized
7766 // activations of the function, it means (a) the function is directly or
7767 // indirectly recursive and (b) an optimized invocation has been
7768 // deoptimized so that we are currently in an unoptimized activation.
7769 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007770 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007771 while (succeeded && !it.done()) {
7772 JavaScriptFrame* frame = it.frame();
7773 succeeded = !frame->is_optimized() || frame->function() != *function;
7774 it.Advance();
7775 }
7776 }
7777
7778 int ast_id = AstNode::kNoNumber;
7779 if (succeeded) {
7780 // The top JS function is this one, the PC is somewhere in the
7781 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007782 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007783 JavaScriptFrame* frame = it.frame();
7784 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007785 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007786 ASSERT(unoptimized->contains(frame->pc()));
7787
7788 // Use linear search of the unoptimized code's stack check table to find
7789 // the AST id matching the PC.
7790 Address start = unoptimized->instruction_start();
7791 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007792 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007793 uint32_t table_length = Memory::uint32_at(table_cursor);
7794 table_cursor += kIntSize;
7795 for (unsigned i = 0; i < table_length; ++i) {
7796 // Table entries are (AST id, pc offset) pairs.
7797 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7798 if (pc_offset == target_pc_offset) {
7799 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7800 break;
7801 }
7802 table_cursor += 2 * kIntSize;
7803 }
7804 ASSERT(ast_id != AstNode::kNoNumber);
7805 if (FLAG_trace_osr) {
7806 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7807 function->PrintName();
7808 PrintF("]\n");
7809 }
7810
7811 // Try to compile the optimized code. A true return value from
7812 // CompileOptimized means that compilation succeeded, not necessarily
7813 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007814 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7815 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007816 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7817 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007818 if (data->OsrPcOffset()->value() >= 0) {
7819 if (FLAG_trace_osr) {
7820 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007821 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007822 }
7823 ASSERT(data->OsrAstId()->value() == ast_id);
7824 } else {
7825 // We may never generate the desired OSR entry if we emit an
7826 // early deoptimize.
7827 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007828 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007829 } else {
7830 succeeded = false;
7831 }
7832 }
7833
7834 // Revert to the original stack checks in the original unoptimized code.
7835 if (FLAG_trace_osr) {
7836 PrintF("[restoring original stack checks in ");
7837 function->PrintName();
7838 PrintF("]\n");
7839 }
7840 StackCheckStub check_stub;
7841 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007842 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007843 Deoptimizer::RevertStackCheckCode(*unoptimized,
7844 *check_code,
7845 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007846
7847 // Allow OSR only at nesting level zero again.
7848 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7849
7850 // If the optimization attempt succeeded, return the AST id tagged as a
7851 // smi. This tells the builtin that we need to translate the unoptimized
7852 // frame to an optimized one.
7853 if (succeeded) {
7854 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7855 return Smi::FromInt(ast_id);
7856 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007857 if (function->IsMarkedForLazyRecompilation()) {
7858 function->ReplaceCode(function->shared()->code());
7859 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007860 return Smi::FromInt(-1);
7861 }
7862}
7863
7864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007865RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007866 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007867 ASSERT(args.length() == 1);
7868 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7869 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7870}
7871
7872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007873RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007874 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007875 ASSERT(args.length() == 1);
7876 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7877 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7878}
7879
7880
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007881RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007882 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007883 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007884
kasper.lund7276f142008-07-30 08:49:36 +00007885 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007886 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007887 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007888 { MaybeObject* maybe_result =
7889 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007890 if (!maybe_result->ToObject(&result)) return maybe_result;
7891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007894
kasper.lund7276f142008-07-30 08:49:36 +00007895 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007896}
7897
lrn@chromium.org303ada72010-10-27 09:33:13 +00007898
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007899MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7900 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007901 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007902 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007903 Object* js_object = object;
7904 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007905 MaybeObject* maybe_js_object = js_object->ToObject();
7906 if (!maybe_js_object->ToObject(&js_object)) {
7907 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7908 return maybe_js_object;
7909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007910 HandleScope scope(isolate);
7911 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007912 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007913 isolate->factory()->NewTypeError("with_expression",
7914 HandleVector(&handle, 1));
7915 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007916 }
7917 }
7918
lrn@chromium.org303ada72010-10-27 09:33:13 +00007919 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007920 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7921 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007922 if (!maybe_result->ToObject(&result)) return maybe_result;
7923 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007924
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007925 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007926 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927
kasper.lund7276f142008-07-30 08:49:36 +00007928 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007929}
7930
7931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007932RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007933 NoHandleAllocation ha;
7934 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007935 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007936}
7937
7938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007939RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007940 NoHandleAllocation ha;
7941 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007942 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007943}
7944
7945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007946RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007947 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007948 ASSERT(args.length() == 2);
7949
7950 CONVERT_ARG_CHECKED(Context, context, 0);
7951 CONVERT_ARG_CHECKED(String, name, 1);
7952
7953 int index;
7954 PropertyAttributes attributes;
7955 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007956 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007957
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007958 // If the slot was not found the result is true.
7959 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007960 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961 }
7962
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007963 // If the slot was found in a context, it should be DONT_DELETE.
7964 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007965 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007966 }
7967
7968 // The slot was found in a JSObject, either a context extension object,
7969 // the global object, or an arguments object. Try to delete it
7970 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7971 // which allows deleting all parameters in functions that mention
7972 // 'arguments', we do this even for the case of slots found on an
7973 // arguments object. The slot was found on an arguments object if the
7974 // index is non-negative.
7975 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7976 if (index >= 0) {
7977 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7978 } else {
7979 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7980 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007981}
7982
7983
ager@chromium.orga1645e22009-09-09 19:27:10 +00007984// A mechanism to return a pair of Object pointers in registers (if possible).
7985// How this is achieved is calling convention-dependent.
7986// All currently supported x86 compiles uses calling conventions that are cdecl
7987// variants where a 64-bit value is returned in two 32-bit registers
7988// (edx:eax on ia32, r1:r0 on ARM).
7989// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7990// In Win64 calling convention, a struct of two pointers is returned in memory,
7991// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007992#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007993struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007994 MaybeObject* x;
7995 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007996};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007997
lrn@chromium.org303ada72010-10-27 09:33:13 +00007998static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007999 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008000 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8001 // In Win64 they are assigned to a hidden first argument.
8002 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008003}
8004#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008005typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008006static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008007 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008008 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008009}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008010#endif
8011
8012
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008013static inline MaybeObject* Unhole(Heap* heap,
8014 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008015 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008016 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8017 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008018 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008019}
8020
8021
danno@chromium.org40cb8782011-05-25 07:58:50 +00008022static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8023 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008024 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008025 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008026 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008027 JSFunction* context_extension_function =
8028 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008029 // If the holder isn't a context extension object, we just return it
8030 // as the receiver. This allows arguments objects to be used as
8031 // receivers, but only if they are put in the context scope chain
8032 // explicitly via a with-statement.
8033 Object* constructor = holder->map()->constructor();
8034 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008035 // Fall back to using the global object as the implicit receiver if
8036 // the property turns out to be a local variable allocated in a
8037 // context extension object - introduced via eval. Implicit global
8038 // receivers are indicated with the hole value.
8039 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008040}
8041
8042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008043static ObjectPair LoadContextSlotHelper(Arguments args,
8044 Isolate* isolate,
8045 bool throw_error) {
8046 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008047 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008049 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008050 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008051 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008052 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008053 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008054
8055 int index;
8056 PropertyAttributes attributes;
8057 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008058 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008060 // If the index is non-negative, the slot has been found in a local
8061 // variable or a parameter. Read it from the context object or the
8062 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008063 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008064 // If the "property" we were looking for is a local variable or an
8065 // argument in a context, the receiver is the global object; see
8066 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008067 //
8068 // Use the hole as the receiver to signal that the receiver is
8069 // implicit and that the global receiver should be used.
8070 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008071 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008072 ? Context::cast(*holder)->get(index)
8073 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008074 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008075 }
8076
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008077 // If the holder is found, we read the property from it.
8078 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008079 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008080 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008081 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008082 if (object->IsGlobalObject()) {
8083 receiver = GlobalObject::cast(object)->global_receiver();
8084 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008085 // Use the hole as the receiver to signal that the receiver is
8086 // implicit and that the global receiver should be used.
8087 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008088 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008089 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008090 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008091
8092 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008093 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008094
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008095 // No need to unhole the value here. This is taken care of by the
8096 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008097 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008098 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008099 }
8100
8101 if (throw_error) {
8102 // The property doesn't exist - throw exception.
8103 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008104 isolate->factory()->NewReferenceError("not_defined",
8105 HandleVector(&name, 1));
8106 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008107 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008108 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008109 return MakePair(isolate->heap()->undefined_value(),
8110 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008111 }
8112}
8113
8114
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008115RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008116 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008117}
8118
8119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008120RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008121 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122}
8123
8124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008125RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008126 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008127 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008129 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008130 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008131 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008132 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
8133 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8134 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008135 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008136
8137 int index;
8138 PropertyAttributes attributes;
8139 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008140 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008141
8142 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008143 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008144 // Ignore if read_only variable.
8145 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008146 // Context is a fixed array and set cannot fail.
8147 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008148 } else if (strict_mode == kStrictMode) {
8149 // Setting read only property in strict mode.
8150 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008151 isolate->factory()->NewTypeError("strict_cannot_assign",
8152 HandleVector(&name, 1));
8153 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008154 }
8155 } else {
8156 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008157 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008158 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008159 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008161 return Failure::Exception();
8162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008163 }
8164 return *value;
8165 }
8166
8167 // Slow case: The property is not in a FixedArray context.
8168 // It is either in an JSObject extension context or it was not found.
8169 Handle<JSObject> context_ext;
8170
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008171 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008172 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008173 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008174 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008175 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008176 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008177
8178 if (strict_mode == kStrictMode) {
8179 // Throw in strict mode (assignment to undefined variable).
8180 Handle<Object> error =
8181 isolate->factory()->NewReferenceError(
8182 "not_defined", HandleVector(&name, 1));
8183 return isolate->Throw(*error);
8184 }
8185 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008186 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008187 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008188 }
8189
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008190 // Set the property, but ignore if read_only variable on the context
8191 // extension object itself.
8192 if ((attributes & READ_ONLY) == 0 ||
8193 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008194 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008195 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008196 SetProperty(context_ext, name, value, NONE, strict_mode));
8197 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008198 // Setting read only property in strict mode.
8199 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200 isolate->factory()->NewTypeError(
8201 "strict_cannot_assign", HandleVector(&name, 1));
8202 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203 }
8204 return *value;
8205}
8206
8207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008208RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008209 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008210 ASSERT(args.length() == 1);
8211
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008212 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008213}
8214
8215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008216RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008217 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008218 ASSERT(args.length() == 1);
8219
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008220 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008221}
8222
8223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008224RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008225 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008226 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008227}
8228
8229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008230RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008231 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232 ASSERT(args.length() == 1);
8233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008234 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008235 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008236 isolate->factory()->NewReferenceError("not_defined",
8237 HandleVector(&name, 1));
8238 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008239}
8240
8241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008242RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008243 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244
8245 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 if (isolate->stack_guard()->IsStackOverflow()) {
8247 NoHandleAllocation na;
8248 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008249 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008251 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008252}
8253
8254
8255// NOTE: These PrintXXX functions are defined for all builds (not just
8256// DEBUG builds) because we may want to be able to trace function
8257// calls in all modes.
8258static void PrintString(String* str) {
8259 // not uncommon to have empty strings
8260 if (str->length() > 0) {
8261 SmartPointer<char> s =
8262 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8263 PrintF("%s", *s);
8264 }
8265}
8266
8267
8268static void PrintObject(Object* obj) {
8269 if (obj->IsSmi()) {
8270 PrintF("%d", Smi::cast(obj)->value());
8271 } else if (obj->IsString() || obj->IsSymbol()) {
8272 PrintString(String::cast(obj));
8273 } else if (obj->IsNumber()) {
8274 PrintF("%g", obj->Number());
8275 } else if (obj->IsFailure()) {
8276 PrintF("<failure>");
8277 } else if (obj->IsUndefined()) {
8278 PrintF("<undefined>");
8279 } else if (obj->IsNull()) {
8280 PrintF("<null>");
8281 } else if (obj->IsTrue()) {
8282 PrintF("<true>");
8283 } else if (obj->IsFalse()) {
8284 PrintF("<false>");
8285 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008286 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008287 }
8288}
8289
8290
8291static int StackSize() {
8292 int n = 0;
8293 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8294 return n;
8295}
8296
8297
8298static void PrintTransition(Object* result) {
8299 // indentation
8300 { const int nmax = 80;
8301 int n = StackSize();
8302 if (n <= nmax)
8303 PrintF("%4d:%*s", n, n, "");
8304 else
8305 PrintF("%4d:%*s", n, nmax, "...");
8306 }
8307
8308 if (result == NULL) {
8309 // constructor calls
8310 JavaScriptFrameIterator it;
8311 JavaScriptFrame* frame = it.frame();
8312 if (frame->IsConstructor()) PrintF("new ");
8313 // function name
8314 Object* fun = frame->function();
8315 if (fun->IsJSFunction()) {
8316 PrintObject(JSFunction::cast(fun)->shared()->name());
8317 } else {
8318 PrintObject(fun);
8319 }
8320 // function arguments
8321 // (we are intentionally only printing the actually
8322 // supplied parameters, not all parameters required)
8323 PrintF("(this=");
8324 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008325 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326 for (int i = 0; i < length; i++) {
8327 PrintF(", ");
8328 PrintObject(frame->GetParameter(i));
8329 }
8330 PrintF(") {\n");
8331
8332 } else {
8333 // function result
8334 PrintF("} -> ");
8335 PrintObject(result);
8336 PrintF("\n");
8337 }
8338}
8339
8340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008341RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008342 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008343 NoHandleAllocation ha;
8344 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008345 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008346}
8347
8348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008349RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008350 NoHandleAllocation ha;
8351 PrintTransition(args[0]);
8352 return args[0]; // return TOS
8353}
8354
8355
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008356RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008357 NoHandleAllocation ha;
8358 ASSERT(args.length() == 1);
8359
8360#ifdef DEBUG
8361 if (args[0]->IsString()) {
8362 // If we have a string, assume it's a code "marker"
8363 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008364 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008365 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008366 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8367 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008368 } else {
8369 PrintF("DebugPrint: ");
8370 }
8371 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008372 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008373 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008374 HeapObject::cast(args[0])->map()->Print();
8375 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008376#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008377 // ShortPrint is available in release mode. Print is not.
8378 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008379#endif
8380 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008381 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008382
8383 return args[0]; // return TOS
8384}
8385
8386
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008387RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008388 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008389 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008390 isolate->PrintStack();
8391 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008392}
8393
8394
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008395RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008396 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008397 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008398
8399 // According to ECMA-262, section 15.9.1, page 117, the precision of
8400 // the number in a Date object representing a particular instant in
8401 // time is milliseconds. Therefore, we floor the result of getting
8402 // the OS time.
8403 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008404 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008405}
8406
8407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008408RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008409 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008410 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008411
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008412 CONVERT_ARG_CHECKED(String, str, 0);
8413 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008415 CONVERT_ARG_CHECKED(JSArray, output, 1);
8416 RUNTIME_ASSERT(output->HasFastElements());
8417
8418 AssertNoAllocation no_allocation;
8419
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008420 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008421 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8422 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008423 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008424 result = DateParser::Parse(str->ToAsciiVector(),
8425 output_array,
8426 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008427 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008428 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008429 result = DateParser::Parse(str->ToUC16Vector(),
8430 output_array,
8431 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008432 }
8433
8434 if (result) {
8435 return *output;
8436 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008437 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008438 }
8439}
8440
8441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008442RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008443 NoHandleAllocation ha;
8444 ASSERT(args.length() == 1);
8445
8446 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008447 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008448 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008449}
8450
8451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008452RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008453 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008454 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008455
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008456 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008457}
8458
8459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008460RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008461 NoHandleAllocation ha;
8462 ASSERT(args.length() == 1);
8463
8464 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008465 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008466}
8467
8468
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008469RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008470 ASSERT(args.length() == 1);
8471 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008472 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008473 return JSGlobalObject::cast(global)->global_receiver();
8474}
8475
8476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008477RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008478 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008479 ASSERT_EQ(1, args.length());
8480 CONVERT_ARG_CHECKED(String, source, 0);
8481
8482 Handle<Object> result = JsonParser::Parse(source);
8483 if (result.is_null()) {
8484 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008485 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008486 return Failure::Exception();
8487 }
8488 return *result;
8489}
8490
8491
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008492bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8493 Handle<Context> context) {
8494 if (context->allow_code_gen_from_strings()->IsFalse()) {
8495 // Check with callback if set.
8496 AllowCodeGenerationFromStringsCallback callback =
8497 isolate->allow_code_gen_callback();
8498 if (callback == NULL) {
8499 // No callback set and code generation disallowed.
8500 return false;
8501 } else {
8502 // Callback set. Let it decide if code generation is allowed.
8503 VMState state(isolate, EXTERNAL);
8504 return callback(v8::Utils::ToLocal(context));
8505 }
8506 }
8507 return true;
8508}
8509
8510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008511RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008512 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008513 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008514 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008515
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008516 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008517 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008518
8519 // Check if global context allows code generation from
8520 // strings. Throw an exception if it doesn't.
8521 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8522 return isolate->Throw(*isolate->factory()->NewError(
8523 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8524 }
8525
8526 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008527 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8528 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008529 true,
8530 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008531 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008532 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008533 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8534 context,
8535 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008536 return *fun;
8537}
8538
8539
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008540static ObjectPair CompileGlobalEval(Isolate* isolate,
8541 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008542 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008543 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008544 Handle<Context> context = Handle<Context>(isolate->context());
8545 Handle<Context> global_context = Handle<Context>(context->global_context());
8546
8547 // Check if global context allows code generation from
8548 // strings. Throw an exception if it doesn't.
8549 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8550 isolate->Throw(*isolate->factory()->NewError(
8551 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8552 return MakePair(Failure::Exception(), NULL);
8553 }
8554
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008555 // Deal with a normal eval call with a string argument. Compile it
8556 // and return the compiled function bound in the local context.
8557 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8558 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008559 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008560 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008561 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008562 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008563 Handle<JSFunction> compiled =
8564 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008565 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008566 return MakePair(*compiled, *receiver);
8567}
8568
8569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008570RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008571 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008572
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008573 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008574 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008575 Handle<Object> receiver; // Will be overwritten.
8576
8577 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008578 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008579#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008580 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008581 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008582 StackFrameLocator locator;
8583 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008584 ASSERT(Context::cast(frame->context()) == *context);
8585#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008586
8587 // Find where the 'eval' symbol is bound. It is unaliased only if
8588 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008589 int index = -1;
8590 PropertyAttributes attributes = ABSENT;
8591 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008592 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8593 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008594 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008595 // Stop search when eval is found or when the global context is
8596 // reached.
8597 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008598 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008599 context = Handle<Context>(Context::cast(context->closure()->context()),
8600 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008601 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008602 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008603 }
8604 }
8605
iposva@chromium.org245aa852009-02-10 00:49:54 +00008606 // If eval could not be resolved, it has been deleted and we need to
8607 // throw a reference error.
8608 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008609 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008610 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008611 isolate->factory()->NewReferenceError("not_defined",
8612 HandleVector(&name, 1));
8613 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008614 }
8615
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008616 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008617 // 'eval' is not bound in the global context. Just call the function
8618 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008619 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008620 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008621 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008622 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008623 }
8624
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008625 // 'eval' is bound in the global context, but it may have been overwritten.
8626 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008627 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008628 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008629 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008630 }
8631
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008632 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008633 return CompileGlobalEval(isolate,
8634 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008635 args.at<Object>(2),
8636 static_cast<StrictModeFlag>(
8637 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008638}
8639
8640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008641RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008642 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008643
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008644 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008645 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008646
8647 // 'eval' is bound in the global context, but it may have been overwritten.
8648 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008649 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008650 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008651 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008652 }
8653
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008654 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008655 return CompileGlobalEval(isolate,
8656 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008657 args.at<Object>(2),
8658 static_cast<StrictModeFlag>(
8659 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008660}
8661
8662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008663RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008664 // This utility adjusts the property attributes for newly created Function
8665 // object ("new Function(...)") by changing the map.
8666 // All it does is changing the prototype property to enumerable
8667 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008668 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008669 ASSERT(args.length() == 1);
8670 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008671
8672 Handle<Map> map = func->shared()->strict_mode()
8673 ? isolate->strict_mode_function_instance_map()
8674 : isolate->function_instance_map();
8675
8676 ASSERT(func->map()->instance_type() == map->instance_type());
8677 ASSERT(func->map()->instance_size() == map->instance_size());
8678 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008679 return *func;
8680}
8681
8682
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008683RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008684 // Allocate a block of memory in NewSpace (filled with a filler).
8685 // Use as fallback for allocation in generated code when NewSpace
8686 // is full.
8687 ASSERT(args.length() == 1);
8688 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8689 int size = size_smi->value();
8690 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8691 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008692 Heap* heap = isolate->heap();
8693 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008694 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008695 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008696 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008697 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008698 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008699 }
8700 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008701 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008702}
8703
8704
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008705// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008706// array. Returns true if the element was pushed on the stack and
8707// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008708RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008709 ASSERT(args.length() == 2);
8710 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008711 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008712 RUNTIME_ASSERT(array->HasFastElements());
8713 int length = Smi::cast(array->length())->value();
8714 FixedArray* elements = FixedArray::cast(array->elements());
8715 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008716 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008717 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008718 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008719 // Strict not needed. Used for cycle detection in Array join implementation.
8720 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8721 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008722 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8723 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008724 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008725}
8726
8727
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008728/**
8729 * A simple visitor visits every element of Array's.
8730 * The backend storage can be a fixed array for fast elements case,
8731 * or a dictionary for sparse array. Since Dictionary is a subtype
8732 * of FixedArray, the class can be used by both fast and slow cases.
8733 * The second parameter of the constructor, fast_elements, specifies
8734 * whether the storage is a FixedArray or Dictionary.
8735 *
8736 * An index limit is used to deal with the situation that a result array
8737 * length overflows 32-bit non-negative integer.
8738 */
8739class ArrayConcatVisitor {
8740 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008741 ArrayConcatVisitor(Isolate* isolate,
8742 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008743 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008744 isolate_(isolate),
8745 storage_(Handle<FixedArray>::cast(
8746 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008747 index_offset_(0u),
8748 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008749
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008750 ~ArrayConcatVisitor() {
8751 clear_storage();
8752 }
8753
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008754 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008755 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008756 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008757
8758 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008759 if (index < static_cast<uint32_t>(storage_->length())) {
8760 storage_->set(index, *elm);
8761 return;
8762 }
8763 // Our initial estimate of length was foiled, possibly by
8764 // getters on the arrays increasing the length of later arrays
8765 // during iteration.
8766 // This shouldn't happen in anything but pathological cases.
8767 SetDictionaryMode(index);
8768 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008769 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008770 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008771 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008772 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008773 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008774 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008775 // Dictionary needed to grow.
8776 clear_storage();
8777 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008778 }
8779}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008780
8781 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008782 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8783 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008784 } else {
8785 index_offset_ += delta;
8786 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008787 }
8788
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008789 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008790 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008791 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008792 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008793 Handle<Map> map;
8794 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008795 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008796 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008797 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008798 }
8799 array->set_map(*map);
8800 array->set_length(*length);
8801 array->set_elements(*storage_);
8802 return array;
8803 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008804
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008805 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008806 // Convert storage to dictionary mode.
8807 void SetDictionaryMode(uint32_t index) {
8808 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008809 Handle<FixedArray> current_storage(*storage_);
8810 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008811 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008812 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8813 for (uint32_t i = 0; i < current_length; i++) {
8814 HandleScope loop_scope;
8815 Handle<Object> element(current_storage->get(i));
8816 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008817 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008818 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008819 if (!new_storage.is_identical_to(slow_storage)) {
8820 slow_storage = loop_scope.CloseAndEscape(new_storage);
8821 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008822 }
8823 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008824 clear_storage();
8825 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008826 fast_elements_ = false;
8827 }
8828
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008829 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008830 isolate_->global_handles()->Destroy(
8831 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008832 }
8833
8834 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 storage_ = Handle<FixedArray>::cast(
8836 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008837 }
8838
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008839 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008840 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008841 // Index after last seen index. Always less than or equal to
8842 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008843 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008844 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008845};
8846
8847
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008848static uint32_t EstimateElementCount(Handle<JSArray> array) {
8849 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8850 int element_count = 0;
8851 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008852 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008853 // Fast elements can't have lengths that are not representable by
8854 // a 32-bit signed integer.
8855 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8856 int fast_length = static_cast<int>(length);
8857 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8858 for (int i = 0; i < fast_length; i++) {
8859 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008860 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008861 break;
8862 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008863 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008864 Handle<NumberDictionary> dictionary(
8865 NumberDictionary::cast(array->elements()));
8866 int capacity = dictionary->Capacity();
8867 for (int i = 0; i < capacity; i++) {
8868 Handle<Object> key(dictionary->KeyAt(i));
8869 if (dictionary->IsKey(*key)) {
8870 element_count++;
8871 }
8872 }
8873 break;
8874 }
8875 default:
8876 // External arrays are always dense.
8877 return length;
8878 }
8879 // As an estimate, we assume that the prototype doesn't contain any
8880 // inherited elements.
8881 return element_count;
8882}
8883
8884
8885
8886template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008887static void IterateExternalArrayElements(Isolate* isolate,
8888 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008889 bool elements_are_ints,
8890 bool elements_are_guaranteed_smis,
8891 ArrayConcatVisitor* visitor) {
8892 Handle<ExternalArrayClass> array(
8893 ExternalArrayClass::cast(receiver->elements()));
8894 uint32_t len = static_cast<uint32_t>(array->length());
8895
8896 ASSERT(visitor != NULL);
8897 if (elements_are_ints) {
8898 if (elements_are_guaranteed_smis) {
8899 for (uint32_t j = 0; j < len; j++) {
8900 HandleScope loop_scope;
8901 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8902 visitor->visit(j, e);
8903 }
8904 } else {
8905 for (uint32_t j = 0; j < len; j++) {
8906 HandleScope loop_scope;
8907 int64_t val = static_cast<int64_t>(array->get(j));
8908 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8909 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8910 visitor->visit(j, e);
8911 } else {
8912 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008913 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008914 visitor->visit(j, e);
8915 }
8916 }
8917 }
8918 } else {
8919 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008920 HandleScope loop_scope(isolate);
8921 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008922 visitor->visit(j, e);
8923 }
8924 }
8925}
8926
8927
8928// Used for sorting indices in a List<uint32_t>.
8929static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8930 uint32_t a = *ap;
8931 uint32_t b = *bp;
8932 return (a == b) ? 0 : (a < b) ? -1 : 1;
8933}
8934
8935
8936static void CollectElementIndices(Handle<JSObject> object,
8937 uint32_t range,
8938 List<uint32_t>* indices) {
8939 JSObject::ElementsKind kind = object->GetElementsKind();
8940 switch (kind) {
8941 case JSObject::FAST_ELEMENTS: {
8942 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8943 uint32_t length = static_cast<uint32_t>(elements->length());
8944 if (range < length) length = range;
8945 for (uint32_t i = 0; i < length; i++) {
8946 if (!elements->get(i)->IsTheHole()) {
8947 indices->Add(i);
8948 }
8949 }
8950 break;
8951 }
8952 case JSObject::DICTIONARY_ELEMENTS: {
8953 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008954 uint32_t capacity = dict->Capacity();
8955 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008956 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008957 Handle<Object> k(dict->KeyAt(j));
8958 if (dict->IsKey(*k)) {
8959 ASSERT(k->IsNumber());
8960 uint32_t index = static_cast<uint32_t>(k->Number());
8961 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008962 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008963 }
8964 }
8965 }
8966 break;
8967 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008968 default: {
8969 int dense_elements_length;
8970 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008971 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008972 dense_elements_length =
8973 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008974 break;
8975 }
8976 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008977 dense_elements_length =
8978 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008979 break;
8980 }
8981 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008982 dense_elements_length =
8983 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008984 break;
8985 }
8986 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008987 dense_elements_length =
8988 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008989 break;
8990 }
8991 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008992 dense_elements_length =
8993 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008994 break;
8995 }
8996 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008997 dense_elements_length =
8998 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008999 break;
9000 }
9001 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009002 dense_elements_length =
9003 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009004 break;
9005 }
9006 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009007 dense_elements_length =
9008 ExternalFloatArray::cast(object->elements())->length();
9009 break;
9010 }
9011 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9012 dense_elements_length =
9013 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009014 break;
9015 }
9016 default:
9017 UNREACHABLE();
9018 dense_elements_length = 0;
9019 break;
9020 }
9021 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9022 if (range <= length) {
9023 length = range;
9024 // We will add all indices, so we might as well clear it first
9025 // and avoid duplicates.
9026 indices->Clear();
9027 }
9028 for (uint32_t i = 0; i < length; i++) {
9029 indices->Add(i);
9030 }
9031 if (length == range) return; // All indices accounted for already.
9032 break;
9033 }
9034 }
9035
9036 Handle<Object> prototype(object->GetPrototype());
9037 if (prototype->IsJSObject()) {
9038 // The prototype will usually have no inherited element indices,
9039 // but we have to check.
9040 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9041 }
9042}
9043
9044
9045/**
9046 * A helper function that visits elements of a JSArray in numerical
9047 * order.
9048 *
9049 * The visitor argument called for each existing element in the array
9050 * with the element index and the element's value.
9051 * Afterwards it increments the base-index of the visitor by the array
9052 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009053 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009054 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009055static bool IterateElements(Isolate* isolate,
9056 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009057 ArrayConcatVisitor* visitor) {
9058 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9059 switch (receiver->GetElementsKind()) {
9060 case JSObject::FAST_ELEMENTS: {
9061 // Run through the elements FixedArray and use HasElement and GetElement
9062 // to check the prototype for missing elements.
9063 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9064 int fast_length = static_cast<int>(length);
9065 ASSERT(fast_length <= elements->length());
9066 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009067 HandleScope loop_scope(isolate);
9068 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009069 if (!element_value->IsTheHole()) {
9070 visitor->visit(j, element_value);
9071 } else if (receiver->HasElement(j)) {
9072 // Call GetElement on receiver, not its prototype, or getters won't
9073 // have the correct receiver.
9074 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009075 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009076 visitor->visit(j, element_value);
9077 }
9078 }
9079 break;
9080 }
9081 case JSObject::DICTIONARY_ELEMENTS: {
9082 Handle<NumberDictionary> dict(receiver->element_dictionary());
9083 List<uint32_t> indices(dict->Capacity() / 2);
9084 // Collect all indices in the object and the prototypes less
9085 // than length. This might introduce duplicates in the indices list.
9086 CollectElementIndices(receiver, length, &indices);
9087 indices.Sort(&compareUInt32);
9088 int j = 0;
9089 int n = indices.length();
9090 while (j < n) {
9091 HandleScope loop_scope;
9092 uint32_t index = indices[j];
9093 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009094 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009095 visitor->visit(index, element);
9096 // Skip to next different index (i.e., omit duplicates).
9097 do {
9098 j++;
9099 } while (j < n && indices[j] == index);
9100 }
9101 break;
9102 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009103 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9104 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9105 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009106 for (uint32_t j = 0; j < length; j++) {
9107 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9108 visitor->visit(j, e);
9109 }
9110 break;
9111 }
9112 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9113 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009114 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009115 break;
9116 }
9117 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9118 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009119 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009120 break;
9121 }
9122 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9123 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009124 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009125 break;
9126 }
9127 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9128 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009129 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009130 break;
9131 }
9132 case JSObject::EXTERNAL_INT_ELEMENTS: {
9133 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009134 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009135 break;
9136 }
9137 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9138 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009139 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009140 break;
9141 }
9142 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9143 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009144 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009145 break;
9146 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009147 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9148 IterateExternalArrayElements<ExternalDoubleArray, double>(
9149 isolate, receiver, false, false, visitor);
9150 break;
9151 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009152 default:
9153 UNREACHABLE();
9154 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009155 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009156 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009157 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009158}
9159
9160
9161/**
9162 * Array::concat implementation.
9163 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009164 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009165 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009166 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009167RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009168 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009169 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009170
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009171 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9172 int argument_count = static_cast<int>(arguments->length()->Number());
9173 RUNTIME_ASSERT(arguments->HasFastElements());
9174 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009175
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009176 // Pass 1: estimate the length and number of elements of the result.
9177 // The actual length can be larger if any of the arguments have getters
9178 // that mutate other arguments (but will otherwise be precise).
9179 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009180
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009181 uint32_t estimate_result_length = 0;
9182 uint32_t estimate_nof_elements = 0;
9183 {
9184 for (int i = 0; i < argument_count; i++) {
9185 HandleScope loop_scope;
9186 Handle<Object> obj(elements->get(i));
9187 uint32_t length_estimate;
9188 uint32_t element_estimate;
9189 if (obj->IsJSArray()) {
9190 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9191 length_estimate =
9192 static_cast<uint32_t>(array->length()->Number());
9193 element_estimate =
9194 EstimateElementCount(array);
9195 } else {
9196 length_estimate = 1;
9197 element_estimate = 1;
9198 }
9199 // Avoid overflows by capping at kMaxElementCount.
9200 if (JSObject::kMaxElementCount - estimate_result_length <
9201 length_estimate) {
9202 estimate_result_length = JSObject::kMaxElementCount;
9203 } else {
9204 estimate_result_length += length_estimate;
9205 }
9206 if (JSObject::kMaxElementCount - estimate_nof_elements <
9207 element_estimate) {
9208 estimate_nof_elements = JSObject::kMaxElementCount;
9209 } else {
9210 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009211 }
9212 }
9213 }
9214
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009215 // If estimated number of elements is more than half of length, a
9216 // fixed array (fast case) is more time and space-efficient than a
9217 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009218 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009219
9220 Handle<FixedArray> storage;
9221 if (fast_case) {
9222 // The backing storage array must have non-existing elements to
9223 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009224 storage = isolate->factory()->NewFixedArrayWithHoles(
9225 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009226 } else {
9227 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9228 uint32_t at_least_space_for = estimate_nof_elements +
9229 (estimate_nof_elements >> 2);
9230 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009231 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009232 }
9233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009234 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009235
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009236 for (int i = 0; i < argument_count; i++) {
9237 Handle<Object> obj(elements->get(i));
9238 if (obj->IsJSArray()) {
9239 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009241 return Failure::Exception();
9242 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009243 } else {
9244 visitor.visit(0, obj);
9245 visitor.increase_index_offset(1);
9246 }
9247 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009248
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009249 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009250}
9251
9252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253// This will not allocate (flatten the string), but it may run
9254// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009255RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009256 NoHandleAllocation ha;
9257 ASSERT(args.length() == 1);
9258
9259 CONVERT_CHECKED(String, string, args[0]);
9260 StringInputBuffer buffer(string);
9261 while (buffer.has_more()) {
9262 uint16_t character = buffer.GetNext();
9263 PrintF("%c", character);
9264 }
9265 return string;
9266}
9267
ager@chromium.org5ec48922009-05-05 07:25:34 +00009268// Moves all own elements of an object, that are below a limit, to positions
9269// starting at zero. All undefined values are placed after non-undefined values,
9270// and are followed by non-existing element. Does not change the length
9271// property.
9272// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009273RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009274 ASSERT(args.length() == 2);
9275 CONVERT_CHECKED(JSObject, object, args[0]);
9276 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9277 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009278}
9279
9280
9281// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009282RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283 ASSERT(args.length() == 2);
9284 CONVERT_CHECKED(JSArray, from, args[0]);
9285 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009286 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009287 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009288 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9289 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009290 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009291 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009292 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009293 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009294 Object* new_map;
9295 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009296 to->set_map(Map::cast(new_map));
9297 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009299 Object* obj;
9300 { MaybeObject* maybe_obj = from->ResetElements();
9301 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9302 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009303 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009304 return to;
9305}
9306
9307
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009308// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009309RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009310 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009311 CONVERT_CHECKED(JSObject, object, args[0]);
9312 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009314 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009315 } else if (object->IsJSArray()) {
9316 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009317 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009318 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009319 }
9320}
9321
9322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009323RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009324 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009325
9326 ASSERT_EQ(3, args.length());
9327
ager@chromium.orgac091b72010-05-05 07:34:42 +00009328 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009329 Handle<Object> key1 = args.at<Object>(1);
9330 Handle<Object> key2 = args.at<Object>(2);
9331
9332 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009333 if (!key1->ToArrayIndex(&index1)
9334 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009335 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009336 }
9337
ager@chromium.orgac091b72010-05-05 07:34:42 +00009338 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9339 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009340 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009341 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009342 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009344 RETURN_IF_EMPTY_HANDLE(isolate,
9345 SetElement(jsobject, index1, tmp2, kStrictMode));
9346 RETURN_IF_EMPTY_HANDLE(isolate,
9347 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009349 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009350}
9351
9352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009353// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009354// might have elements. Can either return keys (positive integers) or
9355// intervals (pair of a negative integer (-start-1) followed by a
9356// positive (length)) or undefined values.
9357// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009358RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009359 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009360 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009361 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009362 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009363 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364 // Create an array and get all the keys into it, then remove all the
9365 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009366 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367 int keys_length = keys->length();
9368 for (int i = 0; i < keys_length; i++) {
9369 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009370 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009371 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009372 // Zap invalid keys.
9373 keys->set_undefined(i);
9374 }
9375 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009376 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009377 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009378 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009379 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009380 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009381 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009382 uint32_t actual_length =
9383 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009384 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009385 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009386 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009387 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009388 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009389 }
9390}
9391
9392
9393// DefineAccessor takes an optional final argument which is the
9394// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9395// to the way accessors are implemented, it is set for both the getter
9396// and setter on the first call to DefineAccessor and ignored on
9397// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009398RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9400 // Compute attributes.
9401 PropertyAttributes attributes = NONE;
9402 if (args.length() == 5) {
9403 CONVERT_CHECKED(Smi, attrs, args[4]);
9404 int value = attrs->value();
9405 // Only attribute bits should be set.
9406 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9407 attributes = static_cast<PropertyAttributes>(value);
9408 }
9409
9410 CONVERT_CHECKED(JSObject, obj, args[0]);
9411 CONVERT_CHECKED(String, name, args[1]);
9412 CONVERT_CHECKED(Smi, flag, args[2]);
9413 CONVERT_CHECKED(JSFunction, fun, args[3]);
9414 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9415}
9416
9417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009418RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009419 ASSERT(args.length() == 3);
9420 CONVERT_CHECKED(JSObject, obj, args[0]);
9421 CONVERT_CHECKED(String, name, args[1]);
9422 CONVERT_CHECKED(Smi, flag, args[2]);
9423 return obj->LookupAccessor(name, flag->value() == 0);
9424}
9425
9426
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009427#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009428RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009429 ASSERT(args.length() == 0);
9430 return Execution::DebugBreakHelper();
9431}
9432
9433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434// Helper functions for wrapping and unwrapping stack frame ids.
9435static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009436 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009437 return Smi::FromInt(id >> 2);
9438}
9439
9440
9441static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9442 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9443}
9444
9445
9446// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009447// args[0]: debug event listener function to set or null or undefined for
9448// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009450RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009451 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009452 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9453 args[0]->IsUndefined() ||
9454 args[0]->IsNull());
9455 Handle<Object> callback = args.at<Object>(0);
9456 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009457 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009459 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009460}
9461
9462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009463RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009464 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009465 isolate->stack_guard()->DebugBreak();
9466 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009467}
9468
9469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009470static MaybeObject* DebugLookupResultValue(Heap* heap,
9471 Object* receiver,
9472 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009473 LookupResult* result,
9474 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009475 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009476 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009477 case NORMAL:
9478 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009479 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009480 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009481 }
9482 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009483 case FIELD:
9484 value =
9485 JSObject::cast(
9486 result->holder())->FastPropertyAt(result->GetFieldIndex());
9487 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009488 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009489 }
9490 return value;
9491 case CONSTANT_FUNCTION:
9492 return result->GetConstantFunction();
9493 case CALLBACKS: {
9494 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009495 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009496 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009497 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009498 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009499 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009500 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009501 maybe_value = heap->isolate()->pending_exception();
9502 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009503 if (caught_exception != NULL) {
9504 *caught_exception = true;
9505 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009506 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009507 }
9508 return value;
9509 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009510 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009511 }
9512 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009514 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009515 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009516 case CONSTANT_TRANSITION:
9517 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009518 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009519 default:
9520 UNREACHABLE();
9521 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009522 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009523 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009524}
9525
9526
ager@chromium.org32912102009-01-16 10:38:43 +00009527// Get debugger related details for an object property.
9528// args[0]: object holding property
9529// args[1]: name of the property
9530//
9531// The array returned contains the following information:
9532// 0: Property value
9533// 1: Property details
9534// 2: Property value is exception
9535// 3: Getter function if defined
9536// 4: Setter function if defined
9537// Items 2-4 are only filled if the property has either a getter or a setter
9538// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009539RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009540 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009541
9542 ASSERT(args.length() == 2);
9543
9544 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9545 CONVERT_ARG_CHECKED(String, name, 1);
9546
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009547 // Make sure to set the current context to the context before the debugger was
9548 // entered (if the debugger is entered). The reason for switching context here
9549 // is that for some property lookups (accessors and interceptors) callbacks
9550 // into the embedding application can occour, and the embedding application
9551 // could have the assumption that its own global context is the current
9552 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553 SaveContext save(isolate);
9554 if (isolate->debug()->InDebugger()) {
9555 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009556 }
9557
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009558 // Skip the global proxy as it has no properties and always delegates to the
9559 // real global object.
9560 if (obj->IsJSGlobalProxy()) {
9561 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9562 }
9563
9564
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009565 // Check if the name is trivially convertible to an index and get the element
9566 // if so.
9567 uint32_t index;
9568 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009569 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009570 Object* element_or_char;
9571 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009572 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009573 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9574 return maybe_element_or_char;
9575 }
9576 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009577 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009578 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009579 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009580 }
9581
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009582 // Find the number of objects making up this.
9583 int length = LocalPrototypeChainLength(*obj);
9584
9585 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009586 Handle<JSObject> jsproto = obj;
9587 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009588 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009589 jsproto->LocalLookup(*name, &result);
9590 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009591 // LookupResult is not GC safe as it holds raw object pointers.
9592 // GC can happen later in this code so put the required fields into
9593 // local variables using handles when required for later use.
9594 PropertyType result_type = result.type();
9595 Handle<Object> result_callback_obj;
9596 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009597 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9598 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009599 }
9600 Smi* property_details = result.GetPropertyDetails().AsSmi();
9601 // DebugLookupResultValue can cause GC so details from LookupResult needs
9602 // to be copied to handles before this.
9603 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009604 Object* raw_value;
9605 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009606 DebugLookupResultValue(isolate->heap(), *obj, *name,
9607 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009608 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9609 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009610 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009611
9612 // If the callback object is a fixed array then it contains JavaScript
9613 // getter and/or setter.
9614 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9615 result_callback_obj->IsFixedArray();
9616 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009617 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009618 details->set(0, *value);
9619 details->set(1, property_details);
9620 if (hasJavaScriptAccessors) {
9621 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009622 caught_exception ? isolate->heap()->true_value()
9623 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009624 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9625 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9626 }
9627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009628 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009629 }
9630 if (i < length - 1) {
9631 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9632 }
9633 }
9634
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009635 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009636}
9637
9638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009639RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009640 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641
9642 ASSERT(args.length() == 2);
9643
9644 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9645 CONVERT_ARG_CHECKED(String, name, 1);
9646
9647 LookupResult result;
9648 obj->Lookup(*name, &result);
9649 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009650 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009651 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009652 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009653}
9654
9655
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009656// Return the property type calculated from the property details.
9657// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009658RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009659 ASSERT(args.length() == 1);
9660 CONVERT_CHECKED(Smi, details, args[0]);
9661 PropertyType type = PropertyDetails(details).type();
9662 return Smi::FromInt(static_cast<int>(type));
9663}
9664
9665
9666// Return the property attribute calculated from the property details.
9667// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009668RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009669 ASSERT(args.length() == 1);
9670 CONVERT_CHECKED(Smi, details, args[0]);
9671 PropertyAttributes attributes = PropertyDetails(details).attributes();
9672 return Smi::FromInt(static_cast<int>(attributes));
9673}
9674
9675
9676// Return the property insertion index calculated from the property details.
9677// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009678RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009679 ASSERT(args.length() == 1);
9680 CONVERT_CHECKED(Smi, details, args[0]);
9681 int index = PropertyDetails(details).index();
9682 return Smi::FromInt(index);
9683}
9684
9685
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009686// Return property value from named interceptor.
9687// args[0]: object
9688// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009689RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009690 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691 ASSERT(args.length() == 2);
9692 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9693 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9694 CONVERT_ARG_CHECKED(String, name, 1);
9695
9696 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009697 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009698}
9699
9700
9701// Return element value from indexed interceptor.
9702// args[0]: object
9703// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009704RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009705 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009706 ASSERT(args.length() == 2);
9707 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9708 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9709 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9710
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009711 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009712}
9713
9714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009715RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009716 ASSERT(args.length() >= 1);
9717 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009718 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009719 if (isolate->debug()->break_id() == 0 ||
9720 break_id != isolate->debug()->break_id()) {
9721 return isolate->Throw(
9722 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009723 }
9724
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009725 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009726}
9727
9728
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009729RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009730 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009731 ASSERT(args.length() == 1);
9732
9733 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009734 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009735 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9736 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009737 if (!maybe_result->ToObject(&result)) return maybe_result;
9738 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009739
9740 // Count all frames which are relevant to debugging stack trace.
9741 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009743 if (id == StackFrame::NO_ID) {
9744 // If there is no JavaScript stack frame count is 0.
9745 return Smi::FromInt(0);
9746 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009747 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009748 return Smi::FromInt(n);
9749}
9750
9751
9752static const int kFrameDetailsFrameIdIndex = 0;
9753static const int kFrameDetailsReceiverIndex = 1;
9754static const int kFrameDetailsFunctionIndex = 2;
9755static const int kFrameDetailsArgumentCountIndex = 3;
9756static const int kFrameDetailsLocalCountIndex = 4;
9757static const int kFrameDetailsSourcePositionIndex = 5;
9758static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009759static const int kFrameDetailsAtReturnIndex = 7;
9760static const int kFrameDetailsDebuggerFrameIndex = 8;
9761static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762
9763// Return an array with frame details
9764// args[0]: number: break id
9765// args[1]: number: frame index
9766//
9767// The array returned contains the following information:
9768// 0: Frame id
9769// 1: Receiver
9770// 2: Function
9771// 3: Argument count
9772// 4: Local count
9773// 5: Source position
9774// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009775// 7: Is at return
9776// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009777// Arguments name, value
9778// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009779// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009780RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009781 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009782 ASSERT(args.length() == 2);
9783
9784 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009785 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009786 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9787 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009788 if (!maybe_check->ToObject(&check)) return maybe_check;
9789 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009790 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009791 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009792
9793 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009794 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009795 if (id == StackFrame::NO_ID) {
9796 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009797 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009799 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009800 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009801 for (; !it.done(); it.Advance()) {
9802 if (count == index) break;
9803 count++;
9804 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009805 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009806
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009807 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009808 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009809
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009810 // Traverse the saved contexts chain to find the active context for the
9811 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009812 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009813 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009814 save = save->prev();
9815 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009816 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009817
9818 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009819 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009820
9821 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009822 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009823 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009824
9825 // Check for constructor frame.
9826 bool constructor = it.frame()->IsConstructor();
9827
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009828 // Get scope info and read from it for local variable information.
9829 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009830 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009831 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009832
9833 // Get the context.
9834 Handle<Context> context(Context::cast(it.frame()->context()));
9835
9836 // Get the locals names and values into a temporary array.
9837 //
9838 // TODO(1240907): Hide compiler-introduced stack variables
9839 // (e.g. .result)? For users of the debugger, they will probably be
9840 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009841 Handle<FixedArray> locals =
9842 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009843
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009844 // Fill in the names of the locals.
9845 for (int i = 0; i < info.NumberOfLocals(); i++) {
9846 locals->set(i * 2, *info.LocalName(i));
9847 }
9848
9849 // Fill in the values of the locals.
9850 for (int i = 0; i < info.NumberOfLocals(); i++) {
9851 if (is_optimized_frame) {
9852 // If we are inspecting an optimized frame use undefined as the
9853 // value for all locals.
9854 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009855 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009856 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009857 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009858 } else if (i < info.number_of_stack_slots()) {
9859 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009860 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9861 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009862 // Traverse the context chain to the function context as all local
9863 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009864 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009865 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866 context = Handle<Context>(context->previous());
9867 }
9868 ASSERT(context->is_function_context());
9869 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009870 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009871 }
9872 }
9873
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009874 // Check whether this frame is positioned at return. If not top
9875 // frame or if the frame is optimized it cannot be at a return.
9876 bool at_return = false;
9877 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009878 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009879 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009880
9881 // If positioned just before return find the value to be returned and add it
9882 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009883 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009884 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009885 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009886 Address internal_frame_sp = NULL;
9887 while (!it2.done()) {
9888 if (it2.frame()->is_internal()) {
9889 internal_frame_sp = it2.frame()->sp();
9890 } else {
9891 if (it2.frame()->is_java_script()) {
9892 if (it2.frame()->id() == it.frame()->id()) {
9893 // The internal frame just before the JavaScript frame contains the
9894 // value to return on top. A debug break at return will create an
9895 // internal frame to store the return value (eax/rax/r0) before
9896 // entering the debug break exit frame.
9897 if (internal_frame_sp != NULL) {
9898 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009899 Handle<Object>(Memory::Object_at(internal_frame_sp),
9900 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009901 break;
9902 }
9903 }
9904 }
9905
9906 // Indicate that the previous frame was not an internal frame.
9907 internal_frame_sp = NULL;
9908 }
9909 it2.Advance();
9910 }
9911 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009912
9913 // Now advance to the arguments adapter frame (if any). It contains all
9914 // the provided parameters whereas the function frame always have the number
9915 // of arguments matching the functions parameters. The rest of the
9916 // information (except for what is collected above) is the same.
9917 it.AdvanceToArgumentsFrame();
9918
9919 // Find the number of arguments to fill. At least fill the number of
9920 // parameters for the function and fill more if more parameters are provided.
9921 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009922 if (argument_count < it.frame()->ComputeParametersCount()) {
9923 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924 }
9925
9926 // Calculate the size of the result.
9927 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009928 2 * (argument_count + info.NumberOfLocals()) +
9929 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009930 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931
9932 // Add the frame id.
9933 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9934
9935 // Add the function (same as in function frame).
9936 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9937
9938 // Add the arguments count.
9939 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9940
9941 // Add the locals count
9942 details->set(kFrameDetailsLocalCountIndex,
9943 Smi::FromInt(info.NumberOfLocals()));
9944
9945 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009946 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009947 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9948 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009949 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950 }
9951
9952 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009953 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009954
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009955 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009956 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009957
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009958 // Add information on whether this frame is invoked in the debugger context.
9959 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009960 heap->ToBoolean(*save->context() ==
9961 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962
9963 // Fill the dynamic part.
9964 int details_index = kFrameDetailsFirstDynamicIndex;
9965
9966 // Add arguments name and value.
9967 for (int i = 0; i < argument_count; i++) {
9968 // Name of the argument.
9969 if (i < info.number_of_parameters()) {
9970 details->set(details_index++, *info.parameter_name(i));
9971 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009972 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009973 }
9974
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009975 // Parameter value. If we are inspecting an optimized frame, use
9976 // undefined as the value.
9977 //
9978 // TODO(3141533): We should be able to get the actual parameter
9979 // value for optimized frames.
9980 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009981 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009982 details->set(details_index++, it.frame()->GetParameter(i));
9983 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009984 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 }
9986 }
9987
9988 // Add locals name and value from the temporary copy from the function frame.
9989 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9990 details->set(details_index++, locals->get(i));
9991 }
9992
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009993 // Add the value being returned.
9994 if (at_return) {
9995 details->set(details_index++, *return_value);
9996 }
9997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009998 // Add the receiver (same as in function frame).
9999 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10000 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010001 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010002 if (!receiver->IsJSObject()) {
10003 // If the receiver is NOT a JSObject we have hit an optimization
10004 // where a value object is not converted into a wrapped JS objects.
10005 // To hide this optimization from the debugger, we wrap the receiver
10006 // by creating correct wrapper object based on the calling frame's
10007 // global context.
10008 it.Advance();
10009 Handle<Context> calling_frames_global_context(
10010 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010011 receiver =
10012 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010013 }
10014 details->set(kFrameDetailsReceiverIndex, *receiver);
10015
10016 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010017 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018}
10019
10020
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010021// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010022static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010023 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010024 Handle<SerializedScopeInfo> serialized_scope_info,
10025 ScopeInfo<>& scope_info,
10026 Handle<Context> context,
10027 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010028 // Fill all context locals to the context extension.
10029 for (int i = Context::MIN_CONTEXT_SLOTS;
10030 i < scope_info.number_of_context_slots();
10031 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010032 int context_index = serialized_scope_info->ContextSlotIndex(
10033 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010034
10035 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 if (*scope_info.context_slot_name(i) !=
10037 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010038 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010039 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010040 SetProperty(scope_object,
10041 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010042 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010043 NONE,
10044 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010045 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010046 }
10047 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010048
10049 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010050}
10051
10052
10053// Create a plain JSObject which materializes the local scope for the specified
10054// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010055static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10056 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010057 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010058 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010059 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10060 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010061
10062 // Allocate and initialize a JSObject with all the arguments, stack locals
10063 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010064 Handle<JSObject> local_scope =
10065 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010066
10067 // First fill all parameters.
10068 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010069 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010070 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010071 SetProperty(local_scope,
10072 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010073 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010074 NONE,
10075 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010076 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010077 }
10078
10079 // Second fill all stack locals.
10080 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010081 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010083 SetProperty(local_scope,
10084 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010085 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010086 NONE,
10087 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010088 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010089 }
10090
10091 // Third fill all context locals.
10092 Handle<Context> frame_context(Context::cast(frame->context()));
10093 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010094 if (!CopyContextLocalsToScopeObject(isolate,
10095 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010096 function_context, local_scope)) {
10097 return Handle<JSObject>();
10098 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010099
10100 // Finally copy any properties from the function context extension. This will
10101 // be variables introduced by eval.
10102 if (function_context->closure() == *function) {
10103 if (function_context->has_extension() &&
10104 !function_context->IsGlobalContext()) {
10105 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010106 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010107 for (int i = 0; i < keys->length(); i++) {
10108 // Names of variables introduced by eval are strings.
10109 ASSERT(keys->get(i)->IsString());
10110 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010111 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010112 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010113 SetProperty(local_scope,
10114 key,
10115 GetProperty(ext, key),
10116 NONE,
10117 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010118 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010119 }
10120 }
10121 }
10122 return local_scope;
10123}
10124
10125
10126// Create a plain JSObject which materializes the closure content for the
10127// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010128static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10129 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010130 ASSERT(context->is_function_context());
10131
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010132 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010133 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10134 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010135
10136 // Allocate and initialize a JSObject with all the content of theis function
10137 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010138 Handle<JSObject> closure_scope =
10139 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010140
10141 // Check whether the arguments shadow object exists.
10142 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 shared->scope_info()->ContextSlotIndex(
10144 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010145 if (arguments_shadow_index >= 0) {
10146 // In this case all the arguments are available in the arguments shadow
10147 // object.
10148 Handle<JSObject> arguments_shadow(
10149 JSObject::cast(context->get(arguments_shadow_index)));
10150 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010151 // We don't expect exception-throwing getters on the arguments shadow.
10152 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010153 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010154 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010155 SetProperty(closure_scope,
10156 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010157 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010158 NONE,
10159 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010160 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010161 }
10162 }
10163
10164 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010165 if (!CopyContextLocalsToScopeObject(isolate,
10166 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010167 context, closure_scope)) {
10168 return Handle<JSObject>();
10169 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010170
10171 // Finally copy any properties from the function context extension. This will
10172 // be variables introduced by eval.
10173 if (context->has_extension()) {
10174 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010175 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010176 for (int i = 0; i < keys->length(); i++) {
10177 // Names of variables introduced by eval are strings.
10178 ASSERT(keys->get(i)->IsString());
10179 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010180 RETURN_IF_EMPTY_HANDLE_VALUE(
10181 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010182 SetProperty(closure_scope,
10183 key,
10184 GetProperty(ext, key),
10185 NONE,
10186 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010187 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010188 }
10189 }
10190
10191 return closure_scope;
10192}
10193
10194
10195// Iterate over the actual scopes visible from a stack frame. All scopes are
10196// backed by an actual context except the local scope, which is inserted
10197// "artifically" in the context chain.
10198class ScopeIterator {
10199 public:
10200 enum ScopeType {
10201 ScopeTypeGlobal = 0,
10202 ScopeTypeLocal,
10203 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010204 ScopeTypeClosure,
10205 // Every catch block contains an implicit with block (its parameter is
10206 // a JSContextExtensionObject) that extends current scope with a variable
10207 // holding exception object. Such with blocks are treated as scopes of their
10208 // own type.
10209 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010210 };
10211
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010212 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10213 : isolate_(isolate),
10214 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010215 function_(JSFunction::cast(frame->function())),
10216 context_(Context::cast(frame->context())),
10217 local_done_(false),
10218 at_local_(false) {
10219
10220 // Check whether the first scope is actually a local scope.
10221 if (context_->IsGlobalContext()) {
10222 // If there is a stack slot for .result then this local scope has been
10223 // created for evaluating top level code and it is not a real local scope.
10224 // Checking for the existence of .result seems fragile, but the scope info
10225 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010226 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010228 at_local_ = index < 0;
10229 } else if (context_->is_function_context()) {
10230 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010231 } else if (context_->closure() != *function_) {
10232 // The context_ is a with block from the outer function.
10233 ASSERT(context_->has_extension());
10234 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010235 }
10236 }
10237
10238 // More scopes?
10239 bool Done() { return context_.is_null(); }
10240
10241 // Move to the next scope.
10242 void Next() {
10243 // If at a local scope mark the local scope as passed.
10244 if (at_local_) {
10245 at_local_ = false;
10246 local_done_ = true;
10247
10248 // If the current context is not associated with the local scope the
10249 // current context is the next real scope, so don't move to the next
10250 // context in this case.
10251 if (context_->closure() != *function_) {
10252 return;
10253 }
10254 }
10255
10256 // The global scope is always the last in the chain.
10257 if (context_->IsGlobalContext()) {
10258 context_ = Handle<Context>();
10259 return;
10260 }
10261
10262 // Move to the next context.
10263 if (context_->is_function_context()) {
10264 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10265 } else {
10266 context_ = Handle<Context>(context_->previous());
10267 }
10268
10269 // If passing the local scope indicate that the current scope is now the
10270 // local scope.
10271 if (!local_done_ &&
10272 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10273 at_local_ = true;
10274 }
10275 }
10276
10277 // Return the type of the current scope.
10278 int Type() {
10279 if (at_local_) {
10280 return ScopeTypeLocal;
10281 }
10282 if (context_->IsGlobalContext()) {
10283 ASSERT(context_->global()->IsGlobalObject());
10284 return ScopeTypeGlobal;
10285 }
10286 if (context_->is_function_context()) {
10287 return ScopeTypeClosure;
10288 }
10289 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010290 // Current scope is either an explicit with statement or a with statement
10291 // implicitely generated for a catch block.
10292 // If the extension object here is a JSContextExtensionObject then
10293 // current with statement is one frome a catch block otherwise it's a
10294 // regular with statement.
10295 if (context_->extension()->IsJSContextExtensionObject()) {
10296 return ScopeTypeCatch;
10297 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010298 return ScopeTypeWith;
10299 }
10300
10301 // Return the JavaScript object with the content of the current scope.
10302 Handle<JSObject> ScopeObject() {
10303 switch (Type()) {
10304 case ScopeIterator::ScopeTypeGlobal:
10305 return Handle<JSObject>(CurrentContext()->global());
10306 break;
10307 case ScopeIterator::ScopeTypeLocal:
10308 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010309 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010310 break;
10311 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010312 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010313 // Return the with object.
10314 return Handle<JSObject>(CurrentContext()->extension());
10315 break;
10316 case ScopeIterator::ScopeTypeClosure:
10317 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010318 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010319 break;
10320 }
10321 UNREACHABLE();
10322 return Handle<JSObject>();
10323 }
10324
10325 // Return the context for this scope. For the local context there might not
10326 // be an actual context.
10327 Handle<Context> CurrentContext() {
10328 if (at_local_ && context_->closure() != *function_) {
10329 return Handle<Context>();
10330 }
10331 return context_;
10332 }
10333
10334#ifdef DEBUG
10335 // Debug print of the content of the current scope.
10336 void DebugPrint() {
10337 switch (Type()) {
10338 case ScopeIterator::ScopeTypeGlobal:
10339 PrintF("Global:\n");
10340 CurrentContext()->Print();
10341 break;
10342
10343 case ScopeIterator::ScopeTypeLocal: {
10344 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010345 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010346 scope_info.Print();
10347 if (!CurrentContext().is_null()) {
10348 CurrentContext()->Print();
10349 if (CurrentContext()->has_extension()) {
10350 Handle<JSObject> extension =
10351 Handle<JSObject>(CurrentContext()->extension());
10352 if (extension->IsJSContextExtensionObject()) {
10353 extension->Print();
10354 }
10355 }
10356 }
10357 break;
10358 }
10359
10360 case ScopeIterator::ScopeTypeWith: {
10361 PrintF("With:\n");
10362 Handle<JSObject> extension =
10363 Handle<JSObject>(CurrentContext()->extension());
10364 extension->Print();
10365 break;
10366 }
10367
ager@chromium.orga1645e22009-09-09 19:27:10 +000010368 case ScopeIterator::ScopeTypeCatch: {
10369 PrintF("Catch:\n");
10370 Handle<JSObject> extension =
10371 Handle<JSObject>(CurrentContext()->extension());
10372 extension->Print();
10373 break;
10374 }
10375
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010376 case ScopeIterator::ScopeTypeClosure: {
10377 PrintF("Closure:\n");
10378 CurrentContext()->Print();
10379 if (CurrentContext()->has_extension()) {
10380 Handle<JSObject> extension =
10381 Handle<JSObject>(CurrentContext()->extension());
10382 if (extension->IsJSContextExtensionObject()) {
10383 extension->Print();
10384 }
10385 }
10386 break;
10387 }
10388
10389 default:
10390 UNREACHABLE();
10391 }
10392 PrintF("\n");
10393 }
10394#endif
10395
10396 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010397 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010398 JavaScriptFrame* frame_;
10399 Handle<JSFunction> function_;
10400 Handle<Context> context_;
10401 bool local_done_;
10402 bool at_local_;
10403
10404 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10405};
10406
10407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010408RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010409 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010410 ASSERT(args.length() == 2);
10411
10412 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010413 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010414 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10415 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010416 if (!maybe_check->ToObject(&check)) return maybe_check;
10417 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010418 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10419
10420 // Get the frame where the debugging is performed.
10421 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010422 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010423 JavaScriptFrame* frame = it.frame();
10424
10425 // Count the visible scopes.
10426 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010427 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010428 n++;
10429 }
10430
10431 return Smi::FromInt(n);
10432}
10433
10434
10435static const int kScopeDetailsTypeIndex = 0;
10436static const int kScopeDetailsObjectIndex = 1;
10437static const int kScopeDetailsSize = 2;
10438
10439// Return an array with scope details
10440// args[0]: number: break id
10441// args[1]: number: frame index
10442// args[2]: number: scope index
10443//
10444// The array returned contains the following information:
10445// 0: Scope type
10446// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010447RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010448 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010449 ASSERT(args.length() == 3);
10450
10451 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010452 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010453 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10454 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010455 if (!maybe_check->ToObject(&check)) return maybe_check;
10456 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010457 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10458 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10459
10460 // Get the frame where the debugging is performed.
10461 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010462 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010463 JavaScriptFrame* frame = frame_it.frame();
10464
10465 // Find the requested scope.
10466 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010467 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010468 for (; !it.Done() && n < index; it.Next()) {
10469 n++;
10470 }
10471 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010473 }
10474
10475 // Calculate the size of the result.
10476 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010477 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010478
10479 // Fill in scope details.
10480 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010481 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010482 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010483 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010484
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010485 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010486}
10487
10488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010489RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010490 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010491 ASSERT(args.length() == 0);
10492
10493#ifdef DEBUG
10494 // Print the scopes for the top frame.
10495 StackFrameLocator locator;
10496 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010498 it.DebugPrint();
10499 }
10500#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010501 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010502}
10503
10504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010505RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010507 ASSERT(args.length() == 1);
10508
10509 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010510 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010511 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10512 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010513 if (!maybe_result->ToObject(&result)) return maybe_result;
10514 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010515
10516 // Count all archived V8 threads.
10517 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010518 for (ThreadState* thread =
10519 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010520 thread != NULL;
10521 thread = thread->Next()) {
10522 n++;
10523 }
10524
10525 // Total number of threads is current thread and archived threads.
10526 return Smi::FromInt(n + 1);
10527}
10528
10529
10530static const int kThreadDetailsCurrentThreadIndex = 0;
10531static const int kThreadDetailsThreadIdIndex = 1;
10532static const int kThreadDetailsSize = 2;
10533
10534// Return an array with thread details
10535// args[0]: number: break id
10536// args[1]: number: thread index
10537//
10538// The array returned contains the following information:
10539// 0: Is current thread?
10540// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010541RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010542 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010543 ASSERT(args.length() == 2);
10544
10545 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010546 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010547 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10548 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010549 if (!maybe_check->ToObject(&check)) return maybe_check;
10550 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010551 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10552
10553 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010554 Handle<FixedArray> details =
10555 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010556
10557 // Thread index 0 is current thread.
10558 if (index == 0) {
10559 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 details->set(kThreadDetailsCurrentThreadIndex,
10561 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010562 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010563 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010564 } else {
10565 // Find the thread with the requested index.
10566 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010567 ThreadState* thread =
10568 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010569 while (index != n && thread != NULL) {
10570 thread = thread->Next();
10571 n++;
10572 }
10573 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010574 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010575 }
10576
10577 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010578 details->set(kThreadDetailsCurrentThreadIndex,
10579 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010580 details->set(kThreadDetailsThreadIdIndex,
10581 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010582 }
10583
10584 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010585 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010586}
10587
10588
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010589// Sets the disable break state
10590// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010591RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010592 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010593 ASSERT(args.length() == 1);
10594 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 isolate->debug()->set_disable_break(disable_break);
10596 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010597}
10598
10599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010600RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010601 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602 ASSERT(args.length() == 1);
10603
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010604 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10605 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606 // Find the number of break points
10607 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010608 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010610 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 Handle<FixedArray>::cast(break_locations));
10612}
10613
10614
10615// Set a break point in a function
10616// args[0]: function
10617// args[1]: number: break source position (within the function source)
10618// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010619RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010620 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010622 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10623 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10625 RUNTIME_ASSERT(source_position >= 0);
10626 Handle<Object> break_point_object_arg = args.at<Object>(2);
10627
10628 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010629 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10630 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010631
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010632 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010633}
10634
10635
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010636Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10637 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010638 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639 // Iterate the heap looking for SharedFunctionInfo generated from the
10640 // script. The inner most SharedFunctionInfo containing the source position
10641 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010642 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010643 // which is found is not compiled it is compiled and the heap is iterated
10644 // again as the compilation might create inner functions from the newly
10645 // compiled function and the actual requested break point might be in one of
10646 // these functions.
10647 bool done = false;
10648 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010649 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010650 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010651 while (!done) {
10652 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010653 for (HeapObject* obj = iterator.next();
10654 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010655 if (obj->IsSharedFunctionInfo()) {
10656 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10657 if (shared->script() == *script) {
10658 // If the SharedFunctionInfo found has the requested script data and
10659 // contains the source position it is a candidate.
10660 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010661 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010662 start_position = shared->start_position();
10663 }
10664 if (start_position <= position &&
10665 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010666 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 // candidate this is the new candidate.
10668 if (target.is_null()) {
10669 target_start_position = start_position;
10670 target = shared;
10671 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010672 if (target_start_position == start_position &&
10673 shared->end_position() == target->end_position()) {
10674 // If a top-level function contain only one function
10675 // declartion the source for the top-level and the function is
10676 // the same. In that case prefer the non top-level function.
10677 if (!shared->is_toplevel()) {
10678 target_start_position = start_position;
10679 target = shared;
10680 }
10681 } else if (target_start_position <= start_position &&
10682 shared->end_position() <= target->end_position()) {
10683 // This containment check includes equality as a function inside
10684 // a top-level function can share either start or end position
10685 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010686 target_start_position = start_position;
10687 target = shared;
10688 }
10689 }
10690 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010691 }
10692 }
10693 }
10694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010695 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010696 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010697 }
10698
10699 // If the candidate found is compiled we are done. NOTE: when lazy
10700 // compilation of inner functions is introduced some additional checking
10701 // needs to be done here to compile inner functions.
10702 done = target->is_compiled();
10703 if (!done) {
10704 // If the candidate is not compiled compile it to reveal any inner
10705 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010706 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707 }
10708 }
10709
10710 return *target;
10711}
10712
10713
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010714// Changes the state of a break point in a script and returns source position
10715// where break point was set. NOTE: Regarding performance see the NOTE for
10716// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010717// args[0]: script to set break point in
10718// args[1]: number: break source position (within the script source)
10719// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010720RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010721 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010722 ASSERT(args.length() == 3);
10723 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10724 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10725 RUNTIME_ASSERT(source_position >= 0);
10726 Handle<Object> break_point_object_arg = args.at<Object>(2);
10727
10728 // Get the script from the script wrapper.
10729 RUNTIME_ASSERT(wrapper->value()->IsScript());
10730 Handle<Script> script(Script::cast(wrapper->value()));
10731
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010732 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010733 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010734 if (!result->IsUndefined()) {
10735 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10736 // Find position within function. The script position might be before the
10737 // source position of the first function.
10738 int position;
10739 if (shared->start_position() > source_position) {
10740 position = 0;
10741 } else {
10742 position = source_position - shared->start_position();
10743 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010744 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010745 position += shared->start_position();
10746 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010748 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010749}
10750
10751
10752// Clear a break point
10753// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010754RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010755 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010756 ASSERT(args.length() == 1);
10757 Handle<Object> break_point_object_arg = args.at<Object>(0);
10758
10759 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010760 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010761
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010762 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010763}
10764
10765
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010766// Change the state of break on exceptions.
10767// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10768// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010769RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010770 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010772 RUNTIME_ASSERT(args[0]->IsNumber());
10773 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010775 // If the number doesn't match an enum value, the ChangeBreakOnException
10776 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010777 ExceptionBreakType type =
10778 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010779 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010780 isolate->debug()->ChangeBreakOnException(type, enable);
10781 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782}
10783
10784
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010785// Returns the state of break on exceptions
10786// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010787RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010788 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010789 ASSERT(args.length() == 1);
10790 RUNTIME_ASSERT(args[0]->IsNumber());
10791
10792 ExceptionBreakType type =
10793 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010794 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010795 return Smi::FromInt(result);
10796}
10797
10798
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010799// Prepare for stepping
10800// args[0]: break id for checking execution state
10801// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010802// args[2]: number of times to perform the step, for step out it is the number
10803// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010804RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010805 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010806 ASSERT(args.length() == 3);
10807 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010808 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010809 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10810 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010811 if (!maybe_check->ToObject(&check)) return maybe_check;
10812 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010813 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010814 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010815 }
10816
10817 // Get the step action and check validity.
10818 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10819 if (step_action != StepIn &&
10820 step_action != StepNext &&
10821 step_action != StepOut &&
10822 step_action != StepInMin &&
10823 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010824 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010825 }
10826
10827 // Get the number of steps.
10828 int step_count = NumberToInt32(args[2]);
10829 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010830 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010831 }
10832
ager@chromium.orga1645e22009-09-09 19:27:10 +000010833 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010834 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010835
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010836 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10838 step_count);
10839 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010840}
10841
10842
10843// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010844RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010845 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010846 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847 isolate->debug()->ClearStepping();
10848 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849}
10850
10851
10852// Creates a copy of the with context chain. The copy of the context chain is
10853// is linked to the function context supplied.
10854static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10855 Handle<Context> function_context) {
10856 // At the bottom of the chain. Return the function context to link to.
10857 if (context_chain->is_function_context()) {
10858 return function_context;
10859 }
10860
10861 // Recursively copy the with contexts.
10862 Handle<Context> previous(context_chain->previous());
10863 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010864 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010865 return context->GetIsolate()->factory()->NewWithContext(
10866 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010867}
10868
10869
10870// Helper function to find or create the arguments object for
10871// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010872static Handle<Object> GetArgumentsObject(Isolate* isolate,
10873 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010875 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010876 const ScopeInfo<>* sinfo,
10877 Handle<Context> function_context) {
10878 // Try to find the value of 'arguments' to pass as parameter. If it is not
10879 // found (that is the debugged function does not reference 'arguments' and
10880 // does not support eval) then create an 'arguments' object.
10881 int index;
10882 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010883 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010884 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010885 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010886 }
10887 }
10888
10889 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010890 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10891 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010892 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010893 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010894 }
10895 }
10896
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010897 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010898 Handle<JSObject> arguments =
10899 isolate->factory()->NewArgumentsObject(function, length);
10900 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010901
10902 AssertNoAllocation no_gc;
10903 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010904 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010905 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010906 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010907 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010908 return arguments;
10909}
10910
10911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010912static const char kSourceStr[] =
10913 "(function(arguments,__source__){return eval(__source__);})";
10914
10915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010917// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010918// extension part has all the parameters and locals of the function on the
10919// stack frame. A function which calls eval with the code to evaluate is then
10920// compiled in this context and called in this context. As this context
10921// replaces the context of the function on the stack frame a new (empty)
10922// function is created as well to be used as the closure for the context.
10923// This function and the context acts as replacements for the function on the
10924// stack frame presenting the same view of the values of parameters and
10925// local variables as if the piece of JavaScript was evaluated at the point
10926// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010927RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010928 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010929
10930 // Check the execution state and decode arguments frame and source to be
10931 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010932 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010933 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010934 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10935 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010936 if (!maybe_check_result->ToObject(&check_result)) {
10937 return maybe_check_result;
10938 }
10939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10941 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010942 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010943 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010944
10945 // Handle the processing of break.
10946 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947
10948 // Get the frame where the debugging is performed.
10949 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010950 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951 JavaScriptFrame* frame = it.frame();
10952 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010953 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010954 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955
10956 // Traverse the saved contexts chain to find the active context for the
10957 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010958 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010959 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960 save = save->prev();
10961 }
10962 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010963 SaveContext savex(isolate);
10964 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010965
10966 // Create the (empty) function replacing the function on the stack frame for
10967 // the purpose of evaluating in the context created below. It is important
10968 // that this function does not describe any parameters and local variables
10969 // in the context. If it does then this will cause problems with the lookup
10970 // in Context::Lookup, where context slots for parameters and local variables
10971 // are looked at before the extension object.
10972 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010973 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10974 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010975 go_between->set_context(function->context());
10976#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010977 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010978 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10979 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10980#endif
10981
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010982 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010983 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10984 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010985
10986 // Allocate a new context for the debug evaluation and set the extension
10987 // object build.
10988 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010989 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10990 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010991 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010993 Handle<Context> frame_context(Context::cast(frame->context()));
10994 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010995 context = CopyWithContextChain(frame_context, context);
10996
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010997 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010998 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010999 Handle<JSObject>::cast(additional_context), false);
11000 }
11001
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011002 // Wrap the evaluation statement in a new function compiled in the newly
11003 // created context. The function has one parameter which has to be called
11004 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011005 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011006 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011007
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011008 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011009 isolate->factory()->NewStringFromAscii(
11010 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011011
11012 // Currently, the eval code will be executed in non-strict mode,
11013 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011014 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011015 Compiler::CompileEval(function_source,
11016 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011017 context->IsGlobalContext(),
11018 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011019 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011020 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011021 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011022
11023 // Invoke the result of the compilation to get the evaluation function.
11024 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011025 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011026 Handle<Object> evaluation_function =
11027 Execution::Call(compiled_function, receiver, 0, NULL,
11028 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011029 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011031 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11032 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011033 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011034
11035 // Invoke the evaluation function and return the result.
11036 const int argc = 2;
11037 Object** argv[argc] = { arguments.location(),
11038 Handle<Object>::cast(source).location() };
11039 Handle<Object> result =
11040 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11041 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011042 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011043
11044 // Skip the global proxy as it has no properties and always delegates to the
11045 // real global object.
11046 if (result->IsJSGlobalProxy()) {
11047 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11048 }
11049
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011050 return *result;
11051}
11052
11053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011054RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011055 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011056
11057 // Check the execution state and decode arguments frame and source to be
11058 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011059 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011060 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011061 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11062 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011063 if (!maybe_check_result->ToObject(&check_result)) {
11064 return maybe_check_result;
11065 }
11066 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011067 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011068 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011069 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011070
11071 // Handle the processing of break.
11072 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011073
11074 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011075 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011076 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011077 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011078 top = top->prev();
11079 }
11080 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011081 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011082 }
11083
11084 // Get the global context now set to the top context from before the
11085 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011086 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011087
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011088 bool is_global = true;
11089
11090 if (additional_context->IsJSObject()) {
11091 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011092 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11093 isolate->factory()->empty_string(),
11094 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011095 go_between->set_context(*context);
11096 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011097 isolate->factory()->NewFunctionContext(
11098 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011099 context->set_extension(JSObject::cast(*additional_context));
11100 is_global = false;
11101 }
11102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011103 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011104 // Currently, the eval code will be executed in non-strict mode,
11105 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011106 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011107 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011108 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011109 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011110 Handle<JSFunction>(
11111 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11112 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011113
11114 // Invoke the result of the compilation to get the evaluation function.
11115 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011117 Handle<Object> result =
11118 Execution::Call(compiled_function, receiver, 0, NULL,
11119 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011120 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011121 return *result;
11122}
11123
11124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011125RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011126 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011127 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011128
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011130 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011131
11132 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011133 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011134 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11135 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11136 // because using
11137 // instances->set(i, *GetScriptWrapper(script))
11138 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11139 // already have deferenced the instances handle.
11140 Handle<JSValue> wrapper = GetScriptWrapper(script);
11141 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011142 }
11143
11144 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011145 Handle<JSObject> result =
11146 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011147 Handle<JSArray>::cast(result)->SetContent(*instances);
11148 return *result;
11149}
11150
11151
11152// Helper function used by Runtime_DebugReferencedBy below.
11153static int DebugReferencedBy(JSObject* target,
11154 Object* instance_filter, int max_references,
11155 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011156 JSFunction* arguments_function) {
11157 NoHandleAllocation ha;
11158 AssertNoAllocation no_alloc;
11159
11160 // Iterate the heap.
11161 int count = 0;
11162 JSObject* last = NULL;
11163 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011164 HeapObject* heap_obj = NULL;
11165 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011166 (max_references == 0 || count < max_references)) {
11167 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011168 if (heap_obj->IsJSObject()) {
11169 // Skip context extension objects and argument arrays as these are
11170 // checked in the context of functions using them.
11171 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011172 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011173 obj->map()->constructor() == arguments_function) {
11174 continue;
11175 }
11176
11177 // Check if the JS object has a reference to the object looked for.
11178 if (obj->ReferencesObject(target)) {
11179 // Check instance filter if supplied. This is normally used to avoid
11180 // references from mirror objects (see Runtime_IsInPrototypeChain).
11181 if (!instance_filter->IsUndefined()) {
11182 Object* V = obj;
11183 while (true) {
11184 Object* prototype = V->GetPrototype();
11185 if (prototype->IsNull()) {
11186 break;
11187 }
11188 if (instance_filter == prototype) {
11189 obj = NULL; // Don't add this object.
11190 break;
11191 }
11192 V = prototype;
11193 }
11194 }
11195
11196 if (obj != NULL) {
11197 // Valid reference found add to instance array if supplied an update
11198 // count.
11199 if (instances != NULL && count < instances_size) {
11200 instances->set(count, obj);
11201 }
11202 last = obj;
11203 count++;
11204 }
11205 }
11206 }
11207 }
11208
11209 // Check for circular reference only. This can happen when the object is only
11210 // referenced from mirrors and has a circular reference in which case the
11211 // object is not really alive and would have been garbage collected if not
11212 // referenced from the mirror.
11213 if (count == 1 && last == target) {
11214 count = 0;
11215 }
11216
11217 // Return the number of referencing objects found.
11218 return count;
11219}
11220
11221
11222// Scan the heap for objects with direct references to an object
11223// args[0]: the object to find references to
11224// args[1]: constructor function for instances to exclude (Mirror)
11225// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011226RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011227 ASSERT(args.length() == 3);
11228
11229 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011230 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011231
11232 // Check parameters.
11233 CONVERT_CHECKED(JSObject, target, args[0]);
11234 Object* instance_filter = args[1];
11235 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11236 instance_filter->IsJSObject());
11237 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11238 RUNTIME_ASSERT(max_references >= 0);
11239
11240 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011241 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011242 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011243 JSFunction* arguments_function =
11244 JSFunction::cast(arguments_boilerplate->map()->constructor());
11245
11246 // Get the number of referencing objects.
11247 int count;
11248 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011249 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011250
11251 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011252 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011253 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011254 if (!maybe_object->ToObject(&object)) return maybe_object;
11255 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011256 FixedArray* instances = FixedArray::cast(object);
11257
11258 // Fill the referencing objects.
11259 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011260 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011261
11262 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011263 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011264 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11265 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011266 if (!maybe_result->ToObject(&result)) return maybe_result;
11267 }
11268 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011269 return result;
11270}
11271
11272
11273// Helper function used by Runtime_DebugConstructedBy below.
11274static int DebugConstructedBy(JSFunction* constructor, int max_references,
11275 FixedArray* instances, int instances_size) {
11276 AssertNoAllocation no_alloc;
11277
11278 // Iterate the heap.
11279 int count = 0;
11280 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011281 HeapObject* heap_obj = NULL;
11282 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011283 (max_references == 0 || count < max_references)) {
11284 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011285 if (heap_obj->IsJSObject()) {
11286 JSObject* obj = JSObject::cast(heap_obj);
11287 if (obj->map()->constructor() == constructor) {
11288 // Valid reference found add to instance array if supplied an update
11289 // count.
11290 if (instances != NULL && count < instances_size) {
11291 instances->set(count, obj);
11292 }
11293 count++;
11294 }
11295 }
11296 }
11297
11298 // Return the number of referencing objects found.
11299 return count;
11300}
11301
11302
11303// Scan the heap for objects constructed by a specific function.
11304// args[0]: the constructor to find instances of
11305// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011306RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011307 ASSERT(args.length() == 2);
11308
11309 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011310 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011311
11312 // Check parameters.
11313 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11314 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11315 RUNTIME_ASSERT(max_references >= 0);
11316
11317 // Get the number of referencing objects.
11318 int count;
11319 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11320
11321 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011322 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011323 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011324 if (!maybe_object->ToObject(&object)) return maybe_object;
11325 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011326 FixedArray* instances = FixedArray::cast(object);
11327
11328 // Fill the referencing objects.
11329 count = DebugConstructedBy(constructor, max_references, instances, count);
11330
11331 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011332 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011333 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11334 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011335 if (!maybe_result->ToObject(&result)) return maybe_result;
11336 }
11337 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011338 return result;
11339}
11340
11341
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011342// Find the effective prototype object as returned by __proto__.
11343// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011344RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011345 ASSERT(args.length() == 1);
11346
11347 CONVERT_CHECKED(JSObject, obj, args[0]);
11348
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011349 // Use the __proto__ accessor.
11350 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011351}
11352
11353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011354RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011355 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011356 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011357 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011358}
11359
11360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011361RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011362#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011363 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011364 ASSERT(args.length() == 1);
11365 // Get the function and make sure it is compiled.
11366 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011367 Handle<SharedFunctionInfo> shared(func->shared());
11368 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011369 return Failure::Exception();
11370 }
11371 func->code()->PrintLn();
11372#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011373 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011374}
ager@chromium.org9085a012009-05-11 19:22:57 +000011375
11376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011377RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011378#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011379 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011380 ASSERT(args.length() == 1);
11381 // Get the function and make sure it is compiled.
11382 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011383 Handle<SharedFunctionInfo> shared(func->shared());
11384 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011385 return Failure::Exception();
11386 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011387 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011388#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011389 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011390}
11391
11392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011393RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011394 NoHandleAllocation ha;
11395 ASSERT(args.length() == 1);
11396
11397 CONVERT_CHECKED(JSFunction, f, args[0]);
11398 return f->shared()->inferred_name();
11399}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011400
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011401
11402static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011403 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011404 AssertNoAllocation no_allocations;
11405
11406 int counter = 0;
11407 int buffer_size = buffer->length();
11408 HeapIterator iterator;
11409 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11410 ASSERT(obj != NULL);
11411 if (!obj->IsSharedFunctionInfo()) {
11412 continue;
11413 }
11414 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11415 if (shared->script() != script) {
11416 continue;
11417 }
11418 if (counter < buffer_size) {
11419 buffer->set(counter, shared);
11420 }
11421 counter++;
11422 }
11423 return counter;
11424}
11425
11426// For a script finds all SharedFunctionInfo's in the heap that points
11427// to this script. Returns JSArray of SharedFunctionInfo wrapped
11428// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011429RUNTIME_FUNCTION(MaybeObject*,
11430 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011431 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011432 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011433 CONVERT_CHECKED(JSValue, script_value, args[0]);
11434
11435 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11436
11437 const int kBufferSize = 32;
11438
11439 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011440 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011441 int number = FindSharedFunctionInfosForScript(*script, *array);
11442 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011443 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011444 FindSharedFunctionInfosForScript(*script, *array);
11445 }
11446
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011447 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011448 result->set_length(Smi::FromInt(number));
11449
11450 LiveEdit::WrapSharedFunctionInfos(result);
11451
11452 return *result;
11453}
11454
11455// For a script calculates compilation information about all its functions.
11456// The script source is explicitly specified by the second argument.
11457// The source of the actual script is not used, however it is important that
11458// all generated code keeps references to this particular instance of script.
11459// Returns a JSArray of compilation infos. The array is ordered so that
11460// each function with all its descendant is always stored in a continues range
11461// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011462RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011463 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011465 CONVERT_CHECKED(JSValue, script, args[0]);
11466 CONVERT_ARG_CHECKED(String, source, 1);
11467 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11468
11469 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11470
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011471 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011472 return Failure::Exception();
11473 }
11474
11475 return result;
11476}
11477
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011478// Changes the source of the script to a new_source.
11479// If old_script_name is provided (i.e. is a String), also creates a copy of
11480// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011481RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011482 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011483 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011484 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11485 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011486 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011487
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011488 CONVERT_CHECKED(Script, original_script_pointer,
11489 original_script_value->value());
11490 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011491
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011492 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11493 new_source,
11494 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011495
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011496 if (old_script->IsScript()) {
11497 Handle<Script> script_handle(Script::cast(old_script));
11498 return *(GetScriptWrapper(script_handle));
11499 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011500 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011501 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011502}
11503
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011505RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011506 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011507 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011508 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11509 return LiveEdit::FunctionSourceUpdated(shared_info);
11510}
11511
11512
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011513// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011514RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011515 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011516 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011517 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11518 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11519
ager@chromium.orgac091b72010-05-05 07:34:42 +000011520 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011521}
11522
11523// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011524RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011525 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 HandleScope scope(isolate);
11527 Handle<Object> function_object(args[0], isolate);
11528 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011529
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011530 if (function_object->IsJSValue()) {
11531 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11532 if (script_object->IsJSValue()) {
11533 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011534 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011535 }
11536
11537 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11538 } else {
11539 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11540 // and we check it in this function.
11541 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011543 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011544}
11545
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011546
11547// In a code of a parent function replaces original function as embedded object
11548// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011549RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011550 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011551 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011552
11553 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11554 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11555 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11556
11557 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11558 subst_wrapper);
11559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011560 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011561}
11562
11563
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011564// Updates positions of a shared function info (first parameter) according
11565// to script source change. Text change is described in second parameter as
11566// array of groups of 3 numbers:
11567// (change_begin, change_end, change_end_new_position).
11568// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011569RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011570 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011571 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011572 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11573 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11574
ager@chromium.orgac091b72010-05-05 07:34:42 +000011575 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011576}
11577
11578
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011579// For array of SharedFunctionInfo's (each wrapped in JSValue)
11580// checks that none of them have activations on stacks (of any thread).
11581// Returns array of the same length with corresponding results of
11582// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011583RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011584 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011585 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011586 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011587 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011588
ager@chromium.org357bf652010-04-12 11:30:10 +000011589 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011590}
11591
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011592// Compares 2 strings line-by-line, then token-wise and returns diff in form
11593// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11594// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011595RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011596 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011597 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011598 CONVERT_ARG_CHECKED(String, s1, 0);
11599 CONVERT_ARG_CHECKED(String, s2, 1);
11600
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011601 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011602}
11603
11604
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011605// A testing entry. Returns statement position which is the closest to
11606// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011607RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011608 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011610 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11611 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11612
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011613 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011614
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011615 if (code->kind() != Code::FUNCTION &&
11616 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011617 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011618 }
11619
11620 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011621 int closest_pc = 0;
11622 int distance = kMaxInt;
11623 while (!it.done()) {
11624 int statement_position = static_cast<int>(it.rinfo()->data());
11625 // Check if this break point is closer that what was previously found.
11626 if (source_position <= statement_position &&
11627 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011628 closest_pc =
11629 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011630 distance = statement_position - source_position;
11631 // Check whether we can't get any closer.
11632 if (distance == 0) break;
11633 }
11634 it.next();
11635 }
11636
11637 return Smi::FromInt(closest_pc);
11638}
11639
11640
ager@chromium.org357bf652010-04-12 11:30:10 +000011641// Calls specified function with or without entering the debugger.
11642// This is used in unit tests to run code as if debugger is entered or simply
11643// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011644RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011645 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011647 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11648 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11649
11650 Handle<Object> result;
11651 bool pending_exception;
11652 {
11653 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011655 &pending_exception);
11656 } else {
11657 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011658 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011659 &pending_exception);
11660 }
11661 }
11662 if (!pending_exception) {
11663 return *result;
11664 } else {
11665 return Failure::Exception();
11666 }
11667}
11668
11669
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011670// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011671RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011672 CONVERT_CHECKED(String, arg, args[0]);
11673 SmartPointer<char> flags =
11674 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11675 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011676 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011677}
11678
11679
11680// Performs a GC.
11681// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011682RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011683 isolate->heap()->CollectAllGarbage(true);
11684 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011685}
11686
11687
11688// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011689RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011690 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011691 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011692 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011693 }
11694 return Smi::FromInt(usage);
11695}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011696
11697
11698// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011699RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011700#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011701 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011702#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011703 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011704#endif
11705}
11706
11707
11708// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011709RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011710#ifdef LIVE_OBJECT_LIST
11711 return LiveObjectList::Capture();
11712#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011713 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011714#endif
11715}
11716
11717
11718// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011719RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011720#ifdef LIVE_OBJECT_LIST
11721 CONVERT_SMI_CHECKED(id, args[0]);
11722 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011723 return success ? isolate->heap()->true_value() :
11724 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011725#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011726 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011727#endif
11728}
11729
11730
11731// Generates the response to a debugger request for a dump of the objects
11732// contained in the difference between the captured live object lists
11733// specified by id1 and id2.
11734// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11735// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011736RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011737#ifdef LIVE_OBJECT_LIST
11738 HandleScope scope;
11739 CONVERT_SMI_CHECKED(id1, args[0]);
11740 CONVERT_SMI_CHECKED(id2, args[1]);
11741 CONVERT_SMI_CHECKED(start, args[2]);
11742 CONVERT_SMI_CHECKED(count, args[3]);
11743 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11744 EnterDebugger enter_debugger;
11745 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11746#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011747 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011748#endif
11749}
11750
11751
11752// Gets the specified object as requested by the debugger.
11753// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011754RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011755#ifdef LIVE_OBJECT_LIST
11756 CONVERT_SMI_CHECKED(obj_id, args[0]);
11757 Object* result = LiveObjectList::GetObj(obj_id);
11758 return result;
11759#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011760 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011761#endif
11762}
11763
11764
11765// Gets the obj id for the specified address if valid.
11766// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011767RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011768#ifdef LIVE_OBJECT_LIST
11769 HandleScope scope;
11770 CONVERT_ARG_CHECKED(String, address, 0);
11771 Object* result = LiveObjectList::GetObjId(address);
11772 return result;
11773#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011774 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011775#endif
11776}
11777
11778
11779// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011780RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011781#ifdef LIVE_OBJECT_LIST
11782 HandleScope scope;
11783 CONVERT_SMI_CHECKED(obj_id, args[0]);
11784 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11785 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11786 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11787 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11788 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11789
11790 Handle<JSObject> instance_filter;
11791 if (args[1]->IsJSObject()) {
11792 instance_filter = args.at<JSObject>(1);
11793 }
11794 bool verbose = false;
11795 if (args[2]->IsBoolean()) {
11796 verbose = args[2]->IsTrue();
11797 }
11798 int start = 0;
11799 if (args[3]->IsSmi()) {
11800 start = Smi::cast(args[3])->value();
11801 }
11802 int limit = Smi::kMaxValue;
11803 if (args[4]->IsSmi()) {
11804 limit = Smi::cast(args[4])->value();
11805 }
11806
11807 return LiveObjectList::GetObjRetainers(obj_id,
11808 instance_filter,
11809 verbose,
11810 start,
11811 limit,
11812 filter_obj);
11813#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011814 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011815#endif
11816}
11817
11818
11819// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011820RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011821#ifdef LIVE_OBJECT_LIST
11822 HandleScope scope;
11823 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11824 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11825 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11826
11827 Handle<JSObject> instance_filter;
11828 if (args[2]->IsJSObject()) {
11829 instance_filter = args.at<JSObject>(2);
11830 }
11831
11832 Object* result =
11833 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11834 return result;
11835#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011836 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011837#endif
11838}
11839
11840
11841// Generates the response to a debugger request for a list of all
11842// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011843RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011844#ifdef LIVE_OBJECT_LIST
11845 CONVERT_SMI_CHECKED(start, args[0]);
11846 CONVERT_SMI_CHECKED(count, args[1]);
11847 return LiveObjectList::Info(start, count);
11848#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011849 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011850#endif
11851}
11852
11853
11854// Gets a dump of the specified object as requested by the debugger.
11855// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011856RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011857#ifdef LIVE_OBJECT_LIST
11858 HandleScope scope;
11859 CONVERT_SMI_CHECKED(obj_id, args[0]);
11860 Object* result = LiveObjectList::PrintObj(obj_id);
11861 return result;
11862#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011863 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011864#endif
11865}
11866
11867
11868// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011869RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011870#ifdef LIVE_OBJECT_LIST
11871 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011872 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011873#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011874 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011875#endif
11876}
11877
11878
11879// Generates the response to a debugger request for a summary of the types
11880// of objects in the difference between the captured live object lists
11881// specified by id1 and id2.
11882// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11883// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011884RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011885#ifdef LIVE_OBJECT_LIST
11886 HandleScope scope;
11887 CONVERT_SMI_CHECKED(id1, args[0]);
11888 CONVERT_SMI_CHECKED(id2, args[1]);
11889 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11890
11891 EnterDebugger enter_debugger;
11892 return LiveObjectList::Summarize(id1, id2, filter_obj);
11893#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011894 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011895#endif
11896}
11897
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011898#endif // ENABLE_DEBUGGER_SUPPORT
11899
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011900
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011901#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011902RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011903 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011904 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011905
11906 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011907 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11908 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011909 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011910}
11911
11912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011913RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011914 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011915 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011916
11917 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011918 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11919 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011920 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011921}
11922
11923#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011924
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011925// Finds the script object from the script data. NOTE: This operation uses
11926// heap traversal to find the function generated for the source position
11927// for the requested break point. For lazily compiled functions several heap
11928// traversals might be required rendering this operation as a rather slow
11929// operation. However for setting break points which is normally done through
11930// some kind of user interaction the performance is not crucial.
11931static Handle<Object> Runtime_GetScriptFromScriptName(
11932 Handle<String> script_name) {
11933 // Scan the heap for Script objects to find the script with the requested
11934 // script data.
11935 Handle<Script> script;
11936 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011937 HeapObject* obj = NULL;
11938 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011939 // If a script is found check if it has the script data requested.
11940 if (obj->IsScript()) {
11941 if (Script::cast(obj)->name()->IsString()) {
11942 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11943 script = Handle<Script>(Script::cast(obj));
11944 }
11945 }
11946 }
11947 }
11948
11949 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011950 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011951
11952 // Return the script found.
11953 return GetScriptWrapper(script);
11954}
11955
11956
11957// Get the script object from script data. NOTE: Regarding performance
11958// see the NOTE for GetScriptFromScriptData.
11959// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011960RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011961 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011962
11963 ASSERT(args.length() == 1);
11964
11965 CONVERT_CHECKED(String, script_name, args[0]);
11966
11967 // Find the requested script.
11968 Handle<Object> result =
11969 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11970 return *result;
11971}
11972
11973
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011974// Determines whether the given stack frame should be displayed in
11975// a stack trace. The caller is the error constructor that asked
11976// for the stack trace to be collected. The first time a construct
11977// call to this function is encountered it is skipped. The seen_caller
11978// in/out parameter is used to remember if the caller has been seen
11979// yet.
11980static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11981 bool* seen_caller) {
11982 // Only display JS frames.
11983 if (!raw_frame->is_java_script())
11984 return false;
11985 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11986 Object* raw_fun = frame->function();
11987 // Not sure when this can happen but skip it just in case.
11988 if (!raw_fun->IsJSFunction())
11989 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011990 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011991 *seen_caller = true;
11992 return false;
11993 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011994 // Skip all frames until we've seen the caller. Also, skip the most
11995 // obvious builtin calls. Some builtin calls (such as Number.ADD
11996 // which is invoked using 'call') are very difficult to recognize
11997 // so we're leaving them in for now.
11998 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011999}
12000
12001
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012002// Collect the raw data for a stack trace. Returns an array of 4
12003// element segments each containing a receiver, function, code and
12004// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012005RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012006 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012007 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012008 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012010 HandleScope scope(isolate);
12011 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012012
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012013 limit = Max(limit, 0); // Ensure that limit is not negative.
12014 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012015 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012016 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012017
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012018 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012019 // If the caller parameter is a function we skip frames until we're
12020 // under it before starting to collect.
12021 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012022 int cursor = 0;
12023 int frames_seen = 0;
12024 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012025 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012026 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012027 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012028 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012029 // Set initial size to the maximum inlining level + 1 for the outermost
12030 // function.
12031 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012032 frame->Summarize(&frames);
12033 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012034 if (cursor + 4 > elements->length()) {
12035 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12036 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012037 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012038 for (int i = 0; i < cursor; i++) {
12039 new_elements->set(i, elements->get(i));
12040 }
12041 elements = new_elements;
12042 }
12043 ASSERT(cursor + 4 <= elements->length());
12044
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012045 Handle<Object> recv = frames[i].receiver();
12046 Handle<JSFunction> fun = frames[i].function();
12047 Handle<Code> code = frames[i].code();
12048 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012049 elements->set(cursor++, *recv);
12050 elements->set(cursor++, *fun);
12051 elements->set(cursor++, *code);
12052 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012053 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012054 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012055 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012056 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012057 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012058 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012059 return *result;
12060}
12061
12062
ager@chromium.org3811b432009-10-28 14:53:37 +000012063// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012064RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012065 ASSERT_EQ(args.length(), 0);
12066
12067 NoHandleAllocation ha;
12068
12069 const char* version_string = v8::V8::GetVersion();
12070
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012071 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12072 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012073}
12074
12075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012076RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012077 ASSERT(args.length() == 2);
12078 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
12079 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012080 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012081 OS::Abort();
12082 UNREACHABLE();
12083 return NULL;
12084}
12085
12086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012087RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012088 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012089 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012090 Object* key = args[1];
12091
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012092 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012093 Object* o = cache->get(finger_index);
12094 if (o == key) {
12095 // The fastest case: hit the same place again.
12096 return cache->get(finger_index + 1);
12097 }
12098
12099 for (int i = finger_index - 2;
12100 i >= JSFunctionResultCache::kEntriesIndex;
12101 i -= 2) {
12102 o = cache->get(i);
12103 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012104 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012105 return cache->get(i + 1);
12106 }
12107 }
12108
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012109 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012110 ASSERT(size <= cache->length());
12111
12112 for (int i = size - 2; i > finger_index; i -= 2) {
12113 o = cache->get(i);
12114 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012115 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012116 return cache->get(i + 1);
12117 }
12118 }
12119
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012120 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012121 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012122
12123 Handle<JSFunctionResultCache> cache_handle(cache);
12124 Handle<Object> key_handle(key);
12125 Handle<Object> value;
12126 {
12127 Handle<JSFunction> factory(JSFunction::cast(
12128 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12129 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012130 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012131 // This handle is nor shared, nor used later, so it's safe.
12132 Object** argv[] = { key_handle.location() };
12133 bool pending_exception = false;
12134 value = Execution::Call(factory,
12135 receiver,
12136 1,
12137 argv,
12138 &pending_exception);
12139 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012140 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012141
12142#ifdef DEBUG
12143 cache_handle->JSFunctionResultCacheVerify();
12144#endif
12145
12146 // Function invocation may have cleared the cache. Reread all the data.
12147 finger_index = cache_handle->finger_index();
12148 size = cache_handle->size();
12149
12150 // If we have spare room, put new data into it, otherwise evict post finger
12151 // entry which is likely to be the least recently used.
12152 int index = -1;
12153 if (size < cache_handle->length()) {
12154 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12155 index = size;
12156 } else {
12157 index = finger_index + JSFunctionResultCache::kEntrySize;
12158 if (index == cache_handle->length()) {
12159 index = JSFunctionResultCache::kEntriesIndex;
12160 }
12161 }
12162
12163 ASSERT(index % 2 == 0);
12164 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12165 ASSERT(index < cache_handle->length());
12166
12167 cache_handle->set(index, *key_handle);
12168 cache_handle->set(index + 1, *value);
12169 cache_handle->set_finger_index(index);
12170
12171#ifdef DEBUG
12172 cache_handle->JSFunctionResultCacheVerify();
12173#endif
12174
12175 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012176}
12177
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012179RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012180 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012181 CONVERT_ARG_CHECKED(String, type, 0);
12182 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012183 return *isolate->factory()->NewJSMessageObject(
12184 type,
12185 arguments,
12186 0,
12187 0,
12188 isolate->factory()->undefined_value(),
12189 isolate->factory()->undefined_value(),
12190 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012191}
12192
12193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012194RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012195 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12196 return message->type();
12197}
12198
12199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012200RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012201 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12202 return message->arguments();
12203}
12204
12205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012206RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012207 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12208 return Smi::FromInt(message->start_position());
12209}
12210
12211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012212RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012213 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12214 return message->script();
12215}
12216
12217
kasper.lund44510672008-07-25 07:37:58 +000012218#ifdef DEBUG
12219// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12220// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012221RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012222 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012223 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012224#define COUNT_ENTRY(Name, argc, ressize) + 1
12225 int entry_count = 0
12226 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12227 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12228 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12229#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012230 Factory* factory = isolate->factory();
12231 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012233 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012234#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012235 { \
12236 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012237 Handle<String> name; \
12238 /* Inline runtime functions have an underscore in front of the name. */ \
12239 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012240 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012241 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12242 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012243 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012244 Vector<const char>(#Name, StrLength(#Name))); \
12245 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012246 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012247 pair_elements->set(0, *name); \
12248 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012249 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012250 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012252 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012253 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012254 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012255 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012256 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012257#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012258 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012259 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012260 return *result;
12261}
kasper.lund44510672008-07-25 07:37:58 +000012262#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012263
12264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012265RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012266 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012267 CONVERT_CHECKED(String, format, args[0]);
12268 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012269 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012270 LOGGER->LogRuntime(chars, elms);
12271 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012272}
12273
12274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012275RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012276 UNREACHABLE(); // implemented as macro in the parser
12277 return NULL;
12278}
12279
12280
12281// ----------------------------------------------------------------------------
12282// Implementation of Runtime
12283
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012284#define F(name, number_of_args, result_size) \
12285 { Runtime::k##name, Runtime::RUNTIME, #name, \
12286 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012287
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012288
12289#define I(name, number_of_args, result_size) \
12290 { Runtime::kInline##name, Runtime::INLINE, \
12291 "_" #name, NULL, number_of_args, result_size },
12292
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012293static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012294 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012295 INLINE_FUNCTION_LIST(I)
12296 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012297};
12298
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012299
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012300MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12301 Object* dictionary) {
12302 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012303 ASSERT(dictionary != NULL);
12304 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12305 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012306 Object* name_symbol;
12307 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012308 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012309 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12310 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012311 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012312 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12313 String::cast(name_symbol),
12314 Smi::FromInt(i),
12315 PropertyDetails(NONE, NORMAL));
12316 if (!maybe_dictionary->ToObject(&dictionary)) {
12317 // Non-recoverable failure. Calling code must restart heap
12318 // initialization.
12319 return maybe_dictionary;
12320 }
12321 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012322 }
12323 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012324}
12325
12326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012327const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12328 Heap* heap = name->GetHeap();
12329 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012330 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012331 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012332 int function_index = Smi::cast(smi_index)->value();
12333 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012334 }
12335 return NULL;
12336}
12337
12338
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012339const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012340 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12341}
12342
12343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012344void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012345 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012346 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012347 if (failure->IsRetryAfterGC()) {
12348 // Try to do a garbage collection; ignore it if it fails. The C
12349 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012350 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012351 } else {
12352 // Handle last resort GC and make sure to allow future allocations
12353 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012354 isolate->counters()->gc_last_resort_from_js()->Increment();
12355 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012356 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012357}
12358
12359
12360} } // namespace v8::internal