blob: 9c23c2c9670a448c820266086fd664e8bbf5af20 [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"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
110 JSObject* boilerplate) {
111 StackLimitCheck check(isolate);
112 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000116 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000117 if (!maybe_result->ToObject(&result)) return maybe_result;
118 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 JSObject* copy = JSObject::cast(result);
120
121 // Deep copy local properties.
122 if (copy->HasFastProperties()) {
123 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000124 for (int i = 0; i < properties->length(); i++) {
125 Object* value = properties->get(i);
126 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000128 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000129 if (!maybe_result->ToObject(&result)) return maybe_result;
130 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000131 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 }
133 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000134 int nof = copy->map()->inobject_properties();
135 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000136 Object* value = copy->InObjectPropertyAt(i);
137 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 if (!maybe_result->ToObject(&result)) return maybe_result;
141 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000142 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000143 }
144 }
145 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000147 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000148 if (!maybe_result->ToObject(&result)) return maybe_result;
149 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 FixedArray* names = FixedArray::cast(result);
151 copy->GetLocalPropertyNames(names, 0);
152 for (int i = 0; i < names->length(); i++) {
153 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 // Only deep copy fields from the object literal expression.
158 // In particular, don't try to copy the length attribute of
159 // an array.
160 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 Object* value =
162 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000163 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000164 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000165 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
168 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000169 // Creating object copy for literals. No strict mode needed.
170 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171 if (!maybe_result->ToObject(&result)) return maybe_result;
172 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 }
176
177 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000179 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000180 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000181 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000182 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000183 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000184 if (elements->map() == heap->fixed_cow_array_map()) {
185 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000186#ifdef DEBUG
187 for (int i = 0; i < elements->length(); i++) {
188 ASSERT(!elements->get(i)->IsJSObject());
189 }
190#endif
191 } else {
192 for (int i = 0; i < elements->length(); i++) {
193 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000194 ASSERT(value->IsSmi() ||
195 value->IsTheHole() ||
196 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 if (value->IsJSObject()) {
198 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000199 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
200 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000203 elements->set(i, result);
204 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000205 }
206 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000207 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000208 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000209 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 NumberDictionary* element_dictionary = copy->element_dictionary();
211 int capacity = element_dictionary->Capacity();
212 for (int i = 0; i < capacity; i++) {
213 Object* k = element_dictionary->KeyAt(i);
214 if (element_dictionary->IsKey(k)) {
215 Object* value = element_dictionary->ValueAt(i);
216 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000217 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000218 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
219 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000220 if (!maybe_result->ToObject(&result)) return maybe_result;
221 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000222 element_dictionary->ValueAtPut(i, result);
223 }
224 }
225 }
226 break;
227 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000228 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000229 UNIMPLEMENTED();
230 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000231 case EXTERNAL_PIXEL_ELEMENTS:
232 case EXTERNAL_BYTE_ELEMENTS:
233 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
234 case EXTERNAL_SHORT_ELEMENTS:
235 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
236 case EXTERNAL_INT_ELEMENTS:
237 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
238 case EXTERNAL_FLOAT_ELEMENTS:
239 case EXTERNAL_DOUBLE_ELEMENTS:
240 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000241 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000242 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000243 }
244 return copy;
245}
246
247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000248RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000249 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000251}
252
253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000254RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000256 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257}
258
259
ager@chromium.org236ad962008-09-25 09:45:57 +0000260static Handle<Map> ComputeObjectLiteralMap(
261 Handle<Context> context,
262 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000263 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000264 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 int properties_length = constant_properties->length();
266 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000268 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000270 for (int p = 0; p != properties_length; p += 2) {
271 Object* key = constant_properties->get(p);
272 uint32_t element_index = 0;
273 if (key->IsSymbol()) {
274 number_of_symbol_keys++;
275 } else if (key->ToArrayIndex(&element_index)) {
276 // An index key does not require space in the property backing store.
277 number_of_properties--;
278 } else {
279 // Bail out as a non-symbol non-index key makes caching impossible.
280 // ASSERT to make sure that the if condition after the loop is false.
281 ASSERT(number_of_symbol_keys != number_of_properties);
282 break;
283 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000285 // If we only have symbols and array indices among keys then we can
286 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000287 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 if ((number_of_symbol_keys == number_of_properties) &&
289 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000290 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 Handle<FixedArray> keys =
292 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000293 if (number_of_symbol_keys > 0) {
294 int index = 0;
295 for (int p = 0; p < properties_length; p += 2) {
296 Object* key = constant_properties->get(p);
297 if (key->IsSymbol()) {
298 keys->set(index++, key);
299 }
300 }
301 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000303 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000305 }
306 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000307 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000308 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000309 Handle<Map>(context->object_function()->initial_map()),
310 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311}
312
313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000314static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316 Handle<FixedArray> literals,
317 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000318
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000319
320static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000321 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000322 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000323 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 bool should_have_fast_elements,
325 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000326 // Get the global context from the literals array. This is the
327 // context in which the function was created and we use the object
328 // function from this context to create the object literal. We do
329 // not use the object function from the current global context
330 // because this might be the object function from another context
331 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000332 Handle<Context> context =
333 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000335 // In case we have function literals, we want the object to be in
336 // slow properties mode for now. We don't go in the map cache because
337 // maps with constant functions can't be shared if the functions are
338 // not the same (which is the common case).
339 bool is_result_from_cache = false;
340 Handle<Map> map = has_function_literal
341 ? Handle<Map>(context->object_function()->initial_map())
342 : ComputeObjectLiteralMap(context,
343 constant_properties,
344 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000347
348 // Normalize the elements of the boilerplate to save space if needed.
349 if (!should_have_fast_elements) NormalizeElements(boilerplate);
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // Add the constant properties to the boilerplate.
352 int length = constant_properties->length();
353 bool should_transform =
354 !is_result_from_cache && boilerplate->HasFastProperties();
355 if (should_transform || has_function_literal) {
356 // Normalize the properties of object to avoid n^2 behavior
357 // when extending the object multiple properties. Indicate the number of
358 // properties to be added.
359 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
360 }
361
362 for (int index = 0; index < length; index +=2) {
363 Handle<Object> key(constant_properties->get(index+0), isolate);
364 Handle<Object> value(constant_properties->get(index+1), isolate);
365 if (value->IsFixedArray()) {
366 // The value contains the constant_properties of a
367 // simple object or array literal.
368 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
369 value = CreateLiteralBoilerplate(isolate, literals, array);
370 if (value.is_null()) return value;
371 }
372 Handle<Object> result;
373 uint32_t element_index = 0;
374 if (key->IsSymbol()) {
375 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
376 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000377 result = SetOwnElement(boilerplate,
378 element_index,
379 value,
380 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000382 Handle<String> name(String::cast(*key));
383 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000384 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
385 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 } else if (key->ToArrayIndex(&element_index)) {
388 // Array index (uint32).
389 result = SetOwnElement(boilerplate,
390 element_index,
391 value,
392 kNonStrictMode);
393 } else {
394 // Non-uint32 number.
395 ASSERT(key->IsNumber());
396 double num = key->Number();
397 char arr[100];
398 Vector<char> buffer(arr, ARRAY_SIZE(arr));
399 const char* str = DoubleToCString(num, buffer);
400 Handle<String> name =
401 isolate->factory()->NewStringFromAscii(CStrVector(str));
402 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
403 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 // If setting the property on the boilerplate throws an
406 // exception, the exception is converted to an empty handle in
407 // the handle based operations. In that case, we need to
408 // convert back to an exception.
409 if (result.is_null()) return result;
410 }
411
412 // Transform to fast properties if necessary. For object literals with
413 // containing function literals we defer this operation until after all
414 // computed properties have been assigned so that we can generate
415 // constant function properties.
416 if (should_transform && !has_function_literal) {
417 TransformToFastProperties(boilerplate,
418 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419 }
420
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000422}
423
424
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000425static const int kSmiOnlyLiteralMinimumLength = 1024;
426
427
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000428static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000430 Handle<FixedArray> literals,
431 Handle<FixedArray> elements) {
432 // Create the JSArray.
433 Handle<JSFunction> constructor(
434 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000435 Handle<JSArray> object =
436 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000437
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000438 ElementsKind constant_elements_kind =
439 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
440 Handle<FixedArrayBase> constant_elements_values(
441 FixedArrayBase::cast(elements->get(1)));
442
443 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
444 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
445 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
446 constant_elements_kind > object->GetElementsKind();
447
448 if (!FLAG_smi_only_arrays &&
449 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
450 constant_elements_kind != object->GetElementsKind()) {
451 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000452 }
453
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000454 // If the ElementsKind of the constant values of the array literal are less
455 // specific than the ElementsKind of the boilerplate array object, change the
456 // boilerplate array object's map to reflect that kind.
457 if (allow_literal_kind_transition) {
458 Handle<Map> transitioned_array_map =
459 isolate->factory()->GetElementsTransitionMap(object,
460 constant_elements_kind);
461 object->set_map(*transitioned_array_map);
462 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 Handle<FixedArrayBase> copied_elements_values;
465 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
466 ASSERT(FLAG_smi_only_arrays);
467 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
468 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000469 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000470 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
471 constant_elements_kind == FAST_ELEMENTS);
472 const bool is_cow =
473 (constant_elements_values->map() ==
474 isolate->heap()->fixed_cow_array_map());
475 if (is_cow) {
476 copied_elements_values = constant_elements_values;
477#if DEBUG
478 Handle<FixedArray> fixed_array_values =
479 Handle<FixedArray>::cast(copied_elements_values);
480 for (int i = 0; i < fixed_array_values->length(); i++) {
481 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
482 }
483#endif
484 } else {
485 Handle<FixedArray> fixed_array_values =
486 Handle<FixedArray>::cast(constant_elements_values);
487 Handle<FixedArray> fixed_array_values_copy =
488 isolate->factory()->CopyFixedArray(fixed_array_values);
489 copied_elements_values = fixed_array_values_copy;
490 for (int i = 0; i < fixed_array_values->length(); i++) {
491 Object* current = fixed_array_values->get(i);
492 if (current->IsFixedArray()) {
493 // The value contains the constant_properties of a
494 // simple object or array literal.
495 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
496 Handle<Object> result =
497 CreateLiteralBoilerplate(isolate, literals, fa);
498 if (result.is_null()) return result;
499 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000500 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000501 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000502 }
503 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000504 object->set_elements(*copied_elements_values);
505 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000506 return object;
507}
508
509
510static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000511 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 Handle<FixedArray> literals,
513 Handle<FixedArray> array) {
514 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000515 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000517 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 return CreateObjectLiteralBoilerplate(isolate,
519 literals,
520 elements,
521 true,
522 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000523 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 return CreateObjectLiteralBoilerplate(isolate,
525 literals,
526 elements,
527 false,
528 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000529 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000531 default:
532 UNREACHABLE();
533 return Handle<Object>::null();
534 }
535}
536
537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000538RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000539 // Takes a FixedArray of elements containing the literal elements of
540 // the array literal and produces JSArray with those elements.
541 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000542 // which contains the context from which to get the Array function
543 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000545 ASSERT(args.length() == 3);
546 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000547 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000548 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 Handle<Object> object =
551 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000552 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000554 // Update the functions literal and return the boilerplate.
555 literals->set(literals_index, *object);
556 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557}
558
559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000560RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000561 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000562 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000563 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000564 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000566 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
568 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569
570 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 Handle<Object> boilerplate(literals->get(literals_index), isolate);
572 if (*boilerplate == isolate->heap()->undefined_value()) {
573 boilerplate = CreateObjectLiteralBoilerplate(isolate,
574 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000575 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 should_have_fast_elements,
577 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 if (boilerplate.is_null()) return Failure::Exception();
579 // Update the functions literal and return the boilerplate.
580 literals->set(literals_index, *boilerplate);
581 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000583}
584
585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000586RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000588 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000590 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000591 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000592 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
594 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000595
596 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 Handle<Object> boilerplate(literals->get(literals_index), isolate);
598 if (*boilerplate == isolate->heap()->undefined_value()) {
599 boilerplate = CreateObjectLiteralBoilerplate(isolate,
600 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000601 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 should_have_fast_elements,
603 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000604 if (boilerplate.is_null()) return Failure::Exception();
605 // Update the functions literal and return the boilerplate.
606 literals->set(literals_index, *boilerplate);
607 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000609}
610
611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000612RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614 ASSERT(args.length() == 3);
615 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000616 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000617 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
618
619 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 Handle<Object> boilerplate(literals->get(literals_index), isolate);
621 if (*boilerplate == isolate->heap()->undefined_value()) {
622 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 if (boilerplate.is_null()) return Failure::Exception();
624 // Update the functions literal and return the boilerplate.
625 literals->set(literals_index, *boilerplate);
626 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000628}
629
630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000631RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633 ASSERT(args.length() == 3);
634 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000635 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000636 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
637
638 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 Handle<Object> boilerplate(literals->get(literals_index), isolate);
640 if (*boilerplate == isolate->heap()->undefined_value()) {
641 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000642 if (boilerplate.is_null()) return Failure::Exception();
643 // Update the functions literal and return the boilerplate.
644 literals->set(literals_index, *boilerplate);
645 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000646 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000648 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000649 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000650 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000651}
652
653
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000654RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
655 ASSERT(args.length() == 2);
656 Object* handler = args[0];
657 Object* prototype = args[1];
658 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000659 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000660 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
661}
662
663
lrn@chromium.org34e60782011-09-15 07:25:40 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
665 ASSERT(args.length() == 4);
666 Object* handler = args[0];
667 Object* call_trap = args[1];
668 Object* construct_trap = args[2];
669 Object* prototype = args[3];
670 Object* used_prototype =
671 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
672 return isolate->heap()->AllocateJSFunctionProxy(
673 handler, call_trap, construct_trap, used_prototype);
674}
675
676
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000677RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
678 ASSERT(args.length() == 1);
679 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000680 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000681}
682
683
lrn@chromium.org34e60782011-09-15 07:25:40 +0000684RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
685 ASSERT(args.length() == 1);
686 Object* obj = args[0];
687 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
688}
689
690
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
692 ASSERT(args.length() == 1);
693 CONVERT_CHECKED(JSProxy, proxy, args[0]);
694 return proxy->handler();
695}
696
697
lrn@chromium.org34e60782011-09-15 07:25:40 +0000698RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
699 ASSERT(args.length() == 1);
700 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
701 return proxy->call_trap();
702}
703
704
705RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
706 ASSERT(args.length() == 1);
707 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
708 return proxy->construct_trap();
709}
710
711
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000712RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
713 ASSERT(args.length() == 1);
714 CONVERT_CHECKED(JSProxy, proxy, args[0]);
715 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000716 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000717}
718
719
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000720RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
721 HandleScope scope(isolate);
722 ASSERT(args.length() == 1);
723 CONVERT_ARG_CHECKED(JSSet, holder, 0);
724 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
725 holder->set_table(*table);
726 return *holder;
727}
728
729
730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 2);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 Handle<Object> key(args[1]);
735 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
736 table = ObjectHashSetAdd(table, key);
737 holder->set_table(*table);
738 return isolate->heap()->undefined_symbol();
739}
740
741
742RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
743 HandleScope scope(isolate);
744 ASSERT(args.length() == 2);
745 CONVERT_ARG_CHECKED(JSSet, holder, 0);
746 Handle<Object> key(args[1]);
747 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
748 return isolate->heap()->ToBoolean(table->Contains(*key));
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
755 CONVERT_ARG_CHECKED(JSSet, holder, 0);
756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 table = ObjectHashSetRemove(table, key);
759 holder->set_table(*table);
760 return isolate->heap()->undefined_symbol();
761}
762
763
764RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
765 HandleScope scope(isolate);
766 ASSERT(args.length() == 1);
767 CONVERT_ARG_CHECKED(JSMap, holder, 0);
768 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
769 holder->set_table(*table);
770 return *holder;
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 2);
777 CONVERT_ARG_CHECKED(JSMap, holder, 0);
778 Handle<Object> key(args[1]);
779 return ObjectHashTable::cast(holder->table())->Lookup(*key);
780}
781
782
783RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
784 HandleScope scope(isolate);
785 ASSERT(args.length() == 3);
786 CONVERT_ARG_CHECKED(JSMap, holder, 0);
787 Handle<Object> key(args[1]);
788 Handle<Object> value(args[2]);
789 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
790 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
791 holder->set_table(*new_table);
792 return *value;
793}
794
795
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000796RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
797 HandleScope scope(isolate);
798 ASSERT(args.length() == 1);
799 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
800 ASSERT(weakmap->map()->inobject_properties() == 0);
801 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
802 weakmap->set_table(*table);
803 weakmap->set_next(Smi::FromInt(0));
804 return *weakmap;
805}
806
807
808RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
809 NoHandleAllocation ha;
810 ASSERT(args.length() == 2);
811 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000812 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
813 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000814}
815
816
817RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
818 HandleScope scope(isolate);
819 ASSERT(args.length() == 3);
820 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000821 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000822 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000823 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
825 weakmap->set_table(*new_table);
826 return *value;
827}
828
829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000830RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831 NoHandleAllocation ha;
832 ASSERT(args.length() == 1);
833 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000834 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835 return JSObject::cast(obj)->class_name();
836}
837
ager@chromium.org7c537e22008-10-16 08:43:32 +0000838
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000839RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
840 NoHandleAllocation ha;
841 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000842 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
843 Object* obj = input_obj;
844 // We don't expect access checks to be needed on JSProxy objects.
845 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000846 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000847 if (obj->IsAccessCheckNeeded() &&
848 !isolate->MayNamedAccess(JSObject::cast(obj),
849 isolate->heap()->Proto_symbol(),
850 v8::ACCESS_GET)) {
851 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
852 return isolate->heap()->undefined_value();
853 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000854 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000855 } while (obj->IsJSObject() &&
856 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000857 return obj;
858}
859
860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000861RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862 NoHandleAllocation ha;
863 ASSERT(args.length() == 2);
864 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
865 Object* O = args[0];
866 Object* V = args[1];
867 while (true) {
868 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000869 if (prototype->IsNull()) return isolate->heap()->false_value();
870 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 V = prototype;
872 }
873}
874
875
ager@chromium.org9085a012009-05-11 19:22:57 +0000876// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000877RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000878 NoHandleAllocation ha;
879 ASSERT(args.length() == 2);
880 CONVERT_CHECKED(JSObject, jsobject, args[0]);
881 CONVERT_CHECKED(JSObject, proto, args[1]);
882
883 // Sanity checks. The old prototype (that we are replacing) could
884 // theoretically be null, but if it is not null then check that we
885 // didn't already install a hidden prototype here.
886 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
887 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
888 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
889
890 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000891 Object* map_or_failure;
892 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
893 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
894 return maybe_map_or_failure;
895 }
896 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000897 Map* new_proto_map = Map::cast(map_or_failure);
898
lrn@chromium.org303ada72010-10-27 09:33:13 +0000899 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
900 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
901 return maybe_map_or_failure;
902 }
903 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000904 Map* new_map = Map::cast(map_or_failure);
905
906 // Set proto's prototype to be the old prototype of the object.
907 new_proto_map->set_prototype(jsobject->GetPrototype());
908 proto->set_map(new_proto_map);
909 new_proto_map->set_is_hidden_prototype();
910
911 // Set the object's prototype to proto.
912 new_map->set_prototype(proto);
913 jsobject->set_map(new_map);
914
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000915 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000916}
917
918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000919RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000921 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000922 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000923 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924}
925
926
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000927// Recursively traverses hidden prototypes if property is not found
928static void GetOwnPropertyImplementation(JSObject* obj,
929 String* name,
930 LookupResult* result) {
931 obj->LocalLookupRealNamedProperty(name, result);
932
933 if (!result->IsProperty()) {
934 Object* proto = obj->GetPrototype();
935 if (proto->IsJSObject() &&
936 JSObject::cast(proto)->map()->is_hidden_prototype())
937 GetOwnPropertyImplementation(JSObject::cast(proto),
938 name, result);
939 }
940}
941
942
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000943static bool CheckAccessException(LookupResult* result,
944 v8::AccessType access_type) {
945 if (result->type() == CALLBACKS) {
946 Object* callback = result->GetCallbackObject();
947 if (callback->IsAccessorInfo()) {
948 AccessorInfo* info = AccessorInfo::cast(callback);
949 bool can_access =
950 (access_type == v8::ACCESS_HAS &&
951 (info->all_can_read() || info->all_can_write())) ||
952 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
953 (access_type == v8::ACCESS_SET && info->all_can_write());
954 return can_access;
955 }
956 }
957
958 return false;
959}
960
961
962static bool CheckAccess(JSObject* obj,
963 String* name,
964 LookupResult* result,
965 v8::AccessType access_type) {
966 ASSERT(result->IsProperty());
967
968 JSObject* holder = result->holder();
969 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000970 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000971 while (true) {
972 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000973 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000974 // Access check callback denied the access, but some properties
975 // can have a special permissions which override callbacks descision
976 // (currently see v8::AccessControl).
977 break;
978 }
979
980 if (current == holder) {
981 return true;
982 }
983
984 current = JSObject::cast(current->GetPrototype());
985 }
986
987 // API callbacks can have per callback access exceptions.
988 switch (result->type()) {
989 case CALLBACKS: {
990 if (CheckAccessException(result, access_type)) {
991 return true;
992 }
993 break;
994 }
995 case INTERCEPTOR: {
996 // If the object has an interceptor, try real named properties.
997 // Overwrite the result to fetch the correct property later.
998 holder->LookupRealNamedProperty(name, result);
999 if (result->IsProperty()) {
1000 if (CheckAccessException(result, access_type)) {
1001 return true;
1002 }
1003 }
1004 break;
1005 }
1006 default:
1007 break;
1008 }
1009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001011 return false;
1012}
1013
1014
1015// TODO(1095): we should traverse hidden prototype hierachy as well.
1016static bool CheckElementAccess(JSObject* obj,
1017 uint32_t index,
1018 v8::AccessType access_type) {
1019 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 return false;
1022 }
1023
1024 return true;
1025}
1026
1027
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001028// Enumerator used as indices into the array returned from GetOwnProperty
1029enum PropertyDescriptorIndices {
1030 IS_ACCESSOR_INDEX,
1031 VALUE_INDEX,
1032 GETTER_INDEX,
1033 SETTER_INDEX,
1034 WRITABLE_INDEX,
1035 ENUMERABLE_INDEX,
1036 CONFIGURABLE_INDEX,
1037 DESCRIPTOR_SIZE
1038};
1039
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001040// Returns an array with the property description:
1041// if args[1] is not a property on args[0]
1042// returns undefined
1043// if args[1] is a data property on args[0]
1044// [false, value, Writeable, Enumerable, Configurable]
1045// if args[1] is an accessor on args[0]
1046// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001047RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001048 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 Heap* heap = isolate->heap();
1050 HandleScope scope(isolate);
1051 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1052 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001053 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001054 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1055 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001056
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001057 // This could be an element.
1058 uint32_t index;
1059 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001060 switch (obj->HasLocalElement(index)) {
1061 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001062 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001063
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001064 case JSObject::STRING_CHARACTER_ELEMENT: {
1065 // Special handling of string objects according to ECMAScript 5
1066 // 15.5.5.2. Note that this might be a string object with elements
1067 // other than the actual string value. This is covered by the
1068 // subsequent cases.
1069 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1070 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001071 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001073 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001074 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075 elms->set(WRITABLE_INDEX, heap->false_value());
1076 elms->set(ENUMERABLE_INDEX, heap->false_value());
1077 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001078 return *desc;
1079 }
1080
1081 case JSObject::INTERCEPTED_ELEMENT:
1082 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001084 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001086 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 elms->set(WRITABLE_INDEX, heap->true_value());
1088 elms->set(ENUMERABLE_INDEX, heap->true_value());
1089 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 return *desc;
1091 }
1092
1093 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001094 Handle<JSObject> holder = obj;
1095 if (obj->IsJSGlobalProxy()) {
1096 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001098 ASSERT(proto->IsJSGlobalObject());
1099 holder = Handle<JSObject>(JSObject::cast(proto));
1100 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001101 FixedArray* elements = FixedArray::cast(holder->elements());
1102 NumberDictionary* dictionary = NULL;
1103 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1104 dictionary = NumberDictionary::cast(elements->get(1));
1105 } else {
1106 dictionary = NumberDictionary::cast(elements);
1107 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001108 int entry = dictionary->FindEntry(index);
1109 ASSERT(entry != NumberDictionary::kNotFound);
1110 PropertyDetails details = dictionary->DetailsAt(entry);
1111 switch (details.type()) {
1112 case CALLBACKS: {
1113 // This is an accessor property with getter and/or setter.
1114 FixedArray* callbacks =
1115 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001116 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1118 elms->set(GETTER_INDEX, callbacks->get(0));
1119 }
1120 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1121 elms->set(SETTER_INDEX, callbacks->get(1));
1122 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001123 break;
1124 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001125 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001126 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001127 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001128 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001129 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001130 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001132 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001133 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001134 default:
1135 UNREACHABLE();
1136 break;
1137 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001138 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1139 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001140 return *desc;
1141 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001142 }
1143 }
1144
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001145 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001146 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001147
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001148 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001149 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001150 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001151
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001152 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001153 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001154 }
1155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001156 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1157 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001158
1159 bool is_js_accessor = (result.type() == CALLBACKS) &&
1160 (result.GetCallbackObject()->IsFixedArray());
1161
1162 if (is_js_accessor) {
1163 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001164 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001165
1166 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1167 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1168 elms->set(GETTER_INDEX, structure->get(0));
1169 }
1170 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1171 elms->set(SETTER_INDEX, structure->get(1));
1172 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001173 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001174 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1175 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001176
1177 PropertyAttributes attrs;
1178 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001179 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001180 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1181 if (!maybe_value->ToObject(&value)) return maybe_value;
1182 }
1183 elms->set(VALUE_INDEX, value);
1184 }
1185
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001186 return *desc;
1187}
1188
1189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001190RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001191 ASSERT(args.length() == 1);
1192 CONVERT_CHECKED(JSObject, obj, args[0]);
1193 return obj->PreventExtensions();
1194}
1195
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001197RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001198 ASSERT(args.length() == 1);
1199 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001200 if (obj->IsJSGlobalProxy()) {
1201 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001202 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001203 ASSERT(proto->IsJSGlobalObject());
1204 obj = JSObject::cast(proto);
1205 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001206 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001207}
1208
1209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001210RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001211 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001213 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1214 CONVERT_ARG_CHECKED(String, pattern, 1);
1215 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001216 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1217 if (result.is_null()) return Failure::Exception();
1218 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001223 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001224 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001225 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001226 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227}
1228
1229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001230RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231 ASSERT(args.length() == 1);
1232 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001233 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001234 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235}
1236
1237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001238RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239 ASSERT(args.length() == 2);
1240 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001242 int index = field->value();
1243 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1244 InstanceType type = templ->map()->instance_type();
1245 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1246 type == OBJECT_TEMPLATE_INFO_TYPE);
1247 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001248 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001249 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1250 } else {
1251 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1252 }
1253 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254}
1255
1256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001257RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001258 ASSERT(args.length() == 1);
1259 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001260 Map* old_map = object->map();
1261 bool needs_access_checks = old_map->is_access_check_needed();
1262 if (needs_access_checks) {
1263 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001264 Object* new_map;
1265 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1266 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1267 }
ager@chromium.org32912102009-01-16 10:38:43 +00001268
1269 Map::cast(new_map)->set_is_access_check_needed(false);
1270 object->set_map(Map::cast(new_map));
1271 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001272 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001273}
1274
1275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001276RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001277 ASSERT(args.length() == 1);
1278 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001279 Map* old_map = object->map();
1280 if (!old_map->is_access_check_needed()) {
1281 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001282 Object* new_map;
1283 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1284 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1285 }
ager@chromium.org32912102009-01-16 10:38:43 +00001286
1287 Map::cast(new_map)->set_is_access_check_needed(true);
1288 object->set_map(Map::cast(new_map));
1289 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001291}
1292
1293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001294static Failure* ThrowRedeclarationError(Isolate* isolate,
1295 const char* type,
1296 Handle<String> name) {
1297 HandleScope scope(isolate);
1298 Handle<Object> type_handle =
1299 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 Handle<Object> args[2] = { type_handle, name };
1301 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1303 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304}
1305
1306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001307RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001308 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 HandleScope scope(isolate);
1310 Handle<GlobalObject> global = Handle<GlobalObject>(
1311 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
ager@chromium.org3811b432009-10-28 14:53:37 +00001313 Handle<Context> context = args.at<Context>(0);
1314 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001315 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 // Traverse the name/value pairs and set the properties.
1318 int length = pairs->length();
1319 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001320 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001322 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323
1324 // We have to declare a global const property. To capture we only
1325 // assign to it when evaluating the assignment for "const x =
1326 // <expr>" the initial value is the hole.
1327 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001328 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 if (value->IsUndefined() || is_const_property) {
1330 // Lookup the property in the global object, and don't set the
1331 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001332 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333 global->Lookup(*name, &lookup);
1334 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001335 // We found an existing property. Unless it was an interceptor
1336 // that claims the property is absent, skip this declaration.
1337 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 continue;
1339 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001340 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1341 if (attributes != ABSENT) {
1342 continue;
1343 }
1344 // Fall-through and introduce the absent property by using
1345 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346 }
1347 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001348 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001350 Handle<SharedFunctionInfo> shared =
1351 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1354 context,
1355 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 value = function;
1357 }
1358
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001359 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 global->LocalLookup(*name, &lookup);
1361
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001362 // Compute the property attributes. According to ECMA-262, section
1363 // 13, page 71, the property must be read-only and
1364 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1365 // property as read-only, so we don't either.
1366 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001367 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001368 attr |= DONT_DELETE;
1369 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001370 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001371 if (is_const_property || (is_native && is_function_declaration)) {
1372 attr |= READ_ONLY;
1373 }
1374
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001375 // Safari does not allow the invocation of callback setters for
1376 // function declarations. To mimic this behavior, we do not allow
1377 // the invocation of setters for function values. This makes a
1378 // difference for global functions with the same names as event
1379 // handlers such as "function onload() {}". Firefox does call the
1380 // onload setter in those case and Safari does not. We follow
1381 // Safari for compatibility.
1382 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001383 // Do not change DONT_DELETE to false from true.
1384 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001385 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001386 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001387 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1388
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001389 RETURN_IF_EMPTY_HANDLE(isolate,
1390 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001391 name,
1392 value,
1393 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001394 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001395 StrictModeFlag strict_mode = DeclareGlobalsStrictModeFlag::decode(flags);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001396 RETURN_IF_EMPTY_HANDLE(isolate,
1397 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001398 name,
1399 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001400 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001401 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 }
1403 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 ASSERT(!isolate->has_pending_exception());
1406 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407}
1408
1409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001410RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001411 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001412 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001414 // Declarations are always made in a function or global context. In the
1415 // case of eval code, the context passed is the context of the caller,
1416 // which may be some nested context and not the declaration context.
1417 RUNTIME_ASSERT(args[0]->IsContext());
1418 Handle<Context> context(Context::cast(args[0])->declaration_context());
1419
ager@chromium.org7c537e22008-10-16 08:43:32 +00001420 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001421 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001422 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001423 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 int index;
1426 PropertyAttributes attributes;
1427 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001428 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001429 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001430 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431
1432 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001433 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1435 // Functions are not read-only.
1436 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1437 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439 }
1440
1441 // Initialize it if necessary.
1442 if (*initial_value != NULL) {
1443 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001444 ASSERT(holder.is_identical_to(context));
1445 if (((attributes & READ_ONLY) == 0) ||
1446 context->get(index)->IsTheHole()) {
1447 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001448 }
1449 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001450 // Slow case: The property is in the context extension object of a
1451 // function context or the global object of a global context.
1452 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001453 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001454 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001455 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 }
1457 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001460 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001461 // "declared" in the function context's extension context or as a
1462 // property of the the global object.
1463 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001464 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001466 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001467 // Context extension objects are allocated lazily.
1468 ASSERT(context->IsFunctionContext());
1469 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001470 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001471 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001472 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001473 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474
ager@chromium.org7c537e22008-10-16 08:43:32 +00001475 // Declare the property by setting it to the initial value if provided,
1476 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1477 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001478 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001479 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001480 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001481 // Declaring a const context slot is a conflicting declaration if
1482 // there is a callback with that name in a prototype. It is
1483 // allowed to introduce const variables in
1484 // JSContextExtensionObjects. They are treated specially in
1485 // SetProperty and no setters are invoked for those since they are
1486 // not real JSObjects.
1487 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001488 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001489 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001490 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001491 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001492 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001493 }
1494 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001495 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001497 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001498 }
1499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001500 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501}
1502
1503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001504RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001505 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001506 // args[0] == name
1507 // args[1] == strict_mode
1508 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509
1510 // Determine if we need to assign to the variable if it already
1511 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001512 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1513 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514
1515 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001516 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001517 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001518 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001519 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520
1521 // According to ECMA-262, section 12.2, page 62, the property must
1522 // not be deletable.
1523 PropertyAttributes attributes = DONT_DELETE;
1524
1525 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001526 // there, there is a property with this name in the prototype chain.
1527 // We follow Safari and Firefox behavior and only set the property
1528 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001529 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001530 // Note that objects can have hidden prototypes, so we need to traverse
1531 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001532 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001533 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001534 while (object->IsJSObject() &&
1535 JSObject::cast(object)->map()->is_hidden_prototype()) {
1536 JSObject* raw_holder = JSObject::cast(object);
1537 raw_holder->LocalLookup(*name, &lookup);
1538 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1539 HandleScope handle_scope(isolate);
1540 Handle<JSObject> holder(raw_holder);
1541 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1542 // Update the raw pointer in case it's changed due to GC.
1543 raw_holder = *holder;
1544 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1545 // Found an interceptor that's not read only.
1546 if (assign) {
1547 return raw_holder->SetProperty(
1548 &lookup, *name, args[2], attributes, strict_mode);
1549 } else {
1550 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001551 }
1552 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001553 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001554 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 }
1556
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001557 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001559 if (assign) {
1560 return global->SetProperty(*name, args[2], attributes, strict_mode);
1561 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001562 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563}
1564
1565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001566RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567 // All constants are declared with an initial value. The name
1568 // of the constant is the first argument and the initial value
1569 // is the second.
1570 RUNTIME_ASSERT(args.length() == 2);
1571 CONVERT_ARG_CHECKED(String, name, 0);
1572 Handle<Object> value = args.at<Object>(1);
1573
1574 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001575 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576
1577 // According to ECMA-262, section 12.2, page 62, the property must
1578 // not be deletable. Since it's a const, it must be READ_ONLY too.
1579 PropertyAttributes attributes =
1580 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1581
1582 // Lookup the property locally in the global object. If it isn't
1583 // there, we add the property and take special precautions to always
1584 // add it as a local property even in case of callbacks in the
1585 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001586 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001587 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 global->LocalLookup(*name, &lookup);
1589 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001590 return global->SetLocalPropertyIgnoreAttributes(*name,
1591 *value,
1592 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001593 }
1594
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001596 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001597 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 HandleScope handle_scope(isolate);
1599 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001601 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 // property through an interceptor and only do it if it's
1603 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001604 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001605 RETURN_IF_EMPTY_HANDLE(isolate,
1606 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001607 name,
1608 value,
1609 attributes,
1610 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 return *value;
1612 }
1613
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 // constant. For now, we determine this by checking if the
1616 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001617 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618 PropertyType type = lookup.type();
1619 if (type == FIELD) {
1620 FixedArray* properties = global->properties();
1621 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001622 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623 properties->set(index, *value);
1624 }
1625 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001626 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1627 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001628 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629 }
1630 } else {
1631 // Ignore re-initialization of constants that have already been
1632 // assigned a function value.
1633 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1634 }
1635
1636 // Use the set value as the result of the operation.
1637 return *value;
1638}
1639
1640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001641RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001642 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643 ASSERT(args.length() == 3);
1644
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001646 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001648 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001649 RUNTIME_ASSERT(args[1]->IsContext());
1650 Handle<Context> context(Context::cast(args[1])->declaration_context());
1651
1652 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001653
1654 int index;
1655 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001656 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001657 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001658 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001659 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001660
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001661 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001662 ASSERT(holder->IsContext());
1663 // Property was found in a context. Perform the assignment if we
1664 // found some non-constant or an uninitialized constant.
1665 Handle<Context> context = Handle<Context>::cast(holder);
1666 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1667 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001668 }
1669 return *value;
1670 }
1671
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001672 // The property could not be found, we introduce it as a property of the
1673 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001674 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001675 Handle<JSObject> global = Handle<JSObject>(
1676 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001677 // Strict mode not needed (const disallowed in strict mode).
1678 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001680 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001681 return *value;
1682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001684 // The property was present in some function's context extension object,
1685 // as a property on the subject of a with, or as a property of the global
1686 // object.
1687 //
1688 // In most situations, eval-introduced consts should still be present in
1689 // the context extension object. However, because declaration and
1690 // initialization are separate, the property might have been deleted
1691 // before we reach the initialization point.
1692 //
1693 // Example:
1694 //
1695 // function f() { eval("delete x; const x;"); }
1696 //
1697 // In that case, the initialization behaves like a normal assignment.
1698 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001700 if (*object == context->extension()) {
1701 // This is the property that was introduced by the const declaration.
1702 // Set it if it hasn't been set before. NOTE: We cannot use
1703 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001704 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001705 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001706 ASSERT(lookup.IsProperty()); // the property was declared
1707 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1708
1709 PropertyType type = lookup.type();
1710 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001711 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001712 int index = lookup.GetFieldIndex();
1713 if (properties->get(index)->IsTheHole()) {
1714 properties->set(index, *value);
1715 }
1716 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001717 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1718 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001719 }
1720 } else {
1721 // We should not reach here. Any real, named property should be
1722 // either a field or a dictionary slot.
1723 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001724 }
1725 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001726 // The property was found on some other object. Set it if it is not a
1727 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001728 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001729 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001730 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001732 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001733 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001734 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001735
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001736 return *value;
1737}
1738
1739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740RUNTIME_FUNCTION(MaybeObject*,
1741 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001743 ASSERT(args.length() == 2);
1744 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001745 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001746 if (object->HasFastProperties()) {
1747 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1748 }
1749 return *object;
1750}
1751
1752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001753RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001755 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001756 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1757 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001758 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001759 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001760 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001761 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001762 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001763 RUNTIME_ASSERT(index >= 0);
1764 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001765 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001766 Handle<Object> result = RegExpImpl::Exec(regexp,
1767 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001768 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001769 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001770 if (result.is_null()) return Failure::Exception();
1771 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772}
1773
1774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001775RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001776 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001777 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001778 if (elements_count < 0 ||
1779 elements_count > FixedArray::kMaxLength ||
1780 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001781 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001782 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001783 Object* new_object;
1784 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001785 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001786 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1787 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001788 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1790 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001791 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1792 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001793 {
1794 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001796 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001797 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001798 }
1799 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001800 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001801 array->set_elements(elements);
1802 array->set_length(Smi::FromInt(elements_count));
1803 // Write in-object properties after the length of the array.
1804 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1805 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1806 return array;
1807}
1808
1809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001810RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001811 AssertNoAllocation no_alloc;
1812 ASSERT(args.length() == 5);
1813 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1814 CONVERT_CHECKED(String, source, args[1]);
1815
1816 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001818
1819 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001820 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821
1822 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001823 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001824
1825 Map* map = regexp->map();
1826 Object* constructor = map->constructor();
1827 if (constructor->IsJSFunction() &&
1828 JSFunction::cast(constructor)->initial_map() == map) {
1829 // If we still have the original map, set in-object properties directly.
1830 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1831 // TODO(lrn): Consider skipping write barrier on booleans as well.
1832 // Both true and false should be in oldspace at all times.
1833 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1834 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1835 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1836 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1837 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001838 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001839 return regexp;
1840 }
1841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001842 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001843 PropertyAttributes final =
1844 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1845 PropertyAttributes writable =
1846 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001847 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001848 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001850 source,
1851 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001852 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001854 global,
1855 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001856 ASSERT(!result->IsFailure());
1857 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001859 ignoreCase,
1860 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001861 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001863 multiline,
1864 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001865 ASSERT(!result->IsFailure());
1866 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001868 Smi::FromInt(0),
1869 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001870 ASSERT(!result->IsFailure());
1871 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001872 return regexp;
1873}
1874
1875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001876RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001877 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001878 ASSERT(args.length() == 1);
1879 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1880 // This is necessary to enable fast checks for absence of elements
1881 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001882 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001883 return Smi::FromInt(0);
1884}
1885
1886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001887static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1888 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001889 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001890 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001891 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1892 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1893 Handle<JSFunction> optimized =
1894 isolate->factory()->NewFunction(key,
1895 JS_OBJECT_TYPE,
1896 JSObject::kHeaderSize,
1897 code,
1898 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001899 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001900 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001901 return optimized;
1902}
1903
1904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001905RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001906 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001907 ASSERT(args.length() == 1);
1908 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1909
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001910 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1911 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1912 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1913 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1914 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1915 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1916 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001917
1918 return *holder;
1919}
1920
1921
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001922RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1923 NoHandleAllocation handle_free;
1924 ASSERT(args.length() == 1);
1925 CONVERT_CHECKED(JSFunction, function, args[0]);
1926 SharedFunctionInfo* shared = function->shared();
1927 if (shared->native() || shared->strict_mode()) {
1928 return isolate->heap()->undefined_value();
1929 }
1930 // Returns undefined for strict or native functions, or
1931 // the associated global receiver for "normal" functions.
1932
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001933 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001934 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001935 return global_context->global()->global_receiver();
1936}
1937
1938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001939RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001940 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 ASSERT(args.length() == 4);
1942 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001943 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001944 Handle<String> pattern = args.at<String>(2);
1945 Handle<String> flags = args.at<String>(3);
1946
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001947 // Get the RegExp function from the context in the literals array.
1948 // This is the RegExp function from the context in which the
1949 // function was created. We do not use the RegExp function from the
1950 // current global context because this might be the RegExp function
1951 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001952 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001953 Handle<JSFunction>(
1954 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001955 // Compute the regular expression literal.
1956 bool has_pending_exception;
1957 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001958 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1959 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001961 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 return Failure::Exception();
1963 }
1964 literals->set(index, *regexp);
1965 return *regexp;
1966}
1967
1968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001969RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001970 NoHandleAllocation ha;
1971 ASSERT(args.length() == 1);
1972
1973 CONVERT_CHECKED(JSFunction, f, args[0]);
1974 return f->shared()->name();
1975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001979 NoHandleAllocation ha;
1980 ASSERT(args.length() == 2);
1981
1982 CONVERT_CHECKED(JSFunction, f, args[0]);
1983 CONVERT_CHECKED(String, name, args[1]);
1984 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001986}
1987
1988
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001989RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1990 NoHandleAllocation ha;
1991 ASSERT(args.length() == 1);
1992 CONVERT_CHECKED(JSFunction, f, args[0]);
1993 return isolate->heap()->ToBoolean(
1994 f->shared()->name_should_print_as_anonymous());
1995}
1996
1997
1998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1999 NoHandleAllocation ha;
2000 ASSERT(args.length() == 1);
2001 CONVERT_CHECKED(JSFunction, f, args[0]);
2002 f->shared()->set_name_should_print_as_anonymous(true);
2003 return isolate->heap()->undefined_value();
2004}
2005
2006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002007RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002008 NoHandleAllocation ha;
2009 ASSERT(args.length() == 1);
2010
2011 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 Object* obj = f->RemovePrototype();
2013 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002014
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002015 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002016}
2017
2018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002019RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002020 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 ASSERT(args.length() == 1);
2022
2023 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002024 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2025 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026
2027 return *GetScriptWrapper(Handle<Script>::cast(script));
2028}
2029
2030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002031RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002032 NoHandleAllocation ha;
2033 ASSERT(args.length() == 1);
2034
2035 CONVERT_CHECKED(JSFunction, f, args[0]);
2036 return f->shared()->GetSourceCode();
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041 NoHandleAllocation ha;
2042 ASSERT(args.length() == 1);
2043
2044 CONVERT_CHECKED(JSFunction, fun, args[0]);
2045 int pos = fun->shared()->start_position();
2046 return Smi::FromInt(pos);
2047}
2048
2049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002050RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002051 ASSERT(args.length() == 2);
2052
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002053 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002054 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2055
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002056 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2057
2058 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002059 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002060}
2061
2062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002063RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064 NoHandleAllocation ha;
2065 ASSERT(args.length() == 2);
2066
2067 CONVERT_CHECKED(JSFunction, fun, args[0]);
2068 CONVERT_CHECKED(String, name, args[1]);
2069 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002070 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002071}
2072
2073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002074RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002075 NoHandleAllocation ha;
2076 ASSERT(args.length() == 2);
2077
2078 CONVERT_CHECKED(JSFunction, fun, args[0]);
2079 CONVERT_CHECKED(Smi, length, args[1]);
2080 fun->shared()->set_length(length->value());
2081 return length;
2082}
2083
2084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002085RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002086 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002087 ASSERT(args.length() == 2);
2088
2089 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002090 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002091 Object* obj;
2092 { MaybeObject* maybe_obj =
2093 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2094 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2095 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002096 return args[0]; // return TOS
2097}
2098
2099
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002100RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2101 NoHandleAllocation ha;
2102 RUNTIME_ASSERT(args.length() == 1);
2103 CONVERT_CHECKED(JSFunction, function, args[0]);
2104
2105 MaybeObject* maybe_name =
2106 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2107 String* name;
2108 if (!maybe_name->To(&name)) return maybe_name;
2109
2110 if (function->HasFastProperties()) {
2111 // Construct a new field descriptor with updated attributes.
2112 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2113 int index = instance_desc->Search(name);
2114 ASSERT(index != DescriptorArray::kNotFound);
2115 PropertyDetails details(instance_desc->GetDetails(index));
2116 CallbacksDescriptor new_desc(name,
2117 instance_desc->GetValue(index),
2118 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2119 details.index());
2120 // Construct a new field descriptors array containing the new descriptor.
2121 Object* descriptors_unchecked;
2122 { MaybeObject* maybe_descriptors_unchecked =
2123 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2124 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2125 return maybe_descriptors_unchecked;
2126 }
2127 }
2128 DescriptorArray* new_descriptors =
2129 DescriptorArray::cast(descriptors_unchecked);
2130 // Create a new map featuring the new field descriptors array.
2131 Object* map_unchecked;
2132 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2133 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2134 return maybe_map_unchecked;
2135 }
2136 }
2137 Map* new_map = Map::cast(map_unchecked);
2138 new_map->set_instance_descriptors(new_descriptors);
2139 function->set_map(new_map);
2140 } else { // Dictionary properties.
2141 // Directly manipulate the property details.
2142 int entry = function->property_dictionary()->FindEntry(name);
2143 ASSERT(entry != StringDictionary::kNotFound);
2144 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2145 PropertyDetails new_details(
2146 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2147 details.type(),
2148 details.index());
2149 function->property_dictionary()->DetailsAtPut(entry, new_details);
2150 }
2151 return function;
2152}
2153
2154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002155RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002156 NoHandleAllocation ha;
2157 ASSERT(args.length() == 1);
2158
2159 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002160 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002161}
2162
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002164RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002165 NoHandleAllocation ha;
2166 ASSERT(args.length() == 1);
2167
2168 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002169 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002170}
2171
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002173RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002174 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002175 ASSERT(args.length() == 2);
2176
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002177 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002178 Handle<Object> code = args.at<Object>(1);
2179
2180 Handle<Context> context(target->context());
2181
2182 if (!code->IsNull()) {
2183 RUNTIME_ASSERT(code->IsJSFunction());
2184 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002185 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002186
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002187 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002188 return Failure::Exception();
2189 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002190 // Since we don't store the source for this we should never
2191 // optimize this.
2192 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002193 // Set the code, scope info, formal parameter count,
2194 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002195 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002196 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002197 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002198 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002200 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002201 // Set the source code of the target function to undefined.
2202 // SetCode is only used for built-in constructors like String,
2203 // Array, and Object, and some web code
2204 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002206 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002207 // Clear the optimization hints related to the compiled code as these are no
2208 // longer valid when the code is overwritten.
2209 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002210 context = Handle<Context>(fun->context());
2211
2212 // Make sure we get a fresh copy of the literal vector to avoid
2213 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002214 int number_of_literals = fun->NumberOfLiterals();
2215 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002216 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002218 // Insert the object, regexp and array functions in the literals
2219 // array prefix. These are the functions that will be used when
2220 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002221 literals->set(JSFunction::kLiteralGlobalContextIndex,
2222 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002223 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002224 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002226
2227 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2228 isolate->logger()->LogExistingFunction(
2229 shared, Handle<Code>(shared->code()));
2230 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002231 }
2232
2233 target->set_context(*context);
2234 return *target;
2235}
2236
2237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002238RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002240 ASSERT(args.length() == 2);
2241 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002242 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002243 RUNTIME_ASSERT(num >= 0);
2244 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002245 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002246}
2247
2248
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002249MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2250 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002251 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002252 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002253 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002255 }
2256 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002257 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002258}
2259
2260
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002261RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002262 NoHandleAllocation ha;
2263 ASSERT(args.length() == 2);
2264
2265 CONVERT_CHECKED(String, subject, args[0]);
2266 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002267 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002268
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002269 uint32_t i = 0;
2270 if (index->IsSmi()) {
2271 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002273 i = value;
2274 } else {
2275 ASSERT(index->IsHeapNumber());
2276 double value = HeapNumber::cast(index)->value();
2277 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002278 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002279
2280 // Flatten the string. If someone wants to get a char at an index
2281 // in a cons string, it is likely that more indices will be
2282 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002283 Object* flat;
2284 { MaybeObject* maybe_flat = subject->TryFlatten();
2285 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2286 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002287 subject = String::cast(flat);
2288
2289 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002291 }
2292
2293 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002294}
2295
2296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002297RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002298 NoHandleAllocation ha;
2299 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002300 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002301}
2302
lrn@chromium.org25156de2010-04-06 13:10:27 +00002303
2304class FixedArrayBuilder {
2305 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002306 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2307 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002308 length_(0),
2309 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002310 // Require a non-zero initial size. Ensures that doubling the size to
2311 // extend the array will work.
2312 ASSERT(initial_capacity > 0);
2313 }
2314
2315 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2316 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002317 length_(0),
2318 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 // Require a non-zero initial size. Ensures that doubling the size to
2320 // extend the array will work.
2321 ASSERT(backing_store->length() > 0);
2322 }
2323
2324 bool HasCapacity(int elements) {
2325 int length = array_->length();
2326 int required_length = length_ + elements;
2327 return (length >= required_length);
2328 }
2329
2330 void EnsureCapacity(int elements) {
2331 int length = array_->length();
2332 int required_length = length_ + elements;
2333 if (length < required_length) {
2334 int new_length = length;
2335 do {
2336 new_length *= 2;
2337 } while (new_length < required_length);
2338 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002339 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002340 array_->CopyTo(0, *extended_array, 0, length_);
2341 array_ = extended_array;
2342 }
2343 }
2344
2345 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002346 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002347 ASSERT(length_ < capacity());
2348 array_->set(length_, value);
2349 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002350 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002351 }
2352
2353 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002354 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002355 ASSERT(length_ < capacity());
2356 array_->set(length_, value);
2357 length_++;
2358 }
2359
2360 Handle<FixedArray> array() {
2361 return array_;
2362 }
2363
2364 int length() {
2365 return length_;
2366 }
2367
2368 int capacity() {
2369 return array_->length();
2370 }
2371
2372 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002373 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002374 result_array->set_length(Smi::FromInt(length_));
2375 return result_array;
2376 }
2377
2378 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002379 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002380 target_array->set_length(Smi::FromInt(length_));
2381 return target_array;
2382 }
2383
2384 private:
2385 Handle<FixedArray> array_;
2386 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002387 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002388};
2389
2390
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002391// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002392const int kStringBuilderConcatHelperLengthBits = 11;
2393const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002394
2395template <typename schar>
2396static inline void StringBuilderConcatHelper(String*,
2397 schar*,
2398 FixedArray*,
2399 int);
2400
lrn@chromium.org25156de2010-04-06 13:10:27 +00002401typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2402 StringBuilderSubstringLength;
2403typedef BitField<int,
2404 kStringBuilderConcatHelperLengthBits,
2405 kStringBuilderConcatHelperPositionBits>
2406 StringBuilderSubstringPosition;
2407
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408
2409class ReplacementStringBuilder {
2410 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002411 ReplacementStringBuilder(Heap* heap,
2412 Handle<String> subject,
2413 int estimated_part_count)
2414 : heap_(heap),
2415 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002418 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 // Require a non-zero initial size. Ensures that doubling the size to
2420 // extend the array will work.
2421 ASSERT(estimated_part_count > 0);
2422 }
2423
lrn@chromium.org25156de2010-04-06 13:10:27 +00002424 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2425 int from,
2426 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 ASSERT(from >= 0);
2428 int length = to - from;
2429 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002430 if (StringBuilderSubstringLength::is_valid(length) &&
2431 StringBuilderSubstringPosition::is_valid(from)) {
2432 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2433 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002434 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002435 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002436 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002437 builder->Add(Smi::FromInt(-length));
2438 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002440 }
2441
2442
2443 void EnsureCapacity(int elements) {
2444 array_builder_.EnsureCapacity(elements);
2445 }
2446
2447
2448 void AddSubjectSlice(int from, int to) {
2449 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002450 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002451 }
2452
2453
2454 void AddString(Handle<String> string) {
2455 int length = string->length();
2456 ASSERT(length > 0);
2457 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002458 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 is_ascii_ = false;
2460 }
2461 IncrementCharacterCount(length);
2462 }
2463
2464
2465 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002466 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002467 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 }
2469
2470 Handle<String> joined_string;
2471 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002472 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002474 char* char_buffer = seq->GetChars();
2475 StringBuilderConcatHelper(*subject_,
2476 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002477 *array_builder_.array(),
2478 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002479 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 } else {
2481 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002482 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002483 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002484 uc16* char_buffer = seq->GetChars();
2485 StringBuilderConcatHelper(*subject_,
2486 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002487 *array_builder_.array(),
2488 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002489 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002490 }
2491 return joined_string;
2492 }
2493
2494
2495 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002496 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 V8::FatalProcessOutOfMemory("String.replace result too large.");
2498 }
2499 character_count_ += by;
2500 }
2501
lrn@chromium.org25156de2010-04-06 13:10:27 +00002502 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002503 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002504 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002505
lrn@chromium.org25156de2010-04-06 13:10:27 +00002506 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002507 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2508 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002509 }
2510
2511
ager@chromium.org04921a82011-06-27 13:21:41 +00002512 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2513 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 }
2515
2516
2517 void AddElement(Object* element) {
2518 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002519 ASSERT(array_builder_.capacity() > array_builder_.length());
2520 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002521 }
2522
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002523 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002524 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002525 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002526 int character_count_;
2527 bool is_ascii_;
2528};
2529
2530
2531class CompiledReplacement {
2532 public:
2533 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002534 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002535
2536 void Compile(Handle<String> replacement,
2537 int capture_count,
2538 int subject_length);
2539
2540 void Apply(ReplacementStringBuilder* builder,
2541 int match_from,
2542 int match_to,
2543 Handle<JSArray> last_match_info);
2544
2545 // Number of distinct parts of the replacement pattern.
2546 int parts() {
2547 return parts_.length();
2548 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002549
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002550 bool simple_hint() {
2551 return simple_hint_;
2552 }
2553
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002554 private:
2555 enum PartType {
2556 SUBJECT_PREFIX = 1,
2557 SUBJECT_SUFFIX,
2558 SUBJECT_CAPTURE,
2559 REPLACEMENT_SUBSTRING,
2560 REPLACEMENT_STRING,
2561
2562 NUMBER_OF_PART_TYPES
2563 };
2564
2565 struct ReplacementPart {
2566 static inline ReplacementPart SubjectMatch() {
2567 return ReplacementPart(SUBJECT_CAPTURE, 0);
2568 }
2569 static inline ReplacementPart SubjectCapture(int capture_index) {
2570 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2571 }
2572 static inline ReplacementPart SubjectPrefix() {
2573 return ReplacementPart(SUBJECT_PREFIX, 0);
2574 }
2575 static inline ReplacementPart SubjectSuffix(int subject_length) {
2576 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2577 }
2578 static inline ReplacementPart ReplacementString() {
2579 return ReplacementPart(REPLACEMENT_STRING, 0);
2580 }
2581 static inline ReplacementPart ReplacementSubString(int from, int to) {
2582 ASSERT(from >= 0);
2583 ASSERT(to > from);
2584 return ReplacementPart(-from, to);
2585 }
2586
2587 // If tag <= 0 then it is the negation of a start index of a substring of
2588 // the replacement pattern, otherwise it's a value from PartType.
2589 ReplacementPart(int tag, int data)
2590 : tag(tag), data(data) {
2591 // Must be non-positive or a PartType value.
2592 ASSERT(tag < NUMBER_OF_PART_TYPES);
2593 }
2594 // Either a value of PartType or a non-positive number that is
2595 // the negation of an index into the replacement string.
2596 int tag;
2597 // The data value's interpretation depends on the value of tag:
2598 // tag == SUBJECT_PREFIX ||
2599 // tag == SUBJECT_SUFFIX: data is unused.
2600 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2601 // tag == REPLACEMENT_SUBSTRING ||
2602 // tag == REPLACEMENT_STRING: data is index into array of substrings
2603 // of the replacement string.
2604 // tag <= 0: Temporary representation of the substring of the replacement
2605 // string ranging over -tag .. data.
2606 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2607 // substring objects.
2608 int data;
2609 };
2610
2611 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002612 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002613 Vector<Char> characters,
2614 int capture_count,
2615 int subject_length) {
2616 int length = characters.length();
2617 int last = 0;
2618 for (int i = 0; i < length; i++) {
2619 Char c = characters[i];
2620 if (c == '$') {
2621 int next_index = i + 1;
2622 if (next_index == length) { // No next character!
2623 break;
2624 }
2625 Char c2 = characters[next_index];
2626 switch (c2) {
2627 case '$':
2628 if (i > last) {
2629 // There is a substring before. Include the first "$".
2630 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2631 last = next_index + 1; // Continue after the second "$".
2632 } else {
2633 // Let the next substring start with the second "$".
2634 last = next_index;
2635 }
2636 i = next_index;
2637 break;
2638 case '`':
2639 if (i > last) {
2640 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2641 }
2642 parts->Add(ReplacementPart::SubjectPrefix());
2643 i = next_index;
2644 last = i + 1;
2645 break;
2646 case '\'':
2647 if (i > last) {
2648 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2649 }
2650 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2651 i = next_index;
2652 last = i + 1;
2653 break;
2654 case '&':
2655 if (i > last) {
2656 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2657 }
2658 parts->Add(ReplacementPart::SubjectMatch());
2659 i = next_index;
2660 last = i + 1;
2661 break;
2662 case '0':
2663 case '1':
2664 case '2':
2665 case '3':
2666 case '4':
2667 case '5':
2668 case '6':
2669 case '7':
2670 case '8':
2671 case '9': {
2672 int capture_ref = c2 - '0';
2673 if (capture_ref > capture_count) {
2674 i = next_index;
2675 continue;
2676 }
2677 int second_digit_index = next_index + 1;
2678 if (second_digit_index < length) {
2679 // Peek ahead to see if we have two digits.
2680 Char c3 = characters[second_digit_index];
2681 if ('0' <= c3 && c3 <= '9') { // Double digits.
2682 int double_digit_ref = capture_ref * 10 + c3 - '0';
2683 if (double_digit_ref <= capture_count) {
2684 next_index = second_digit_index;
2685 capture_ref = double_digit_ref;
2686 }
2687 }
2688 }
2689 if (capture_ref > 0) {
2690 if (i > last) {
2691 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2692 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002693 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002694 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2695 last = next_index + 1;
2696 }
2697 i = next_index;
2698 break;
2699 }
2700 default:
2701 i = next_index;
2702 break;
2703 }
2704 }
2705 }
2706 if (length > last) {
2707 if (last == 0) {
2708 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002709 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002710 } else {
2711 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2712 }
2713 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002714 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002715 }
2716
2717 ZoneList<ReplacementPart> parts_;
2718 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002719 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002720};
2721
2722
2723void CompiledReplacement::Compile(Handle<String> replacement,
2724 int capture_count,
2725 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002726 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002727 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002728 String::FlatContent content = replacement->GetFlatContent();
2729 ASSERT(content.IsFlat());
2730 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002731 simple_hint_ = ParseReplacementPattern(&parts_,
2732 content.ToAsciiVector(),
2733 capture_count,
2734 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002735 } else {
2736 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002737 simple_hint_ = ParseReplacementPattern(&parts_,
2738 content.ToUC16Vector(),
2739 capture_count,
2740 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002741 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002742 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002743 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002744 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002745 int substring_index = 0;
2746 for (int i = 0, n = parts_.length(); i < n; i++) {
2747 int tag = parts_[i].tag;
2748 if (tag <= 0) { // A replacement string slice.
2749 int from = -tag;
2750 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002751 replacement_substrings_.Add(
2752 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002753 parts_[i].tag = REPLACEMENT_SUBSTRING;
2754 parts_[i].data = substring_index;
2755 substring_index++;
2756 } else if (tag == REPLACEMENT_STRING) {
2757 replacement_substrings_.Add(replacement);
2758 parts_[i].data = substring_index;
2759 substring_index++;
2760 }
2761 }
2762}
2763
2764
2765void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2766 int match_from,
2767 int match_to,
2768 Handle<JSArray> last_match_info) {
2769 for (int i = 0, n = parts_.length(); i < n; i++) {
2770 ReplacementPart part = parts_[i];
2771 switch (part.tag) {
2772 case SUBJECT_PREFIX:
2773 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2774 break;
2775 case SUBJECT_SUFFIX: {
2776 int subject_length = part.data;
2777 if (match_to < subject_length) {
2778 builder->AddSubjectSlice(match_to, subject_length);
2779 }
2780 break;
2781 }
2782 case SUBJECT_CAPTURE: {
2783 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002784 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002785 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2786 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2787 if (from >= 0 && to > from) {
2788 builder->AddSubjectSlice(from, to);
2789 }
2790 break;
2791 }
2792 case REPLACEMENT_SUBSTRING:
2793 case REPLACEMENT_STRING:
2794 builder->AddString(replacement_substrings_[part.data]);
2795 break;
2796 default:
2797 UNREACHABLE();
2798 }
2799 }
2800}
2801
2802
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002803void FindAsciiStringIndices(Vector<const char> subject,
2804 char pattern,
2805 ZoneList<int>* indices,
2806 unsigned int limit) {
2807 ASSERT(limit > 0);
2808 // Collect indices of pattern in subject using memchr.
2809 // Stop after finding at most limit values.
2810 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2811 const char* subject_end = subject_start + subject.length();
2812 const char* pos = subject_start;
2813 while (limit > 0) {
2814 pos = reinterpret_cast<const char*>(
2815 memchr(pos, pattern, subject_end - pos));
2816 if (pos == NULL) return;
2817 indices->Add(static_cast<int>(pos - subject_start));
2818 pos++;
2819 limit--;
2820 }
2821}
2822
2823
2824template <typename SubjectChar, typename PatternChar>
2825void FindStringIndices(Isolate* isolate,
2826 Vector<const SubjectChar> subject,
2827 Vector<const PatternChar> pattern,
2828 ZoneList<int>* indices,
2829 unsigned int limit) {
2830 ASSERT(limit > 0);
2831 // Collect indices of pattern in subject.
2832 // Stop after finding at most limit values.
2833 int pattern_length = pattern.length();
2834 int index = 0;
2835 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2836 while (limit > 0) {
2837 index = search.Search(subject, index);
2838 if (index < 0) return;
2839 indices->Add(index);
2840 index += pattern_length;
2841 limit--;
2842 }
2843}
2844
2845
2846void FindStringIndicesDispatch(Isolate* isolate,
2847 String* subject,
2848 String* pattern,
2849 ZoneList<int>* indices,
2850 unsigned int limit) {
2851 {
2852 AssertNoAllocation no_gc;
2853 String::FlatContent subject_content = subject->GetFlatContent();
2854 String::FlatContent pattern_content = pattern->GetFlatContent();
2855 ASSERT(subject_content.IsFlat());
2856 ASSERT(pattern_content.IsFlat());
2857 if (subject_content.IsAscii()) {
2858 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2859 if (pattern_content.IsAscii()) {
2860 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2861 if (pattern_vector.length() == 1) {
2862 FindAsciiStringIndices(subject_vector,
2863 pattern_vector[0],
2864 indices,
2865 limit);
2866 } else {
2867 FindStringIndices(isolate,
2868 subject_vector,
2869 pattern_vector,
2870 indices,
2871 limit);
2872 }
2873 } else {
2874 FindStringIndices(isolate,
2875 subject_vector,
2876 pattern_content.ToUC16Vector(),
2877 indices,
2878 limit);
2879 }
2880 } else {
2881 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002882 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002883 FindStringIndices(isolate,
2884 subject_vector,
2885 pattern_content.ToAsciiVector(),
2886 indices,
2887 limit);
2888 } else {
2889 FindStringIndices(isolate,
2890 subject_vector,
2891 pattern_content.ToUC16Vector(),
2892 indices,
2893 limit);
2894 }
2895 }
2896 }
2897}
2898
2899
2900template<typename ResultSeqString>
2901MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2902 Isolate* isolate,
2903 Handle<String> subject,
2904 Handle<JSRegExp> pattern_regexp,
2905 Handle<String> replacement) {
2906 ASSERT(subject->IsFlat());
2907 ASSERT(replacement->IsFlat());
2908
2909 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2910 ZoneList<int> indices(8);
2911 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2912 String* pattern =
2913 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2914 int subject_len = subject->length();
2915 int pattern_len = pattern->length();
2916 int replacement_len = replacement->length();
2917
2918 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2919
2920 int matches = indices.length();
2921 if (matches == 0) return *subject;
2922
2923 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2924 int subject_pos = 0;
2925 int result_pos = 0;
2926
2927 Handle<ResultSeqString> result;
2928 if (ResultSeqString::kHasAsciiEncoding) {
2929 result = Handle<ResultSeqString>::cast(
2930 isolate->factory()->NewRawAsciiString(result_len));
2931 } else {
2932 result = Handle<ResultSeqString>::cast(
2933 isolate->factory()->NewRawTwoByteString(result_len));
2934 }
2935
2936 for (int i = 0; i < matches; i++) {
2937 // Copy non-matched subject content.
2938 if (subject_pos < indices.at(i)) {
2939 String::WriteToFlat(*subject,
2940 result->GetChars() + result_pos,
2941 subject_pos,
2942 indices.at(i));
2943 result_pos += indices.at(i) - subject_pos;
2944 }
2945
2946 // Replace match.
2947 if (replacement_len > 0) {
2948 String::WriteToFlat(*replacement,
2949 result->GetChars() + result_pos,
2950 0,
2951 replacement_len);
2952 result_pos += replacement_len;
2953 }
2954
2955 subject_pos = indices.at(i) + pattern_len;
2956 }
2957 // Add remaining subject content at the end.
2958 if (subject_pos < subject_len) {
2959 String::WriteToFlat(*subject,
2960 result->GetChars() + result_pos,
2961 subject_pos,
2962 subject_len);
2963 }
2964 return *result;
2965}
2966
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002967
lrn@chromium.org303ada72010-10-27 09:33:13 +00002968MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002969 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002970 String* subject,
2971 JSRegExp* regexp,
2972 String* replacement,
2973 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002974 ASSERT(subject->IsFlat());
2975 ASSERT(replacement->IsFlat());
2976
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002977 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002978
2979 int length = subject->length();
2980 Handle<String> subject_handle(subject);
2981 Handle<JSRegExp> regexp_handle(regexp);
2982 Handle<String> replacement_handle(replacement);
2983 Handle<JSArray> last_match_info_handle(last_match_info);
2984 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2985 subject_handle,
2986 0,
2987 last_match_info_handle);
2988 if (match.is_null()) {
2989 return Failure::Exception();
2990 }
2991 if (match->IsNull()) {
2992 return *subject_handle;
2993 }
2994
2995 int capture_count = regexp_handle->CaptureCount();
2996
2997 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002998 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002999 CompiledReplacement compiled_replacement;
3000 compiled_replacement.Compile(replacement_handle,
3001 capture_count,
3002 length);
3003
3004 bool is_global = regexp_handle->GetFlags().is_global();
3005
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003006 // Shortcut for simple non-regexp global replacements
3007 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003008 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003009 compiled_replacement.simple_hint()) {
3010 if (subject_handle->HasOnlyAsciiChars() &&
3011 replacement_handle->HasOnlyAsciiChars()) {
3012 return StringReplaceStringWithString<SeqAsciiString>(
3013 isolate, subject_handle, regexp_handle, replacement_handle);
3014 } else {
3015 return StringReplaceStringWithString<SeqTwoByteString>(
3016 isolate, subject_handle, regexp_handle, replacement_handle);
3017 }
3018 }
3019
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003020 // Guessing the number of parts that the final result string is built
3021 // from. Global regexps can match any number of times, so we guess
3022 // conservatively.
3023 int expected_parts =
3024 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003025 ReplacementStringBuilder builder(isolate->heap(),
3026 subject_handle,
3027 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003028
3029 // Index of end of last match.
3030 int prev = 0;
3031
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003032 // Number of parts added by compiled replacement plus preceeding
3033 // string and possibly suffix after last match. It is possible for
3034 // all components to use two elements when encoded as two smis.
3035 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003036 bool matched = true;
3037 do {
3038 ASSERT(last_match_info_handle->HasFastElements());
3039 // Increase the capacity of the builder before entering local handle-scope,
3040 // so its internal buffer can safely allocate a new handle if it grows.
3041 builder.EnsureCapacity(parts_added_per_loop);
3042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003043 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003044 int start, end;
3045 {
3046 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003047 FixedArray* match_info_array =
3048 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003049
3050 ASSERT_EQ(capture_count * 2 + 2,
3051 RegExpImpl::GetLastCaptureCount(match_info_array));
3052 start = RegExpImpl::GetCapture(match_info_array, 0);
3053 end = RegExpImpl::GetCapture(match_info_array, 1);
3054 }
3055
3056 if (prev < start) {
3057 builder.AddSubjectSlice(prev, start);
3058 }
3059 compiled_replacement.Apply(&builder,
3060 start,
3061 end,
3062 last_match_info_handle);
3063 prev = end;
3064
3065 // Only continue checking for global regexps.
3066 if (!is_global) break;
3067
3068 // Continue from where the match ended, unless it was an empty match.
3069 int next = end;
3070 if (start == end) {
3071 next = end + 1;
3072 if (next > length) break;
3073 }
3074
3075 match = RegExpImpl::Exec(regexp_handle,
3076 subject_handle,
3077 next,
3078 last_match_info_handle);
3079 if (match.is_null()) {
3080 return Failure::Exception();
3081 }
3082 matched = !match->IsNull();
3083 } while (matched);
3084
3085 if (prev < length) {
3086 builder.AddSubjectSlice(prev, length);
3087 }
3088
3089 return *(builder.ToString());
3090}
3091
3092
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003093template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003094MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003096 String* subject,
3097 JSRegExp* regexp,
3098 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003099 ASSERT(subject->IsFlat());
3100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003101 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003102
3103 Handle<String> subject_handle(subject);
3104 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003105
3106 // Shortcut for simple non-regexp global replacements
3107 if (regexp_handle->GetFlags().is_global() &&
3108 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3109 Handle<String> empty_string_handle(HEAP->empty_string());
3110 if (subject_handle->HasOnlyAsciiChars()) {
3111 return StringReplaceStringWithString<SeqAsciiString>(
3112 isolate, subject_handle, regexp_handle, empty_string_handle);
3113 } else {
3114 return StringReplaceStringWithString<SeqTwoByteString>(
3115 isolate, subject_handle, regexp_handle, empty_string_handle);
3116 }
3117 }
3118
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003119 Handle<JSArray> last_match_info_handle(last_match_info);
3120 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3121 subject_handle,
3122 0,
3123 last_match_info_handle);
3124 if (match.is_null()) return Failure::Exception();
3125 if (match->IsNull()) return *subject_handle;
3126
3127 ASSERT(last_match_info_handle->HasFastElements());
3128
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003129 int start, end;
3130 {
3131 AssertNoAllocation match_info_array_is_not_in_a_handle;
3132 FixedArray* match_info_array =
3133 FixedArray::cast(last_match_info_handle->elements());
3134
3135 start = RegExpImpl::GetCapture(match_info_array, 0);
3136 end = RegExpImpl::GetCapture(match_info_array, 1);
3137 }
3138
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003139 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003140 int new_length = length - (end - start);
3141 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003142 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003143 }
3144 Handle<ResultSeqString> answer;
3145 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003146 answer = Handle<ResultSeqString>::cast(
3147 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003148 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003149 answer = Handle<ResultSeqString>::cast(
3150 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003151 }
3152
3153 // If the regexp isn't global, only match once.
3154 if (!regexp_handle->GetFlags().is_global()) {
3155 if (start > 0) {
3156 String::WriteToFlat(*subject_handle,
3157 answer->GetChars(),
3158 0,
3159 start);
3160 }
3161 if (end < length) {
3162 String::WriteToFlat(*subject_handle,
3163 answer->GetChars() + start,
3164 end,
3165 length);
3166 }
3167 return *answer;
3168 }
3169
3170 int prev = 0; // Index of end of last match.
3171 int next = 0; // Start of next search (prev unless last match was empty).
3172 int position = 0;
3173
3174 do {
3175 if (prev < start) {
3176 // Add substring subject[prev;start] to answer string.
3177 String::WriteToFlat(*subject_handle,
3178 answer->GetChars() + position,
3179 prev,
3180 start);
3181 position += start - prev;
3182 }
3183 prev = end;
3184 next = end;
3185 // Continue from where the match ended, unless it was an empty match.
3186 if (start == end) {
3187 next++;
3188 if (next > length) break;
3189 }
3190 match = RegExpImpl::Exec(regexp_handle,
3191 subject_handle,
3192 next,
3193 last_match_info_handle);
3194 if (match.is_null()) return Failure::Exception();
3195 if (match->IsNull()) break;
3196
3197 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003198 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003199 {
3200 AssertNoAllocation match_info_array_is_not_in_a_handle;
3201 FixedArray* match_info_array =
3202 FixedArray::cast(last_match_info_handle->elements());
3203 start = RegExpImpl::GetCapture(match_info_array, 0);
3204 end = RegExpImpl::GetCapture(match_info_array, 1);
3205 }
3206 } while (true);
3207
3208 if (prev < length) {
3209 // Add substring subject[prev;length] to answer string.
3210 String::WriteToFlat(*subject_handle,
3211 answer->GetChars() + position,
3212 prev,
3213 length);
3214 position += length - prev;
3215 }
3216
3217 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003218 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003219 }
3220
3221 // Shorten string and fill
3222 int string_size = ResultSeqString::SizeFor(position);
3223 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3224 int delta = allocated_string_size - string_size;
3225
3226 answer->set_length(position);
3227 if (delta == 0) return *answer;
3228
3229 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003230 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003231 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3232 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3233 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003234
3235 return *answer;
3236}
3237
3238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003239RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003240 ASSERT(args.length() == 4);
3241
3242 CONVERT_CHECKED(String, subject, args[0]);
3243 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003244 Object* flat_subject;
3245 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3246 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3247 return maybe_flat_subject;
3248 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 }
3250 subject = String::cast(flat_subject);
3251 }
3252
3253 CONVERT_CHECKED(String, replacement, args[2]);
3254 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003255 Object* flat_replacement;
3256 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3257 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3258 return maybe_flat_replacement;
3259 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003260 }
3261 replacement = String::cast(flat_replacement);
3262 }
3263
3264 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3265 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3266
3267 ASSERT(last_match_info->HasFastElements());
3268
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003269 if (replacement->length() == 0) {
3270 if (subject->HasOnlyAsciiChars()) {
3271 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003272 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003273 } else {
3274 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003275 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003276 }
3277 }
3278
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003279 return StringReplaceRegExpWithString(isolate,
3280 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003281 regexp,
3282 replacement,
3283 last_match_info);
3284}
3285
3286
ager@chromium.org7c537e22008-10-16 08:43:32 +00003287// Perform string match of pattern on subject, starting at start index.
3288// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003289// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290int Runtime::StringMatch(Isolate* isolate,
3291 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003292 Handle<String> pat,
3293 int start_index) {
3294 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003295 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003296
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003297 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003298 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003300 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003301 if (start_index + pattern_length > subject_length) return -1;
3302
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003303 if (!sub->IsFlat()) FlattenString(sub);
3304 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003305
ager@chromium.org7c537e22008-10-16 08:43:32 +00003306 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003307 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003308 String::FlatContent seq_sub = sub->GetFlatContent();
3309 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003310
ager@chromium.org7c537e22008-10-16 08:43:32 +00003311 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003312 if (seq_pat.IsAscii()) {
3313 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3314 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003315 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003316 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003317 pat_vector,
3318 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003319 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003320 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003321 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003322 pat_vector,
3323 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003324 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003325 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3326 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003327 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003328 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003329 pat_vector,
3330 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003331 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003332 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003333 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003334 pat_vector,
3335 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003336}
3337
3338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003339RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003340 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003341 ASSERT(args.length() == 3);
3342
ager@chromium.org7c537e22008-10-16 08:43:32 +00003343 CONVERT_ARG_CHECKED(String, sub, 0);
3344 CONVERT_ARG_CHECKED(String, pat, 1);
3345
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003346 Object* index = args[2];
3347 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003348 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003349
ager@chromium.org870a0b62008-11-04 11:43:05 +00003350 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003351 int position =
3352 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003353 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354}
3355
3356
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003357template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003358static int StringMatchBackwards(Vector<const schar> subject,
3359 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003360 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003361 int pattern_length = pattern.length();
3362 ASSERT(pattern_length >= 1);
3363 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003364
3365 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003366 for (int i = 0; i < pattern_length; i++) {
3367 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003368 if (c > String::kMaxAsciiCharCode) {
3369 return -1;
3370 }
3371 }
3372 }
3373
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003374 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003376 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003377 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003378 while (j < pattern_length) {
3379 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003380 break;
3381 }
3382 j++;
3383 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003384 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003385 return i;
3386 }
3387 }
3388 return -1;
3389}
3390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003391RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393 ASSERT(args.length() == 3);
3394
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003395 CONVERT_ARG_CHECKED(String, sub, 0);
3396 CONVERT_ARG_CHECKED(String, pat, 1);
3397
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003398 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003400 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003402 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003403 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003404
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003405 if (start_index + pat_length > sub_length) {
3406 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003409 if (pat_length == 0) {
3410 return Smi::FromInt(start_index);
3411 }
3412
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003413 if (!sub->IsFlat()) FlattenString(sub);
3414 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003415
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003416 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003417 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3418
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003419 String::FlatContent sub_content = sub->GetFlatContent();
3420 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003421
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003422 if (pat_content.IsAscii()) {
3423 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3424 if (sub_content.IsAscii()) {
3425 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426 pat_vector,
3427 start_index);
3428 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003429 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 pat_vector,
3431 start_index);
3432 }
3433 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003434 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3435 if (sub_content.IsAscii()) {
3436 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 pat_vector,
3438 start_index);
3439 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003440 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003441 pat_vector,
3442 start_index);
3443 }
3444 }
3445
3446 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003447}
3448
3449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003450RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451 NoHandleAllocation ha;
3452 ASSERT(args.length() == 2);
3453
3454 CONVERT_CHECKED(String, str1, args[0]);
3455 CONVERT_CHECKED(String, str2, args[1]);
3456
3457 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003458 int str1_length = str1->length();
3459 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460
3461 // Decide trivial cases without flattening.
3462 if (str1_length == 0) {
3463 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3464 return Smi::FromInt(-str2_length);
3465 } else {
3466 if (str2_length == 0) return Smi::FromInt(str1_length);
3467 }
3468
3469 int end = str1_length < str2_length ? str1_length : str2_length;
3470
3471 // No need to flatten if we are going to find the answer on the first
3472 // character. At this point we know there is at least one character
3473 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003474 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003475 if (d != 0) return Smi::FromInt(d);
3476
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003477 str1->TryFlatten();
3478 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003479
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003480 StringInputBuffer& buf1 =
3481 *isolate->runtime_state()->string_locale_compare_buf1();
3482 StringInputBuffer& buf2 =
3483 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003484
3485 buf1.Reset(str1);
3486 buf2.Reset(str2);
3487
3488 for (int i = 0; i < end; i++) {
3489 uint16_t char1 = buf1.GetNext();
3490 uint16_t char2 = buf2.GetNext();
3491 if (char1 != char2) return Smi::FromInt(char1 - char2);
3492 }
3493
3494 return Smi::FromInt(str1_length - str2_length);
3495}
3496
3497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003498RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003499 NoHandleAllocation ha;
3500 ASSERT(args.length() == 3);
3501
3502 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003503 int start, end;
3504 // We have a fast integer-only case here to avoid a conversion to double in
3505 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003506 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3507 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3508 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3509 start = from_number;
3510 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003511 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003512 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3513 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003514 start = FastD2I(from_number);
3515 end = FastD2I(to_number);
3516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003517 RUNTIME_ASSERT(end >= start);
3518 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003519 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003520 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003521 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522}
3523
3524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003525RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003526 ASSERT_EQ(3, args.length());
3527
3528 CONVERT_ARG_CHECKED(String, subject, 0);
3529 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3530 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3531 HandleScope handles;
3532
3533 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3534
3535 if (match.is_null()) {
3536 return Failure::Exception();
3537 }
3538 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003539 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003540 }
3541 int length = subject->length();
3542
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003543 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003544 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003545 int start;
3546 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003547 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003548 {
3549 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003550 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003551 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3552 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3553 }
3554 offsets.Add(start);
3555 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003556 if (start == end) if (++end > length) break;
3557 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003558 if (match.is_null()) {
3559 return Failure::Exception();
3560 }
3561 } while (!match->IsNull());
3562 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003563 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003564 Handle<String> substring = isolate->factory()->
3565 NewSubString(subject, offsets.at(0), offsets.at(1));
3566 elements->set(0, *substring);
3567 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003568 int from = offsets.at(i * 2);
3569 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003570 Handle<String> substring = isolate->factory()->
3571 NewProperSubString(subject, from, to);
3572 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003573 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003574 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003575 result->set_length(Smi::FromInt(matches));
3576 return *result;
3577}
3578
3579
lrn@chromium.org25156de2010-04-06 13:10:27 +00003580// Two smis before and after the match, for very long strings.
3581const int kMaxBuilderEntriesPerRegExpMatch = 5;
3582
3583
3584static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3585 Handle<JSArray> last_match_info,
3586 int match_start,
3587 int match_end) {
3588 // Fill last_match_info with a single capture.
3589 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3590 AssertNoAllocation no_gc;
3591 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3592 RegExpImpl::SetLastCaptureCount(elements, 2);
3593 RegExpImpl::SetLastInput(elements, *subject);
3594 RegExpImpl::SetLastSubject(elements, *subject);
3595 RegExpImpl::SetCapture(elements, 0, match_start);
3596 RegExpImpl::SetCapture(elements, 1, match_end);
3597}
3598
3599
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003600template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003601static bool SearchStringMultiple(Isolate* isolate,
3602 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003603 Vector<const PatternChar> pattern,
3604 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003605 FixedArrayBuilder* builder,
3606 int* match_pos) {
3607 int pos = *match_pos;
3608 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003609 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003610 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003611 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003612 while (pos <= max_search_start) {
3613 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3614 *match_pos = pos;
3615 return false;
3616 }
3617 // Position of end of previous match.
3618 int match_end = pos + pattern_length;
3619 int new_pos = search.Search(subject, match_end);
3620 if (new_pos >= 0) {
3621 // A match.
3622 if (new_pos > match_end) {
3623 ReplacementStringBuilder::AddSubjectSlice(builder,
3624 match_end,
3625 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003626 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003627 pos = new_pos;
3628 builder->Add(pattern_string);
3629 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003630 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003631 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003632 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003633
lrn@chromium.org25156de2010-04-06 13:10:27 +00003634 if (pos < max_search_start) {
3635 ReplacementStringBuilder::AddSubjectSlice(builder,
3636 pos + pattern_length,
3637 subject_length);
3638 }
3639 *match_pos = pos;
3640 return true;
3641}
3642
3643
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003644static bool SearchStringMultiple(Isolate* isolate,
3645 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003646 Handle<String> pattern,
3647 Handle<JSArray> last_match_info,
3648 FixedArrayBuilder* builder) {
3649 ASSERT(subject->IsFlat());
3650 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003651
3652 // Treating as if a previous match was before first character.
3653 int match_pos = -pattern->length();
3654
3655 for (;;) { // Break when search complete.
3656 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3657 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003658 String::FlatContent subject_content = subject->GetFlatContent();
3659 String::FlatContent pattern_content = pattern->GetFlatContent();
3660 if (subject_content.IsAscii()) {
3661 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3662 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663 if (SearchStringMultiple(isolate,
3664 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003665 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003666 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003667 builder,
3668 &match_pos)) break;
3669 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003670 if (SearchStringMultiple(isolate,
3671 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003672 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003673 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003674 builder,
3675 &match_pos)) break;
3676 }
3677 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003678 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3679 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 if (SearchStringMultiple(isolate,
3681 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003682 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003683 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003684 builder,
3685 &match_pos)) break;
3686 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003687 if (SearchStringMultiple(isolate,
3688 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003689 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003690 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003691 builder,
3692 &match_pos)) break;
3693 }
3694 }
3695 }
3696
3697 if (match_pos >= 0) {
3698 SetLastMatchInfoNoCaptures(subject,
3699 last_match_info,
3700 match_pos,
3701 match_pos + pattern->length());
3702 return true;
3703 }
3704 return false; // No matches at all.
3705}
3706
3707
3708static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003709 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003710 Handle<String> subject,
3711 Handle<JSRegExp> regexp,
3712 Handle<JSArray> last_match_array,
3713 FixedArrayBuilder* builder) {
3714 ASSERT(subject->IsFlat());
3715 int match_start = -1;
3716 int match_end = 0;
3717 int pos = 0;
3718 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3719 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3720
3721 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003722 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003723 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003724 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003725
3726 for (;;) { // Break on failure, return on exception.
3727 RegExpImpl::IrregexpResult result =
3728 RegExpImpl::IrregexpExecOnce(regexp,
3729 subject,
3730 pos,
3731 register_vector);
3732 if (result == RegExpImpl::RE_SUCCESS) {
3733 match_start = register_vector[0];
3734 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3735 if (match_end < match_start) {
3736 ReplacementStringBuilder::AddSubjectSlice(builder,
3737 match_end,
3738 match_start);
3739 }
3740 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003742 if (!first) {
3743 builder->Add(*isolate->factory()->NewProperSubString(subject,
3744 match_start,
3745 match_end));
3746 } else {
3747 builder->Add(*isolate->factory()->NewSubString(subject,
3748 match_start,
3749 match_end));
3750 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003751 if (match_start != match_end) {
3752 pos = match_end;
3753 } else {
3754 pos = match_end + 1;
3755 if (pos > subject_length) break;
3756 }
3757 } else if (result == RegExpImpl::RE_FAILURE) {
3758 break;
3759 } else {
3760 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3761 return result;
3762 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003763 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003764 }
3765
3766 if (match_start >= 0) {
3767 if (match_end < subject_length) {
3768 ReplacementStringBuilder::AddSubjectSlice(builder,
3769 match_end,
3770 subject_length);
3771 }
3772 SetLastMatchInfoNoCaptures(subject,
3773 last_match_array,
3774 match_start,
3775 match_end);
3776 return RegExpImpl::RE_SUCCESS;
3777 } else {
3778 return RegExpImpl::RE_FAILURE; // No matches at all.
3779 }
3780}
3781
3782
3783static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003784 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003785 Handle<String> subject,
3786 Handle<JSRegExp> regexp,
3787 Handle<JSArray> last_match_array,
3788 FixedArrayBuilder* builder) {
3789
3790 ASSERT(subject->IsFlat());
3791 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3792 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3793
3794 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003795 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003796
3797 RegExpImpl::IrregexpResult result =
3798 RegExpImpl::IrregexpExecOnce(regexp,
3799 subject,
3800 0,
3801 register_vector);
3802
3803 int capture_count = regexp->CaptureCount();
3804 int subject_length = subject->length();
3805
3806 // Position to search from.
3807 int pos = 0;
3808 // End of previous match. Differs from pos if match was empty.
3809 int match_end = 0;
3810 if (result == RegExpImpl::RE_SUCCESS) {
3811 // Need to keep a copy of the previous match for creating last_match_info
3812 // at the end, so we have two vectors that we swap between.
3813 OffsetsVector registers2(required_registers);
3814 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003815 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003816 do {
3817 int match_start = register_vector[0];
3818 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3819 if (match_end < match_start) {
3820 ReplacementStringBuilder::AddSubjectSlice(builder,
3821 match_end,
3822 match_start);
3823 }
3824 match_end = register_vector[1];
3825
3826 {
3827 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003828 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003829 // Arguments array to replace function is match, captures, index and
3830 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003831 Handle<FixedArray> elements =
3832 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003833 Handle<String> match;
3834 if (!first) {
3835 match = isolate->factory()->NewProperSubString(subject,
3836 match_start,
3837 match_end);
3838 } else {
3839 match = isolate->factory()->NewSubString(subject,
3840 match_start,
3841 match_end);
3842 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003843 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003844 for (int i = 1; i <= capture_count; i++) {
3845 int start = register_vector[i * 2];
3846 if (start >= 0) {
3847 int end = register_vector[i * 2 + 1];
3848 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003849 Handle<String> substring;
3850 if (!first) {
3851 substring = isolate->factory()->NewProperSubString(subject,
3852 start,
3853 end);
3854 } else {
3855 substring = isolate->factory()->NewSubString(subject, start, end);
3856 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003857 elements->set(i, *substring);
3858 } else {
3859 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003860 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003861 }
3862 }
3863 elements->set(capture_count + 1, Smi::FromInt(match_start));
3864 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003865 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003866 }
3867 // Swap register vectors, so the last successful match is in
3868 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003869 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003870 prev_register_vector = register_vector;
3871 register_vector = tmp;
3872
3873 if (match_end > match_start) {
3874 pos = match_end;
3875 } else {
3876 pos = match_end + 1;
3877 if (pos > subject_length) {
3878 break;
3879 }
3880 }
3881
3882 result = RegExpImpl::IrregexpExecOnce(regexp,
3883 subject,
3884 pos,
3885 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003886 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003887 } while (result == RegExpImpl::RE_SUCCESS);
3888
3889 if (result != RegExpImpl::RE_EXCEPTION) {
3890 // Finished matching, with at least one match.
3891 if (match_end < subject_length) {
3892 ReplacementStringBuilder::AddSubjectSlice(builder,
3893 match_end,
3894 subject_length);
3895 }
3896
3897 int last_match_capture_count = (capture_count + 1) * 2;
3898 int last_match_array_size =
3899 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3900 last_match_array->EnsureSize(last_match_array_size);
3901 AssertNoAllocation no_gc;
3902 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3903 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3904 RegExpImpl::SetLastSubject(elements, *subject);
3905 RegExpImpl::SetLastInput(elements, *subject);
3906 for (int i = 0; i < last_match_capture_count; i++) {
3907 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3908 }
3909 return RegExpImpl::RE_SUCCESS;
3910 }
3911 }
3912 // No matches at all, return failure or exception result directly.
3913 return result;
3914}
3915
3916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003917RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003918 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003919 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003920
3921 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003922 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3924 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3925 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3926
3927 ASSERT(last_match_info->HasFastElements());
3928 ASSERT(regexp->GetFlags().is_global());
3929 Handle<FixedArray> result_elements;
3930 if (result_array->HasFastElements()) {
3931 result_elements =
3932 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003933 }
3934 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003936 }
3937 FixedArrayBuilder builder(result_elements);
3938
3939 if (regexp->TypeTag() == JSRegExp::ATOM) {
3940 Handle<String> pattern(
3941 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003942 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003943 if (SearchStringMultiple(isolate, subject, pattern,
3944 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003945 return *builder.ToJSArray(result_array);
3946 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003947 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003948 }
3949
3950 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3951
3952 RegExpImpl::IrregexpResult result;
3953 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003954 result = SearchRegExpNoCaptureMultiple(isolate,
3955 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003956 regexp,
3957 last_match_info,
3958 &builder);
3959 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003960 result = SearchRegExpMultiple(isolate,
3961 subject,
3962 regexp,
3963 last_match_info,
3964 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003965 }
3966 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003967 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003968 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3969 return Failure::Exception();
3970}
3971
3972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003973RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 NoHandleAllocation ha;
3975 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003976 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003977 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003979 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003980 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003981 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003982 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003983 // Character array used for conversion.
3984 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003985 return isolate->heap()->
3986 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003987 }
3988 }
3989
3990 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003991 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003993 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994 }
3995 if (isinf(value)) {
3996 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003997 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003999 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004002 MaybeObject* result =
4003 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 DeleteArray(str);
4005 return result;
4006}
4007
4008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004009RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 NoHandleAllocation ha;
4011 ASSERT(args.length() == 2);
4012
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004013 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004015 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 }
4017 if (isinf(value)) {
4018 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004019 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004021 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004023 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 int f = FastD2I(f_number);
4025 RUNTIME_ASSERT(f >= 0);
4026 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004027 MaybeObject* res =
4028 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031}
4032
4033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004034RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004035 NoHandleAllocation ha;
4036 ASSERT(args.length() == 2);
4037
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004038 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004040 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 }
4042 if (isinf(value)) {
4043 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004044 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004046 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004048 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004049 int f = FastD2I(f_number);
4050 RUNTIME_ASSERT(f >= -1 && f <= 20);
4051 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004052 MaybeObject* res =
4053 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004055 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056}
4057
4058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004059RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 NoHandleAllocation ha;
4061 ASSERT(args.length() == 2);
4062
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004063 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004065 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 }
4067 if (isinf(value)) {
4068 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004069 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004070 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004071 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004073 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074 int f = FastD2I(f_number);
4075 RUNTIME_ASSERT(f >= 1 && f <= 21);
4076 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004077 MaybeObject* res =
4078 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081}
4082
4083
4084// Returns a single character string where first character equals
4085// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004086static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004087 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004088 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004089 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004090 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004092 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093}
4094
4095
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004096MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4097 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004098 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 // Handle [] indexing on Strings
4100 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004101 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4102 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 }
4104
4105 // Handle [] indexing on String objects
4106 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004107 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4108 Handle<Object> result =
4109 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4110 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 }
4112
4113 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004114 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 return prototype->GetElement(index);
4116 }
4117
4118 return object->GetElement(index);
4119}
4120
4121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004122MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4123 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004124 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004125 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004128 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004130 isolate->factory()->NewTypeError("non_object_property_load",
4131 HandleVector(args, 2));
4132 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 }
4134
4135 // Check if the given key is an array index.
4136 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004137 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004138 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004139 }
4140
4141 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004142 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004144 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004145 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004146 bool has_pending_exception = false;
4147 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004148 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004149 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004150 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004151 }
4152
ager@chromium.org32912102009-01-16 10:38:43 +00004153 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004154 // the element if so.
4155 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004156 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004157 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004158 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004159 }
4160}
4161
4162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004163RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 NoHandleAllocation ha;
4165 ASSERT(args.length() == 2);
4166
4167 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004168 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004170 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171}
4172
4173
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004174// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004175RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004176 NoHandleAllocation ha;
4177 ASSERT(args.length() == 2);
4178
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004179 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004180 // itself.
4181 //
4182 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004183 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004184 // global proxy object never has properties. This is the case
4185 // because the global proxy object forwards everything to its hidden
4186 // prototype including local lookups.
4187 //
4188 // Additionally, we need to make sure that we do not cache results
4189 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004190 if (args[0]->IsJSObject() &&
4191 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00004192 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004193 args[1]->IsString()) {
4194 JSObject* receiver = JSObject::cast(args[0]);
4195 String* key = String::cast(args[1]);
4196 if (receiver->HasFastProperties()) {
4197 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004198 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004199 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4200 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004201 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004202 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004203 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004204 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004205 // Lookup cache miss. Perform lookup and update the cache if appropriate.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004206 LookupResult result(isolate);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004207 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004208 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004209 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004210 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004211 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004212 }
4213 } else {
4214 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004215 StringDictionary* dictionary = receiver->property_dictionary();
4216 int entry = dictionary->FindEntry(key);
4217 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004218 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004219 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004220 if (!receiver->IsGlobalObject()) return value;
4221 value = JSGlobalPropertyCell::cast(value)->value();
4222 if (!value->IsTheHole()) return value;
4223 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004224 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004225 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004226 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4227 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004228 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004229 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004230 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004231 if (index >= 0 && index < str->length()) {
4232 Handle<Object> result = GetCharAt(str, index);
4233 return *result;
4234 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004235 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004236
4237 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004238 return Runtime::GetObjectProperty(isolate,
4239 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004240 args.at<Object>(1));
4241}
4242
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004243// Implements part of 8.12.9 DefineOwnProperty.
4244// There are 3 cases that lead here:
4245// Step 4b - define a new accessor property.
4246// Steps 9c & 12 - replace an existing data property with an accessor property.
4247// Step 12 - update an existing accessor property with an accessor or generic
4248// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004249RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004250 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004251 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004252 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4253 CONVERT_CHECKED(String, name, args[1]);
4254 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004255 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004256 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004257 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4258 int unchecked = flag_attr->value();
4259 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4260 RUNTIME_ASSERT(!obj->IsNull());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004261 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004262 obj->LocalLookupRealNamedProperty(name, &result);
4263
4264 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4265 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4266 // delete it to avoid running into trouble in DefineAccessor, which
4267 // handles this incorrectly if the property is readonly (does nothing)
4268 if (result.IsProperty() &&
4269 (result.type() == FIELD || result.type() == NORMAL
4270 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004271 Object* ok;
4272 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004273 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004274 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4275 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004276 }
4277 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4278}
4279
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004280// Implements part of 8.12.9 DefineOwnProperty.
4281// There are 3 cases that lead here:
4282// Step 4a - define a new data property.
4283// Steps 9b & 12 - replace an existing accessor property with a data property.
4284// Step 12 - update an existing data property with a data or generic
4285// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004286RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004287 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004288 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004289 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4290 CONVERT_ARG_CHECKED(String, name, 1);
4291 Handle<Object> obj_value = args.at<Object>(2);
4292
4293 CONVERT_CHECKED(Smi, flag, args[3]);
4294 int unchecked = flag->value();
4295 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4296
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004297 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4298
4299 // Check if this is an element.
4300 uint32_t index;
4301 bool is_element = name->AsArrayIndex(&index);
4302
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004303 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004304 // If elements are in fast case we always implicitly assume that:
4305 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004306 if (is_element && (attr != NONE ||
4307 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004308 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004309 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004310 // We do not need to do access checks here since these has already
4311 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004312 Handle<Object> proto(js_object->GetPrototype());
4313 // If proxy is detached, ignore the assignment. Alternatively,
4314 // we could throw an exception.
4315 if (proto->IsNull()) return *obj_value;
4316 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004317 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004318
4319 // Don't allow element properties to be redefined on objects with external
4320 // array elements.
4321 if (js_object->HasExternalArrayElements()) {
4322 Handle<Object> args[2] = { js_object, name };
4323 Handle<Object> error =
4324 isolate->factory()->NewTypeError("redef_external_array_element",
4325 HandleVector(args, 2));
4326 return isolate->Throw(*error);
4327 }
4328
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004329 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004330 // Make sure that we never go back to fast case.
4331 dictionary->set_requires_slow_elements();
4332 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004333 Handle<NumberDictionary> extended_dictionary =
4334 NumberDictionarySet(dictionary, index, obj_value, details);
4335 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004336 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004337 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4338 } else {
4339 js_object->set_elements(*extended_dictionary);
4340 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004341 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004342 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004343 }
4344
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004345 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004346 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004347
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004348 // To be compatible with safari we do not change the value on API objects
4349 // in defineProperty. Firefox disagrees here, and actually changes the value.
4350 if (result.IsProperty() &&
4351 (result.type() == CALLBACKS) &&
4352 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004353 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004354 }
4355
ager@chromium.org5c838252010-02-19 08:53:10 +00004356 // Take special care when attributes are different and there is already
4357 // a property. For simplicity we normalize the property which enables us
4358 // to not worry about changing the instance_descriptor and creating a new
4359 // map. The current version of SetObjectProperty does not handle attributes
4360 // correctly in the case where a property is a field and is reset with
4361 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004362 if (result.IsProperty() &&
4363 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004364 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004365 if (js_object->IsJSGlobalProxy()) {
4366 // Since the result is a property, the prototype will exist so
4367 // we don't have to check for null.
4368 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004369 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004370 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004371 // Use IgnoreAttributes version since a readonly property may be
4372 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004373 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4374 *obj_value,
4375 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004376 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004377
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 return Runtime::ForceSetObjectProperty(isolate,
4379 js_object,
4380 name,
4381 obj_value,
4382 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004383}
4384
4385
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004386// Special case for elements if any of the flags are true.
4387// If elements are in fast case we always implicitly assume that:
4388// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4389static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4390 Handle<JSObject> js_object,
4391 uint32_t index,
4392 Handle<Object> value,
4393 PropertyAttributes attr) {
4394 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004395 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004396 // Make sure that we never go back to fast case.
4397 dictionary->set_requires_slow_elements();
4398 PropertyDetails details = PropertyDetails(attr, NORMAL);
4399 Handle<NumberDictionary> extended_dictionary =
4400 NumberDictionarySet(dictionary, index, value, details);
4401 if (*extended_dictionary != *dictionary) {
4402 js_object->set_elements(*extended_dictionary);
4403 }
4404 return *value;
4405}
4406
4407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004408MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4409 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004410 Handle<Object> key,
4411 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004412 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004413 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004414 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004415
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004416 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004417 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004418 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004419 isolate->factory()->NewTypeError("non_object_property_store",
4420 HandleVector(args, 2));
4421 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 }
4423
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004424 if (object->IsJSProxy()) {
4425 bool has_pending_exception = false;
4426 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4427 if (has_pending_exception) return Failure::Exception();
4428 return JSProxy::cast(*object)->SetProperty(
4429 String::cast(*name), *value, attr, strict_mode);
4430 }
4431
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004432 // If the object isn't a JavaScript object, we ignore the store.
4433 if (!object->IsJSObject()) return *value;
4434
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004435 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004437 // Check if the given key is an array index.
4438 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004439 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004440 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4441 // of a string using [] notation. We need to support this too in
4442 // JavaScript.
4443 // In the case of a String object we just need to redirect the assignment to
4444 // the underlying string if the index is in range. Since the underlying
4445 // string does nothing with the assignment then we can ignore such
4446 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004447 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004449 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004451 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4452 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4453 }
4454
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004455 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004456 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004457 return *value;
4458 }
4459
4460 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004461 Handle<Object> result;
4462 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004463 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4464 return NormalizeObjectSetElement(isolate,
4465 js_object,
4466 index,
4467 value,
4468 attr);
4469 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004470 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004472 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004473 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004474 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004476 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 return *value;
4478 }
4479
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 bool has_pending_exception = false;
4482 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4483 if (has_pending_exception) return Failure::Exception();
4484 Handle<String> name = Handle<String>::cast(converted);
4485
4486 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004487 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004489 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 }
4491}
4492
4493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004494MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4495 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004496 Handle<Object> key,
4497 Handle<Object> value,
4498 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004499 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004500
4501 // Check if the given key is an array index.
4502 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004503 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004504 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4505 // of a string using [] notation. We need to support this too in
4506 // JavaScript.
4507 // In the case of a String object we just need to redirect the assignment to
4508 // the underlying string if the index is in range. Since the underlying
4509 // string does nothing with the assignment then we can ignore such
4510 // assignments.
4511 if (js_object->IsStringObjectWithCharacterAt(index)) {
4512 return *value;
4513 }
4514
whesse@chromium.org7b260152011-06-20 15:33:18 +00004515 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004516 }
4517
4518 if (key->IsString()) {
4519 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004520 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004521 } else {
4522 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004523 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004524 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4525 *value,
4526 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004527 }
4528 }
4529
4530 // Call-back into JavaScript to convert the key to a string.
4531 bool has_pending_exception = false;
4532 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4533 if (has_pending_exception) return Failure::Exception();
4534 Handle<String> name = Handle<String>::cast(converted);
4535
4536 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004537 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004538 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004539 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004540 }
4541}
4542
4543
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004544MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004545 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004546 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004547 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004548
4549 // Check if the given key is an array index.
4550 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004551 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004552 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4553 // characters of a string using [] notation. In the case of a
4554 // String object we just need to redirect the deletion to the
4555 // underlying string if the index is in range. Since the
4556 // underlying string does nothing with the deletion, we can ignore
4557 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004558 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004559 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004560 }
4561
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004562 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004563 }
4564
4565 Handle<String> key_string;
4566 if (key->IsString()) {
4567 key_string = Handle<String>::cast(key);
4568 } else {
4569 // Call-back into JavaScript to convert the key to a string.
4570 bool has_pending_exception = false;
4571 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4572 if (has_pending_exception) return Failure::Exception();
4573 key_string = Handle<String>::cast(converted);
4574 }
4575
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004576 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004577 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004578}
4579
4580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004581RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004582 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004583 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584
4585 Handle<Object> object = args.at<Object>(0);
4586 Handle<Object> key = args.at<Object>(1);
4587 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004588 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004589 RUNTIME_ASSERT(
4590 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004591 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004592 PropertyAttributes attributes =
4593 static_cast<PropertyAttributes>(unchecked_attributes);
4594
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004595 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004596 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004597 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004598 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4599 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004600 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004603 return Runtime::SetObjectProperty(isolate,
4604 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004605 key,
4606 value,
4607 attributes,
4608 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004609}
4610
4611
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004612MaybeObject* TransitionElements(Handle<Object> object,
4613 ElementsKind to_kind,
4614 Isolate* isolate) {
4615 HandleScope scope(isolate);
4616 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4617 ElementsKind from_kind =
4618 Handle<JSObject>::cast(object)->map()->elements_kind();
4619 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4620 Handle<Object> result =
4621 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4622 if (result.is_null()) return isolate->ThrowIllegalOperation();
4623 return *result;
4624 }
4625 return isolate->ThrowIllegalOperation();
4626}
4627
4628
4629RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4630 NoHandleAllocation ha;
4631 RUNTIME_ASSERT(args.length() == 1);
4632 Handle<Object> object = args.at<Object>(0);
4633 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4634}
4635
4636
4637RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4638 NoHandleAllocation ha;
4639 RUNTIME_ASSERT(args.length() == 1);
4640 Handle<Object> object = args.at<Object>(0);
4641 return TransitionElements(object, FAST_ELEMENTS, isolate);
4642}
4643
4644
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004645// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004646// This is used to decide if we should transform null and undefined
4647// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004648RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004649 NoHandleAllocation ha;
4650 RUNTIME_ASSERT(args.length() == 1);
4651
4652 Handle<Object> object = args.at<Object>(0);
4653
4654 if (object->IsJSFunction()) {
4655 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004656 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004657 }
4658 return isolate->heap()->undefined_value();
4659}
4660
4661
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662// Set a local property, even if it is READ_ONLY. If the property does not
4663// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004664RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004665 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004666 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004667 CONVERT_CHECKED(JSObject, object, args[0]);
4668 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004669 // Compute attributes.
4670 PropertyAttributes attributes = NONE;
4671 if (args.length() == 4) {
4672 CONVERT_CHECKED(Smi, value_obj, args[3]);
4673 int unchecked_value = value_obj->value();
4674 // Only attribute bits should be set.
4675 RUNTIME_ASSERT(
4676 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4677 attributes = static_cast<PropertyAttributes>(unchecked_value);
4678 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004679
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004680 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004681 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004682}
4683
4684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004685RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004686 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004687 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004689 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004691 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004692 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004693 ? JSReceiver::STRICT_DELETION
4694 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695}
4696
4697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004698static Object* HasLocalPropertyImplementation(Isolate* isolate,
4699 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004700 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004701 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004702 // Handle hidden prototypes. If there's a hidden prototype above this thing
4703 // then we have to check it for properties, because they are supposed to
4704 // look like they are on this object.
4705 Handle<Object> proto(object->GetPrototype());
4706 if (proto->IsJSObject() &&
4707 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004708 return HasLocalPropertyImplementation(isolate,
4709 Handle<JSObject>::cast(proto),
4710 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004711 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004713}
4714
4715
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004716RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004717 NoHandleAllocation ha;
4718 ASSERT(args.length() == 2);
4719 CONVERT_CHECKED(String, key, args[1]);
4720
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004721 uint32_t index;
4722 const bool key_is_array_index = key->AsArrayIndex(&index);
4723
ager@chromium.org9085a012009-05-11 19:22:57 +00004724 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004726 if (obj->IsJSObject()) {
4727 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004728 // Fast case: either the key is a real named property or it is not
4729 // an array index and there are no interceptors or hidden
4730 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004731 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004732 Map* map = object->map();
4733 if (!key_is_array_index &&
4734 !map->has_named_interceptor() &&
4735 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4736 return isolate->heap()->false_value();
4737 }
4738 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004739 HandleScope scope(isolate);
4740 return HasLocalPropertyImplementation(isolate,
4741 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004742 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004743 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004744 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004745 String* string = String::cast(obj);
4746 if (index < static_cast<uint32_t>(string->length())) {
4747 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004748 }
4749 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004750 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751}
4752
4753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004754RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 NoHandleAllocation na;
4756 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004757 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4758 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004760 bool result = receiver->HasProperty(key);
4761 if (isolate->has_pending_exception()) return Failure::Exception();
4762 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763}
4764
4765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004766RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004767 NoHandleAllocation na;
4768 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004769 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4770 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004771
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004772 bool result = receiver->HasElement(index->value());
4773 if (isolate->has_pending_exception()) return Failure::Exception();
4774 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775}
4776
4777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004778RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779 NoHandleAllocation ha;
4780 ASSERT(args.length() == 2);
4781
4782 CONVERT_CHECKED(JSObject, object, args[0]);
4783 CONVERT_CHECKED(String, key, args[1]);
4784
4785 uint32_t index;
4786 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004787 JSObject::LocalElementType type = object->HasLocalElement(index);
4788 switch (type) {
4789 case JSObject::UNDEFINED_ELEMENT:
4790 case JSObject::STRING_CHARACTER_ELEMENT:
4791 return isolate->heap()->false_value();
4792 case JSObject::INTERCEPTED_ELEMENT:
4793 case JSObject::FAST_ELEMENT:
4794 return isolate->heap()->true_value();
4795 case JSObject::DICTIONARY_ELEMENT: {
4796 if (object->IsJSGlobalProxy()) {
4797 Object* proto = object->GetPrototype();
4798 if (proto->IsNull()) {
4799 return isolate->heap()->false_value();
4800 }
4801 ASSERT(proto->IsJSGlobalObject());
4802 object = JSObject::cast(proto);
4803 }
4804 FixedArray* elements = FixedArray::cast(object->elements());
4805 NumberDictionary* dictionary = NULL;
4806 if (elements->map() ==
4807 isolate->heap()->non_strict_arguments_elements_map()) {
4808 dictionary = NumberDictionary::cast(elements->get(1));
4809 } else {
4810 dictionary = NumberDictionary::cast(elements);
4811 }
4812 int entry = dictionary->FindEntry(index);
4813 ASSERT(entry != NumberDictionary::kNotFound);
4814 PropertyDetails details = dictionary->DetailsAt(entry);
4815 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4816 }
4817 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818 }
4819
ager@chromium.org870a0b62008-11-04 11:43:05 +00004820 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004821 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822}
4823
4824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004826 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004828 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4829 bool threw = false;
4830 Handle<JSArray> result = GetKeysFor(object, &threw);
4831 if (threw) return Failure::Exception();
4832 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833}
4834
4835
4836// Returns either a FixedArray as Runtime_GetPropertyNames,
4837// or, if the given object has an enum cache that contains
4838// all enumerable properties of the object and its prototypes
4839// have none, the map of the object. This is used to speed up
4840// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004841RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004842 ASSERT(args.length() == 1);
4843
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004844 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004845
4846 if (raw_object->IsSimpleEnum()) return raw_object->map();
4847
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004848 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004849 Handle<JSReceiver> object(raw_object);
4850 bool threw = false;
4851 Handle<FixedArray> content =
4852 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4853 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854
4855 // Test again, since cache may have been built by preceding call.
4856 if (object->IsSimpleEnum()) return object->map();
4857
4858 return *content;
4859}
4860
4861
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004862// Find the length of the prototype chain that is to to handled as one. If a
4863// prototype object is hidden it is to be viewed as part of the the object it
4864// is prototype for.
4865static int LocalPrototypeChainLength(JSObject* obj) {
4866 int count = 1;
4867 Object* proto = obj->GetPrototype();
4868 while (proto->IsJSObject() &&
4869 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4870 count++;
4871 proto = JSObject::cast(proto)->GetPrototype();
4872 }
4873 return count;
4874}
4875
4876
4877// Return the names of the local named properties.
4878// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004879RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004880 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004881 ASSERT(args.length() == 1);
4882 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004883 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004884 }
4885 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4886
4887 // Skip the global proxy as it has no properties and always delegates to the
4888 // real global object.
4889 if (obj->IsJSGlobalProxy()) {
4890 // Only collect names if access is permitted.
4891 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004892 !isolate->MayNamedAccess(*obj,
4893 isolate->heap()->undefined_value(),
4894 v8::ACCESS_KEYS)) {
4895 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4896 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004897 }
4898 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4899 }
4900
4901 // Find the number of objects making up this.
4902 int length = LocalPrototypeChainLength(*obj);
4903
4904 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004905 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004906 int total_property_count = 0;
4907 Handle<JSObject> jsproto = obj;
4908 for (int i = 0; i < length; i++) {
4909 // Only collect names if access is permitted.
4910 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004911 !isolate->MayNamedAccess(*jsproto,
4912 isolate->heap()->undefined_value(),
4913 v8::ACCESS_KEYS)) {
4914 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4915 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004916 }
4917 int n;
4918 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4919 local_property_count[i] = n;
4920 total_property_count += n;
4921 if (i < length - 1) {
4922 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4923 }
4924 }
4925
4926 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004927 Handle<FixedArray> names =
4928 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004929
4930 // Get the property names.
4931 jsproto = obj;
4932 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004933 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004934 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004935 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4936 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004937 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004938 proto_with_hidden_properties++;
4939 }
4940 if (i < length - 1) {
4941 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4942 }
4943 }
4944
4945 // Filter out name of hidden propeties object.
4946 if (proto_with_hidden_properties > 0) {
4947 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004949 names->length() - proto_with_hidden_properties);
4950 int dest_pos = 0;
4951 for (int i = 0; i < total_property_count; i++) {
4952 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004953 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004954 continue;
4955 }
4956 names->set(dest_pos++, name);
4957 }
4958 }
4959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004960 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004961}
4962
4963
4964// Return the names of the local indexed properties.
4965// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004966RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004967 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004968 ASSERT(args.length() == 1);
4969 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004970 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004971 }
4972 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4973
4974 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004975 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004976 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004978}
4979
4980
4981// Return information on whether an object has a named or indexed interceptor.
4982// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004983RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004985 ASSERT(args.length() == 1);
4986 if (!args[0]->IsJSObject()) {
4987 return Smi::FromInt(0);
4988 }
4989 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4990
4991 int result = 0;
4992 if (obj->HasNamedInterceptor()) result |= 2;
4993 if (obj->HasIndexedInterceptor()) result |= 1;
4994
4995 return Smi::FromInt(result);
4996}
4997
4998
4999// Return property names from named interceptor.
5000// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005001RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005002 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005003 ASSERT(args.length() == 1);
5004 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5005
5006 if (obj->HasNamedInterceptor()) {
5007 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5008 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5009 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005010 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005011}
5012
5013
5014// Return element names from indexed interceptor.
5015// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005016RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005017 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005018 ASSERT(args.length() == 1);
5019 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5020
5021 if (obj->HasIndexedInterceptor()) {
5022 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5023 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5024 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005025 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005026}
5027
5028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005029RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005030 ASSERT_EQ(args.length(), 1);
5031 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005032 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005033 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005034
5035 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005036 // Do access checks before going to the global object.
5037 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005039 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5041 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005042 }
5043
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005044 Handle<Object> proto(object->GetPrototype());
5045 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005046 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005047 object = Handle<JSObject>::cast(proto);
5048 }
5049
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005050 bool threw = false;
5051 Handle<FixedArray> contents =
5052 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5053 if (threw) return Failure::Exception();
5054
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005055 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5056 // property array and since the result is mutable we have to create
5057 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005058 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005059 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005060 for (int i = 0; i < length; i++) {
5061 Object* entry = contents->get(i);
5062 if (entry->IsString()) {
5063 copy->set(i, entry);
5064 } else {
5065 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005066 HandleScope scope(isolate);
5067 Handle<Object> entry_handle(entry, isolate);
5068 Handle<Object> entry_str =
5069 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005070 copy->set(i, *entry_str);
5071 }
5072 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005074}
5075
5076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005077RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005078 NoHandleAllocation ha;
5079 ASSERT(args.length() == 1);
5080
5081 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005082 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005083 it.AdvanceToArgumentsFrame();
5084 JavaScriptFrame* frame = it.frame();
5085
5086 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005087 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005088
5089 // Try to convert the key to an index. If successful and within
5090 // index return the the argument from the frame.
5091 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005092 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005093 return frame->GetParameter(index);
5094 }
5095
5096 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005097 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005098 bool exception = false;
5099 Handle<Object> converted =
5100 Execution::ToString(args.at<Object>(0), &exception);
5101 if (exception) return Failure::Exception();
5102 Handle<String> key = Handle<String>::cast(converted);
5103
5104 // Try to convert the string key into an array index.
5105 if (key->AsArrayIndex(&index)) {
5106 if (index < n) {
5107 return frame->GetParameter(index);
5108 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005109 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005110 }
5111 }
5112
5113 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005114 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5115 if (key->Equals(isolate->heap()->callee_symbol())) {
5116 Object* function = frame->function();
5117 if (function->IsJSFunction() &&
5118 JSFunction::cast(function)->shared()->strict_mode()) {
5119 return isolate->Throw(*isolate->factory()->NewTypeError(
5120 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5121 }
5122 return function;
5123 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005124
5125 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005126 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005127}
5128
5129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005130RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005131 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005132
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005133 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005134 Handle<Object> object = args.at<Object>(0);
5135 if (object->IsJSObject()) {
5136 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005137 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005138 MaybeObject* ok = js_object->TransformToFastProperties(0);
5139 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005140 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005141 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005142 return *object;
5143}
5144
5145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005146RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005147 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005148
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005149 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005150 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005151 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005152 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005153 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005154 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005155 return *object;
5156}
5157
5158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005159RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005160 NoHandleAllocation ha;
5161 ASSERT(args.length() == 1);
5162
5163 return args[0]->ToBoolean();
5164}
5165
5166
5167// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5168// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005169RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005170 NoHandleAllocation ha;
5171
5172 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005173 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005174 HeapObject* heap_obj = HeapObject::cast(obj);
5175
5176 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005177 if (heap_obj->map()->is_undetectable()) {
5178 return isolate->heap()->undefined_symbol();
5179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180
5181 InstanceType instance_type = heap_obj->map()->instance_type();
5182 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005183 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005184 }
5185
5186 switch (instance_type) {
5187 case ODDBALL_TYPE:
5188 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005189 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190 }
5191 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005192 return FLAG_harmony_typeof
5193 ? isolate->heap()->null_symbol()
5194 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195 }
5196 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005197 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005198 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005199 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005200 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201 default:
5202 // For any kind of object not handled above, the spec rule for
5203 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005205 }
5206}
5207
5208
lrn@chromium.org25156de2010-04-06 13:10:27 +00005209static bool AreDigits(const char*s, int from, int to) {
5210 for (int i = from; i < to; i++) {
5211 if (s[i] < '0' || s[i] > '9') return false;
5212 }
5213
5214 return true;
5215}
5216
5217
5218static int ParseDecimalInteger(const char*s, int from, int to) {
5219 ASSERT(to - from < 10); // Overflow is not possible.
5220 ASSERT(from < to);
5221 int d = s[from] - '0';
5222
5223 for (int i = from + 1; i < to; i++) {
5224 d = 10 * d + (s[i] - '0');
5225 }
5226
5227 return d;
5228}
5229
5230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005231RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232 NoHandleAllocation ha;
5233 ASSERT(args.length() == 1);
5234 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005235 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005236
5237 // Fast case: short integer or some sorts of junk values.
5238 int len = subject->length();
5239 if (subject->IsSeqAsciiString()) {
5240 if (len == 0) return Smi::FromInt(0);
5241
5242 char const* data = SeqAsciiString::cast(subject)->GetChars();
5243 bool minus = (data[0] == '-');
5244 int start_pos = (minus ? 1 : 0);
5245
5246 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005247 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005248 } else if (data[start_pos] > '9') {
5249 // Fast check for a junk value. A valid string may start from a
5250 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5251 // the 'I' character ('Infinity'). All of that have codes not greater than
5252 // '9' except 'I'.
5253 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005254 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005255 }
5256 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5257 // The maximal/minimal smi has 10 digits. If the string has less digits we
5258 // know it will fit into the smi-data type.
5259 int d = ParseDecimalInteger(data, start_pos, len);
5260 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005261 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005262 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005263 } else if (!subject->HasHashCode() &&
5264 len <= String::kMaxArrayIndexSize &&
5265 (len == 1 || data[0] != '0')) {
5266 // String hash is not calculated yet but all the data are present.
5267 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005268 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005269#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005270 subject->Hash(); // Force hash calculation.
5271 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5272 static_cast<int>(hash));
5273#endif
5274 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005275 }
5276 return Smi::FromInt(d);
5277 }
5278 }
5279
5280 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005281 return isolate->heap()->NumberFromDouble(
5282 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005283}
5284
5285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005286RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 NoHandleAllocation ha;
5288 ASSERT(args.length() == 1);
5289
5290 CONVERT_CHECKED(JSArray, codes, args[0]);
5291 int length = Smi::cast(codes->length())->value();
5292
5293 // Check if the string can be ASCII.
5294 int i;
5295 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005296 Object* element;
5297 { MaybeObject* maybe_element = codes->GetElement(i);
5298 // We probably can't get an exception here, but just in order to enforce
5299 // the checking of inputs in the runtime calls we check here.
5300 if (!maybe_element->ToObject(&element)) return maybe_element;
5301 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005302 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5303 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5304 break;
5305 }
5306
lrn@chromium.org303ada72010-10-27 09:33:13 +00005307 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005308 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005309 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005310 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005311 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005312 }
5313
lrn@chromium.org303ada72010-10-27 09:33:13 +00005314 Object* object = NULL;
5315 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005316 String* result = String::cast(object);
5317 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005318 Object* element;
5319 { MaybeObject* maybe_element = codes->GetElement(i);
5320 if (!maybe_element->ToObject(&element)) return maybe_element;
5321 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005322 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005323 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 }
5325 return result;
5326}
5327
5328
5329// kNotEscaped is generated by the following:
5330//
5331// #!/bin/perl
5332// for (my $i = 0; $i < 256; $i++) {
5333// print "\n" if $i % 16 == 0;
5334// my $c = chr($i);
5335// my $escaped = 1;
5336// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5337// print $escaped ? "0, " : "1, ";
5338// }
5339
5340
5341static bool IsNotEscaped(uint16_t character) {
5342 // Only for 8 bit characters, the rest are always escaped (in a different way)
5343 ASSERT(character < 256);
5344 static const char kNotEscaped[256] = {
5345 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5346 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5347 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5348 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5349 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5350 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5351 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5353 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5354 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5361 };
5362 return kNotEscaped[character] != 0;
5363}
5364
5365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005366RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005367 const char hex_chars[] = "0123456789ABCDEF";
5368 NoHandleAllocation ha;
5369 ASSERT(args.length() == 1);
5370 CONVERT_CHECKED(String, source, args[0]);
5371
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005372 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005373
5374 int escaped_length = 0;
5375 int length = source->length();
5376 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005377 Access<StringInputBuffer> buffer(
5378 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005379 buffer->Reset(source);
5380 while (buffer->has_more()) {
5381 uint16_t character = buffer->GetNext();
5382 if (character >= 256) {
5383 escaped_length += 6;
5384 } else if (IsNotEscaped(character)) {
5385 escaped_length++;
5386 } else {
5387 escaped_length += 3;
5388 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005389 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005390 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005391 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005392 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005393 return Failure::OutOfMemoryException();
5394 }
5395 }
5396 }
5397 // No length change implies no change. Return original string if no change.
5398 if (escaped_length == length) {
5399 return source;
5400 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005401 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005402 { MaybeObject* maybe_o =
5403 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005404 if (!maybe_o->ToObject(&o)) return maybe_o;
5405 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406 String* destination = String::cast(o);
5407 int dest_position = 0;
5408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005409 Access<StringInputBuffer> buffer(
5410 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 buffer->Rewind();
5412 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005413 uint16_t chr = buffer->GetNext();
5414 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005415 destination->Set(dest_position, '%');
5416 destination->Set(dest_position+1, 'u');
5417 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5418 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5419 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5420 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005421 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005422 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005423 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005424 dest_position++;
5425 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005426 destination->Set(dest_position, '%');
5427 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5428 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005429 dest_position += 3;
5430 }
5431 }
5432 return destination;
5433}
5434
5435
5436static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5437 static const signed char kHexValue['g'] = {
5438 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5439 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5440 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5441 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5442 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5443 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5444 -1, 10, 11, 12, 13, 14, 15 };
5445
5446 if (character1 > 'f') return -1;
5447 int hi = kHexValue[character1];
5448 if (hi == -1) return -1;
5449 if (character2 > 'f') return -1;
5450 int lo = kHexValue[character2];
5451 if (lo == -1) return -1;
5452 return (hi << 4) + lo;
5453}
5454
5455
ager@chromium.org870a0b62008-11-04 11:43:05 +00005456static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005457 int i,
5458 int length,
5459 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005460 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005461 int32_t hi = 0;
5462 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005463 if (character == '%' &&
5464 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005465 source->Get(i + 1) == 'u' &&
5466 (hi = TwoDigitHex(source->Get(i + 2),
5467 source->Get(i + 3))) != -1 &&
5468 (lo = TwoDigitHex(source->Get(i + 4),
5469 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005470 *step = 6;
5471 return (hi << 8) + lo;
5472 } else if (character == '%' &&
5473 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005474 (lo = TwoDigitHex(source->Get(i + 1),
5475 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005476 *step = 3;
5477 return lo;
5478 } else {
5479 *step = 1;
5480 return character;
5481 }
5482}
5483
5484
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005485RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005486 NoHandleAllocation ha;
5487 ASSERT(args.length() == 1);
5488 CONVERT_CHECKED(String, source, args[0]);
5489
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005490 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491
5492 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005493 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494
5495 int unescaped_length = 0;
5496 for (int i = 0; i < length; unescaped_length++) {
5497 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005498 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005499 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005500 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 i += step;
5502 }
5503
5504 // No length change implies no change. Return original string if no change.
5505 if (unescaped_length == length)
5506 return source;
5507
lrn@chromium.org303ada72010-10-27 09:33:13 +00005508 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005509 { MaybeObject* maybe_o =
5510 ascii ?
5511 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5512 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005513 if (!maybe_o->ToObject(&o)) return maybe_o;
5514 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515 String* destination = String::cast(o);
5516
5517 int dest_position = 0;
5518 for (int i = 0; i < length; dest_position++) {
5519 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005520 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521 i += step;
5522 }
5523 return destination;
5524}
5525
5526
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005527static const unsigned int kQuoteTableLength = 128u;
5528
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005529static const int kJsonQuotesCharactersPerEntry = 8;
5530static const char* const JsonQuotes =
5531 "\\u0000 \\u0001 \\u0002 \\u0003 "
5532 "\\u0004 \\u0005 \\u0006 \\u0007 "
5533 "\\b \\t \\n \\u000b "
5534 "\\f \\r \\u000e \\u000f "
5535 "\\u0010 \\u0011 \\u0012 \\u0013 "
5536 "\\u0014 \\u0015 \\u0016 \\u0017 "
5537 "\\u0018 \\u0019 \\u001a \\u001b "
5538 "\\u001c \\u001d \\u001e \\u001f "
5539 " ! \\\" # "
5540 "$ % & ' "
5541 "( ) * + "
5542 ", - . / "
5543 "0 1 2 3 "
5544 "4 5 6 7 "
5545 "8 9 : ; "
5546 "< = > ? "
5547 "@ A B C "
5548 "D E F G "
5549 "H I J K "
5550 "L M N O "
5551 "P Q R S "
5552 "T U V W "
5553 "X Y Z [ "
5554 "\\\\ ] ^ _ "
5555 "` a b c "
5556 "d e f g "
5557 "h i j k "
5558 "l m n o "
5559 "p q r s "
5560 "t u v w "
5561 "x y z { "
5562 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005563
5564
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005565// For a string that is less than 32k characters it should always be
5566// possible to allocate it in new space.
5567static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5568
5569
5570// Doing JSON quoting cannot make the string more than this many times larger.
5571static const int kJsonQuoteWorstCaseBlowup = 6;
5572
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005573static const int kSpaceForQuotesAndComma = 3;
5574static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005575
5576// Covers the entire ASCII range (all other characters are unchanged by JSON
5577// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005578static const byte JsonQuoteLengths[kQuoteTableLength] = {
5579 6, 6, 6, 6, 6, 6, 6, 6,
5580 2, 2, 2, 6, 2, 2, 6, 6,
5581 6, 6, 6, 6, 6, 6, 6, 6,
5582 6, 6, 6, 6, 6, 6, 6, 6,
5583 1, 1, 2, 1, 1, 1, 1, 1,
5584 1, 1, 1, 1, 1, 1, 1, 1,
5585 1, 1, 1, 1, 1, 1, 1, 1,
5586 1, 1, 1, 1, 1, 1, 1, 1,
5587 1, 1, 1, 1, 1, 1, 1, 1,
5588 1, 1, 1, 1, 1, 1, 1, 1,
5589 1, 1, 1, 1, 1, 1, 1, 1,
5590 1, 1, 1, 1, 2, 1, 1, 1,
5591 1, 1, 1, 1, 1, 1, 1, 1,
5592 1, 1, 1, 1, 1, 1, 1, 1,
5593 1, 1, 1, 1, 1, 1, 1, 1,
5594 1, 1, 1, 1, 1, 1, 1, 1,
5595};
5596
5597
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005598template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005599MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005600
5601
5602template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005603MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5604 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005605}
5606
5607
5608template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005609MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5610 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005611}
5612
5613
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005614template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005615static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5616 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005617 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005618 const Char* read_cursor = characters.start();
5619 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005620 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005621 int quoted_length = kSpaceForQuotes;
5622 while (read_cursor < end) {
5623 Char c = *(read_cursor++);
5624 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5625 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005626 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005627 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005628 }
5629 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005630 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5631 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005632 Object* new_object;
5633 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005634 return new_alloc;
5635 }
5636 StringType* new_string = StringType::cast(new_object);
5637
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005638 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005639 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005640 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005641 *(write_cursor++) = '"';
5642
5643 read_cursor = characters.start();
5644 while (read_cursor < end) {
5645 Char c = *(read_cursor++);
5646 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5647 *(write_cursor++) = c;
5648 } else {
5649 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5650 const char* replacement = JsonQuotes +
5651 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5652 for (int i = 0; i < len; i++) {
5653 *write_cursor++ = *replacement++;
5654 }
5655 }
5656 }
5657 *(write_cursor++) = '"';
5658 return new_string;
5659}
5660
5661
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005662template <typename SinkChar, typename SourceChar>
5663static inline SinkChar* WriteQuoteJsonString(
5664 Isolate* isolate,
5665 SinkChar* write_cursor,
5666 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005667 // SinkChar is only char if SourceChar is guaranteed to be char.
5668 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005669 const SourceChar* read_cursor = characters.start();
5670 const SourceChar* end = read_cursor + characters.length();
5671 *(write_cursor++) = '"';
5672 while (read_cursor < end) {
5673 SourceChar c = *(read_cursor++);
5674 if (sizeof(SourceChar) > 1u &&
5675 static_cast<unsigned>(c) >= kQuoteTableLength) {
5676 *(write_cursor++) = static_cast<SinkChar>(c);
5677 } else {
5678 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5679 const char* replacement = JsonQuotes +
5680 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5681 write_cursor[0] = replacement[0];
5682 if (len > 1) {
5683 write_cursor[1] = replacement[1];
5684 if (len > 2) {
5685 ASSERT(len == 6);
5686 write_cursor[2] = replacement[2];
5687 write_cursor[3] = replacement[3];
5688 write_cursor[4] = replacement[4];
5689 write_cursor[5] = replacement[5];
5690 }
5691 }
5692 write_cursor += len;
5693 }
5694 }
5695 *(write_cursor++) = '"';
5696 return write_cursor;
5697}
5698
5699
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005700template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005701static MaybeObject* QuoteJsonString(Isolate* isolate,
5702 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005703 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005704 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005705 int worst_case_length =
5706 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005707 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005708 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005709 }
5710
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005711 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5712 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005713 Object* new_object;
5714 if (!new_alloc->ToObject(&new_object)) {
5715 return new_alloc;
5716 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005717 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005718 // Even if our string is small enough to fit in new space we still have to
5719 // handle it being allocated in old space as may happen in the third
5720 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5721 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005722 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005723 }
5724 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005725 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005726
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005727 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005728 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005729 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005730 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5731 write_cursor,
5732 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005733 int final_length = static_cast<int>(
5734 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005735 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005736 isolate->heap()->new_space()->
5737 template ShrinkStringAtAllocationBoundary<StringType>(
5738 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005739 return new_string;
5740}
5741
5742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005743RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005744 NoHandleAllocation ha;
5745 CONVERT_CHECKED(String, str, args[0]);
5746 if (!str->IsFlat()) {
5747 MaybeObject* try_flatten = str->TryFlatten();
5748 Object* flat;
5749 if (!try_flatten->ToObject(&flat)) {
5750 return try_flatten;
5751 }
5752 str = String::cast(flat);
5753 ASSERT(str->IsFlat());
5754 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005755 String::FlatContent flat = str->GetFlatContent();
5756 ASSERT(flat.IsFlat());
5757 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005758 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005759 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005760 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005761 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005762 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005763 }
5764}
5765
5766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005767RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005768 NoHandleAllocation ha;
5769 CONVERT_CHECKED(String, str, args[0]);
5770 if (!str->IsFlat()) {
5771 MaybeObject* try_flatten = str->TryFlatten();
5772 Object* flat;
5773 if (!try_flatten->ToObject(&flat)) {
5774 return try_flatten;
5775 }
5776 str = String::cast(flat);
5777 ASSERT(str->IsFlat());
5778 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005779 String::FlatContent flat = str->GetFlatContent();
5780 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005781 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005782 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005783 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005784 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005785 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005786 }
5787}
5788
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005789
5790template <typename Char, typename StringType>
5791static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5792 FixedArray* array,
5793 int worst_case_length) {
5794 int length = array->length();
5795
5796 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5797 worst_case_length);
5798 Object* new_object;
5799 if (!new_alloc->ToObject(&new_object)) {
5800 return new_alloc;
5801 }
5802 if (!isolate->heap()->new_space()->Contains(new_object)) {
5803 // Even if our string is small enough to fit in new space we still have to
5804 // handle it being allocated in old space as may happen in the third
5805 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5806 // CEntryStub::GenerateCore.
5807 return isolate->heap()->undefined_value();
5808 }
5809 AssertNoAllocation no_gc;
5810 StringType* new_string = StringType::cast(new_object);
5811 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5812
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005813 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005814 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005815 *(write_cursor++) = '[';
5816 for (int i = 0; i < length; i++) {
5817 if (i != 0) *(write_cursor++) = ',';
5818 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005819 String::FlatContent content = str->GetFlatContent();
5820 ASSERT(content.IsFlat());
5821 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005822 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5823 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005824 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005825 } else {
5826 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5827 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005828 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005829 }
5830 }
5831 *(write_cursor++) = ']';
5832
5833 int final_length = static_cast<int>(
5834 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005835 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005836 isolate->heap()->new_space()->
5837 template ShrinkStringAtAllocationBoundary<StringType>(
5838 new_string, final_length);
5839 return new_string;
5840}
5841
5842
5843RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5844 NoHandleAllocation ha;
5845 ASSERT(args.length() == 1);
5846 CONVERT_CHECKED(JSArray, array, args[0]);
5847
5848 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5849 FixedArray* elements = FixedArray::cast(array->elements());
5850 int n = elements->length();
5851 bool ascii = true;
5852 int total_length = 0;
5853
5854 for (int i = 0; i < n; i++) {
5855 Object* elt = elements->get(i);
5856 if (!elt->IsString()) return isolate->heap()->undefined_value();
5857 String* element = String::cast(elt);
5858 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5859 total_length += element->length();
5860 if (ascii && element->IsTwoByteRepresentation()) {
5861 ascii = false;
5862 }
5863 }
5864
5865 int worst_case_length =
5866 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5867 + total_length * kJsonQuoteWorstCaseBlowup;
5868
5869 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5870 return isolate->heap()->undefined_value();
5871 }
5872
5873 if (ascii) {
5874 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5875 elements,
5876 worst_case_length);
5877 } else {
5878 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5879 elements,
5880 worst_case_length);
5881 }
5882}
5883
5884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005885RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005886 NoHandleAllocation ha;
5887
5888 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005889 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005890
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005891 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892
lrn@chromium.org25156de2010-04-06 13:10:27 +00005893 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005894 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005895 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005896}
5897
5898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005899RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005900 NoHandleAllocation ha;
5901 CONVERT_CHECKED(String, str, args[0]);
5902
5903 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005904 double value = StringToDouble(isolate->unicode_cache(),
5905 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906
5907 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005908 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005909}
5910
5911
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005913MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005914 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005915 String* s,
5916 int length,
5917 int input_string_length,
5918 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005919 // We try this twice, once with the assumption that the result is no longer
5920 // than the input and, if that assumption breaks, again with the exact
5921 // length. This may not be pretty, but it is nicer than what was here before
5922 // and I hereby claim my vaffel-is.
5923 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924 // Allocate the resulting string.
5925 //
5926 // NOTE: This assumes that the upper/lower case of an ascii
5927 // character is also ascii. This is currently the case, but it
5928 // might break in the future if we implement more context and locale
5929 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005930 Object* o;
5931 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005932 ? isolate->heap()->AllocateRawAsciiString(length)
5933 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005934 if (!maybe_o->ToObject(&o)) return maybe_o;
5935 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005936 String* result = String::cast(o);
5937 bool has_changed_character = false;
5938
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939 // Convert all characters to upper case, assuming that they will fit
5940 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005941 Access<StringInputBuffer> buffer(
5942 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005943 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005944 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005945 // We can assume that the string is not empty
5946 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005947 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005948 bool has_next = buffer->has_more();
5949 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005950 int char_length = mapping->get(current, next, chars);
5951 if (char_length == 0) {
5952 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005953 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954 i++;
5955 } else if (char_length == 1) {
5956 // Common case: converting the letter resulted in one character.
5957 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005958 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959 has_changed_character = true;
5960 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005961 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005962 // We've assumed that the result would be as long as the
5963 // input but here is a character that converts to several
5964 // characters. No matter, we calculate the exact length
5965 // of the result and try the whole thing again.
5966 //
5967 // Note that this leaves room for optimization. We could just
5968 // memcpy what we already have to the result string. Also,
5969 // the result string is the last object allocated we could
5970 // "realloc" it and probably, in the vast majority of cases,
5971 // extend the existing string to be able to hold the full
5972 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005973 int next_length = 0;
5974 if (has_next) {
5975 next_length = mapping->get(next, 0, chars);
5976 if (next_length == 0) next_length = 1;
5977 }
5978 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 while (buffer->has_more()) {
5980 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005981 // NOTE: we use 0 as the next character here because, while
5982 // the next character may affect what a character converts to,
5983 // it does not in any case affect the length of what it convert
5984 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005985 int char_length = mapping->get(current, 0, chars);
5986 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005987 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005988 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005989 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005990 return Failure::OutOfMemoryException();
5991 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005993 // Try again with the real length.
5994 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 } else {
5996 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005997 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 i++;
5999 }
6000 has_changed_character = true;
6001 }
6002 current = next;
6003 }
6004 if (has_changed_character) {
6005 return result;
6006 } else {
6007 // If we didn't actually change anything in doing the conversion
6008 // we simple return the result and let the converted string
6009 // become garbage; there is no reason to keep two identical strings
6010 // alive.
6011 return s;
6012 }
6013}
6014
6015
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006016namespace {
6017
lrn@chromium.org303ada72010-10-27 09:33:13 +00006018static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6019
6020
6021// Given a word and two range boundaries returns a word with high bit
6022// set in every byte iff the corresponding input byte was strictly in
6023// the range (m, n). All the other bits in the result are cleared.
6024// This function is only useful when it can be inlined and the
6025// boundaries are statically known.
6026// Requires: all bytes in the input word and the boundaries must be
6027// ascii (less than 0x7F).
6028static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6029 // Every byte in an ascii string is less than or equal to 0x7F.
6030 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6031 // Use strict inequalities since in edge cases the function could be
6032 // further simplified.
6033 ASSERT(0 < m && m < n && n < 0x7F);
6034 // Has high bit set in every w byte less than n.
6035 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6036 // Has high bit set in every w byte greater than m.
6037 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6038 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6039}
6040
6041
6042enum AsciiCaseConversion {
6043 ASCII_TO_LOWER,
6044 ASCII_TO_UPPER
6045};
6046
6047
6048template <AsciiCaseConversion dir>
6049struct FastAsciiConverter {
6050 static bool Convert(char* dst, char* src, int length) {
6051#ifdef DEBUG
6052 char* saved_dst = dst;
6053 char* saved_src = src;
6054#endif
6055 // We rely on the distance between upper and lower case letters
6056 // being a known power of 2.
6057 ASSERT('a' - 'A' == (1 << 5));
6058 // Boundaries for the range of input characters than require conversion.
6059 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6060 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6061 bool changed = false;
6062 char* const limit = src + length;
6063#ifdef V8_HOST_CAN_READ_UNALIGNED
6064 // Process the prefix of the input that requires no conversion one
6065 // (machine) word at a time.
6066 while (src <= limit - sizeof(uintptr_t)) {
6067 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6068 if (AsciiRangeMask(w, lo, hi) != 0) {
6069 changed = true;
6070 break;
6071 }
6072 *reinterpret_cast<uintptr_t*>(dst) = w;
6073 src += sizeof(uintptr_t);
6074 dst += sizeof(uintptr_t);
6075 }
6076 // Process the remainder of the input performing conversion when
6077 // required one word at a time.
6078 while (src <= limit - sizeof(uintptr_t)) {
6079 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6080 uintptr_t m = AsciiRangeMask(w, lo, hi);
6081 // The mask has high (7th) bit set in every byte that needs
6082 // conversion and we know that the distance between cases is
6083 // 1 << 5.
6084 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6085 src += sizeof(uintptr_t);
6086 dst += sizeof(uintptr_t);
6087 }
6088#endif
6089 // Process the last few bytes of the input (or the whole input if
6090 // unaligned access is not supported).
6091 while (src < limit) {
6092 char c = *src;
6093 if (lo < c && c < hi) {
6094 c ^= (1 << 5);
6095 changed = true;
6096 }
6097 *dst = c;
6098 ++src;
6099 ++dst;
6100 }
6101#ifdef DEBUG
6102 CheckConvert(saved_dst, saved_src, length, changed);
6103#endif
6104 return changed;
6105 }
6106
6107#ifdef DEBUG
6108 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6109 bool expected_changed = false;
6110 for (int i = 0; i < length; i++) {
6111 if (dst[i] == src[i]) continue;
6112 expected_changed = true;
6113 if (dir == ASCII_TO_LOWER) {
6114 ASSERT('A' <= src[i] && src[i] <= 'Z');
6115 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6116 } else {
6117 ASSERT(dir == ASCII_TO_UPPER);
6118 ASSERT('a' <= src[i] && src[i] <= 'z');
6119 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6120 }
6121 }
6122 ASSERT(expected_changed == changed);
6123 }
6124#endif
6125};
6126
6127
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006128struct ToLowerTraits {
6129 typedef unibrow::ToLowercase UnibrowConverter;
6130
lrn@chromium.org303ada72010-10-27 09:33:13 +00006131 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006132};
6133
6134
6135struct ToUpperTraits {
6136 typedef unibrow::ToUppercase UnibrowConverter;
6137
lrn@chromium.org303ada72010-10-27 09:33:13 +00006138 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006139};
6140
6141} // namespace
6142
6143
6144template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006145MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006146 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006147 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006149 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006150 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006151 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006152
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006153 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006154 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006155 if (length == 0) return s;
6156
6157 // Simpler handling of ascii strings.
6158 //
6159 // NOTE: This assumes that the upper/lower case of an ascii
6160 // character is also ascii. This is currently the case, but it
6161 // might break in the future if we implement more context and locale
6162 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006163 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006164 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006165 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006166 if (!maybe_o->ToObject(&o)) return maybe_o;
6167 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006168 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006169 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006170 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171 return has_changed_character ? result : s;
6172 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006173
lrn@chromium.org303ada72010-10-27 09:33:13 +00006174 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006175 { MaybeObject* maybe_answer =
6176 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006177 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6178 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006179 if (answer->IsSmi()) {
6180 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006181 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006182 ConvertCaseHelper(isolate,
6183 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006184 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6185 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006186 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006187 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006188}
6189
6190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006191RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 return ConvertCase<ToLowerTraits>(
6193 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006194}
6195
6196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006197RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006198 return ConvertCase<ToUpperTraits>(
6199 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006200}
6201
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006202
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006203static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006204 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006205}
6206
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006208RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006209 NoHandleAllocation ha;
6210 ASSERT(args.length() == 3);
6211
6212 CONVERT_CHECKED(String, s, args[0]);
6213 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6214 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6215
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006217 int length = s->length();
6218
6219 int left = 0;
6220 if (trimLeft) {
6221 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6222 left++;
6223 }
6224 }
6225
6226 int right = length;
6227 if (trimRight) {
6228 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6229 right--;
6230 }
6231 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006232 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006233}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006234
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006236RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006237 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006238 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006239 CONVERT_ARG_CHECKED(String, subject, 0);
6240 CONVERT_ARG_CHECKED(String, pattern, 1);
6241 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6242
6243 int subject_length = subject->length();
6244 int pattern_length = pattern->length();
6245 RUNTIME_ASSERT(pattern_length > 0);
6246
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006247 if (limit == 0xffffffffu) {
6248 Handle<Object> cached_answer(StringSplitCache::Lookup(
6249 isolate->heap()->string_split_cache(),
6250 *subject,
6251 *pattern));
6252 if (*cached_answer != Smi::FromInt(0)) {
6253 Handle<JSArray> result =
6254 isolate->factory()->NewJSArrayWithElements(
6255 Handle<FixedArray>::cast(cached_answer));
6256 return *result;
6257 }
6258 }
6259
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006260 // The limit can be very large (0xffffffffu), but since the pattern
6261 // isn't empty, we can never create more parts than ~half the length
6262 // of the subject.
6263
6264 if (!subject->IsFlat()) FlattenString(subject);
6265
6266 static const int kMaxInitialListCapacity = 16;
6267
danno@chromium.org40cb8782011-05-25 07:58:50 +00006268 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006269
6270 // Find (up to limit) indices of separator and end-of-string in subject
6271 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6272 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006273 if (!pattern->IsFlat()) FlattenString(pattern);
6274
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006275 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006276
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006277 if (static_cast<uint32_t>(indices.length()) < limit) {
6278 indices.Add(subject_length);
6279 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006280
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006281 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006282
6283 // Create JSArray of substrings separated by separator.
6284 int part_count = indices.length();
6285
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006286 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006287 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6288 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006289 result->set_length(Smi::FromInt(part_count));
6290
6291 ASSERT(result->HasFastElements());
6292
6293 if (part_count == 1 && indices.at(0) == subject_length) {
6294 FixedArray::cast(result->elements())->set(0, *subject);
6295 return *result;
6296 }
6297
6298 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6299 int part_start = 0;
6300 for (int i = 0; i < part_count; i++) {
6301 HandleScope local_loop_handle;
6302 int part_end = indices.at(i);
6303 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006304 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 elements->set(i, *substring);
6306 part_start = part_end + pattern_length;
6307 }
6308
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006309 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006310 if (result->HasFastElements()) {
6311 StringSplitCache::Enter(isolate->heap(),
6312 isolate->heap()->string_split_cache(),
6313 *subject,
6314 *pattern,
6315 *elements);
6316 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006317 }
6318
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006319 return *result;
6320}
6321
6322
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006323// Copies ascii characters to the given fixed array looking up
6324// one-char strings in the cache. Gives up on the first char that is
6325// not in the cache and fills the remainder with smi zeros. Returns
6326// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006327static int CopyCachedAsciiCharsToArray(Heap* heap,
6328 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006329 FixedArray* elements,
6330 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006331 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006332 FixedArray* ascii_cache = heap->single_character_string_cache();
6333 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006334 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006335 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006336 for (i = 0; i < length; ++i) {
6337 Object* value = ascii_cache->get(chars[i]);
6338 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006339 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006340 }
6341 if (i < length) {
6342 ASSERT(Smi::FromInt(0) == 0);
6343 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6344 }
6345#ifdef DEBUG
6346 for (int j = 0; j < length; ++j) {
6347 Object* element = elements->get(j);
6348 ASSERT(element == Smi::FromInt(0) ||
6349 (element->IsString() && String::cast(element)->LooksValid()));
6350 }
6351#endif
6352 return i;
6353}
6354
6355
6356// Converts a String to JSArray.
6357// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006358RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006359 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006360 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006361 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006362 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006363
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006364 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006365 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006366
6367 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006368 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006369 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006370 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006371 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006372 { MaybeObject* maybe_obj =
6373 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006374 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6375 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006376 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006377 String::FlatContent content = s->GetFlatContent();
6378 if (content.IsAscii()) {
6379 Vector<const char> chars = content.ToAsciiVector();
6380 // Note, this will initialize all elements (not only the prefix)
6381 // to prevent GC from seeing partially initialized array.
6382 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6383 chars.start(),
6384 *elements,
6385 length);
6386 } else {
6387 MemsetPointer(elements->data_start(),
6388 isolate->heap()->undefined_value(),
6389 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006390 }
6391 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006392 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006393 }
6394 for (int i = position; i < length; ++i) {
6395 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6396 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006397 }
6398
6399#ifdef DEBUG
6400 for (int i = 0; i < length; ++i) {
6401 ASSERT(String::cast(elements->get(i))->length() == 1);
6402 }
6403#endif
6404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006405 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006406}
6407
6408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006409RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006410 NoHandleAllocation ha;
6411 ASSERT(args.length() == 1);
6412 CONVERT_CHECKED(String, value, args[0]);
6413 return value->ToObject();
6414}
6415
6416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006417bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006418 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006419 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006420 return char_length == 0;
6421}
6422
6423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006424RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006425 NoHandleAllocation ha;
6426 ASSERT(args.length() == 1);
6427
6428 Object* number = args[0];
6429 RUNTIME_ASSERT(number->IsNumber());
6430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006431 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006432}
6433
6434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006435RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006436 NoHandleAllocation ha;
6437 ASSERT(args.length() == 1);
6438
6439 Object* number = args[0];
6440 RUNTIME_ASSERT(number->IsNumber());
6441
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006442 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006443}
6444
6445
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006446RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006447 NoHandleAllocation ha;
6448 ASSERT(args.length() == 1);
6449
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006450 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006451
6452 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6453 if (number > 0 && number <= Smi::kMaxValue) {
6454 return Smi::FromInt(static_cast<int>(number));
6455 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457}
6458
6459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006460RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006461 NoHandleAllocation ha;
6462 ASSERT(args.length() == 1);
6463
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006464 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006465
6466 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6467 if (number > 0 && number <= Smi::kMaxValue) {
6468 return Smi::FromInt(static_cast<int>(number));
6469 }
6470
6471 double double_value = DoubleToInteger(number);
6472 // Map both -0 and +0 to +0.
6473 if (double_value == 0) double_value = 0;
6474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006475 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006476}
6477
6478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006479RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006480 NoHandleAllocation ha;
6481 ASSERT(args.length() == 1);
6482
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006483 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006484 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006485}
6486
6487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006488RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006489 NoHandleAllocation ha;
6490 ASSERT(args.length() == 1);
6491
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006492 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006493
6494 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6495 if (number > 0 && number <= Smi::kMaxValue) {
6496 return Smi::FromInt(static_cast<int>(number));
6497 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006498 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006499}
6500
6501
ager@chromium.org870a0b62008-11-04 11:43:05 +00006502// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6503// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006504RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006505 NoHandleAllocation ha;
6506 ASSERT(args.length() == 1);
6507
6508 Object* obj = args[0];
6509 if (obj->IsSmi()) {
6510 return obj;
6511 }
6512 if (obj->IsHeapNumber()) {
6513 double value = HeapNumber::cast(obj)->value();
6514 int int_value = FastD2I(value);
6515 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6516 return Smi::FromInt(int_value);
6517 }
6518 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006519 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006520}
6521
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006523RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006524 NoHandleAllocation ha;
6525 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006526 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006527}
6528
6529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006530RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006531 NoHandleAllocation ha;
6532 ASSERT(args.length() == 2);
6533
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006534 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6535 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006536 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006537}
6538
6539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006540RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006541 NoHandleAllocation ha;
6542 ASSERT(args.length() == 2);
6543
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006544 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6545 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006546 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547}
6548
6549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006550RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006551 NoHandleAllocation ha;
6552 ASSERT(args.length() == 2);
6553
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006554 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6555 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006556 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006557}
6558
6559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006560RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561 NoHandleAllocation ha;
6562 ASSERT(args.length() == 1);
6563
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006564 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006565 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566}
6567
6568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006569RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006570 NoHandleAllocation ha;
6571 ASSERT(args.length() == 0);
6572
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006573 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006574}
6575
6576
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006577RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578 NoHandleAllocation ha;
6579 ASSERT(args.length() == 2);
6580
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006581 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6582 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006583 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584}
6585
6586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006587RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006588 NoHandleAllocation ha;
6589 ASSERT(args.length() == 2);
6590
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006591 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6592 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593
ager@chromium.org3811b432009-10-28 14:53:37 +00006594 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006595 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006596 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006597}
6598
6599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006600RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601 NoHandleAllocation ha;
6602 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603 CONVERT_CHECKED(String, str1, args[0]);
6604 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 isolate->counters()->string_add_runtime()->Increment();
6606 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006607}
6608
6609
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006610template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006611static inline void StringBuilderConcatHelper(String* special,
6612 sinkchar* sink,
6613 FixedArray* fixed_array,
6614 int array_length) {
6615 int position = 0;
6616 for (int i = 0; i < array_length; i++) {
6617 Object* element = fixed_array->get(i);
6618 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006619 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006620 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006621 int pos;
6622 int len;
6623 if (encoded_slice > 0) {
6624 // Position and length encoded in one smi.
6625 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6626 len = StringBuilderSubstringLength::decode(encoded_slice);
6627 } else {
6628 // Position and length encoded in two smis.
6629 Object* obj = fixed_array->get(++i);
6630 ASSERT(obj->IsSmi());
6631 pos = Smi::cast(obj)->value();
6632 len = -encoded_slice;
6633 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006634 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006635 sink + position,
6636 pos,
6637 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006638 position += len;
6639 } else {
6640 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006641 int element_length = string->length();
6642 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006643 position += element_length;
6644 }
6645 }
6646}
6647
6648
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006649RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006650 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006651 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006653 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006654 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006655 return Failure::OutOfMemoryException();
6656 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006657 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006658 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006659
6660 // This assumption is used by the slice encoding in one or two smis.
6661 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6662
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006663 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6664 if (maybe_result->IsFailure()) return maybe_result;
6665
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006666 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006667 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006668 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669 }
6670 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006671 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006674
6675 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006676 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677 } else if (array_length == 1) {
6678 Object* first = fixed_array->get(0);
6679 if (first->IsString()) return first;
6680 }
6681
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006682 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683 int position = 0;
6684 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006685 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 Object* elt = fixed_array->get(i);
6687 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006688 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006689 int smi_value = Smi::cast(elt)->value();
6690 int pos;
6691 int len;
6692 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006693 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006694 pos = StringBuilderSubstringPosition::decode(smi_value);
6695 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006696 } else {
6697 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006698 len = -smi_value;
6699 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006700 i++;
6701 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006702 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006703 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006704 Object* next_smi = fixed_array->get(i);
6705 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006706 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006707 }
6708 pos = Smi::cast(next_smi)->value();
6709 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006710 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006711 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006713 ASSERT(pos >= 0);
6714 ASSERT(len >= 0);
6715 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006716 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006717 }
6718 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006719 } else if (elt->IsString()) {
6720 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006721 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006722 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006723 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006724 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006725 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006726 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006727 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006729 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006730 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006731 return Failure::OutOfMemoryException();
6732 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006733 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006734 }
6735
6736 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006739 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006740 { MaybeObject* maybe_object =
6741 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006742 if (!maybe_object->ToObject(&object)) return maybe_object;
6743 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006744 SeqAsciiString* answer = SeqAsciiString::cast(object);
6745 StringBuilderConcatHelper(special,
6746 answer->GetChars(),
6747 fixed_array,
6748 array_length);
6749 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006751 { MaybeObject* maybe_object =
6752 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006753 if (!maybe_object->ToObject(&object)) return maybe_object;
6754 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006755 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6756 StringBuilderConcatHelper(special,
6757 answer->GetChars(),
6758 fixed_array,
6759 array_length);
6760 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762}
6763
6764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006765RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006766 NoHandleAllocation ha;
6767 ASSERT(args.length() == 3);
6768 CONVERT_CHECKED(JSArray, array, args[0]);
6769 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006770 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006771 return Failure::OutOfMemoryException();
6772 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006773 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006774 CONVERT_CHECKED(String, separator, args[2]);
6775
6776 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006777 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006778 }
6779 FixedArray* fixed_array = FixedArray::cast(array->elements());
6780 if (fixed_array->length() < array_length) {
6781 array_length = fixed_array->length();
6782 }
6783
6784 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006785 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006786 } else if (array_length == 1) {
6787 Object* first = fixed_array->get(0);
6788 if (first->IsString()) return first;
6789 }
6790
6791 int separator_length = separator->length();
6792 int max_nof_separators =
6793 (String::kMaxLength + separator_length - 1) / separator_length;
6794 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006795 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006796 return Failure::OutOfMemoryException();
6797 }
6798 int length = (array_length - 1) * separator_length;
6799 for (int i = 0; i < array_length; i++) {
6800 Object* element_obj = fixed_array->get(i);
6801 if (!element_obj->IsString()) {
6802 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006803 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006804 }
6805 String* element = String::cast(element_obj);
6806 int increment = element->length();
6807 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006808 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006809 return Failure::OutOfMemoryException();
6810 }
6811 length += increment;
6812 }
6813
6814 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006815 { MaybeObject* maybe_object =
6816 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006817 if (!maybe_object->ToObject(&object)) return maybe_object;
6818 }
6819 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6820
6821 uc16* sink = answer->GetChars();
6822#ifdef DEBUG
6823 uc16* end = sink + length;
6824#endif
6825
6826 String* first = String::cast(fixed_array->get(0));
6827 int first_length = first->length();
6828 String::WriteToFlat(first, sink, 0, first_length);
6829 sink += first_length;
6830
6831 for (int i = 1; i < array_length; i++) {
6832 ASSERT(sink + separator_length <= end);
6833 String::WriteToFlat(separator, sink, 0, separator_length);
6834 sink += separator_length;
6835
6836 String* element = String::cast(fixed_array->get(i));
6837 int element_length = element->length();
6838 ASSERT(sink + element_length <= end);
6839 String::WriteToFlat(element, sink, 0, element_length);
6840 sink += element_length;
6841 }
6842 ASSERT(sink == end);
6843
6844 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6845 return answer;
6846}
6847
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006848template <typename Char>
6849static void JoinSparseArrayWithSeparator(FixedArray* elements,
6850 int elements_length,
6851 uint32_t array_length,
6852 String* separator,
6853 Vector<Char> buffer) {
6854 int previous_separator_position = 0;
6855 int separator_length = separator->length();
6856 int cursor = 0;
6857 for (int i = 0; i < elements_length; i += 2) {
6858 int position = NumberToInt32(elements->get(i));
6859 String* string = String::cast(elements->get(i + 1));
6860 int string_length = string->length();
6861 if (string->length() > 0) {
6862 while (previous_separator_position < position) {
6863 String::WriteToFlat<Char>(separator, &buffer[cursor],
6864 0, separator_length);
6865 cursor += separator_length;
6866 previous_separator_position++;
6867 }
6868 String::WriteToFlat<Char>(string, &buffer[cursor],
6869 0, string_length);
6870 cursor += string->length();
6871 }
6872 }
6873 if (separator_length > 0) {
6874 // Array length must be representable as a signed 32-bit number,
6875 // otherwise the total string length would have been too large.
6876 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6877 int last_array_index = static_cast<int>(array_length - 1);
6878 while (previous_separator_position < last_array_index) {
6879 String::WriteToFlat<Char>(separator, &buffer[cursor],
6880 0, separator_length);
6881 cursor += separator_length;
6882 previous_separator_position++;
6883 }
6884 }
6885 ASSERT(cursor <= buffer.length());
6886}
6887
6888
6889RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6890 NoHandleAllocation ha;
6891 ASSERT(args.length() == 3);
6892 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006893 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6894 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006895 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6896 CONVERT_CHECKED(String, separator, args[2]);
6897 // elements_array is fast-mode JSarray of alternating positions
6898 // (increasing order) and strings.
6899 // array_length is length of original array (used to add separators);
6900 // separator is string to put between elements. Assumed to be non-empty.
6901
6902 // Find total length of join result.
6903 int string_length = 0;
6904 bool is_ascii = true;
6905 int max_string_length = SeqAsciiString::kMaxLength;
6906 bool overflow = false;
6907 CONVERT_NUMBER_CHECKED(int, elements_length,
6908 Int32, elements_array->length());
6909 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6910 FixedArray* elements = FixedArray::cast(elements_array->elements());
6911 for (int i = 0; i < elements_length; i += 2) {
6912 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6913 CONVERT_CHECKED(String, string, elements->get(i + 1));
6914 int length = string->length();
6915 if (is_ascii && !string->IsAsciiRepresentation()) {
6916 is_ascii = false;
6917 max_string_length = SeqTwoByteString::kMaxLength;
6918 }
6919 if (length > max_string_length ||
6920 max_string_length - length < string_length) {
6921 overflow = true;
6922 break;
6923 }
6924 string_length += length;
6925 }
6926 int separator_length = separator->length();
6927 if (!overflow && separator_length > 0) {
6928 if (array_length <= 0x7fffffffu) {
6929 int separator_count = static_cast<int>(array_length) - 1;
6930 int remaining_length = max_string_length - string_length;
6931 if ((remaining_length / separator_length) >= separator_count) {
6932 string_length += separator_length * (array_length - 1);
6933 } else {
6934 // Not room for the separators within the maximal string length.
6935 overflow = true;
6936 }
6937 } else {
6938 // Nonempty separator and at least 2^31-1 separators necessary
6939 // means that the string is too large to create.
6940 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6941 overflow = true;
6942 }
6943 }
6944 if (overflow) {
6945 // Throw OutOfMemory exception for creating too large a string.
6946 V8::FatalProcessOutOfMemory("Array join result too large.");
6947 }
6948
6949 if (is_ascii) {
6950 MaybeObject* result_allocation =
6951 isolate->heap()->AllocateRawAsciiString(string_length);
6952 if (result_allocation->IsFailure()) return result_allocation;
6953 SeqAsciiString* result_string =
6954 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6955 JoinSparseArrayWithSeparator<char>(elements,
6956 elements_length,
6957 array_length,
6958 separator,
6959 Vector<char>(result_string->GetChars(),
6960 string_length));
6961 return result_string;
6962 } else {
6963 MaybeObject* result_allocation =
6964 isolate->heap()->AllocateRawTwoByteString(string_length);
6965 if (result_allocation->IsFailure()) return result_allocation;
6966 SeqTwoByteString* result_string =
6967 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6968 JoinSparseArrayWithSeparator<uc16>(elements,
6969 elements_length,
6970 array_length,
6971 separator,
6972 Vector<uc16>(result_string->GetChars(),
6973 string_length));
6974 return result_string;
6975 }
6976}
6977
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006979RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006980 NoHandleAllocation ha;
6981 ASSERT(args.length() == 2);
6982
6983 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6984 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006985 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986}
6987
6988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006989RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006990 NoHandleAllocation ha;
6991 ASSERT(args.length() == 2);
6992
6993 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6994 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006995 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006996}
6997
6998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006999RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007000 NoHandleAllocation ha;
7001 ASSERT(args.length() == 2);
7002
7003 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7004 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007005 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007006}
7007
7008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007009RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007010 NoHandleAllocation ha;
7011 ASSERT(args.length() == 1);
7012
7013 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007014 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007015}
7016
7017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007019 NoHandleAllocation ha;
7020 ASSERT(args.length() == 2);
7021
7022 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7023 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007024 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025}
7026
7027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007028RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029 NoHandleAllocation ha;
7030 ASSERT(args.length() == 2);
7031
7032 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7033 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007034 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035}
7036
7037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007038RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007039 NoHandleAllocation ha;
7040 ASSERT(args.length() == 2);
7041
7042 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7043 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007044 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045}
7046
7047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007048RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007049 NoHandleAllocation ha;
7050 ASSERT(args.length() == 2);
7051
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007052 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7053 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7055 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7056 if (x == y) return Smi::FromInt(EQUAL);
7057 Object* result;
7058 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7059 result = Smi::FromInt(EQUAL);
7060 } else {
7061 result = Smi::FromInt(NOT_EQUAL);
7062 }
7063 return result;
7064}
7065
7066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007067RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 NoHandleAllocation ha;
7069 ASSERT(args.length() == 2);
7070
7071 CONVERT_CHECKED(String, x, args[0]);
7072 CONVERT_CHECKED(String, y, args[1]);
7073
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007074 bool not_equal = !x->Equals(y);
7075 // This is slightly convoluted because the value that signifies
7076 // equality is 0 and inequality is 1 so we have to negate the result
7077 // from String::Equals.
7078 ASSERT(not_equal == 0 || not_equal == 1);
7079 STATIC_CHECK(EQUAL == 0);
7080 STATIC_CHECK(NOT_EQUAL == 1);
7081 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007082}
7083
7084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007085RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007086 NoHandleAllocation ha;
7087 ASSERT(args.length() == 3);
7088
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007089 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7090 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091 if (isnan(x) || isnan(y)) return args[2];
7092 if (x == y) return Smi::FromInt(EQUAL);
7093 if (isless(x, y)) return Smi::FromInt(LESS);
7094 return Smi::FromInt(GREATER);
7095}
7096
7097
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007098// Compare two Smis as if they were converted to strings and then
7099// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007100RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007101 NoHandleAllocation ha;
7102 ASSERT(args.length() == 2);
7103
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007104 // Extract the integer values from the Smis.
7105 CONVERT_CHECKED(Smi, x, args[0]);
7106 CONVERT_CHECKED(Smi, y, args[1]);
7107 int x_value = x->value();
7108 int y_value = y->value();
7109
7110 // If the integers are equal so are the string representations.
7111 if (x_value == y_value) return Smi::FromInt(EQUAL);
7112
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007113 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007114 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007115 if (x_value == 0 || y_value == 0)
7116 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007117
ager@chromium.org32912102009-01-16 10:38:43 +00007118 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007119 // smallest because the char code of '-' is less than the char code
7120 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007121
7122 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7123 // architectures using 32-bit Smis.
7124 uint32_t x_scaled = x_value;
7125 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007126 if (x_value < 0 || y_value < 0) {
7127 if (y_value >= 0) return Smi::FromInt(LESS);
7128 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007129 x_scaled = -x_value;
7130 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007131 }
7132
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007133 static const uint32_t kPowersOf10[] = {
7134 1, 10, 100, 1000, 10*1000, 100*1000,
7135 1000*1000, 10*1000*1000, 100*1000*1000,
7136 1000*1000*1000
7137 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007138
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007139 // If the integers have the same number of decimal digits they can be
7140 // compared directly as the numeric order is the same as the
7141 // lexicographic order. If one integer has fewer digits, it is scaled
7142 // by some power of 10 to have the same number of digits as the longer
7143 // integer. If the scaled integers are equal it means the shorter
7144 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007145
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007146 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7147 int x_log2 = IntegerLog2(x_scaled);
7148 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7149 x_log10 -= x_scaled < kPowersOf10[x_log10];
7150
7151 int y_log2 = IntegerLog2(y_scaled);
7152 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7153 y_log10 -= y_scaled < kPowersOf10[y_log10];
7154
7155 int tie = EQUAL;
7156
7157 if (x_log10 < y_log10) {
7158 // X has fewer digits. We would like to simply scale up X but that
7159 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7160 // be scaled up to 9_000_000_000. So we scale up by the next
7161 // smallest power and scale down Y to drop one digit. It is OK to
7162 // drop one digit from the longer integer since the final digit is
7163 // past the length of the shorter integer.
7164 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7165 y_scaled /= 10;
7166 tie = LESS;
7167 } else if (y_log10 < x_log10) {
7168 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7169 x_scaled /= 10;
7170 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007171 }
7172
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007173 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7174 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7175 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007176}
7177
7178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007179static Object* StringInputBufferCompare(RuntimeState* state,
7180 String* x,
7181 String* y) {
7182 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7183 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007184 bufx.Reset(x);
7185 bufy.Reset(y);
7186 while (bufx.has_more() && bufy.has_more()) {
7187 int d = bufx.GetNext() - bufy.GetNext();
7188 if (d < 0) return Smi::FromInt(LESS);
7189 else if (d > 0) return Smi::FromInt(GREATER);
7190 }
7191
7192 // x is (non-trivial) prefix of y:
7193 if (bufy.has_more()) return Smi::FromInt(LESS);
7194 // y is prefix of x:
7195 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7196}
7197
7198
7199static Object* FlatStringCompare(String* x, String* y) {
7200 ASSERT(x->IsFlat());
7201 ASSERT(y->IsFlat());
7202 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7203 int prefix_length = x->length();
7204 if (y->length() < prefix_length) {
7205 prefix_length = y->length();
7206 equal_prefix_result = Smi::FromInt(GREATER);
7207 } else if (y->length() > prefix_length) {
7208 equal_prefix_result = Smi::FromInt(LESS);
7209 }
7210 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007211 String::FlatContent x_content = x->GetFlatContent();
7212 String::FlatContent y_content = y->GetFlatContent();
7213 if (x_content.IsAscii()) {
7214 Vector<const char> x_chars = x_content.ToAsciiVector();
7215 if (y_content.IsAscii()) {
7216 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007217 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007218 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007219 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007220 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7221 }
7222 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007223 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7224 if (y_content.IsAscii()) {
7225 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007226 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7227 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007228 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007229 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7230 }
7231 }
7232 Object* result;
7233 if (r == 0) {
7234 result = equal_prefix_result;
7235 } else {
7236 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7237 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007238 ASSERT(result ==
7239 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007240 return result;
7241}
7242
7243
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007244RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007245 NoHandleAllocation ha;
7246 ASSERT(args.length() == 2);
7247
7248 CONVERT_CHECKED(String, x, args[0]);
7249 CONVERT_CHECKED(String, y, args[1]);
7250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007251 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007253 // A few fast case tests before we flatten.
7254 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007255 if (y->length() == 0) {
7256 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007257 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007258 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007259 return Smi::FromInt(LESS);
7260 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007261
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007262 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007263 if (d < 0) return Smi::FromInt(LESS);
7264 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265
lrn@chromium.org303ada72010-10-27 09:33:13 +00007266 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007267 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007268 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7269 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007270 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007271 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7272 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007273
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007274 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007275 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276}
7277
7278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007279RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007280 NoHandleAllocation ha;
7281 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007282 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007284 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007285 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007286}
7287
7288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007289RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290 NoHandleAllocation ha;
7291 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007292 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007293
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007294 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007295 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007296}
7297
7298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007299RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007300 NoHandleAllocation ha;
7301 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007302 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007304 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306}
7307
7308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007309static const double kPiDividedBy4 = 0.78539816339744830962;
7310
7311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007312RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313 NoHandleAllocation ha;
7314 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007315 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007316
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007317 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7318 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319 double result;
7320 if (isinf(x) && isinf(y)) {
7321 // Make sure that the result in case of two infinite arguments
7322 // is a multiple of Pi / 4. The sign of the result is determined
7323 // by the first argument (x) and the sign of the second argument
7324 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007325 int multiplier = (x < 0) ? -1 : 1;
7326 if (y < 0) multiplier *= 3;
7327 result = multiplier * kPiDividedBy4;
7328 } else {
7329 result = atan2(x, y);
7330 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007331 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007332}
7333
7334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007335RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007336 NoHandleAllocation ha;
7337 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007338 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007340 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007341 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007342}
7343
7344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007345RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346 NoHandleAllocation ha;
7347 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007348 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007350 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007351 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007352}
7353
7354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007355RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356 NoHandleAllocation ha;
7357 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007358 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007359
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007360 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007362}
7363
7364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007365RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366 NoHandleAllocation ha;
7367 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007368 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007370 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372}
7373
7374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007375RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376 NoHandleAllocation ha;
7377 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007378 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007380 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007381 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007382}
7383
7384
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007385RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386 NoHandleAllocation ha;
7387 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007388 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007390 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007391
7392 // If the second argument is a smi, it is much faster to call the
7393 // custom powi() function than the generic pow().
7394 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007395 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007397 }
7398
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007399 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007400 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007401}
7402
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007403// Fast version of Math.pow if we know that y is not an integer and
7404// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007405RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007406 NoHandleAllocation ha;
7407 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7409 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007410 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007411 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007412 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007413 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007414 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007415 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007416 }
7417}
7418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007420RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421 NoHandleAllocation ha;
7422 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007423 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007424
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007425 if (!args[0]->IsHeapNumber()) {
7426 // Must be smi. Return the argument unchanged for all the other types
7427 // to make fuzz-natives test happy.
7428 return args[0];
7429 }
7430
7431 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7432
7433 double value = number->value();
7434 int exponent = number->get_exponent();
7435 int sign = number->get_sign();
7436
danno@chromium.org160a7b02011-04-18 15:51:38 +00007437 if (exponent < -1) {
7438 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7439 if (sign) return isolate->heap()->minus_zero_value();
7440 return Smi::FromInt(0);
7441 }
7442
7443 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7444 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7445 // agument holds for 32-bit smis).
7446 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007447 return Smi::FromInt(static_cast<int>(value + 0.5));
7448 }
7449
7450 // If the magnitude is big enough, there's no place for fraction part. If we
7451 // try to add 0.5 to this number, 1.0 will be added instead.
7452 if (exponent >= 52) {
7453 return number;
7454 }
7455
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007456 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007457
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007458 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007459 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007460}
7461
7462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007463RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007464 NoHandleAllocation ha;
7465 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007466 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007468 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007469 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007470}
7471
7472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007473RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474 NoHandleAllocation ha;
7475 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007476 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007477
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007478 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007479 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007480}
7481
7482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007483RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007484 NoHandleAllocation ha;
7485 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007486 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007487
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007488 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007489 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490}
7491
7492
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007493static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007494 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7495 181, 212, 243, 273, 304, 334};
7496 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7497 182, 213, 244, 274, 305, 335};
7498
7499 year += month / 12;
7500 month %= 12;
7501 if (month < 0) {
7502 year--;
7503 month += 12;
7504 }
7505
7506 ASSERT(month >= 0);
7507 ASSERT(month < 12);
7508
7509 // year_delta is an arbitrary number such that:
7510 // a) year_delta = -1 (mod 400)
7511 // b) year + year_delta > 0 for years in the range defined by
7512 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7513 // Jan 1 1970. This is required so that we don't run into integer
7514 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007515 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007516 // operations.
7517 static const int year_delta = 399999;
7518 static const int base_day = 365 * (1970 + year_delta) +
7519 (1970 + year_delta) / 4 -
7520 (1970 + year_delta) / 100 +
7521 (1970 + year_delta) / 400;
7522
7523 int year1 = year + year_delta;
7524 int day_from_year = 365 * year1 +
7525 year1 / 4 -
7526 year1 / 100 +
7527 year1 / 400 -
7528 base_day;
7529
7530 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007531 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007532 }
7533
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007534 return day_from_year + day_from_month_leap[month] + day - 1;
7535}
7536
7537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007538RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007539 NoHandleAllocation ha;
7540 ASSERT(args.length() == 3);
7541
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007542 CONVERT_SMI_ARG_CHECKED(year, 0);
7543 CONVERT_SMI_ARG_CHECKED(month, 1);
7544 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007545
7546 return Smi::FromInt(MakeDay(year, month, date));
7547}
7548
7549
7550static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7551static const int kDaysIn4Years = 4 * 365 + 1;
7552static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7553static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7554static const int kDays1970to2000 = 30 * 365 + 7;
7555static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7556 kDays1970to2000;
7557static const int kYearsOffset = 400000;
7558
7559static const char kDayInYear[] = {
7560 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7561 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7562 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7563 22, 23, 24, 25, 26, 27, 28,
7564 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7565 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7566 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7567 22, 23, 24, 25, 26, 27, 28, 29, 30,
7568 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7569 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7570 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7571 22, 23, 24, 25, 26, 27, 28, 29, 30,
7572 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7573 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7574 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7575 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7576 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7577 22, 23, 24, 25, 26, 27, 28, 29, 30,
7578 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7579 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7580 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7581 22, 23, 24, 25, 26, 27, 28, 29, 30,
7582 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7583 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7584
7585 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7586 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7587 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7588 22, 23, 24, 25, 26, 27, 28,
7589 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7590 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7591 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7592 22, 23, 24, 25, 26, 27, 28, 29, 30,
7593 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7594 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7595 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7596 22, 23, 24, 25, 26, 27, 28, 29, 30,
7597 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7598 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7599 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7600 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7601 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7602 22, 23, 24, 25, 26, 27, 28, 29, 30,
7603 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7604 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7605 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7606 22, 23, 24, 25, 26, 27, 28, 29, 30,
7607 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7608 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7609
7610 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7611 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7612 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7613 22, 23, 24, 25, 26, 27, 28, 29,
7614 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7615 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7616 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7617 22, 23, 24, 25, 26, 27, 28, 29, 30,
7618 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7619 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7620 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7621 22, 23, 24, 25, 26, 27, 28, 29, 30,
7622 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7623 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7624 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7625 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7626 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7627 22, 23, 24, 25, 26, 27, 28, 29, 30,
7628 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7629 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7630 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7631 22, 23, 24, 25, 26, 27, 28, 29, 30,
7632 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7633 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7634
7635 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7636 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7637 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7638 22, 23, 24, 25, 26, 27, 28,
7639 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7640 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7641 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7642 22, 23, 24, 25, 26, 27, 28, 29, 30,
7643 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7644 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7645 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7646 22, 23, 24, 25, 26, 27, 28, 29, 30,
7647 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7648 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7649 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7650 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7651 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7652 22, 23, 24, 25, 26, 27, 28, 29, 30,
7653 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7654 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7655 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7656 22, 23, 24, 25, 26, 27, 28, 29, 30,
7657 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7658 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7659
7660static const char kMonthInYear[] = {
7661 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,
7662 0, 0, 0, 0, 0, 0,
7663 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,
7664 1, 1, 1,
7665 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,
7666 2, 2, 2, 2, 2, 2,
7667 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,
7668 3, 3, 3, 3, 3,
7669 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,
7670 4, 4, 4, 4, 4, 4,
7671 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,
7672 5, 5, 5, 5, 5,
7673 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,
7674 6, 6, 6, 6, 6, 6,
7675 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,
7676 7, 7, 7, 7, 7, 7,
7677 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,
7678 8, 8, 8, 8, 8,
7679 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,
7680 9, 9, 9, 9, 9, 9,
7681 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7682 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7683 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7684 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7685
7686 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,
7687 0, 0, 0, 0, 0, 0,
7688 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,
7689 1, 1, 1,
7690 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,
7691 2, 2, 2, 2, 2, 2,
7692 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,
7693 3, 3, 3, 3, 3,
7694 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,
7695 4, 4, 4, 4, 4, 4,
7696 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,
7697 5, 5, 5, 5, 5,
7698 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,
7699 6, 6, 6, 6, 6, 6,
7700 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,
7701 7, 7, 7, 7, 7, 7,
7702 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,
7703 8, 8, 8, 8, 8,
7704 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,
7705 9, 9, 9, 9, 9, 9,
7706 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7707 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7708 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7709 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7710
7711 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,
7712 0, 0, 0, 0, 0, 0,
7713 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,
7714 1, 1, 1, 1,
7715 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,
7716 2, 2, 2, 2, 2, 2,
7717 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,
7718 3, 3, 3, 3, 3,
7719 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,
7720 4, 4, 4, 4, 4, 4,
7721 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,
7722 5, 5, 5, 5, 5,
7723 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,
7724 6, 6, 6, 6, 6, 6,
7725 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,
7726 7, 7, 7, 7, 7, 7,
7727 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,
7728 8, 8, 8, 8, 8,
7729 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,
7730 9, 9, 9, 9, 9, 9,
7731 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7732 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7733 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7734 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7735
7736 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,
7737 0, 0, 0, 0, 0, 0,
7738 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,
7739 1, 1, 1,
7740 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,
7741 2, 2, 2, 2, 2, 2,
7742 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,
7743 3, 3, 3, 3, 3,
7744 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,
7745 4, 4, 4, 4, 4, 4,
7746 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,
7747 5, 5, 5, 5, 5,
7748 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,
7749 6, 6, 6, 6, 6, 6,
7750 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,
7751 7, 7, 7, 7, 7, 7,
7752 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,
7753 8, 8, 8, 8, 8,
7754 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,
7755 9, 9, 9, 9, 9, 9,
7756 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7757 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7758 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7759 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7760
7761
7762// This function works for dates from 1970 to 2099.
7763static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007764 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007765#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007766 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007767#endif
7768
7769 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7770 date %= kDaysIn4Years;
7771
7772 month = kMonthInYear[date];
7773 day = kDayInYear[date];
7774
7775 ASSERT(MakeDay(year, month, day) == save_date);
7776}
7777
7778
7779static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007780 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007781#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007782 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007783#endif
7784
7785 date += kDaysOffset;
7786 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7787 date %= kDaysIn400Years;
7788
7789 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7790
7791 date--;
7792 int yd1 = date / kDaysIn100Years;
7793 date %= kDaysIn100Years;
7794 year += 100 * yd1;
7795
7796 date++;
7797 int yd2 = date / kDaysIn4Years;
7798 date %= kDaysIn4Years;
7799 year += 4 * yd2;
7800
7801 date--;
7802 int yd3 = date / 365;
7803 date %= 365;
7804 year += yd3;
7805
7806 bool is_leap = (!yd1 || yd2) && !yd3;
7807
7808 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007809 ASSERT(is_leap || (date >= 0));
7810 ASSERT((date < 365) || (is_leap && (date < 366)));
7811 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7812 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7813 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007814
7815 if (is_leap) {
7816 day = kDayInYear[2*365 + 1 + date];
7817 month = kMonthInYear[2*365 + 1 + date];
7818 } else {
7819 day = kDayInYear[date];
7820 month = kMonthInYear[date];
7821 }
7822
7823 ASSERT(MakeDay(year, month, day) == save_date);
7824}
7825
7826
7827static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007828 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007829 if (date >= 0 && date < 32 * kDaysIn4Years) {
7830 DateYMDFromTimeAfter1970(date, year, month, day);
7831 } else {
7832 DateYMDFromTimeSlow(date, year, month, day);
7833 }
7834}
7835
7836
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007837RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007838 NoHandleAllocation ha;
7839 ASSERT(args.length() == 2);
7840
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007841 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007842 CONVERT_CHECKED(JSArray, res_array, args[1]);
7843
7844 int year, month, day;
7845 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7846
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007847 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7848 RUNTIME_ASSERT(elms_base->length() == 3);
7849 RUNTIME_ASSERT(res_array->GetElementsKind() <= FAST_DOUBLE_ELEMENTS);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007850
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007851 if (res_array->HasFastDoubleElements()) {
7852 FixedDoubleArray* elms = FixedDoubleArray::cast(res_array->elements());
7853 elms->set(0, year);
7854 elms->set(1, month);
7855 elms->set(2, day);
7856 } else {
7857 FixedArray* elms = FixedArray::cast(res_array->elements());
7858 elms->set(0, Smi::FromInt(year));
7859 elms->set(1, Smi::FromInt(month));
7860 elms->set(2, Smi::FromInt(day));
7861 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007862
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007863 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007864}
7865
7866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007867RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007868 HandleScope scope(isolate);
7869 ASSERT(args.length() == 3);
7870
7871 Handle<JSFunction> callee = args.at<JSFunction>(0);
7872 Object** parameters = reinterpret_cast<Object**>(args[1]);
7873 const int argument_count = Smi::cast(args[2])->value();
7874
7875 Handle<JSObject> result =
7876 isolate->factory()->NewArgumentsObject(callee, argument_count);
7877 // Allocate the elements if needed.
7878 int parameter_count = callee->shared()->formal_parameter_count();
7879 if (argument_count > 0) {
7880 if (parameter_count > 0) {
7881 int mapped_count = Min(argument_count, parameter_count);
7882 Handle<FixedArray> parameter_map =
7883 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7884 parameter_map->set_map(
7885 isolate->heap()->non_strict_arguments_elements_map());
7886
7887 Handle<Map> old_map(result->map());
7888 Handle<Map> new_map =
7889 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007890 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007891
7892 result->set_map(*new_map);
7893 result->set_elements(*parameter_map);
7894
7895 // Store the context and the arguments array at the beginning of the
7896 // parameter map.
7897 Handle<Context> context(isolate->context());
7898 Handle<FixedArray> arguments =
7899 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7900 parameter_map->set(0, *context);
7901 parameter_map->set(1, *arguments);
7902
7903 // Loop over the actual parameters backwards.
7904 int index = argument_count - 1;
7905 while (index >= mapped_count) {
7906 // These go directly in the arguments array and have no
7907 // corresponding slot in the parameter map.
7908 arguments->set(index, *(parameters - index - 1));
7909 --index;
7910 }
7911
7912 ScopeInfo<> scope_info(callee->shared()->scope_info());
7913 while (index >= 0) {
7914 // Detect duplicate names to the right in the parameter list.
7915 Handle<String> name = scope_info.parameter_name(index);
7916 int context_slot_count = scope_info.number_of_context_slots();
7917 bool duplicate = false;
7918 for (int j = index + 1; j < parameter_count; ++j) {
7919 if (scope_info.parameter_name(j).is_identical_to(name)) {
7920 duplicate = true;
7921 break;
7922 }
7923 }
7924
7925 if (duplicate) {
7926 // This goes directly in the arguments array with a hole in the
7927 // parameter map.
7928 arguments->set(index, *(parameters - index - 1));
7929 parameter_map->set_the_hole(index + 2);
7930 } else {
7931 // The context index goes in the parameter map with a hole in the
7932 // arguments array.
7933 int context_index = -1;
7934 for (int j = Context::MIN_CONTEXT_SLOTS;
7935 j < context_slot_count;
7936 ++j) {
7937 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7938 context_index = j;
7939 break;
7940 }
7941 }
7942 ASSERT(context_index >= 0);
7943 arguments->set_the_hole(index);
7944 parameter_map->set(index + 2, Smi::FromInt(context_index));
7945 }
7946
7947 --index;
7948 }
7949 } else {
7950 // If there is no aliasing, the arguments object elements are not
7951 // special in any way.
7952 Handle<FixedArray> elements =
7953 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7954 result->set_elements(*elements);
7955 for (int i = 0; i < argument_count; ++i) {
7956 elements->set(i, *(parameters - i - 1));
7957 }
7958 }
7959 }
7960 return *result;
7961}
7962
7963
7964RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007965 NoHandleAllocation ha;
7966 ASSERT(args.length() == 3);
7967
7968 JSFunction* callee = JSFunction::cast(args[0]);
7969 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007970 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007971
lrn@chromium.org303ada72010-10-27 09:33:13 +00007972 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007973 { MaybeObject* maybe_result =
7974 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007975 if (!maybe_result->ToObject(&result)) return maybe_result;
7976 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007977 // Allocate the elements if needed.
7978 if (length > 0) {
7979 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007980 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007981 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007982 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7983 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007984
7985 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007986 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007987 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007988 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007989
7990 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007991 for (int i = 0; i < length; i++) {
7992 array->set(i, *--parameters, mode);
7993 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007994 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007995 }
7996 return result;
7997}
7998
7999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008000RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008001 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008002 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008003 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008004 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008005 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008006
whesse@chromium.org7b260152011-06-20 15:33:18 +00008007 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008008 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008009 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008010 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008011 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8012 context,
8013 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008014 return *result;
8015}
8016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008017
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008018// Find the arguments of the JavaScript function invocation that called
8019// into C++ code. Collect these in a newly allocated array of handles (possibly
8020// prefixed by a number of empty handles).
8021static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8022 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008023 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008024 // Find frame containing arguments passed to the caller.
8025 JavaScriptFrameIterator it;
8026 JavaScriptFrame* frame = it.frame();
8027 List<JSFunction*> functions(2);
8028 frame->GetFunctions(&functions);
8029 if (functions.length() > 1) {
8030 int inlined_frame_index = functions.length() - 1;
8031 JSFunction* inlined_function = functions[inlined_frame_index];
8032 int args_count = inlined_function->shared()->formal_parameter_count();
8033 ScopedVector<SlotRef> args_slots(args_count);
8034 SlotRef::ComputeSlotMappingForArguments(frame,
8035 inlined_frame_index,
8036 &args_slots);
8037
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008038 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008039 SmartArrayPointer<Handle<Object> > param_data(
8040 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008041 for (int i = 0; i < args_count; i++) {
8042 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008043 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008044 }
8045 return param_data;
8046 } else {
8047 it.AdvanceToArgumentsFrame();
8048 frame = it.frame();
8049 int args_count = frame->ComputeParametersCount();
8050
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008051 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008052 SmartArrayPointer<Handle<Object> > param_data(
8053 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008054 for (int i = 0; i < args_count; i++) {
8055 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008056 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008057 }
8058 return param_data;
8059 }
8060}
8061
8062
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008063RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8064 HandleScope scope(isolate);
8065 ASSERT(args.length() == 4);
8066 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8067 RUNTIME_ASSERT(args[3]->IsNumber());
8068 Handle<Object> bindee = args.at<Object>(1);
8069
8070 // TODO(lrn): Create bound function in C++ code from premade shared info.
8071 bound_function->shared()->set_bound(true);
8072 // Get all arguments of calling function (Function.prototype.bind).
8073 int argc = 0;
8074 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8075 // Don't count the this-arg.
8076 if (argc > 0) {
8077 ASSERT(*arguments[0] == args[2]);
8078 argc--;
8079 } else {
8080 ASSERT(args[2]->IsUndefined());
8081 }
8082 // Initialize array of bindings (function, this, and any existing arguments
8083 // if the function was already bound).
8084 Handle<FixedArray> new_bindings;
8085 int i;
8086 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8087 Handle<FixedArray> old_bindings(
8088 JSFunction::cast(*bindee)->function_bindings());
8089 new_bindings =
8090 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8091 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8092 i = 0;
8093 for (int n = old_bindings->length(); i < n; i++) {
8094 new_bindings->set(i, old_bindings->get(i));
8095 }
8096 } else {
8097 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8098 new_bindings = isolate->factory()->NewFixedArray(array_size);
8099 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8100 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8101 i = 2;
8102 }
8103 // Copy arguments, skipping the first which is "this_arg".
8104 for (int j = 0; j < argc; j++, i++) {
8105 new_bindings->set(i, *arguments[j + 1]);
8106 }
8107 new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
8108 bound_function->set_function_bindings(*new_bindings);
8109
8110 // Update length.
8111 Handle<String> length_symbol = isolate->factory()->length_symbol();
8112 Handle<Object> new_length(args.at<Object>(3));
8113 PropertyAttributes attr =
8114 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8115 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8116 return *bound_function;
8117}
8118
8119
8120RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8121 HandleScope handles(isolate);
8122 ASSERT(args.length() == 1);
8123 CONVERT_ARG_CHECKED(JSObject, callable, 0);
8124 if (callable->IsJSFunction()) {
8125 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8126 if (function->shared()->bound()) {
8127 Handle<FixedArray> bindings(function->function_bindings());
8128 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8129 return *isolate->factory()->NewJSArrayWithElements(bindings);
8130 }
8131 }
8132 return isolate->heap()->undefined_value();
8133}
8134
8135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008136RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008137 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008138 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008139 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008140 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008141 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008142
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008143 // The argument is a bound function. Extract its bound arguments
8144 // and callable.
8145 Handle<FixedArray> bound_args =
8146 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8147 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8148 Handle<Object> bound_function(
8149 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8150 ASSERT(!bound_function->IsJSFunction() ||
8151 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008153 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008154 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008155 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008156 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008157 param_data[i] = Handle<Object>(bound_args->get(
8158 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008159 }
8160
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008161 if (!bound_function->IsJSFunction()) {
8162 bool exception_thrown;
8163 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8164 &exception_thrown);
8165 if (exception_thrown) return Failure::Exception();
8166 }
8167 ASSERT(bound_function->IsJSFunction());
8168
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008169 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008170 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008171 Execution::New(Handle<JSFunction>::cast(bound_function),
8172 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008173 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008174 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008175 }
8176 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008177 return *result;
8178}
8179
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008180
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008181static void TrySettingInlineConstructStub(Isolate* isolate,
8182 Handle<JSFunction> function) {
8183 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008184 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008185 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008186 }
8187 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008188 HandleScope scope(isolate);
8189 ConstructStubCompiler compiler(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008190 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008191 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008192 function->shared()->set_construct_stub(
8193 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008194 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008195 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008196}
8197
8198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008199RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008201 ASSERT(args.length() == 1);
8202
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008203 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008204
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008205 // If the constructor isn't a proper function we throw a type error.
8206 if (!constructor->IsJSFunction()) {
8207 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8208 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008209 isolate->factory()->NewTypeError("not_constructor", arguments);
8210 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008211 }
8212
8213 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008214
8215 // If function should not have prototype, construction is not allowed. In this
8216 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008217 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008218 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8219 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008220 isolate->factory()->NewTypeError("not_constructor", arguments);
8221 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008222 }
8223
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008224#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008225 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008226 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008227 if (debug->StepInActive()) {
8228 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008229 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008230#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008231
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008232 if (function->has_initial_map()) {
8233 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008234 // The 'Function' function ignores the receiver object when
8235 // called using 'new' and creates a new JSFunction object that
8236 // is returned. The receiver object is only used for error
8237 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008238 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008239 // allocate JSFunctions since it does not properly initialize
8240 // the shared part of the function. Since the receiver is
8241 // ignored anyway, we use the global object as the receiver
8242 // instead of a new JSFunction object. This way, errors are
8243 // reported the same way whether or not 'Function' is called
8244 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008245 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008247 }
8248
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008249 // The function should be compiled for the optimization hints to be
8250 // available. We cannot use EnsureCompiled because that forces a
8251 // compilation through the shared function info which makes it
8252 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008253 if (!function->is_compiled()) {
8254 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8255 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008256
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008257 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008258 if (!function->has_initial_map() &&
8259 shared->IsInobjectSlackTrackingInProgress()) {
8260 // The tracking is already in progress for another function. We can only
8261 // track one initial_map at a time, so we force the completion before the
8262 // function is called as a constructor for the first time.
8263 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008264 }
8265
8266 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008267 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8268 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008269 // Delay setting the stub if inobject slack tracking is in progress.
8270 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008271 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008272 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008273
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274 isolate->counters()->constructed_objects()->Increment();
8275 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008276
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008277 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008278}
8279
8280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008281RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008283 ASSERT(args.length() == 1);
8284
8285 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8286 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008287 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008290}
8291
8292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008293RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008294 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008295 ASSERT(args.length() == 1);
8296
8297 Handle<JSFunction> function = args.at<JSFunction>(0);
8298#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008299 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008301 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008302 PrintF("]\n");
8303 }
8304#endif
8305
lrn@chromium.org34e60782011-09-15 07:25:40 +00008306 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008307 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008308 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008309 return Failure::Exception();
8310 }
8311
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008312 // All done. Return the compiled code.
8313 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008314 return function->code();
8315}
8316
8317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008318RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008319 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008320 ASSERT(args.length() == 1);
8321 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008322
8323 // If the function is not compiled ignore the lazy
8324 // recompilation. This can happen if the debugger is activated and
8325 // the function is returned to the not compiled state.
8326 if (!function->shared()->is_compiled()) {
8327 function->ReplaceCode(function->shared()->code());
8328 return function->code();
8329 }
8330
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008331 // If the function is not optimizable or debugger is active continue using the
8332 // code from the full compiler.
8333 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008334 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008335 if (FLAG_trace_opt) {
8336 PrintF("[failed to optimize ");
8337 function->PrintName();
8338 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8339 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008340 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008341 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008342 function->ReplaceCode(function->shared()->code());
8343 return function->code();
8344 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008345 if (JSFunction::CompileOptimized(function,
8346 AstNode::kNoNumber,
8347 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008348 return function->code();
8349 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008350 if (FLAG_trace_opt) {
8351 PrintF("[failed to optimize ");
8352 function->PrintName();
8353 PrintF(": optimized compilation failed]\n");
8354 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008355 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008356 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008357}
8358
8359
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008360class ActivationsFinder : public ThreadVisitor {
8361 public:
8362 explicit ActivationsFinder(JSFunction* function)
8363 : function_(function), has_activations_(false) {}
8364
8365 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8366 if (has_activations_) return;
8367
8368 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8369 JavaScriptFrame* frame = it.frame();
8370 if (frame->is_optimized() && frame->function() == function_) {
8371 has_activations_ = true;
8372 return;
8373 }
8374 }
8375 }
8376
8377 bool has_activations() { return has_activations_; }
8378
8379 private:
8380 JSFunction* function_;
8381 bool has_activations_;
8382};
8383
8384
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008385RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008386 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008387 ASSERT(args.length() == 1);
8388 RUNTIME_ASSERT(args[0]->IsSmi());
8389 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008390 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008391 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8392 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008393 int frames = deoptimizer->output_count();
8394
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008395 deoptimizer->MaterializeHeapNumbers();
8396 delete deoptimizer;
8397
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008398 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008399 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008400 for (int i = 0; i < frames - 1; i++) it.Advance();
8401 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008402
8403 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008404 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008405 Handle<Object> arguments;
8406 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008407 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008408 if (arguments.is_null()) {
8409 // FunctionGetArguments can't throw an exception, so cast away the
8410 // doubt with an assert.
8411 arguments = Handle<Object>(
8412 Accessors::FunctionGetArguments(*function,
8413 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008414 ASSERT(*arguments != isolate->heap()->null_value());
8415 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008416 }
8417 frame->SetExpression(i, *arguments);
8418 }
8419 }
8420
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008421 if (type == Deoptimizer::EAGER) {
8422 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008423 }
8424
8425 // Avoid doing too much work when running with --always-opt and keep
8426 // the optimized code around.
8427 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008428 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008429 }
8430
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008431 // Find other optimized activations of the function.
8432 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008433 while (!it.done()) {
8434 JavaScriptFrame* frame = it.frame();
8435 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008436 has_other_activations = true;
8437 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008438 }
8439 it.Advance();
8440 }
8441
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008442 if (!has_other_activations) {
8443 ActivationsFinder activations_finder(*function);
8444 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8445 has_other_activations = activations_finder.has_activations();
8446 }
8447
8448 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008449 if (FLAG_trace_deopt) {
8450 PrintF("[removing optimized code for: ");
8451 function->PrintName();
8452 PrintF("]\n");
8453 }
8454 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008455 } else {
8456 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008457 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008458 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008459}
8460
8461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008462RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008463 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008464 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008465 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008466}
8467
8468
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008469RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008470 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008471 ASSERT(args.length() == 1);
8472 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008473 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008474
8475 Deoptimizer::DeoptimizeFunction(*function);
8476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008477 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008478}
8479
8480
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008481RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8482#if defined(USE_SIMULATOR)
8483 return isolate->heap()->true_value();
8484#else
8485 return isolate->heap()->false_value();
8486#endif
8487}
8488
8489
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008490RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8491 HandleScope scope(isolate);
8492 ASSERT(args.length() == 1);
8493 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8494 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8495 function->MarkForLazyRecompilation();
8496 return isolate->heap()->undefined_value();
8497}
8498
8499
lrn@chromium.org1c092762011-05-09 09:42:16 +00008500RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8501 HandleScope scope(isolate);
8502 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008503 // The least significant bit (after untagging) indicates whether the
8504 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008505 if (!V8::UseCrankshaft()) {
8506 return Smi::FromInt(4); // 4 == "never".
8507 }
8508 if (FLAG_always_opt) {
8509 return Smi::FromInt(3); // 3 == "always".
8510 }
8511 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8512 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8513 : Smi::FromInt(2); // 2 == "no".
8514}
8515
8516
8517RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8518 HandleScope scope(isolate);
8519 ASSERT(args.length() == 1);
8520 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8521 return Smi::FromInt(function->shared()->opt_count());
8522}
8523
8524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008525RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008526 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008527 ASSERT(args.length() == 1);
8528 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8529
8530 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008531 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008532
8533 // We have hit a back edge in an unoptimized frame for a function that was
8534 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008535 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008536 // Keep track of whether we've succeeded in optimizing.
8537 bool succeeded = unoptimized->optimizable();
8538 if (succeeded) {
8539 // If we are trying to do OSR when there are already optimized
8540 // activations of the function, it means (a) the function is directly or
8541 // indirectly recursive and (b) an optimized invocation has been
8542 // deoptimized so that we are currently in an unoptimized activation.
8543 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008544 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008545 while (succeeded && !it.done()) {
8546 JavaScriptFrame* frame = it.frame();
8547 succeeded = !frame->is_optimized() || frame->function() != *function;
8548 it.Advance();
8549 }
8550 }
8551
8552 int ast_id = AstNode::kNoNumber;
8553 if (succeeded) {
8554 // The top JS function is this one, the PC is somewhere in the
8555 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008556 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008557 JavaScriptFrame* frame = it.frame();
8558 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008559 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008560 ASSERT(unoptimized->contains(frame->pc()));
8561
8562 // Use linear search of the unoptimized code's stack check table to find
8563 // the AST id matching the PC.
8564 Address start = unoptimized->instruction_start();
8565 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008566 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008567 uint32_t table_length = Memory::uint32_at(table_cursor);
8568 table_cursor += kIntSize;
8569 for (unsigned i = 0; i < table_length; ++i) {
8570 // Table entries are (AST id, pc offset) pairs.
8571 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8572 if (pc_offset == target_pc_offset) {
8573 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8574 break;
8575 }
8576 table_cursor += 2 * kIntSize;
8577 }
8578 ASSERT(ast_id != AstNode::kNoNumber);
8579 if (FLAG_trace_osr) {
8580 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8581 function->PrintName();
8582 PrintF("]\n");
8583 }
8584
8585 // Try to compile the optimized code. A true return value from
8586 // CompileOptimized means that compilation succeeded, not necessarily
8587 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008588 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008589 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008590 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8591 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008592 if (data->OsrPcOffset()->value() >= 0) {
8593 if (FLAG_trace_osr) {
8594 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008595 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008596 }
8597 ASSERT(data->OsrAstId()->value() == ast_id);
8598 } else {
8599 // We may never generate the desired OSR entry if we emit an
8600 // early deoptimize.
8601 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008602 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008603 } else {
8604 succeeded = false;
8605 }
8606 }
8607
8608 // Revert to the original stack checks in the original unoptimized code.
8609 if (FLAG_trace_osr) {
8610 PrintF("[restoring original stack checks in ");
8611 function->PrintName();
8612 PrintF("]\n");
8613 }
8614 StackCheckStub check_stub;
8615 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008616 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008617 Deoptimizer::RevertStackCheckCode(*unoptimized,
8618 *check_code,
8619 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008620
8621 // Allow OSR only at nesting level zero again.
8622 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8623
8624 // If the optimization attempt succeeded, return the AST id tagged as a
8625 // smi. This tells the builtin that we need to translate the unoptimized
8626 // frame to an optimized one.
8627 if (succeeded) {
8628 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8629 return Smi::FromInt(ast_id);
8630 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008631 if (function->IsMarkedForLazyRecompilation()) {
8632 function->ReplaceCode(function->shared()->code());
8633 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008634 return Smi::FromInt(-1);
8635 }
8636}
8637
8638
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008639RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8640 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8641 return isolate->heap()->undefined_value();
8642}
8643
8644
lrn@chromium.org34e60782011-09-15 07:25:40 +00008645RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8646 HandleScope scope(isolate);
8647 ASSERT(args.length() == 5);
8648 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8649 Object* receiver = args[1];
8650 CONVERT_CHECKED(JSObject, arguments, args[2]);
8651 CONVERT_CHECKED(Smi, shift, args[3]);
8652 CONVERT_CHECKED(Smi, arity, args[4]);
8653
8654 int offset = shift->value();
8655 int argc = arity->value();
8656 ASSERT(offset >= 0);
8657 ASSERT(argc >= 0);
8658
8659 // If there are too many arguments, allocate argv via malloc.
8660 const int argv_small_size = 10;
8661 Handle<Object> argv_small_buffer[argv_small_size];
8662 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8663 Handle<Object>* argv = argv_small_buffer;
8664 if (argc > argv_small_size) {
8665 argv = new Handle<Object>[argc];
8666 if (argv == NULL) return isolate->StackOverflow();
8667 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8668 }
8669
8670 for (int i = 0; i < argc; ++i) {
8671 MaybeObject* maybe = arguments->GetElement(offset + i);
8672 Object* object;
8673 if (!maybe->To<Object>(&object)) return maybe;
8674 argv[i] = Handle<Object>(object);
8675 }
8676
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008677 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008678 Handle<JSReceiver> hfun(fun);
8679 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008680 Handle<Object> result =
8681 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008682
8683 if (threw) return Failure::Exception();
8684 return *result;
8685}
8686
8687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008688RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008689 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690 ASSERT(args.length() == 1);
8691 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8692 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8693}
8694
8695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008696RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008697 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008698 ASSERT(args.length() == 1);
8699 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8700 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8701}
8702
8703
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008704RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008705 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008706 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707
kasper.lund7276f142008-07-30 08:49:36 +00008708 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008709 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008710 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008711 { MaybeObject* maybe_result =
8712 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008713 if (!maybe_result->ToObject(&result)) return maybe_result;
8714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008715
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008716 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008717
kasper.lund7276f142008-07-30 08:49:36 +00008718 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008719}
8720
lrn@chromium.org303ada72010-10-27 09:33:13 +00008721
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008722RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8723 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008724 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008725 JSObject* extension_object;
8726 if (args[0]->IsJSObject()) {
8727 extension_object = JSObject::cast(args[0]);
8728 } else {
8729 // Convert the object to a proper JavaScript object.
8730 MaybeObject* maybe_js_object = args[0]->ToObject();
8731 if (!maybe_js_object->To(&extension_object)) {
8732 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8733 HandleScope scope(isolate);
8734 Handle<Object> handle = args.at<Object>(0);
8735 Handle<Object> result =
8736 isolate->factory()->NewTypeError("with_expression",
8737 HandleVector(&handle, 1));
8738 return isolate->Throw(*result);
8739 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008740 return maybe_js_object;
8741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008742 }
8743 }
8744
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008745 JSFunction* function;
8746 if (args[1]->IsSmi()) {
8747 // A smi sentinel indicates a context nested inside global code rather
8748 // than some function. There is a canonical empty function that can be
8749 // gotten from the global context.
8750 function = isolate->context()->global_context()->closure();
8751 } else {
8752 function = JSFunction::cast(args[1]);
8753 }
8754
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008755 Context* context;
8756 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008757 isolate->heap()->AllocateWithContext(function,
8758 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008759 extension_object);
8760 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008761 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008762 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008763}
8764
8765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008766RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008767 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008768 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008769 String* name = String::cast(args[0]);
8770 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008771 JSFunction* function;
8772 if (args[2]->IsSmi()) {
8773 // A smi sentinel indicates a context nested inside global code rather
8774 // than some function. There is a canonical empty function that can be
8775 // gotten from the global context.
8776 function = isolate->context()->global_context()->closure();
8777 } else {
8778 function = JSFunction::cast(args[2]);
8779 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008780 Context* context;
8781 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008782 isolate->heap()->AllocateCatchContext(function,
8783 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008784 name,
8785 thrown_object);
8786 if (!maybe_context->To(&context)) return maybe_context;
8787 isolate->set_context(context);
8788 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008789}
8790
8791
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008792RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8793 NoHandleAllocation ha;
8794 ASSERT(args.length() == 2);
8795 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8796 JSFunction* function;
8797 if (args[1]->IsSmi()) {
8798 // A smi sentinel indicates a context nested inside global code rather
8799 // than some function. There is a canonical empty function that can be
8800 // gotten from the global context.
8801 function = isolate->context()->global_context()->closure();
8802 } else {
8803 function = JSFunction::cast(args[1]);
8804 }
8805 Context* context;
8806 MaybeObject* maybe_context =
8807 isolate->heap()->AllocateBlockContext(function,
8808 isolate->context(),
8809 scope_info);
8810 if (!maybe_context->To(&context)) return maybe_context;
8811 isolate->set_context(context);
8812 return context;
8813}
8814
8815
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008816RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008817 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818 ASSERT(args.length() == 2);
8819
8820 CONVERT_ARG_CHECKED(Context, context, 0);
8821 CONVERT_ARG_CHECKED(String, name, 1);
8822
8823 int index;
8824 PropertyAttributes attributes;
8825 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008826 BindingFlags binding_flags;
8827 Handle<Object> holder = context->Lookup(name,
8828 flags,
8829 &index,
8830 &attributes,
8831 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008833 // If the slot was not found the result is true.
8834 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836 }
8837
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008838 // If the slot was found in a context, it should be DONT_DELETE.
8839 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008840 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008841 }
8842
8843 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008844 // the global object, or the subject of a with. Try to delete it
8845 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008846 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008847 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848}
8849
8850
ager@chromium.orga1645e22009-09-09 19:27:10 +00008851// A mechanism to return a pair of Object pointers in registers (if possible).
8852// How this is achieved is calling convention-dependent.
8853// All currently supported x86 compiles uses calling conventions that are cdecl
8854// variants where a 64-bit value is returned in two 32-bit registers
8855// (edx:eax on ia32, r1:r0 on ARM).
8856// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8857// In Win64 calling convention, a struct of two pointers is returned in memory,
8858// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008859#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008860struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008861 MaybeObject* x;
8862 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008863};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008864
lrn@chromium.org303ada72010-10-27 09:33:13 +00008865static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008866 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008867 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8868 // In Win64 they are assigned to a hidden first argument.
8869 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008870}
8871#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008872typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008873static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008874 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008875 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008876}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008877#endif
8878
8879
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008880static inline MaybeObject* Unhole(Heap* heap,
8881 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008882 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008883 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8884 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008885 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008886}
8887
8888
danno@chromium.org40cb8782011-05-25 07:58:50 +00008889static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8890 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008891 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008892 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008893 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008894 JSFunction* context_extension_function =
8895 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008896 // If the holder isn't a context extension object, we just return it
8897 // as the receiver. This allows arguments objects to be used as
8898 // receivers, but only if they are put in the context scope chain
8899 // explicitly via a with-statement.
8900 Object* constructor = holder->map()->constructor();
8901 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008902 // Fall back to using the global object as the implicit receiver if
8903 // the property turns out to be a local variable allocated in a
8904 // context extension object - introduced via eval. Implicit global
8905 // receivers are indicated with the hole value.
8906 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008907}
8908
8909
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008910static ObjectPair LoadContextSlotHelper(Arguments args,
8911 Isolate* isolate,
8912 bool throw_error) {
8913 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008914 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008916 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008917 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008918 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008919 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008920 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008921
8922 int index;
8923 PropertyAttributes attributes;
8924 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008925 BindingFlags binding_flags;
8926 Handle<Object> holder = context->Lookup(name,
8927 flags,
8928 &index,
8929 &attributes,
8930 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008931
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008932 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008933 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008934 ASSERT(holder->IsContext());
8935 // If the "property" we were looking for is a local variable, the
8936 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008937 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008938 // Use the hole as the receiver to signal that the receiver is implicit
8939 // and that the global receiver should be used (as distinguished from an
8940 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008941 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008942 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008943 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008944 switch (binding_flags) {
8945 case MUTABLE_CHECK_INITIALIZED:
8946 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8947 if (value->IsTheHole()) {
8948 Handle<Object> reference_error =
8949 isolate->factory()->NewReferenceError("not_defined",
8950 HandleVector(&name, 1));
8951 return MakePair(isolate->Throw(*reference_error), NULL);
8952 }
8953 // FALLTHROUGH
8954 case MUTABLE_IS_INITIALIZED:
8955 case IMMUTABLE_IS_INITIALIZED:
8956 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8957 ASSERT(!value->IsTheHole());
8958 return MakePair(value, *receiver);
8959 case IMMUTABLE_CHECK_INITIALIZED:
8960 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8961 case MISSING_BINDING:
8962 UNREACHABLE();
8963 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008964 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008965 }
8966
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008967 // Otherwise, if the slot was found the holder is a context extension
8968 // object, subject of a with, or a global object. We read the named
8969 // property from it.
8970 if (!holder.is_null()) {
8971 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8972 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008973 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008974 Handle<Object> receiver_handle(object->IsGlobalObject()
8975 ? GlobalObject::cast(*object)->global_receiver()
8976 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008977
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008978 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008979 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008980 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008981 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982 }
8983
8984 if (throw_error) {
8985 // The property doesn't exist - throw exception.
8986 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008987 isolate->factory()->NewReferenceError("not_defined",
8988 HandleVector(&name, 1));
8989 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008991 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008992 return MakePair(isolate->heap()->undefined_value(),
8993 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008994 }
8995}
8996
8997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008998RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008999 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009000}
9001
9002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009003RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009004 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009005}
9006
9007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009008RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009009 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009010 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009012 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009014 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009015 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009016 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
9017 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009018 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019
9020 int index;
9021 PropertyAttributes attributes;
9022 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009023 BindingFlags binding_flags;
9024 Handle<Object> holder = context->Lookup(name,
9025 flags,
9026 &index,
9027 &attributes,
9028 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009029
9030 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009031 // The property was found in a context slot.
9032 Handle<Context> context = Handle<Context>::cast(holder);
9033 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9034 context->get(index)->IsTheHole()) {
9035 Handle<Object> error =
9036 isolate->factory()->NewReferenceError("not_defined",
9037 HandleVector(&name, 1));
9038 return isolate->Throw(*error);
9039 }
9040 // Ignore if read_only variable.
9041 if ((attributes & READ_ONLY) == 0) {
9042 // Context is a fixed array and set cannot fail.
9043 context->set(index, *value);
9044 } else if (strict_mode == kStrictMode) {
9045 // Setting read only property in strict mode.
9046 Handle<Object> error =
9047 isolate->factory()->NewTypeError("strict_cannot_assign",
9048 HandleVector(&name, 1));
9049 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009050 }
9051 return *value;
9052 }
9053
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009054 // Slow case: The property is not in a context slot. It is either in a
9055 // context extension object, a property of the subject of a with, or a
9056 // property of the global object.
9057 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009059 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009060 // The property exists on the holder.
9061 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009062 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009063 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009065
9066 if (strict_mode == kStrictMode) {
9067 // Throw in strict mode (assignment to undefined variable).
9068 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009069 isolate->factory()->NewReferenceError(
9070 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009071 return isolate->Throw(*error);
9072 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009073 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009075 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009076 }
9077
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009078 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009079 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009080 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009081 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009082 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009083 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009084 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009085 // Setting read only property in strict mode.
9086 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009087 isolate->factory()->NewTypeError(
9088 "strict_cannot_assign", HandleVector(&name, 1));
9089 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009090 }
9091 return *value;
9092}
9093
9094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009095RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009096 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009097 ASSERT(args.length() == 1);
9098
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009099 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009100}
9101
9102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009103RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009104 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105 ASSERT(args.length() == 1);
9106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009108}
9109
9110
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009111RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009112 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009113 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009114}
9115
9116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009117RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009118 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 ASSERT(args.length() == 1);
9120
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009121 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009122 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009123 isolate->factory()->NewReferenceError("not_defined",
9124 HandleVector(&name, 1));
9125 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009126}
9127
9128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009129RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009130 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009131
9132 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009133 if (isolate->stack_guard()->IsStackOverflow()) {
9134 NoHandleAllocation na;
9135 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009136 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009138 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009139}
9140
9141
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142static int StackSize() {
9143 int n = 0;
9144 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9145 return n;
9146}
9147
9148
9149static void PrintTransition(Object* result) {
9150 // indentation
9151 { const int nmax = 80;
9152 int n = StackSize();
9153 if (n <= nmax)
9154 PrintF("%4d:%*s", n, n, "");
9155 else
9156 PrintF("%4d:%*s", n, nmax, "...");
9157 }
9158
9159 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009160 JavaScriptFrame::PrintTop(stdout, true, false);
9161 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 } else {
9163 // function result
9164 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009165 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166 PrintF("\n");
9167 }
9168}
9169
9170
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009171RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
9172 ASSERT(args.length() == 5);
9173 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9174 CONVERT_SMI_ARG_CHECKED(from_kind, 1);
9175 CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
9176 CONVERT_SMI_ARG_CHECKED(to_kind, 3);
9177 CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
9178 NoHandleAllocation ha;
9179 PrintF("*");
9180 obj->PrintElementsTransition(stdout,
9181 static_cast<ElementsKind>(from_kind), *from_elements,
9182 static_cast<ElementsKind>(to_kind), *to_elements);
9183 return isolate->heap()->undefined_value();
9184}
9185
9186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009187RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009188 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009189 NoHandleAllocation ha;
9190 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009191 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009192}
9193
9194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009195RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009196 NoHandleAllocation ha;
9197 PrintTransition(args[0]);
9198 return args[0]; // return TOS
9199}
9200
9201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009202RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009203 NoHandleAllocation ha;
9204 ASSERT(args.length() == 1);
9205
9206#ifdef DEBUG
9207 if (args[0]->IsString()) {
9208 // If we have a string, assume it's a code "marker"
9209 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009210 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009211 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009212 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9213 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009214 } else {
9215 PrintF("DebugPrint: ");
9216 }
9217 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009218 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009219 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009220 HeapObject::cast(args[0])->map()->Print();
9221 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009222#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009223 // ShortPrint is available in release mode. Print is not.
9224 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009225#endif
9226 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009227 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228
9229 return args[0]; // return TOS
9230}
9231
9232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009233RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009234 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009235 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009236 isolate->PrintStack();
9237 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009238}
9239
9240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009241RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009242 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009243 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244
9245 // According to ECMA-262, section 15.9.1, page 117, the precision of
9246 // the number in a Date object representing a particular instant in
9247 // time is milliseconds. Therefore, we floor the result of getting
9248 // the OS time.
9249 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009250 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009251}
9252
9253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009254RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009255 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009256 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009258 CONVERT_ARG_CHECKED(String, str, 0);
9259 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009260
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009261 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009262
9263 MaybeObject* maybe_result_array =
9264 output->EnsureCanContainNonSmiElements();
9265 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009266 RUNTIME_ASSERT(output->HasFastElements());
9267
9268 AssertNoAllocation no_allocation;
9269
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009270 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009271 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9272 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009273 String::FlatContent str_content = str->GetFlatContent();
9274 if (str_content.IsAscii()) {
9275 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009276 output_array,
9277 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009278 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009279 ASSERT(str_content.IsTwoByte());
9280 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009281 output_array,
9282 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009283 }
9284
9285 if (result) {
9286 return *output;
9287 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009288 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289 }
9290}
9291
9292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009293RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009294 NoHandleAllocation ha;
9295 ASSERT(args.length() == 1);
9296
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009297 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009298 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009299 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009300}
9301
9302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009303RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009304 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009305 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009306
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009307 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009308}
9309
9310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009311RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312 NoHandleAllocation ha;
9313 ASSERT(args.length() == 1);
9314
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009315 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009316 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009317}
9318
9319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009320RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009321 ASSERT(args.length() == 1);
9322 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009323 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009324 return JSGlobalObject::cast(global)->global_receiver();
9325}
9326
9327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009328RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009329 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009330 ASSERT_EQ(1, args.length());
9331 CONVERT_ARG_CHECKED(String, source, 0);
9332
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009333 source = Handle<String>(source->TryFlattenGetString());
9334 // Optimized fast case where we only have ascii characters.
9335 Handle<Object> result;
9336 if (source->IsSeqAsciiString()) {
9337 result = JsonParser<true>::Parse(source);
9338 } else {
9339 result = JsonParser<false>::Parse(source);
9340 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009341 if (result.is_null()) {
9342 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009343 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009344 return Failure::Exception();
9345 }
9346 return *result;
9347}
9348
9349
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009350bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9351 Handle<Context> context) {
9352 if (context->allow_code_gen_from_strings()->IsFalse()) {
9353 // Check with callback if set.
9354 AllowCodeGenerationFromStringsCallback callback =
9355 isolate->allow_code_gen_callback();
9356 if (callback == NULL) {
9357 // No callback set and code generation disallowed.
9358 return false;
9359 } else {
9360 // Callback set. Let it decide if code generation is allowed.
9361 VMState state(isolate, EXTERNAL);
9362 return callback(v8::Utils::ToLocal(context));
9363 }
9364 }
9365 return true;
9366}
9367
9368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009369RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009370 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009371 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009372 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009373
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009374 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009375 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009376
9377 // Check if global context allows code generation from
9378 // strings. Throw an exception if it doesn't.
9379 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9380 return isolate->Throw(*isolate->factory()->NewError(
9381 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9382 }
9383
9384 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009385 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9386 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009387 true,
9388 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009389 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009390 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009391 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9392 context,
9393 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009394 return *fun;
9395}
9396
9397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398static ObjectPair CompileGlobalEval(Isolate* isolate,
9399 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009400 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009401 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009402 Handle<Context> context = Handle<Context>(isolate->context());
9403 Handle<Context> global_context = Handle<Context>(context->global_context());
9404
9405 // Check if global context allows code generation from
9406 // strings. Throw an exception if it doesn't.
9407 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9408 isolate->Throw(*isolate->factory()->NewError(
9409 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9410 return MakePair(Failure::Exception(), NULL);
9411 }
9412
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009413 // Deal with a normal eval call with a string argument. Compile it
9414 // and return the compiled function bound in the local context.
9415 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9416 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009417 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009418 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009419 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009420 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009421 Handle<JSFunction> compiled =
9422 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009423 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009424 return MakePair(*compiled, *receiver);
9425}
9426
9427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009428RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009429 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009431 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009432 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009433 Handle<Object> receiver; // Will be overwritten.
9434
9435 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009437#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009438 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009439 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009440 StackFrameLocator locator;
9441 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009442 ASSERT(Context::cast(frame->context()) == *context);
9443#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009444
9445 // Find where the 'eval' symbol is bound. It is unaliased only if
9446 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009447 int index = -1;
9448 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009449 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009450 while (true) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009451 // Don't follow context chains in Context::Lookup and implement the loop
9452 // up the context chain here, so that we can know the context where eval
9453 // was found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009454 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9455 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009456 &index,
9457 &attributes,
9458 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009459 // Stop search when eval is found or when the global context is
9460 // reached.
9461 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009462 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009463 }
9464
iposva@chromium.org245aa852009-02-10 00:49:54 +00009465 // If eval could not be resolved, it has been deleted and we need to
9466 // throw a reference error.
9467 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009468 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009469 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009470 isolate->factory()->NewReferenceError("not_defined",
9471 HandleVector(&name, 1));
9472 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009473 }
9474
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009475 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009476 // 'eval' is not bound in the global context. Just call the function
9477 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009478 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009479 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009480 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009481 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009482 }
9483
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009484 // 'eval' is bound in the global context, but it may have been overwritten.
9485 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009486 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009487 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009488 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009489 }
9490
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009491 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009492 return CompileGlobalEval(isolate,
9493 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009494 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009495 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009496}
9497
9498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009499RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009500 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009503 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009504
9505 // 'eval' is bound in the global context, but it may have been overwritten.
9506 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009507 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009508 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009509 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009510 }
9511
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009512 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513 return CompileGlobalEval(isolate,
9514 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009515 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009516 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009517}
9518
9519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009520RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009521 // This utility adjusts the property attributes for newly created Function
9522 // object ("new Function(...)") by changing the map.
9523 // All it does is changing the prototype property to enumerable
9524 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009525 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526 ASSERT(args.length() == 1);
9527 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009528
9529 Handle<Map> map = func->shared()->strict_mode()
9530 ? isolate->strict_mode_function_instance_map()
9531 : isolate->function_instance_map();
9532
9533 ASSERT(func->map()->instance_type() == map->instance_type());
9534 ASSERT(func->map()->instance_size() == map->instance_size());
9535 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536 return *func;
9537}
9538
9539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009540RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009541 // Allocate a block of memory in NewSpace (filled with a filler).
9542 // Use as fallback for allocation in generated code when NewSpace
9543 // is full.
9544 ASSERT(args.length() == 1);
9545 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9546 int size = size_smi->value();
9547 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9548 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009549 Heap* heap = isolate->heap();
9550 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009551 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009552 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009554 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009555 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009556 }
9557 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009558 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009559}
9560
9561
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009562// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009563// array. Returns true if the element was pushed on the stack and
9564// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009565RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009566 ASSERT(args.length() == 2);
9567 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009568 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009569 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009570 int length = Smi::cast(array->length())->value();
9571 FixedArray* elements = FixedArray::cast(array->elements());
9572 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009574 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009575 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009576 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009577 { MaybeObject* maybe_obj =
9578 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009579 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9580 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009581 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009582}
9583
9584
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009585/**
9586 * A simple visitor visits every element of Array's.
9587 * The backend storage can be a fixed array for fast elements case,
9588 * or a dictionary for sparse array. Since Dictionary is a subtype
9589 * of FixedArray, the class can be used by both fast and slow cases.
9590 * The second parameter of the constructor, fast_elements, specifies
9591 * whether the storage is a FixedArray or Dictionary.
9592 *
9593 * An index limit is used to deal with the situation that a result array
9594 * length overflows 32-bit non-negative integer.
9595 */
9596class ArrayConcatVisitor {
9597 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009598 ArrayConcatVisitor(Isolate* isolate,
9599 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009600 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 isolate_(isolate),
9602 storage_(Handle<FixedArray>::cast(
9603 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009604 index_offset_(0u),
9605 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009606
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009607 ~ArrayConcatVisitor() {
9608 clear_storage();
9609 }
9610
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009611 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009612 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009613 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009614
9615 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009616 if (index < static_cast<uint32_t>(storage_->length())) {
9617 storage_->set(index, *elm);
9618 return;
9619 }
9620 // Our initial estimate of length was foiled, possibly by
9621 // getters on the arrays increasing the length of later arrays
9622 // during iteration.
9623 // This shouldn't happen in anything but pathological cases.
9624 SetDictionaryMode(index);
9625 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009626 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009627 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009628 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009629 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009630 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009631 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009632 // Dictionary needed to grow.
9633 clear_storage();
9634 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009635 }
9636}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009637
9638 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009639 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9640 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009641 } else {
9642 index_offset_ += delta;
9643 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009644 }
9645
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009646 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009647 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009648 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009649 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009650 Handle<Map> map;
9651 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009652 map = isolate_->factory()->GetElementsTransitionMap(array,
9653 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009654 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009655 map = isolate_->factory()->GetElementsTransitionMap(array,
9656 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 }
9658 array->set_map(*map);
9659 array->set_length(*length);
9660 array->set_elements(*storage_);
9661 return array;
9662 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009663
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009664 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009665 // Convert storage to dictionary mode.
9666 void SetDictionaryMode(uint32_t index) {
9667 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009668 Handle<FixedArray> current_storage(*storage_);
9669 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009670 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009671 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9672 for (uint32_t i = 0; i < current_length; i++) {
9673 HandleScope loop_scope;
9674 Handle<Object> element(current_storage->get(i));
9675 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009676 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009677 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009678 if (!new_storage.is_identical_to(slow_storage)) {
9679 slow_storage = loop_scope.CloseAndEscape(new_storage);
9680 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009681 }
9682 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009683 clear_storage();
9684 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009685 fast_elements_ = false;
9686 }
9687
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009688 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009689 isolate_->global_handles()->Destroy(
9690 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009691 }
9692
9693 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009694 storage_ = Handle<FixedArray>::cast(
9695 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009696 }
9697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009698 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009699 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009700 // Index after last seen index. Always less than or equal to
9701 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009702 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009703 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009704};
9705
9706
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009707static uint32_t EstimateElementCount(Handle<JSArray> array) {
9708 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9709 int element_count = 0;
9710 switch (array->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009711 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009712 // Fast elements can't have lengths that are not representable by
9713 // a 32-bit signed integer.
9714 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9715 int fast_length = static_cast<int>(length);
9716 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9717 for (int i = 0; i < fast_length; i++) {
9718 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009719 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009720 break;
9721 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009722 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009723 Handle<NumberDictionary> dictionary(
9724 NumberDictionary::cast(array->elements()));
9725 int capacity = dictionary->Capacity();
9726 for (int i = 0; i < capacity; i++) {
9727 Handle<Object> key(dictionary->KeyAt(i));
9728 if (dictionary->IsKey(*key)) {
9729 element_count++;
9730 }
9731 }
9732 break;
9733 }
9734 default:
9735 // External arrays are always dense.
9736 return length;
9737 }
9738 // As an estimate, we assume that the prototype doesn't contain any
9739 // inherited elements.
9740 return element_count;
9741}
9742
9743
9744
9745template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009746static void IterateExternalArrayElements(Isolate* isolate,
9747 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009748 bool elements_are_ints,
9749 bool elements_are_guaranteed_smis,
9750 ArrayConcatVisitor* visitor) {
9751 Handle<ExternalArrayClass> array(
9752 ExternalArrayClass::cast(receiver->elements()));
9753 uint32_t len = static_cast<uint32_t>(array->length());
9754
9755 ASSERT(visitor != NULL);
9756 if (elements_are_ints) {
9757 if (elements_are_guaranteed_smis) {
9758 for (uint32_t j = 0; j < len; j++) {
9759 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009760 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009761 visitor->visit(j, e);
9762 }
9763 } else {
9764 for (uint32_t j = 0; j < len; j++) {
9765 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009766 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009767 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9768 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9769 visitor->visit(j, e);
9770 } else {
9771 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009772 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009773 visitor->visit(j, e);
9774 }
9775 }
9776 }
9777 } else {
9778 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009779 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009780 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009781 visitor->visit(j, e);
9782 }
9783 }
9784}
9785
9786
9787// Used for sorting indices in a List<uint32_t>.
9788static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9789 uint32_t a = *ap;
9790 uint32_t b = *bp;
9791 return (a == b) ? 0 : (a < b) ? -1 : 1;
9792}
9793
9794
9795static void CollectElementIndices(Handle<JSObject> object,
9796 uint32_t range,
9797 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009798 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009799 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009800 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009801 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009802 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9803 uint32_t length = static_cast<uint32_t>(elements->length());
9804 if (range < length) length = range;
9805 for (uint32_t i = 0; i < length; i++) {
9806 if (!elements->get(i)->IsTheHole()) {
9807 indices->Add(i);
9808 }
9809 }
9810 break;
9811 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009812 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009813 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009814 uint32_t capacity = dict->Capacity();
9815 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009816 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009817 Handle<Object> k(dict->KeyAt(j));
9818 if (dict->IsKey(*k)) {
9819 ASSERT(k->IsNumber());
9820 uint32_t index = static_cast<uint32_t>(k->Number());
9821 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009822 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009823 }
9824 }
9825 }
9826 break;
9827 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009828 default: {
9829 int dense_elements_length;
9830 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009831 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009832 dense_elements_length =
9833 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009834 break;
9835 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009836 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009837 dense_elements_length =
9838 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 break;
9840 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009841 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009842 dense_elements_length =
9843 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009844 break;
9845 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009846 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009847 dense_elements_length =
9848 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009849 break;
9850 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009851 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009852 dense_elements_length =
9853 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009854 break;
9855 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009856 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009857 dense_elements_length =
9858 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009859 break;
9860 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009861 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009862 dense_elements_length =
9863 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009864 break;
9865 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009866 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009867 dense_elements_length =
9868 ExternalFloatArray::cast(object->elements())->length();
9869 break;
9870 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009871 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009872 dense_elements_length =
9873 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009874 break;
9875 }
9876 default:
9877 UNREACHABLE();
9878 dense_elements_length = 0;
9879 break;
9880 }
9881 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9882 if (range <= length) {
9883 length = range;
9884 // We will add all indices, so we might as well clear it first
9885 // and avoid duplicates.
9886 indices->Clear();
9887 }
9888 for (uint32_t i = 0; i < length; i++) {
9889 indices->Add(i);
9890 }
9891 if (length == range) return; // All indices accounted for already.
9892 break;
9893 }
9894 }
9895
9896 Handle<Object> prototype(object->GetPrototype());
9897 if (prototype->IsJSObject()) {
9898 // The prototype will usually have no inherited element indices,
9899 // but we have to check.
9900 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9901 }
9902}
9903
9904
9905/**
9906 * A helper function that visits elements of a JSArray in numerical
9907 * order.
9908 *
9909 * The visitor argument called for each existing element in the array
9910 * with the element index and the element's value.
9911 * Afterwards it increments the base-index of the visitor by the array
9912 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009913 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009914 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009915static bool IterateElements(Isolate* isolate,
9916 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009917 ArrayConcatVisitor* visitor) {
9918 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9919 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009920 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009921 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 // Run through the elements FixedArray and use HasElement and GetElement
9923 // to check the prototype for missing elements.
9924 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9925 int fast_length = static_cast<int>(length);
9926 ASSERT(fast_length <= elements->length());
9927 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009928 HandleScope loop_scope(isolate);
9929 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009930 if (!element_value->IsTheHole()) {
9931 visitor->visit(j, element_value);
9932 } else if (receiver->HasElement(j)) {
9933 // Call GetElement on receiver, not its prototype, or getters won't
9934 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009935 element_value = Object::GetElement(receiver, j);
9936 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009937 visitor->visit(j, element_value);
9938 }
9939 }
9940 break;
9941 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009942 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009943 Handle<NumberDictionary> dict(receiver->element_dictionary());
9944 List<uint32_t> indices(dict->Capacity() / 2);
9945 // Collect all indices in the object and the prototypes less
9946 // than length. This might introduce duplicates in the indices list.
9947 CollectElementIndices(receiver, length, &indices);
9948 indices.Sort(&compareUInt32);
9949 int j = 0;
9950 int n = indices.length();
9951 while (j < n) {
9952 HandleScope loop_scope;
9953 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009954 Handle<Object> element = Object::GetElement(receiver, index);
9955 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009956 visitor->visit(index, element);
9957 // Skip to next different index (i.e., omit duplicates).
9958 do {
9959 j++;
9960 } while (j < n && indices[j] == index);
9961 }
9962 break;
9963 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009964 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009965 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9966 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009967 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009968 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009969 visitor->visit(j, e);
9970 }
9971 break;
9972 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009973 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009974 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009975 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009976 break;
9977 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009978 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009979 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009980 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009981 break;
9982 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009983 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009984 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009985 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009986 break;
9987 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009989 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009991 break;
9992 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009993 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009994 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009996 break;
9997 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009998 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009999 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010000 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010001 break;
10002 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010003 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010004 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010005 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010006 break;
10007 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010008 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010009 IterateExternalArrayElements<ExternalDoubleArray, double>(
10010 isolate, receiver, false, false, visitor);
10011 break;
10012 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010013 default:
10014 UNREACHABLE();
10015 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010016 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010017 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010018 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010019}
10020
10021
10022/**
10023 * Array::concat implementation.
10024 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010025 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010026 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010027 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010028RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010029 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010030 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010031
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010032 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10033 int argument_count = static_cast<int>(arguments->length()->Number());
10034 RUNTIME_ASSERT(arguments->HasFastElements());
10035 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010036
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010037 // Pass 1: estimate the length and number of elements of the result.
10038 // The actual length can be larger if any of the arguments have getters
10039 // that mutate other arguments (but will otherwise be precise).
10040 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010041
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 uint32_t estimate_result_length = 0;
10043 uint32_t estimate_nof_elements = 0;
10044 {
10045 for (int i = 0; i < argument_count; i++) {
10046 HandleScope loop_scope;
10047 Handle<Object> obj(elements->get(i));
10048 uint32_t length_estimate;
10049 uint32_t element_estimate;
10050 if (obj->IsJSArray()) {
10051 Handle<JSArray> array(Handle<JSArray>::cast(obj));
10052 length_estimate =
10053 static_cast<uint32_t>(array->length()->Number());
10054 element_estimate =
10055 EstimateElementCount(array);
10056 } else {
10057 length_estimate = 1;
10058 element_estimate = 1;
10059 }
10060 // Avoid overflows by capping at kMaxElementCount.
10061 if (JSObject::kMaxElementCount - estimate_result_length <
10062 length_estimate) {
10063 estimate_result_length = JSObject::kMaxElementCount;
10064 } else {
10065 estimate_result_length += length_estimate;
10066 }
10067 if (JSObject::kMaxElementCount - estimate_nof_elements <
10068 element_estimate) {
10069 estimate_nof_elements = JSObject::kMaxElementCount;
10070 } else {
10071 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010072 }
10073 }
10074 }
10075
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010076 // If estimated number of elements is more than half of length, a
10077 // fixed array (fast case) is more time and space-efficient than a
10078 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010079 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010080
10081 Handle<FixedArray> storage;
10082 if (fast_case) {
10083 // The backing storage array must have non-existing elements to
10084 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010085 storage = isolate->factory()->NewFixedArrayWithHoles(
10086 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010087 } else {
10088 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10089 uint32_t at_least_space_for = estimate_nof_elements +
10090 (estimate_nof_elements >> 2);
10091 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010092 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010093 }
10094
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010095 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010096
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010097 for (int i = 0; i < argument_count; i++) {
10098 Handle<Object> obj(elements->get(i));
10099 if (obj->IsJSArray()) {
10100 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010101 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010102 return Failure::Exception();
10103 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010104 } else {
10105 visitor.visit(0, obj);
10106 visitor.increase_index_offset(1);
10107 }
10108 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010109
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010110 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010111}
10112
10113
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010114// This will not allocate (flatten the string), but it may run
10115// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010116RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117 NoHandleAllocation ha;
10118 ASSERT(args.length() == 1);
10119
10120 CONVERT_CHECKED(String, string, args[0]);
10121 StringInputBuffer buffer(string);
10122 while (buffer.has_more()) {
10123 uint16_t character = buffer.GetNext();
10124 PrintF("%c", character);
10125 }
10126 return string;
10127}
10128
ager@chromium.org5ec48922009-05-05 07:25:34 +000010129// Moves all own elements of an object, that are below a limit, to positions
10130// starting at zero. All undefined values are placed after non-undefined values,
10131// and are followed by non-existing element. Does not change the length
10132// property.
10133// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010134RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010135 ASSERT(args.length() == 2);
10136 CONVERT_CHECKED(JSObject, object, args[0]);
10137 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10138 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010139}
10140
10141
10142// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010143RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144 ASSERT(args.length() == 2);
10145 CONVERT_CHECKED(JSArray, from, args[0]);
10146 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010147 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010148 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010149 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010150 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10151 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010152 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010153 } else if (new_elements->map() ==
10154 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010155 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010156 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010157 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010158 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010159 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010160 Object* new_map;
10161 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010162 to->set_map(Map::cast(new_map));
10163 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010164 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010165 Object* obj;
10166 { MaybeObject* maybe_obj = from->ResetElements();
10167 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10168 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010169 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010170 return to;
10171}
10172
10173
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010174// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010175RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010176 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010177 CONVERT_CHECKED(JSObject, object, args[0]);
10178 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010180 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010181 } else if (object->IsJSArray()) {
10182 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010183 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010184 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010185 }
10186}
10187
10188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010189RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010190 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010191
10192 ASSERT_EQ(3, args.length());
10193
ager@chromium.orgac091b72010-05-05 07:34:42 +000010194 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010195 Handle<Object> key1 = args.at<Object>(1);
10196 Handle<Object> key2 = args.at<Object>(2);
10197
10198 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010199 if (!key1->ToArrayIndex(&index1)
10200 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010201 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010202 }
10203
ager@chromium.orgac091b72010-05-05 07:34:42 +000010204 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010205 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010206 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010207 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010208 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010210 RETURN_IF_EMPTY_HANDLE(isolate,
10211 SetElement(jsobject, index1, tmp2, kStrictMode));
10212 RETURN_IF_EMPTY_HANDLE(isolate,
10213 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010215 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010216}
10217
10218
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010220// might have elements. Can either return keys (positive integers) or
10221// intervals (pair of a negative integer (-start-1) followed by a
10222// positive (length)) or undefined values.
10223// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010224RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010225 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010226 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010227 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010228 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010229 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230 // Create an array and get all the keys into it, then remove all the
10231 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010232 bool threw = false;
10233 Handle<FixedArray> keys =
10234 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10235 if (threw) return Failure::Exception();
10236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237 int keys_length = keys->length();
10238 for (int i = 0; i < keys_length; i++) {
10239 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010240 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010241 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242 // Zap invalid keys.
10243 keys->set_undefined(i);
10244 }
10245 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010246 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010247 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010248 ASSERT(array->HasFastElements() ||
10249 array->HasFastSmiOnlyElements() ||
10250 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010251 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010252 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010253 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010254 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010255 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010256 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010257 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010258 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010259 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010260 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262 }
10263}
10264
10265
10266// DefineAccessor takes an optional final argument which is the
10267// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10268// to the way accessors are implemented, it is set for both the getter
10269// and setter on the first call to DefineAccessor and ignored on
10270// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010271RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10273 // Compute attributes.
10274 PropertyAttributes attributes = NONE;
10275 if (args.length() == 5) {
10276 CONVERT_CHECKED(Smi, attrs, args[4]);
10277 int value = attrs->value();
10278 // Only attribute bits should be set.
10279 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10280 attributes = static_cast<PropertyAttributes>(value);
10281 }
10282
10283 CONVERT_CHECKED(JSObject, obj, args[0]);
10284 CONVERT_CHECKED(String, name, args[1]);
10285 CONVERT_CHECKED(Smi, flag, args[2]);
10286 CONVERT_CHECKED(JSFunction, fun, args[3]);
10287 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10288}
10289
10290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010291RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010292 ASSERT(args.length() == 3);
10293 CONVERT_CHECKED(JSObject, obj, args[0]);
10294 CONVERT_CHECKED(String, name, args[1]);
10295 CONVERT_CHECKED(Smi, flag, args[2]);
10296 return obj->LookupAccessor(name, flag->value() == 0);
10297}
10298
10299
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010300#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010301RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010302 ASSERT(args.length() == 0);
10303 return Execution::DebugBreakHelper();
10304}
10305
10306
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010307// Helper functions for wrapping and unwrapping stack frame ids.
10308static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010309 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310 return Smi::FromInt(id >> 2);
10311}
10312
10313
10314static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10315 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10316}
10317
10318
10319// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010320// args[0]: debug event listener function to set or null or undefined for
10321// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010323RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010325 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10326 args[0]->IsUndefined() ||
10327 args[0]->IsNull());
10328 Handle<Object> callback = args.at<Object>(0);
10329 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010330 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010332 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333}
10334
10335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010336RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010337 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010338 isolate->stack_guard()->DebugBreak();
10339 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010340}
10341
10342
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010343static MaybeObject* DebugLookupResultValue(Heap* heap,
10344 Object* receiver,
10345 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010346 LookupResult* result,
10347 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010348 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010349 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010350 case NORMAL:
10351 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010352 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010353 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354 }
10355 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010356 case FIELD:
10357 value =
10358 JSObject::cast(
10359 result->holder())->FastPropertyAt(result->GetFieldIndex());
10360 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010361 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010362 }
10363 return value;
10364 case CONSTANT_FUNCTION:
10365 return result->GetConstantFunction();
10366 case CALLBACKS: {
10367 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010368 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010369 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10370 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010371 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010372 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010373 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010374 maybe_value = heap->isolate()->pending_exception();
10375 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010376 if (caught_exception != NULL) {
10377 *caught_exception = true;
10378 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010379 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010380 }
10381 return value;
10382 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010383 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010384 }
10385 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010386 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010387 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010388 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010389 case CONSTANT_TRANSITION:
10390 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010391 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010392 default:
10393 UNREACHABLE();
10394 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010395 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010396 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397}
10398
10399
ager@chromium.org32912102009-01-16 10:38:43 +000010400// Get debugger related details for an object property.
10401// args[0]: object holding property
10402// args[1]: name of the property
10403//
10404// The array returned contains the following information:
10405// 0: Property value
10406// 1: Property details
10407// 2: Property value is exception
10408// 3: Getter function if defined
10409// 4: Setter function if defined
10410// Items 2-4 are only filled if the property has either a getter or a setter
10411// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010412RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010413 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414
10415 ASSERT(args.length() == 2);
10416
10417 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10418 CONVERT_ARG_CHECKED(String, name, 1);
10419
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010420 // Make sure to set the current context to the context before the debugger was
10421 // entered (if the debugger is entered). The reason for switching context here
10422 // is that for some property lookups (accessors and interceptors) callbacks
10423 // into the embedding application can occour, and the embedding application
10424 // could have the assumption that its own global context is the current
10425 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010426 SaveContext save(isolate);
10427 if (isolate->debug()->InDebugger()) {
10428 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010429 }
10430
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010431 // Skip the global proxy as it has no properties and always delegates to the
10432 // real global object.
10433 if (obj->IsJSGlobalProxy()) {
10434 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10435 }
10436
10437
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010438 // Check if the name is trivially convertible to an index and get the element
10439 // if so.
10440 uint32_t index;
10441 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010442 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010443 Object* element_or_char;
10444 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010445 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010446 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10447 return maybe_element_or_char;
10448 }
10449 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010450 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010452 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010453 }
10454
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010455 // Find the number of objects making up this.
10456 int length = LocalPrototypeChainLength(*obj);
10457
10458 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010459 Handle<JSObject> jsproto = obj;
10460 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010461 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010462 jsproto->LocalLookup(*name, &result);
10463 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010464 // LookupResult is not GC safe as it holds raw object pointers.
10465 // GC can happen later in this code so put the required fields into
10466 // local variables using handles when required for later use.
10467 PropertyType result_type = result.type();
10468 Handle<Object> result_callback_obj;
10469 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10471 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010472 }
10473 Smi* property_details = result.GetPropertyDetails().AsSmi();
10474 // DebugLookupResultValue can cause GC so details from LookupResult needs
10475 // to be copied to handles before this.
10476 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010477 Object* raw_value;
10478 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010479 DebugLookupResultValue(isolate->heap(), *obj, *name,
10480 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010481 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10482 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010483 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010484
10485 // If the callback object is a fixed array then it contains JavaScript
10486 // getter and/or setter.
10487 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10488 result_callback_obj->IsFixedArray();
10489 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010490 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010491 details->set(0, *value);
10492 details->set(1, property_details);
10493 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010494 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010495 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10496 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10497 }
10498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010499 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010500 }
10501 if (i < length - 1) {
10502 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10503 }
10504 }
10505
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507}
10508
10509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010510RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010511 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010512
10513 ASSERT(args.length() == 2);
10514
10515 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10516 CONVERT_ARG_CHECKED(String, name, 1);
10517
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010518 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519 obj->Lookup(*name, &result);
10520 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010521 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010522 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010523 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524}
10525
10526
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527// Return the property type calculated from the property details.
10528// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010529RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530 ASSERT(args.length() == 1);
10531 CONVERT_CHECKED(Smi, details, args[0]);
10532 PropertyType type = PropertyDetails(details).type();
10533 return Smi::FromInt(static_cast<int>(type));
10534}
10535
10536
10537// Return the property attribute calculated from the property details.
10538// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010539RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540 ASSERT(args.length() == 1);
10541 CONVERT_CHECKED(Smi, details, args[0]);
10542 PropertyAttributes attributes = PropertyDetails(details).attributes();
10543 return Smi::FromInt(static_cast<int>(attributes));
10544}
10545
10546
10547// Return the property insertion index calculated from the property details.
10548// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010549RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010550 ASSERT(args.length() == 1);
10551 CONVERT_CHECKED(Smi, details, args[0]);
10552 int index = PropertyDetails(details).index();
10553 return Smi::FromInt(index);
10554}
10555
10556
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557// Return property value from named interceptor.
10558// args[0]: object
10559// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010560RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010561 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010562 ASSERT(args.length() == 2);
10563 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10564 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10565 CONVERT_ARG_CHECKED(String, name, 1);
10566
10567 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010568 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010569}
10570
10571
10572// Return element value from indexed interceptor.
10573// args[0]: object
10574// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010575RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010576 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010577 ASSERT(args.length() == 2);
10578 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10579 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10580 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10581
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010582 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010583}
10584
10585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010586RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587 ASSERT(args.length() >= 1);
10588 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010589 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010590 if (isolate->debug()->break_id() == 0 ||
10591 break_id != isolate->debug()->break_id()) {
10592 return isolate->Throw(
10593 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594 }
10595
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010596 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597}
10598
10599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010600RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
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
10604 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010605 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010606 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10607 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010608 if (!maybe_result->ToObject(&result)) return maybe_result;
10609 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610
10611 // Count all frames which are relevant to debugging stack trace.
10612 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010613 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010614 if (id == StackFrame::NO_ID) {
10615 // If there is no JavaScript stack frame count is 0.
10616 return Smi::FromInt(0);
10617 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010618
10619 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10620 n += it.frame()->GetInlineCount();
10621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622 return Smi::FromInt(n);
10623}
10624
10625
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010626class FrameInspector {
10627 public:
10628 FrameInspector(JavaScriptFrame* frame,
10629 int inlined_frame_index,
10630 Isolate* isolate)
10631 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10632 // Calculate the deoptimized frame.
10633 if (frame->is_optimized()) {
10634 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10635 frame, inlined_frame_index, isolate);
10636 }
10637 has_adapted_arguments_ = frame_->has_adapted_arguments();
10638 is_optimized_ = frame_->is_optimized();
10639 }
10640
10641 ~FrameInspector() {
10642 // Get rid of the calculated deoptimized frame if any.
10643 if (deoptimized_frame_ != NULL) {
10644 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10645 isolate_);
10646 }
10647 }
10648
10649 int GetParametersCount() {
10650 return is_optimized_
10651 ? deoptimized_frame_->parameters_count()
10652 : frame_->ComputeParametersCount();
10653 }
10654 int expression_count() { return deoptimized_frame_->expression_count(); }
10655 Object* GetFunction() {
10656 return is_optimized_
10657 ? deoptimized_frame_->GetFunction()
10658 : frame_->function();
10659 }
10660 Object* GetParameter(int index) {
10661 return is_optimized_
10662 ? deoptimized_frame_->GetParameter(index)
10663 : frame_->GetParameter(index);
10664 }
10665 Object* GetExpression(int index) {
10666 return is_optimized_
10667 ? deoptimized_frame_->GetExpression(index)
10668 : frame_->GetExpression(index);
10669 }
10670
10671 // To inspect all the provided arguments the frame might need to be
10672 // replaced with the arguments frame.
10673 void SetArgumentsFrame(JavaScriptFrame* frame) {
10674 ASSERT(has_adapted_arguments_);
10675 frame_ = frame;
10676 is_optimized_ = frame_->is_optimized();
10677 ASSERT(!is_optimized_);
10678 }
10679
10680 private:
10681 JavaScriptFrame* frame_;
10682 DeoptimizedFrameInfo* deoptimized_frame_;
10683 Isolate* isolate_;
10684 bool is_optimized_;
10685 bool has_adapted_arguments_;
10686
10687 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10688};
10689
10690
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010691static const int kFrameDetailsFrameIdIndex = 0;
10692static const int kFrameDetailsReceiverIndex = 1;
10693static const int kFrameDetailsFunctionIndex = 2;
10694static const int kFrameDetailsArgumentCountIndex = 3;
10695static const int kFrameDetailsLocalCountIndex = 4;
10696static const int kFrameDetailsSourcePositionIndex = 5;
10697static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010698static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010699static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010700static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010701
10702// Return an array with frame details
10703// args[0]: number: break id
10704// args[1]: number: frame index
10705//
10706// The array returned contains the following information:
10707// 0: Frame id
10708// 1: Receiver
10709// 2: Function
10710// 3: Argument count
10711// 4: Local count
10712// 5: Source position
10713// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010714// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010715// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010716// Arguments name, value
10717// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010718// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010720 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010721 ASSERT(args.length() == 2);
10722
10723 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010724 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010725 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10726 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010727 if (!maybe_check->ToObject(&check)) return maybe_check;
10728 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010729 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010730 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010731
10732 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010733 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010734 if (id == StackFrame::NO_ID) {
10735 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010736 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010737 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010738
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010739 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010740
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010741 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010742 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010743 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010744 if (index < count + it.frame()->GetInlineCount()) break;
10745 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010747 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010748
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010749 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010750 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010751 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010752 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010753 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010754
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755 // Traverse the saved contexts chain to find the active context for the
10756 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010757 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010758 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759 save = save->prev();
10760 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010761 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762
10763 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010764 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010765
10766 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010768 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010769
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010770 // Check for constructor frame. Inlined frames cannot be construct calls.
10771 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010772 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010773 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010775 // Get scope info and read from it for local variable information.
10776 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010777 Handle<SharedFunctionInfo> shared(function->shared());
10778 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010779 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010780 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782 // Get the locals names and values into a temporary array.
10783 //
10784 // TODO(1240907): Hide compiler-introduced stack variables
10785 // (e.g. .result)? For users of the debugger, they will probably be
10786 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010787 Handle<FixedArray> locals =
10788 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010789
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010790 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010791 int i = 0;
10792 for (; i < info.number_of_stack_slots(); ++i) {
10793 // Use the value from the stack.
10794 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010795 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010796 }
10797 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010798 // Get the context containing declarations.
10799 Handle<Context> context(
10800 Context::cast(it.frame()->context())->declaration_context());
10801 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010802 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010803 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010804 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010805 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010806 }
10807 }
10808
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010809 // Check whether this frame is positioned at return. If not top
10810 // frame or if the frame is optimized it cannot be at a return.
10811 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010812 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010813 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010814 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010815
10816 // If positioned just before return find the value to be returned and add it
10817 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010818 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010819 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010820 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010821 Address internal_frame_sp = NULL;
10822 while (!it2.done()) {
10823 if (it2.frame()->is_internal()) {
10824 internal_frame_sp = it2.frame()->sp();
10825 } else {
10826 if (it2.frame()->is_java_script()) {
10827 if (it2.frame()->id() == it.frame()->id()) {
10828 // The internal frame just before the JavaScript frame contains the
10829 // value to return on top. A debug break at return will create an
10830 // internal frame to store the return value (eax/rax/r0) before
10831 // entering the debug break exit frame.
10832 if (internal_frame_sp != NULL) {
10833 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010834 Handle<Object>(Memory::Object_at(internal_frame_sp),
10835 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010836 break;
10837 }
10838 }
10839 }
10840
10841 // Indicate that the previous frame was not an internal frame.
10842 internal_frame_sp = NULL;
10843 }
10844 it2.Advance();
10845 }
10846 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010847
10848 // Now advance to the arguments adapter frame (if any). It contains all
10849 // the provided parameters whereas the function frame always have the number
10850 // of arguments matching the functions parameters. The rest of the
10851 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010852 if (it.frame()->has_adapted_arguments()) {
10853 it.AdvanceToArgumentsFrame();
10854 frame_inspector.SetArgumentsFrame(it.frame());
10855 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856
10857 // Find the number of arguments to fill. At least fill the number of
10858 // parameters for the function and fill more if more parameters are provided.
10859 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010860 if (argument_count < frame_inspector.GetParametersCount()) {
10861 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010862 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010863#ifdef DEBUG
10864 if (it.frame()->is_optimized()) {
10865 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10866 }
10867#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010868
10869 // Calculate the size of the result.
10870 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010871 2 * (argument_count + info.NumberOfLocals()) +
10872 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010873 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874
10875 // Add the frame id.
10876 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10877
10878 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010879 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880
10881 // Add the arguments count.
10882 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10883
10884 // Add the locals count
10885 details->set(kFrameDetailsLocalCountIndex,
10886 Smi::FromInt(info.NumberOfLocals()));
10887
10888 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010889 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10891 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010892 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893 }
10894
10895 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010896 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010897
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010898 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010899 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010900
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010901 // Add flags to indicate information on whether this frame is
10902 // bit 0: invoked in the debugger context.
10903 // bit 1: optimized frame.
10904 // bit 2: inlined in optimized frame
10905 int flags = 0;
10906 if (*save->context() == *isolate->debug()->debug_context()) {
10907 flags |= 1 << 0;
10908 }
10909 if (it.frame()->is_optimized()) {
10910 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010911 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010912 }
10913 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010914
10915 // Fill the dynamic part.
10916 int details_index = kFrameDetailsFirstDynamicIndex;
10917
10918 // Add arguments name and value.
10919 for (int i = 0; i < argument_count; i++) {
10920 // Name of the argument.
10921 if (i < info.number_of_parameters()) {
10922 details->set(details_index++, *info.parameter_name(i));
10923 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010924 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010925 }
10926
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010927 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010928 if (i < it.frame()->ComputeParametersCount()) {
10929 // Get the value from the stack.
10930 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010932 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010933 }
10934 }
10935
10936 // Add locals name and value from the temporary copy from the function frame.
10937 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10938 details->set(details_index++, locals->get(i));
10939 }
10940
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010941 // Add the value being returned.
10942 if (at_return) {
10943 details->set(details_index++, *return_value);
10944 }
10945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946 // Add the receiver (same as in function frame).
10947 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10948 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010949 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010950 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10951 // If the receiver is not a JSObject and the function is not a
10952 // builtin or strict-mode we have hit an optimization where a
10953 // value object is not converted into a wrapped JS objects. To
10954 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955 // by creating correct wrapper object based on the calling frame's
10956 // global context.
10957 it.Advance();
10958 Handle<Context> calling_frames_global_context(
10959 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010960 receiver =
10961 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010962 }
10963 details->set(kFrameDetailsReceiverIndex, *receiver);
10964
10965 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010966 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967}
10968
10969
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010970// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010971static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010972 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010973 Handle<SerializedScopeInfo> serialized_scope_info,
10974 ScopeInfo<>& scope_info,
10975 Handle<Context> context,
10976 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010977 // Fill all context locals to the context extension.
10978 for (int i = Context::MIN_CONTEXT_SLOTS;
10979 i < scope_info.number_of_context_slots();
10980 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010981 int context_index = serialized_scope_info->ContextSlotIndex(
10982 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010983
whesse@chromium.org7b260152011-06-20 15:33:18 +000010984 RETURN_IF_EMPTY_HANDLE_VALUE(
10985 isolate,
10986 SetProperty(scope_object,
10987 scope_info.context_slot_name(i),
10988 Handle<Object>(context->get(context_index), isolate),
10989 NONE,
10990 kNonStrictMode),
10991 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010992 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010993
10994 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010995}
10996
10997
10998// Create a plain JSObject which materializes the local scope for the specified
10999// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011000static Handle<JSObject> MaterializeLocalScope(
11001 Isolate* isolate,
11002 JavaScriptFrame* frame,
11003 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011004 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011005 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000011006 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
11007 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011008 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011009
11010 // Allocate and initialize a JSObject with all the arguments, stack locals
11011 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011012 Handle<JSObject> local_scope =
11013 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011014
11015 // First fill all parameters.
11016 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011017 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011018 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011019 SetProperty(local_scope,
11020 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011021 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011022 NONE,
11023 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011024 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011025 }
11026
11027 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011028 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011029 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011030 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011031 SetProperty(local_scope,
11032 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011033 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011034 NONE,
11035 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011036 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011037 }
11038
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011039 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
11040 // Third fill all context locals.
11041 Handle<Context> frame_context(Context::cast(frame->context()));
11042 Handle<Context> function_context(frame_context->declaration_context());
11043 if (!CopyContextLocalsToScopeObject(isolate,
11044 serialized_scope_info, scope_info,
11045 function_context, local_scope)) {
11046 return Handle<JSObject>();
11047 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011048
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011049 // Finally copy any properties from the function context extension.
11050 // These will be variables introduced by eval.
11051 if (function_context->closure() == *function) {
11052 if (function_context->has_extension() &&
11053 !function_context->IsGlobalContext()) {
11054 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011055 bool threw = false;
11056 Handle<FixedArray> keys =
11057 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11058 if (threw) return Handle<JSObject>();
11059
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011060 for (int i = 0; i < keys->length(); i++) {
11061 // Names of variables introduced by eval are strings.
11062 ASSERT(keys->get(i)->IsString());
11063 Handle<String> key(String::cast(keys->get(i)));
11064 RETURN_IF_EMPTY_HANDLE_VALUE(
11065 isolate,
11066 SetProperty(local_scope,
11067 key,
11068 GetProperty(ext, key),
11069 NONE,
11070 kNonStrictMode),
11071 Handle<JSObject>());
11072 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011073 }
11074 }
11075 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011076
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011077 return local_scope;
11078}
11079
11080
11081// Create a plain JSObject which materializes the closure content for the
11082// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011083static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11084 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011085 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011086
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011087 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000011088 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
11089 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011090
11091 // Allocate and initialize a JSObject with all the content of theis function
11092 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011093 Handle<JSObject> closure_scope =
11094 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011095
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011096 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011097 if (!CopyContextLocalsToScopeObject(isolate,
11098 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011099 context, closure_scope)) {
11100 return Handle<JSObject>();
11101 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011102
11103 // Finally copy any properties from the function context extension. This will
11104 // be variables introduced by eval.
11105 if (context->has_extension()) {
11106 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011107 bool threw = false;
11108 Handle<FixedArray> keys =
11109 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11110 if (threw) return Handle<JSObject>();
11111
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112 for (int i = 0; i < keys->length(); i++) {
11113 // Names of variables introduced by eval are strings.
11114 ASSERT(keys->get(i)->IsString());
11115 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 RETURN_IF_EMPTY_HANDLE_VALUE(
11117 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011118 SetProperty(closure_scope,
11119 key,
11120 GetProperty(ext, key),
11121 NONE,
11122 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011123 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124 }
11125 }
11126
11127 return closure_scope;
11128}
11129
11130
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011131// Create a plain JSObject which materializes the scope for the specified
11132// catch context.
11133static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11134 Handle<Context> context) {
11135 ASSERT(context->IsCatchContext());
11136 Handle<String> name(String::cast(context->extension()));
11137 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11138 Handle<JSObject> catch_scope =
11139 isolate->factory()->NewJSObject(isolate->object_function());
11140 RETURN_IF_EMPTY_HANDLE_VALUE(
11141 isolate,
11142 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11143 Handle<JSObject>());
11144 return catch_scope;
11145}
11146
11147
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011148// Create a plain JSObject which materializes the block scope for the specified
11149// block context.
11150static Handle<JSObject> MaterializeBlockScope(
11151 Isolate* isolate,
11152 Handle<Context> context) {
11153 ASSERT(context->IsBlockContext());
11154 Handle<SerializedScopeInfo> serialized_scope_info(
11155 SerializedScopeInfo::cast(context->extension()));
11156 ScopeInfo<> scope_info(*serialized_scope_info);
11157
11158 // Allocate and initialize a JSObject with all the arguments, stack locals
11159 // heap locals and extension properties of the debugged function.
11160 Handle<JSObject> block_scope =
11161 isolate->factory()->NewJSObject(isolate->object_function());
11162
11163 // Fill all context locals.
11164 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
11165 if (!CopyContextLocalsToScopeObject(isolate,
11166 serialized_scope_info, scope_info,
11167 context, block_scope)) {
11168 return Handle<JSObject>();
11169 }
11170 }
11171
11172 return block_scope;
11173}
11174
11175
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011176// Iterate over the actual scopes visible from a stack frame. The iteration
11177// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011178// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011179// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011180class ScopeIterator {
11181 public:
11182 enum ScopeType {
11183 ScopeTypeGlobal = 0,
11184 ScopeTypeLocal,
11185 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011186 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011187 ScopeTypeCatch,
11188 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011189 };
11190
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011191 ScopeIterator(Isolate* isolate,
11192 JavaScriptFrame* frame,
11193 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011194 : isolate_(isolate),
11195 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011196 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011197 function_(JSFunction::cast(frame->function())),
11198 context_(Context::cast(frame->context())),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011199 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011200
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011201 // Catch the case when the debugger stops in an internal function.
11202 Handle<SharedFunctionInfo> shared_info(function_->shared());
11203 if (shared_info->script() == isolate->heap()->undefined_value()) {
11204 while (context_->closure() == *function_) {
11205 context_ = Handle<Context>(context_->previous(), isolate_);
11206 }
11207 return;
11208 }
11209
11210 // Check whether we are in global code or function code. If there is a stack
11211 // slot for .result then this function has been created for evaluating
11212 // global code and it is not a real function.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011213 // Checking for the existence of .result seems fragile, but the scope info
11214 // saved with the code object does not otherwise have that information.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011215 int index = shared_info->scope_info()->
lrn@chromium.org34e60782011-09-15 07:25:40 +000011216 StackSlotIndex(isolate_->heap()->result_symbol());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011217
11218 // Reparse the code and analyze the scopes.
11219 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11220 Handle<Script> script(Script::cast(shared_info->script()));
11221 Scope* scope;
lrn@chromium.org34e60782011-09-15 07:25:40 +000011222 if (index >= 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011223 // Global code
11224 CompilationInfo info(script);
11225 info.MarkAsGlobal();
11226 bool result = ParserApi::Parse(&info);
11227 ASSERT(result);
11228 result = Scope::Analyze(&info);
11229 ASSERT(result);
11230 scope = info.function()->scope();
11231 } else {
11232 // Function code
11233 CompilationInfo info(shared_info);
11234 bool result = ParserApi::Parse(&info);
11235 ASSERT(result);
11236 result = Scope::Analyze(&info);
11237 ASSERT(result);
11238 scope = info.function()->scope();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011239 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011240
11241 // Retrieve the scope chain for the current position.
11242 int statement_position =
11243 shared_info->code()->SourceStatementPosition(frame_->pc());
11244 scope->GetNestedScopeChain(&nested_scope_chain_, statement_position);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011245 }
11246
11247 // More scopes?
11248 bool Done() { return context_.is_null(); }
11249
11250 // Move to the next scope.
11251 void Next() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011252 ScopeType scope_type = Type();
11253 if (scope_type == ScopeTypeGlobal) {
11254 // The global scope is always the last in the chain.
11255 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011256 context_ = Handle<Context>();
11257 return;
11258 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011259 if (nested_scope_chain_.is_empty()) {
11260 context_ = Handle<Context>(context_->previous(), isolate_);
11261 } else {
11262 if (nested_scope_chain_.last()->HasContext()) {
11263 context_ = Handle<Context>(context_->previous(), isolate_);
11264 }
11265 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011266 }
11267 }
11268
11269 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011270 ScopeType Type() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011271 if (!nested_scope_chain_.is_empty()) {
11272 Handle<SerializedScopeInfo> scope_info = nested_scope_chain_.last();
11273 switch (scope_info->Type()) {
11274 case FUNCTION_SCOPE:
11275 ASSERT(context_->IsFunctionContext() ||
11276 !scope_info->HasContext());
11277 return ScopeTypeLocal;
11278 case GLOBAL_SCOPE:
11279 ASSERT(context_->IsGlobalContext());
11280 return ScopeTypeGlobal;
11281 case WITH_SCOPE:
11282 ASSERT(context_->IsWithContext());
11283 return ScopeTypeWith;
11284 case CATCH_SCOPE:
11285 ASSERT(context_->IsCatchContext());
11286 return ScopeTypeCatch;
11287 case BLOCK_SCOPE:
11288 ASSERT(!scope_info->HasContext() ||
11289 context_->IsBlockContext());
11290 return ScopeTypeBlock;
11291 case EVAL_SCOPE:
11292 UNREACHABLE();
11293 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011294 }
11295 if (context_->IsGlobalContext()) {
11296 ASSERT(context_->global()->IsGlobalObject());
11297 return ScopeTypeGlobal;
11298 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011299 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011300 return ScopeTypeClosure;
11301 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011302 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011303 return ScopeTypeCatch;
11304 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011305 if (context_->IsBlockContext()) {
11306 return ScopeTypeBlock;
11307 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011308 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011309 return ScopeTypeWith;
11310 }
11311
11312 // Return the JavaScript object with the content of the current scope.
11313 Handle<JSObject> ScopeObject() {
11314 switch (Type()) {
11315 case ScopeIterator::ScopeTypeGlobal:
11316 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011317 case ScopeIterator::ScopeTypeLocal:
11318 // Materialize the content of the local scope into a JSObject.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011319 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011320 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011321 case ScopeIterator::ScopeTypeWith:
11322 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011323 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11324 case ScopeIterator::ScopeTypeCatch:
11325 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011326 case ScopeIterator::ScopeTypeClosure:
11327 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011328 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011329 case ScopeIterator::ScopeTypeBlock:
11330 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011331 }
11332 UNREACHABLE();
11333 return Handle<JSObject>();
11334 }
11335
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011336 Handle<SerializedScopeInfo> CurrentScopeInfo() {
11337 if (!nested_scope_chain_.is_empty()) {
11338 return nested_scope_chain_.last();
11339 } else if (context_->IsBlockContext()) {
11340 return Handle<SerializedScopeInfo>(
11341 SerializedScopeInfo::cast(context_->extension()));
11342 } else if (context_->IsFunctionContext()) {
11343 return Handle<SerializedScopeInfo>(
11344 context_->closure()->shared()->scope_info());
11345 }
11346 return Handle<SerializedScopeInfo>::null();
11347 }
11348
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011349 // Return the context for this scope. For the local context there might not
11350 // be an actual context.
11351 Handle<Context> CurrentContext() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011352 if (Type() == ScopeTypeGlobal ||
11353 nested_scope_chain_.is_empty()) {
11354 return context_;
11355 } else if (nested_scope_chain_.last()->HasContext()) {
11356 return context_;
11357 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011358 return Handle<Context>();
11359 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011360 }
11361
11362#ifdef DEBUG
11363 // Debug print of the content of the current scope.
11364 void DebugPrint() {
11365 switch (Type()) {
11366 case ScopeIterator::ScopeTypeGlobal:
11367 PrintF("Global:\n");
11368 CurrentContext()->Print();
11369 break;
11370
11371 case ScopeIterator::ScopeTypeLocal: {
11372 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011373 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011374 scope_info.Print();
11375 if (!CurrentContext().is_null()) {
11376 CurrentContext()->Print();
11377 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011378 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011379 if (extension->IsJSContextExtensionObject()) {
11380 extension->Print();
11381 }
11382 }
11383 }
11384 break;
11385 }
11386
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011387 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011388 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011389 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011390 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011391
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011392 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011393 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011394 CurrentContext()->extension()->Print();
11395 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011396 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011397
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011398 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011399 PrintF("Closure:\n");
11400 CurrentContext()->Print();
11401 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011402 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011403 if (extension->IsJSContextExtensionObject()) {
11404 extension->Print();
11405 }
11406 }
11407 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011408
11409 default:
11410 UNREACHABLE();
11411 }
11412 PrintF("\n");
11413 }
11414#endif
11415
11416 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011417 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011418 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011419 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011420 Handle<JSFunction> function_;
11421 Handle<Context> context_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011422 List<Handle<SerializedScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011423
11424 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11425};
11426
11427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011428RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011429 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011430 ASSERT(args.length() == 2);
11431
11432 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011433 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011434 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11435 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011436 if (!maybe_check->ToObject(&check)) return maybe_check;
11437 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011438 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11439
11440 // Get the frame where the debugging is performed.
11441 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011442 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011443 JavaScriptFrame* frame = it.frame();
11444
11445 // Count the visible scopes.
11446 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011447 for (ScopeIterator it(isolate, frame, 0);
11448 !it.Done();
11449 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011450 n++;
11451 }
11452
11453 return Smi::FromInt(n);
11454}
11455
11456
11457static const int kScopeDetailsTypeIndex = 0;
11458static const int kScopeDetailsObjectIndex = 1;
11459static const int kScopeDetailsSize = 2;
11460
11461// Return an array with scope details
11462// args[0]: number: break id
11463// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011464// args[2]: number: inlined frame index
11465// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011466//
11467// The array returned contains the following information:
11468// 0: Scope type
11469// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011470RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011471 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011472 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011473
11474 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011475 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011476 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11477 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011478 if (!maybe_check->ToObject(&check)) return maybe_check;
11479 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011480 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011481 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11482 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011483
11484 // Get the frame where the debugging is performed.
11485 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011486 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011487 JavaScriptFrame* frame = frame_it.frame();
11488
11489 // Find the requested scope.
11490 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011491 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011492 for (; !it.Done() && n < index; it.Next()) {
11493 n++;
11494 }
11495 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011496 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011497 }
11498
11499 // Calculate the size of the result.
11500 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011501 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011502
11503 // Fill in scope details.
11504 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011505 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011507 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011508
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011509 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011510}
11511
11512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011513RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011514 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011515 ASSERT(args.length() == 0);
11516
11517#ifdef DEBUG
11518 // Print the scopes for the top frame.
11519 StackFrameLocator locator;
11520 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011521 for (ScopeIterator it(isolate, frame, 0);
11522 !it.Done();
11523 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011524 it.DebugPrint();
11525 }
11526#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011527 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011528}
11529
11530
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011531RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011532 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011533 ASSERT(args.length() == 1);
11534
11535 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011536 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011537 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11538 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011539 if (!maybe_result->ToObject(&result)) return maybe_result;
11540 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011541
11542 // Count all archived V8 threads.
11543 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011544 for (ThreadState* thread =
11545 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011546 thread != NULL;
11547 thread = thread->Next()) {
11548 n++;
11549 }
11550
11551 // Total number of threads is current thread and archived threads.
11552 return Smi::FromInt(n + 1);
11553}
11554
11555
11556static const int kThreadDetailsCurrentThreadIndex = 0;
11557static const int kThreadDetailsThreadIdIndex = 1;
11558static const int kThreadDetailsSize = 2;
11559
11560// Return an array with thread details
11561// args[0]: number: break id
11562// args[1]: number: thread index
11563//
11564// The array returned contains the following information:
11565// 0: Is current thread?
11566// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011567RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011568 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011569 ASSERT(args.length() == 2);
11570
11571 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011572 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011573 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11574 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011575 if (!maybe_check->ToObject(&check)) return maybe_check;
11576 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011577 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11578
11579 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 Handle<FixedArray> details =
11581 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011582
11583 // Thread index 0 is current thread.
11584 if (index == 0) {
11585 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011586 details->set(kThreadDetailsCurrentThreadIndex,
11587 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011588 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011589 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011590 } else {
11591 // Find the thread with the requested index.
11592 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011593 ThreadState* thread =
11594 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011595 while (index != n && thread != NULL) {
11596 thread = thread->Next();
11597 n++;
11598 }
11599 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011600 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011601 }
11602
11603 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011604 details->set(kThreadDetailsCurrentThreadIndex,
11605 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011606 details->set(kThreadDetailsThreadIdIndex,
11607 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011608 }
11609
11610 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011611 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011612}
11613
11614
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011615// Sets the disable break state
11616// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011617RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011618 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011619 ASSERT(args.length() == 1);
11620 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 isolate->debug()->set_disable_break(disable_break);
11622 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011623}
11624
11625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011626RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011628 ASSERT(args.length() == 1);
11629
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011630 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11631 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011632 // Find the number of break points
11633 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011634 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011635 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011636 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011637 Handle<FixedArray>::cast(break_locations));
11638}
11639
11640
11641// Set a break point in a function
11642// args[0]: function
11643// args[1]: number: break source position (within the function source)
11644// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011645RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011648 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11649 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011650 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11651 RUNTIME_ASSERT(source_position >= 0);
11652 Handle<Object> break_point_object_arg = args.at<Object>(2);
11653
11654 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11656 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011657
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011658 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011659}
11660
11661
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011662Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11663 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011664 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011665 // Iterate the heap looking for SharedFunctionInfo generated from the
11666 // script. The inner most SharedFunctionInfo containing the source position
11667 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011668 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011669 // which is found is not compiled it is compiled and the heap is iterated
11670 // again as the compilation might create inner functions from the newly
11671 // compiled function and the actual requested break point might be in one of
11672 // these functions.
11673 bool done = false;
11674 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011675 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011676 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011677 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011678 { // Extra scope for iterator and no-allocation.
11679 isolate->heap()->EnsureHeapIsIterable();
11680 AssertNoAllocation no_alloc_during_heap_iteration;
11681 HeapIterator iterator;
11682 for (HeapObject* obj = iterator.next();
11683 obj != NULL; obj = iterator.next()) {
11684 if (obj->IsSharedFunctionInfo()) {
11685 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11686 if (shared->script() == *script) {
11687 // If the SharedFunctionInfo found has the requested script data and
11688 // contains the source position it is a candidate.
11689 int start_position = shared->function_token_position();
11690 if (start_position == RelocInfo::kNoPosition) {
11691 start_position = shared->start_position();
11692 }
11693 if (start_position <= position &&
11694 position <= shared->end_position()) {
11695 // If there is no candidate or this function is within the current
11696 // candidate this is the new candidate.
11697 if (target.is_null()) {
11698 target_start_position = start_position;
11699 target = shared;
11700 } else {
11701 if (target_start_position == start_position &&
11702 shared->end_position() == target->end_position()) {
11703 // If a top-level function contain only one function
11704 // declartion the source for the top-level and the
11705 // function is the same. In that case prefer the non
11706 // top-level function.
11707 if (!shared->is_toplevel()) {
11708 target_start_position = start_position;
11709 target = shared;
11710 }
11711 } else if (target_start_position <= start_position &&
11712 shared->end_position() <= target->end_position()) {
11713 // This containment check includes equality as a function
11714 // inside a top-level function can share either start or end
11715 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011716 target_start_position = start_position;
11717 target = shared;
11718 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011719 }
11720 }
11721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011722 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011723 } // End for loop.
11724 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011725
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011726 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011727 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011728 }
11729
11730 // If the candidate found is compiled we are done. NOTE: when lazy
11731 // compilation of inner functions is introduced some additional checking
11732 // needs to be done here to compile inner functions.
11733 done = target->is_compiled();
11734 if (!done) {
11735 // If the candidate is not compiled compile it to reveal any inner
11736 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011737 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011738 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011739 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011740
11741 return *target;
11742}
11743
11744
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011745// Changes the state of a break point in a script and returns source position
11746// where break point was set. NOTE: Regarding performance see the NOTE for
11747// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011748// args[0]: script to set break point in
11749// args[1]: number: break source position (within the script source)
11750// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011751RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011752 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011753 ASSERT(args.length() == 3);
11754 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11755 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11756 RUNTIME_ASSERT(source_position >= 0);
11757 Handle<Object> break_point_object_arg = args.at<Object>(2);
11758
11759 // Get the script from the script wrapper.
11760 RUNTIME_ASSERT(wrapper->value()->IsScript());
11761 Handle<Script> script(Script::cast(wrapper->value()));
11762
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011763 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011764 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011765 if (!result->IsUndefined()) {
11766 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11767 // Find position within function. The script position might be before the
11768 // source position of the first function.
11769 int position;
11770 if (shared->start_position() > source_position) {
11771 position = 0;
11772 } else {
11773 position = source_position - shared->start_position();
11774 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011775 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011776 position += shared->start_position();
11777 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011778 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011779 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011780}
11781
11782
11783// Clear a break point
11784// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011785RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011786 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011787 ASSERT(args.length() == 1);
11788 Handle<Object> break_point_object_arg = args.at<Object>(0);
11789
11790 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011791 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011793 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011794}
11795
11796
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011797// Change the state of break on exceptions.
11798// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11799// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011800RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011801 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011802 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011803 RUNTIME_ASSERT(args[0]->IsNumber());
11804 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011805
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011806 // If the number doesn't match an enum value, the ChangeBreakOnException
11807 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011808 ExceptionBreakType type =
11809 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011810 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011811 isolate->debug()->ChangeBreakOnException(type, enable);
11812 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011813}
11814
11815
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011816// Returns the state of break on exceptions
11817// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011818RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011819 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011820 ASSERT(args.length() == 1);
11821 RUNTIME_ASSERT(args[0]->IsNumber());
11822
11823 ExceptionBreakType type =
11824 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011825 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011826 return Smi::FromInt(result);
11827}
11828
11829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011830// Prepare for stepping
11831// args[0]: break id for checking execution state
11832// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011833// args[2]: number of times to perform the step, for step out it is the number
11834// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011835RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011836 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837 ASSERT(args.length() == 3);
11838 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011839 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011840 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11841 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011842 if (!maybe_check->ToObject(&check)) return maybe_check;
11843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011844 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011845 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846 }
11847
11848 // Get the step action and check validity.
11849 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11850 if (step_action != StepIn &&
11851 step_action != StepNext &&
11852 step_action != StepOut &&
11853 step_action != StepInMin &&
11854 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011855 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011856 }
11857
11858 // Get the number of steps.
11859 int step_count = NumberToInt32(args[2]);
11860 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011861 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011862 }
11863
ager@chromium.orga1645e22009-09-09 19:27:10 +000011864 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011865 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011866
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011867 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011868 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11869 step_count);
11870 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011871}
11872
11873
11874// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011875RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011876 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011877 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011878 isolate->debug()->ClearStepping();
11879 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011880}
11881
11882
11883// Creates a copy of the with context chain. The copy of the context chain is
11884// is linked to the function context supplied.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011885static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11886 Handle<JSFunction> function,
11887 Handle<Context> base,
11888 JavaScriptFrame* frame,
11889 int inlined_frame_index) {
11890 HandleScope scope(isolate);
11891 List<Handle<SerializedScopeInfo> > scope_chain;
11892 List<Handle<Context> > context_chain;
11893
11894 ScopeIterator it(isolate, frame, inlined_frame_index);
11895 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11896 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11897 ASSERT(!it.Done());
11898 scope_chain.Add(it.CurrentScopeInfo());
11899 context_chain.Add(it.CurrentContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900 }
11901
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011902 // At the end of the chain. Return the base context to link to.
11903 Handle<Context> context = base;
11904
11905 // Iteratively copy and or materialize the nested contexts.
11906 while (!scope_chain.is_empty()) {
11907 Handle<SerializedScopeInfo> scope_info = scope_chain.RemoveLast();
11908 Handle<Context> current = context_chain.RemoveLast();
11909 ASSERT(!(scope_info->HasContext() & current.is_null()));
11910
11911 if (scope_info->Type() == CATCH_SCOPE) {
11912 Handle<String> name(String::cast(current->extension()));
11913 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11914 context =
11915 isolate->factory()->NewCatchContext(function,
11916 context,
11917 name,
11918 thrown_object);
11919 } else if (scope_info->Type() == BLOCK_SCOPE) {
11920 // Materialize the contents of the block scope into a JSObject.
11921 Handle<JSObject> block_scope_object =
11922 MaterializeBlockScope(isolate, current);
11923 if (block_scope_object.is_null()) {
11924 return Handle<Context>::null();
11925 }
11926 // Allocate a new function context for the debug evaluation and set the
11927 // extension object.
11928 Handle<Context> new_context =
11929 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11930 function);
11931 new_context->set_extension(*block_scope_object);
11932 new_context->set_previous(*context);
11933 context = new_context;
11934 } else {
11935 ASSERT(scope_info->Type() == WITH_SCOPE);
11936 ASSERT(current->IsWithContext());
11937 Handle<JSObject> extension(JSObject::cast(current->extension()));
11938 context =
11939 isolate->factory()->NewWithContext(function, context, extension);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011940 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011941 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011942
11943 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011944}
11945
11946
11947// Helper function to find or create the arguments object for
11948// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011949static Handle<Object> GetArgumentsObject(Isolate* isolate,
11950 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011951 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011952 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011953 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011954 const ScopeInfo<>* sinfo,
11955 Handle<Context> function_context) {
11956 // Try to find the value of 'arguments' to pass as parameter. If it is not
11957 // found (that is the debugged function does not reference 'arguments' and
11958 // does not support eval) then create an 'arguments' object.
11959 int index;
11960 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011961 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011962 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011963 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011964 }
11965 }
11966
11967 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011968 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11969 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011971 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011972 }
11973 }
11974
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011975 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11976
11977 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011978 Handle<JSObject> arguments =
11979 isolate->factory()->NewArgumentsObject(function, length);
11980 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011981
11982 AssertNoAllocation no_gc;
11983 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011984 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011985 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011987 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988 return arguments;
11989}
11990
11991
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011992static const char kSourceStr[] =
11993 "(function(arguments,__source__){return eval(__source__);})";
11994
11995
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011997// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011998// extension part has all the parameters and locals of the function on the
11999// stack frame. A function which calls eval with the code to evaluate is then
12000// compiled in this context and called in this context. As this context
12001// replaces the context of the function on the stack frame a new (empty)
12002// function is created as well to be used as the closure for the context.
12003// This function and the context acts as replacements for the function on the
12004// stack frame presenting the same view of the values of parameters and
12005// local variables as if the piece of JavaScript was evaluated at the point
12006// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012007RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012008 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012009
12010 // Check the execution state and decode arguments frame and source to be
12011 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012012 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012013 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012014 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12015 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012016 if (!maybe_check_result->ToObject(&check_result)) {
12017 return maybe_check_result;
12018 }
12019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012020 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012021 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12022 CONVERT_ARG_CHECKED(String, source, 3);
12023 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12024 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012025
12026 // Handle the processing of break.
12027 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012028
12029 // Get the frame where the debugging is performed.
12030 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012031 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012032 JavaScriptFrame* frame = it.frame();
12033 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000012034 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012035 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012036
12037 // Traverse the saved contexts chain to find the active context for the
12038 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012039 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012040 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012041 save = save->prev();
12042 }
12043 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012044 SaveContext savex(isolate);
12045 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012046
12047 // Create the (empty) function replacing the function on the stack frame for
12048 // the purpose of evaluating in the context created below. It is important
12049 // that this function does not describe any parameters and local variables
12050 // in the context. If it does then this will cause problems with the lookup
12051 // in Context::Lookup, where context slots for parameters and local variables
12052 // are looked at before the extension object.
12053 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012054 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12055 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012056 go_between->set_context(function->context());
12057#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012058 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012059 ASSERT(go_between_sinfo.number_of_parameters() == 0);
12060 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
12061#endif
12062
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012063 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012064 Handle<JSObject> local_scope = MaterializeLocalScope(
12065 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012066 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012067
12068 // Allocate a new context for the debug evaluation and set the extension
12069 // object build.
12070 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012071 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12072 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012073 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012074 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012075 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012076 Handle<Context> function_context;
12077 // Get the function's context if it has one.
12078 if (scope_info->HasHeapAllocatedLocals()) {
12079 function_context = Handle<Context>(frame_context->declaration_context());
12080 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012081 context = CopyNestedScopeContextChain(isolate,
12082 go_between,
12083 context,
12084 frame,
12085 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012086
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012087 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012088 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012089 context =
12090 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012091 }
12092
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012093 // Wrap the evaluation statement in a new function compiled in the newly
12094 // created context. The function has one parameter which has to be called
12095 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012096 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012098
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012100 isolate->factory()->NewStringFromAscii(
12101 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012102
12103 // Currently, the eval code will be executed in non-strict mode,
12104 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012105 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012106 Compiler::CompileEval(function_source,
12107 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012108 context->IsGlobalContext(),
12109 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012110 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012111 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012112 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012113
12114 // Invoke the result of the compilation to get the evaluation function.
12115 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012116 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117 Handle<Object> evaluation_function =
12118 Execution::Call(compiled_function, receiver, 0, NULL,
12119 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012120 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012122 Handle<Object> arguments = GetArgumentsObject(isolate,
12123 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012124 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012125 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012126
12127 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012128 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012129 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012130 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12131 receiver,
12132 ARRAY_SIZE(argv),
12133 argv,
12134 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012135 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012136
12137 // Skip the global proxy as it has no properties and always delegates to the
12138 // real global object.
12139 if (result->IsJSGlobalProxy()) {
12140 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12141 }
12142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012143 return *result;
12144}
12145
12146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012147RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012148 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012149
12150 // Check the execution state and decode arguments frame and source to be
12151 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012152 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012153 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012154 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12155 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012156 if (!maybe_check_result->ToObject(&check_result)) {
12157 return maybe_check_result;
12158 }
12159 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012160 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012161 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012162 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012163
12164 // Handle the processing of break.
12165 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012166
12167 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012168 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012169 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012170 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012171 top = top->prev();
12172 }
12173 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012174 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012175 }
12176
12177 // Get the global context now set to the top context from before the
12178 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012179 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012180
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012181 bool is_global = true;
12182
12183 if (additional_context->IsJSObject()) {
12184 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012185 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
12186 isolate->factory()->empty_string(),
12187 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012188 go_between->set_context(*context);
12189 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012190 isolate->factory()->NewFunctionContext(
12191 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012192 context->set_extension(JSObject::cast(*additional_context));
12193 is_global = false;
12194 }
12195
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012196 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012197 // Currently, the eval code will be executed in non-strict mode,
12198 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012199 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012200 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012201 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012202 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012203 Handle<JSFunction>(
12204 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12205 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012206
12207 // Invoke the result of the compilation to get the evaluation function.
12208 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012209 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210 Handle<Object> result =
12211 Execution::Call(compiled_function, receiver, 0, NULL,
12212 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012213 // Clear the oneshot breakpoints so that the debugger does not step further.
12214 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012215 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012216 return *result;
12217}
12218
12219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012220RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012221 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012222 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012223
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012224 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012225 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012226
12227 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012228 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012229 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12230 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12231 // because using
12232 // instances->set(i, *GetScriptWrapper(script))
12233 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12234 // already have deferenced the instances handle.
12235 Handle<JSValue> wrapper = GetScriptWrapper(script);
12236 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012237 }
12238
12239 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012240 Handle<JSObject> result =
12241 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012242 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012243 return *result;
12244}
12245
12246
12247// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012248static int DebugReferencedBy(HeapIterator* iterator,
12249 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012250 Object* instance_filter, int max_references,
12251 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012252 JSFunction* arguments_function) {
12253 NoHandleAllocation ha;
12254 AssertNoAllocation no_alloc;
12255
12256 // Iterate the heap.
12257 int count = 0;
12258 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012259 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012260 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012261 (max_references == 0 || count < max_references)) {
12262 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012263 if (heap_obj->IsJSObject()) {
12264 // Skip context extension objects and argument arrays as these are
12265 // checked in the context of functions using them.
12266 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012267 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012268 obj->map()->constructor() == arguments_function) {
12269 continue;
12270 }
12271
12272 // Check if the JS object has a reference to the object looked for.
12273 if (obj->ReferencesObject(target)) {
12274 // Check instance filter if supplied. This is normally used to avoid
12275 // references from mirror objects (see Runtime_IsInPrototypeChain).
12276 if (!instance_filter->IsUndefined()) {
12277 Object* V = obj;
12278 while (true) {
12279 Object* prototype = V->GetPrototype();
12280 if (prototype->IsNull()) {
12281 break;
12282 }
12283 if (instance_filter == prototype) {
12284 obj = NULL; // Don't add this object.
12285 break;
12286 }
12287 V = prototype;
12288 }
12289 }
12290
12291 if (obj != NULL) {
12292 // Valid reference found add to instance array if supplied an update
12293 // count.
12294 if (instances != NULL && count < instances_size) {
12295 instances->set(count, obj);
12296 }
12297 last = obj;
12298 count++;
12299 }
12300 }
12301 }
12302 }
12303
12304 // Check for circular reference only. This can happen when the object is only
12305 // referenced from mirrors and has a circular reference in which case the
12306 // object is not really alive and would have been garbage collected if not
12307 // referenced from the mirror.
12308 if (count == 1 && last == target) {
12309 count = 0;
12310 }
12311
12312 // Return the number of referencing objects found.
12313 return count;
12314}
12315
12316
12317// Scan the heap for objects with direct references to an object
12318// args[0]: the object to find references to
12319// args[1]: constructor function for instances to exclude (Mirror)
12320// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012321RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012322 ASSERT(args.length() == 3);
12323
12324 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012325 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12326 // The heap iterator reserves the right to do a GC to make the heap iterable.
12327 // Due to the GC above we know it won't need to do that, but it seems cleaner
12328 // to get the heap iterator constructed before we start having unprotected
12329 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012330
12331 // Check parameters.
12332 CONVERT_CHECKED(JSObject, target, args[0]);
12333 Object* instance_filter = args[1];
12334 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12335 instance_filter->IsJSObject());
12336 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12337 RUNTIME_ASSERT(max_references >= 0);
12338
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012339
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012340 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012341 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012342 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012343 JSFunction* arguments_function =
12344 JSFunction::cast(arguments_boilerplate->map()->constructor());
12345
12346 // Get the number of referencing objects.
12347 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012348 HeapIterator heap_iterator;
12349 count = DebugReferencedBy(&heap_iterator,
12350 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012351 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012352
12353 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012354 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012355 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012356 if (!maybe_object->ToObject(&object)) return maybe_object;
12357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012358 FixedArray* instances = FixedArray::cast(object);
12359
12360 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012361 // AllocateFixedArray above does not make the heap non-iterable.
12362 ASSERT(HEAP->IsHeapIterable());
12363 HeapIterator heap_iterator2;
12364 count = DebugReferencedBy(&heap_iterator2,
12365 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012366 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012367
12368 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012369 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012370 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012371 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012372 if (!maybe_result->ToObject(&result)) return maybe_result;
12373 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012374}
12375
12376
12377// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012378static int DebugConstructedBy(HeapIterator* iterator,
12379 JSFunction* constructor,
12380 int max_references,
12381 FixedArray* instances,
12382 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012383 AssertNoAllocation no_alloc;
12384
12385 // Iterate the heap.
12386 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012387 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012388 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012389 (max_references == 0 || count < max_references)) {
12390 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012391 if (heap_obj->IsJSObject()) {
12392 JSObject* obj = JSObject::cast(heap_obj);
12393 if (obj->map()->constructor() == constructor) {
12394 // Valid reference found add to instance array if supplied an update
12395 // count.
12396 if (instances != NULL && count < instances_size) {
12397 instances->set(count, obj);
12398 }
12399 count++;
12400 }
12401 }
12402 }
12403
12404 // Return the number of referencing objects found.
12405 return count;
12406}
12407
12408
12409// Scan the heap for objects constructed by a specific function.
12410// args[0]: the constructor to find instances of
12411// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012412RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012413 ASSERT(args.length() == 2);
12414
12415 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012416 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012417
12418 // Check parameters.
12419 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12420 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12421 RUNTIME_ASSERT(max_references >= 0);
12422
12423 // Get the number of referencing objects.
12424 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012425 HeapIterator heap_iterator;
12426 count = DebugConstructedBy(&heap_iterator,
12427 constructor,
12428 max_references,
12429 NULL,
12430 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012431
12432 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012433 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012434 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012435 if (!maybe_object->ToObject(&object)) return maybe_object;
12436 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012437 FixedArray* instances = FixedArray::cast(object);
12438
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012439 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012440 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012441 HeapIterator heap_iterator2;
12442 count = DebugConstructedBy(&heap_iterator2,
12443 constructor,
12444 max_references,
12445 instances,
12446 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012447
12448 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012449 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012450 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12451 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012452 if (!maybe_result->ToObject(&result)) return maybe_result;
12453 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012454 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012455}
12456
12457
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012458// Find the effective prototype object as returned by __proto__.
12459// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012460RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012461 ASSERT(args.length() == 1);
12462
12463 CONVERT_CHECKED(JSObject, obj, args[0]);
12464
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012465 // Use the __proto__ accessor.
12466 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012467}
12468
12469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012470RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012471 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012472 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012473 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012474}
12475
12476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012477RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012478#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012479 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012480 ASSERT(args.length() == 1);
12481 // Get the function and make sure it is compiled.
12482 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012483 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012484 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012485 return Failure::Exception();
12486 }
12487 func->code()->PrintLn();
12488#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012489 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012490}
ager@chromium.org9085a012009-05-11 19:22:57 +000012491
12492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012493RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012494#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012496 ASSERT(args.length() == 1);
12497 // Get the function and make sure it is compiled.
12498 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012499 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012500 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012501 return Failure::Exception();
12502 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012503 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012504#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012505 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012506}
12507
12508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012509RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012510 NoHandleAllocation ha;
12511 ASSERT(args.length() == 1);
12512
12513 CONVERT_CHECKED(JSFunction, f, args[0]);
12514 return f->shared()->inferred_name();
12515}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012516
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012517
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012518static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12519 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012520 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012521 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012522 int counter = 0;
12523 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012524 for (HeapObject* obj = iterator->next();
12525 obj != NULL;
12526 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012527 ASSERT(obj != NULL);
12528 if (!obj->IsSharedFunctionInfo()) {
12529 continue;
12530 }
12531 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12532 if (shared->script() != script) {
12533 continue;
12534 }
12535 if (counter < buffer_size) {
12536 buffer->set(counter, shared);
12537 }
12538 counter++;
12539 }
12540 return counter;
12541}
12542
12543// For a script finds all SharedFunctionInfo's in the heap that points
12544// to this script. Returns JSArray of SharedFunctionInfo wrapped
12545// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012546RUNTIME_FUNCTION(MaybeObject*,
12547 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012548 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012549 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012550 CONVERT_CHECKED(JSValue, script_value, args[0]);
12551
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012552
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012553 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12554
12555 const int kBufferSize = 32;
12556
12557 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012558 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012559 int number;
12560 {
12561 isolate->heap()->EnsureHeapIsIterable();
12562 AssertNoAllocation no_allocations;
12563 HeapIterator heap_iterator;
12564 Script* scr = *script;
12565 FixedArray* arr = *array;
12566 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12567 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012568 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012569 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012570 isolate->heap()->EnsureHeapIsIterable();
12571 AssertNoAllocation no_allocations;
12572 HeapIterator heap_iterator;
12573 Script* scr = *script;
12574 FixedArray* arr = *array;
12575 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012576 }
12577
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012578 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012579 result->set_length(Smi::FromInt(number));
12580
12581 LiveEdit::WrapSharedFunctionInfos(result);
12582
12583 return *result;
12584}
12585
12586// For a script calculates compilation information about all its functions.
12587// The script source is explicitly specified by the second argument.
12588// The source of the actual script is not used, however it is important that
12589// all generated code keeps references to this particular instance of script.
12590// Returns a JSArray of compilation infos. The array is ordered so that
12591// each function with all its descendant is always stored in a continues range
12592// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012593RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012594 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012595 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012596 CONVERT_CHECKED(JSValue, script, args[0]);
12597 CONVERT_ARG_CHECKED(String, source, 1);
12598 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12599
12600 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012602 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012603 return Failure::Exception();
12604 }
12605
12606 return result;
12607}
12608
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012609// Changes the source of the script to a new_source.
12610// If old_script_name is provided (i.e. is a String), also creates a copy of
12611// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012612RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012613 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012614 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012615 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12616 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012617 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012618
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012619 CONVERT_CHECKED(Script, original_script_pointer,
12620 original_script_value->value());
12621 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012622
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012623 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12624 new_source,
12625 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012626
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012627 if (old_script->IsScript()) {
12628 Handle<Script> script_handle(Script::cast(old_script));
12629 return *(GetScriptWrapper(script_handle));
12630 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012631 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012632 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012633}
12634
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012636RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012637 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012638 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012639 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12640 return LiveEdit::FunctionSourceUpdated(shared_info);
12641}
12642
12643
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012644// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012645RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012646 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012647 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012648 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12649 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12650
ager@chromium.orgac091b72010-05-05 07:34:42 +000012651 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012652}
12653
12654// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012655RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012656 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012657 HandleScope scope(isolate);
12658 Handle<Object> function_object(args[0], isolate);
12659 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012660
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012661 if (function_object->IsJSValue()) {
12662 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12663 if (script_object->IsJSValue()) {
12664 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012665 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012666 }
12667
12668 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12669 } else {
12670 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12671 // and we check it in this function.
12672 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012673
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012674 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012675}
12676
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012677
12678// In a code of a parent function replaces original function as embedded object
12679// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012680RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012681 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012682 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012683
12684 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12685 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12686 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12687
12688 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12689 subst_wrapper);
12690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012691 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012692}
12693
12694
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012695// Updates positions of a shared function info (first parameter) according
12696// to script source change. Text change is described in second parameter as
12697// array of groups of 3 numbers:
12698// (change_begin, change_end, change_end_new_position).
12699// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012700RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012701 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012702 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012703 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12704 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12705
ager@chromium.orgac091b72010-05-05 07:34:42 +000012706 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012707}
12708
12709
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012710// For array of SharedFunctionInfo's (each wrapped in JSValue)
12711// checks that none of them have activations on stacks (of any thread).
12712// Returns array of the same length with corresponding results of
12713// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012714RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012715 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012716 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012717 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012718 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012719
ager@chromium.org357bf652010-04-12 11:30:10 +000012720 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012721}
12722
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012723// Compares 2 strings line-by-line, then token-wise and returns diff in form
12724// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12725// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012726RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012727 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012728 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012729 CONVERT_ARG_CHECKED(String, s1, 0);
12730 CONVERT_ARG_CHECKED(String, s2, 1);
12731
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012732 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012733}
12734
12735
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012736// A testing entry. Returns statement position which is the closest to
12737// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012738RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012739 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012740 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012741 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12742 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12743
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012744 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012745
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012746 if (code->kind() != Code::FUNCTION &&
12747 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012748 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012749 }
12750
12751 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012752 int closest_pc = 0;
12753 int distance = kMaxInt;
12754 while (!it.done()) {
12755 int statement_position = static_cast<int>(it.rinfo()->data());
12756 // Check if this break point is closer that what was previously found.
12757 if (source_position <= statement_position &&
12758 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012759 closest_pc =
12760 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012761 distance = statement_position - source_position;
12762 // Check whether we can't get any closer.
12763 if (distance == 0) break;
12764 }
12765 it.next();
12766 }
12767
12768 return Smi::FromInt(closest_pc);
12769}
12770
12771
ager@chromium.org357bf652010-04-12 11:30:10 +000012772// Calls specified function with or without entering the debugger.
12773// This is used in unit tests to run code as if debugger is entered or simply
12774// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012775RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012776 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012777 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012778 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12779 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12780
12781 Handle<Object> result;
12782 bool pending_exception;
12783 {
12784 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012785 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012786 &pending_exception);
12787 } else {
12788 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012789 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012790 &pending_exception);
12791 }
12792 }
12793 if (!pending_exception) {
12794 return *result;
12795 } else {
12796 return Failure::Exception();
12797 }
12798}
12799
12800
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012801// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012802RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012803 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012804 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012805 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12806 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012807 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012808}
12809
12810
12811// Performs a GC.
12812// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012813RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012814 isolate->heap()->CollectAllGarbage(true);
12815 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012816}
12817
12818
12819// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012820RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012821 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012822 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012823 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012824 }
12825 return Smi::FromInt(usage);
12826}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012827
12828
12829// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012830RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012831#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012832 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012833#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012834 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012835#endif
12836}
12837
12838
12839// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012840RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012841#ifdef LIVE_OBJECT_LIST
12842 return LiveObjectList::Capture();
12843#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012844 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012845#endif
12846}
12847
12848
12849// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012850RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012851#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012852 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012853 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012854 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012855#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012856 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012857#endif
12858}
12859
12860
12861// Generates the response to a debugger request for a dump of the objects
12862// contained in the difference between the captured live object lists
12863// specified by id1 and id2.
12864// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12865// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012866RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012867#ifdef LIVE_OBJECT_LIST
12868 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012869 CONVERT_SMI_ARG_CHECKED(id1, 0);
12870 CONVERT_SMI_ARG_CHECKED(id2, 1);
12871 CONVERT_SMI_ARG_CHECKED(start, 2);
12872 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012873 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12874 EnterDebugger enter_debugger;
12875 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12876#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012877 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012878#endif
12879}
12880
12881
12882// Gets the specified object as requested by the debugger.
12883// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012884RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012885#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012886 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012887 Object* result = LiveObjectList::GetObj(obj_id);
12888 return result;
12889#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012890 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012891#endif
12892}
12893
12894
12895// Gets the obj id for the specified address if valid.
12896// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012897RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012898#ifdef LIVE_OBJECT_LIST
12899 HandleScope scope;
12900 CONVERT_ARG_CHECKED(String, address, 0);
12901 Object* result = LiveObjectList::GetObjId(address);
12902 return result;
12903#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012904 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012905#endif
12906}
12907
12908
12909// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012910RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012911#ifdef LIVE_OBJECT_LIST
12912 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012913 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012914 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12915 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12916 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12917 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12918 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12919
12920 Handle<JSObject> instance_filter;
12921 if (args[1]->IsJSObject()) {
12922 instance_filter = args.at<JSObject>(1);
12923 }
12924 bool verbose = false;
12925 if (args[2]->IsBoolean()) {
12926 verbose = args[2]->IsTrue();
12927 }
12928 int start = 0;
12929 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012930 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012931 }
12932 int limit = Smi::kMaxValue;
12933 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012934 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012935 }
12936
12937 return LiveObjectList::GetObjRetainers(obj_id,
12938 instance_filter,
12939 verbose,
12940 start,
12941 limit,
12942 filter_obj);
12943#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012944 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012945#endif
12946}
12947
12948
12949// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012950RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012951#ifdef LIVE_OBJECT_LIST
12952 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012953 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12954 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012955 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12956
12957 Handle<JSObject> instance_filter;
12958 if (args[2]->IsJSObject()) {
12959 instance_filter = args.at<JSObject>(2);
12960 }
12961
12962 Object* result =
12963 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12964 return result;
12965#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012966 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012967#endif
12968}
12969
12970
12971// Generates the response to a debugger request for a list of all
12972// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012973RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012974#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012975 CONVERT_SMI_ARG_CHECKED(start, 0);
12976 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012977 return LiveObjectList::Info(start, count);
12978#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012979 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012980#endif
12981}
12982
12983
12984// Gets a dump of the specified object as requested by the debugger.
12985// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012986RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012987#ifdef LIVE_OBJECT_LIST
12988 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012989 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012990 Object* result = LiveObjectList::PrintObj(obj_id);
12991 return result;
12992#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012993 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012994#endif
12995}
12996
12997
12998// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012999RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013000#ifdef LIVE_OBJECT_LIST
13001 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013002 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013003#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013004 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013005#endif
13006}
13007
13008
13009// Generates the response to a debugger request for a summary of the types
13010// of objects in the difference between the captured live object lists
13011// specified by id1 and id2.
13012// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13013// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013014RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013015#ifdef LIVE_OBJECT_LIST
13016 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013017 CONVERT_SMI_ARG_CHECKED(id1, 0);
13018 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013019 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13020
13021 EnterDebugger enter_debugger;
13022 return LiveObjectList::Summarize(id1, id2, filter_obj);
13023#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013024 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013025#endif
13026}
13027
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013028#endif // ENABLE_DEBUGGER_SUPPORT
13029
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013031RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013032 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013033 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013034 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013035}
13036
13037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013038RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013039 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013040 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013041 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013042}
13043
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013044
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013045// Finds the script object from the script data. NOTE: This operation uses
13046// heap traversal to find the function generated for the source position
13047// for the requested break point. For lazily compiled functions several heap
13048// traversals might be required rendering this operation as a rather slow
13049// operation. However for setting break points which is normally done through
13050// some kind of user interaction the performance is not crucial.
13051static Handle<Object> Runtime_GetScriptFromScriptName(
13052 Handle<String> script_name) {
13053 // Scan the heap for Script objects to find the script with the requested
13054 // script data.
13055 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013056 script_name->GetHeap()->EnsureHeapIsIterable();
13057 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013058 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013059 HeapObject* obj = NULL;
13060 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013061 // If a script is found check if it has the script data requested.
13062 if (obj->IsScript()) {
13063 if (Script::cast(obj)->name()->IsString()) {
13064 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13065 script = Handle<Script>(Script::cast(obj));
13066 }
13067 }
13068 }
13069 }
13070
13071 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013072 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013073
13074 // Return the script found.
13075 return GetScriptWrapper(script);
13076}
13077
13078
13079// Get the script object from script data. NOTE: Regarding performance
13080// see the NOTE for GetScriptFromScriptData.
13081// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013082RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013083 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013084
13085 ASSERT(args.length() == 1);
13086
13087 CONVERT_CHECKED(String, script_name, args[0]);
13088
13089 // Find the requested script.
13090 Handle<Object> result =
13091 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13092 return *result;
13093}
13094
13095
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013096// Determines whether the given stack frame should be displayed in
13097// a stack trace. The caller is the error constructor that asked
13098// for the stack trace to be collected. The first time a construct
13099// call to this function is encountered it is skipped. The seen_caller
13100// in/out parameter is used to remember if the caller has been seen
13101// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013102static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13103 Object* caller,
13104 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013105 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013106 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013107 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013108 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013109 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13110 Object* raw_fun = frame->function();
13111 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013112 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013113 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013114 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013115 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013116 *seen_caller = true;
13117 return false;
13118 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013119 // Skip all frames until we've seen the caller.
13120 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013121 // Also, skip non-visible built-in functions and any call with the builtins
13122 // object as receiver, so as to not reveal either the builtins object or
13123 // an internal function.
13124 // The --builtins-in-stack-traces command line flag allows including
13125 // internal call sites in the stack trace for debugging purposes.
13126 if (!FLAG_builtins_in_stack_traces) {
13127 JSFunction* fun = JSFunction::cast(raw_fun);
13128 if (frame->receiver()->IsJSBuiltinsObject() ||
13129 (fun->IsBuiltin() && !fun->shared()->native())) {
13130 return false;
13131 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013132 }
13133 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013134}
13135
13136
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013137// Collect the raw data for a stack trace. Returns an array of 4
13138// element segments each containing a receiver, function, code and
13139// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013140RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013141 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013142 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013143 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013145 HandleScope scope(isolate);
13146 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013147
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013148 limit = Max(limit, 0); // Ensure that limit is not negative.
13149 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013150 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013151 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013152
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013153 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013154 // If the caller parameter is a function we skip frames until we're
13155 // under it before starting to collect.
13156 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013157 int cursor = 0;
13158 int frames_seen = 0;
13159 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013160 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013161 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013162 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013163 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013164 // Set initial size to the maximum inlining level + 1 for the outermost
13165 // function.
13166 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013167 frame->Summarize(&frames);
13168 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013169 if (cursor + 4 > elements->length()) {
13170 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13171 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013172 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013173 for (int i = 0; i < cursor; i++) {
13174 new_elements->set(i, elements->get(i));
13175 }
13176 elements = new_elements;
13177 }
13178 ASSERT(cursor + 4 <= elements->length());
13179
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013180 Handle<Object> recv = frames[i].receiver();
13181 Handle<JSFunction> fun = frames[i].function();
13182 Handle<Code> code = frames[i].code();
13183 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013184 elements->set(cursor++, *recv);
13185 elements->set(cursor++, *fun);
13186 elements->set(cursor++, *code);
13187 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013188 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013189 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013190 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013191 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013192 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013193 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013194 return *result;
13195}
13196
13197
ager@chromium.org3811b432009-10-28 14:53:37 +000013198// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013199RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013200 ASSERT_EQ(args.length(), 0);
13201
13202 NoHandleAllocation ha;
13203
13204 const char* version_string = v8::V8::GetVersion();
13205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013206 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13207 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013208}
13209
13210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013211RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013212 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013213 OS::PrintError("abort: %s\n",
13214 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013215 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013216 OS::Abort();
13217 UNREACHABLE();
13218 return NULL;
13219}
13220
13221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013222RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013223 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013224 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013225 Object* key = args[1];
13226
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013227 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013228 Object* o = cache->get(finger_index);
13229 if (o == key) {
13230 // The fastest case: hit the same place again.
13231 return cache->get(finger_index + 1);
13232 }
13233
13234 for (int i = finger_index - 2;
13235 i >= JSFunctionResultCache::kEntriesIndex;
13236 i -= 2) {
13237 o = cache->get(i);
13238 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013239 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013240 return cache->get(i + 1);
13241 }
13242 }
13243
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013244 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013245 ASSERT(size <= cache->length());
13246
13247 for (int i = size - 2; i > finger_index; i -= 2) {
13248 o = cache->get(i);
13249 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013250 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013251 return cache->get(i + 1);
13252 }
13253 }
13254
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013255 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013256 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013257
13258 Handle<JSFunctionResultCache> cache_handle(cache);
13259 Handle<Object> key_handle(key);
13260 Handle<Object> value;
13261 {
13262 Handle<JSFunction> factory(JSFunction::cast(
13263 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13264 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013265 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013266 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013267 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013268 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013269 value = Execution::Call(factory,
13270 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013271 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013272 argv,
13273 &pending_exception);
13274 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013275 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013276
13277#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013278 if (FLAG_verify_heap) {
13279 cache_handle->JSFunctionResultCacheVerify();
13280 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013281#endif
13282
13283 // Function invocation may have cleared the cache. Reread all the data.
13284 finger_index = cache_handle->finger_index();
13285 size = cache_handle->size();
13286
13287 // If we have spare room, put new data into it, otherwise evict post finger
13288 // entry which is likely to be the least recently used.
13289 int index = -1;
13290 if (size < cache_handle->length()) {
13291 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13292 index = size;
13293 } else {
13294 index = finger_index + JSFunctionResultCache::kEntrySize;
13295 if (index == cache_handle->length()) {
13296 index = JSFunctionResultCache::kEntriesIndex;
13297 }
13298 }
13299
13300 ASSERT(index % 2 == 0);
13301 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13302 ASSERT(index < cache_handle->length());
13303
13304 cache_handle->set(index, *key_handle);
13305 cache_handle->set(index + 1, *value);
13306 cache_handle->set_finger_index(index);
13307
13308#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013309 if (FLAG_verify_heap) {
13310 cache_handle->JSFunctionResultCacheVerify();
13311 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013312#endif
13313
13314 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013315}
13316
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013318RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013319 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013320 CONVERT_ARG_CHECKED(String, type, 0);
13321 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013322 return *isolate->factory()->NewJSMessageObject(
13323 type,
13324 arguments,
13325 0,
13326 0,
13327 isolate->factory()->undefined_value(),
13328 isolate->factory()->undefined_value(),
13329 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013330}
13331
13332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013333RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013334 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13335 return message->type();
13336}
13337
13338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013339RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013340 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13341 return message->arguments();
13342}
13343
13344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013345RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013346 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13347 return Smi::FromInt(message->start_position());
13348}
13349
13350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013351RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013352 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13353 return message->script();
13354}
13355
13356
kasper.lund44510672008-07-25 07:37:58 +000013357#ifdef DEBUG
13358// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13359// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013360RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013361 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013362 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013363#define COUNT_ENTRY(Name, argc, ressize) + 1
13364 int entry_count = 0
13365 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13366 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13367 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13368#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013369 Factory* factory = isolate->factory();
13370 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013371 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013372 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013373#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013374 { \
13375 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013376 Handle<String> name; \
13377 /* Inline runtime functions have an underscore in front of the name. */ \
13378 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013379 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013380 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13381 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013382 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013383 Vector<const char>(#Name, StrLength(#Name))); \
13384 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013385 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013386 pair_elements->set(0, *name); \
13387 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013388 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013389 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013390 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013391 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013392 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013393 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013394 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013395 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013396#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013397 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013398 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013399 return *result;
13400}
kasper.lund44510672008-07-25 07:37:58 +000013401#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013402
13403
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013404RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013405 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013406 CONVERT_CHECKED(String, format, args[0]);
13407 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013408 String::FlatContent format_content = format->GetFlatContent();
13409 RUNTIME_ASSERT(format_content.IsAscii());
13410 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013411 LOGGER->LogRuntime(chars, elms);
13412 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013413}
13414
13415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013416RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013417 UNREACHABLE(); // implemented as macro in the parser
13418 return NULL;
13419}
13420
13421
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013422#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13423 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13424 CONVERT_CHECKED(JSObject, obj, args[0]); \
13425 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13426 }
13427
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013428ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013429ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13430ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13431ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13432ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13433ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13434ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13435ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13436ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13437ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13438ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13439ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13440ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13441ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13442
13443#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13444
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013445
13446RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13447 ASSERT(args.length() == 2);
13448 CONVERT_CHECKED(JSObject, obj1, args[0]);
13449 CONVERT_CHECKED(JSObject, obj2, args[1]);
13450 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13451}
13452
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013453// ----------------------------------------------------------------------------
13454// Implementation of Runtime
13455
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013456#define F(name, number_of_args, result_size) \
13457 { Runtime::k##name, Runtime::RUNTIME, #name, \
13458 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013459
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013460
13461#define I(name, number_of_args, result_size) \
13462 { Runtime::kInline##name, Runtime::INLINE, \
13463 "_" #name, NULL, number_of_args, result_size },
13464
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013465static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013466 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013467 INLINE_FUNCTION_LIST(I)
13468 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013469};
13470
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013472MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13473 Object* dictionary) {
13474 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013475 ASSERT(dictionary != NULL);
13476 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13477 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013478 Object* name_symbol;
13479 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013480 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013481 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13482 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013483 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013484 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13485 String::cast(name_symbol),
13486 Smi::FromInt(i),
13487 PropertyDetails(NONE, NORMAL));
13488 if (!maybe_dictionary->ToObject(&dictionary)) {
13489 // Non-recoverable failure. Calling code must restart heap
13490 // initialization.
13491 return maybe_dictionary;
13492 }
13493 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013494 }
13495 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013496}
13497
13498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013499const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13500 Heap* heap = name->GetHeap();
13501 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013502 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013503 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013504 int function_index = Smi::cast(smi_index)->value();
13505 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013506 }
13507 return NULL;
13508}
13509
13510
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013511const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013512 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13513}
13514
13515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013516void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013517 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013518 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013519 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013520 if (isolate->heap()->new_space()->AddFreshPage()) {
13521 return;
13522 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013523 // Try to do a garbage collection; ignore it if it fails. The C
13524 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013525 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013526 } else {
13527 // Handle last resort GC and make sure to allow future allocations
13528 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013529 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013530 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013531 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013532}
13533
13534
13535} } // namespace v8::internal